Files
Minikura/packages/k8s-operator/src/resources/reverseProxyServer.ts
T

231 lines
6.7 KiB
TypeScript
Raw Normal View History

2026-01-16 12:32:36 +07:00
import type * as k8s from "@kubernetes/client-node";
import type { ReverseProxyServerType } from "@minikura/db";
import { LABEL_PREFIX } from "../config/constants";
2026-02-17 18:12:02 +07:00
import { DEFAULT_PROXY_MEMORY, JAVA_MEMORY_FACTOR } from "../config/resource-defaults";
2026-01-16 12:32:36 +07:00
import type { ReverseProxyConfig } from "../types";
2026-02-17 18:12:02 +07:00
import { logger } from "../utils/logger";
import { calculateJavaMemory, convertToK8sFormat } from "../utils/memory";
import { mapServiceType } from "../utils/service-type";
2025-05-12 12:34:09 +07:00
export async function createReverseProxyServer(
server: ReverseProxyConfig,
appsApi: k8s.AppsV1Api,
coreApi: k8s.CoreV1Api,
2026-02-13 15:52:13 +07:00
_networkingApi: k8s.NetworkingV1Api,
2025-05-12 12:34:09 +07:00
namespace: string
): Promise<void> {
2026-02-17 18:12:02 +07:00
logger.debug(
{ proxyId: server.id, proxyType: server.type, namespace },
"Creating reverse proxy server"
);
2026-01-16 12:32:36 +07:00
2025-05-12 12:34:09 +07:00
const serverType = server.type.toLowerCase();
const serverName = `${serverType}-${server.id}`;
2026-01-16 12:32:36 +07:00
2025-05-12 12:34:09 +07:00
const configMap = {
2026-01-16 12:32:36 +07:00
apiVersion: "v1",
kind: "ConfigMap",
2025-05-12 12:34:09 +07:00
metadata: {
name: `${serverName}-config`,
namespace: namespace,
labels: {
app: serverName,
[`${LABEL_PREFIX}/server-type`]: serverType,
[`${LABEL_PREFIX}/proxy-id`]: server.id,
2026-01-16 12:32:36 +07:00
},
2025-05-12 12:34:09 +07:00
},
data: {
2026-01-16 12:32:36 +07:00
"minikura-api-key": server.apiKey,
},
2025-05-12 12:34:09 +07:00
};
2026-01-16 12:32:36 +07:00
2025-05-12 12:34:09 +07:00
try {
2026-02-13 15:52:13 +07:00
await coreApi.createNamespacedConfigMap({ namespace, body: configMap });
2026-02-17 18:12:02 +07:00
logger.debug({ proxyId: server.id, resource: "ConfigMap" }, "Created ConfigMap");
2025-05-12 12:34:09 +07:00
} catch (error: any) {
2026-02-17 18:12:02 +07:00
if (error.code === 409) {
await coreApi.replaceNamespacedConfigMap({
name: `${serverName}-config`,
namespace,
body: configMap,
});
logger.debug({ proxyId: server.id, resource: "ConfigMap" }, "Updated ConfigMap");
2025-05-12 12:34:09 +07:00
} else {
throw error;
}
}
2026-01-16 12:32:36 +07:00
2025-05-12 12:34:09 +07:00
const service = {
2026-01-16 12:32:36 +07:00
apiVersion: "v1",
kind: "Service",
2025-05-12 12:34:09 +07:00
metadata: {
name: serverName,
namespace: namespace,
labels: {
app: serverName,
[`${LABEL_PREFIX}/server-type`]: serverType,
[`${LABEL_PREFIX}/proxy-id`]: server.id,
2026-01-16 12:32:36 +07:00
},
2025-05-12 12:34:09 +07:00
},
spec: {
selector: {
app: serverName,
},
ports: [
{
port: server.external_port,
targetPort: server.listen_port,
2026-01-16 12:32:36 +07:00
protocol: "TCP",
name: "minecraft",
},
2025-05-12 12:34:09 +07:00
],
2026-02-17 18:12:02 +07:00
type: mapServiceType(server.service_type, "LoadBalancer"),
2026-01-16 12:32:36 +07:00
},
2025-05-12 12:34:09 +07:00
};
2026-01-16 12:32:36 +07:00
2025-05-12 12:34:09 +07:00
try {
2026-02-13 15:52:13 +07:00
await coreApi.createNamespacedService({ namespace, body: service });
2026-02-17 18:12:02 +07:00
logger.debug({ proxyId: server.id, resource: "Service" }, "Created Service");
2025-05-12 12:34:09 +07:00
} catch (error: any) {
2026-02-17 18:12:02 +07:00
if (error.code === 409) {
2026-02-13 15:52:13 +07:00
await coreApi.replaceNamespacedService({ name: serverName, namespace, body: service });
2026-02-17 18:12:02 +07:00
logger.debug({ proxyId: server.id, resource: "Service" }, "Updated Service");
2025-05-12 12:34:09 +07:00
} else {
throw error;
}
}
2026-01-16 12:32:36 +07:00
2025-05-12 12:34:09 +07:00
const deployment = {
2026-01-16 12:32:36 +07:00
apiVersion: "apps/v1",
kind: "Deployment",
2025-05-12 12:34:09 +07:00
metadata: {
name: serverName,
namespace: namespace,
labels: {
app: serverName,
[`${LABEL_PREFIX}/server-type`]: serverType,
[`${LABEL_PREFIX}/proxy-id`]: server.id,
2026-01-16 12:32:36 +07:00
},
2025-05-12 12:34:09 +07:00
},
spec: {
replicas: 1,
selector: {
matchLabels: {
app: serverName,
2026-01-16 12:32:36 +07:00
},
2025-05-12 12:34:09 +07:00
},
template: {
metadata: {
labels: {
app: serverName,
[`${LABEL_PREFIX}/server-type`]: serverType,
[`${LABEL_PREFIX}/proxy-id`]: server.id,
2026-01-16 12:32:36 +07:00
},
2025-05-12 12:34:09 +07:00
},
spec: {
containers: [
{
name: serverType,
2026-01-16 12:32:36 +07:00
image: "itzg/mc-proxy:latest",
2025-05-12 12:34:09 +07:00
ports: [
{
containerPort: server.listen_port,
2026-01-16 12:32:36 +07:00
name: "minecraft",
},
2025-05-12 12:34:09 +07:00
],
env: [
{
2026-01-16 12:32:36 +07:00
name: "TYPE",
2025-05-12 12:34:09 +07:00
value: server.type,
},
{
2026-01-16 12:32:36 +07:00
name: "NETWORKADDRESS_CACHE_TTL",
value: "30",
2025-05-12 12:34:09 +07:00
},
{
2026-01-16 12:32:36 +07:00
name: "MEMORY",
2026-02-17 18:12:02 +07:00
value: calculateJavaMemory(
server.memory || DEFAULT_PROXY_MEMORY,
JAVA_MEMORY_FACTOR
),
2025-05-12 12:34:09 +07:00
},
2026-01-16 12:32:36 +07:00
...(server.env_variables || []).map((ev) => ({
2025-05-12 12:34:09 +07:00
name: ev.key,
value: ev.value,
})),
],
readinessProbe: {
tcpSocket: {
2026-01-16 12:32:36 +07:00
port: server.listen_port,
2025-05-12 12:34:09 +07:00
},
initialDelaySeconds: 30,
periodSeconds: 10,
},
resources: {
requests: {
2026-02-17 18:12:02 +07:00
memory: convertToK8sFormat(server.memory || DEFAULT_PROXY_MEMORY),
2025-05-12 12:34:09 +07:00
cpu: "250m",
},
limits: {
2026-02-17 18:12:02 +07:00
memory: convertToK8sFormat(server.memory || DEFAULT_PROXY_MEMORY),
2025-05-12 12:34:09 +07:00
cpu: "500m",
2026-01-16 12:32:36 +07:00
},
},
},
],
},
},
},
2025-05-12 12:34:09 +07:00
};
2026-01-16 12:32:36 +07:00
2025-05-12 12:34:09 +07:00
try {
2026-02-13 15:52:13 +07:00
await appsApi.createNamespacedDeployment({ namespace, body: deployment });
2026-02-17 18:12:02 +07:00
logger.debug({ proxyId: server.id, resource: "Deployment" }, "Created Deployment");
2025-05-12 12:34:09 +07:00
} catch (error: any) {
2026-02-17 18:12:02 +07:00
if (error.code === 409) {
2026-02-13 15:52:13 +07:00
await appsApi.replaceNamespacedDeployment({ name: serverName, namespace, body: deployment });
2026-02-17 18:12:02 +07:00
logger.debug({ proxyId: server.id, resource: "Deployment" }, "Updated Deployment");
2025-05-12 12:34:09 +07:00
} else {
throw error;
}
}
}
export async function deleteReverseProxyServer(
proxyId: string,
proxyType: ReverseProxyServerType,
appsApi: k8s.AppsV1Api,
coreApi: k8s.CoreV1Api,
namespace: string
): Promise<void> {
const serverType = proxyType.toLowerCase();
const name = `${serverType}-${proxyId}`;
2026-01-16 12:32:36 +07:00
2025-05-12 12:34:09 +07:00
try {
2026-02-13 15:52:13 +07:00
await appsApi.deleteNamespacedDeployment({ name, namespace });
2026-02-17 18:12:02 +07:00
logger.debug({ proxyId, resource: "Deployment" }, "Deleted Deployment");
2025-05-12 12:34:09 +07:00
} catch (error: any) {
if (error.response?.statusCode !== 404) {
2026-02-17 18:12:02 +07:00
logger.error({ err: error, proxyId, resource: "Deployment" }, "Failed to delete Deployment");
2025-05-12 12:34:09 +07:00
}
}
2026-01-16 12:32:36 +07:00
2025-05-12 12:34:09 +07:00
try {
2026-02-13 15:52:13 +07:00
await coreApi.deleteNamespacedService({ name, namespace });
2026-02-17 18:12:02 +07:00
logger.debug({ proxyId, resource: "Service" }, "Deleted Service");
2025-05-12 12:34:09 +07:00
} catch (error: any) {
if (error.response?.statusCode !== 404) {
2026-02-17 18:12:02 +07:00
logger.error({ err: error, proxyId, resource: "Service" }, "Failed to delete Service");
2025-05-12 12:34:09 +07:00
}
}
2026-01-16 12:32:36 +07:00
2025-05-12 12:34:09 +07:00
try {
2026-02-13 15:52:13 +07:00
await coreApi.deleteNamespacedConfigMap({ name: `${name}-config`, namespace });
2026-02-17 18:12:02 +07:00
logger.debug({ proxyId, resource: "ConfigMap" }, "Deleted ConfigMap");
2025-05-12 12:34:09 +07:00
} catch (error: any) {
if (error.response?.statusCode !== 404) {
2026-02-17 18:12:02 +07:00
logger.error({ err: error, proxyId, resource: "ConfigMap" }, "Failed to delete ConfigMap");
2025-05-12 12:34:09 +07:00
}
}
2026-01-16 12:32:36 +07:00
}