Docker镜像管理:从原理到实战
镜像管理,说白了就是Docker的命根子。我刚开始接触Docker时,总觉得镜像不就是个压缩包吗?后来踩了不少坑才明白——理解镜像分层,才是用好Docker的第一步。
镜像分层原理:为什么Docker镜像这么“省”
你想想看,如果每个容器都完整打包一个操作系统,那硬盘早就爆了。Docker的精妙之处就在于——分层。
每个Docker镜像由多个只读层叠加而成。每一层代表一个Dockerfile指令。比如:
FROM ubuntu:20.04 # 基础层
RUN apt-get update # 第二层
COPY app /app # 第三层
CMD ["./app"] # 元数据层
这些层是共享的。我在项目中遇到过这样的情况:五个微服务都基于同一个Ubuntu镜像,实际磁盘占用只有一份基础层。这就是分层复用的威力。
核心要点:镜像层是只读的,容器启动时会在最上层加一个可写层。所有写操作都在可写层完成,镜像本身不会被修改。
为什么会这样设计?因为一旦层被共享,就不能随便改了。你改了一层,所有依赖它的镜像都得重建。嗯,这里要注意——层的顺序很重要。经常变动的指令(比如COPY代码)应该放在后面,这样能最大化利用缓存。
常用镜像命令:每天都要敲的命令
这些命令我几乎每天都在用。咱们一个一个说。
1. docker pull:拉取镜像
docker pull nginx:latest
docker pull registry.cn-hangzhou.aliyuncs.com/library/nginx:1.21
默认从Docker Hub拉取。国内用户建议配个镜像加速器,不然慢得想砸键盘。我曾经在客户现场没配加速器,拉一个200MB的镜像等了半小时……
小技巧:拉取时指定具体版本号,别用latest。latest在生产环境就是个定时炸弹——今天拉的和明天拉的可能是两个东西。
2. docker images:查看本地镜像
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 605c77e624dd 2 weeks ago 141MB
ubuntu 20.04 ba6acccedd29 4 weeks ago 72.8MB
我习惯加个 --format 参数,只看我关心的字段:
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
3. docker rmi:删除镜像
docker rmi nginx:latest
docker rmi 605c77e624dd # 用IMAGE ID删除
注意:如果有容器正在使用这个镜像,是删不掉的。得先删容器。我曾经手滑想删一个镜像,结果发现十几个容器都依赖它……
避坑指南:不要用 docker rmi $(docker images -q) 这种骚操作。除非你确定要清空所有镜像。我见过有人把生产环境的镜像全删了,然后……嗯,你懂的。
4. docker tag:给镜像打标签
docker tag nginx:latest myregistry.com/nginx:v1.0
docker tag ubuntu:20.04 ubuntu:20.04.3
标签其实就是个别名。同一个镜像ID可以有多个标签。我个人习惯用 项目名-环境-版本 的命名方式,比如 order-service-prod-v2.1.0。
5. docker push:推送镜像
docker push myregistry.com/nginx:v1.0
推送前必须先登录:
docker login myregistry.com
这里有个坑——如果你没打标签直接push,默认会推latest。我建议每次push前都确认一下标签对不对。
搭建私有镜像仓库:Harbor实战
公共仓库虽好,但企业级场景下,你得有自己的仓库。Harbor是目前最流行的选择。为什么?因为它不光是个仓库,还带安全扫描、权限管理、复制策略——说白了就是企业级该有的它都有。
安装Harbor
先下载离线安装包:
wget https://github.com/goharbor/harbor/releases/download/v2.8.0/harbor-offline-installer-v2.8.0.tgz
tar xzf harbor-offline-installer-v2.8.0.tgz
cd harbor
修改配置文件 harbor.yml:
hostname: 192.168.1.100 # 改成你的IP或域名
http:
port: 80
https:
port: 443
certificate: /your/cert.pem
private_key: /your/key.pem
harbor_admin_password: Harbor12345
然后执行安装:
./install.sh
安装完成后,浏览器访问 http://192.168.1.100,默认账号 admin,密码 Harbor12345。
个人经验:生产环境一定要配HTTPS。我见过有人用HTTP跑Harbor,结果镜像被中间人篡改,部署上去的应用全是挖矿程序……
配置Docker客户端
要让Docker信任Harbor,需要配置 /etc/docker/daemon.json:
{
"insecure-registries": ["192.168.1.100"]
}
然后重启Docker:
systemctl restart docker
登录测试:
docker login 192.168.1.100
推送镜像到Harbor
docker tag nginx:latest 192.168.1.100/library/nginx:v1.0
docker push 192.168.1.100/library/nginx:v1.0
在Harbor的Web界面就能看到这个镜像了。你还可以配置项目权限——比如开发团队只能push到dev项目,只有运维能push到prod项目。
Harbor的进阶功能
| 功能 | 说明 | 我的建议 |
|---|---|---|
| 镜像复制 | 跨机房同步镜像 | 灾备必备,我一般配双向复制 |
| 漏洞扫描 | 自动检测镜像安全漏洞 | 每次push都扫一遍,别偷懒 |
| 垃圾回收 | 清理未被引用的镜像层 | 每月跑一次,能省不少磁盘 |
| Webhook | 镜像更新时触发CI/CD | 配合Jenkins或GitLab CI很香 |
重要提醒:Harbor的垃圾回收操作会锁住仓库,建议在业务低峰期执行。我曾经白天跑了一次GC,结果CI/CD全部卡住……
镜像管理的最佳实践
最后分享几个我踩坑总结出来的经验:
- 镜像要小——用Alpine基础镜像,多阶段构建,别把编译工具链带进生产镜像
- 标签要有意义——别用latest,用
v1.2.3或git-commit-hash - 定期清理——没人用的旧镜像就是磁盘杀手,写个脚本每周清理一次
- 安全第一——Harbor的漏洞扫描一定要开,我见过一个基础镜像有200多个高危漏洞
镜像管理看起来简单,但真正用好它,需要理解分层原理,熟悉常用命令,再搭一个靠谱的私有仓库。嗯,这些你都掌握了,下一步就可以开始玩CI/CD流水线了。