用GitHub Actions配合华为云SWR搞定个人项目的轻量自动化部署
做独立开发或者维护几个小网站,每次发布新版本最让人头疼的就是上线流程。以前我的做法特别原始:要么本地打包完二进制,scp传上服务器,手忙脚乱地关服务、换文件、再重启;要么直接在华为云服务器上装Git和编译环境,每次ssh上去git pull然后原地编译。
这种方式在单台小机器上跑非常折腾:有时候碰上依赖包更新,小机器在编译时CPU直接被拉到100%,内存吃紧甚至引发OOM,正在跑的线上服务跟着卡死;加上在服务器本地经常遇到各种外部网络拉取超时,每次发版都得盯着终端守十几分钟。
后来我想做一套全自动的CI/CD流水线,但市面上常见的重型方案(比如自己搭个Jenkins或者搞套轻量K8s集群)对我这台2核4G的云服务器来说实在太奢侈了,光是跑那些底座组件就能吃掉大半资源。琢磨了一圈,我决定把“构建”和“运行”彻底拆开:利用GitHub Actions的免费算力在云端远程构建Docker镜像,推送到华为云SWR(容器镜像服务),最后通过SSH在服务器上静默拉取并重启容器。折腾完这套轻量部署方案后,发版体验直接变成了“本地推完代码就关电脑”,记录一下整个过程中踩平的几个坑。
第一件事是把镜像托管从公开仓库迁移到华为云SWR。
最开始我想着图省事,直接把镜像推到Docker Hub或者国外的一些公开仓库。
但在实际部署拉取时经常让人火大:因为网络波动,我的云服务器从国外拉镜像经常卡在某个层不动,或者速度只有几十KB,一次更新能耗上二十分钟,偶尔还会拉取失败导致发布中断。
后来发现华为云的SWR容器镜像服务对个人开发者非常友好,有免费的基础配额,而且因为和我的ECS云服务器在同一个国内可用区,走内网或者国内骨干网拉取镜像,基本都是瞬间拉满带宽,一个上百兆的镜像三四秒就能拽下来。
不过配置这里有个小细节:在GitHub Actions里登录SWR时,不要用每次几小时就过期的临时登录凭证,而是去华为云SWR控制台生成一个专属的长期登录密钥(AK/SK转换后的固定密码),把这个密钥安全地保存在GitHub仓库的Secrets配置里,流水线就能长期稳定地完成自动鉴权。
第二件事是做好Docker构建缓存,别每次都全量重新下载依赖。
刚配好流水线跑前几次构建时,我发现每次在GitHub Actions里打镜像都要耗费六七分钟,大部分时间都花在下载系统基础依赖和前端npm包上。
Docker的层缓存(Layer Cache)机制如果没用好,一旦代码有变动就会导致后面的缓存全部失效。
解决办法分两步:
首先是在项目根目录下写好严格的.dockerignore,把本地的node_modules、临时构建产物、.git目录和测试文件通通剔除,避免把不相干的文件作为构建上下文传给Docker引擎;
其次在Dockerfile里严格区分依赖安装和业务代码复制。先单独拷贝package.json或者requirements.txt并执行安装,最后一步再复制源代码。这样只要依赖文件没有变更,前面的依赖层就会直接命中缓存。
同时在GitHub Actions里启用GitHub自带的Cache后端(type=gha),把构建缓存保留下来,改完之后单次构建耗时直接从七分钟压缩到了一分半左右。
第三件事是解决旧镜像疯狂蚕食服务器磁盘的问题。
流水线跑顺畅之后,我经常本地修个小文案也顺手git push触发自动上线。
跑了一个多月后,有一天登录服务器敲df -h看状态,发现40G的系统盘居然红了,使用了超过92%。
进Docker目录一查才发现罪魁祸首:每次自动发布新版本,旧容器虽然被停掉了,但之前版本的镜像并没有被清理,在本地全变成了标记为none的虚悬镜像(Dangling Images)。一个月下来几十次发版,几百兆的镜像堆了几十个,不知不觉把小云主机的磁盘塞得满满当当。
解决这个问题不需要额外的复杂监控,只要在最终执行更新的Shell脚本末尾顺手补上一行清理命令:docker image prune -af --filter until=72h。这行命令的意思是强制清理掉所有未被任何容器使用的旧镜像,但保留最近72小时内生成的层作为回滚缓冲。加上这句之后,服务器上的旧镜像会自动维持在极低数量,磁盘水位再也没异常过。
第四件事是轻量单机上的简易平滑切换。
只有单台机器时,通常不能像集群那样做复杂的滚动发布。早期我写部署脚本特别野蛮:docker stop旧容器,然后docker rm,最后docker run新镜像。
这意味着在拉取新镜像以及新服务初始化的这十几秒甚至半分钟里,外部访问是完全断开的,直接返回502 Bad Gateway。
为了让几秒钟的短暂中断降到最低,我把脚本改成了“先拉后起再删”的顺序:
脚本登录SWR后,先执行docker pull把最新镜像在后台完整下载好,这时候线上旧容器还在正常扛请求;
拉完之后,再执行替换操作。如果想要更稳一点,可以用Docker Compose配合一个最简单的同端口映射交替,或者把服务启动时间压缩到秒级后再平滑重载Nginx代理。现在整套发布过程对外部访问来说基本只有一瞬间的无感重试,完全不影响正常浏览。
整套流水线跑通到现在已经有几个月了。
现在日常写代码彻底摆脱了心智负担:只要本地git push到main分支,GitHub在后台默默编译打包打标签,推送到华为云SWR,接着通过SSH自动触发服务器拉取更新并清理垃圾,全程两分钟自动化搞定,手机上甚至能实时收到微信或者飞书的发布成功提醒。
对于没有复杂业务体量的个人开发者来说,真没必要过早去追逐微服务治理那一套繁重的工具链。单台华为云服务器配合远程免费算力和云镜像仓库,足够搭出一套兼顾开发体验、运行速度和极低维护成本的自动化发布体系。
- 点赞
- 收藏
- 关注作者
评论(0)