把容器镜像交给 SWR:从推拉镜像到安全上线的完整实践思路
做容器化部署久了,会慢慢形成一个共识:代码可以随时改,镜像却必须是确定的。一次上线到底跑的是哪个版本的代码,答案不在仓库的提交记录里,而在镜像仓库的那个标签上。镜像仓库看起来只是个存放文件的地方,实际上它是整个交付链路的事实来源。把这件事想清楚,再去选工具、定规范,会少走很多弯路。
一、为什么需要一个私有的镜像仓库
刚接触容器时,很多人直接用公共镜像仓库,用着也挺顺手。但项目一旦要正式上线,问题就一个个冒出来:公共仓库的拉取速度和稳定性不受自己控制;公司的业务镜像放在公共仓库不合适,合规上也说不过去;镜像里一旦混入敏感信息,清理起来非常被动。
私有镜像仓库解决的是三个基本问题:第一,镜像的存放位置自己说了算;第二,谁能拉、谁能推,有明确的权限边界;第三,镜像从构建到上线全程可追溯。这三个问题解决了,容器化交付才算有了底。
华为云的容器镜像服务 SWR(Software Repository for Container),就是这样一个面向容器镜像的托管服务。它和弹性云服务器、云容器引擎 CCE、CodeArts 这些服务在同一个云上,镜像从构建、存放到被集群拉取,整条链路都在云内完成。
二、SWR 里最核心的三个概念
第一次打开 SWR 控制台,会看到三个层层递进的概念:组织、镜像仓库、镜像标签。
组织(Organization)相当于命名空间,一般按团队或者项目来划分,比如后端团队一个组织,前端团队一个组织。组织之下是镜像仓库,一个镜像仓库对应一个应用的镜像,例如 myapp。镜像仓库之下是镜像标签(Tag),一个标签对应镜像的一个版本,例如 v1.0.0、v1.1.0。
镜像的完整名字就是这三层拼起来:
仓库地址/组织名/镜像名:标签
例如 swr.cn-north-4.myhuaweicloud.com/myteam/myapp:v1.0.0。这里的仓库地址是区域相关的,每个区域有自己独立的镜像仓库地址。名字里的每一层都有用:组织用来隔离团队,镜像名用来区分应用,标签用来区分版本。
三、第一次推拉镜像:四条命令走通全流程
理论说完,动手走一遍是最快的理解方式。假设本地已经有一个打好标签的应用镜像,完整流程只需要四步。
第一步,登录。在 SWR 控制台找到登录指令,用华为云账号名和密码执行 docker login。控制台提供的登录指令可以直接复制使用,省去了自己拼地址的麻烦。
docker login -u <账号名> -p <密码> swr.cn-north-4.myhuaweicloud.com
第二步,给本地镜像打上 SWR 的地址标签。docker tag 不复制镜像文件,只是给同一个镜像多起一个名字。
docker tag myapp:v1.0.0 swr.cn-north-4.myhuaweicloud.com/myteam/myapp:v1.0.0
第三步,推送。
docker push swr.cn-north-4.myhuaweicloud.com/myteam/myapp:v1.0.0
第四步,在另一台机器或者集群节点上拉取验证。
docker pull swr.cn-north-4.myhuaweicloud.com/myteam/myapp:v1.0.0
这四条命令跑通,说明账号权限、网络、镜像命名都没有问题。之后所有更复杂的操作,都是在这个流程上加规则。
四、让 CCE 集群拉到私有镜像
镜像推上去了,下一步是让云容器引擎 CCE 的集群能把它拉下来。私有镜像和公开镜像的区别就在这里:公开镜像谁都能拉,私有镜像需要凭证。
最常用的做法是在集群所在的命名空间里创建一个 docker-registry 类型的 Secret,把 SWR 的登录账号密码放进去,然后在工作负载的 Pod 模板里通过 imagePullSecrets 引用它:
kubectl create secret docker-registry swr-secret \
--docker-server=swr.cn-north-4.myhuaweicloud.com \
--docker-username=<账号名> \
--docker-password=<密码> \
-n default
spec:
imagePullSecrets:
- name: swr-secret
containers:
- name: myapp
image: swr.cn-north-4.myhuaweicloud.com/myteam/myapp:v1.0.0
如果镜像和集群在同一个区域、同一个账号下,配置起来最简单;跨区域或者跨账号时,就要多想一步:镜像要不要复制到目标区域,目标账号有没有拉取权限。这些问题提前想好,比上线当天再排障轻松得多。
五、镜像安全的四件小事
镜像安全这件事,平时感觉不到它的存在,出问题时才后悔。比较稳妥的做法,是把四件小事做在前面。
第一,默认私有。新建的镜像仓库默认不公开,只有明确要对外分享的基础镜像才设为公开。公开是一次性操作,收回公开的影响却可能扩散到所有拉取方。
第二,定期做镜像安全扫描。SWR 提供镜像扫描能力,可以发现镜像里的已知漏洞。扫描不是上线前才想起来的仪式,而是每次推送新版本后的固定动作。发现高危漏洞先修镜像、再发版本,不要带着已知漏洞上线。
第三,生产环境用 digest 锁定版本。标签是可以被覆盖的,今天的 v1.0.0 和明天的 v1.0.0 未必是同一个镜像。生产环境引用镜像时,用镜像摘要(digest)锁定,例如 myapp@sha256:xxxx…,这样无论标签怎么变,跑的都是当时验证过的那一份。
第四,定期清理。镜像越积越多,旧版本、无人使用的测试镜像会悄悄占用空间。按保留策略定期清理,比如只保留最近几个版本和正在使用的版本,仓库会一直保持清爽。
六、团队协作的命名和标签习惯
镜像仓库是团队共用的,规范比工具更重要。几个实践中比较顺手的习惯:
- 一个镜像仓库只放一个应用的镜像,不要把多个应用塞进同一个仓库。
- 标签用语义化版本,例如 v1.2.3,major 版本变化表示不兼容的改动,minor 表示新增功能,patch 表示修复。
- latest 只用在开发联调环境,测试和生产环境永远写死具体版本号。
- 组织名和镜像名都用小写字母、数字和中划线,避免特殊字符带来的麻烦。
这些习惯看起来琐碎,但当团队里十几个人同时推镜像、集群里跑着几十个版本时,规范就是唯一的秩序来源。
七、遇到问题先看哪里
推拉镜像遇到问题时,大部分情况出在三个地方,可以按顺序排查。
推送失败,先看登录。账号密码有没有输错、登录指令里的仓库地址对不对、网络能不能通到 SWR。docker login 成功是推送的前提。
拉取失败,先看权限和名字。镜像名有没有拼错、标签存不存在、拉取的账号有没有这个镜像仓库的读取权限。把完整镜像名复制到控制台搜索一下,往往能立刻定位问题。
集群拉取镜像失败,除了上面两点,再看 Secret。有没有创建在正确的命名空间、Secret 里的账号密码有没有过期、工作负载有没有正确引用 imagePullSecrets。这三项都对,基本就能拉下来。
八、把 SWR 放进整条交付链路里看
单独看 SWR,它是一个镜像仓库;放进交付链路里看,它是连接构建和运行的枢纽。上游是 CodeArts 这类 CI 工具,代码合入后自动构建镜像并推送到 SWR;下游是 CCE 集群,从 SWR 拉取指定版本的镜像运行。中间是 SWR 的权限、扫描和清理规则,保证流进来的镜像干净、流出去的镜像可控。
把这条链路跑通之后,发布新版本就变成一件很确定的事:构建一次,推送一个带版本号的镜像,集群更新到这个版本,回滚就是把版本改回去。镜像仓库,就是这份确定性的底座。
如果你正在把业务往容器化迁移,不妨先花半天时间把 SWR 的组织、权限、标签规范定下来。这半天花得值,后面每一次上线都会因此省心一点。
- 点赞
- 收藏
- 关注作者
评论(0)