传统的企业服务如何部署在k8s集群中
在云计算的浪潮下,Kubernetes(简称 K8s)已成为容器编排的 事实标准。那么传统的服务如何部署在容器中并且使用k8s来进行管理?今天,我们就在本地环境进行测试揭秘!
- k8s集群一套(集群挂载了NFS服务)。
- 安装了docker的主机一台(可以制作docker镜像)
- 源码一套(在这以gitee上的开源博客系统拾壹博客为例)
1.部署Mysql
该系统使用mysql数据库进行数据存储并利用redis进行数据缓存
step1:编写yaml文件来创建mysql所需的各种资源
vi mysql.yaml
##文件内容
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: default
spec:
capacity:
storage: 10Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs-mysql
nfs:
path: /nfs/mysql-data/
server: 192.168.5.129 #替换为你的 NFS 服务器 IP
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k8s-node1 # 替换为实际挂载了/nfs/mysql-data 的节点主机名
---------
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
namespace: default
spec:
storageClassName: nfs-mysql
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
namespace: default
labels:
app: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: docker.io/library/mysql:8.4.7
ports:
- containerPort: 3306
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456" # Mysql访问密码
- name: MYSQL_DATABASE
value: "myapp"
- name: MYSQL_USER
value: "myapp_user"
- name: MYSQL_PASSWORD
value: "123456" # Mysql访问密码
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
livenessProbe:
exec:
command: ["mysqladmin", "ping", "-h", "localhost"]
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
readinessProbe:
exec:
command: ["mysql", "-h", "localhost", "-u", "root", "-p$(MYSQL_ROOT_PASSWORD)", "-e", "SELECT 1"]
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
volumes:
- name: mysql-storage
persistentVolumeClaim:
claimName: mysql-pvc
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: mysql-service
namespace: default
spec:
selector:
app: mysql
ports:
- port: 3306 # 服务端口
targetPort: 3306 # Pod 端口
nodePort: 30006 # 节点映射端口 (30000-32767)
type: NodePort
#step2:以上文件创建后执行以下命令进行应用:
kubectl apply -f redis.yaml ##应用资源
kubectl get pods -o wide | grep redis ##查看pod进行成功运行
kubectl describe pod <pod-name> ##如果pod未成功运行使用此命令查看创建失败原因。
##配置文件说明:上边文件一共创建了4个k8s资源
1.数据存储说明(pv/pvc):mysql服务属于有状态的pod,且需要进行数据持久化存储来保证数据库数据不丢失。
2.deployment资源指定了pod的运行参数
3.service资源定义了pod的访问方式。

2.部署redis
step1:编写yaml文件来创建redis各种资源
vi redis.yaml
#文件内容
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: default
labels:
app: redis
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: docker.io/library/redis:6.2.6
ports:
- containerPort: 6379
name: redis
command:
- redis-server
- "--appendonly no" # 关闭持久化,因为不需要数据持久化
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "250m"
livenessProbe:
exec:
command: ["redis-cli", "ping"]
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
readinessProbe:
exec:
command: ["redis-cli", "ping"]
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: redis-service
namespace: default
spec:
selector:
app: redis
ports:
- port: 6379
targetPort: 6379
nodePort: 31790
type: NodePort
##以上文件创建后执行以下命令进行应用:
kubectl apply -f redis.yaml ##应用资源
kubectl get pods -o wide | grep redis ##查看pod进行成功运行
kubectl describe pod <pod-name> ##如果pod未成功运行使用此命令查看创建失败原因。
##配置文件说明:
1.deployment资源定义了pod的运行参数以及副本数还是redis的参数
2.service资源定义了pod内服务的访问方式。

3.导入源码到IDEA中并制作Dcoker镜像
根据实际情况修改图中标记的信息即可:

修改完成后,打包项目为jar包并上传到可以制作docker镜像的主机上:

制作镜像
#step1:编写制作镜像文件内容
vi dockerfile
#指定基础镜像版本
FROM openjdk:8-jdk
#指定工作目录
WORKDIR /app
#容器内安装相关命令
RUN apt-get update && \
apt-get install -y --no-install-recommends curl && \
apt-install net-tools \
apt-install vim \
rm -rf /var/lib/apt/lists/*
#将jar文件复制到容器的工作目录下
COPY ./mojian-blog-v2.0.0.jar app.jar
#配置容器时间(将宿主机相关文件映射到容器镜像中)
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
#暴露服务端口
EXPOSE 8800
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \
CMD curl -f http://localhost:8800/actuator/health || exit 1
##添加容器内服务运行脚本,容器创建后自动运行
ENTRYPOINT ["java", "-Xms512m", "-Xmx1024m", "-jar", "app.jar"]
#step2:制作镜像
docker build -t <镜像名>:<镜像版本>
docker build -t blog-server:v1.0.0
docker images #查看镜像是否制作完成。

保存本地镜像并上传至k8s集群中
#step1:保存本地镜像为.tar文件
docker save -o blog-server.tar blog-server:v1.0.0
#step2:上传镜像至k8s集群的所有node节点并导入镜像
docker load -i <tar文件>
docker load -i blog-server.tar
如果容器使用的是containerd则使用以下命令加载
ctr -n k8s.io images import blog-server.tar
注:由于在测试环境直接利用本地镜像导出和导入即可,也可在阿里云创建个人镜像仓库将制作完成的镜像推送至远程个人仓库,完了直接自动拉取即可。
$ docker login --username=echo crpi-o4vqz8nrivn0wa56.cn-hongkong.personal.cr.aliyuncs.com
$ docker tag [ImageId] crpi-o4vqz8nrivn0wa56.cn-hongkong.personal.cr.aliyuncs.com/echo-blog/blog-server:[镜像版本号]
$ docker push crpi-o4vqz8nrivn0wa56.cn-hongkong.personal.cr.aliyuncs.com/echo-blog/blog-server:[镜像版本号]
##1.登录到远程仓库
##2.将本地镜像定义标签
##3.推送本地镜像到远程仓库
##镜像拉取
$ docker pull crpi-o4vqz8nrivn0wa56.cn-hongkong.personal.cr.aliyuncs.com/echo-blog/blog:[镜像版本号]
$ ctr -n k8s.io images pull --user <仓库名>:仓库密码 crpi-o4vqz8nrivn0wa56.cn-hongkong.personal.cr.aliyuncs.com/blog-server:[版本号] ##containerd拉取命令

制作npm镜像
此系统前端和管理端使用了 vue2.0编写,在这需要经前端和管理端制作成镜像即可。
制作镜像前先修改管理端和前端连接后端服务的地址;修该blog-web与blog-admin下的/env.development文件的后端接口地址,在这由于是pod内部相互访问,直接配置成server-name+服务端口即可。

#step1:管理端镜像制作(blog-admin)
##镜像制作文件
FROM node:22.21.0-alpine
WORKDIR /app
COPY ./blog-admin /app
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
#安装依赖
RUN npm install
#暴露的端口
EXPOSE 3000
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost/ || exit 1
# 设置启动命令
CMD ["npm", "run", "dev"]
#step2:前端镜像制作(blog-web)
##镜像制作文件
FROM node:22.21.0-alpine
WORKDIR /app
COPY ./blog-web /app
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
#安装依赖
RUN npm install
#暴露的端口
EXPOSE 3000
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost/ || exit 1
# 设置启动命令
CMD ["npm", "run", "dev"]
注:1.将本地的blog-admin与blog-web文件夹分别打包上传至服务器进行解压缩。
2.先制作blog-admin镜像,根据上边dockerfile文件内容进行制作镜像;制作完毕在制作blog-web镜像。
3.镜像保存与上传,可采用制作blog-sever的方法进行镜像的保存和导入也可将制作的镜像上传至远程仓库,完了自动拉取即可。
4.创建后端管理端以及前端的Pod
4.1服务端pod创建
step1:编写资源文件
vi blog-server.yaml
##文件内容
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: blog-server
namespace: default # 可根据需要修改命名空间
spec:
replicas: 1
selector:
matchLabels:
app: blog-server
template:
metadata:
labels:
app: blog-server
spec:
containers:
- name: blog-server
image: docker.io/library/blog-server:v1.0.0 # 根据情况修改镜像地址即可
imagePullPolicy: IfNotPresent # 关键:避免尝试从远程拉取
ports:
- containerPort: 8800
protocol: TCP
resources:
limits:
memory: "1024Mi"
cpu: "500m"
requests:
memory: "512Mi"
cpu: "200m"
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: blog-server-svc #此名称要和修改的代码中连接后端服务的地址一致,不然前端无法请求后端
namespace: default
spec:
type: NodePort # 或 ClusterIP / LoadBalancer(根据环境)
ports:
- port: 8800
targetPort: 8800
nodePort: 30090 # 可选,范围 30000-32767
selector:
app: blog-server
step2:应用资源文件
kubectl apply -f blog-server.yaml ##应用资源
kubectl get pods -o wide #查看pod是否创建成功
kubectl get svc | grep blog-server #查看service是否创建成功
kubectl descrieb pod <pod-name> #如果Pod创建不成功可以使用此命令查看你event事件详细描述

4.2管理端pod创建
step1:编写pod资源文件
vi blog-admin.yaml
#文件内容
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: blog-admin
namespace: default
labels:
app: blog-admin
spec:
replicas: 1
selector:
matchLabels:
app: blog-admin
template:
metadata:
labels:
app: blog-admin
spec:
containers:
- name: blog-admin
image: crpi-o4vqz8nrivn0wa56.cn-hongkong.personal.cr.aliyuncs.com/echo-blog/blog-admin:v2.0.1 # 请替换为您的第一个镜像名称和标签
ports:
- containerPort: 3000
name: http
resources:
requests:
memory: "512Mi"
cpu: "200m"
limits:
memory: "1024Mi"
cpu: "200m"
---
apiVersion: v1
kind: Service
metadata:
name: blog-admin
namespace: default
spec:
selector:
app: blog-admin
ports:
- name: http
port: 3000 # Service端口
targetPort: 3000 # 容器端口
protocol: TCP
type: NodePort
step2:应用资源
kubectl apply -f blog-admin.yaml #创建资源
kubectl get pods | grep blog-admin #查看pod是否创建成功以及pod状态(running状态即为成功)
kubectl get svc | grep blog-admin #查看svc是否创建成功
kubectl descrieb pod <pod-name> #如果Pod创建不成功可以使用此命令查看你event事件详细描述

Pod如果创建成功,可以使用任意节点IP+NodePort访问测试 。


4.3前端镜像制作
step1:创建Pod以及其他资源
vi blog-web.yaml
#文件内容
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: blog-web
namespace: default
labels:
app: blog-web
spec:
replicas: 1
selector:
matchLabels:
app: blog-web
template:
metadata:
labels:
app: blog-web
spec:
containers:
- name: blog-web
image: crpi-o4vqz8nrivn0wa56.cn-hongkong.personal.cr.aliyuncs.com/echo-blog/blog-web:v2.0.1
ports:
- containerPort: 3001
name: http
resources:
requests:
memory: "512Mi"
cpu: "200m"
limits:
memory: "1024Mi"
cpu: "200m"
---
apiVersion: v1
kind: Service
metadata:
name: blog-web
namespace: default
spec:
selector:
app: blog-web
ports:
- name: http
port: 3001 # Service端口
targetPort: 3001 # 容器端口
protocol: TCP
type: NodePort
step2:资源应用
kubectl apply -f blog-web.yaml #创建资源
kubectl get pods -o wide | grep blog-web #创建pod是否创建成功以及状态
kubectl get svc | grep blog-web #查看service是否创建成功
kubectl descrieb pod <pod-name> #如果Pod创建不成功可以使用此命令查看你event事件详细描述

Pod如果创建成功,可以使用任意节点IP+NodePort访问测试。

生产环境部署建议
- Redis配置 :
"--appendonly no"(不持久化数据)可能造成数据丢失- 改进建议:根据业务需求决定是否需要持久化
1. 镜像管理问题
- 本地镜像导出导入 :这是不推荐 的生产环境做法
- 改进建议:使用私有镜像仓库(如Harbor、阿里云容器镜像服务)
2. 部署架构问题
- 单点故障 :所有服务都使用
replicas: 1,生产环境应至少部署2个副本- 改进建议 :将
replicas: 1改为replicas: 3(或根据业务需求调整)
- 改进建议 :将
- 服务暴露方式 :使用NodePort暴露服务(30000-32767端口范围)
- 改进建议:在生产环境中应使用Ingress控制器或LoadBalancer类型Service
3. 配置管理问题
- 硬编码配置 :前端配置中直接写后端地址(如
blog-server-svc.default.svc.cluster.local)- 改进建议:使用ConfigMap管理配置,而不是硬编码
4. 存储方案问题
- NFS存储 :使用NFS作为存储后端
- 改进建议 :NFS在生产环境中性能和可靠性可能不足,应考虑:
- 云存储(如阿里云EBS、Ceph)
- 更适合K8s的存储解决方案(如Rook、Longhorn)
- 改进建议 :NFS在生产环境中性能和可靠性可能不足,应考虑:
注:喜欢的话就点赞收藏吧