Skip to content

Docker 镜像管理

本章将深入讲解 Docker 镜像的管理,包括镜像的获取、构建、标记、分发和优化等核心操作。

镜像基础概念回顾

镜像的分层结构

Docker 镜像采用联合文件系统(Union File System),由多个只读层组成:

┌─────────────────────────────────────┐
│     应用层 (writable layer)         │  ← 容器运行时的可写层
├─────────────────────────────────────┤
│     Layer 4: 应用程序文件           │  ← 只读层
├─────────────────────────────────────┤
│     Layer 3: 应用依赖               │  ← 只读层
├─────────────────────────────────────┤
│     Layer 2: 运行时环境             │  ← 只读层
├─────────────────────────────────────┤
│     Layer 1: 基础操作系统           │  ← 只读层 (Base Image)
└─────────────────────────────────────┘

镜像标识

每个镜像都有唯一的标识符:

bash
# 完整格式
[registry_host[:port]/]username/repository[:tag]

# 示例
docker.io/library/nginx:1.21.6          # 官方镜像
docker.io/myuser/myapp:v1.0             # 用户镜像
registry.company.com:5000/team/app:latest # 私有仓库镜像

镜像获取操作

从仓库拉取镜像

bash
# 拉取最新版本
docker pull nginx

# 拉取指定版本
docker pull nginx:1.21.6

# 拉取指定架构的镜像
docker pull --platform linux/amd64 nginx:latest

# 从私有仓库拉取
docker pull registry.company.com:5000/myapp:v1.0

# 拉取所有标签
docker pull -a nginx

# 查看拉取进度
docker pull nginx:latest

搜索镜像

bash
# 搜索官方镜像
docker search nginx

# 限制搜索结果数量
docker search --limit 10 nginx

# 只显示官方镜像
docker search --filter is-official=true nginx

# 按星级过滤
docker search --filter stars=100 nginx

# 格式化输出
docker search --format "table {{.Name}}\t{{.Description}}\t{{.Stars}}" nginx

镜像查看操作

列出本地镜像

bash
# 列出所有镜像
docker images
docker image ls

# 显示镜像摘要
docker images --digests

# 只显示镜像 ID
docker images -q

# 显示所有镜像(包括中间层)
docker images -a

# 自定义输出格式
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"

# 过滤镜像
docker images --filter "dangling=true"      # 悬空镜像
docker images --filter "before=nginx:latest" # 指定镜像之前创建的
docker images --filter "since=nginx:latest"  # 指定镜像之后创建的
docker images --filter "reference=nginx:*"   # 匹配名称模式

查看镜像详细信息

bash
# 查看镜像详细配置
docker inspect nginx:latest

# 获取特定信息
docker inspect --format='{{.Config.Env}}' nginx:latest
docker inspect --format='{{.Architecture}}' nginx:latest
docker inspect --format='{{.Size}}' nginx:latest

# 查看镜像历史
docker history nginx:latest

# 显示详细的历史信息
docker history --no-trunc nginx:latest

# 查看镜像层信息
docker image inspect --format='{{json .RootFS.Layers}}' nginx:latest

镜像标记操作

标记镜像

bash
# 为镜像添加新标签
docker tag nginx:latest myregistry/nginx:v1.0

# 标记为不同版本
docker tag myapp:latest myapp:v1.0
docker tag myapp:latest myapp:stable

# 标记到私有仓库
docker tag myapp:latest registry.company.com:5000/myapp:v1.0

# 查看标记结果
docker images myapp

重命名镜像

bash
# Docker 没有直接的重命名命令,需要通过标记和删除实现
# 1. 创建新标签
docker tag old-name:tag new-name:tag

# 2. 删除旧标签
docker rmi old-name:tag

# 示例:重命名镜像
docker tag myapp:old myapp:new
docker rmi myapp:old

镜像构建操作

使用 Dockerfile 构建

bash
# 基本构建命令
docker build -t myapp:v1.0 .

# 指定 Dockerfile 路径
docker build -f /path/to/Dockerfile -t myapp:v1.0 .

# 指定构建上下文
docker build -t myapp:v1.0 /path/to/context

# 从 URL 构建
docker build -t myapp:v1.0 https://github.com/user/repo.git

# 从标准输入构建
docker build -t myapp:v1.0 - < Dockerfile

# 不使用缓存构建
docker build --no-cache -t myapp:v1.0 .

# 指定构建参数
docker build --build-arg VERSION=1.0 -t myapp:v1.0 .

# 指定目标阶段(多阶段构建)
docker build --target production -t myapp:v1.0 .

# 设置内存限制
docker build -m 1g -t myapp:v1.0 .

构建示例

创建一个简单的 Node.js 应用镜像:

dockerfile
# Dockerfile
FROM node:16-alpine

# 设置工作目录
WORKDIR /app

# 复制 package.json
COPY package*.json ./

# 安装依赖
RUN npm ci --only=production

# 复制应用代码
COPY . .

# 暴露端口
EXPOSE 3000

# 设置启动命令
CMD ["npm", "start"]
bash
# 构建镜像
docker build -t mynode-app:v1.0 .

# 运行容器测试
docker run -d -p 3000:3000 --name test-app mynode-app:v1.0

镜像导入导出

导出镜像

bash
# 导出单个镜像
docker save nginx:latest -o nginx.tar
docker save nginx:latest > nginx.tar

# 导出多个镜像
docker save nginx:latest ubuntu:20.04 -o images.tar

# 压缩导出
docker save nginx:latest | gzip > nginx.tar.gz

# 查看导出文件大小
ls -lh nginx.tar

导入镜像

bash
# 导入镜像
docker load -i nginx.tar
docker load < nginx.tar

# 导入压缩镜像
gunzip -c nginx.tar.gz | docker load

# 验证导入结果
docker images nginx

容器导出为镜像

bash
# 从运行中的容器创建镜像
docker commit container_name new_image:tag

# 添加提交信息
docker commit -m "Added new feature" -a "Author Name" container_name new_image:tag

# 指定配置变更
docker commit --change='CMD ["nginx", "-g", "daemon off;"]' container_name new_image:tag

# 暂停容器后提交
docker commit --pause=true container_name new_image:tag

镜像删除操作

删除镜像

bash
# 删除单个镜像
docker rmi nginx:latest

# 删除多个镜像
docker rmi nginx:latest ubuntu:20.04

# 强制删除镜像
docker rmi -f nginx:latest

# 删除所有悬空镜像
docker image prune

# 删除所有未使用的镜像
docker image prune -a

# 删除指定时间之前的镜像
docker image prune --filter "until=24h"

# 批量删除镜像
docker rmi $(docker images -q)
docker rmi $(docker images --filter "dangling=true" -q)

清理镜像空间

bash
# 查看 Docker 磁盘使用情况
docker system df

# 详细查看磁盘使用
docker system df -v

# 清理所有未使用的资源
docker system prune

# 清理所有资源(包括未使用的镜像)
docker system prune -a

# 清理指定时间之前的资源
docker system prune --filter "until=72h"

# 强制清理(不询问确认)
docker system prune -f

镜像仓库操作

登录和认证

bash
# 登录 Docker Hub
docker login

# 登录私有仓库
docker login registry.company.com:5000

# 使用用户名密码登录
docker login -u username -p password registry.company.com:5000

# 从文件读取密码
cat password.txt | docker login -u username --password-stdin

# 查看登录信息
cat ~/.docker/config.json

# 登出
docker logout
docker logout registry.company.com:5000

推送镜像

bash
# 推送到 Docker Hub
docker push myuser/myapp:v1.0

# 推送到私有仓库
docker push registry.company.com:5000/myapp:v1.0

# 推送所有标签
docker push -a myuser/myapp

# 查看推送进度
docker push myuser/myapp:v1.0

私有仓库配置

bash
# 运行本地 Registry
docker run -d -p 5000:5000 --name registry registry:2

# 推送到本地仓库
docker tag myapp:v1.0 localhost:5000/myapp:v1.0
docker push localhost:5000/myapp:v1.0

# 从本地仓库拉取
docker pull localhost:5000/myapp:v1.0

# 配置不安全的仓库(/etc/docker/daemon.json)
{
  "insecure-registries": ["registry.company.com:5000"]
}

镜像优化技巧

减小镜像大小

dockerfile
# 1. 使用多阶段构建
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:16-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]

# 2. 使用 .dockerignore 文件
# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
coverage
.nyc_output

# 3. 合并 RUN 指令
RUN apt-get update && \
    apt-get install -y curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# 4. 使用轻量级基础镜像
FROM alpine:3.14
FROM node:16-alpine
FROM python:3.9-slim

镜像安全优化

dockerfile
# 1. 使用非 root 用户
FROM node:16-alpine
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
USER nextjs

# 2. 只安装必要的包
RUN apk add --no-cache curl

# 3. 设置只读根文件系统
FROM alpine:3.14
RUN adduser -D -s /bin/sh appuser
USER appuser
# 运行时使用 --read-only 标志

# 4. 扫描镜像漏洞
docker scan myapp:v1.0

构建缓存优化

dockerfile
# 1. 优化层顺序(变化少的层放前面)
FROM node:16-alpine
WORKDIR /app

# 先复制依赖文件
COPY package*.json ./
RUN npm ci

# 后复制应用代码
COPY . .
RUN npm run build

# 2. 使用 BuildKit 缓存挂载
# syntax=docker/dockerfile:1
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci

# 3. 使用外部缓存
docker buildx build --cache-from type=registry,ref=myapp:cache \
                   --cache-to type=registry,ref=myapp:cache \
                   -t myapp:v1.0 .

镜像分析工具

使用 dive 分析镜像

bash
# 安装 dive
curl -OL https://github.com/wagoodman/dive/releases/download/v0.10.0/dive_0.10.0_linux_amd64.deb
sudo apt install ./dive_0.10.0_linux_amd64.deb

# 分析镜像
dive nginx:latest

# 分析本地构建的镜像
dive myapp:v1.0

使用 docker-slim 优化镜像

bash
# 安装 docker-slim
curl -sL https://raw.githubusercontent.com/docker-slim/docker-slim/master/scripts/install-dockerslim.sh | sudo -E bash -

# 优化镜像
docker-slim build --target nginx:latest --tag nginx:slim

# 查看优化结果
docker images nginx

实战练习

练习 1:构建 Python Web 应用镜像

dockerfile
# Dockerfile
FROM python:3.9-slim

# 设置工作目录
WORKDIR /app

# 安装系统依赖
RUN apt-get update && \
    apt-get install -y --no-install-recommends gcc && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# 复制依赖文件
COPY requirements.txt .

# 安装 Python 依赖
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY . .

# 创建非 root 用户
RUN useradd --create-home --shell /bin/bash app && \
    chown -R app:app /app
USER app

# 暴露端口
EXPOSE 8000

# 启动命令
CMD ["python", "app.py"]
bash
# 构建镜像
docker build -t python-web:v1.0 .

# 运行测试
docker run -d -p 8000:8000 --name python-app python-web:v1.0

# 查看镜像大小
docker images python-web:v1.0

练习 2:多阶段构建 Go 应用

dockerfile
# 多阶段构建 Dockerfile
# 构建阶段
FROM golang:1.19-alpine AS builder

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o main .

# 运行阶段
FROM alpine:3.16

RUN apk --no-cache add ca-certificates
WORKDIR /root/

# 从构建阶段复制二进制文件
COPY --from=builder /app/main .

# 创建非 root 用户
RUN adduser -D -s /bin/sh appuser
USER appuser

EXPOSE 8080
CMD ["./main"]
bash
# 构建镜像
docker build -t go-app:v1.0 .

# 比较镜像大小
docker images go-app:v1.0
docker images golang:1.19-alpine

练习 3:镜像仓库管理

bash
# 1. 启动本地仓库
docker run -d -p 5000:5000 --name local-registry \
  -v registry-data:/var/lib/registry \
  registry:2

# 2. 构建并推送镜像
docker build -t myapp:v1.0 .
docker tag myapp:v1.0 localhost:5000/myapp:v1.0
docker push localhost:5000/myapp:v1.0

# 3. 查看仓库内容
curl http://localhost:5000/v2/_catalog
curl http://localhost:5000/v2/myapp/tags/list

# 4. 从仓库拉取镜像
docker rmi localhost:5000/myapp:v1.0
docker pull localhost:5000/myapp:v1.0

常见问题和解决方案

问题 1:镜像构建失败

bash
# 检查 Dockerfile 语法
docker build --no-cache -t test .

# 逐步构建调试
docker build --target stage1 -t debug .
docker run -it debug /bin/bash

# 查看构建历史
docker history image_name

问题 2:镜像过大

bash
# 分析镜像层
docker history --no-trunc image_name

# 使用 dive 分析
dive image_name

# 优化建议
# 1. 使用多阶段构建
# 2. 合并 RUN 指令
# 3. 清理缓存和临时文件
# 4. 使用 .dockerignore

问题 3:推送失败

bash
# 检查登录状态
docker login

# 检查镜像标签
docker images

# 重新标记镜像
docker tag local_image:tag registry/image:tag

# 检查网络连接
ping registry.domain.com

问题 4:悬空镜像过多

bash
# 查看悬空镜像
docker images --filter "dangling=true"

# 清理悬空镜像
docker image prune

# 定期清理脚本
#!/bin/bash
docker image prune -f
docker container prune -f
docker volume prune -f
docker network prune -f

本章小结

本章全面介绍了 Docker 镜像管理的各个方面:

关键要点:

  • 镜像获取:拉取、搜索、导入镜像
  • 镜像查看:列出、检查、分析镜像
  • 镜像构建:使用 Dockerfile 构建自定义镜像
  • 镜像标记:版本管理和命名规范
  • 镜像分发:推送到仓库和私有仓库管理
  • 镜像优化:减小大小、提高安全性、优化构建

最佳实践:

  • 使用具体的镜像标签而不是 latest
  • 定期清理未使用的镜像
  • 使用多阶段构建减小镜像大小
  • 遵循镜像安全最佳实践
  • 合理使用构建缓存

在下一章中,我们将学习 Docker 的数据管理,包括数据卷、绑定挂载和数据持久化策略。

延伸阅读

本站内容仅供学习和研究使用。