mirror of
https://github.com/YuzuZensai/Minikura.git
synced 2026-09-14 03:09:50 +00:00
✨ feat: k8s operator
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
import { NAMESPACE } from '../config/constants';
|
||||
|
||||
/**
|
||||
* Namespace definition
|
||||
*/
|
||||
export const minikuraNamespace = {
|
||||
apiVersion: 'v1',
|
||||
kind: 'Namespace',
|
||||
metadata: {
|
||||
name: NAMESPACE,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Service account
|
||||
*/
|
||||
export const minikuraServiceAccount = {
|
||||
apiVersion: 'v1',
|
||||
kind: 'ServiceAccount',
|
||||
metadata: {
|
||||
name: 'minikura-operator',
|
||||
namespace: NAMESPACE,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Cluster role
|
||||
*/
|
||||
export const minikuraClusterRole = {
|
||||
apiVersion: 'rbac.authorization.k8s.io/v1',
|
||||
kind: 'ClusterRole',
|
||||
metadata: {
|
||||
name: 'minikura-operator-role',
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
apiGroups: [''],
|
||||
resources: ['configmaps', 'services', 'secrets'],
|
||||
verbs: ['get', 'list', 'watch', 'create', 'update', 'patch', 'delete'],
|
||||
},
|
||||
{
|
||||
apiGroups: ['apps'],
|
||||
resources: ['deployments', 'statefulsets'],
|
||||
verbs: ['get', 'list', 'watch', 'create', 'update', 'patch', 'delete'],
|
||||
},
|
||||
{
|
||||
apiGroups: ['networking.k8s.io'],
|
||||
resources: ['ingresses'],
|
||||
verbs: ['get', 'list', 'watch', 'create', 'update', 'patch', 'delete'],
|
||||
},
|
||||
{
|
||||
apiGroups: ['apiextensions.k8s.io'],
|
||||
resources: ['customresourcedefinitions'],
|
||||
verbs: ['get', 'list', 'watch', 'create', 'update', 'patch', 'delete'],
|
||||
},
|
||||
{
|
||||
apiGroups: ['minikura.kirameki.cafe'],
|
||||
resources: ['minecraftservers', 'velocityproxies'],
|
||||
verbs: ['get', 'list', 'watch', 'create', 'update', 'patch', 'delete'],
|
||||
},
|
||||
{
|
||||
apiGroups: ['minikura.kirameki.cafe'],
|
||||
resources: ['minecraftservers/status', 'velocityproxies/status'],
|
||||
verbs: ['get', 'update', 'patch'],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* Cluster role binding
|
||||
*/
|
||||
export const minikuraClusterRoleBinding = {
|
||||
apiVersion: 'rbac.authorization.k8s.io/v1',
|
||||
kind: 'ClusterRoleBinding',
|
||||
metadata: {
|
||||
name: 'minikura-operator-role-binding',
|
||||
},
|
||||
subjects: [
|
||||
{
|
||||
kind: 'ServiceAccount',
|
||||
name: 'minikura-operator',
|
||||
namespace: NAMESPACE,
|
||||
},
|
||||
],
|
||||
roleRef: {
|
||||
kind: 'ClusterRole',
|
||||
name: 'minikura-operator-role',
|
||||
apiGroup: 'rbac.authorization.k8s.io',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Deployment for the Minikura operator
|
||||
*/
|
||||
export const minikuraOperatorDeployment = {
|
||||
apiVersion: 'apps/v1',
|
||||
kind: 'Deployment',
|
||||
metadata: {
|
||||
name: 'minikura-operator',
|
||||
namespace: NAMESPACE,
|
||||
},
|
||||
spec: {
|
||||
replicas: 1,
|
||||
selector: {
|
||||
matchLabels: {
|
||||
app: 'minikura-operator',
|
||||
},
|
||||
},
|
||||
template: {
|
||||
metadata: {
|
||||
labels: {
|
||||
app: 'minikura-operator',
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
serviceAccountName: 'minikura-operator',
|
||||
containers: [
|
||||
{
|
||||
name: 'operator',
|
||||
image: '${REGISTRY_URL}/minikura-operator:latest',
|
||||
env: [
|
||||
{
|
||||
name: 'DATABASE_URL',
|
||||
valueFrom: {
|
||||
secretKeyRef: {
|
||||
name: 'minikura-operator-secrets',
|
||||
key: 'DATABASE_URL',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'KUBERNETES_NAMESPACE',
|
||||
value: NAMESPACE,
|
||||
},
|
||||
{
|
||||
name: 'USE_CRDS',
|
||||
value: 'true',
|
||||
},
|
||||
],
|
||||
resources: {
|
||||
requests: {
|
||||
memory: '256Mi',
|
||||
cpu: '200m',
|
||||
},
|
||||
limits: {
|
||||
memory: '512Mi',
|
||||
cpu: '500m',
|
||||
},
|
||||
},
|
||||
livenessProbe: {
|
||||
exec: {
|
||||
command: ['bun', '-e', "console.log('Health check')"],
|
||||
},
|
||||
initialDelaySeconds: 30,
|
||||
periodSeconds: 30,
|
||||
},
|
||||
readinessProbe: {
|
||||
exec: {
|
||||
command: ['bun', '-e', "console.log('Ready check')"],
|
||||
},
|
||||
initialDelaySeconds: 5,
|
||||
periodSeconds: 10,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,156 @@
|
||||
import { API_GROUP, API_VERSION, RESOURCE_TYPES } from '../config/constants';
|
||||
|
||||
export const REVERSE_PROXY_SERVER_CRD = {
|
||||
apiVersion: 'apiextensions.k8s.io/v1',
|
||||
kind: 'CustomResourceDefinition',
|
||||
metadata: {
|
||||
name: `${RESOURCE_TYPES.REVERSE_PROXY_SERVER.plural}.${API_GROUP}`,
|
||||
},
|
||||
spec: {
|
||||
group: API_GROUP,
|
||||
versions: [
|
||||
{
|
||||
name: API_VERSION,
|
||||
served: true,
|
||||
storage: true,
|
||||
schema: {
|
||||
openAPIV3Schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
spec: {
|
||||
type: 'object',
|
||||
required: ['id', 'external_address', 'external_port'],
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
pattern: '^[a-zA-Z0-9-_]+$',
|
||||
description: 'ID of the reverse proxy server',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
description: 'Optional description of the server',
|
||||
},
|
||||
external_address: {
|
||||
type: 'string',
|
||||
description: 'External address of the proxy server',
|
||||
},
|
||||
external_port: {
|
||||
type: 'integer',
|
||||
minimum: 1,
|
||||
maximum: 65535,
|
||||
description: 'External port of the proxy server',
|
||||
},
|
||||
listen_port: {
|
||||
type: 'integer',
|
||||
minimum: 1,
|
||||
maximum: 65535,
|
||||
default: 25565,
|
||||
nullable: true,
|
||||
description: 'Port the proxy server listens on internally',
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
enum: ['VELOCITY', 'BUNGEECORD'],
|
||||
default: 'VELOCITY',
|
||||
nullable: true,
|
||||
description: 'Type of the reverse proxy server',
|
||||
},
|
||||
memory: {
|
||||
type: 'string',
|
||||
default: '512M',
|
||||
nullable: true,
|
||||
description: 'Memory allocation for the server',
|
||||
},
|
||||
environmentVariables: {
|
||||
type: 'array',
|
||||
nullable: true,
|
||||
items: {
|
||||
type: 'object',
|
||||
required: ['key', 'value'],
|
||||
properties: {
|
||||
key: {
|
||||
type: 'string',
|
||||
description: 'Environment variable key',
|
||||
},
|
||||
value: {
|
||||
type: 'string',
|
||||
description: 'Environment variable value',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
status: {
|
||||
type: 'object',
|
||||
nullable: true,
|
||||
properties: {
|
||||
phase: {
|
||||
type: 'string',
|
||||
enum: ['Pending', 'Running', 'Failed'],
|
||||
description: 'Current phase of the server',
|
||||
},
|
||||
message: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
description: 'Detailed message about the current status',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
description: 'API key for server communication',
|
||||
},
|
||||
internalId: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
description: 'Internal ID assigned by Minikura',
|
||||
},
|
||||
lastSyncedAt: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
description: 'Last time the server was synced with Kubernetes',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
additionalPrinterColumns: [
|
||||
{
|
||||
name: 'Type',
|
||||
type: 'string',
|
||||
jsonPath: '.spec.type',
|
||||
},
|
||||
{
|
||||
name: 'External Address',
|
||||
type: 'string',
|
||||
jsonPath: '.spec.external_address',
|
||||
},
|
||||
{
|
||||
name: 'External Port',
|
||||
type: 'integer',
|
||||
jsonPath: '.spec.external_port',
|
||||
},
|
||||
{
|
||||
name: 'Status',
|
||||
type: 'string',
|
||||
jsonPath: '.status.phase',
|
||||
},
|
||||
{
|
||||
name: 'Age',
|
||||
type: 'date',
|
||||
jsonPath: '.metadata.creationTimestamp',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
scope: 'Namespaced',
|
||||
names: {
|
||||
singular: RESOURCE_TYPES.REVERSE_PROXY_SERVER.singular,
|
||||
plural: RESOURCE_TYPES.REVERSE_PROXY_SERVER.plural,
|
||||
kind: RESOURCE_TYPES.REVERSE_PROXY_SERVER.kind,
|
||||
shortNames: RESOURCE_TYPES.REVERSE_PROXY_SERVER.shortNames,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,132 @@
|
||||
import { API_GROUP, API_VERSION, RESOURCE_TYPES } from '../config/constants';
|
||||
|
||||
export const MINECRAFT_SERVER_CRD = {
|
||||
apiVersion: 'apiextensions.k8s.io/v1',
|
||||
kind: 'CustomResourceDefinition',
|
||||
metadata: {
|
||||
name: `${RESOURCE_TYPES.MINECRAFT_SERVER.plural}.${API_GROUP}`,
|
||||
},
|
||||
spec: {
|
||||
group: API_GROUP,
|
||||
versions: [
|
||||
{
|
||||
name: API_VERSION,
|
||||
served: true,
|
||||
storage: true,
|
||||
schema: {
|
||||
openAPIV3Schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
spec: {
|
||||
type: 'object',
|
||||
required: ['id', 'type', 'listen_port'],
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
pattern: '^[a-zA-Z0-9-_]+$',
|
||||
description: 'ID of the Minecraft server',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
description: 'Optional description of the server',
|
||||
},
|
||||
listen_port: {
|
||||
type: 'integer',
|
||||
minimum: 1,
|
||||
maximum: 65535,
|
||||
description: 'Port the server listens on',
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
enum: ['STATEFUL', 'STATELESS'],
|
||||
description: 'Type of the server',
|
||||
},
|
||||
memory: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
default: '1G',
|
||||
description: 'Memory allocation for the server',
|
||||
},
|
||||
environmentVariables: {
|
||||
type: 'array',
|
||||
nullable: true,
|
||||
items: {
|
||||
type: 'object',
|
||||
required: ['key', 'value'],
|
||||
properties: {
|
||||
key: {
|
||||
type: 'string',
|
||||
description: 'Environment variable key',
|
||||
},
|
||||
value: {
|
||||
type: 'string',
|
||||
description: 'Environment variable value',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
status: {
|
||||
type: 'object',
|
||||
nullable: true,
|
||||
properties: {
|
||||
phase: {
|
||||
type: 'string',
|
||||
enum: ['Pending', 'Running', 'Failed'],
|
||||
description: 'Current phase of the server',
|
||||
},
|
||||
message: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
description: 'Detailed message about the current status',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
description: 'API key for server communication',
|
||||
},
|
||||
internalId: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
description: 'Internal ID assigned by Minikura',
|
||||
},
|
||||
lastSyncedAt: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
description: 'Last time the server was synced with Kubernetes',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
additionalPrinterColumns: [
|
||||
{
|
||||
name: 'Type',
|
||||
type: 'string',
|
||||
jsonPath: '.spec.type',
|
||||
},
|
||||
{
|
||||
name: 'Status',
|
||||
type: 'string',
|
||||
jsonPath: '.status.phase',
|
||||
},
|
||||
{
|
||||
name: 'Age',
|
||||
type: 'date',
|
||||
jsonPath: '.metadata.creationTimestamp',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
scope: 'Namespaced',
|
||||
names: {
|
||||
singular: RESOURCE_TYPES.MINECRAFT_SERVER.singular,
|
||||
plural: RESOURCE_TYPES.MINECRAFT_SERVER.plural,
|
||||
kind: RESOURCE_TYPES.MINECRAFT_SERVER.kind,
|
||||
shortNames: RESOURCE_TYPES.MINECRAFT_SERVER.shortNames,
|
||||
},
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user