CI/CD从零到实战:3天自动部署,节省90%重复劳动

CI/CD从零到实战:3天自动部署,节省90%重复劳动

刚开始我也以为CI/CD是那种高大上的东西,得资深DevOps才能搞。结果被线上bug逼疯之后,花了一个周末硬啃下来,发现这玩意儿其实没那么玄乎——关键是你得知道哪些坑别踩,哪些配置是白送的。

本文纯实战,不讲那些虚头巴脑的理论。我直接拿我们项目组从手动部署到自动流水线的过程说事儿,你跟着走一遍,3天之内肯定能跑起来。

(开篇配图:一张对比图,左边是手动部署的混乱流程图——打码、上传、查日志、反复崩溃;右边是CI/CD流水线的清晰箭头——Push代码→自动测试→自动部署→上线成功。配文:“手动部署 VS CI/CD,你选哪个?”)

先搞清楚CI/CD到底解决了什么

0px rgba(0,0,0,.08);”
loading=”lazy” width=”800″ height=”500″>

rgba(0,0,0,.08);”
loading=”lazy” width=”800″ height=”500″>

别被那些专业名词唬住。CI/CD说白了就是两件事:

  • CI(持续集成):你每次提交代码后,自动跑测试、自动检查代码质量。防止你写的垃圾代码污染主分支。
  • CD(持续交付/部署)):测试通过后,自动把代码部署到服务器上。省掉你手动打jar包、传服务器、重启的那些破事儿。

我以前团队有个哥们儿,每天下午4点准时手动部署,然后盯着屏幕等5分钟,再查日志。一天至少重复5次,每次提心吊胆。后来上了流水线,他每天多出两小时喝茶摸鱼。

工具选型:别纠结,直接GitHub Actions

市面上工具一大堆:Jenkins、GitLab CI、CircleCI、Travis CI……但我建议新手直接上GitHub Actions。原因就仨:

  • 不用额外搭服务器——Jenkins得自己装,维护起来烦死你
  • 配置简单——YAML文件,跟写文档似的
  • 市场免费额度够用——公开仓库无限免费,私有仓库每月2000分钟
  • 你要是用GitLab,也有类似的CI,但GitHub用户量大,社区模板多,抄作业方便。

    第一步:搭一个最简单的CI——代码检查+单元测试

    先别想部署那一步,先让代码提交后自动跑检查。这是CI的核心。

    我拿一个前端React项目举例。在项目根目录建个.github/workflows/ci.yml

    yaml
    name: CI - Code Check

    on:
    push:
    branches: [ main, develop ]
    pull_request:
    branches: [ main ]

    jobs:
    lint-and-test:
    runs-on: ubuntu-latest

    steps:
    - name: 拉取代码
    uses: actions/checkout@v3

    - name: 搭建Node环境
    uses: actions/setup-node@v3
    with:
    node-version: '18'
    cache: 'npm'

    - name: 安装依赖
    run: npm ci

    - name: 代码风格检查
    run: npm run lint

    - name: 运行单元测试
    run: npm test -- --coverage

    - name: 上传测试报告
    uses: actions/upload-artifact@v3
    if: always()
    with:
    name: coverage-report
    path: coverage/
    `

    为什么要这么写?

    • on.pushon.pull_request:只在主分支和拉取请求时触发,避免每次提交都跑一遍浪费时间
    • npm ci:比npm install更快更严格,会根据package-lock.json安装,避免团队间环境不一致
    • upload-artifact:这个很有用,测试报告会上传到GitHub,你可以直接在Action页面下载查看覆盖率

    我第一次写完这个配置,push上去,看到那个绿色勾勾亮起来的时候,真有种“老子终于自动化了”的爽感。

    第二步:加上Docker构建和镜像推送

    这里有个坑:千万别在CI里现编译代码。太慢了。正确的做法是:先把代码编译成可部署的产物(比如Docker镜像),推到镜像仓库,然后部署时直接拉镜像。

    我用的阿里云容器镜像服务(ACR),国内速度快,价格便宜。你也可以用Docker Hub,但国内访问慢得想砸电脑。

    `yaml
    name: Build and Push Docker Image

    on:
    push:
    tags:
    - 'v*'

    jobs:
    build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - name: 登录到阿里云镜像仓库
    uses: aliyun/acr-login@v1
    with:
    region-id: cn-hangzhou
    access-key-id: ${{ secrets.ALIYUN_ACCESS_KEY_ID }}
    access-key-secret: ${{ secrets.ALIYUN_ACCESS_KEY_SECRET }}
    instance-id: your-instance-id

    - name: 构建并推送镜像
    uses: docker/build-push-action@v4
    with:
    context: .
    push: true
    tags: |
    registry.cn-hangzhou.aliyuncs.com/my-project/my-app:latest
    registry.cn-hangzhou.aliyuncs.com/my-project/my-app:${{ github.ref_name }}
    `

    为什么用tag触发而不是branch?

    因为生产环境部署应该慎重。只有打了v1.0.0这种版本标签的提交,才构建生产镜像。main分支的提交只跑CI,不构建镜像,这样可以防止手滑。

    第三步:自动部署到服务器——最爽的一步

    这里我用的方案是:阿里云ECS + Docker Compose。GitHub Actions通过SSH连接到服务器,执行部署脚本。

    `yaml
    name: Deploy to Production

    on:
    workflow_run:
    workflows: ["Build and Push Docker Image"]
    types:
    - completed

    jobs:
    deploy:
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion == 'success' }}

    steps:
    - name: SSH到服务器并部署
    uses: appleboy/ssh-action@v0.1.5
    with:
    host: ${{ secrets.SERVER_HOST }}
    username: ${{ secrets.SERVER_USER }}
    key: ${{ secrets.SERVER_SSH_KEY }}
    script: |
    cd /opt/my-app
    docker-compose pull
    docker-compose up -d --remove-orphans
    docker image prune -f
    `

    这个设计真的反人类吗? 第一次看这个配置时我也觉得“怎么这么绕”,但实际跑通了就真香。它解决了三个痛点:

  • 自动拉取最新镜像:不用手动ssh进去敲命令
  • 零停机更新docker-compose up -d会先启动新容器,再停掉旧的
  • 清理旧镜像docker image prune -f防止服务器磁盘爆满
  • (中间配图:一张CI/CD流水线的可视化截图,展示GitHub Actions界面上三个工作流的运行状态——CI检查绿勾、构建镜像绿勾、部署成功绿勾。配文:“三个工作流串联起来,就是一条完整的CI/CD流水线”)

    避坑指南:我连踩的三个坑

    坑1:Secrets管理不当

    一开始我把服务器密码直接写在YAML文件里,push上去后GitHub报警说检测到敏感信息。吓得我赶紧改了。

    正确做法:所有敏感信息(密码、密钥、Token)都存到GitHub仓库的Settings → Secrets and variables → Actions里。然后在YAML中用${{ secrets.XXX }}引用。

    坑2:测试环境和生产环境配置混在一起

    有次我改了数据库配置,结果CI跑测试时连接了生产数据库,差点酿成大祸。

    解决方案:用环境变量区分。process.env.NODE_ENV设为testdevelopmentproduction。不同环境加载不同配置文件。

    坑3:deploy脚本没有幂等性

    我写的第一个部署脚本是“先停掉所有容器,再启动新的”。结果有一次部署到一半,网络断了,容器全停了但新的没起来,服务挂了10分钟。

    改进后:用docker-compose up -d –no-deps先启动新容器,等新容器运行正常后,再停掉旧容器。整个过程服务不间断。

    还有个技巧:自动回滚

    这个是我后来加的,但强烈推荐。如果部署后监控到错误率飙升,自动触发回滚。

    思路是在服务器上保留上一次成功的镜像版本,然后写一个健康检查脚本:

    `bash
    #!/bin/bash

    健康检查脚本,部署后运行

    sleep 30
    HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/health)

    if [ "$HTTP_STATUS" -ne 200 ]; then
    echo "Health check failed! Rolling back..."
    docker-compose down
    docker-compose -f docker-compose.rollback.yml up -d
    exit 1
    fi

    echo "Deployment successful!"
    `

    然后在GitHub Actions里加一个步骤:

    `yaml

    • name: 健康检查

    run: |
    sleep 20
    if ! curl -f http://localhost:8080/health; then
    echo "Deploy failed, rolling back"
    # 触发回滚工作流
    fi
    `

    (结尾配图:一张时间线对比图,展示手动部署流程耗时(平均8分钟/次,含等待和排查)vs CI/CD自动化流程耗时(平均45秒/次)。配文:“从8分钟到45秒的差距”)

    总结一下,你可以立刻用的三个点

  • 今天就能干:在你的项目里加一个.github/workflows/ci.yml`,只做代码检查和单元测试,10分钟搞定。push代码后看那个绿色勾勾,你会爱上这种感觉。
  • 周末进阶:加上Docker构建和部署,用上面给的模板,改一下镜像仓库地址和服务器信息就行。记得把敏感信息存到Secrets里。
  • 下周一生产可用:加上自动回滚和健康检查,让你的流水线真正“无人值守”。我团队用了这个方案后,部署时间从手动8分钟降到45秒,而且再没出过因为部署导致的服务中断。
  • 最后说一句:CI/CD不是大公司的专利。哪怕你只有一个个人项目、一台低配服务器,也值得花半天时间搞一套。当你习惯了“push代码就完事儿”的爽感,就再也回不去了。

    滚动至顶部