mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-21 21:17:25 +00:00
feat(k8s): mvp
This commit is contained in:
parent
1941679d27
commit
166a283c70
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -20,3 +20,6 @@
|
||||
[submodule "thirdparty/magic_enum"]
|
||||
path = thirdparty/magic_enum
|
||||
url = https://github.com/Neargye/magic_enum.git
|
||||
[submodule "thirdparty/kubernetes-client-c"]
|
||||
path = thirdparty/kubernetes-client-c
|
||||
url = https://github.com/kubernetes-client/c
|
||||
|
@ -121,6 +121,7 @@ void CatchUnhandled(int sig) {
|
||||
} catch(const std::exception& e) {
|
||||
LOG("Caught exception: '%s'", e.what());
|
||||
}
|
||||
Game::logger->Flush();
|
||||
|
||||
#ifndef INCLUDE_BACKTRACE
|
||||
|
||||
@ -186,7 +187,7 @@ void CatchUnhandled(int sig) {
|
||||
Bt(state);
|
||||
|
||||
#endif // INCLUDE_BACKTRACE
|
||||
|
||||
Game::logger->Flush();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,26 @@
|
||||
set(DMASTERSERVER_SOURCES
|
||||
"InstanceManager.cpp"
|
||||
"ObjectIDManager.cpp"
|
||||
"Start.cpp"
|
||||
)
|
||||
|
||||
add_library(dMasterServer ${DMASTERSERVER_SOURCES})
|
||||
add_executable(MasterServer "MasterServer.cpp")
|
||||
add_compile_definitions(MasterServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"")
|
||||
|
||||
target_link_libraries(dMasterServer ${COMMON_LIBRARIES})
|
||||
|
||||
add_executable(MasterServer "MasterServer.cpp" "Start.cpp")
|
||||
add_compile_definitions(MasterServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"")
|
||||
target_link_libraries(MasterServer ${COMMON_LIBRARIES} dMasterServer)
|
||||
|
||||
option(ENABLE_K8S "Whether to enable kubernetes support")
|
||||
|
||||
if (${ENABLE_K8S})
|
||||
# See k8s folder
|
||||
find_package(kubernetes CONFIG REQUIRED COMPONENTS kubernetes)
|
||||
|
||||
add_executable(MasterServerK8s "MasterServer.cpp" "StartK8s.cpp")
|
||||
add_compile_definitions(MasterServerK8s PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"")
|
||||
target_link_libraries(MasterServerK8s PRIVATE ${COMMON_LIBRARIES} dMasterServer kubernetes::kubernetes)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
add_dependencies(MasterServer WorldServer AuthServer ChatServer)
|
||||
endif()
|
||||
|
@ -125,6 +125,8 @@ int main(int argc, char** argv) {
|
||||
LOG("Version: %s", PROJECT_VERSION);
|
||||
LOG("Compiled on: %s", __TIMESTAMP__);
|
||||
|
||||
Game::logger->Flush();
|
||||
|
||||
//Connect to the MySQL Database
|
||||
try {
|
||||
Database::Connect();
|
||||
@ -851,6 +853,7 @@ int ShutdownSequence(int32_t signal) {
|
||||
}
|
||||
|
||||
LOG("Attempting to shutdown instances, max 60 seconds...");
|
||||
Game::logger->Flush();
|
||||
|
||||
auto t = std::chrono::high_resolution_clock::now();
|
||||
uint32_t framesSinceShutdownStart = 0;
|
||||
|
288
dMasterServer/StartK8s.cpp
Normal file
288
dMasterServer/StartK8s.cpp
Normal file
@ -0,0 +1,288 @@
|
||||
#include "Start.h"
|
||||
#include "Logger.h"
|
||||
|
||||
extern "C" {
|
||||
#include <kubernetes/config/kube_config.h>
|
||||
#include <kubernetes/config/incluster_config.h>
|
||||
#include <kubernetes/include/apiClient.h>
|
||||
#include <kubernetes/model/v1_daemon_set_spec.h>
|
||||
#include <kubernetes/api/CoreV1API.h>
|
||||
#include <kubernetes/api/AppsV1API.h>
|
||||
}
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cerrno>
|
||||
|
||||
namespace k8s {
|
||||
using DaemonSet = std::unique_ptr<v1_daemon_set_t, decltype(v1_daemon_set_free)&>;
|
||||
using Deployment = std::unique_ptr<v1_deployment_t, decltype(v1_deployment_free)&>;
|
||||
using PodSpec = std::unique_ptr<v1_pod_spec_t, decltype(v1_pod_spec_free)&>;
|
||||
using Pod = std::unique_ptr<v1_pod_t, decltype(v1_pod_free)&>;
|
||||
}
|
||||
|
||||
class ApiClient {
|
||||
char* basePath = NULL;
|
||||
sslConfig_t* sslConfig = NULL;
|
||||
list_t* apiKeys = NULL;
|
||||
apiClient_t* k8sApiClient = NULL;
|
||||
|
||||
public:
|
||||
ApiClient();
|
||||
~ApiClient();
|
||||
|
||||
k8s::DaemonSet CreateOrReplaceDeamonSet(const std::string& namespace_, k8s::DaemonSet& daemonset);
|
||||
k8s::Deployment CreateOrReplaceDeployment(const std::string& namespace_, k8s::Deployment& deployment);
|
||||
k8s::Pod SpawnPod(const std::string& namespace_, k8s::Pod& pod);
|
||||
k8s::PodSpec CreatePodSpec(const std::string& entrypoint, int container_port, int host_port, const std::vector<std::string>& args);
|
||||
};
|
||||
|
||||
k8s::PodSpec ApiClient::CreatePodSpec(const std::string& entrypoint, int container_port, int host_port, const std::vector<std::string>& args) {
|
||||
v1_pod_spec_t* pod_spec;
|
||||
|
||||
char* podTemplateName = strdup("pod-template");
|
||||
char* podTemplateNamespace = strdup("default");
|
||||
v1_pod_template_t* pod_template = CoreV1API_readNamespacedPodTemplate(k8sApiClient, podTemplateName, podTemplateNamespace, NULL);
|
||||
LOG("code = %d", k8sApiClient->response_code);
|
||||
Game::logger->Flush();
|
||||
if (k8sApiClient->response_code >= 400) {
|
||||
throw new std::runtime_error("pod-template not found");
|
||||
}
|
||||
|
||||
pod_spec = pod_template->_template->spec;
|
||||
pod_template->_template->spec = NULL;
|
||||
v1_pod_template_free(pod_template);
|
||||
free(podTemplateName);
|
||||
free(podTemplateNamespace);
|
||||
|
||||
v1_container_t* con = (v1_container_t*) list_getElementAt(pod_spec->containers, 0)->data;
|
||||
|
||||
/* set command for container */
|
||||
list_t* commandlist = list_createList();
|
||||
char* cmd = strdup(entrypoint.c_str());
|
||||
list_addElement(commandlist, cmd);
|
||||
// FIXME: old value?
|
||||
con->command = commandlist;
|
||||
|
||||
if (!args.empty()) {
|
||||
list_t *arglist = list_createList();
|
||||
for (auto it = args.begin(); it != args.end(); it++) {
|
||||
char *arg1 = strdup(it->c_str());
|
||||
list_addElement(arglist, arg1);
|
||||
}
|
||||
// FIXME: old value?
|
||||
con->args = arglist;
|
||||
}
|
||||
|
||||
v1_container_port_t* port = (v1_container_port_t*) list_getElementAt(con->ports, 0)->data;
|
||||
port->container_port = container_port;
|
||||
port->host_port = host_port;
|
||||
|
||||
return std::move(k8s::PodSpec(pod_spec, v1_pod_spec_free));
|
||||
}
|
||||
|
||||
k8s::DaemonSet CreateDeamonSet(const std::string& name, const std::string& app_label, k8s::PodSpec podSpec) {
|
||||
v1_daemon_set_t* daemonsetinfo = (v1_daemon_set_t*)calloc(1, sizeof(v1_daemon_set_t));
|
||||
daemonsetinfo->api_version = strdup("apps/v1");
|
||||
daemonsetinfo->kind = strdup("DaemonSet");
|
||||
|
||||
daemonsetinfo->metadata = (v1_object_meta_t*)calloc(1, sizeof(v1_object_meta_t));
|
||||
daemonsetinfo->metadata->name = strdup(name.c_str());
|
||||
|
||||
daemonsetinfo->spec = (v1_daemon_set_spec_t*)calloc(1, sizeof(v1_daemon_set_spec_t));
|
||||
list_t* match_labels = list_createList();
|
||||
list_addElement(match_labels, keyValuePair_create(strdup("app.kubernetes.io/name"), strdup(app_label.c_str())));
|
||||
daemonsetinfo->spec->selector = (v1_label_selector_t*)calloc(1, sizeof(v1_label_selector_t));
|
||||
daemonsetinfo->spec->selector->match_labels = match_labels;
|
||||
|
||||
v1_pod_template_spec_t* pod_template_spec = (v1_pod_template_spec_t*)calloc(1, sizeof(v1_pod_template_spec_t));
|
||||
pod_template_spec->metadata = (v1_object_meta_t*)calloc(1, sizeof(v1_object_meta_t));
|
||||
list_t* labels = list_createList();
|
||||
list_addElement(labels, keyValuePair_create(strdup("app.kubernetes.io/name"), strdup(app_label.c_str())));
|
||||
pod_template_spec->metadata->labels = labels;
|
||||
pod_template_spec->spec = podSpec.release();
|
||||
|
||||
daemonsetinfo->spec->_template = pod_template_spec;
|
||||
return std::move(k8s::DaemonSet(daemonsetinfo, v1_daemon_set_free));
|
||||
}
|
||||
|
||||
k8s::Deployment CreateDeployment(const std::string& name, const std::string& app_label, k8s::PodSpec podSpec) {
|
||||
v1_deployment_t* deployment = (v1_deployment_t*)calloc(1, sizeof(v1_deployment_t));
|
||||
deployment->api_version = strdup("apps/v1");
|
||||
deployment->kind = strdup("Deployment");
|
||||
|
||||
deployment->metadata = (v1_object_meta_t*)calloc(1, sizeof(v1_object_meta_t));
|
||||
deployment->metadata->name = strdup(name.c_str());
|
||||
|
||||
deployment->spec = (v1_deployment_spec_t*)calloc(1, sizeof(v1_deployment_spec_t));
|
||||
deployment->spec->replicas = 1;
|
||||
|
||||
list_t* match_labels = list_createList();
|
||||
list_addElement(match_labels, keyValuePair_create(strdup("app.kubernetes.io/name"), strdup(app_label.c_str())));
|
||||
deployment->spec->selector = (v1_label_selector_t*)calloc(1, sizeof(v1_label_selector_t));
|
||||
deployment->spec->selector->match_labels = match_labels;
|
||||
|
||||
v1_pod_template_spec_t* pod_template_spec = (v1_pod_template_spec_t*)calloc(1, sizeof(v1_pod_template_spec_t));
|
||||
pod_template_spec->metadata = (v1_object_meta_t*)calloc(1, sizeof(v1_object_meta_t));
|
||||
list_t* labels = list_createList();
|
||||
list_addElement(labels, keyValuePair_create(strdup("app.kubernetes.io/name"), strdup(app_label.c_str())));
|
||||
pod_template_spec->metadata->labels = labels;
|
||||
pod_template_spec->spec = podSpec.release();
|
||||
|
||||
deployment->spec->_template = pod_template_spec;
|
||||
return std::move(k8s::Deployment(deployment, v1_deployment_free));
|
||||
}
|
||||
|
||||
char shiftNumbers(char c) {
|
||||
return c < 'a' ? c - ('a' - 10 - '0') : c;
|
||||
}
|
||||
|
||||
k8s::Pod CreatePod(const std::string& name, const std::string& app_label, k8s::PodSpec podSpec) {
|
||||
v1_pod_t* pod = (v1_pod_t*)calloc(1, sizeof(v1_pod_t));
|
||||
pod->api_version = strdup("v1");
|
||||
pod->kind = strdup("Pod");
|
||||
|
||||
std::uniform_int_distribution<char> distribution('a' - 10, 'z');
|
||||
std::string pod_name = name + '-';
|
||||
for (int i = 0; i < 5; i++) {
|
||||
pod_name += shiftNumbers(distribution(Game::randomEngine));
|
||||
}
|
||||
|
||||
pod->metadata = (v1_object_meta_t*)calloc(1, sizeof(v1_object_meta_t));
|
||||
pod->metadata->name = strdup(pod_name.c_str());
|
||||
|
||||
list_t* labels = list_createList();
|
||||
list_addElement(labels, keyValuePair_create(strdup("app.kubernetes.io/name"), strdup(app_label.c_str())));
|
||||
pod->metadata->labels = labels;
|
||||
|
||||
pod->spec = podSpec.release();
|
||||
return std::move(k8s::Pod(pod, v1_pod_free));
|
||||
}
|
||||
|
||||
ApiClient::ApiClient() {
|
||||
int rc = 0;
|
||||
rc = load_incluster_config(&basePath, &sslConfig, &apiKeys);
|
||||
if (0 == rc) {
|
||||
k8sApiClient = apiClient_create_with_base_path(basePath, sslConfig, apiKeys);
|
||||
} else {
|
||||
throw std::runtime_error("Cannot load kubernetes configuration in cluster.");
|
||||
}
|
||||
}
|
||||
|
||||
k8s::DaemonSet ApiClient::CreateOrReplaceDeamonSet(const std::string& namespace_, k8s::DaemonSet& daemonset) {
|
||||
char* podNamespace = strdup(namespace_.c_str());
|
||||
|
||||
v1_daemon_set_t* created;
|
||||
v1_daemon_set_t* existing = AppsV1API_readNamespacedDaemonSet(k8sApiClient, daemonset->metadata->name, podNamespace, NULL);
|
||||
LOG("read code=%ld", k8sApiClient->response_code);
|
||||
if (k8sApiClient->response_code == 200) {
|
||||
daemonset->metadata->resource_version = existing->metadata->resource_version;
|
||||
created = AppsV1API_replaceNamespacedDaemonSet(k8sApiClient, daemonset->metadata->name, podNamespace, daemonset.get(), NULL, NULL, NULL, NULL);
|
||||
} else {
|
||||
created = AppsV1API_createNamespacedDaemonSet(k8sApiClient, podNamespace, daemonset.get(), NULL, NULL, NULL, NULL);
|
||||
}
|
||||
LOG("code=%ld", k8sApiClient->response_code);
|
||||
|
||||
free(podNamespace);
|
||||
v1_daemon_set_free(existing);
|
||||
return k8s::DaemonSet(created, v1_daemon_set_free);
|
||||
}
|
||||
|
||||
k8s::Pod ApiClient::SpawnPod(const std::string& namespace_, k8s::Pod& pod) {
|
||||
char* podNamespace = strdup(namespace_.c_str());
|
||||
|
||||
// Kill the pod (if it exists)
|
||||
//int grace_period_seconds = 0;
|
||||
//v1_pod_t* existing = CoreV1API_deleteNamespacedPod(k8sApiClient, pod->metadata->name, podNamespace, NULL, NULL, &grace_period_seconds, NULL, NULL, NULL);
|
||||
//LOG("read code=%ld", k8sApiClient->response_code);
|
||||
// Spawn a new pod
|
||||
v1_pod_t* created = CoreV1API_createNamespacedPod(k8sApiClient, podNamespace, pod.get(), NULL, NULL, NULL, NULL);
|
||||
LOG("code=%ld", k8sApiClient->response_code);
|
||||
|
||||
free(podNamespace);
|
||||
//v1_pod_free(existing);
|
||||
return k8s::Pod(created, v1_pod_free);
|
||||
}
|
||||
|
||||
k8s::Deployment ApiClient::CreateOrReplaceDeployment(const std::string& namespace_, k8s::Deployment& deployment) {
|
||||
char* podNamespace = strdup(namespace_.c_str());
|
||||
|
||||
v1_deployment_t* created;
|
||||
v1_deployment_t* existing = AppsV1API_readNamespacedDeployment(k8sApiClient, deployment->metadata->name, podNamespace, NULL);
|
||||
LOG("read code=%ld", k8sApiClient->response_code);
|
||||
if (k8sApiClient->response_code == 200) {
|
||||
deployment->metadata->resource_version = existing->metadata->resource_version;
|
||||
created = AppsV1API_replaceNamespacedDeployment(k8sApiClient, deployment->metadata->name, podNamespace, deployment.get(), NULL, NULL, NULL, NULL);
|
||||
} else {
|
||||
created = AppsV1API_createNamespacedDeployment(k8sApiClient, podNamespace, deployment.get(), NULL, NULL, NULL, NULL);
|
||||
}
|
||||
LOG("code=%ld", k8sApiClient->response_code);
|
||||
|
||||
free(podNamespace);
|
||||
v1_deployment_free(existing);
|
||||
return k8s::Deployment(created, v1_deployment_free);
|
||||
}
|
||||
|
||||
ApiClient::~ApiClient() {
|
||||
free_client_config(basePath, sslConfig, apiKeys);
|
||||
basePath = NULL;
|
||||
sslConfig = NULL;
|
||||
apiKeys = NULL;
|
||||
|
||||
apiClient_free(k8sApiClient);
|
||||
k8sApiClient = NULL;
|
||||
apiClient_unsetupGlobalEnv();
|
||||
}
|
||||
|
||||
void StartAuthServer() {
|
||||
if (Game::ShouldShutdown()) {
|
||||
LOG("Currently shutting down. Auth will not be restarted.");
|
||||
return;
|
||||
}
|
||||
LOG("Starting AuthServer");
|
||||
ApiClient apiClient;
|
||||
k8s::PodSpec podSpec = apiClient.CreatePodSpec("/app/AuthServer", 1001, 1001, {});
|
||||
//k8s::DaemonSet daemonset = CreateDeamonSet("auth-servers", "auth-server", podSpec);
|
||||
k8s::Pod pod = CreatePod("auth-server-pod", "auth-server", std::move(podSpec));
|
||||
apiClient.SpawnPod("default", pod);
|
||||
LOG("Done starting AuthServer");
|
||||
}
|
||||
|
||||
void StartChatServer() {
|
||||
if (Game::ShouldShutdown()) {
|
||||
LOG("Currently shutting down. Chat will not be restarted.");
|
||||
return;
|
||||
}
|
||||
LOG("Starting ChatServer");
|
||||
ApiClient apiClient;
|
||||
k8s::PodSpec podSpec = apiClient.CreatePodSpec("/app/ChatServer", 2005, 0, {});
|
||||
//k8s::Deployment deployment = CreateDeployment("chat-server", "chat-server", podSpec);
|
||||
k8s::Pod pod = CreatePod("chat-server-pod", "chat-server", std::move(podSpec));
|
||||
apiClient.SpawnPod("default", pod);
|
||||
LOG("Done starting ChatServer");
|
||||
}
|
||||
|
||||
void StartWorldServer(LWOMAPID mapID, uint16_t port, LWOINSTANCEID instanceID, int maxPlayers, LWOCLONEID cloneID) {
|
||||
LOG("Starting WorldServer %d %d %d (port %d)", mapID, instanceID, cloneID, port);
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"-zone",
|
||||
std::to_string(mapID),
|
||||
"-port",
|
||||
std::to_string(port),
|
||||
"-instance",
|
||||
std::to_string(instanceID),
|
||||
"-maxclients",
|
||||
std::to_string(maxPlayers),
|
||||
"-clone",
|
||||
std::to_string(cloneID),
|
||||
};
|
||||
|
||||
ApiClient apiClient;
|
||||
int host_port = (int) port; // for now
|
||||
k8s::PodSpec podSpec = apiClient.CreatePodSpec("/app/WorldServer", (int) port, host_port, args);
|
||||
std::string name = "world-" + std::to_string(mapID) + "-" + std::to_string(instanceID) + "-" + std::to_string(cloneID);
|
||||
k8s::Pod pod = CreatePod(name, "world-server", std::move(podSpec));
|
||||
apiClient.SpawnPod("default", pod);
|
||||
LOG("Done starting WorldServer");
|
||||
}
|
50
k8s/DLU.Dockerfile
Normal file
50
k8s/DLU.Dockerfile
Normal file
@ -0,0 +1,50 @@
|
||||
FROM gcc:12 AS build
|
||||
|
||||
RUN --mount=type=cache,id=build-apt-cache,target=/var/cache/apt \
|
||||
apt update && \
|
||||
apt install -y libssl-dev libcurl4-openssl-dev uncrustify git cmake && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /work
|
||||
RUN git clone https://libwebsockets.org/repo/libwebsockets --depth 1 --branch v4.2-stable
|
||||
RUN git clone https://github.com/yaml/libyaml --depth 1 --branch release/0.2.5
|
||||
|
||||
WORKDIR /work/libwebsockets/build
|
||||
RUN cmake -DLWS_WITHOUT_TESTAPPS=ON -DLWS_WITHOUT_TEST_SERVER=ON -DLWS_WITHOUT_TEST_SERVER_EXTPOLL=ON \
|
||||
-DLWS_WITHOUT_TEST_PING=ON -DLWS_WITHOUT_TEST_CLIENT=ON -DCMAKE_C_FLAGS="-fpic" -DCMAKE_INSTALL_PREFIX=/usr/local ..
|
||||
RUN make install
|
||||
|
||||
WORKDIR /work/libyaml/build
|
||||
RUN cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=ON ..
|
||||
RUN make install
|
||||
|
||||
COPY ../thirdparty/kubernetes-client-c/kubernetes /work/kubernetes-client-c/
|
||||
WORKDIR /work/kubernetes-client-c/build
|
||||
RUN cmake -DCMAKE_INSTALL_PREFIX=/usr/local ..
|
||||
RUN make install
|
||||
|
||||
FROM debian:12
|
||||
|
||||
RUN --mount=type=cache,id=build-apt-cache,target=/var/cache/apt \
|
||||
apt update && \
|
||||
apt install -y libssl3 libcurl4 && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
COPY build/mariadbcpp/src/mariadb_connector_cpp-build/libmariadb/libmariadb/libmariadb.so.3 /usr/local/lib
|
||||
COPY --from=build /usr/local/lib/libkubernetes.so /usr/local/lib
|
||||
COPY --from=build /usr/local/lib/libyaml.so /usr/local/lib
|
||||
COPY --from=build /usr/local/lib/libwebsockets.so.18 /usr/local/lib
|
||||
COPY --from=build /usr/local/lib/libwebsockets.so /usr/local/lib
|
||||
COPY build/libmariadbcpp.so /usr/local/lib
|
||||
RUN ldconfig
|
||||
COPY build/MasterServerK8s /app/MasterServerK8s
|
||||
COPY build/MasterServer /app/MasterServer
|
||||
COPY build/AuthServer /app/AuthServer
|
||||
COPY build/ChatServer /app/ChatServer
|
||||
COPY build/WorldServer /app/WorldServer
|
||||
|
||||
COPY build/migrations /app/migrations
|
||||
COPY build/navmeshes /app/navmeshes
|
||||
|
||||
ENTRYPOINT ["/app/MasterServer"]
|
26
k8s/README.md
Normal file
26
k8s/README.md
Normal file
@ -0,0 +1,26 @@
|
||||
## Kubernetes Setup
|
||||
|
||||
Debian
|
||||
```
|
||||
minikube start --driver kvm2
|
||||
minikube mount /path/to/client:/luclient
|
||||
```
|
||||
or
|
||||
```
|
||||
minikube start --mount --mount-options="ro" --mount-string="/path/to/client:/luclient"
|
||||
```
|
||||
|
||||
Fish Shell
|
||||
```
|
||||
eval $(minikube -p minikube docker-env)
|
||||
```
|
||||
|
||||
To Build
|
||||
```
|
||||
docker build -t ghcr.io/darkflameuniverse/darkflameserver -f ./k8s/DLU.Dockerfile .
|
||||
```
|
||||
|
||||
Install
|
||||
```
|
||||
kubectl apply -k k8s
|
||||
```
|
4
k8s/common.env
Normal file
4
k8s/common.env
Normal file
@ -0,0 +1,4 @@
|
||||
EXTERNAL_IP=192.168.39.84
|
||||
MYSQL_HOST=mariadb-service
|
||||
MASTER_IP=master-service
|
||||
DLU_CONFIG_DIR=/app/config
|
94
k8s/darkflame.yml
Normal file
94
k8s/darkflame.yml
Normal file
@ -0,0 +1,94 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: master-server
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: pod-creator
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["pods"]
|
||||
verbs: ["create", "update", "patch", "get", "watch", "list", "delete"]
|
||||
- apiGroups: [""]
|
||||
resources: ["podtemplates"]
|
||||
verbs: ["get", "watch", "list"]
|
||||
- apiGroups: ["apps"]
|
||||
resources: ["daemonsets", "deployments"]
|
||||
verbs: ["create", "update", "patch", "get", "watch", "list", "delete"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: master-server-pod-creator
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: pod-creator
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: master-server
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: master-server-deployment
|
||||
labels:
|
||||
app: master-server
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: master-server
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: master-server
|
||||
spec:
|
||||
serviceAccountName: master-server
|
||||
volumes:
|
||||
- name: game-config
|
||||
configMap:
|
||||
name: game-config
|
||||
- name: luclient
|
||||
hostPath:
|
||||
path: /luclient
|
||||
- name: res-server
|
||||
hostPath:
|
||||
path: /resServer
|
||||
containers:
|
||||
- name: master-server
|
||||
image: ghcr.io/darkflameuniverse/darkflameserver
|
||||
imagePullPolicy: IfNotPresent
|
||||
command: ["/app/MasterServerK8s"]
|
||||
ports:
|
||||
- containerPort: 2000
|
||||
protocol: UDP
|
||||
name: master
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: env-common
|
||||
- secretRef:
|
||||
name: db-secret
|
||||
prefix: MYSQL_
|
||||
volumeMounts:
|
||||
- mountPath: "/app/res"
|
||||
name: luclient
|
||||
- mountPath: "/app/resServer"
|
||||
name: res-server
|
||||
- mountPath: "/app/config"
|
||||
name: game-config
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: master-service
|
||||
spec:
|
||||
selector:
|
||||
app: master-server
|
||||
ports:
|
||||
- name: master
|
||||
protocol: UDP
|
||||
port: 2000
|
||||
targetPort: master
|
17
k8s/kustomization.yml
Normal file
17
k8s/kustomization.yml
Normal file
@ -0,0 +1,17 @@
|
||||
resources:
|
||||
- mariadb.yml
|
||||
- ../resources
|
||||
- ../vanity
|
||||
- pod-template.yml
|
||||
- darkflame.yml
|
||||
secretGenerator:
|
||||
- name: db-secret
|
||||
literals:
|
||||
- DATABASE=darkflame
|
||||
- USER=darkflame # for MariaDB
|
||||
- USERNAME=darkflame # for DLU
|
||||
- PASSWORD=gjN@5#TTE&H&Yees5Q3a%tTC
|
||||
configMapGenerator:
|
||||
- name: env-common
|
||||
envs:
|
||||
- common.env
|
74
k8s/mariadb.yml
Normal file
74
k8s/mariadb.yml
Normal file
@ -0,0 +1,74 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: pv0001
|
||||
spec:
|
||||
storageClassName: manual
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
capacity:
|
||||
storage: 5Gi
|
||||
hostPath:
|
||||
path: /data/pv0001/
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: db-pv-claim
|
||||
spec:
|
||||
storageClassName: manual
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 3Gi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: mariadb-deployment
|
||||
labels:
|
||||
app: mariadb
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: mariadb
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: mariadb
|
||||
spec:
|
||||
volumes:
|
||||
- name: db-pv-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: db-pv-claim
|
||||
containers:
|
||||
- name: mariadb
|
||||
image: mariadb:11
|
||||
ports:
|
||||
- containerPort: 3306
|
||||
name: tcp-db-svc
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: db-secret
|
||||
prefix: MARIADB_
|
||||
env:
|
||||
- name: MARIADB_RANDOM_ROOT_PASSWORD
|
||||
value: "1"
|
||||
volumeMounts:
|
||||
- mountPath: "/var/lib/mysql"
|
||||
name: db-pv-storage
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: mariadb-service
|
||||
spec:
|
||||
selector:
|
||||
app: mariadb
|
||||
ports:
|
||||
- name: mariadb
|
||||
protocol: TCP
|
||||
port: 3306
|
||||
targetPort: tcp-db-svc
|
50
k8s/pod-template.yml
Normal file
50
k8s/pod-template.yml
Normal file
@ -0,0 +1,50 @@
|
||||
apiVersion: v1
|
||||
kind: PodTemplate
|
||||
metadata:
|
||||
name: pod-template
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: darkflame-server
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
volumes:
|
||||
- name: game-config
|
||||
configMap:
|
||||
name: game-config
|
||||
- name: vanity
|
||||
configMap:
|
||||
name: vanity
|
||||
- name: luclient
|
||||
hostPath:
|
||||
path: /luclient
|
||||
- name: res-server
|
||||
hostPath:
|
||||
path: /resServer
|
||||
containers:
|
||||
- name: darkflame-server
|
||||
image: ghcr.io/darkflameuniverse/darkflameserver
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
protocol: UDP
|
||||
name: raknet
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: env-common
|
||||
- secretRef:
|
||||
name: db-secret
|
||||
prefix: MYSQL_
|
||||
volumeMounts:
|
||||
- mountPath: "/app/res"
|
||||
readOnly: true
|
||||
name: luclient
|
||||
- mountPath: "/app/resServer"
|
||||
readOnly: true
|
||||
name: res-server
|
||||
- mountPath: "/app/config"
|
||||
readOnly: true
|
||||
name: game-config
|
||||
- mountPath: "/app/vanity"
|
||||
readOnly: true
|
||||
name: vanity
|
8
resources/kustomization.yml
Normal file
8
resources/kustomization.yml
Normal file
@ -0,0 +1,8 @@
|
||||
configMapGenerator:
|
||||
- name: game-config
|
||||
files:
|
||||
- authconfig.ini
|
||||
- chatconfig.ini
|
||||
- masterconfig.ini
|
||||
- sharedconfig.ini
|
||||
- worldconfig.ini
|
1
thirdparty/CMakeMariaDBLists.txt
vendored
1
thirdparty/CMakeMariaDBLists.txt
vendored
@ -94,6 +94,7 @@ else() # Build from source
|
||||
${MARIADB_EXTRA_CMAKE_ARGS}
|
||||
PREFIX "${PROJECT_BINARY_DIR}/mariadbcpp"
|
||||
BUILD_COMMAND cmake --build . --config RelWithDebInfo -j${MARIADB_CONNECTOR_COMPILE_JOBS}
|
||||
BUILD_ALWAYS true
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
ExternalProject_Get_Property(mariadb_connector_cpp BINARY_DIR)
|
||||
|
1
thirdparty/kubernetes-client-c
vendored
Submodule
1
thirdparty/kubernetes-client-c
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 131583107a939acf455f7df3bc9e3738981c310f
|
7
vanity/kustomization.yml
Normal file
7
vanity/kustomization.yml
Normal file
@ -0,0 +1,7 @@
|
||||
configMapGenerator:
|
||||
- name: vanity
|
||||
files:
|
||||
- CREDITS.md
|
||||
- INFO.md
|
||||
- NPC.xml
|
||||
- TESTAMENT.md
|
Loading…
Reference in New Issue
Block a user