最近用 Go 开发项目,本地发开和调试起来都非常方便,当到了接口对接阶段就出现了问题。

CI/CD 中文为持续集成/持续部署是敏捷开发的重要一环,有了 CI/CD 你可以快速的构建出 Feature/Fix 环境,加快版本的上线节奏。

本次的设计目标是:让开发者只需要提交代码即可,由 Gitlab 去执行代码构建和代码部署的能力,此外我还需要在部署阶段保证服务的正常可用。

我将 Gitlab 流水线 (Pipelines) 设置了两个阶段:

  1. 构建:编译出 Go 的可执行文件
  2. 部署:完成线上的部署工作

在部署阶段, Runner 会保证原有接口的正常的情况下:

  1. 用最新的可执行文件启动一个临时服务,并修改 nignix 反向代理,将所有的新请求代理到临时服务
  2. 停掉并升级老服务
  3. 把 Nginx 反向代理代理到新的正是服务,关闭掉临时服务。 无标题-2024-02-22-1416.png

具体 .gitlab-ci.yml 内容如下:

stages:  
  - build  
  - deploy  
variables:  
  GOMODCACHE: /project-path/mod  

build:  
  image: golang:1.21  
  stage: build  
  cache: # 缓存  
    paths:  
      - mod  
  script:  
    - touch ./config/config.yml  
    # 编译你的 Go 程序  
    - export GO111MODULE=on  
    - export GOPROXY=https://goproxy.cn  
    - go mod download  
    - go build -ldflags "-linkmode external -extldflags -static -s -w" -o main ./cmd/app/main.go  
  artifacts:  
    expire_in: 1 week  
    paths:  
      - main  
deploy_test:  
  image: instrumentisto/rsync-ssh:latest # 指定镜像  
  stage: deploy  
  script:  
    - mkdir -p ~/.ssh  
    - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config  
    - echo "$PREVIEW_SSH_PRIVATE_KEY" >> ~/.ssh/id_rsa # 将 Gitlab 里设置的的私钥环境变量输出到 ~/.ssh/id_rsa  
    - chmod 600 ~/.ssh/id_rsa  
    - rsync -rav -e "ssh -p 22 -o StrictHostKeyChecking=no" main "root"@"$PREVIEW_SERVER":"$PREVIEW_PROJECT_PATH"  
    - ssh -p 22 -i ~/.ssh/id_rsa root@"$PREVIEW_SERVER" "ln -snf $PREVIEW_PROJECT_PATH/main main_run && supervisorctl restart maintemp && echo 'upstream myserver {  
      server 127.0.0.1:41524 max_fails=3 fail_timeout=30s weight=1;  
      }' > /usr/local/nginx/conf/proxy/main  && systemctl reload nginx && supervisorctl restart main"  
    - ssh -p 22 -i ~/.ssh/id_rsa root@"$PREVIEW_SERVER" "echo 'upstream myserver {  
      server 127.0.0.1:8100 max_fails=3 fail_timeout=30s weight=1;  
      }' > /usr/local/nginx/conf/proxy/main && systemctl reload nginx && supervisorctl stop maintemp"  
  retry: 2  
  only:  
    refs:  
      - master  

至此,就完成了 Go 的持续集成和持续部署的目标,开发人员只只需要关注开发本身,提交代码即可,无需关心构建和部署的问题。

Gitlab 去执行程序构建和部署,并且保证程序在部署期间不停服。