第4章 Docker镜像基础:分层原理、镜像仓库、私有仓库搭建

这一章我们聊聊Docker镜像最核心的东西。说它基础,是因为后面所有质控流程都踩在这些概念上。我见过不少团队镜像越做越大、构建越来越慢,根源就是没吃透分层原理。咱们把底打牢,后面才省心。

4.1 分层原理——镜像为什么这么“轻”

Docker镜像不是一个大文件,而是一堆只读层的堆叠。每层记录文件系统的增量变化。你写一条RUN指令,Docker就会在已有层上面加一层新层。容器启动时,联合挂载(UnionFS)把这些层合并成完整的根文件系统。

这个机制带来了两个好处:

  • 复用缓存——层没变,构建时直接用缓存,不用重跑。
  • 节省空间——多个镜像共享相同的底层(比如Ubuntu基础层),磁盘上只存一份。
我的经验:分层是“空间换时间”的典范。但层数太多反而拖慢构建和拉取。我一般在三个到五个RUN指令之间权衡,太多就合并一下。

每层都是只读的。容器运行时再叠加一层可写层(容器层)。你改文件、删文件都只影响这一层,不影响镜像本身。这就是容器与镜像分离的关键——镜像不变,实例随便改。

来看一个简单的例子,看看分层长什么样:

FROM ubuntu:22.04
RUN apt-get update && apt-get install -y python3
COPY app.py /app/
CMD ["python3", "/app/app.py"]

这个Dockerfile实际上构建出四层:

  1. ubuntu:22.04 基础镜像(层1)
  2. apt-get 安装python3(层2)
  3. COPY app.py(层3)
  4. CMD 元数据层(层4,只记录指令,不占空间)
避坑:我曾经犯过一个错:在同一个RUN里既装包又删缓存,但忘了清理/var/cache/apt。结果每层都保存了缓存文件,镜像体积翻了一倍。正确做法是apt-get clean在同一层里做。

4.2 镜像仓库——去哪找镜像、怎么推送

镜像仓库就是Docker镜像的存储和分发中心。最常用的是Docker Hub(公共的),但你想想看,企业内部质控环境肯定不能全用公网仓库——延迟、安全、限速都是问题。

仓库的命名规则很简单:<仓库地址>/<用户名>/<镜像名>:<标签>。不加仓库地址就默认Docker Hub。例如:

docker pull ubuntu:22.04
docker pull registry.example.com/qa-team/app:v1.2

第一条是从Docker Hub拉,第二条是从私有仓库拉。我这里强调一下:在质控环境里,一定要给镜像打上明确版本标签,别用latest。我有个项目就因为latest指向了不同时间点的镜像,导致测试环境炸了两次。从那以后,我定了个规矩:所有镜像必须带YYYYMMDD-{build}或vX.Y.Z标签。

常用仓库操作

命令说明
docker pull 镜像名拉取镜像
docker push 镜像名推送镜像
docker tag 源镜像 目标镜像给镜像重打标签
docker search 关键词搜索公共镜像
docker login 仓库地址登录仓库

4.3 私有仓库搭建——用Harbor给质控环境加把锁

私有仓库在质控场景里是刚需。你想想看:测试镜像、内部工具、合规版本,都不能暴露到公网。我建议用Harbor——这是目前最成熟的企业级镜像仓库。它支持RBAC、镜像漏洞扫描、复制、垃圾回收。

咱们这里只讲快速搭建,够质控团队用就行。Harbor依赖Docker Compose,安装方式如下:

# 下载离线安装包(选最新稳定版)
wget https://github.com/goharbor/harbor/releases/download/v2.9.0/harbor-offline-installer-v2.9.0.tgz
tar -xzf harbor-offline-installer-v2.9.0.tgz
cd harbor

# 复制配置模板并修改
cp harbor.yml.tmpl harbor.yml
# 修改 hostname、端口、管理员密码等
# 比如:
# hostname: registry.qa.internal
# http.port: 8080
# harbor_admin_password: Qa@2024!

# 准备安装
./prepare
# 安装(会启动所有容器)
sudo ./install.sh
关键配置项:如果不配HTTPS,记得在Docker daemon配置中添加insecure-registries。否则会报证书错误。

安装完成后,浏览器访问http://你的主机IP:8080,默认账户admin登录。然后创建项目(比如qa-env),把用户拉入项目,就能推送镜像了:

# 先打标签,注意要包含仓库地址
docker tag nginx:alpine registry.qa.internal/qa-env/nginx:3.2

# 登录
docker login registry.qa.internal

# 推送
docker push registry.qa.internal/qa-env/nginx:3.2
注意:如果在Docker daemon配置里加了insecure-registries,记得重启Docker服务。我曾经因为忘了重启,排查了半天,发现推送一直报x509错误……重启后就好了。

4.4 本章知识结构

下面这张图把分层原理、公共仓库、私有仓库的关系串起来了。你看一遍就明白:镜像从Dockerfile构建出来,经过分层缓存,可以推送到Docker Hub也能推到内部Harbor,质控流水线再从Harbor拉取进行测试。

Docker镜像基础核心逻辑图 Docker镜像基础:分层 - 仓库 - 私有仓库 Dockerfile 元数据层 COPY app.py apt-get install ubuntu基础层 Docker Hub Harbor 私有仓库 docker build / push 核心要点 1. 镜像由只读层叠加 2. 公用仓库:Docker Hub 3. 私有仓库:Harbor 4. 标签管理:别用latest 实战建议 • 每个RUN合并清理操作 • 私有仓库开启扫描

4.5 多节点同步与垃圾回收

当质控团队规模大了,一台Harbor可能不够。你要在多个机房部署Harbor实例,通过复制规则同步镜像。Harbor支持两种模式:

  • 推模式——主Harbor主动推给备节点
  • 拉模式——备节点主动去主节点拉

我建议质控环境用拉模式,因为备节点离线时不影响主节点的写入。配置复制规则在Harbor Web界面的“系统管理→复制管理”里,填上远端仓库地址和项目映射即可。

还有一个容易忽略的点:垃圾回收。镜像删除后,底层数据还在磁盘上,需要手动触发GC:

# 在Harbor主机上执行
docker run --rm -v /data/harbor:/data -v /var/run/docker.sock:/var/run/docker.sock \
  goharbor/registry-photon:v2.9.0 garbage-collect /etc/registry/config.yml
我的习惯:每周定时跑一次GC。否则半年后你会发现磁盘爆满,明明只存了50个镜像,却占了几百GB。Harbor官方也建议在低峰期执行。

好了,这章的内容就这些。记住三点:分层是镜像设计的灵魂,仓库是分发的枢纽,私有仓库是质控的基石。把这几个概念理清了,后面搭建批量质控环境就顺理成章了。