From 166a283c70b4a3c052c720f409ab0601de806c5d Mon Sep 17 00:00:00 2001 From: Xiphoseer Date: Tue, 2 Jan 2024 00:34:43 +0100 Subject: [PATCH] feat(k8s): mvp --- .gitmodules | 3 + dCommon/Diagnostics.cpp | 3 +- dMasterServer/CMakeLists.txt | 18 +- dMasterServer/MasterServer.cpp | 3 + dMasterServer/StartK8s.cpp | 288 +++++++++++++++++++++++++++++++ k8s/DLU.Dockerfile | 50 ++++++ k8s/README.md | 26 +++ k8s/common.env | 4 + k8s/darkflame.yml | 94 ++++++++++ k8s/kustomization.yml | 17 ++ k8s/mariadb.yml | 74 ++++++++ k8s/pod-template.yml | 50 ++++++ resources/kustomization.yml | 8 + thirdparty/CMakeMariaDBLists.txt | 1 + thirdparty/kubernetes-client-c | 1 + vanity/kustomization.yml | 7 + 16 files changed, 642 insertions(+), 5 deletions(-) create mode 100644 dMasterServer/StartK8s.cpp create mode 100644 k8s/DLU.Dockerfile create mode 100644 k8s/README.md create mode 100644 k8s/common.env create mode 100644 k8s/darkflame.yml create mode 100644 k8s/kustomization.yml create mode 100644 k8s/mariadb.yml create mode 100644 k8s/pod-template.yml create mode 100644 resources/kustomization.yml create mode 160000 thirdparty/kubernetes-client-c create mode 100644 vanity/kustomization.yml diff --git a/.gitmodules b/.gitmodules index 700e7536..08a7a0dc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/dCommon/Diagnostics.cpp b/dCommon/Diagnostics.cpp index 46c17e43..279e86d9 100644 --- a/dCommon/Diagnostics.cpp +++ b/dCommon/Diagnostics.cpp @@ -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); } diff --git a/dMasterServer/CMakeLists.txt b/dMasterServer/CMakeLists.txt index 2ebdee37..a15edb35 100644 --- a/dMasterServer/CMakeLists.txt +++ b/dMasterServer/CMakeLists.txt @@ -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() diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index fbece646..4fe95577 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -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; diff --git a/dMasterServer/StartK8s.cpp b/dMasterServer/StartK8s.cpp new file mode 100644 index 00000000..05cf03c7 --- /dev/null +++ b/dMasterServer/StartK8s.cpp @@ -0,0 +1,288 @@ +#include "Start.h" +#include "Logger.h" + +extern "C" { +#include +#include +#include +#include +#include +#include +} + +#include +#include +#include + +namespace k8s { + using DaemonSet = std::unique_ptr; + using Deployment = std::unique_ptr; + using PodSpec = std::unique_ptr; + using Pod = std::unique_ptr; +} + +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& args); +}; + +k8s::PodSpec ApiClient::CreatePodSpec(const std::string& entrypoint, int container_port, int host_port, const std::vector& 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 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 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"); +} diff --git a/k8s/DLU.Dockerfile b/k8s/DLU.Dockerfile new file mode 100644 index 00000000..0100351b --- /dev/null +++ b/k8s/DLU.Dockerfile @@ -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"] diff --git a/k8s/README.md b/k8s/README.md new file mode 100644 index 00000000..6601366d --- /dev/null +++ b/k8s/README.md @@ -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 +``` diff --git a/k8s/common.env b/k8s/common.env new file mode 100644 index 00000000..30bfcec7 --- /dev/null +++ b/k8s/common.env @@ -0,0 +1,4 @@ +EXTERNAL_IP=192.168.39.84 +MYSQL_HOST=mariadb-service +MASTER_IP=master-service +DLU_CONFIG_DIR=/app/config diff --git a/k8s/darkflame.yml b/k8s/darkflame.yml new file mode 100644 index 00000000..a88f11ef --- /dev/null +++ b/k8s/darkflame.yml @@ -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 diff --git a/k8s/kustomization.yml b/k8s/kustomization.yml new file mode 100644 index 00000000..963cd676 --- /dev/null +++ b/k8s/kustomization.yml @@ -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 diff --git a/k8s/mariadb.yml b/k8s/mariadb.yml new file mode 100644 index 00000000..338015e7 --- /dev/null +++ b/k8s/mariadb.yml @@ -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 diff --git a/k8s/pod-template.yml b/k8s/pod-template.yml new file mode 100644 index 00000000..995acaf1 --- /dev/null +++ b/k8s/pod-template.yml @@ -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 \ No newline at end of file diff --git a/resources/kustomization.yml b/resources/kustomization.yml new file mode 100644 index 00000000..30891b90 --- /dev/null +++ b/resources/kustomization.yml @@ -0,0 +1,8 @@ +configMapGenerator: +- name: game-config + files: + - authconfig.ini + - chatconfig.ini + - masterconfig.ini + - sharedconfig.ini + - worldconfig.ini diff --git a/thirdparty/CMakeMariaDBLists.txt b/thirdparty/CMakeMariaDBLists.txt index d7a17f28..c68fcdb3 100644 --- a/thirdparty/CMakeMariaDBLists.txt +++ b/thirdparty/CMakeMariaDBLists.txt @@ -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) diff --git a/thirdparty/kubernetes-client-c b/thirdparty/kubernetes-client-c new file mode 160000 index 00000000..13158310 --- /dev/null +++ b/thirdparty/kubernetes-client-c @@ -0,0 +1 @@ +Subproject commit 131583107a939acf455f7df3bc9e3738981c310f diff --git a/vanity/kustomization.yml b/vanity/kustomization.yml new file mode 100644 index 00000000..3ec01a51 --- /dev/null +++ b/vanity/kustomization.yml @@ -0,0 +1,7 @@ +configMapGenerator: +- name: vanity + files: + - CREDITS.md + - INFO.md + - NPC.xml + - TESTAMENT.md