Ubuntu 22.04 Docker 完整使用手册(2)

5. Docker 核心概念

5.1 镜像 (Image)

Docker 镜像是一个轻量级、可执行的独立软件包,包含运行某个软件所需的一切:代码、运行时、系统工具、库和设置。

  • 镜像是只读的模板
  • 镜像由多层(Layer)组成,每层对应 Dockerfile 中的一条指令
  • 镜像层可以被多个镜像共享,节省存储空间
  • 镜像通过 Dockerfile 构建或从仓库拉取

5.2 容器 (Container)

容器是镜像的可运行实例。可以将容器理解为镜像的"运行时快照"。

  • 容器在镜像层之上增加了可写层(容器层)
  • 容器可以被启动、停止、删除、暂停
  • 容器内的修改在容器删除后会丢失(除非使用数据卷持久化)
  • 多个容器可以基于同一个镜像创建

5.3 数据卷 (Volume)

数据卷用于持久化容器产生的数据,以及容器间共享数据。

  • 独立于容器的生命周期
  • 存储在宿主机文件系统中(/var/lib/docker/volumes/
  • 支持多种挂载方式:Volume、Bind Mount、tmpfs Mount

5.4 网络 (Network)

Docker 网络管理容器之间的通信,以及容器与外部网络的通信。

  • 默认提供:bridge、host、none、overlay 等网络驱动
  • 容器可以通过网络名称互相访问(自定义网络支持 DNS 解析)
  • 端口映射实现容器与宿主机之间的通信

5.5 Docker 架构图

复制代码
+------------------+          +------------------+
|   Docker Client  |  REST    |   Docker Daemon   |
|   (docker CLI)   |--------->|    (dockerd)      |
+------------------+          +--------+---------+
                                       |
                          +------------+------------+
                          |                         |
                   +------v------+          +-------v--------+
                   |  containerd  |          |  Docker Registry |
                   |  (运行时)    |          |  (镜像仓库)     |
                   +------+------+          +----------------+
                          |
                   +------v------+
                   |    runc     |
                   | (OCI 运行层) |
                   +------+------+
                          |
                    +-----v-----+
                    |  容器实例  |
                    +-----------+

6. 镜像管理

6.1 搜索镜像

bash 复制代码
# 在 Docker Hub 上搜索镜像
docker search nginx

# 搜索并限制星标数量
docker search --stars=1000 nginx

# 搜索官方镜像
docker search --filter "is-official=true" nginx

# 搜索已启用自动化构建的镜像
docker search --filter "is-automated=true" nginx

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

6.2 拉取镜像

bash 复制代码
# 拉取最新版本(默认 tag 为 latest)
docker pull nginx

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

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

# 从第三方仓库拉取
docker pull quay.io/prometheus/node-exporter

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

# 拉取所有 tag(仅适用于某些仓库)
docker pull -a nginx

6.3 查看镜像

bash 复制代码
# 列出所有镜像
docker images

# 或使用等价的命令
docker image ls

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

# 只显示镜像 ID
docker images -q

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

# 按仓库名过滤
docker images --filter "reference=nginx"

# 过滤悬空镜像(dangling images,即 <none>:<none>)
docker images --filter "dangling=true"

# 按时间过滤(before、since)
docker images --filter "before=nginx:1.25"
docker images --filter "since=nginx:1.24"

6.4 标记镜像

bash 复制代码
# 为镜像添加标签(格式:仓库名:标签)
docker tag nginx:latest mynginx:1.0

# 为镜像添加完整的仓库地址标签(用于推送到私有仓库)
docker tag nginx:latest registry.example.com:5000/mynginx:1.0

6.5 删除镜像

bash 复制代码
# 删除指定镜像(通过镜像名:标签 或 镜像 ID)
docker rmi nginx:1.25
docker rmi abc123def456

# 强制删除(即使有容器正在使用)
docker rmi -f nginx:1.25

# 删除全部悬空镜像
docker image prune

# 删除所有未使用的镜像(无容器引用的)
docker image prune -a

# 删除所有镜像
docker rmi $(docker images -q)

# 清理所有未使用的 Docker 对象(镜像、容器、网络、构建缓存)
docker system prune -a

6.6 导出和导入镜像

bash 复制代码
# 将镜像导出为 tar 文件
docker save -o nginx.tar nginx:latest

# 将多个镜像导出到一个 tar 文件
docker save -o multiple-images.tar nginx:latest ubuntu:22.04

# 从 tar 文件加载镜像
docker load -i nginx.tar

# 或使用管道(常用于传输)
# 把镜像文件打包+压缩为一个压缩包
docker save nginx:latest | gzip > nginx.tar.gz
# 把压缩包解压并加载镜像
gunzip -c nginx.tar.gz | docker load

6.7 查看镜像详细信息

bash 复制代码
# 查看镜像的详细信息(JSON 格式)
docker inspect nginx:latest

# 查看镜像的层级信息
docker history nginx:latest

# 查看镜像的创建时间、大小等
docker history --no-trunc nginx:latest

# 查看镜像的具体配置(如暴露端口、环境变量等)
docker inspect --format='{{.Config.ExposedPorts}}' nginx:latest
docker inspect --format='{{.Config.Env}}' nginx:latest

6.8 构建镜像

bash 复制代码
# 使用 Dockerfile 构建镜像
docker build -t myapp:1.0 .

# 指定 Dockerfile 路径和构建上下文
docker build -f /path/to/Dockerfile -t myapp:1.0 /path/to/context

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

# 为镜像添加多个标签
docker build -t myapp:1.0 -t myapp:latest .

# 构建时传递构建参数
docker build --build-arg VERSION=1.0 --build-arg ENV=production -t myapp:1.0 .

# 指定目标构建阶段(多阶段构建时)
docker build --target builder -t myapp-builder:1.0 .

7. 容器管理

7.1 创建和启动容器

bash 复制代码
# 创建并启动容器(前台运行)
docker run nginx

# 创建并启动容器(后台运行,-d = detached)
docker run -d nginx

# 为容器指定名称
docker run -d --name my-nginx nginx

# 映射端口(宿主机端口:容器端口)
docker run -d --name my-nginx -p 8080:80 nginx

# 映射多个端口
docker run -d --name my-nginx -p 8080:80 -p 443:443 nginx

# 随机映射端口(宿主机自动分配端口)
docker run -d --name my-nginx -P nginx

# 挂载数据卷
docker run -d --name my-nginx -v /host/path:/container/path nginx

# 设置环境变量
docker run -d --name my-mysql \
    -e MYSQL_ROOT_PASSWORD=my-secret-pw \
    -e MYSQL_DATABASE=myapp \
    mysql:8.0

# 设置资源限制
docker run -d --name my-app \
    --memory="512m" \
    --cpus="1.5" \
    --memory-swap="1g" \
    nginx

# 以交互模式运行容器(常用于测试)
docker run -it --name test-container ubuntu:22.04 /bin/bash

# 容器退出后自动删除
docker run --rm -it ubuntu:22.04 /bin/bash

# 指定容器主机名
docker run -d --name my-nginx --hostname web01 nginx

# 添加 DNS 配置
docker run -d --name my-nginx \
    --dns 8.8.8.8 \
    --dns 114.114.114.114 \
    nginx

# 使容器使用宿主机网络
docker run -d --name my-nginx --network host nginx

# 设置容器重启策略
docker run -d --name my-app \
    --restart always \
    myapp:1.0

--restart 策略说明:

策略 说明
no 不自动重启(默认)
on-failure 容器因错误退出时重启(退出码非 0)
on-failure:3 最多重启 3 次
always 总是重启(除非手动停止)
unless-stopped 总是重启,除非手动停止
'docker run' 常用的选项

docker run [选项] 镜像名[:标签]

  • -d / --detach ------ 后台运行(最常用)
  • -p / --publish ------ 端口映射, 把容器内部端口暴露给本机
  • --name ------ 给容器起名字
  • -v / --volume ------ 目录挂载(数据持久化)
    • -v "/tmp/.X11-unix:/tmp/.X11-unix:rw" :让容器里的 GUI 程序,能把画面显示到我电脑屏幕上!
    • -v /mnt/disk1/chrono_develop:/root/work : 挂载宿主机目录到容器
  • -it ------ 交互式终端(进入容器内部)
  • -e / --env ------ 设置环境变量, -e 名字=值
  • --restart ------ 开机 / 重启自动运行
  • --rm ------ 运行结束自动删除容器,适合临时测试用
  • --gpus ------ 把宿主机所有的 NVIDIA 显卡,都分配给 Docker 容器使用
    • --gpus all : 使用所有显卡
    • --gpus '"device=0"' : 只使用第0号显卡
    • --gpus all --memory 4g : 限制显卡使用内存

7.2 查看容器

bash 复制代码
# 列出运行中的容器
docker ps

# 列出所有容器(包括已停止的)
docker ps -a

# 只显示容器 ID
docker ps -q

# 显示最近创建的容器(默认只显示最近的 n 个)
docker ps -n 5

# 显示容器大小
docker ps -s

# 按状态过滤
docker ps --filter "status=exited"
docker ps --filter "status=running"
docker ps --filter "status=created"
docker ps --filter "status=paused"

# 按名称过滤
docker ps --filter "name=my-nginx"

# 按暴露端口过滤
docker ps --filter "expose=80"

# 以自定义格式输出
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}"

# 只输出运行中的容器名
docker ps --format "{{.Names}}"

7.3 停止和启动容器

bash 复制代码
# 停止容器(发送 SIGTERM 信号,等待优雅退出)
docker stop my-nginx

# 设置停止前的等待时间(默认 10 秒)
docker stop --time=30 my-nginx

# 强制停止容器(发送 SIGKILL 信号)
docker kill my-nginx

# 启动已停止的容器
docker start my-nginx

# 重启容器(先停止再启动)
docker restart my-nginx

# 暂停容器(冻结进程)
docker pause my-nginx

# 恢复暂停的容器
docker unpause my-nginx

7.4 进入容器

bash 复制代码
# 在容器内执行命令(交互式)
docker exec -it my-nginx /bin/bash

# 如果容器中没有 bash,尝试 sh
docker exec -it my-nginx /bin/sh

# 在容器内执行命令(非交互)
docker exec my-nginx ls -la /var/log

# 在容器内执行命令并设置工作目录
docker exec -w /var/log my-nginx cat access.log

# 在容器内执行命令并设置环境变量
docker exec -e MY_VAR=hello my-nginx env

# 以指定用户身份在容器内执行命令
docker exec -u root my-nginx whoami

# 查看容器内的目录
docker exec 容器名 ls

# 查看容器内进程
docker exec 容器名 ps aux
选项 作用
-i 交互式,保持标准输入打开
-t 分配一个终端(能看到光标、能输入)
-d 后台执行命令(不输出到屏幕)
-u 指定用户(root、www-data 等)
-w 指定工作目录
-e 传递环境变量

7.5 查看容器日志

bash 复制代码
# 查看容器日志
docker logs my-nginx

# 实时跟踪日志输出(类似 tail -f)
docker logs -f my-nginx

# 查看最后 N 行日志
docker logs --tail 100 my-nginx

# 查看特定时间范围内的日志
docker logs --since "2024-01-01T00:00:00" --until "2024-01-02T00:00:00" my-nginx

# 查看最近 30 分钟的日志
docker logs --since 30m my-nginx

# 包含时间戳
docker logs -t my-nginx

# 组合使用
docker logs --tail 50 -f -t my-nginx

7.6 容器端口映射

bash 复制代码
# 查看容器端口映射
docker port my-nginx

# 查看特定协议端口映射
docker port my-nginx 80
docker port my-nginx 80/tcp

7.7 容器资源使用统计

bash 复制代码
# 实时查看容器资源使用情况
docker stats

# 查看指定容器
docker stats my-nginx

# 只查看一次就退出
docker stats --no-stream

# 查看所有容器(包括已停止的)的资源使用
docker stats --all

7.8 容器与宿主机之间的文件传输

bash 复制代码
# 从容器复制文件到宿主机
docker cp my-nginx:/etc/nginx/nginx.conf ./nginx.conf

# 从宿主机复制文件到容器
docker cp ./my-config.conf my-nginx:/etc/nginx/conf.d/

# 复制目录
docker cp my-nginx:/var/log/nginx/ ./logs/

7.9 容器的导入和导出

bash 复制代码
# 将容器导出为 tar 文件(包含文件系统快照)
docker export -o my-container.tar my-nginx

# 从 tar 文件导入为镜像
docker import my-container.tar my-nginx:imported

# 使用管道
docker export my-nginx | gzip > my-container.tar.gz
gunzip -c my-container.tar.gz | docker import - my-nginx:imported

注意docker export/importdocker save/load 的区别:

  • export/import:操作对象是容器,导出的内容不包含镜像的层级信息,历史记录和元数据
  • save/load:操作对象是镜像,保留完整的层级结构和历史记录

7.10 删除容器

bash 复制代码
# 删除单个已停止的容器
docker rm my-nginx

# 强制删除正在运行的容器
docker rm -f my-nginx

# 删除多个容器
docker rm my-nginx my-nginx2 mysql

# 删除所有已停止的容器
docker container prune

# 删除所有容器(包括运行中的,需要 -f)
docker rm -f $(docker ps -aq)

# 删除所有已退出的容器
docker rm $(docker ps -q -f status=exited)

7.11 容器生命周期图示

复制代码
    +-----------+
    |  docker   |
    |  create   |
    +-----+-----+
          |
    +-----v-----+
    |  Created   |<---------+
    +-----+-----+          |
          |                 |
    +-----v-----+    +-----+-----+
    |  Running   |--->|  Stopped  |
    +-----+-----+    +-----+-----+
          |                 |
    +-----v-----+          |
    |  Paused    |         |
    +-----+-----+          |
          |                 |
          +-----------------+

8. 数据卷管理

8.1 数据卷类型

类型 说明 特点
Volume Docker 管理的数据卷 存储在 /var/lib/docker/volumes/,推荐使用
Bind Mount 挂载宿主机目录/文件 可挂载任意宿主机路径,依赖宿主机目录结构
tmpfs Mount 临时文件系统 仅存储在内存中,容器停止后数据消失

8.2 Volume 管理

bash 复制代码
# 创建数据卷
docker volume create my-volume

# 创建带标签的数据卷
docker volume create --label project=myapp my-volume

# 查看所有数据卷
docker volume ls

# 过滤显示
docker volume ls --filter "label=project=myapp"
docker volume ls --filter "dangling=true"

# 查看数据卷详细信息
docker volume inspect my-volume

# 使用数据卷运行容器
docker run -d --name my-nginx \
    -v my-volume:/usr/share/nginx/html \
    nginx

# 使用匿名数据卷(Docker 自动生成名称)
docker run -d --name my-nginx -v /usr/share/nginx/html nginx

# 以只读方式挂载数据卷
docker run -d --name my-nginx \
    -v my-volume:/usr/share/nginx/html:ro \
    nginx

# 删除数据卷
docker volume rm my-volume

# 删除所有未使用的数据卷
docker volume prune

# 强制删除所有未使用的数据卷(不询问确认)
docker volume prune -f

# 删除所有数据卷(谨慎!)
docker volume rm $(docker volume ls -q)

8.3 Bind Mount

bash 复制代码
# 挂载宿主机目录到容器
docker run -d --name my-nginx \
    -v /home/user/html:/usr/share/nginx/html \
    nginx

# 挂载单个文件
docker run -d --name my-nginx \
    -v /home/user/nginx.conf:/etc/nginx/nginx.conf \
    nginx

# 使用新的 --mount 语法(推荐,更清晰)
docker run -d --name my-nginx \
    --mount type=bind,source=/home/user/html,target=/usr/share/nginx/html \
    nginx

# 只读挂载
docker run -d --name my-nginx \
    --mount type=bind,source=/home/user/html,target=/usr/share/nginx/html,readonly \
    nginx

# 使用 --mount 挂载单个文件
docker run -d --name my-nginx \
    --mount type=bind,source=/home/user/nginx.conf,target=/etc/nginx/nginx.conf \
    nginx

8.4 tmpfs 挂载

bash 复制代码
# 挂载 tmpfs(数据存储在内存中)
docker run -d --name my-app \
    --tmpfs /app/cache:uid=1000,gid=1000 \
    nginx

# 使用 --mount 语法挂载 tmpfs
docker run -d --name my-app \
    --mount type=tmpfs,destination=/app/cache,tmpfs-size=100m \
    nginx

8.5 容器间共享数据卷

bash 复制代码
# 创建数据卷
docker volume create shared-data

# 容器 1:写入数据
docker run -d --name writer \
    -v shared-data:/data \
    alpine sh -c "while true; do echo 'Hello' >> /data/log.txt; sleep 1; done"

# 容器 2:读取数据
docker run -d --name reader \
    -v shared-data:/data \
    alpine tail -f /data/log.txt

# 使用 --volumes-from 继承另一个容器的挂载
docker run -d --name writer-container -v shared-data:/data alpine ...
docker run -d --name reader-container --volumes-from writer-container alpine ...

8.6 数据卷容器模式

bash 复制代码
# 步骤 1:创建数据卷容器(仅用于持有数据卷)
docker create -v /data --name data-container alpine /bin/true

# 步骤 2:其他容器使用 --volumes-from 挂载数据
docker run -d --name app1 --volumes-from data-container nginx
docker run -d --name app2 --volumes-from data-container nginx

# 步骤 3:备份数据
docker run --rm --volumes-from data-container \
    -v /backup:/backup \
    alpine tar czf /backup/data-backup.tar.gz /data

8.7 备份和恢复数据卷

bash 复制代码
# 备份数据卷
docker run --rm \
    -v my-volume:/source:ro \
    -v /backup:/destination:rw \
    alpine tar czf /destination/my-volume-backup.tar.gz -C /source .

# 恢复数据卷
docker volume create my-volume
docker run --rm \
    -v my-volume:/target \
    -v /backup:/source:ro \
    alpine tar xzf /source/my-volume-backup.tar.gz -C /target

9. 网络管理

9.1 Docker 网络驱动

网络驱动 说明 适用场景
bridge 默认网络驱动,容器通过网桥互相通信 单机容器通信
host 容器使用宿主机网络栈,无需端口映射 需要网络性能的场景
none 容器无网络接口 安全场景、只需本地访问
overlay 跨主机容器网络 Swarm 集群、多机部署
macvlan 为容器分配 MAC 地址 需要直连物理网络的场景
ipvlan 为容器分配 IP 地址 类似 macvlan,但 MAC 地址可控

9.2 查看和管理网络

bash 复制代码
# 列出所有网络
docker network ls

# 查看网络详细信息
docker network inspect bridge

# 创建自定义 bridge 网络
docker network create my-network

# 创建指定子网的网络
docker network create \
    --subnet=172.20.0.0/16 \
    --gateway=172.20.0.1 \
    my-network

# 创建带 IP 范围限制的网络
docker network create \
    --subnet=172.20.0.0/16 \
    --ip-range=172.20.10.0/24 \
    my-network

# 创建 overlay 网络(需要 Swarm 模式)
docker network create -d overlay my-overlay-network

# 创建 macvlan 网络
docker network create -d macvlan \
    --subnet=192.168.1.0/24 \
    --gateway=192.168.1.1 \
    -o parent=eth0 \
    my-macvlan-network

# 删除网络
docker network rm my-network

# 删除所有未使用的网络
docker network prune

9.3 容器连接到网络

bash 复制代码
# 运行容器并连接到指定网络
docker run -d --name my-nginx --network my-network nginx

# 将运行中的容器连接到网络
docker network connect my-network my-nginx

# 连接时指定容器 IP
docker network connect \
    --ip 172.20.10.5 \
    my-network my-nginx

# 将容器从网络断开
docker network disconnect my-network my-nginx

# 断网并清理网络配置
docker network disconnect -f my-network my-nginx

9.4 默认网络详解

bridge 网络
bash 复制代码
# 查看默认 bridge 网络
docker network inspect bridge

# 默认 bridge 网络中的容器通过 IP 通信
docker run -d --name container1 alpine sleep 3600
docker run -d --name container2 alpine sleep 3600

# 获取 container1 的 IP
docker inspect container1 | grep IPAddress

# container2 可以通过 IP 访问 container1
docker exec container2 ping <container1-ip>

限制 :默认 bridge 网络中容器不能通过容器名通信(需要使用 --link,但已废弃)。自定义网络才支持 DNS 自动解析。

host 网络
bash 复制代码
# 使用 host 网络(容器共享宿主机网络栈)
docker run -d --name my-nginx --network host nginx

# 此时不需要 -p 端口映射,直接通过宿主机 IP 访问
# 注意:host 网络仅适用于 Linux
none 网络
bash 复制代码
# 容器无网络
docker run -d --name isolated --network none alpine sleep 3600

# 验证:容器内没有网络接口
docker exec isolated ifconfig  # 或无此命令
docker exec isolated ip addr   # 只有 lo 接口

9.5 自定义 bridge 网络(推荐)

自定义 bridge 网络相比默认 bridge 网络的优势:

  1. 自动 DNS 解析:容器间可以通过容器名通信
  2. 更好的隔离性:只有连接到同一网络的容器才能通信
  3. 动态连接:容器可以在运行中连接和断开网络
bash 复制代码
# 创建自定义网络
docker network create --driver bridge app-network

# 启动两个容器在同一个自定义网络中
docker run -d --name web --network app-network nginx
docker run -d --name app --network app-network alpine sleep 3600

# 通过容器名通信(自动 DNS 解析)
docker exec app ping web

# 查看容器在自定义网络中的 DNS 配置
docker exec app cat /etc/resolv.conf
docker exec app cat /etc/hosts

9.6 端口映射详解

bash 复制代码
# 基础端口映射(宿主机随机端口 -> 容器端口)
docker run -d -p 80 nginx

# 宿主机指定端口 -> 容器端口
docker run -d -p 8080:80 nginx

# 指定 IP 和端口
docker run -d -p 127.0.0.1:8080:80 nginx

# 指定 UDP 端口
docker run -d -p 53:53/udp dns-container

# 同时映射 TCP 和 UDP
docker run -d -p 53:53/tcp -p 53:53/udp dns-container

# 映射端口范围
docker run -d -p 8000-8010:8000-8010 nginx

# 将所有暴露端口映射到宿主机随机端口
docker run -d -P nginx

9.7 容器间通信示例

bash 复制代码
# 方案一:使用自定义网络(推荐)
docker network create backend-network

docker run -d --name redis --network backend-network redis:7
docker run -d --name app \
    --network backend-network \
    -e REDIS_HOST=redis \
    myapp:1.0

# app 容器中可以直接通过主机名 "redis" 访问 Redis

# 方案二:端口映射(外部访问)
docker run -d --name postgres \
    -p 5432:5432 \
    -e POSTGRES_PASSWORD=secret \
    postgres:15

10. Dockerfile 编写指南

10.1 Dockerfile 指令速查

指令 用途 示例
FROM 指定基础镜像 FROM ubuntu:22.04
LABEL 添加元数据标签 LABEL version="1.0"
RUN 执行命令(构建时) RUN apt-get update && apt-get install -y nginx
CMD 容器启动命令 CMD ["nginx", "-g", "daemon off;"]
ENTRYPOINT 容器入口点 ENTRYPOINT ["docker-entrypoint.sh"]
COPY 复制文件/目录 COPY ./app /app
ADD 复制文件/目录(支持 URL 和自动解压) ADD app.tar.gz /app
WORKDIR 设置工作目录 WORKDIR /app
ENV 设置环境变量 ENV NODE_ENV=production
ARG 构建参数 ARG VERSION=1.0
EXPOSE 声明暴露端口 EXPOSE 80
VOLUME 声明数据卷挂载点 VOLUME /data
USER 指定运行用户 USER appuser
HEALTHCHECK 健康检查 HEALTHCHECK CMD curl -f http://localhost/
SHELL 指定 shell SHELL ["/bin/bash", "-c"]
ONBUILD 触发器(子镜像构建时执行) ONBUILD COPY . /app
STOPSIGNAL 停止信号 STOPSIGNAL SIGQUIT

10.2 Dockerfile 最佳实践示例

dockerfile 复制代码
# ================================================
# 多阶段构建示例:Go 应用
# ================================================

# ---- 第一阶段:构建 ----
FROM golang:1.21-alpine AS builder

# 设置工作目录
WORKDIR /app

# 安装构建依赖
RUN apk add --no-cache git ca-certificates

# 先复制 go.mod 和 go.sum 以利用 Docker 缓存
COPY go.mod go.sum ./
RUN go mod download

# 复制源代码并构建
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o myapp .

# ---- 第二阶段:运行 ----
FROM alpine:3.19

# 添加元数据
LABEL maintainer="developer@example.com"
LABEL version="1.0"
LABEL description="Production-ready Go application"

# 安装运行时依赖(根据需要)
RUN apk add --no-cache tzdata ca-certificates && \
    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo "Asia/Shanghai" > /etc/timezone

# 使用非 root 用户运行(安全最佳实践)
RUN adduser -D -u 1000 appuser

# 创建工作目录并设置权限
WORKDIR /app
RUN chown appuser:appuser /app

# 从构建阶段复制编译好的二进制文件
COPY --from=builder /app/myapp .

# 复制配置文件(如果需要)
# COPY --from=builder /app/config.yaml .

# 声明端口
EXPOSE 8080

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1

# 切换为用户
USER appuser

# 设置默认命令
ENTRYPOINT ["./myapp"]
CMD ["--config", "/app/config.yaml"]

10.3 通用 Dockerfile 模板

Python 应用
dockerfile 复制代码
FROM python:3.11-slim

WORKDIR /app

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

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

# 复制应用代码
COPY . .

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

EXPOSE 8000

CMD ["python", "app.py"]
Node.js 应用
dockerfile 复制代码
FROM node:20-alpine

WORKDIR /app

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

# 安装依赖
RUN npm ci --only=production && \
    npm cache clean --force

# 复制应用代码
COPY . .

# 创建非 root 用户
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001 && \
    chown -R nodejs:nodejs /app
USER nodejs

EXPOSE 3000

CMD ["node", "server.js"]
Java 应用
dockerfile 复制代码
FROM eclipse-temurin:17-jre-alpine

WORKDIR /app

# 添加非 root 用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

# 复制 JAR 包
COPY target/*.jar app.jar

# 设置 JVM 参数
ENV JAVA_OPTS="-Xmx512m -Xms256m"

USER appuser

EXPOSE 8080

ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

10.4 .dockerignore 文件

创建 .dockerignore 文件可以排除不必要的文件进入构建上下文,提高构建速度:

dockerignore 复制代码
# .dockerignore
.git
.gitignore
node_modules
npm-debug.log
Dockerfile
.dockerignore
*.md
.env
.env.local
.gitlab-ci.yml
.cache
dist
*.log
.gitkeep
.idea
.vscode
*.swp
*.swo
*~
.DS_Store
Thumbs.db
docker-compose*.yml

10.5 构建缓存优化技巧

dockerfile 复制代码
# 不符合缓存优化:每次修改源代码都需要重新下载依赖
FROM node:20-alpine
WORKDIR /app
COPY . .          # 源代码变更导致缓存失效
RUN npm install   # 每次都要重新执行
CMD ["npm", "start"]

# 符合缓存优化:利用 Docker 层缓存
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./    # 单独复制依赖文件
RUN npm install           # 只有 package.json 变更时才重新执行
COPY . .                  # 源代码变更不影响依赖层
CMD ["npm", "start"]

10.6 减少镜像体积的技巧

dockerfile 复制代码
# 技巧 1:使用更小的基础镜像
# 不推荐:python:3.11(~900MB)
# 推荐:python:3.11-slim(~120MB)或 python:3.11-alpine(~50MB)

# 技巧 2:合并 RUN 指令并清理缓存
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        package1 \
        package2 \
    && rm -rf /var/lib/apt/lists/*

# 技巧 3:多阶段构建
FROM golang:1.21 AS builder
# ... 构建阶段 ...

FROM alpine:3.19
COPY --from=builder /app/myapp .
# 最终镜像只有几十 MB

# 技巧 4:不要安装不必要的包
# 不推荐
RUN apt-get update && apt-get install -y curl vim git wget

# 推荐:只安装需要的包
RUN apt-get update && apt-get install -y --no-install-recommends curl

11. Docker Compose

11.1 Docker Compose 简介

Docker Compose 是一个用于定义和运行多容器 Docker 应用的工具。通过一个 compose.yaml(或 docker-compose.yml)文件来配置应用的服务、网络和数据卷。

注意:Ubuntu 22.04 Docker 安装推荐使用 docker compose(子命令形式,插件版本),而非传统的 docker-compose(独立二进制版本)。

11.2 Compose 文件结构

yaml 复制代码
# compose.yaml (Docker Compose V3 格式)
---
name: myapp  # 项目名称(Compose V2+ 支持)

services:
  web:
    image: nginx:alpine
    container_name: my-web
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro
    networks:
      - frontend
    depends_on:
      - api
    restart: unless-stopped

  api:
    build:
      context: ./api
      dockerfile: Dockerfile
      args:
        - NODE_ENV=production
    container_name: my-api
    environment:
      - DB_HOST=db
      - DB_PORT=5432
      - NODE_ENV=production
    env_file:
      - ./api/.env
    volumes:
      - api-data:/app/data
    networks:
      - backend
      - frontend
    depends_on:
      db:
        condition: service_healthy
    restart: always

  db:
    image: postgres:15-alpine
    container_name: my-db
    environment:
      POSTGRES_USER: appuser
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: myapp
    volumes:
      - pg-data:/var/lib/postgresql/data
      - ./init-db:/docker-entrypoint-initdb.d
    networks:
      - backend
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U appuser"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    container_name: my-redis
    command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis-data:/data
    networks:
      - backend
    restart: unless-stopped

volumes:
  pg-data:
    driver: local
  redis-data:
    driver: local
  api-data:
    driver: local

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

11.3 Compose 文件核心配置详解

services 配置
yaml 复制代码
services:
  myservice:
    # 使用已存在的镜像
    image: nginx:latest

    # 或从 Dockerfile 构建
    build:
      context: ./dir           # 构建上下文
      dockerfile: Dockerfile   # Dockerfile 路径(默认 Dockerfile)
      args:                    # 构建参数
        - BUILD_VAR=value
      target: builder          # 多阶段构建的目标阶段
      cache_from:              # 缓存来源
        - myimage:latest
      labels:                  # 镜像标签
        - "com.example.label=value"

    # 容器名
    container_name: my-service

    # 端口映射
    ports:
      - "80:80"                # host:container
      - "8080:80"              # 指定 host 端口
      - "443:443/tcp"          # 指定协议
      - "127.0.0.1:8000:8000"  # 绑定到特定 IP

    # 环境变量
    environment:
      - ENV_VAR=value          # 直接指定
      - SECRET_VAR             # 从宿主机环境变量继承
    environment:
      ENV_VAR: value           # 也可以使用这种格式
      SECRET_VAR:

    # 从文件加载环境变量
    env_file:
      - ./common.env
      - ./app.env

    # 数据卷挂载
    volumes:
      - ./host/path:/container/path        # bind mount
      - myvolume:/container/path            # named volume
      - /absolute/host/path:/container/path # 绝对路径 bind mount
      - ./data:/data:ro                     # 只读挂载

    # 依赖关系
    depends_on:
      - db
      - redis
    # 带条件的依赖
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started

    # 网络
    networks:
      - frontend
    networks:
      frontend:
        aliases:              # 网络别名
          - web-frontend
      backend:
        ipv4_address: 172.20.0.10  # 固定 IP

    # 重启策略
    restart: always           # no | always | on-failure | unless-stopped

    # 资源限制
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

    # 健康检查
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

    # 命令
    command: ["nginx", "-g", "daemon off;"]
    # 或
    command: nginx -g daemon off;

    # 入口点
    entrypoint: ["/entrypoint.sh"]

    # 用户
    user: "1000:1000"

    # 工作目录
    working_dir: /app

    # DNS
    dns:
      - 8.8.8.8
      - 114.114.114.114

    # 额外主机映射(类似 /etc/hosts)
    extra_hosts:
      - "host.docker.internal:host-gateway"

    # 日志配置
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

    # 安全配置
    security_opt:
      - no-new-privileges:true

    # cap_add / cap_drop(Linux capabilities)
    cap_add:
      - NET_ADMIN
    cap_drop:
      - ALL

    # 特权模式
    privileged: false

    # sysctl 设置
    sysctls:
      - net.core.somaxconn=1024

    # ulimit 设置
    ulimits:
      nofile:
        soft: 65535
        hard: 65535
变量替换与 .env 文件
bash 复制代码
# .env 文件(与 compose.yaml 同目录)
DB_PASSWORD=SuperSecretPassword123
REDIS_PASSWORD=RedisSecret456
NGINX_PORT=8080
yaml 复制代码
# compose.yaml 中引用变量
services:
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}

  web:
    image: nginx
    ports:
      - "${NGINX_PORT}:80"

变量引用语法:

语法 说明
${VAR} 使用变量值,未设置时为空字符串
${VAR:-default} 未设置时使用默认值
${VAR:?error} 未设置时报错
${VAR:+value} 设置时使用替代值

11.4 Compose 常用命令

bash 复制代码
# 启动所有服务(前台模式)
docker compose up

# 启动所有服务(后台模式)
docker compose up -d

# 启动指定服务
docker compose up -d web api

# 构建并启动
docker compose up -d --build

# 停止所有服务
docker compose down

# 停止并删除卷
docker compose down -v

# 停止并删除所有内容(卷、网络、镜像)
docker compose down --rmi all -v

# 查看运行中的服务
docker compose ps

# 查看日志
docker compose logs
docker compose logs -f
docker compose logs -f web api

# 查看最后 N 行日志
docker compose logs --tail 100 -f

# 在服务中执行命令
docker compose exec web /bin/sh
docker compose exec db pg_isready

# 查看服务状态
docker compose top

# 构建/重建服务
docker compose build
docker compose build --no-cache api

# 拉取服务镜像
docker compose pull

# 推送服务镜像
docker compose push

# 列出服务
docker compose config --services

# 校验 Compose 文件格式
docker compose config

# 输出渲染后的 Compose 配置
docker compose config -o output.yaml

# 滚动重启服务
docker compose restart web

# 暂停/恢复服务
docker compose pause web
docker compose unpause web

# 启动已停止的服务
docker compose start web

# 停止服务(保留容器)
docker compose stop web

# 删除服务容器
docker compose rm web
docker compose rm -f -v web

11.5 完整实战示例:WordPress + MySQL

yaml 复制代码
# compose.yaml
---
name: wordpress

services:
  db:
    image: mysql:8.0
    container_name: wp-db
    command:
      - --default-authentication-plugin=mysql_native_password
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
    volumes:
      - db-data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-rootpassword}
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: ${MYSQL_PASSWORD:-wppassword}
    networks:
      - wp-network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  wordpress:
    image: wordpress:6.4-php8.2-apache
    container_name: wp-app
    ports:
      - "${WP_PORT:-8080}:80"
    volumes:
      - wp-data:/var/www/html
      - ./wp-content/plugins:/var/www/html/wp-content/plugins
      - ./wp-content/themes:/var/www/html/wp-content/themes
      - ./wp-content/uploads:/var/www/html/wp-content/uploads
      - ./php.ini:/usr/local/etc/php/conf.d/custom.ini
    restart: always
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD:-wppassword}
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_TABLE_PREFIX: wp_
      WORDPRESS_DEBUG: ${WP_DEBUG:-0}
    networks:
      - wp-network
    depends_on:
      db:
        condition: service_healthy

  phpmyadmin:
    image: phpmyadmin:latest
    container_name: wp-pma
    ports:
      - "8081:80"
    environment:
      PMA_HOST: db
      PMA_PORT: 3306
      UPLOAD_LIMIT: 64M
    networks:
      - wp-network
    depends_on:
      - db
    restart: always

volumes:
  db-data:
    driver: local
  wp-data:
    driver: local

networks:
  wp-network:
    driver: bridge

11.6 Compose 配置文件使用配置文件扩展

yaml 复制代码
# compose.base.yaml - 基础配置
services:
  app:
    image: myapp:latest
    networks:
      - app-net

networks:
  app-net:

# compose.prod.yaml - 生产环境扩展
---
name: myapp-prod
services:
  app:
    image: myapp:${VERSION:-latest}
    environment:
      - NODE_ENV=production
      - DEBUG=0
    deploy:
      replicas: 3

# compose.dev.yaml - 开发环境扩展
---
name: myapp-dev
services:
  app:
    build:
      context: .
    environment:
      - NODE_ENV=development
      - DEBUG=1
      - HOT_RELOAD=true
    volumes:
      - .:/app

# 使用方式:
# docker compose -f compose.base.yaml -f compose.dev.yaml up -d
# docker compose -f compose.base.yaml -f compose.prod.yaml up -d

12. Docker 仓库与镜像仓库

12.1 Docker Hub

bash 复制代码
# 登录 Docker Hub
docker login

# 使用指定用户名登录
docker login -u username

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

# 登出
docker logout

# 推送镜像到 Docker Hub
docker push username/myapp:1.0

# 推送镜像到私有仓库
docker push registry.example.com:5000/myapp:1.0

12.2 搭建私有镜像仓库(Registry)

bash 复制代码
# 使用 Docker 运行 Registry
docker run -d \
    --name registry \
    -p 5000:5000 \
    -v /data/registry:/var/lib/registry \
    registry:2

# 配置 HTTPS(推荐生产环境)
docker run -d \
    --name registry \
    -p 443:443 \
    -v /data/registry:/var/lib/registry \
    -v /etc/ssl/certs:/certs \
    -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
    -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
    registry:2

# 使用 Compose 搭建带认证的 Registry
# compose.yml
yaml 复制代码
# compose.yml - 完整的 Registry 部署
---
name: docker-registry

services:
  registry:
    image: registry:2
    container_name: registry
    restart: always
    ports:
      - "5000:5000"
    environment:
      REGISTRY_STORAGE_DELETE_ENABLED: "true"
      REGISTRY_HTTP_HEADERS_X-Content-Type-Options: nosniff
      # 如果使用 HTTPS(取消注释以下行)
      # REGISTRY_HTTP_TLS_CERTIFICATE: /certs/domain.crt
      # REGISTRY_HTTP_TLS_KEY: /certs/domain.key
      # 如果启用认证(取消注释以下行)
      # REGISTRY_AUTH: htpasswd
      # REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
      # REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
    volumes:
      - registry-data:/var/lib/registry
      # - /etc/ssl/certs:/certs:ro
      # - ./auth:/auth:ro
    networks:
      - registry-net
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5000/v2/"]
      interval: 30s
      timeout: 10s
      retries: 3

  # Web UI 管理界面(可选)
  registry-ui:
    image: joxit/docker-registry-ui:latest
    container_name: registry-ui
    restart: always
    ports:
      - "8080:80"
    environment:
      REGISTRY_TITLE: "Private Docker Registry"
      REGISTRY_URL: "http://registry:5000"
      DELETE_IMAGES_ENABLED: "true"
    networks:
      - registry-net
    depends_on:
      - registry

volumes:
  registry-data:

networks:
  registry-net:
    driver: bridge

12.3 Registry 常用操作

bash 复制代码
# 查看仓库列表
curl http://localhost:5000/v2/_catalog

# 查看镜像标签列表
curl http://localhost:5000/v2/myapp/tags/list

# 删除镜像(需要启用 REGISTRY_STORAGE_DELETE_ENABLED)
# 先获取镜像的 digest
curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
    http://localhost:5000/v2/myapp/manifests/1.0 | jq -r '.config.digest'

# 使用 digest 删除镜像
curl -X DELETE http://localhost:5000/v2/myapp/manifests/<digest>

# 垃圾回收(清理已删除镜像的存储)
docker exec registry /bin/registry garbage-collect /etc/docker/registry/config.yml

12.4 配置使用不安全的 Registry(HTTP)

如果私有仓库未启用 HTTPS,需要在 Docker Daemon 配置中将其加入不安全仓库列表:

bash 复制代码
# 编辑 /etc/docker/daemon.json
{
  "insecure-registries": [
    "registry.example.com:5000",
    "192.168.1.100:5000"
  ]
}

# 重启 Docker
sudo systemctl daemon-reload
sudo systemctl restart docker

12.5 Harbor 企业级镜像仓库

Harbor 是一个开源的云原生制品仓库,比 Docker Registry 功能更丰富。

bash 复制代码
# 下载 Harbor 安装包
wget https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-offline-installer-v2.10.0.tgz
tar xzf harbor-offline-installer-v2.10.0.tgz
cd harbor

# 复制配置模板并修改
cp harbor.yml.tmpl harbor.yml

# 编辑 harbor.yml 配置
vim harbor.yml

# 安装 Harbor
sudo ./install.sh

# 带 Trivy 漏洞扫描安装
sudo ./install.sh --with-trivy

# 带 Chart Museum(Helm 仓库)安装
sudo ./install.sh --with-chartmuseum

# 访问 Harbor Web UI:http://<host-ip>
# 默认管理账号:admin / Harbor12345

13. 容器监控与日志

13.1 内置监控命令

bash 复制代码
# 实时查看所有容器的 CPU、内存、网络、磁盘 I/O
docker stats

# 每 2 秒刷新一次
docker stats --no-stream  # 只输出一次

# 查看指定容器
docker stats my-nginx my-mysql

# 查看容器进程
docker top my-nginx

# 查看容器资源使用详情
docker inspect my-nginx | grep -A 20 "HostConfig"

# 查看容器网络性能指标
# 需要在容器内安装工具
docker exec my-nginx apt-get update
docker exec my-nginx apt-get install -y iftop
docker exec -it my-nginx iftop

13.2 日志管理

配置日志驱动
bash 复制代码
# 全局日志驱动配置(/etc/docker/daemon.json)
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

# 容器级别的日志驱动配置
docker run -d \
    --log-driver json-file \
    --log-opt max-size=10m \
    --log-opt max-file=3 \
    --name my-nginx nginx

# 使用 syslog 日志驱动
docker run -d \
    --log-driver syslog \
    --log-opt syslog-address=tcp://192.168.1.1:514 \
    --log-opt syslog-facility=daemon \
    --name my-nginx nginx

# 使用 journald 日志驱动
docker run -d \
    --log-driver journald \
    --name my-nginx nginx
支持的日志驱动
日志驱动 说明 适用场景
none 禁用日志 不需要日志
json-file JSON 格式文件(默认) 单机部署
syslog Syslog 集中式日志收集
journald systemd journal systemd 环境
gelf Graylog Extended Log Format Graylog 收集
fluentd Fluentd Fluentd 收集
awslogs Amazon CloudWatch AWS 环境
splunk Splunk HTTP Event Collector Splunk
etwlogs Event Tracing for Windows Windows 环境
gcplogs Google Cloud Logging GCP 环境
logentries Logentries Logentries 服务
logz Logz.io Logz.io 服务

13.3 使用 cAdvisor 监控

bash 复制代码
# 运行 cAdvisor 容器
docker run -d \
    --name cadvisor \
    --restart always \
    -p 8080:8080 \
    -v /:/rootfs:ro \
    -v /var/run:/var/run:ro \
    -v /sys:/sys:ro \
    -v /var/lib/docker/:/var/lib/docker:ro \
    -v /dev/disk/:/dev/disk:ro \
    --privileged \
    --device=/dev/kmsg \
    gcr.io/cadvisor/cadvisor:latest

# 访问 cAdvisor Web 界面:http://localhost:8080

13.4 Docker 事件监控

bash 复制代码
# 实时查看 Docker 事件
docker events

# 按类型过滤事件
docker events --filter "type=container"
docker events --filter "type=image"
docker events --filter "type=volume"
docker events --filter "type=network"

# 按事件过滤
docker events --filter "event=start"
docker events --filter "event=stop"
docker events --filter "event=destroy"

# 按容器名过滤
docker events --filter "container=my-nginx"

# 组合过滤
docker events --filter "type=container" --filter "event=die"

# 查看特定时间范围内的事件
docker events --since "2024-01-01T00:00:00"
docker events --until "2024-12-31T23:59:59"

14. 安全最佳实践

14.1 容器安全原则

  1. 最小权限原则:容器只拥有完成任务所需的最小权限
  2. 非 root 用户运行:不要在容器内以 root 身份运行应用
  3. 只读文件系统:如非必要,将文件系统设为只读
  4. 镜像安全扫描:定期扫描镜像中的漏洞
  5. 资源限制:限制容器的 CPU、内存使用量
  6. 网络隔离:使用自定义网络,限制容器间通信

14.2 安全运行容器

bash 复制代码
# 以非 root 用户运行
docker run -d \
    --user 1000:1000 \
    --name my-app \
    myapp:1.0

# 只读根文件系统
docker run -d \
    --read-only \
    --tmpfs /tmp \
    --tmpfs /var/run \
    --name my-app \
    myapp:1.0

# 删除所有 Linux capabilities
docker run -d \
    --cap-drop ALL \
    --cap-add NET_BIND_SERVICE \
    --name my-app \
    myapp:1.0

# 禁止权限提升
docker run -d \
    --security-opt no-new-privileges:true \
    --name my-app \
    myapp:1.0

# 限制系统调用
docker run -d \
    --security-opt seccomp=/path/to/seccomp-profile.json \
    --name my-app \
    myapp:1.0

# 使用 AppArmor
docker run -d \
    --security-opt apparmor=docker-default \
    --name my-app \
    myapp:1.0

# 组合使用
docker run -d \
    --user 1000:1000 \
    --read-only \
    --tmpfs /tmp:rw,noexec,nosuid,size=100m \
    --tmpfs /var/run:rw,noexec,nosuid \
    --cap-drop ALL \
    --cap-add NET_BIND_SERVICE \
    --security-opt no-new-privileges:true \
    --security-opt seccomp=default \
    -p 8080:8080 \
    --memory="256m" \
    --cpus="0.5" \
    --name secure-app \
    myapp:1.0

14.3 镜像安全扫描

bash 复制代码
# 使用 Docker Scout(内置)
docker scout quickview myapp:1.0
docker scout cves myapp:1.0
docker scout recommendations myapp:1.0

# 使用 Trivy(开源)
docker run --rm \
    -v /var/run/docker.sock:/var/run/docker.sock \
    aquasec/trivy:latest \
    image nginx:latest

# 使用 Clair(开源)
# 需要运行 Clair 服务

14.4 敏感信息管理

bash 复制代码
# 不推荐:在 Dockerfile 中硬编码密码
ENV DB_PASSWORD=123456

# 不推荐:在 docker run 命令中明文传递
docker run -e DB_PASSWORD=123456 ...

# 推荐:使用 Docker Secrets(Swarm 模式)
echo "my-secret-password" | docker secret create db_password -
docker service create \
    --secret db_password \
    --name my-service \
    myapp:1.0

# 推荐:使用 .env 文件(Compose)

14.5 Docker Daemon 安全

bash 复制代码
# 开启 TLS 认证(生产环境必须)
# 生成 CA 证书和服务器证书
# 配置 dockerd 使用 TLS

# 限制 Docker API 访问
# 方案 1:只监听本地 socket
# /etc/docker/daemon.json
{
  "hosts": ["unix:///var/run/docker.sock"]
}

# 方案 2:使用 iptables 限制 API 访问
sudo iptables -A INPUT -p tcp --dport 2375 -j DROP
sudo iptables -A INPUT -p tcp --dport 2376 -s 10.0.0.0/8 -j ACCEPT

14.6 Docker Socker 安全

bash 复制代码
# 不要将 /var/run/docker.sock 挂载到容器中
# 除非绝对必要(如 CI/CD runner、Portainer 等)

# 如果需要挂载 Docker Socket,使用只读模式
docker run -v /var/run/docker.sock:/var/run/docker.sock:ro ...

# 考虑使用 Docker Socket Proxy 替代直接挂载
docker run -d \
    --name docker-socket-proxy \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -e CONTAINERS=1 \
    -e POST=0 \
    -p 2375:2375 \
    tecnativa/docker-socket-proxy

15. 性能优化

15.1 镜像优化

bash 复制代码
# 1. 使用合适的基础镜像
# 不推荐:ubuntu:22.04(~77MB)
# 推荐:alpine:3.19(~7MB)或 debian:stable-slim(~25MB)

# 2. 多阶段构建
# 详见 Dockerfile 章节

# 3. 减少镜像层数
# 不推荐(产生多个层):
RUN apt-get update
RUN apt-get install -y package1
RUN apt-get install -y package2
RUN rm -rf /var/lib/apt/lists/*

# 推荐(合并为一层):
RUN apt-get update && \
    apt-get install -y --no-install-recommends package1 package2 && \
    rm -rf /var/lib/apt/lists/*

# 4. 使用 .dockerignore 排除不必要的文件

# 5. 利用构建缓存
# 将不常变更的指令放在前面

15.2 容器运行时优化

bash 复制代码
# 1. 资源限制
docker run -d \
    --memory="512m" \
    --memory-swap="1g" \
    --memory-reservation="256m" \
    --cpus="1.5" \
    --cpuset-cpus="0-1" \
    myapp:1.0

# 2. 使用 host 网络获得最佳网络性能
docker run -d --network host myapp:1.0

# 3. I/O 性能优化
# 使用数据卷而非存储驱动
docker run -d -v /data:/data myapp:1.0

# 4. 调整 ulimit
docker run -d \
    --ulimit nofile=65535:65535 \
    --ulimit nproc=1024:2048 \
    myapp:1.0

# 5. 使用 --oom-score-adj 防止 OOM kill
docker run -d \
    --oom-score-adj=-500 \
    myapp:1.0

15.3 Docker Daemon 优化

json 复制代码
{
  "storage-driver": "overlay2",
  "exec-opts": ["native.cgroupdriver=systemd"],
  "max-concurrent-downloads": 10,
  "max-concurrent-uploads": 5,
  "default-shm-size": "64m",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "live-restore": true,
  "selinux-enabled": false
}

15.4 磁盘空间清理

bash 复制代码
# 查看 Docker 磁盘使用情况
docker system df

# 以更详细的方式显示
docker system df -v

# 清理所有未使用的对象
docker system prune

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

# 清理指定资源
docker image prune          # 清理未使用的镜像
docker container prune      # 清理已停止的容器
docker volume prune         # 清理未使用的数据卷
docker network prune        # 清理未使用的网络
docker builder prune        # 清理 BuildKit 构建缓存

# 不带确认的清理
docker system prune -a -f

# 查看 Docker 数据目录大小
sudo du -sh /var/lib/docker
sudo du -sh /var/lib/docker/containers
sudo du -sh /var/lib/docker/volumes
sudo du -sh /var/lib/docker/overlay2

15.5 BuildKit 优化

bash 复制代码
# 启用 BuildKit(设置环境变量)
export DOCKER_BUILDKIT=1
docker build -t myapp:1.0 .

# 永久启用 BuildKit
# 在 /etc/docker/daemon.json 中设置
{
  "features": {
    "buildkit": true
  }
}

# BuildKit 特性
# 1. 并发构建 - 多阶段构建的并行执行
# 2. 缓存优化 - 更好的缓存命中率
# 3. 密钥传递 - 安全的构建时密钥传递
# 4. 仅在需要时拉取基础镜像

# 使用 BuildKit 的缓存功能
# 在 Dockerfile 中使用 --mount=type=cache
RUN --mount=type=cache,target=/var/cache/apt \
    apt-get update && apt-get install -y package1

# 使用 --mount=type=secret 传递密钥
RUN --mount=type=secret,id=mysecret \
    cat /run/secrets/mysecret

16. 常见问题与故障排除

16.1 权限问题

问题: permission denied while trying to connect to the Docker daemon socket

复制代码
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock

解决方法:

bash 复制代码
# 方案 1:将用户加入 docker 组
sudo usermod -aG docker $USER
newgrp docker

# 方案 2:使用 sudo(不推荐长期使用)
sudo docker ps

# 方案 3:修改 socket 权限(不推荐)
sudo chmod 666 /var/run/docker.sock

16.2 磁盘空间不足

问题: no space left on device

bash 复制代码
# 查看磁盘使用情况
docker system df

# 清理所有未使用的 Docker 对象
docker system prune -a -f

# 如果还是空间不足,检查 Docker 数据目录
sudo du -sh /var/lib/docker/*
sudo du -sh /var/lib/docker/overlay2/* | sort -rh | head -10

# 移动 Docker 数据目录到更大的磁盘
# 编辑 /etc/docker/daemon.json
{
  "data-root": "/mnt/large-disk/docker"
}

# 重启 Docker
sudo systemctl daemon-reload
sudo systemctl restart docker

16.3 容器无法启动

bash 复制代码
# 查看容器日志
docker logs my-container

# 检查容器状态和退出码
docker ps -a | grep my-container
docker inspect my-container --format='{{.State.ExitCode}}'

# 常见退出码
# 0   - 正常退出
# 1   - 一般错误
# 137 - SIGKILL(OOM 或被 docker kill)
# 139 - SIGSEGV(段错误)
# 143 - SIGTERM(优雅停止)

# 以调试模式启动容器
docker run -it --entrypoint /bin/sh myimage:tag
docker run -it --entrypoint /bin/bash myimage:tag

# 检查容器资源限制
docker inspect my-container | grep -A 10 "HostConfig"

# 查看系统资源使用
free -h
df -h

16.4 端口冲突

问题: port is already allocated

复制代码
Error: failed to start container: port is already allocated

解决方法:

bash 复制代码
# 查看哪个进程占用了端口
sudo lsof -i :8080
sudo netstat -tlnp | grep 8080
sudo ss -tlnp | grep 8080

# 查看哪个容器占用了端口
docker ps | grep 8080

# 停止占用端口的容器
docker stop conflicting-container

# 或使用不同的端口
docker run -d -p 8081:80 nginx

16.5 网络问题

问题: 容器无法访问外部网络或 DNS 解析失败

bash 复制代码
# 检查容器 DNS 配置
docker exec my-container cat /etc/resolv.conf

# 检查宿主机网络
ping google.com
nslookup google.com

# 测试容器网络连接
docker exec my-container ping 8.8.8.8
docker exec my-container ping google.com

# 修改容器的 DNS
docker run -d --dns 8.8.8.8 --dns 114.114.114.114 myimage

# 重启 Docker 网络(可能解决某些网络问题)
sudo systemctl restart docker

# 重置 iptables 规则(谨慎,会影响所有 Docker 网络)
sudo iptables -P FORWARD ACCEPT

16.6 OOM(Out of Memory)

问题: 容器被系统 OOM Killer 杀死

bash 复制代码
# 检查容器是否被 OOM 杀掉
docker inspect my-container --format='{{.State.OOMKilled}}'

# 查看容器退出码
docker inspect my-container --format='{{.State.ExitCode}}'
# OOM 的退出码通常是 137

# 增加容器内存限制
docker run -d --memory="1g" --memory-swap="2g" myapp:1.0

# 调整 OOM 优先级(越小越不容易被 OOM kill)
docker run -d --oom-score-adj=-500 myapp:1.0

# 查看系统 OOM 日志
sudo dmesg | grep -i oom
sudo journalctl -k | grep -i oom

16.7 镜像拉取慢

bash 复制代码
# 1. 配置镜像加速器(推荐)
# 编辑 /etc/docker/daemon.json
{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://dockerproxy.com"
  ]
}

# 2. 使用代理(如果配置了代理)
# 创建 /etc/systemd/system/docker.service.d/proxy.conf
[Service]
Environment="HTTP_PROXY=http://proxy.example.com:8080"
Environment="HTTPS_PROXY=http://proxy.example.com:8080"
Environment="NO_PROXY=localhost,127.0.0.1"

# 重新加载并重启
sudo systemctl daemon-reload
sudo systemctl restart docker

# 3. 预先拉取常用镜像
docker pull nginx:alpine
docker pull alpine:latest

16.8 时间同步问题

问题: 容器内时间与宿主机不一致

bash 复制代码
# 方案 1:挂载宿主机时区文件
docker run -d \
    -v /etc/localtime:/etc/localtime:ro \
    -v /etc/timezone:/etc/timezone:ro \
    nginx

# 方案 2:设置环境变量
docker run -d \
    -e TZ=Asia/Shanghai \
    nginx

# 方案 3:在 Dockerfile 中设置
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo "Asia/Shanghai" > /etc/timezone

16.9 Docker Daemon 无法启动

bash 复制代码
# 检查 Docker 服务状态
sudo systemctl status docker

# 查看详细错误日志
sudo journalctl -u docker.service -n 100

# 检查配置文件语法
dockerd --config-file /etc/docker/daemon.json --validate

# 尝试手动启动 Docker Daemon 查看错误
sudo dockerd --debug

# 常见原因及解决方法
# 1. daemon.json 语法错误
# 2. 端口冲突(默认 API 端口 2375/2376)
# 3. 存储驱动问题
# 4. 磁盘空间不足

# 重置 Docker 配置(备份后)
sudo mv /etc/docker/daemon.json /etc/docker/daemon.json.bak
sudo systemctl restart docker

16.10 overlay2 存储驱动问题

bash 复制代码
# 检查是否使用了 overlay2
docker info | grep "Storage Driver"

# 如果 overlay2 不支持,可以尝试修改存储驱动
# 编辑 /etc/docker/daemon.json
{
  "storage-driver": "overlay2",
  "storage-opts": [
    "overlay2.override_kernel_check=true"
  ]
}

# 如果 overlay2 仍不工作,可以切换到 overlay 或其他驱动
# 注意:切换存储驱动会丢失所有现有镜像和容器

17. 附录:常用命令速查

17.1 镜像操作

命令 说明
docker search <name> 搜索镜像
docker pull <name>:<tag> 拉取镜像
docker images 列出镜像
docker rmi <id> 删除镜像
docker build -t <name>:<tag> . 构建镜像
docker tag <src> <target> 标记镜像
docker push <name>:<tag> 推送镜像
docker save -o <file> <image> 导出镜像
docker load -i <file> 导入镜像
docker history <image> 查看镜像构建历史
docker inspect <image> 查看镜像详情

17.2 容器操作

命令 说明
docker run <image> 创建并启动容器
docker ps 列出运行中的容器
docker ps -a 列出所有容器
docker start <container> 启动容器
docker stop <container> 停止容器
docker restart <container> 重启容器
docker kill <container> 强制停止容器
docker rm <container> 删除容器
docker logs <container> 查看日志
docker logs -f <container> 跟踪日志
docker exec -it <container> sh 进入容器
docker cp <src> <dest> 文件复制
docker stats 资源监控
docker top <container> 查看进程

17.3 网络操作

命令 说明
docker network ls 列出网络
docker network create <name> 创建网络
docker network rm <name> 删除网络
docker network connect <name> <container> 连接网络
docker network disconnect <name> <container> 断开网络
docker network inspect <name> 查看网络详情
docker network prune 清理未使用的网络

17.4 数据卷操作

命令 说明
docker volume ls 列出数据卷
docker volume create <name> 创建数据卷
docker volume rm <name> 删除数据卷
docker volume inspect <name> 查看数据卷详情
docker volume prune 清理未使用的数据卷

17.5 Compose 操作

命令 说明
docker compose up -d 启动服务
docker compose down 停止并删除服务
docker compose ps 列出服务状态
docker compose logs -f 跟踪服务日志
docker compose exec <service> sh 进入服务容器
docker compose build 构建服务镜像
docker compose pull 拉取服务镜像
docker compose restart 重启服务
docker compose stop 停止服务
docker compose start 启动已停止的服务
docker compose config 校验并查看配置
docker compose top 查看服务进程

17.6 系统维护

命令 说明
docker info 查看 Docker 系统信息
docker version 查看 Docker 版本
docker system df 查看磁盘使用情况
docker system prune 清理未使用的资源
docker system prune -a 清理所有未使用的资源
docker events 实时监控 Docker 事件
systemctl start docker 启动 Docker 服务
systemctl stop docker 停止 Docker 服务
systemctl restart docker 重启 Docker 服务
systemctl status docker 查看 Docker 服务状态
systemctl enable docker 设置 Docker 开机自启
systemctl disable docker 禁用 Docker 开机自启

17.7 日志管理命令

命令 说明
journalctl -u docker.service -n 100 查看 Docker Daemon 日志
journalctl -u docker.service -f 实时跟踪 Docker Daemon 日志
journalctl -u docker.service --since "1 hour ago" 查看最近 1 小时日志
docker logs --tail 100 -f <container> 查看容器日志后 100 行并跟踪

版权声明 :本文档仅供学习参考,如有疏漏或错误,欢迎指正。

建议定期访问 Docker 官方文档 获取最新信息。

相关推荐
天才测试猿12 小时前
Jenkins+Docker自动化测试全攻略
自动化测试·软件测试·python·测试工具·docker·jenkins·测试用例
JAVA学习通12 小时前
《大营销平台系统设计实现》 - 营销服务 第8节:抽奖规则树模型结构设计
运维·决策树·docker·容器·责任链模式
无相孤君18 小时前
我用 Docker + JunimoServer 搭了一个星露谷物语无头服,还顺手做了个本地管理面板
linux·游戏·docker·开源
爱吃龙利鱼18 小时前
ubuntu2026.04部署k8s1.36版本的傻瓜式教程(注:运行时为docker,网络插件为calico)
运维·网络·笔记·docker·云原生·kubernetes
会编程的土豆19 小时前
Docker 日常操作笔记(开发最常用命令)
笔记·docker·容器
杨浦老苏21 小时前
Twitter风格RSS聚合阅读器DanB-RSS
docker·群晖·rss
白日做梦Q21 小时前
Docker部署YOLOv8训练+推理完整教程(含报错解决)
yolo·docker·容器
终端行者21 小时前
企业级Jenkins Pipeline 实战 Docker构建+Ansible发布
ci/cd·docker·ansible·jenkins
身如柳絮随风扬21 小时前
Docker 化部署 Spring Boot + Vue 全栈应用:从打包到容器化上线
vue.js·spring boot·docker