把本地镜像推送到阿里云 ACR,步骤不多,卡住的地方通常是两件事:镜像标签和登录凭证对不上。这篇文章以一个小团队的改造过程为例,重点讲推送前后怎么检查,出错时从哪里排查。

一、为什么用 Docker 加阿里云
Docker 让开发、测试和生产跑的是同一份镜像,“在我机器上是好的”这类问题会少很多。阿里云提供计算、存储和镜像仓库,团队不用自建机房也能拿到弹性资源。业务量有起伏、人手又不多的时候,这套组合比较省心。
二、案例背景
某县域生鲜电商团队有三名后端开发,服务由一个 Node.js 接口和一个 Python 定时任务组成。过去发布要手工登录服务器拉代码、装依赖,每次至少半小时。两台服务器的环境版本还不一致,因此引发过一次线上故障。团队决定引入 Docker,并把运行环境迁到阿里云 ECS 上。
三、准备工作
方案由三部分组成:ECS 做运行主机,ACR 存放镜像,安全组和 RAM 账号管访问。开通之后,建议先做这几件事:
- 在 ECS 上安装 Docker Engine,并配置阿里云提供的镜像加速器。基础镜像拉取快了,首次部署的等待时间会明显变短。
- 在 ACR 里建好命名空间和仓库,测试和生产镜像分开存放,避免生产环境误拉测试版本。
- 给发布用的子账号只授予必要的仓库推拉权限。主账号的 AccessKey 不要写进脚本或 CI 配置。
- 安全组只开放业务端口。数据库和 Docker 管理端口不要对公网开放,临时放开过的端口用完记得收回。
四、构建与推送镜像
团队在 Dockerfile 里选用官方轻量基础镜像,并用多阶段构建把编译工具留在构建阶段,最终镜像从约 1.1GB 降到 180MB 左右。
登录凭证
推送前要先登录。用户名是 RAM 子账号名,密码是在 ACR 控制台为登录设置的访问凭证密码,不是阿里云账号的登录密码。两者很容易混在一起,遇到 unauthorized 报错时先核对这一点。
echo "$ACR_PASSWORD" | docker login --username=发布子账号 --password-stdin registry.cn-hangzhou.aliyuncs.com
用 –password-stdin 传密码,比直接写在命令行里稳妥,密码不会留在 shell 历史中。ACR_PASSWORD 可以从环境变量或 CI 的密钥配置里读取。登录地址要和仓库所在地域一致,杭州地域是 registry.cn-hangzhou.aliyuncs.com,仓库建在其他地域时地址也要跟着换。
标签命名
推送地址由三段组成:仓库地址、命名空间加仓库名、标签。缺任何一段,或者命名空间拼错,推送时都会报 denied 之类的错误。构建时直接用完整地址打标签,可以省掉后面改名的步骤:
docker build -t registry.cn-hangzhou.aliyuncs.com/shop-team/api:v1.2.0 .
docker push registry.cn-hangzhou.aliyuncs.com/shop-team/api:v1.2.0
标签建议用版本号或提交哈希,不要长期使用 latest。latest 会随每次推送被覆盖,出问题时很难判断线上跑的是哪一版。同一个版本号推过一次之后就不要再覆盖,要改号重推。这样回滚只需切换到上一个标签。
五、部署与运维
在 ECS 上拉取指定版本并启动容器,加上重启策略,服务器重启后服务会自动恢复:
docker pull registry.cn-hangzhou.aliyuncs.com/shop-team/api:v1.2.0
docker run -d --name api --restart=always -p 8080:8080 --env-file /opt/app/.env registry.cn-hangzhou.aliyuncs.com/shop-team/api:v1.2.0
敏感配置通过 .env 文件或阿里云密钥管理服务注入,不写进镜像。镜像一旦打包,里面就不该有密码,否则拿到镜像的人都能看到。日志输出到标准输出,由日志服务统一采集,排查问题时在一个地方看就够了。
六、效果与经验
改造后,单次发布从半小时缩短到五分钟以内,回滚从手工重装变成一条命令。团队整理了几点经验:
- 先统一环境,再谈自动化。镜像本身就是交付物,比任何一台服务器上的手工配置都可靠。
- 镜像要瘦身。体积小,拉取快,里面的东西少,攻击面也随之变小。
- 权限和网络边界要在上线前定好。事后补,通常得停机或返工。
- 服务数量涨到十几个以上时,可以考虑迁到容器服务 ACK,由编排系统接管调度和扩缩容。
推送出问题,多半出在标签、地址和凭证这三处。三处对上了,后面的部署一般不会卡。