基于git的轻量级docker镜像版本发布

# 背景

目前工作开发流程代码编译阶段,是各个开发自行在本地进行编译打包。

新来的同事抱怨说,当初搞定编译环境折腾了很久,申请云服务器的系统版本不一致,GCC版本也做了升级,导致无法编译,因为安全性问题GCC也无法降级,存在着个人环境搭建困难;有几次也遇到了同事将测试环境部分代码发布到生产环境的情况,无法知道编译的这个版本包含了哪些改动,尽管现在已经保持了git代码和生产环境代码一致,也会因为个人的不规范导致额外的版本发布风险。

因此,抱着学习的态度,探索了一条CI/CD标准化代码发布部署流程。

# 工具列表

下面是涉及到的工具

  • git仓库

  • 镜像仓库

  • 蓝盾流水线

  • docker:24.0.4

  • docker compose:v2.19.1

  • watchtower

# 前期准备

# Dockerfile

制作golang项目的镜像包,需要将其提交到项目的根目录下。

 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
FROM ubuntu:18.04 AS builder

COPY . /src
WORKDIR /src

ARG GOPROXY
ARG GOPRIVATE
ARG GOSUMDB

ENV PATH=$PATH:/usr/local/go/bin \
    HOME=/root \
    GOPROXY=${GOPROXY} \
    GOPRIVATE=${GOPRIVATE} \
    GOSUMDB=${GOSUMDB} \
    GOROOT=/usr/local/go \
    GOPATH=${HOME}/go \
    GOBIN=${HOME}/go/bin

RUN apt-get update \
    && apt-get install gcc-4.8 g++-4.8 wget -y \
    && update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 40 \
    && update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 40 \
    && wget https://go.dev/dl/go1.18.1.linux-amd64.tar.gz \
    && tar -C /usr/local -xzf go1.18.1.linux-amd64.tar.gz \
    && go build -o ./bin/AppMain .

FROM ubuntu:18.04

COPY --from=builder /src/bin /app/bin
COPY --from=builder /src/conf /app/conf

WORKDIR /app/bin

# 设置时区
RUN apt update \
    && apt install tzdata \
    && apt-get install -y ca-certificates \
    && chmod +x ./AppMain
ENV TZ=Asia/Shanghai

ENTRYPOINT ["./AppMain"]

# watchtower启动配置文件

将会每120秒检测一次镜像版本是否有更新

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
version: '3'
services:
  watchtower:
    image: containrrr/watchtower
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /root/.docker/config.json:/config.json
    command: --interval 120 --label-enable --cleanup
    network_mode: host

启动命令

1
docker compose up -d

# AppMain启动配置文件

watchtower将会检测携带com.centurylinklabs.watchtower.enable标签的容器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
version: '3'

services:
  inner:
    #需要填写实际的仓库名
    image: AppMain_image:latest
    restart: always
    volumes:
      - $PWD/conf:/app/conf
      - $PWD/logs:/app/logs
    network_mode: host
    labels:
      - com.centurylinklabs.watchtower.enable=true

启动命令

1
docker compose up -d

# 测试环境最佳实践

测试环境不需要设置的太过严格,提交git时注意做好提示说明。

# 创建开发代码分支版本

1
git checkout -b feature

# 在蓝盾创建测试流水线

设置分支有代码提交则编译打包最新镜像,不需要审核流程。

# 生产环境最佳实践

# 保持master分支是最新代码

将开发分支代码合并到主分支

1
2
3
A - B - C - D - E (main)
         \
          F - G - H (feature)

# 只合并某个commit

这里的 是你想要合并的那个提交的哈希值。

1
git cherry-pick <commit-hash>

# 将某个提交之前的所有提交合并到主分支

这里的 <F-hash> 是提交 F 的哈希值,<G-hash> 是提交 G 的哈希值。<F-hash>^ 表示 F 的父提交。

1
git cherry-pick <F-hash>^..<G-hash>

# 合并分支中特定文件的更改

这里的 <feature-branch> 是你想要提取更改的分支名称,<path-to-file> 是你想要提取的文件路径。

1
git checkout <feature-branch> -- <path-to-file>

需要再次执行commit命令。

# 在蓝盾创建生产流水线

  • 触发方式设置为Releases,或者手动执行。

  • 增加人员审核流程。

  • 打包为两个镜像,用于灰度和全量。

# FAQ

# 如何确保docker不会崩溃

1
2
3
4
5
6
7
#通过配置 systemd 服务文件,可以确保 Docker 守护进程在失败后自动重启。
sudo systemctl edit docker
#添加以下内容:

[Service]
Restart=always
RestartSec=5

# 如何实现灰度发布

流水线分阶段打包两个镜像,一个用于灰度机器使用,一个用于全量机器使用。

# 如何快速回滚

在每次流水线构建时增加构建号标识,通过镜像转存插件快速将上一版本设置为最新版本镜像。

Licensed under CC BY-NC-SA 4.0