# Template variables (rendered by Jenkins `envsubst "$K8S_RENDER_VARS"`): # KRA_APP application name, derives every resource name # KRA_NAMESPACE target namespace # KRA_ENV development | production # KRA_REPLICAS replicas per deployment # KRA_FRONTEND_NODEPORT node port for the frontend service # KRA_BACKEND_NODEPORT node port for the backend debug service # KRA_MYSQL_IMAGE mysql server image # KRA_REDIS_IMAGE redis server image # KRA_BACKEND_IMAGE backend image built by Jenkins # KRA_FRONTEND_IMAGE frontend image built by Jenkins # BIN_NAME backend binary name inside the image apiVersion: v1 kind: Namespace metadata: name: ${KRA_NAMESPACE} labels: app.kubernetes.io/part-of: ${KRA_APP} app.kubernetes.io/managed-by: jenkins --- apiVersion: apps/v1 kind: StatefulSet metadata: name: ${KRA_APP}-mysql namespace: ${KRA_NAMESPACE} labels: app.kubernetes.io/name: ${KRA_APP}-mysql app.kubernetes.io/part-of: ${KRA_APP} spec: serviceName: ${KRA_APP}-mysql replicas: 1 selector: matchLabels: app.kubernetes.io/name: ${KRA_APP}-mysql template: metadata: labels: app.kubernetes.io/name: ${KRA_APP}-mysql app.kubernetes.io/part-of: ${KRA_APP} spec: containers: - name: mysql image: ${KRA_MYSQL_IMAGE} imagePullPolicy: IfNotPresent ports: - name: mysql containerPort: 3306 env: - name: MYSQL_DATABASE value: ${KRA_APP} - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: ${KRA_APP}-runtime key: mysql-root-password volumeMounts: - name: mysql-data mountPath: /var/lib/mysql readinessProbe: exec: command: ["sh", "-c", "mysqladmin ping -h 127.0.0.1 -uroot -p\"$MYSQL_ROOT_PASSWORD\" --silent"] initialDelaySeconds: 20 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 12 livenessProbe: exec: command: ["sh", "-c", "mysqladmin ping -h 127.0.0.1 -uroot -p\"$MYSQL_ROOT_PASSWORD\" --silent"] initialDelaySeconds: 60 periodSeconds: 20 timeoutSeconds: 5 resources: requests: cpu: 250m memory: 512Mi limits: cpu: 1 memory: 2Gi volumes: - name: mysql-data hostPath: path: /var/lib/${KRA_APP}/mysql type: DirectoryOrCreate --- apiVersion: v1 kind: Service metadata: name: ${KRA_APP}-redis namespace: ${KRA_NAMESPACE} spec: selector: app.kubernetes.io/name: ${KRA_APP}-redis ports: - name: redis port: 6379 targetPort: redis --- apiVersion: apps/v1 kind: Deployment metadata: name: ${KRA_APP}-redis namespace: ${KRA_NAMESPACE} labels: app.kubernetes.io/name: ${KRA_APP}-redis app.kubernetes.io/part-of: ${KRA_APP} spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: ${KRA_APP}-redis template: metadata: labels: app.kubernetes.io/name: ${KRA_APP}-redis app.kubernetes.io/part-of: ${KRA_APP} spec: containers: - name: redis image: ${KRA_REDIS_IMAGE} imagePullPolicy: IfNotPresent ports: - name: redis containerPort: 6379 command: ["redis-server", "--appendonly", "yes"] volumeMounts: - name: redis-data mountPath: /data readinessProbe: exec: command: ["redis-cli", "ping"] initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: exec: command: ["redis-cli", "ping"] initialDelaySeconds: 15 periodSeconds: 20 resources: requests: cpu: 50m memory: 64Mi limits: cpu: 250m memory: 512Mi volumes: - name: redis-data hostPath: path: /var/lib/${KRA_APP}/redis type: DirectoryOrCreate --- apiVersion: apps/v1 kind: Deployment metadata: name: ${KRA_APP}-backend namespace: ${KRA_NAMESPACE} labels: app.kubernetes.io/name: ${KRA_APP}-backend app.kubernetes.io/part-of: ${KRA_APP} spec: replicas: ${KRA_REPLICAS} revisionHistoryLimit: 3 strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 1 maxSurge: 1 selector: matchLabels: app.kubernetes.io/name: ${KRA_APP}-backend template: metadata: labels: app.kubernetes.io/name: ${KRA_APP}-backend app.kubernetes.io/part-of: ${KRA_APP} spec: # /data/conf 由部署人员预先放置 config.yaml(见 deploy/k8s/config.example.yaml), # 目录必须可写:初始化向导会把数据库连接写回该文件。 imagePullSecrets: - name: harbor-registry affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: topologyKey: kubernetes.io/hostname labelSelector: matchLabels: app.kubernetes.io/name: ${KRA_APP}-backend containers: - name: backend image: ${KRA_BACKEND_IMAGE} imagePullPolicy: Always command: ["./${BIN_NAME}"] args: ["-conf", "/data/conf"] ports: - name: http containerPort: 8000 env: # 数据库连接不在这里注入:应用启动时未配置数据库会进入 bootstrap 模式, # 首页出现"前往初始化",由 /init/initdb 建表、写入种子数据并持久化连接配置。 # 只注入 JWT 签名密钥;Redis 地址已在下方 config.yaml 中指定。 - name: KRA_ADMIN_JWT_SIGNING_KEY valueFrom: secretKeyRef: name: ${KRA_APP}-runtime key: jwt-signing-key - name: KRA_ADMIN_SYSTEM_USE_REDIS value: "true" volumeMounts: - name: conf mountPath: /data/conf - name: uploads mountPath: /app/uploads readinessProbe: httpGet: path: /health port: http initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 6 livenessProbe: httpGet: path: /health port: http initialDelaySeconds: 30 periodSeconds: 20 timeoutSeconds: 3 failureThreshold: 3 resources: requests: cpu: 100m memory: 256Mi limits: cpu: 500m memory: 1Gi volumes: - name: conf hostPath: path: /var/lib/${KRA_APP}/conf type: DirectoryOrCreate - name: uploads emptyDir: {} --- apiVersion: v1 kind: Service metadata: name: ${KRA_APP}-backend namespace: ${KRA_NAMESPACE} labels: app.kubernetes.io/name: ${KRA_APP}-backend spec: type: ClusterIP selector: app.kubernetes.io/name: ${KRA_APP}-backend ports: - name: http port: 8000 targetPort: http --- apiVersion: v1 kind: Service metadata: name: ${KRA_APP}-backend-nodeport namespace: ${KRA_NAMESPACE} spec: type: NodePort selector: app.kubernetes.io/name: ${KRA_APP}-backend ports: - name: http port: 8000 targetPort: http nodePort: ${KRA_BACKEND_NODEPORT} --- apiVersion: apps/v1 kind: Deployment metadata: name: ${KRA_APP}-frontend namespace: ${KRA_NAMESPACE} labels: app.kubernetes.io/name: ${KRA_APP}-frontend app.kubernetes.io/part-of: ${KRA_APP} spec: replicas: ${KRA_REPLICAS} revisionHistoryLimit: 3 strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 1 maxSurge: 1 selector: matchLabels: app.kubernetes.io/name: ${KRA_APP}-frontend template: metadata: labels: app.kubernetes.io/name: ${KRA_APP}-frontend app.kubernetes.io/part-of: ${KRA_APP} spec: imagePullSecrets: - name: harbor-registry affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: topologyKey: kubernetes.io/hostname labelSelector: matchLabels: app.kubernetes.io/name: ${KRA_APP}-frontend containers: - name: frontend image: ${KRA_FRONTEND_IMAGE} imagePullPolicy: Always ports: - name: http containerPort: 80 readinessProbe: httpGet: path: / port: http initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: httpGet: path: / port: http initialDelaySeconds: 15 periodSeconds: 20 resources: requests: cpu: 50m memory: 64Mi limits: cpu: 250m memory: 256Mi --- apiVersion: v1 kind: Service metadata: name: ${KRA_APP}-frontend namespace: ${KRA_NAMESPACE} spec: type: NodePort selector: app.kubernetes.io/name: ${KRA_APP}-frontend ports: - name: http port: 80 targetPort: http nodePort: ${KRA_FRONTEND_NODEPORT}