go服务部署(升级+回滚)

1991/6/26 基础

# 1. 项目信息

# 1.1 目录结构

# 项目目录信息
$ tree go-container 
go-container
├── Dockerfile
├── go.mod
├── go.sum
└── main.go
1
2
3
4
5
6
7

# 1.2 主代码信息

main.go 代码如下:

package main

import (
 "github.com/gin-gonic/gin"
 "os"
 "time"
)

func main() {
 engine := gin.Default()
 engine.GET("/", func(context *gin.Context) {
  // 显示主机名字
  hostName, _ := os.Hostname()
  context.JSON(200, gin.H{
   "version":  "v1",
   "hostName": hostName,
   "time":     time.Now().Format("2006-01-02 15:04:05"),
  })
 })
 _ = engine.Run(":80")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 2. 制作镜像

# 2.1 编写Dockerfile

# Golang版本;Alpine镜像的体积较小。
FROM golang:1.18 as builder

# 将代码复制到构建镜像中。
ADD . /workspace
WORKDIR /workspace

# 挂载构建缓存。
# GOPROXY防止下载失败。
RUN --mount=type=cache,target=/go \
  env GOPROXY=https://goproxy.cn,direct \
  go build -buildmode=pie -ldflags "-linkmode external -extldflags -static -w" \
  -o /workspace/gin-hello

# 运行时镜像。
# Alpine兼顾了镜像大小和运维性。
FROM alpine:3.14
EXPOSE 8080
# 复制构建产物。
COPY --from=builder /workspace/gin-hello /app/

# 指定默认的启动命令。
CMD ["/app/gin-hello"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 2.2 构建镜像

# 进入项目目录执行
$ docker build -t liuqinghui/gin-hello:v1 .
[+] Building 30.7s (12/12) FINISHED
...
 => => naming to docker.io/liuqinghui/gin-hello:v1
1
2
3
4
5

# 2.3 推送镜像

这里将镜像推送到https://hub.docker.com/

# 先登陆
$ docker login
Authenticating with existing credentials...
Login Succeeded
# 推送
$ docker push liuqinghui/gin-hello:v1
The push refers to repository [docker.io/liuqinghui/gin-hello]
1320a677095b: Pushed
63493a9ab2d4: Mounted from library/alpine
v1: digest: sha256:25ae6ce90d8810450b9f84d89fe7499f6ce24167ec47b4fbd8aeb79a02632fa5 size: 739
1
2
3
4
5
6
7
8
9
10

# 3. 部署到Kubernetes

# 3.1 编写yaml

文件:gin-hello.yaml

apiVersion: apps/v1 # 配置格式版本
kind: Deployment   #资源类型,Deployment
metadata:
  name: gin-hello-deploy #Deployment 的名称
spec:
  replicas: 2   # 副本数量
  selector:   #标签选择器,
    matchLabels: #选择包含标签app:gin_hello_pod的资源
      app: gin_hello_pod
  template: #Pod信息
    metadata:
      labels:
        app: gin_hello_pod
    spec:
      containers:
      - name: gin-hello 
        image: docker.io/liuqinghui/gin-hello:v1 # 我们构建的镜像

---
apiVersion: v1 
kind: Service
metadata:
  name: gin-hello-svc
spec:
  type: NodePort
  selector:
    app: gin_hello_pod 
  ports:
  - name: http
    protocol: TCP
    port: 8080 # ClusterIP监听的端口
    targetPort: 80 # Pod监听的端口
    nodePort: 30000
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

deployment、service等多个资源类型的配置可以写到一个文件,使用---间隔开即可。

# 3.2 部署

$ kubectl apply -f gin-hello.yaml
deployment.apps/gin-hello-deploy created
service/gin-hello-svc created
1
2
3

# 3.3 验证

# 查看 deployment
$ kubectl get deployment
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
gin-hello-deploy   2/2     2            2           13m
# 查看pod
$ kubectl get pod
NAME                                READY   STATUS    RESTARTS   AGE
gin-hello-deploy-86f8cfb7b9-bkmhv   1/1     Running   0          14m
gin-hello-deploy-86f8cfb7b9-dwgwk   1/1     Running   0          14m

# 查看 service
$ kubectl get service
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
gin-hello-svc   NodePort    10.105.12.214   <none>        8080:30000/TCP   14m
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 4. 服务升级

# 4.1 修改yaml

通过修改镜像版本,来实现服务升级,为了便于观察,把副本数量调大

修改文件 gin-hello.yaml

apiVersion: apps/v1 
kind: Deployment 
metadata:
  name: gin-hello-deploy  
spec:
  replicas: 3   # 调大副本数量
  selector:   
    matchLabels: 
      app: gin_hello_pod
  template: 
    metadata:
      labels:
        app: gin_hello_pod
    spec:
      containers:
      - name: gin-hello 
        image: docker.io/liuqinghui/gin-hello:v2 # 升级镜像为v2
---
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 4.2 发布

# 依旧通过 kubectl apply 发布
$ kubectl apply -f gin-hello.yaml
deployment.apps/gin-hello-deploy configured
service/gin-hello-svc unchanged
1
2
3
4

# 4.3 访问验证

$ curl 10.105.12.214:8080
{"hostName":"gin-hello-deploy-6bb7456d9b-bk9mf","time":"2022-08-10 09:12:04","version":"v2"}
$ curl 10.105.12.214:8080
{"hostName":"gin-hello-deploy-6bb7456d9b-vqds9","time":"2022-08-10 09:12:33","version":"v2"}
$  curl 10.105.12.214:8080
{"hostName":"gin-hello-deploy-6bb7456d9b-2j9p2","time":"2022-08-10 09:12:34","version":"v2"}
1
2
3
4
5
6

# 5. 服务回滚

# 5.1 准备yaml文件

为了方便操作和后续回滚,编写多个配置文件,具体版本对应如下:

配置文件 镜像版本
gin-hello-v1.yaml gin-hello:v1
gin-hello-v2.yaml gin-hello:v2
gin-hello-v3.yaml gin-hello:v3

# 5.2 保存发布记录

kubectl apply每次更新应用时,Kubernetes都会记录下当前的配置,保存为一个revision(版次),这样就可以回滚到某个特定revision。发布时,携带参数 --record,可以将当前命令记录到revision记录中。

为了方便后面回滚,按照顺序都发布下。

# 发布 v1
$ kubectl apply -f gin-hello-v1.yaml --record
# 验证 v1
$ curl 10.105.12.214:8080
{"hostName":"gin-hello-deploy-86f8cfb7b9-4z8kj","time":"2022-08-10 11:03:45","version":"v1"}

# 发布 v2
$ kubectl apply -f gin-hello-v2.yaml --record
# 验证 v2
$ curl 10.105.12.214:8080
{"hostName":"gin-hello-deploy-6bb7456d9b-p8hw2","time":"2022-08-10 11:04:19","version":"v2"}

# 发布 v3
$ kubectl apply -f gin-hello-v3.yaml --record
# 验证 v3
$ curl 10.105.12.214:8080
{"hostName":"gin-hello-deploy-69c4fd68ff-4ppfh","time":"2022-08-10 11:06:17","version":"v3"}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 5.3 查看发布历史

通过kubectl rollout history deployment 名称查看revison历史记录

# 查看发布历史
$ kubectl rollout history deployment gin-hello-deploy
deployment.apps/gin-hello-deploy
REVISION  CHANGE-CAUSE
3         kubectl apply --filename=gin-hello-v1.yaml --record=true
4         kubectl apply --filename=gin-hello-v2.yaml --record=true
5         kubectl apply --filename=gin-hello-v3.yaml --record=true
1
2
3
4
5
6
7

# 5.4 回滚指定版本

通过执行命令kubectl rollout undo deployment 名称 --to-revision=?,其中--to-revision=的值,就历史记录中REVISION,所对应的值。

# 查看当前所在版本
$ curl 10.105.12.214:8080
{"hostName":"gin-hello-deploy-69c4fd68ff-4ppfh","time":"2022-08-10 11:06:17","version":"v3"}

# 回滚到v1,而v1对应的REVISION = 3
$ kubectl rollout undo deployment gin-hello-deploy --to-revision=3
deployment.apps/gin-hello-deploy rolled back
# 验证结果
$ curl 10.105.12.214:8080
{"hostName":"gin-hello-deploy-86f8cfb7b9-r2jvr","time":"2022-08-10 11:14:31","version":"v1"}
1
2
3
4
5
6
7
8
9
10