华为云 SWR 实战:本地 Docker 镜像推送、拉取与常见坑全梳理
前言
很多团队上云的第一步就是把镜像从 Docker Hub 或自建 Registry 迁到华为云容器镜像服务 SWR(SoftWare Repository for Container)。流程看起来只有 docker login、docker tag、docker push 三步,但实际操作中经常卡在登录过期、区域写错、权限不足这些细节上。本文用一个简单的 Go 服务做例子,把完整链路走一遍,并把我踩过的坑集中整理出来。
说明:本文以华北-北京四(
cn-north-4)为例,其它区域把区域代码替换即可。控制台菜单名称可能随版本调整,以实际界面为准。
一、先搞清楚镜像地址的结构
SWR 的镜像完整地址由四部分组成:
swr.<区域代码>.myhuaweicloud.com/<组织名>/<镜像名>:<标签>
例如:
swr.cn-north-4.myhuaweicloud.com/demo-team/order-service:1.2.0
- 区域 Endpoint:形如
swr.cn-north-4.myhuaweicloud.com,每个区域独立,镜像不会自动跨区域共享。 - 组织(Organization):相当于命名空间,用来隔离团队或项目,权限也按组织授权。推送前必须先在控制台“组织管理”中创建,组织名在区域内全局唯一,建议带上公司或团队前缀,避免和别人冲突。
- 镜像名与标签:镜像名建议用小写字母、数字和
-;标签遵循 Docker 规范(字母、数字、_、.、-,不能以.或-开头)。
二、登录:临时指令 vs 长期指令
1. 临时登录指令
在 SWR 控制台“总览”或镜像列表页点击“登录指令”,可以直接复制一条临时登录命令,格式大致如下:
docker login -u cn-north-4@<AK> -p <临时令牌> swr.cn-north-4.myhuaweicloud.com
临时指令有效期较短(控制台标注为 24 小时左右),适合本地手动调试。不要把它写进 CI 脚本,否则第二天流水线就会莫名失败。
2. 长期登录指令
CI/CD 或构建机建议使用长期登录指令。用户名是 区域项目名@AK,密码由 SK 对 AK 做 HMAC-SHA256 计算得到:
AK="你的AccessKey"
SK="你的SecretKey"
# 生成登录密钥
LOGIN_KEY=$(printf "$AK" | openssl dgst -binary -sha256 -hmac "$SK" \
| od -An -vtx1 | sed 's/[ \n]//g' | sed 'N;s/\n//')
echo "$LOGIN_KEY" | docker login -u "cn-north-4@${AK}" --password-stdin \
swr.cn-north-4.myhuaweicloud.com
几点注意:
- 长期指令在 AK/SK 有效期内一直可用,AK 被删除或停用后立即失效。
- 建议为 CI 单独创建一个 IAM 用户和 AK,只授予必要组织的权限,而不是直接用主账号 AK。
- AK/SK 放到流水线的密钥变量里,用
--password-stdin避免出现在 shell 历史和日志中。
三、构建与推送:顺手做一次多阶段瘦身
一个典型的 Go 服务,如果直接用 golang 基础镜像打包,镜像往往有几百 MB。用多阶段构建只把二进制拷到运行镜像中,体积能明显下降,推送和拉取都会更快:
# 构建阶段
FROM golang:1.22 AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /out/app ./cmd/server
# 运行阶段
FROM alpine:3.20
RUN apk add --no-cache ca-certificates tzdata
WORKDIR /app
COPY --from=builder /out/app /app/app
USER 65534
ENTRYPOINT ["/app/app"]
其它瘦身习惯:
- 写好
.dockerignore,排除.git、本地构建产物、测试数据。 - 先复制依赖描述文件再复制源码,充分利用层缓存。
- 合并
RUN指令并在同一层清理包管理器缓存。
构建、打标签、推送:
REGISTRY=swr.cn-north-4.myhuaweicloud.com
ORG=demo-team
IMAGE=order-service
TAG=1.2.0-$(git rev-parse --short HEAD)
docker build -t ${IMAGE}:${TAG} .
docker tag ${IMAGE}:${TAG} ${REGISTRY}/${ORG}/${IMAGE}:${TAG}
docker push ${REGISTRY}/${ORG}/${IMAGE}:${TAG}
标签建议:生产环境不要依赖 latest。推荐“语义化版本 + 短 commit”的组合,既可读又能精确回溯到代码版本;latest 可以额外打一份给开发环境用。
四、在同区域 ECS 上拉取
在同区域(同为 cn-north-4)的 ECS 上,同样先登录再拉取:
docker login -u cn-north-4@<AK> -p <登录密钥> swr.cn-north-4.myhuaweicloud.com
docker pull swr.cn-north-4.myhuaweicloud.com/demo-team/order-service:1.2.0-a1b2c3d
同区域的 ECS 使用华为云默认内网 DNS 时,访问 SWR 一般可以走内网,速度和稳定性都更好。如果 ECS 没有绑定 EIP 却拉取失败,可以排查两点:一是 /etc/resolv.conf 中的 DNS 是否被改成了公网 DNS;二是所在 VPC 是否需要按官方文档配置 SWR 相关的 VPC 终端节点。具体网络方案以官方文档为准。
如果是在云容器引擎 CCE 中使用,CCE 命名空间下默认提供名为 default-secret 的镜像拉取密钥,工作负载拉取同区域 SWR 私有镜像时引用它即可,无需在节点上手动 docker login。
五、常见坑与排查
坑 1:denied: You may not login yet
这是推送或拉取时最常见的报错,基本含义是“当前请求没有有效的登录凭证”。常见原因:
- 临时登录指令已过期,重新获取或改用长期指令。
- 登录的 Endpoint 和推送地址的区域不一致,例如登录了
cn-north-4,推送地址却写成cn-east-3。 - 使用了
sudo docker push,而登录时没有加sudo,两者读取的凭证文件(~/.docker/config.json)不同。 - 长期登录密钥计算错误,比如 AK/SK 里混入了换行符。
可以用 cat ~/.docker/config.json 查看当前已登录的 Registry 列表进行核对。
坑 2:区域写错导致“镜像找不到”
镜像推到了 cn-north-4,CCE 集群却在 cn-south-1,就会出现拉取失败。SWR 各区域相互独立,跨区域使用需要在目标区域再推一份,或使用 SWR 提供的镜像同步能力(以控制台实际功能为准)。
坑 3:IAM 子用户有登录权限却推不上去
子用户除了需要 SWR 服务层面的 IAM 权限,还需要在目标组织上被授予相应权限(只读 / 编辑 / 管理)。只读只能拉取,推送至少需要编辑权限。报 denied 类错误且确认已登录时,优先检查组织授权。
坑 4:组织不存在
推送地址里的组织名必须提前创建,拼写错误或大小写不一致都会导致推送失败。
六、镜像保留与清理
按 commit 打标签后,镜像版本会快速增长。建议:
- 在镜像仓库中配置镜像老化规则,可以按保留天数或保留标签数量自动清理旧版本,并通过标签保留规则把
release-*之类的正式版本排除在外。 - 构建机上定期执行
docker image prune -f,避免本地磁盘被悬空镜像占满。 - 删除镜像前确认没有线上工作负载仍在引用该标签,否则节点重新调度时会拉取失败。
七、小结
| 环节 | 推荐做法 | 常见坑 |
|---|---|---|
| 登录 | CI 使用长期登录指令 + --password-stdin |
临时指令过期、sudo 凭证不一致 |
| 组织 | 推送前创建,按团队/项目划分 | 组织不存在、子用户未授权 |
| 标签 | 语义化版本 + 短 commit | 生产依赖 latest 难以回溯 |
| 构建 | 多阶段构建 + .dockerignore |
带着编译工具链上线,镜像臃肿 |
| 拉取 | 同区域 ECS/CCE,CCE 用 default-secret |
区域不一致、DNS 被改导致走不了内网 |
| 清理 | 配置镜像老化规则 + 本地 prune | 误删线上仍在使用的标签 |
SWR 本身使用门槛不高,真正影响效率的是登录方式、区域和权限这些细节。把长期登录、命名规范和老化规则一次配好,后续接入 CCE 或流水线基本就是“改个镜像地址”的事情。
- 点赞
- 收藏
- 关注作者
评论(0)