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.3git-commit-hash
  • 定期清理——没人用的旧镜像就是磁盘杀手,写个脚本每周清理一次
  • 安全第一——Harbor的漏洞扫描一定要开,我见过一个基础镜像有200多个高危漏洞

镜像管理看起来简单,但真正用好它,需要理解分层原理,熟悉常用命令,再搭一个靠谱的私有仓库。嗯,这些你都掌握了,下一步就可以开始玩CI/CD流水线了。