最近将一个应用部署到 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