【Kubernetes】集群环境下的应用部署案例

最近将一个应用部署到 K8s 集群,并进行了详细记录,希望能对大家有所帮助该应用主要功能是简化加载地图的 WMTS 和 WMS,其架构采用 MySQL 作为后端数据库,后端使用 NestJS 来连接数据库,而前端则基于 Vue 实现用户界面展示。

GitHub 地址:https://gitee.com/geogy/wmts_wms_tools

  • 数据库:Mysql 8.0
  • 后端:Nestjs 10.0.0
  • 前端:Vue 3.5.13

1、制作 Docker 镜像

1.1、Mysql 数据库

bash 复制代码
###  Dockerfile ###
# 使用官方 MySQL 镜像
FROM mysql:8.0

# 设置环境变量
ENV MYSQL_DATABASE=mytool

# 将 SQL 脚本复制到 Docker 镜像中进行初始化
COPY *.sql /docker-entrypoint-initdb.d/

# 暴露 MySQL 默认端口
EXPOSE 3306

### 构建镜像 ###
docker build . -t mytool-db:v1

1.2、Nest 后端

bash 复制代码
### Dockerfile ###
# 使用官方的 Node.js 镜像作为基础镜像
FROM node:20.17.0-slim
 
# 设置工作目录
WORKDIR /data

# 复制项目打包文件到工作目录
COPY package*.json ./
COPY dist ./dist

# 安装依赖
RUN npm install

# 暴露端口
EXPOSE 3000

# 定义容器启动时执行命令运行项目
CMD ["npm","run","start:prod"]

### 构建镜像 ###
docker build . -t mytool-server:v1

1.3、vue 前端

bash 复制代码
###  Dockerfile ###
# Tomcat 基础镜像
FROM tomcat:10.1-jdk17

# 设置工作目录
WORKDIR /usr/local/tomcat/bin

# 删除默认的 webapps 内容
RUN rm -rf /usr/local/tomcat/webapps/*

# 复制项目文件到工作目录
COPY ./mytool /usr/local/tomcat/webapps/mytool
COPY ./ROOT  /usr/local/tomcat/webapps/ROOT

# 暴露端口(默认)
EXPOSE 8080

# 启动 Tomcat
CMD ["catalina.sh", "run"]

### 构建镜像 ###
docker build . -t mytool-ui:v1

2、编写 YAML

2.1、创建命名空间

bash 复制代码
# 命令:kubectl create ns mytool
apiVersion: v1
kind: Namespace
metadata:
  labels:
    kubernetes.io/metadata.name: mytool
  name: mytool

2.2、Secret / ConfigMap 配置

bash 复制代码
# 加密内容(如账号密码)使用 Secret 存储
# 非加密配置用 ConfigMap 存储

# 存储数据库 root 用户密码(base64 加密)
kind: Secret
apiVersion: v1
metadata:
  name: mytool-db-secret
  namespace: mytool
  labels:
    app: mytool-db
data:
  mysql.password: MTIzNDU2
  mysql.root.password: MTIzNDU2
  mysql.username: cm9vdA==
type: Opaque

# 后端 mytool-server 配置(配置前端跨域连接)
apiVersion: v1
kind: ConfigMap
metadata:
  name: mytool-server-conf
  namespace: mytool
data:
  .env: |
    SERVER_TITLE = WMTS/WMS-Tools Service
    # 运行端口
    SERVER_PORT = 3000
    # JWT配置
    JWT_SECRET = zheshimiyao
    JWT_EXP = 24h
    # 跨域白名单
    THITE_LIST = ['http://localhost:6060', 'http://127.0.0.1:6060'] 

# 前端 mytool-ui 配置(用于连接后端)
apiVersion: v1
kind: ConfigMap
metadata:
  name: mytool-ui-conf
  namespace: mytool
data:
  config.js: |
    window.serviceConfig = {
     dev: {
      url: 'http://localhost:3000/api'
     },
     test: {
      url: 'http://localhost:3000/api'
     },
     prod: {
      url: 'http://localhost:3000/api'
     }
    }

2.3、pv / pvc 挂载

bash 复制代码
# 实现数据库持久化
# 此处使用 hostPath 挂载(可结合 nfs 使用)
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-mytool
spec:
  capacity:
    storage: 2Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: /home/mytool
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-mytool-db
  namespace: mytool
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 2Gi
  volumeName: pv-mytool

2.4、为 Pod 绑定 Service

bash 复制代码
# 数据库 mytool-db -> Service
kind: Service
apiVersion: v1
metadata:
  name: mytool-db
  namespace: mytool
  labels:
    app: mytool-db
spec:
  ports:
  - protocol: TCP
    port: 3306
    targetPort: 3306
  selector:
    app: mytool-db
  type: ClusterIP

# 后端 mytool-server -> service
# NodePort 端口可结合实际修改(需同步修改 ConfigMap 中的地址)
kind: Service
apiVersion: v1
metadata:
  name: mytool-server
  namespace: mytool
  labels:
    app: mytool-server
spec:
  ports:
  - protocol: TCP
    port: 3000
    targetPort: 3000
    nodePort: 31111
  selector:
    app: mytool-server
  type: NodePort

# 前端 mytool-ui -> service
# NodePort 端口可结合实际修改(需同步修改 ConfigMap 中的地址)
kind: Service
apiVersion: v1
metadata:
  name: mytool-ui
  namespace: mytool
  labels:
    app: mytool-ui
spec:
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
    nodePort: 32222
  selector:
    app: mytool-ui
  type: NodePort

2.5、Deployment 部署应用

2.5.1、数据库 mytool-db

bash 复制代码
# 数据库 mytool-db
# 使用 secret 挂载 env 环境变量(root 用户密码)
# pv / pvc 持久化存储数据库数据
kind: Deployment
apiVersion: apps/v1
metadata:
  name: mytool-db
  namespace: mytool
  labels:
    app: mytool-db
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mytool-db
  template:
    metadata:
      labels:
        app: mytool-db
    spec:
      volumes:
        - name: mytool-db-volume
          persistentVolumeClaim:
            claimName: pvc-mytool-db
        - name: timezone
          hostPath:
            path: /etc/localtime
            type: ''
      containers:
        - name: mytool-db
          image: mytool-db:v1
          ports:
            - containerPort: 3306
              protocol: TCP
          env:
            - name: MYSQL_DATABASE
              value: mytool
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mytool-db-secret
                  key: mysql.root.password
          resources:
            limits:
              cpu: '1'
              memory: 1Gi
            requests:
              cpu: 200m
              memory: 200Mi
          volumeMounts:
            - name: timezone
              mountPath: /etc/localtime
            - name: timezone
              mountPath: /etc/timezone
            - name: mytool-db-volume
              mountPath: /var/lib/mysql
              subPath: mytool-db
          imagePullPolicy: IfNotPresent
          livenessProbe:
            exec:
              command:
                - /bin/sh
                - '-c'
                - mysql -u root -p$MYSQL_ROOT_PASSWORD -e 'SELECT 1'
            initialDelaySeconds: 15
            timeoutSeconds: 20
            periodSeconds: 30
            successThreshold: 1
            failureThreshold: 5
          readinessProbe:
            exec:
              command:
                - /bin/sh
                - '-c'
                - mysql -u root -p$MYSQL_ROOT_PASSWORD -e 'SELECT 1'
            initialDelaySeconds: 15
            timeoutSeconds: 20
            periodSeconds: 30
            successThreshold: 1
            failureThreshold: 5
      restartPolicy: Always    

2.5.2、后端 mytool-server

bash 复制代码
# 后端 mytool-server
# initContainers 等待数据库可用后再启动后端
# configMap 挂载后端连接信息配置
kind: Deployment
apiVersion: apps/v1
metadata:
  name: mytool-server
  namespace: mytool
  labels:
    app: mytool-server
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mytool-server
  template:
    metadata:
      labels:
        app: mytool-server
    spec:
      volumes:
        - name: timezone
          hostPath:
            path: /etc/localtime
            type: ''
        - name: mytool-server-env
          configMap:
            name: mytool-server-conf
      initContainers:
        - name: wait-for-mysql
          image: mytool-db:v1
          command: ['/bin/sh', '-c', 'until mysql -h$MYTOOL_DB_SERVICE_HOST -u root -p$MYSQL_ROOT_PASSWORD -e "SELECT 1"; do sleep 5; echo "等待 MySQL 启动..."; done; echo "MySQL 已启动...";']
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mytool-db-secret
                  key: mysql.root.password
          resources: {}
          imagePullPolicy: IfNotPresent
      containers:
        - name: mytool-server
          image: mytool-server:v1
          ports:
            - containerPort: 3000
              protocol: TCP
          command: ['/bin/sh', '-c', 'cp /tmp/env/.env /data/dist/env/.env; npm run start:prod']
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mytool-db-secret
                  key: mysql.root.password
          resources:
            limits:
              cpu: '1'
              memory: 1Gi
            requests:
              cpu: 200m
              memory: 200Mi
          livenessProbe:
            tcpSocket:
              port: 3000
            initialDelaySeconds: 50
            timeoutSeconds: 20
            periodSeconds: 30
            successThreshold: 1
            failureThreshold: 5
          readinessProbe:
            tcpSocket:
              port: 3000
            initialDelaySeconds: 50
            timeoutSeconds: 20
            periodSeconds: 30
            successThreshold: 1
            failureThreshold: 5
          volumeMounts:
            - name: timezone
              mountPath: /etc/localtime
            - name: timezone
              mountPath: /etc/timezone
            - name: mytool-server-env
              mountPath: /tmp/env
      restartPolicy: Always

2.5.3、前端 mytool-ui

bash 复制代码
# 前端 mytool-ui
# configMap 挂载后端连接配置
# startupProbe 探针检测后端服务是否可用
kind: Deployment
apiVersion: apps/v1
metadata:
  name: mytool-ui
  namespace: mytool
  labels:
    app: mytool-ui
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mytool-ui
  template:
    metadata:
      labels:
        app: mytool-ui
    spec:
      volumes:
        - name: timezone
          hostPath:
            path: /etc/localtime
            type: ''
        - name: mytool-ui-env
          configMap:
            name: mytool-ui-conf
      containers:
        - name: mytool-ui
          image: mytool-ui:v1
          command: ['/bin/sh', '-c', 'cp /tmp/config/config.js /usr/local/tomcat/webapps/mytool/config/config.js; catalina.sh run;']
          resources:
            limits:
              cpu: '1'
              memory: 1Gi
            requests:
              cpu: 200m
              memory: 200Mi
          ports:
            - containerPort: 8080
              protocol: TCP
          startupProbe:
            exec:
              command:
              - sh
              - -c
              - "curl -sSf $MYTOOL_SERVER_SERVICE_HOST:3000/api/code >/dev/null || exit 1"
            initialDelaySeconds: 50
            timeoutSeconds: 20
            periodSeconds: 30
            successThreshold: 1
            failureThreshold: 5
          livenessProbe:
            httpGet:
              path: /
              port: 8080
              scheme: HTTP
            initialDelaySeconds: 50
            timeoutSeconds: 20
            periodSeconds: 30
            successThreshold: 1
            failureThreshold: 5
          readinessProbe:
            httpGet:
              path: /
              port: 8080
              scheme: HTTP
            initialDelaySeconds: 50
            timeoutSeconds: 20
            periodSeconds: 30
            successThreshold: 1
            failureThreshold: 5
          volumeMounts:
            - name: timezone
              mountPath: /etc/localtime
            - name: timezone
              mountPath: /etc/timezone
            - name: mytool-ui-env
              mountPath: /tmp/config
      restartPolicy: Always
相关推荐
爱吃芝麻汤圆4 小时前
k8s之NDS解析到Ingress服务暴露
容器·kubernetes
东风微鸣7 小时前
职场生存指南:如何优雅应对"双面人"同事
docker·云原生·kubernetes·可观察性
云和数据.ChenGuang8 小时前
云计算k8s集群部署配置问题总结
云原生·容器·kubernetes·云计算
斯普信专业组8 小时前
k8s云原生rook-ceph pvc快照与恢复(下)
ceph·云原生·kubernetes
爱吃芝麻汤圆9 小时前
k8s之DevicePlugin
云原生·容器·kubernetes
David爱编程12 小时前
K8s 的工作机制原理:控制器如何“自动修复”
云原生·容器·kubernetes
David爱编程12 小时前
Kubernetes 中 StorageClass 高级用法与实战
云原生·容器·kubernetes
爱吃芝麻汤圆13 小时前
开源vGPU解决方案HAMi
kubernetes·开源·vgpu
斯普信专业组15 小时前
k8s云原生rook-ceph pvc快照与恢复(上)
ceph·云原生·kubernetes