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 的数据管理,包括数据卷、绑定挂载和数据持久化策略。