最近学习时看到 CI/CD,前面几份工作很少接触到,因为都是运维的活,甚至自己搞的发布系统,也没机会接触,所以就拿 Github 浅浅尝试配置下吧。
Why
CI 全称 Continuous integration,顾名思义“持续集成”,核心在于集成,一个团队每时每刻都可能有人在提交代码,而怎样可以快速发现可能出现的错误,就在于每次提交后自动进行集成结果测试。
CD 全称 Continuous delivery 持续交付,Continuous deploy 持续部署,其核心在于可以随时交付出一个可以部署的东西,比如使用 Docker 打包出某个版本的镜像后,这个镜像可以随时随地拿去部署使用。
所以使用原因很明显,及时发现问题,随时可以一键部署或者回滚。
Github CI/CD
有很多系统可以做,甚至自己手工写也可以搞这些,目前较流行的是 Jenkins,并且它是免费的,除此之外就 Github 还有 Gitlab 都可以做,因为本身就是代码库,集成起来肯定更方便,总之根据状况选择即可。
CI
mkdir .github/workflows
name: CI
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
steps:
- uses: actions/checkout@v3
- name: Use Node.js
uses: actions/setup-node@v3.4.1
with:
node-version: "18.x"
- name: Run build
run: |
cd management-system-react
npm install
npm run build
首先,我们来一个 CI 测试下,配置文件是 yaml 格式,看上去是不是很简单?而且一眼就能看出每行的作用,比如 on 很明显就是什么时候触发,关键词和语法可以去文档里查询。
用语言描述就是:“在 master 分支有 push 或者 pull_request 时触发,然后执行一个叫 build 的工作,build 中首先 checkout 代码,然后安装 node v18 环境,最后根据提供的命令行执行 build”。
保存并提交后 workflow 就会自动运行,绿色代表运行成功。
点进去可以看到执行了那些步骤,每个步骤是否成功。
CD
上面只 build 但是并没有保存和部署,所以现在来做这些操作,可以通过 Github 界面上的 Create 尝试下,内部预定义好了很多平台的配置方法,比如微软云,阿里云,亚马逊云等云服务商。
这次我要做的是另一种,基于本地或者说自有服务器的构建部署。
首先来到项目下的 settings -> actions -> runners,点击 New 有文档告诉你如何增加自己的 runner,我这里已经加好了一个具有四个 tag 的 runner,后续使用可根据 tag 匹配 runner 使用。
我们这次的最终目的是一个 React 项目提交代码后,自动触发打包并且部署好。共需要创建三个文件:
- Github 的 workflow 配置文件
- Dockerfile
- nginx.conf
docker.yaml
name: Self Hosted Docker
on:
push:
branches: ["test-runner"]
workflow_dispatch:
jobs:
build:
runs-on: [self-hosted, docker]
defaults:
run:
working-directory: ./management-system-react
steps:
- uses: actions/checkout@v3
- name: Get commit tag
run: echo "SHORT_SHA=`echo ${GITHUB_SHA} | cut -c1-8`" >> $GITHUB_ENV
- name: Build
run: docker build -t frontend:${{ env.SHORT_SHA }} .
deploy:
needs: build
runs-on: [self-hosted, docker]
defaults:
run:
working-directory: ./management-system-react
steps:
- name: Get commit tag
run: echo "SHORT_SHA=`echo ${GITHUB_SHA} | cut -c1-8`" >> $GITHUB_ENV
- name: Stop old container
continue-on-error: true
run: |
docker stop $(docker ps --filter name=frontend -q)
docker rm frontend-${{ env.SHORT_SHA }}
- name: Deploy
run: docker run --name frontend-${{ env.SHORT_SHA }} -d -p 80:80 frontend:${{ env.SHORT_SHA }}
Dockerfile
FROM node:18-alpine as builder
WORKDIR /app
COPY package.json .
RUN npm config set registry http://registry.npm.taobao.org
RUN npm install
COPY . .
# Because Error: The service was stopped
# https://github.com/vitejs/vite/issues/876#issuecomment-824557144
RUN node node_modules/esbuild/install.js
RUN npm run build
FROM nginx:1.23-alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/dist /usr/share/nginx/html
nginx.conf
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
try_files $uri $uri/index.html /index.html;
}
}
通过 Github Action 触发 workflow,workflow 分为两个 job
- build job 使用 git commit 的 sha 打包镜像
- deploy job 停掉旧的运行容器,并启动新的容器
以上是一次完整的流程,发布后线上忽然出现了一个紧急 BUG,需要立刻会滚,那么可以通过点击需要会滚到的版本,点击 deploy 的 re-run 即可。
如图中最新版 #31e403 忽然发现 BUG 需要回滚,进入前一个正常版本 #a9169629 的 deploy job 点击运行,然后运行的容器就自动回滚到 #a9169629,并且是不需要重新执行 build 动作的,因为之前已经 build 过了。