我的自动化部署实践
引言
说起部署这件事,估计很多开发同学都有一把辛酸泪。记得刚工作那会儿,每次上线都跟打仗似的——凌晨三四点盯着屏幕,手抖着敲命令,生怕一个不小心就搞挂生产环境。有时候改了个小 bug,光是部署就要折腾半天,测试环境、生产环境来回倒腾,累得半死不说,还经常出各种幺蛾子。
后来痛定思痛,我决定好好折腾一下自动化部署。这一搞就是好几年,中间踩了无数坑,也总结了不少经验。今天就聊聊我是怎么做自动化部署的,希望能给有同样困扰的同学一些参考。
那些年被部署支配的恐惧
刚工作的时候,我们团队的部署流程大概是这样的:开发本地测完没问题,然后手动打包成 war 包或者 jar 包,用 FTP 传到服务器,登录服务器停止服务、替换文件、启动服务。听起来很简单对吧?但实际操作中问题一堆:
- 经常漏传某个依赖包,导致启动失败
- 多台服务器要手动同步操作,有一次忘了在一台机器上更新,结果用户访问到的还是旧版本
- 回滚特别麻烦,需要手动找之前的备份
- 没有任何日志记录,出了问题都不知道该查哪里
最崩溃的是有一次上线,刚好遇到服务器磁盘满了,部署到一半卡住,上不去下不来,硬是折腾到早上八点才搞定。那一刻我就下定决心,一定要把这破流程改掉。
选型:踩过的那些坑
一开始我尝试用 Jenkins,不得不说这玩意儿功能确实强大,但配置起来也是真的复杂。各种插件版本兼容问题、权限配置、节点管理,搞得人头大。而且 Jenkins 那个界面,怎么说呢,比较有年代感……
后来试了 GitHub Actions,体验还不错,配置简单,跟 GitHub 集成也很紧密。但问题是我们的代码仓库在公司内部的 GitLab 上,用起来不太方便。
最后选来选去,我们决定用 GitLab CI。原因很简单:本身就是用 GitLab 托管代码,集成度高,而且 CI/CD 配置直接写在项目里的 .gitlab-ci.yml,版本控制也方便。
当然,如果你用的是 GitHub,GitHub Actions 也是很好的选择。关键是要选一个适合自己团队的工具,别盲目追求"最强大",适合自己的才是最好的。
我的 CI/CD 流程设计
说了这么多,来看看我现在的部署流程大概是什么样子。
首先在项目根目录创建一个 .gitlab-ci.yml 文件,内容大概是这样的:
stages:
- build
- test
- deploy
build:
stage: build
image: maven:3.8-openjdk-17
script:
- mvn clean package -DskipTests
artifacts:
paths:
- target/*.jar
expire_in: 1 hour
test:
stage: test
image: maven:3.8-openjdk-17
script:
- mvn test
coverage: '/Total.*?([0-9]{1,3})%/'
deploy_staging:
stage: deploy
script:
- ssh deploy@staging-server "cd /app && docker-compose pull && docker-compose up -d"
only:
- develop
environment:
name: staging
url: https://staging.example.com
deploy_production:
stage: deploy
script:
- ssh deploy@production-server "cd /app && docker-compose pull && docker-compose up -d"
only:
- main
environment:
name: production
url: https://example.com
when: manual
这个配置定义了三个阶段:构建、测试、部署。代码推送到 develop 分支会自动部署到测试环境,而推送到 main 分支则需要手动触发生产环境部署——这个 when: manual 真的很重要,至少给你一个后悔的机会。
Docker 与 Kubernetes 的应用
说到部署,不得不提 Docker。这玩意儿简直是部署界的救星,把应用和依赖打包成一个镜像,走到哪儿都能跑,再也不用担心"在我机器上能跑"的问题了。
我们项目用的是 Spring Boot + Vue,前后端分离。前端用 Nginx serve,后端打成 jar 包用 Docker 运行。docker-compose.yml 大概是这样的:
version: '3.8'
services:
backend:
build: ./backend
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
- DB_HOST=postgres
depends_on:
- postgres
- redis
frontend:
build: ./frontend
ports:
- "80:80"
depends_on:
- backend
postgres:
image: postgres:14
volumes:
- pgdata:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=secret
redis:
image: redis:7-alpine
volumes:
pgdata:
这样一套下来,新同事入职只需要装好 Docker 和 Docker Compose,clone 代码,敲一行 docker-compose up -d,整个系统就跑起来了再也,不用花半天时间配环境。
至于 Kubernetes,之前也尝试过一段时间,但说实话,对于我们这种小团队来说,Kubernetes 的学习成本和运维成本都有点高。Docker Compose 已经能满足我们的需求,等团队规模大一些再考虑上 K8s。
一些小心得
最后分享几个我觉得比较有用的经验:
1. 做好监控和告警。部署成功不代表万事大吉,要监控应用健康状态、错误日志、接口响应时间等指标。我们用的是 Prometheus + Grafana + 钉钉告警,效果还不错。
2. 保留回滚能力。每次部署前自动打一个镜像标签,出了问题一键回滚到上一个版本,这个功能救过我的命。
3. 部署日志要完整。谁在什么时候部署的、部署的是哪个版本、部署过程中有没有错误,这些信息都要记录下来,方便出问题的时候排查。
4. 小步迭代。不要想着一口气把自动化做得十全十美,先把最痛的点解决掉,比如自动打包、自动部署测试环境,然后再逐步完善。
总结
自动化部署这件事,说难也不难,说简单也不简单。关键是要迈出第一步,然后不断迭代优化。现在我们团队每次部署基本不需要人工干预,推送代码后 CI 自动跑完测试、构建镜像、部署到对应环境,整个过程可能就几分钟的事。
虽然前期需要花时间搭建和踩坑,但长远来看省心太多了。最重要的是,终于不用熬夜部署了,头发也少掉了几根(误)。
如果你还在被手动部署折磨,不妨试试从今天开始搭建第一套自动化流程,哪怕只是自动打包、自动测试,也比纯手动强太多。祝各位部署顺利,永无 bug!
我的自动化部署实践
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法