SpringCloud项目迁移到k8s集群

SpringCloud项目迁移到k8s集群

一、项目迁移需求分析

现有一个SpringCloud项目需要迁移至Kubernetes,该项目采用Eureka注册中心,并采用前后端分离框架。该项目首页域名为demo.test.com,域名的主路径/转发至项目的前端,路径/receiveapi转发至网关服务,其他服务注册至Eureka,由网关服务进行流量转发。

1.1迁移Eureka集群

1.1.1代码构建及容器化

代码地址:https://gitee.com/liujunweipy/demo-eureka

构建命令:mvn clean package

Java 版本:jdk 1.8

构建镜像:registry.cn-beijing.aliyuncs.com/k8s-liujunwei/maven:3.5.3

下载源代码:

1
2
3
4
5
6
7
8
9
# 下载代码
[root@k8s-master01 18-SpringCloud]# git clone https://gitee.com/liujunweipy/demo-eureka.git
Cloning into 'demo-eureka'...
remote: Enumerating objects: 24, done.
remote: Counting objects: 100% (24/24), done.
remote: Compressing objects: 100% (15/15), done.
remote: Total 24 (delta 6), reused 24 (delta 6), pack-reused 0 (from 0)
Receiving objects: 100% (24/24), 6.82 KiB | 2.27 MiB/s, done.
Resolving deltas: 100% (6/6), done.

执行构建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#  把maven构建所依赖的插件持久化
[root@k8s-master01 18-SpringCloud]# mkdir -p /data/m2

# 运行一个maven临时容器进行代码的构建
# --rm: 自动清理。这意味退出容器后,Docker 会自动删除这个容器实例。这非常适合临时性的任务。
# -v:s 数据卷挂载,将宿主机的目录挂载到容器内,把宿主机`pwd`/demo-eureka目录挂载到容器的/mnt,把宿主机的/data/m2目录挂载到容器的/root/.m2目录。
# bash: 这是容器启动后立即执行的命令。它覆盖了镜像默认的 CMD 或 ENTRYPOINT。

[root@k8s-master01 18-SpringCloud]# docker run -ti --rm -v `pwd`/demo-eureka:/mnt -v /data/m2:/root/.m2 registry.cn-beijing.aliyuncs.com/k8s-liujunwei/maven:3.5.3 bash
Unable to find image 'registry.cn-beijing.aliyuncs.com/k8s-liujunwei/maven:3.5.3' locally
3.5.3: Pulling from k8s-liujunwei/maven
cc1a78bfd46b: Pull complete
d2c05365ee2a: Pull complete
231cb0e216d3: Pull complete
3d2aa70286b8: Pull complete
276ddd61a47b: Pull complete
2c60f2a0b551: Pull complete
4abbe5585c9b: Pull complete
aaeb39f0b473: Pull complete
a1ec96bfaf16: Pull complete
16d38ec4eb12: Pull complete
ff6759072b35: Pull complete
37a68c3b1fc7: Pull complete
Digest: sha256:d5c6b61f886178a925283918ac8984f963d279c9a3fdae813d6fc462fef1899c
Status: Downloaded newer image for registry.cn-beijing.aliyuncs.com/k8s-liujunwei/maven:3.5.3
root@70830096ac9f:/#

#进入到代码目录执行构建命令
root@70830096ac9f:/# cd /mnt/
root@70830096ac9f:/mnt# mvn clean package
Downloading from central: https://repo.maven.apache.org/maven2/com/google/guava/guava/19.0/guava-19.0.jar
Downloaded from central: https://repo.maven.apache.org/maven2/org/ow2/asm/asm-util/7.0-beta/asm-util-7.0-beta.jar (81 kB at 3.5 kB/s)
Downloaded from central: https://repo.maven.apache.org/maven2/org/jdom/jdom2/2.0.6/jdom2-2.0.6.jar (305 kB at 11 kB/s)
Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/maven-model/3.3.9/maven-model-3.3.9.jar (164 kB at 5.6 kB/s)
Downloaded from central: https://repo.maven.apache.org/maven2/org/vafer/jdependency/2.1.1/jdependency-2.1.1.jar (186 kB at 6.0 kB/s)
Downloaded from central: https://repo.maven.apache.org/maven2/com/google/guava/guava/19.0/guava-19.0.jar (2.3 MB at 42 kB/s)
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 23:18 min
[INFO] Finished at: 2025-12-14T07:41:21Z
[INFO] ------------------------------------------------------------------------

查看构建后的产物:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 构建完成后会在target目录中产生一个jar包,
root@70830096ac9f:/mnt# ls -l
total 12
-rw-r--r-- 1 root root 856 Dec 14 06:56 README.en.md
-rw-r--r-- 1 root root 945 Dec 14 06:56 README.md
-rw-r--r-- 1 root root 2399 Dec 14 06:56 pom.xml
drwxr-xr-x 3 root root 18 Dec 14 06:56 src
drwxr-xr-x 6 root root 189 Dec 14 07:41 target
root@70830096ac9f:/mnt# cd target/
root@70830096ac9f:/mnt/target# ls -l
total 46080
drwxr-xr-x 3 root root 86 Dec 14 07:37 classes
drwxr-xr-x 3 root root 25 Dec 14 07:37 generated-sources
drwxr-xr-x 2 root root 28 Dec 14 07:39 maven-archiver
drwxr-xr-x 3 root root 35 Dec 14 07:37 maven-status
-rw-r--r-- 1 root root 47179265 Dec 14 07:41 spring-cloud-eureka-0.0.1-SNAPSHOT.jar
-rw-r--r-- 1 root root 3964 Dec 14 07:39 spring-cloud-eureka-0.0.1-SNAPSHOT.jar.original

#因为做了目录映射,所以在宿主机的/root/18-SpringCloud/demo-eureka/target也有相同的文件
[root@k8s-master01 target]# ll
total 46080
drwxr-xr-x 3 root root 86 Dec 14 15:37 classes
drwxr-xr-x 3 root root 25 Dec 14 15:37 generated-sources
drwxr-xr-x 2 root root 28 Dec 14 15:39 maven-archiver
drwxr-xr-x 3 root root 35 Dec 14 15:37 maven-status
-rw-r--r-- 1 root root 47179265 Dec 14 15:41 spring-cloud-eureka-0.0.1-SNAPSHOT.jar
-rw-r--r-- 1 root root 3964 Dec 14 15:39 spring-cloud-eureka-0.0.1-SNAPSHOT.jar.original

spring-cloud-eureka-0.0.1-SNAPSHOT.jar制作镜像:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 进入项目目录
[root@k8s-master01 18-SpringCloud]# cd demo-eureka/

#准备Dockerfile
[root@k8s-master01 demo-eureka]# cat Dockerfile
FROM registry.cn-beijing.aliyuncs.com/k8s-liujunwei/openjdk:8u111-jdk
WORKDIR /home/app
COPY target/*.jar ./app.jar
CMD ["java", "-jar", "app.jar"]

# 制作镜像
[root@k8s-master01 demo-eureka]# docker build -t registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-eureka:v0.0.1 .

#查看制作好的镜像
[root@k8s-master01 demo-eureka]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-eureka v0.0.1 f47e60a46b3c About a minute ago 690MB

#推送到我自己的阿里云镜像仓库
[root@k8s-master01 demo-eureka]# docker push registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-eureka:v0.0.1
The push refers to repository [registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-eureka]
c8badce1e55f: Pushed
3ae57a88572b: Pushed
35c20f26d188: Mounted from k8s-liujunwei/openjdk
c3fe59dd9556: Mounted from k8s-liujunwei/openjdk
6ed1a81ba5b6: Mounted from k8s-liujunwei/openjdk
a3483ce177ce: Mounted from k8s-liujunwei/openjdk
ce6c8756685b: Mounted from k8s-liujunwei/openjdk
30339f20ced0: Mounted from k8s-liujunwei/openjdk
0eb22bfb707d: Mounted from k8s-liujunwei/openjdk
a2ae92ffcd29: Mounted from k8s-liujunwei/openjdk
v0.0.1: digest: sha256:aa2efcc1a7676f47b611a4f511abd5e4cb09ace4a1ae8efd9c704477c748843a size: 2419

1.1.2将demo-eureka 部署到k8s

在这个场景下(StatefulSet + Eureka 集群),必须要用 Headless Service。不能用普通 Service。

如果使用普通 Service(即有 ClusterIP 的 Service),Eureka 集群大概率会组建失败,或者数据同步出现严重问题。

为什么 Eureka 必须用Headless?

Eureka Server 之间的数据同步(Replication)是 Peer-to-Peer(点对点) 的,而不是简单的 Client-Server 模式。

如果用了普通 Service:

假设配置的地址是普通的 Service 地址 http://eureka-svc:8761

  1. Eureka-0 启动了,它想把自己注册给伙伴。
  2. 它向 eureka-svc 发送了一个请求:“嘿,我是 Eureka-0,这是我的数据,请同步一下。”
  3. K8s Service (总机) 拦截了这个请求,进行负载均衡
  4. 灾难发生:Service 可能会把这个请求转回给 Eureka-0 自己(因为 Eureka-0 也是 Service 后端的 Pod 之一)。
  5. 或者,Service 把请求转给了 Eureka-1。下一次心跳,它又转给了 Eureka-2。
  6. 后果:Eureka-0 认为它只有一个 Peer(就是那个 Service IP),它无法建立稳定的、全网状的(Mesh)连接。集群状态会变得混乱,数据不一致。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#该Service是一个Headless Service,用来组件eureka集群
kind: Service
apiVersion: v1
metadata:
name: demo-eureka
namespace: eureka
spec:
clusterIP: None
ports:
- port: 8761
targetPort: 8761
selector:
app: demo-eureka
---
# 该Service是用来暴露eureka服务,方便在web浏览器访问
kind: Service
apiVersion: v1
metadata:
name: demo-eureka-nodeport
namespace: eureka
spec:
type: NodePort
ports:
- port: 8761
targetPort: 8761
selector:
app: demo-eureka
---
# eureka服务使用StatefulSet部署
kind: StatefulSet
apiVersion: apps/v1
metadata:
name: demo-eureka
namespace: eureka
labels:
app: demo-eureka
spec:
replicas: 3
selector:
matchLabels:
app: demo-eureka
serviceName: demo-eureka
podManagementPolicy: Parallel
template:
metadata:
labels:
app: demo-eureka
spec:
containers:
- name: demo-eureka
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-eureka:v0.0.1
ports:
- containerPort: 8761
env:
- name: EUREKA_PORT
value: "8761"
- name: SPRING_PROFILES_ACTIVE
value: "k8s"
- name: EUREKA_SERVER_ADDRESS
value: http://demo-eureka-0.demo-eureka:8761/eureka,http://demo-eureka-1.demo-eureka:8761/eureka,http://demo-eureka-2.demo-eureka:8761/eureka
- name: EUREKA_SERVER_ENABLE_SELF_PRESERVATION
value: "false"
- name: EUREKA_SERVER_EVICTION_INTERVAL_TIMER_IN_MS
value: "500"
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 1000m
memory: 1Gi
imagePullPolicy: Always

部署服务:

1
2
3
4
5
#将eureka服务部署到独立的命名空间中
[root@k8s-master01 springcloud]# kubectl create ns eureka

#创建服务
[root@k8s-master01 springcloud]# kubectl create -f demo-eureka.StatefulSet.yaml

检查pod状态:

1
2
3
4
5
6
7
8
9
[root@k8s-master01 springcloud]# kubectl get po -n eureka
NAME READY STATUS RESTARTS AGE
demo-eureka-0 1/1 Running 0 5s
demo-eureka-1 1/1 Running 0 5s
demo-eureka-2 1/1 Running 0 5s
[root@k8s-master01 springcloud]# kubectl get svc -n eureka
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
demo-eureka ClusterIP None <none> 8761/TCP 14s
demo-eureka-nodeport NodePort 10.96.117.7 <none> 8761:31183/TCP 14s

浏览器可以通过demo-eureka-nodeport暴露的31183端口进行访问,如下图:

1.2迁移网关服务

1.2.1代码构建及容器化

代码地址:https://gitee.com/liujunweipy/demo-receive

构建命令:mvn clean package

Java 版本:jdk 1.8

构建镜像:registry.cn-beijing.aliyuncs.com/k8s-liujunwei/maven:3.5.3

下载源代码:

1
2
3
4
5
6
7
8
9
# 下载代码
[root@k8s-master01 18-SpringCloud]# git clone https://gitee.com/liujunweipy/demo-receive.git
Cloning into 'demo-receive'...
remote: Enumerating objects: 56, done.
remote: Counting objects: 100% (56/56), done.
remote: Compressing objects: 100% (36/36), done.
remote: Total 56 (delta 9), reused 56 (delta 9), pack-reused 0 (from 0)
Receiving objects: 100% (56/56), 9.52 KiB | 1.36 MiB/s, done.
Resolving deltas: 100% (9/9), done.

执行构建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#  把maven构建所依赖的插件持久化
[root@k8s-master01 18-SpringCloud]# mkdir -p /data/m2

# 运行一个maven临时容器进行代码的构建
# --rm: 自动清理。这意味退出容器后,Docker 会自动删除这个容器实例。这非常适合临时性的任务。
# -v:s 数据卷挂载,将宿主机的目录挂载到容器内,把宿主机`pwd`/demo-eureka目录挂载到容器的/mnt,把宿主机的/data/m2目录挂载到容器的/root/.m2目录。
# bash: 这是容器启动后立即执行的命令。它覆盖了镜像默认的 CMD 或 ENTRYPOINT。

[root@k8s-master01 18-SpringCloud]# docker run -ti --rm -v `pwd`/demo-receive:/mnt -v /data/m2/:/root/.m2 registry.cn-beijing.aliyuncs.com/k8s-liujunwei/maven:3.5.3 bash
root@7ceb1cf6a3da:/#

#进入到代码目录执行构建命令
root@7ceb1cf6a3da:/# cd /mnt/
root@7ceb1cf6a3da:/mnt# ls -l
total 4
-rw-r--r-- 1 root root 2170 Dec 15 04:22 pom.xml
drwxr-xr-x 3 root root 18 Dec 15 04:22 src

# 代码构建
root@70830096ac9f:/mnt# mvn clean package
[INFO] --- spring-boot-maven-plugin:2.1.9.RELEASE:repackage (repackage) @ receive ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 42.790 s
[INFO] Finished at: 2025-12-15T04:29:04Z
[INFO] ------------------------------------------------------------------------

查看构建后的产物:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 构建完成后会在target目录中产生一个jar包,
root@7ceb1cf6a3da:/mnt# ls -l
total 4
-rw-r--r-- 1 root root 2170 Dec 15 04:22 pom.xml
drwxr-xr-x 3 root root 18 Dec 15 04:22 src
drwxr-xr-x 6 root root 165 Dec 15 04:29 target
root@7ceb1cf6a3da:/mnt# ls -l target/
total 38112
drwxr-xr-x 3 root root 101 Dec 15 04:28 classes
drwxr-xr-x 3 root root 25 Dec 15 04:28 generated-sources
drwxr-xr-x 2 root root 28 Dec 15 04:29 maven-archiver
drwxr-xr-x 3 root root 35 Dec 15 04:28 maven-status
-rw-r--r-- 1 root root 39016394 Dec 15 04:29 receive-0.0.1-SNAPSHOT.jar
-rw-r--r-- 1 root root 4181 Dec 15 04:29 receive-0.0.1-SNAPSHOT.jar.original

#因为做了目录映射,所以在宿主机的/root/18-SpringCloud/demo-receive/target也有相同的文件
[root@k8s-master01 target]# ll
total 38112
drwxr-xr-x 3 root root 101 Dec 15 12:28 classes
drwxr-xr-x 3 root root 25 Dec 15 12:28 generated-sources
drwxr-xr-x 2 root root 28 Dec 15 12:29 maven-archiver
drwxr-xr-x 3 root root 35 Dec 15 12:28 maven-status
-rw-r--r-- 1 root root 39016394 Dec 15 12:29 receive-0.0.1-SNAPSHOT.jar
-rw-r--r-- 1 root root 4181 Dec 15 12:29 receive-0.0.1-SNAPSHOT.jar.original

receive-0.0.1-SNAPSHOT.jar制作镜像:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 进入项目目录
[root@k8s-master01 18-SpringCloud]# cd demo-receive/

#准备Dockerfile
[root@k8s-master01 demo-eureka]# cat Dockerfile
FROM registry.cn-beijing.aliyuncs.com/k8s-liujunwei/openjdk:8u111-jdk
WORKDIR /home/app
COPY target/*.jar ./app.jar
CMD ["java", "-jar", "app.jar"]

# 制作镜像
[root@k8s-master01 demo-receive]# docker build -t registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-receive:v0.0.1 .


#查看制作好的镜像
[root@k8s-master01 demo-receive]# docker images|grep demo-re
registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-receive v0.0.1 922d7b988708 38 seconds ago 682MB

#推送到我自己的阿里云镜像仓库
[root@k8s-master01 demo-receive]# docker push registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-receive:v0.0.1

1.2.2将网关服务部署到k8s

准备网关服务的deployment资源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[root@k8s-master01 springcloud]# cat demo-receive.deploy.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
name: demo-receive
namespace: eureka
spec:
replicas: 2
selector:
matchLabels:
app: demo-receive
template:
metadata:
labels:
app: demo-receive
spec:
containers:
- name: demo-receive
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-receive:v0.0.1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: "k8s"
- name: SERVER_PORT
value: "8080"
- name: EUREKA_SERVER_URL
value: "http://demo-eureka-0.demo-eureka:8761/eureka,http://demo-eureka-1.demo-eureka:8761/eureka,http://demo-eureka-2.demo-eureka:8761/eureka"
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"

准备网关服务的service资源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cat demo-receive-svc.yaml
kind: Service
apiVersion: v1
metadata:
name: demo-receive-svc
namespace: eureka
labels:
app: demo-receive-svc
spec:
type: ClusterIP
selector:
app: demo-receive
ports:
- name: http
port: 8080
targetPort: 8080

准备网关服务的Ingress:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
cat demo-receive-ingress.yaml
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
name: demo-receive-ingress
namespace: eureka
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- host: demo.test.com
http:
paths:
- path: /receiveapi(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: demo-receive-svc
port:
number: 8080

创建上述资源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#创建网关的deployment服务
[root@k8s-master01 springcloud]# kubectl create -f demo-receive.deploy.yaml
deployment.apps/demo-receive created

#创建网关的svc服务
[root@k8s-master01 springcloud]# kubectl create -f demo-receive-svc.yaml
service/demo-receive-svc created

##创建网关的ingress服务
[root@k8s-master01 springcloud]# kubectl create -f demo-receive-ingress.yaml
ingress.networking.k8s.io/demo-receive-ingress created

#查看创建的服务
[root@k8s-master01 springcloud]# kubectl get po -n eureka
NAME READY STATUS RESTARTS AGE
demo-eureka-0 1/1 Running 0 22h
demo-eureka-1 1/1 Running 0 22h
demo-eureka-2 1/1 Running 0 22h
demo-receive-c98d88558-59tb9 1/1 Running 0 14s
demo-receive-c98d88558-flzxn 1/1 Running 0 14s

[root@k8s-master01 springcloud]# kubectl get svc -n eureka
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
demo-eureka ClusterIP None <none> 8761/TCP 27m
demo-eureka-nodeport NodePort 10.96.12.172 <none> 8761:31335/TCP 27m
demo-receive-svc ClusterIP 10.96.105.27 <none> 8080/TCP 105s
[root@k8s-master01 springcloud]# kubectl get ingress -n eureka
NAME CLASS HOSTS ADDRESS PORTS AGE
demo-receive-ingress nginx demo.test.com 192.168.0.84,192.168.0.85,192.168.0.86 80 102s

检查网关服务是否注册到eureka:

1.3迁移其他SpringBoot服务

1.3.1代码构建及容器化

代码地址:https://gitee.com/liujunweipy/demo-handler

构建命令:mvn clean package

Java 版本:jdk 1.8

构建镜像:registry.cn-beijing.aliyuncs.com/k8s-liujunwei/maven:3.5.3

下载源代码:

1
2
3
4
5
6
7
8
9
# 下载代码
[root@k8s-master01 18-SpringCloud]# git clone https://gitee.com/liujunweipy/demo-handler.git
Cloning into 'demo-handler'...
remote: Enumerating objects: 77, done.
remote: Counting objects: 100% (77/77), done.
remote: Compressing objects: 100% (48/48), done.
remote: Total 77 (delta 13), reused 77 (delta 13), pack-reused 0 (from 0)
Receiving objects: 100% (77/77), 13.16 KiB | 539.00 KiB/s, done.
Resolving deltas: 100% (13/13), done.

执行构建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#  把maven构建所依赖的插件持久化
[root@k8s-master01 18-SpringCloud]# mkdir -p /data/m2

# 运行一个maven临时容器进行代码的构建
# --rm: 自动清理。这意味退出容器后,Docker 会自动删除这个容器实例。这非常适合临时性的任务。
# -v:s 数据卷挂载,将宿主机的目录挂载到容器内,把宿主机`pwd`/demo-eureka目录挂载到容器的/mnt,把宿主机的/data/m2目录挂载到容器的/root/.m2目录。
# bash: 这是容器启动后立即执行的命令。它覆盖了镜像默认的 CMD 或 ENTRYPOINT。

[root@k8s-master01 18-SpringCloud]# docker run -ti --rm -v `pwd`/demo-handler:/mnt -v /data/m2/:/root/.m2 registry.cn-beijing.aliyuncs.com/k8s-liujunwei/maven:3.5.3 bash
root@41920c905cd7:/#

#进入到代码目录执行构建命令
root@41920c905cd7:/# cd /mnt/
root@41920c905cd7:/mnt# ls -l
total 4
-rw-r--r-- 1 root root 2170 Dec 15 10:57 pom.xml
drwxr-xr-x 3 root root 18 Dec 15 10:57 src

# 代码构建
root@41920c905cd7:/mnt# mvn clean package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------< com.handler:handler >-------------------------
[INFO] Building handler 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 13.462 s
[INFO] Finished at: 2025-12-15T11:06:45Z
[INFO] ------------------------------------------------------------------------
root@41920c905cd7:/mnt#

查看构建后的产物:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 构建完成后会在target目录中产生一个jar包,
root@41920c905cd7:/mnt# ls -l
total 4
-rw-r--r-- 1 root root 2170 Dec 15 10:57 pom.xml
drwxr-xr-x 3 root root 18 Dec 15 10:57 src
drwxr-xr-x 6 root root 165 Dec 15 11:06 target

root@41920c905cd7:/mnt# ls -l target/
total 38112
drwxr-xr-x 3 root root 101 Dec 15 11:06 classes
drwxr-xr-x 3 root root 25 Dec 15 11:06 generated-sources
-rw-r--r-- 1 root root 39016738 Dec 15 11:06 handler-0.0.1-SNAPSHOT.jar
-rw-r--r-- 1 root root 4525 Dec 15 11:06 handler-0.0.1-SNAPSHOT.jar.original
drwxr-xr-x 2 root root 28 Dec 15 11:06 maven-archiver
drwxr-xr-x 3 root root 35 Dec 15 11:06 maven-status

#因为做了目录映射,所以在宿主机的/root/18-SpringCloud/demo-handler/target也有相同的文件
[root@k8s-master01 18-SpringCloud]# ll demo-handler/target/
total 38112
drwxr-xr-x 3 root root 101 Dec 15 19:06 classes
drwxr-xr-x 3 root root 25 Dec 15 19:06 generated-sources
-rw-r--r-- 1 root root 39016738 Dec 15 19:06 handler-0.0.1-SNAPSHOT.jar
-rw-r--r-- 1 root root 4525 Dec 15 19:06 handler-0.0.1-SNAPSHOT.jar.original
drwxr-xr-x 2 root root 28 Dec 15 19:06 maven-archiver
drwxr-xr-x 3 root root 35 Dec 15 19:06 maven-status

handler-0.0.1-SNAPSHOT.jar制作镜像:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 进入项目目录
[root@k8s-master01 18-SpringCloud]# cd demo-handler/

#准备Dockerfile
[root@k8s-master01 demo-eureka]# cat Dockerfile
FROM registry.cn-beijing.aliyuncs.com/k8s-liujunwei/openjdk:8u111-jdk
WORKDIR /home/app
COPY target/*.jar ./app.jar
CMD ["java", "-jar", "app.jar"]

# 制作镜像
[root@k8s-master01 demo-receive]# docker build -t registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-handler:v0.0.1 .


#查看制作好的镜像
[root@k8s-master01 demo-handler]# docker images|grep handler
registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-handler v0.0.1 d1648160e57f 15 seconds ago 682MB

#推送到我自己的阿里云镜像仓库
[root@k8s-master01 demo-handler]# docker push registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-handler:v0.0.1
The push refers to repository [registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-handler]
6915ab2a13e7: Pushed
3ae57a88572b: Mounted from k8s-liujunwei/demo-receive
35c20f26d188: Mounted from k8s-liujunwei/demo-receive
c3fe59dd9556: Mounted from k8s-liujunwei/demo-receive
6ed1a81ba5b6: Mounted from k8s-liujunwei/demo-receive
a3483ce177ce: Mounted from k8s-liujunwei/demo-receive
ce6c8756685b: Mounted from k8s-liujunwei/demo-receive
30339f20ced0: Mounted from k8s-liujunwei/demo-receive
0eb22bfb707d: Mounted from k8s-liujunwei/demo-receive
a2ae92ffcd29: Mounted from k8s-liujunwei/demo-receive
v0.0.1: digest: sha256:d425170eec6c660a296d4e2697584f3920e3dbc5b0f042bcbd47f9dbeb39c445 size: 2419

1.3.2将demo-handler部署到k8s

准备deployment资源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
kind: Deployment
apiVersion: apps/v1
metadata:
name: demo-handler
namespace: eureka
spec:
replicas: 2
selector:
matchLabels:
app: demo-handler
template:
metadata:
labels:
app: demo-handler
spec:
containers:
- name: demo-handler
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-handler:v0.0.1
ports:
- containerPort: 8080
env:
- name: SERVER_PORT
value: "8080"
- name: SPRING_PROFILES_ACTIVE
value: "k8s"
- name: EUREKA_SERVER_ADDRESS
value: "http://demo-eureka-0.demo-eureka:8761/eureka,http://demo-eureka-1.demo-eureka:8761/eureka,http://demo-eureka-2.demo-eureka:8761/eureka"
resources:
limits:
cpu: 1000m
memory: 1024Mi
requests:
cpu: 500m
memory: 512Mi

创建资源:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@k8s-master01 springcloud]# kubectl create -f demo-handler-deploy.yaml
deployment.apps/demo-handler created

#查看pod状态
[root@k8s-master01 springcloud]# kubectl get po -n eureka
NAME READY STATUS RESTARTS AGE
demo-eureka-0 1/1 Running 0 5h33m
demo-eureka-1 1/1 Running 0 5h33m
demo-eureka-2 1/1 Running 0 5h33m
demo-handler-579c66cb44-85js2 1/1 Running 0 52s
demo-handler-579c66cb44-cldbw 1/1 Running 0 64s
demo-receive-54bf5ddb4d-btm25 1/1 Running 0 177m
demo-receive-54bf5ddb4d-hjfbq 1/1 Running 0 177m

查看服务是否注册到eureka:

1.4迁移前端服务

1.4.1前端项目构建及容器化

代码地址:https://gitee.com/liujunweipy/demo-ui

构建命令:npm install –registry=https://registry.npmmirror.com && npm run build

Node版本:16.17+

构建镜像:registry.cn-beijing.aliyuncs.com/k8s-liujunwei/node:16.20

下载源代码:

1
2
3
4
5
6
7
8
9
# 下载代码
[root@k8s-master01 18-SpringCloud]# git clone https://gitee.com/liujunweipy/demo-ui.git
Cloning into 'demo-ui'...
remote: Enumerating objects: 43, done.
remote: Counting objects: 100% (43/43), done.
remote: Compressing objects: 100% (26/26), done.
remote: Total 43 (delta 14), reused 43 (delta 14), pack-reused 0 (from 0)
Receiving objects: 100% (43/43), 26.09 KiB | 861.00 KiB/s, done.
Resolving deltas: 100% (14/14), done.

执行构建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
[root@k8s-master01 18-SpringCloud]# docker run -ti --rm -v `pwd`/demo-ui:/mnt/ registry.cn-beijing.aliyuncs.com/k8s-liujunwei/node:16.20 bash
Unable to find image 'registry.cn-beijing.aliyuncs.com/k8s-liujunwei/node:16.20' locally
16.20: Pulling from k8s-liujunwei/node
311da6c465ea: Pull complete
ee7d78be1eb9: Pull complete
Digest: sha256:c94b82f9827cab6e421b350965a9ef11b25b13ffbd1030536203d541f55dcbe2
Status: Downloaded newer image for registry.cn-beijing.aliyuncs.com/k8s-liujunwei/node:16.20
root@8933ee58783b:/#

#进入项目目录
root@8933ee58783b:/# cd /mnt/
root@8933ee58783b:/mnt# ls -l
total 96
-rw-r--r-- 1 root root 440 Dec 15 13:45 README.md
-rw-r--r-- 1 root root 357 Dec 15 13:45 index.html
-rw-r--r-- 1 root root 78659 Dec 15 13:45 package-lock.json
-rw-r--r-- 1 root root 335 Dec 15 13:45 package.json
drwxr-xr-x 2 root root 22 Dec 15 13:45 public
drwxr-xr-x 4 root root 85 Dec 15 13:45 src
-rw-r--r-- 1 root root 157 Dec 15 13:45 vite.config.js

# 构建前端代码
root@8933ee58783b:/mnt# npm install --registry=https://registry.npmmirror.com
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE package: '@vitejs/plugin-vue@5.0.4',
npm WARN EBADENGINE required: { node: '^18.0.0 || >=20.0.0' },
npm WARN EBADENGINE current: { node: 'v16.20.2', npm: '8.19.4' }
npm WARN EBADENGINE }
added 54 packages in 7s
10 packages are looking for funding
run `npm fund` for details
npm notice
npm notice New major version of npm available! 8.19.4 -> 11.7.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.7.0
npm notice Run npm install -g npm@11.7.0 to update!
npm notice

root@8933ee58783b:/mnt# npm run build

> demo-ui@0.0.0 build
> vite build

vite v5.2.0 building for production...
✓ 58 modules transformed.
dist/index.html 0.46 kB │ gzip: 0.29 kB
dist/assets/index-BYh5Cz0w.css 1.27 kB │ gzip: 0.65 kB
dist/assets/index-BZep8zp5.js 83.61 kB │ gzip: 33.25 kB
✓ built in 5.02s

# 构建完成,查看构建后的产物
root@8933ee58783b:/mnt# ls -l dist/
total 8
drwxr-xr-x 2 root root 57 Dec 15 14:25 assets
-rw-r--r-- 1 root root 456 Dec 15 14:25 index.html
-rw-r--r-- 1 root root 1497 Dec 15 14:25 vite.svg
root@8933ee58783b:/mnt#

构建前端镜像:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#准备一个nginx的配置文件,用来替换镜像中默认的配置文件,使用默认的也可以
[root@k8s-master01 demo-ui]# cat /root/18-SpringCloud/demo-ui/default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
gzip on;
gzip_types text/plain application/javascript text/css;

root /usr/share/nginx/html;
index index.html;

location / {
add_header Cache-Control "no-cache, no-store";
try_files $uri $uri/ /index.html;
}

location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires 30d;
}

}

准备Dockerfile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@k8s-master01 demo-ui]# cat /root/18-SpringCloud/demo-ui/Dockerfile
FROM registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
# 1. (可选) 设置时区为上海,方便查看 Nginx 日志时间
RUN apk add --no-cache tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
# 2. 先删除 Nginx 默认的配置文件,防止冲突
RUN rm -rf /etc/nginx/conf.d/*
# 3. 复制你的自定义配置
COPY default.conf /etc/nginx/conf.d/default.conf
# 4. 复制构建产物
COPY dist /usr/share/nginx/html
# 5. (可选) 这是一个好习惯,显式声明端口,虽然 Nginx 默认就是 80
EXPOSE 80
# 6. (可选) 显式启动命令
CMD ["nginx", "-g", "daemon off;"]

制作前端镜像:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[root@k8s-master01 demo-ui]# docker build -t registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-ui:v0.0.1 .
[+] Building 98.4s (11/11) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 734B 0.0s
=> [internal] load metadata for registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine 0.9s
...
=> [2/5] RUN apk add --no-cache tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo "Asia/Shanghai" > /etc/timezone 91.0s
=> [3/5] RUN rm -rf /etc/nginx/conf.d/* 0.6s
=> [4/5] COPY default.conf /etc/nginx/conf.d/default.conf 0.1s
=> [5/5] COPY dist /usr/share/nginx/html
=> => writing image sha256:863e9465728d1a67e24a72fa11c009702ccc2d4c78a6ed4152222dd74525ae79 0.0s
=> => naming to registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-ui:v0.0.1


# 镜像已经制作完毕
[root@k8s-master01 demo-ui]# docker images|grep 'demo-ui'
registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-ui v0.0.1 863e9465728d 6 minutes ago 43.5MB

# 将制作好的前端镜像推送到阿里云镜像仓库
[root@k8s-master01 demo-ui]# docker push registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-ui:v0.0.1
The push refers to repository [registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-ui]
67ee358a8f38: Pushed
277aadeb1168: Pushed
8831ee1ed178: Pushed
81ad19c3658b: Pushed
a51b172d7184: Mounted from k8s-liujunwei/nginx
b7486fe26981: Mounted from k8s-liujunwei/nginx
320c8baef084: Mounted from k8s-liujunwei/nginx
d2cef4a1b224: Mounted from k8s-liujunwei/nginx
4275164ce225: Mounted from k8s-liujunwei/nginx
6e92270dbfe6: Mounted from k8s-liujunwei/nginx
b5d2e1fcf1ad: Mounted from k8s-liujunwei/nginx
af9a70194aa4: Mounted from k8s-liujunwei/nginx
v0.0.1: digest: sha256:c298d37e2f537fc8b3735f8fd94cb78bd798c91160103e3e1211733851375cd2 size: 2821

检查镜像仓库是否有该镜像:

1.4.2部署前端项目到k8s

准备前端资源文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
cat  demo-ui-deploy.yaml
# 前端的deployment
kind: Deployment
apiVersion: apps/v1
metadata:
name: demo-ui
namespace: eureka
labels:
app: demo-ui
spec:
replicas: 1
selector:
matchLabels:
app: demo-ui
template:
metadata:
labels:
app: demo-ui
spec:
containers:
- name: demo-ui
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/demo-ui:v0.0.1
ports:
- containerPort: 80
resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 100m
memory: 256Mi
---
# 前端Service文件
kind: Service
apiVersion: v1
metadata:
name: demo-ui
namespace: eureka
labels:
app: demo-ui
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
selector:
app: demo-ui


---
# demo-ui前端的Ingress
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
name: demo-ui-ingress
namespace: eureka
spec:
ingressClassName: nginx
rules:
- host: demo.test.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: demo-ui
port:
number: 80

创建资源:

1
2
3
4
[root@k8s-master01 springcloud]# kubectl create -f demo-ui-deploy.yaml
deployment.apps/demo-ui created
service/demo-ui created
ingress.networking.k8s.io/demo-ui-ingress created

查看pod运行情况:

1
2
3
4
5
6
7
8
9
10
11
[root@k8s-master01 springcloud]# kubectl get po -n eureka
NAME READY STATUS RESTARTS AGE
demo-eureka-0 1/1 Running 0 22h
demo-eureka-1 1/1 Running 0 22h
demo-eureka-2 1/1 Running 0 22h
demo-handler-579c66cb44-85js2 1/1 Running 0 16h
demo-handler-579c66cb44-hd57s 1/1 Running 0 41s
demo-receive-54bf5ddb4d-btm25 1/1 Running 0 19h
demo-receive-54bf5ddb4d-wkqxb 1/1 Running 0 52s
demo-ui-56f5c5d4db-cz88x 1/1 Running 0 18s
demo-ui-56f5c5d4db-vfdsg 1/1 Running 0 117s

浏览器访问测试demo.test.com,测试环境需要添加hosts解析:

到此项目迁移完成!