Next项目自动化部署之使用阿里云镜像仓库

技术相关153233 阅读0

之前我Github Action的workflows部署Nextjs项目的流程是这样的:控制服务器拉取代码,打包、构建镜像并运行。

由于打包代码后构建镜像都在我2核2G的服务器上,导致执行这个流程的时候服务器上的其他应用卡顿,有时候甚至会导致服务器卡死。

思索之下决定优化我的部署流程,采用在Github Action打包和构建镜像,服务器直接拉取镜像并运行的方式,大大减轻了我服务器压力。

这个方法最关键的是需要一个镜像仓库,我这里选择的是阿里云镜像仓库

创建容器

打开阿里云官网镜像仓库官网,首先先创建一个个人实例。然后需要在这个实例下创建一个命名空间,这个命名空间只相当于一个文件夹。关键的是在这个命名空间下创建一个镜像仓库。

我推荐直接使用项目名来命名这个镜像仓库,因为一个镜像仓库通常只放你的这一个项目,方便统一命名和版本管理。

推送镜像

创建完镜像仓库之后会得到一份操作指南,如何控制这个镜像仓库登录、推送等方法按照其给出的方法就行。

在我nextjs项目的workflows文件中我是这样的流程:

  • docker login --username=xxx --password=xxx xxxx.cn-chengdu.personal.cr.aliyuncs.com

  • docker build (这一步会根据你项目中的Dockerfile来构建镜像)

  • docker push xxx

至此我们的镜像就构建完成,并且推送这个镜像到了阿里云仓库。

部署

我们继续在workflows中控制服务器来部署

首先通过ssh访问服务器,然后

  • 和上面一样的登录流程
  • docker compose pull xxx (拉取镜像)

  • docker compose up -d xxx (启动镜像)

  • docker image prune -af (清除旧镜像)

遇到的问题

首先是在用ssh连接服务器的阶段,因为<< 'EOF'后执行都是在服务器上,这里面的指令无法使用workflows中定义的env变量。这个问题让我兜兜转转了一早上,连ChatGPT都没有发现这个问题。最终Claude +deepseek 一眼看出了问题:

关键在这里:

  ssh -i private_key.pem -o StrictHostKeyChecking=no root@xx.xx.xx.xx << 'EOF'

  << 'EOF'(带引号)会阻止 shell 对 heredoc 中的变量进行展开。所以 $REGISTRY 被原样发送到远程服务器,但远程服务器上并没有定义这个变量,docker login 没有收到 registry 地址,就默认去连 Docker
  Hub(registry-1.docker.io),而你的服务器在国内,Docker Hub 被墙,导致超时。

  修复方案:在远程命令中显式定义 REGISTRY,或者直接在命令里写死地址。

其次是Next.js 在 Docker 容器内的 DNS 解析问题。容器 hostname 被设成了容器 ID xxxx,但 Next.js 尝试解析这个 hostname 时失败了。

原因是Next.js standalone 模式默认用系统 hostname(即容器 ID)作为监听地址,但容器内无法解析这个 hostname。需要指定 HOSTNAME=0.0.0.0。

在 Dockerfile 的 runner 阶段加了 ENV HOSTNAME=0.0.0.0,让 Next.js 监听所有网络接口,而不是尝试解析容器 ID。

推送后 CI 会自动重新构建镜像并部署,问题就解决了。

 WORKDIR /app

ENV NODE_ENV=production
ENV HOSTNAME=0.0.0.0 
ENV PORT=8080

结论

顺手将我的Java服务的部署也按照同样的方式优化了,服务器更清爽了。

能使用第三方的免费服务还真不错。最初的时候我在我的小服务器上部署了Jenkins,由自己管理部署流程。从监听代码仓库变动自动拉取代码,到项目一件回滚等,折腾了几天下来,最终的结果就是每天重启N次服务器。

最后使用Github Action,服务器的压力也减轻了,只用接收GitHub构建后的产物就行了,非常轻量。

到现在又使用了阿里云的镜像仓库来优化了我沉重的Next部署流程,不得不说,还是得善用工具。

由于这篇文章是快速记录我的踩坑流程,有些地方我说的可能不是很详细。如果有疑问欢迎下方评论区交流。

评论

发表评论