安装
对于 Windows,需要安装 Docker Desktop,这是一个带有 gui 面板的合体程序。但是对于 Linux,为了方便起见,直接安装 Docker Engine 即可。 https://docs.docker.com/engine/install/
以 Debian 为例,可以使用网页中提到的一键部署脚本:
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh该脚本会自动安装 docker 并解决所以有的用户组与权限问题。
但是他更建议直接使用 apt 进行安装,需要将 docker 秘钥和仓库源添加到 apt 仓库列表中。
由于网络关系,没有海外代理的情况下可以直接查看清华镜像的安装步骤: https://mirrors.tuna.tsinghua.edu.cn/help/docker-ce/
由于一些特殊关系,使用 apt 安装 docker 后,运行各种 docker 命令必须 sudo,要解决这种问题,按如下步骤操作即可: https://docs.docker.com/engine/install/linux-postinstall/
之后运行
docker run hello-world测试,只要不再出现 permission denied while trying to connect to the docker API at unix:///var/run/docker.sock 即可,其他错误是由于被墙导致的网络问题。
配置与运行
在成功安装 Docker Engine 后,我们即可开始部署和管理容器。根据业务复杂度和定制化需求,Docker 的核心使用流程主要分为以下三个层级:
- 运行现有镜像 (Docker CLI):这是最基础的使用方式。通过
docker run等命令行指令,我们可以直接从远端仓库拉取标准化打包好的镜像,并快速启动为独立运行的容器。适用于部署基础且无需复杂参数配置的服务。 - 服务编排与管理 (Docker Compose):当应用架构涉及多个容器协同工作,或需要持久化记录复杂的运行参数(如端口映射、环境变量、挂载目录)时,直接使用 CLI 会变得难以维护。此时需要编写
docker-compose.yml配置文件,通过docker compose up -d命令实现多服务的统一定义、一键启动与网络隔离管理。 - 自定义构建镜像 (Dockerfile):若公共仓库的镜像无法满足特定业务需求(如需注入自定义代码、特殊系统依赖或驱动),则需要编写 Dockerfile。该文件定义了从基础系统环境到最终业务代码的完整构建逻辑。通过构建指令,即可生成定制化的私有镜像,供后续运行或 Compose 编排使用。
有关存储位置
无论是通过
docker pull拉取的官方镜像,还是基于 Dockerfile 自行构建的定制镜像,在 Linux 系统下,其物理数据默认均统一存储于/var/lib/docker/目录中。Docker 引擎通过分层文件系统(如 overlay2 存储驱动)来高效管理这些只读的镜像层与可写的容器层。在逻辑操作层面,我们仅需通过docker images命令即可查看和管理本地的所有镜像,无需直接干预底层物理目录。
命令行指令
以下包含各种常用的 docker 命令行(包含 compose)和其用法解释:
# ==============================================================================
# 第一部分:Docker CLI (基础命令行 - 用于管理单个资源)
# ==============================================================================
# --- 1. 镜像管理 (Image Management) ---
docker pull nginx:latest
# 从远程仓库拉取镜像。格式为 image:tag,若不写 tag 默认是 latest。
docker images
# 列出本地所有已下载的镜像。包含镜像 ID、创建时间、大小等信息。
docker rmi <image_id>
# 删除指定的本地镜像。如果镜像正在被容器使用,需要先删除容器或加 -f 强制删除。
docker image prune -a
# 清理所有未被使用的镜像(悬空镜像和未被容器引用的镜像),释放磁盘空间。
docker build -t my_app:v1 .
# 从当前目录(.)的 Dockerfile 构建镜像。
# -t: 为构建的镜像打上标签(Tag),即命名为 my_app 版本 v1。
docker save -o my_image.tar my_app:v1
# 将镜像保存为 tar 归档文件,用于离线传输。
docker load -i my_image.tar
# 从 tar 归档文件中加载镜像。
# --- 2. 容器生命周期管理 (Container Lifecycle) ---
docker run -d -p 8080:80 --name my_web --restart always -v /data:/var/www nginx
# 启动一个新的容器(这是最常用的命令)。
# -d: 后台运行模式 (Detached),容器启动后不会占用当前终端。
# -p 8080:80: 端口映射。将宿主机的 8080 端口映射到容器内部的 80 端口。
# --name my_web: 给容器起一个自定义名称,方便后续操作。
# --restart always: 重启策略。如果容器崩溃或 Docker 重启,容器会自动重启。
# -v /host/path:/container/path: 挂载数据卷。将宿主机目录挂载到容器内,实现数据持久化。
# nginx: 指定使用的镜像名称。
docker ps
# 列出当前正在运行的容器。
docker ps -a
# 列出所有容器,包括已经停止运行的容器。
docker stop my_web
# 优雅地停止指定容器(发送 SIGTERM 信号)。
docker kill my_web
# 强制停止指定容器(发送 SIGKILL 信号)。
docker start my_web
# 启动一个已经停止的容器。
docker restart my_web
# 重启容器。
docker rm my_web
# 删除已停止的容器。
# -f: 强制删除,即使容器正在运行也能删除。
# --- 3. 容器交互与调试 (Interaction & Debugging) ---
docker exec -it my_web /bin/bash
# 进入正在运行的容器内部进行操作。
# -i: 保持标准输入 (STDIN) 打开。
# -t: 分配一个伪终端 (TTY)。
# /bin/bash: 指定在容器内执行的 shell(部分精简镜像可能是 /bin/sh)。
docker logs -f --tail 100 my_web
# 查看容器的日志输出。
# -f: 实时跟踪日志输出 (Follow)。
# --tail 100: 只显示最后 100 行日志。
docker inspect my_web
# 查看容器的详细元数据(JSON 格式)。包含 IP 地址、挂载点、环境变量等底层信息。
docker cp local_file.txt my_web:/app/
# 将宿主机的文件复制到容器内部。
# 反之:docker cp my_web:/app/file.txt . 将容器文件复制到宿主机。
docker stats
# 实时显示容器的资源使用情况(CPU、内存、网络 I/O)。
# --- 4. 网络管理 (Network) ---
docker network create my_net
# 创建一个自定义的 Bridge 网络。自定义网络允许容器通过容器名相互解析(DNS)。
docker network ls
# 列出所有 Docker 网络。
docker run --network my_net ...
# 启动容器时加入指定网络。
docker network inspect my_net
# 查看网络详情,看哪些容器连接到了该网络。
# --- 5. 数据卷管理 (Volumes) ---
docker volume create my_data
# 创建一个命名数据卷(由 Docker 托管,通常在 /var/lib/docker/volumes 下)。
docker volume ls
# 列出所有数据卷。
docker volume prune
# 清理所有未被容器挂载的数据卷。
# ==============================================================================
# 第二部分:Docker Compose (服务编排 - 用于管理多容器应用)
# ==============================================================================
# 注意:v2版本命令是 'docker compose',v1旧版本是 'docker-compose'(带横杠)。
# 这里的命令主要操作对象是当前目录下的 docker-compose.yml 文件。
docker compose up -d
# 根据 docker-compose.yml 启动所有服务。
# -d: 后台运行。
# --build: 启动前强制重新构建镜像(如果代码有更新)。
docker compose down
# 停止并删除由 compose 启动的容器、网络。
# -v: 同时删除挂载的数据卷(慎用)。
docker compose ps
# 列出当前 compose 项目下的所有容器状态。
docker compose logs -f
# 查看所有服务的日志聚合。
# docker compose logs -f service_name: 只查看特定服务的日志。
docker compose exec service_name /bin/bash
# 进入 compose 中定义的某个服务的容器内部。
docker compose restart service_name
# 重启特定的服务。
docker compose config
# 检查并打印解析后的 docker-compose.yml 配置,用于验证语法错误。system 命令:
docker system df # 显示 Docker 磁盘使用情况
-v, --verbose # 显示详细的空间使用信息,单独列出每个镜像、容器和数据卷的占用大小
docker system events # 从 Docker 守护进程获取实时的事件日志
-f, --filter filter # 根据提供的条件过滤事件(例如:event=start, container=my_container)
--format string # 使用指定的 Go 模板格式化输出结果
--since string # 显示自指定时间戳或相对时间(如 1h)以来的所有事件
--until string # 显示指定时间戳或相对时间之前的所有事件
docker system info # 显示系统级别的详细信息(包含容器总数、镜像总数、存储驱动、网络配置等)
-f, --format string # 使用指定的 Go 模板格式化输出结果
docker system prune # 清理所有未使用的数据(默认仅清理停止的容器、未使用的网络和悬空镜像)
-a, --all # 清理所有未被使用的镜像,不仅限于悬空镜像
--filter filter # 提供过滤条件(例如:until=24h,指示仅清理创建时间在24小时前的数据)
-f, --force # 强制执行清理操作,跳过命令行交互式的确认提示
--volumes # 同时清理未被任何容器引用的本地数据卷compose配置文件
以下是常见的 compose 写法和解释,一个 compose 中可以同时配置多个容器。
# 版本号 (可选)
# 现在较新版本的 Docker Compose (v2) 其实可以省略这个,但写上 '3.8' 或 '3' 是个好习惯,保证兼容性。
version: '3.8'
# 服务定义区域:这里面每一项都是一个独立的容器服务
services:
# ============================
# 场景一:使用现成的镜像 (直接下载或已经构建完成的)
# ============================
database_service:
# 镜像名称:格式为 [仓库/][用户名/]镜像名[:标签]
# 如果不写标签,默认就是 latest。建议生产环境写死版本号,防止自动更新导致不兼容。
image: postgres:14.2-alpine
# 容器名称:指定容器运行时的名字。
# 如果不写,Docker 会自动生成 文件夹名_服务名_1。指定名字方便脚本管理。
container_name: my_postgres_db
# 重启策略:
# "no": 默认值,挂了就不重启。
# "always": 只要容器停了就重启(手动停止除外)。
# "on-failure": 只有在非正常退出(错误码不为0)时才重启。
# "unless-stopped": 除非手动 docker stop,否则一直重启(推荐)。
restart: unless-stopped
# 环境变量:传入容器内部的参数。
# 可以是数组格式,也可以是键值对字典格式。
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: secure_password
TZ: Asia/Shanghai # 设置时区,非常重要,否则日志时间会差8小时。
# 环境变量文件:如果变量太多,可以写在一个 .env 文件里,这里直接引用路径。
env_file:
- ./db_config.env
# 数据卷挂载 (Volumes):核心配置!
# 格式:宿主机路径:容器内路径[:读写权限]
volumes:
# 1. 绑定挂载 (Bind Mount):把本机的一个具体目录映射进去。
# 这种方式最直观,数据直接在眼皮底下。
- ./pg_data:/var/lib/postgresql/data
# 2. 命名卷挂载 (Named Volume):使用 Docker 托管的卷。
# 数据在 /var/lib/docker/volumes/ 下,迁移稍微麻烦点,但性能略好。
- pg_config:/etc/postgresql
# 3. 只读挂载:加上 :ro,容器内无法修改这个文件。
- ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
# 网络配置:
# 指定该服务加入哪个网络。如果不写,Compose 会默认创建一个 default 网络。
#
networks:
- backend_net
# ============================
# 场景二:自己构建镜像 (Build)
# ============================
web_app_service:
# 构建配置:告诉 Compose 去哪里找 Dockerfile。
build:
context: . # 构建上下文目录,通常是当前目录。
dockerfile: Dockerfile.dev # 指定文件名,如果叫 Dockerfile 可以省略。
args: # 构建参数 (ARG),只在构建过程中有效。
build_version: 1.0
# 端口映射 (Ports):
# 格式:宿主机端口:容器端口
ports:
- "8080:80" # 任何IP访问主机的8080,都转发给容器的80。
- "127.0.0.1:3000:3000" # 仅限本机访问3000端口(安全做法)。
# 依赖关系 (Depends On):
# 决定启动顺序。这里表示:先启动 database_service,再启动我。
depends_on:
- database_service
# 资源限制 (Deploy):
# 限制容器能用多少 CPU 和 内存,防止一个程序把死机搞崩。
deploy:
resources:
limits:
cpus: '0.50' # 限制使用 50% 的 CPU 核心。
memory: 512M # 限制最大使用 512MB 内存。
# 健康检查 (Healthcheck):
# 定期检查容器是不是还“活着”。
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s # 每30秒检查一次。
timeout: 10s # 超过10秒没响应算失败。
retries: 3 # 连续失败3次标记为 unhealthy。
# 这里的 command 会覆盖 Dockerfile 里的 CMD 指令。
command: python manage.py runserver 0.0.0.0:80
# 全局网络定义
networks:
backend_net:
driver: bridge # 桥接模式(默认)。
ipam: # 自定义网段(高级用法)。
config:
- subnet: 172.20.0.0/16
# 全局数据卷定义
volumes:
pg_config: # 这里声明上面用到的命名卷。
# ============================
# 场景三:硬件驱动与权限控制 (高级配置)
# ============================
advanced_service:
image: custom_hardware_app:latest
# 特权模式:
# 开启后,容器将获取系统内核的无限制访问权,拥有接近宿主机 root 用户的完整系统权限。
# 仅在需要完全操作底层硬件、修改内核参数或运行 Docker-in-Docker 时使用,存在安全风险。
privileged: true
# 细粒度权限控制:
# 为了避免 privileged 带来的安全隐患,可以按需为容器添加特定的 Linux Capabilities。
# NET_ADMIN 允许修改网络配置,SYS_ADMIN 允许挂载文件系统。
cap_add:
- NET_ADMIN
- SYS_ADMIN
# 移除权限:
# 也可以显式剥夺容器的默认权限以提升安全性。
cap_drop:
- ALL
# 设备映射:
# 将宿主机的物理硬件设备直接映射进容器内部供程序调用。
# 格式为 宿主机物理设备路径:容器内挂载路径。常用于音视频采集与硬件加速。
devices:
- "/dev/video0:/dev/video0" # 映射 USB 摄像头或采集卡
- "/dev/snd:/dev/snd" # 映射音频设备
- "/dev/dri:/dev/dri" # 映射 GPU 显卡以支持硬件解码
# 内存文件系统:
# 将指定的容器目录挂载到宿主机的物理内存中,而非磁盘上。
# 读写速度极快,且容器重启后数据自动清空。极度适合存放高频刷新的临时缓存或安全密钥。
tmpfs:
- /run
- /tmp
关于网络定义
Docker 提供了多种网络模式,其中常用的有桥接模式(默认)和 Host模式,区别如下:
| 特性 | 默认模式 (Bridge) | Host 模式 |
|---|---|---|
| IP 地址 | 容器有独立的内网 IP (如 172.17.0.2) | 直接用系统的 IP (如 192.168.1.66) |
| 端口映射 | 需要手动映射 (-p 8080:80) | 不需要映射 (写了也没用,容器监听啥就是啥) |
| 端口冲突 | 不怕冲突 (容器80可以映到主机8080) | 极易冲突 (如果容器监听80,主机的80就被占了) |
| 隔离性 | 强 (网络隔离) | 弱 (网络不隔离) |
除了这两个之外,还有如下模式:
none模式
配置:
network_mode: "none"特点: 容器有自己的网络命名空间,但是没有任何网卡(除了
lo回环接口),也没有 IP 地址。用途: 极致的安全隔离。适用于不需要联网、只需要处理本地数据(比如离线批处理计算、生成密码、分析敏感日志)的任务。
macvlan模式
配置: 需要先创建 macvlan 网络,然后指定容器加入。
特点: 容器会拥有一个物理局域网的 MAC 地址和 真实的局域网 IP。
用途: 此时容器看起来就像是路由器上连接的另一台真实的物理电脑。这在需要容器和家里其他设备(如路由器、智能家居)处于同一网段,或者需要极高性能网络转发时非常有用。
container:<name|id>模式 (复用模式)
配置:
network_mode: "service:another_container"特点: 新容器不创建自己的网卡,而是直接共用另一个已存在容器的网络栈。它们之间可以通过
localhost通信。用途: Kubernetes (K8s) 的 Pod 就是基于这个原理。比如容器如果需要配合一个监控插件,这个插件就可以用这种模式依附在其身上,直接抓取它的流量。
DockerFile
- 下面是一个例子:
# ==============================================================================
# Dockerfile (镜像构建脚本 - 其他主要形式)
# ==============================================================================
# 这是一个文本文件,名为 Dockerfile,用于定义镜像构建过程。
# 以下是常见指令的解释:
FROM ubuntu:20.04
# 指定基础镜像。所有操作都基于这个镜像开始。
MAINTAINER Master
# (可选) 指定镜像维护者信息。
ENV APP_HOME /app
# 设置环境变量。在后续指令或容器运行时均可访问。
WORKDIR $APP_HOME
# 设置工作目录。后续的 RUN, CMD, COPY 等指令都在此目录下执行。类似于 cd。
COPY requirements.txt .
# 将宿主机文件复制到镜像中。
# COPY 源路径 目标路径。
RUN pip install -r requirements.txt
# 在构建过程中执行命令。每执行一条 RUN 都会在镜像中生成一个新的层 (Layer)。
ADD package.tar.gz .
# 类似于 COPY,但功能更强。如果源文件是压缩包,ADD 会自动解压。
EXPOSE 8080
# 声明容器运行时监听的端口。这只是一个声明,实际映射仍需在 run 时使用 -p 参数。
VOLUME ["/data"]
# 声明挂载点。
ENTRYPOINT ["python", "app.py"]
# 设置容器启动时执行的可执行文件。
# 与 CMD 不同,ENTRYPOINT 的参数很难被 run 命令行参数覆盖,通常用于将容器当作可执行程序使用。
CMD ["--help"]
# 提供容器启动时的默认参数。
# 如果 Dockerfile 中同时有 ENTRYPOINT 和 CMD,CMD 的内容会作为参数传给 ENTRYPOINT。
# 如果 docker run 指定了命令,CMD 会被覆盖。- 多阶段构建:
# 1. 多阶段构建 (Multi-stage Build)
# 语法:FROM ... AS <阶段名称>
# 作用:在一个 Dockerfile 中定义多个阶段。第一阶段包含所有编译工具和源码,
# 编译出二进制文件后,在第二阶段只使用一个极其精简的基础镜像(如 debian-slim 或 alpine),
# 并通过 COPY --from=<阶段名称> 将编译好的文件复制过来。
# 优势:极大减小最终镜像的体积,且最终镜像中不包含任何源码和编译环境,提升安全性。
COPY --from=builder /out/backend-core /usr/local/bin/backend-core
# 2. ARG: 构建参数
# 语法:ARG <变量名>[=<默认值>]
# 作用:定义一个只在 docker build 构建过程中生效的变量。
# 与 ENV 的区别:ENV 定义的变量在镜像构建后、容器运行时依然存在;
# 而 ARG 在镜像构建完成后就失效了,容器内部无法访问。
# 通常用于传递编译时的参数,如版本号、代理地址或目标架构。
ARG GOPROXY=https://goproxy.cn,direct更多多阶段构建知识,请看这里。
高级配置与运维
分发镜像
无论是使用 compose 配置并运行镜像,还是在 cli 中直接 run,对于自定义构建的镜像,Docker 需要先拿到镜像本体之后才能运行。
因此,当我们构建了一个镜像,想把它交给别人,我们可以选择导出镜像并交由别人导入镜像和推送到 Docker 仓库两种分发方式。
- 导出导入:
# 将镜像导出为归档文件
docker save -o my_backend.tar my_backend:latest
# 将 my_backend.tar 发送给别人后,别人在机器上执行加载命令
docker load -i my_backend.tar
# 加载完成后,可以直接 run 或通过 compose 进行配置- 推送到 Docker 仓库:
请先登录。
# 1. 登录 Docker 仓库
docker login
# 2. 按照仓库规范给镜像打标签(格式必须是:用户名/镜像名:版本号)
docker tag my_backend:latest name/my_backend:v1.0
# 3. 将镜像推送到云端
docker push name/my_backend:v1.0
# 4. 在仓库为 public 的情况下,别人只需要执行 pull 即可下载运行
docker pull name/my_backend:v1.0关于镜像名
无论是直接 run 还是使用 compose 配置,其中的镜像名需要和已有的镜像或云端仓库中的镜像名完全一致。
对于 compose,填写了远端仓库的镜像名后,不需要提前手动
docker compose pull,只要docker compose up -d就会在首次运行前自动拉取镜像。
更新镜像
compose 中的
latest的含义仅代表首次运行时,会自动拉取最新的镜像,之后运行并不会自动更新。因此对于镜像,需要手动更新:
# 1. 强制拉取云端最新的镜像,这会覆盖本地旧的 latest 标签 docker compose pull # 2. 重新启动服务。Compose 会自动对比镜像的哈希值, # 发现镜像有变动后,会自动销毁旧容器,并使用新镜像创建新容器运行 docker compose up -d
日志检索与容器调试
# ==============================================================================
# 容器日志排错与调试指南 (Logging & Debugging)
# ==============================================================================
# --- 1. 日志查阅 (Logs) ---
# 当容器状态为 Exited 或服务异常时,优先查看标准输出和标准错误。
docker logs <container_name_or_id>
# 查看指定容器的全部历史日志。
docker logs -f <container_name_or_id>
# -f, --follow: 实时跟踪日志输出,终端会阻塞并持续打印新日志。
docker logs --tail 100 <container_name_or_id>
# --tail <行数>: 仅显示末尾指定行数的日志,避免日志过大导致刷屏。
docker logs -t <container_name_or_id>
# -t, --timestamps: 在每行日志前附加精确的时间戳,用于对齐和分析时间线。
docker logs --since 30m <container_name_or_id>
# --since: 仅显示指定时间之后的日志。支持格式如 30m (30分钟前), 2h (2小时前) 或绝对时间戳。
docker logs --until 5m <container_name_or_id>
# --until: 仅显示指定时间之前的日志,常与 --since 配合截取特定时间段的日志。
docker compose logs -f <service_name>
# 查看 Compose 环境中特定服务的实时聚合日志。不加服务名则查看所有服务的日志。
# --- 2. 内部状态动态排查 (Exec) ---
# 当容器正在运行但逻辑异常时,进入其隔离的命名空间内部执行命令。
docker exec -it <container_name_or_id> /bin/bash
# -i, --interactive: 保持标准输入打开。
# -t, --tty: 分配一个伪终端。
# /bin/bash (或 /bin/sh): 在容器内部启动的 Shell。用于进入容器内部进行排查。
docker exec -u root -it <container_name_or_id> /bin/bash
# -u, --user <UID|用户名>: 指定以哪个用户身份在容器内执行命令。常用于提权排查权限被拒绝(Permission denied)的问题。
docker exec -e DEBUG=1 <container_name_or_id> env
# -e, --env <键=值>: 在执行命令时临时注入环境变量。
docker exec <container_name_or_id> ls -l /app/data
# 不进入容器交互界面,直接在宿主机终端请求容器执行单条非交互命令并返回结果。
docker compose exec <service_name> /bin/sh
# 在 Compose 环境中快速进入指定服务容器的内部。
# --- 3. 底层元数据与配置分析 (Inspect) ---
# 查阅 Docker 引擎维护的容器静态配置数据,定位挂载、网络分配、环境变量错误。
docker inspect <container_name_or_id>
# 返回容器的完整元数据,输出格式为 JSON 数组。包含网络配置、挂载点、运行状态等所有底层信息。
docker inspect -f '{{.NetworkSettings.IPAddress}}' <container_name_or_id>
# -f, --format: 使用 Go 模板语法提取 JSON 中的特定字段。此命令仅提取并输出容器的内网 IP 地址。
docker inspect -f '{{json .Mounts}}' <container_name_or_id>
# 仅输出容器的存储卷挂载详情,用于排查宿主机路径与容器路径的映射配置是否准确。
# --- 4. 实时资源监控 (Monitoring) ---
# 分析内存泄漏(OOM)、CPU 飙升或网络 I/O 瓶颈。
docker stats
# 实时流式显示所有运行中容器的 CPU使用率、内存使用量/限制、网络读写、磁盘 I/O 统计信息。
docker stats --no-stream <container_name_or_id>
# --no-stream: 仅输出当前瞬间的状态快照,不进行实时刷新,适合脚本记录。
docker top <container_name_or_id>
# 显示容器内部正在运行的进程信息 (PID, 用户, 资源占用等),类似于 Linux 宿主机的 top 或 ps 命令。
docker events
# 监听 Docker 守护进程的实时事件流 (如容器的创建、启动、崩溃、停止等),用于全局监控故障发生的时间点。
# --- 5. 致命崩溃强制介入 (Entrypoint Override) ---
# 当容器一启动就崩溃退出无法使用 exec 进入时,必须修改启动入口进行干预。
docker run -it --rm --entrypoint /bin/sh <image_name>
# --entrypoint <命令>: 强制覆盖 Dockerfile 中定义的 ENTRYPOINT 或 CMD。
# --rm: 容器退出后自动删除。
# 逻辑:将启动命令替换为基础的 shell,阻止会导致崩溃的业务代码运行。这让开发人员能够成功进入容器环境内部,手动执行原始启动脚本以捕获具体报错堆栈。多阶段构建
多阶段构建是编写生产级别 Dockerfile 的核心技术。它允许我们在同一个文件中定义编译环境和运行环境,并在最终打包时,只保留编译好的纯净二进制文件。这不仅能将镜像体积从几个 GB 极致压缩到十几 MB,还能大幅减少运行环境的攻击面,提升安全性。
# ==============================================================================
# 多阶段构建与体积优化指南
# ==============================================================================
# --- 1. 命名构建阶段 ---
FROM golang:1.22-alpine AS builder
# AS <阶段名称>: 为当前的基础构建阶段声明一个别名。
# 逻辑:我们将这个包含了完整 Go 语言编译器、SDK 和各类依赖库的庞大基础镜像命名为 builder。
# 该阶段的任务仅限于拉取依赖和编译源代码,生成最终的二进制执行文件。
WORKDIR /src
COPY . .
RUN go build -o /app/backend-core main.go
# --- 2. 启动新阶段 ---
FROM alpine:latest
# 独立的 FROM 指令:在同一个 Dockerfile 中开启一个全新的构建阶段。
# 逻辑:一旦执行新的 FROM,Docker 会丢弃之前 builder 阶段的所有环境变量、层级缓存以及庞大的编译工具链。
# 这里选择一个极其精简的基础镜像 alpine 作为最终的运行环境基底。
# --- 3. 跨阶段文件抽取 ---
COPY --from=builder /app/backend-core /usr/local/bin/backend-core
# --from=<阶段名称或阶段索引>: 指定源文件所在的构建阶段。
# 逻辑:将 builder 阶段中已经编译好的 backend-core 二进制文件,直接抽取并复制到当前纯净阶段的指定目录中。
# 结果:最终生成的镜像内只包含精简的 alpine 系统和编译好的可执行文件,不包含任何 Go 源码或编译器。
# --- 4. 引用外部镜像文件 ---
COPY --from=nginx:latest /etc/nginx/nginx.conf /custom/nginx.conf
# 逻辑:--from 参数不仅可以引用当前 Dockerfile 中定义的阶段,还可以直接指定远程仓库中的外部可用镜像。
# 作用是从外部镜像中直接提取特定文件或静态资源到当前阶段,而无需在该外部镜像前使用 FROM 进行全局拉取。
# ==============================================================================
# 构建上下文优化
# ==============================================================================
# --- .dockerignore 文件的使用 ---
# 注意:这不是 Dockerfile 内部的指令,而是在项目根目录下与 Dockerfile 同级的独立纯文本文件。
# 其语法与规则与 .gitignore 完全一致。
# 示例内容:
# .git/
# node_modules/
# *.md
# temp_data/
# 逻辑:在执行 docker build 时,Docker Client 默认会将当前目录(即构建上下文)下的所有文件打包发送给 Docker Daemon。
# 如果上下文中包含数百 MB 的 node_modules 或庞大的 .git 历史记录,会导致构建前的传输极其缓慢,并占用大量内存。
# 在 .dockerignore 中声明这些目录后,Docker 会在传输前直接过滤掉这些无关文件,强制降低上下文体积,大幅提升构建效率。配置解耦与日志管理
# ==============================================================================
# 环境变量与日志管理 (配置解耦与运维进阶)
# ==============================================================================
# 场景引入:
# 在复杂的项目中(如包含多个微服务的系统),如果把所有的本地硬盘路径、时区、密码等信息
# 全部写死在 docker-compose.yml 文件里,会导致项目极难在其他机器上复用。别人拿到项目后,
# 必须逐行去改 YAML 文件里的路径,极易改错。
# 为了解决这个问题,Docker 引入了 .env 环境变量机制,实现“代码与配置的彻底分离”。
# --- 1. .env 文件的基本概念 ---
# 这是一个放置在 docker-compose.yml 同级目录下的隐藏纯文本文件。
# 它被用来定义项目全局的动态参数,里面只存放简单的键值对,例如:
# HC_TZ=Asia/Shanghai
# HC_DATA_ROOT=/media/data/homecenter
# --- 2. Compose 文件中的变量插值 (Variable Substitution) ---
# 当执行 docker compose up -d 时,Docker 会自动读取上述的 .env 文件,
# 并将其中的值动态替换到 docker-compose.yml 中带有 ${} 的占位符里。
# 示例:
volumes:
# 语法结构:${变量名:-默认值}
# 解析:尝试从 .env 中读取 HC_DATA_ROOT 的值。
# 如果 .env 存在该变量,则替换为对应的值;
# 如果未定义,则触发容错机制,使用 :- 后面的默认路径。
# 核心优势:别人部署项目时,只需要修改那个小小的 .env 文件适配自己的硬盘路径,完全不需要改动核心的 Compose 逻辑。
- ${HC_DATA_ROOT:-/media/default/path}/gateway/logs:/var/log/nginx
environment:
# 同理,动态设置容器内部的时区。
- TZ=${HC_TZ:-Asia/Shanghai}
# --- 3. 区分 env_file 与 environment ---
# 上面的插值是用来修改 Compose 文件自身的。但容器内部运行的程序(如 Python、Go)也需要读取环境变量。
# Docker 提供了两种将变量注入容器内部的方法:
env_file:
# 批量注入:将指定文件(如 ./backend-core/.env)内的所有键值对,
# 作为一个整体全部注入到容器的操作系统环境中。极其适合变量极多(如包含大量数据库账号密码)的场景。
- ./backend-core/.env
environment:
# 显式注入:直接在 YAML 中定义并传入容器。
- DOCKER_SOCKET_PATH=/var/run/docker.sock
# 宿主机穿透注入:如果只写变量名(如 NODE_ENV),Docker 会自动捕获宿主机的同名环境变量并穿透传入容器。
- NODE_ENV
# ==============================================================================
# 容器日志轮转配置 (Log Rotation)
# ==============================================================================
# 场景引入:
# 容器的标准输出日志默认会无限制地追加保存在宿主机的 /var/lib/docker/containers/ 下。
# 对于高频输出的服务(如网关、推流服务),如果不限制日志大小,几天内就会将宿主机的系统磁盘彻底撑爆。
logging:
driver: "json-file"
# 指定底层日志驱动为标准的 json-file。
options:
max-size: "10m"
# 容量阈值:当单份日志文件达到 10MB 时,自动触发日志切割,将旧文件归档(如 log.1),并创建新文件。
max-file: "5"
# 数量阈值:在文件系统中最多保留 5 份历史归档日志。
# 效果:该服务产生的总日志占用空间被严格限制在 50MB 封顶(10MB * 5),旧日志会被循环覆盖,彻底杜绝磁盘溢出风险。数据迁移
# ==============================================================================
# 数据备份、恢复与无缝迁移指南
# ==============================================================================
# --- 1. 数据卷物理备份 (Volume Backup) ---
# 逻辑:数据卷由 Docker 引擎托管,直接拷贝底层物理目录容易导致权限错乱或数据损坏。
# 标准做法是启动一个临时容器,将目标数据卷和宿主机的备份目录同时挂载,在容器内执行归档打包。
docker run --rm -v my_database_data:/volume_data -v $(pwd):/backup alpine tar -cvf /backup/db_data_backup.tar /volume_data
# --rm: 临时容器在执行完打包命令后立即自动销毁。
# -v my_database_data:/volume_data: 将需要备份的命名数据卷挂载到临时容器的 /volume_data 目录。
# -v $(pwd):/backup: 将宿主机当前目录挂载到临时容器的 /backup 目录。
# alpine: 使用体积极小的 alpine 镜像执行任务。
# tar -cvf ...: 在临时容器内部执行 tar 命令,将 /volume_data 目录打包为 db_data_backup.tar 并存放在 /backup 目录(即宿主机当前目录)。
# --- 2. 数据卷物理恢复 (Volume Restore) ---
# 逻辑:在目标服务器上创建一个新的空数据卷,然后通过临时容器将归档文件解压到该数据卷中。
docker volume create my_new_database_data
# 首先在目标机器上创建一个新的命名数据卷。
docker run --rm -v my_new_database_data:/volume_data -v $(pwd):/backup alpine tar -xvf /backup/db_data_backup.tar -C /
# 将包含备份文件的宿主机目录和新创建的数据卷挂载到临时容器。
# tar -xvf ... -C /: 在容器内部将 tar 包解压。注意使用 -C / 确保解压路径与备份时的绝对路径结构一致,从而准确还原到 /volume_data 中。
# --- 3. 运行态容器归档 (Container Commit) ---
# 逻辑:在排错或紧急热修复场景下,如果直接进入容器内部修改了配置或安装了工具,这些更改并未记录在原镜像中。
# 使用 commit 可以将当前容器的读写层与底层只读镜像固化为一个全新的本地镜像。
docker commit -m "Added debugging tools" -a "Master" <container_name_or_id> my_custom_backend:v1.1
# -m: 添加提交说明。
# -a: 指定作者信息。
# my_custom_backend:v1.1: 为生成的新镜像指定名称和标签。
# 注意:这不属于常规发布流程。常规发布必须通过修改 Dockerfile 并重新 build 来实现,commit 生成的镜像属于黑盒,无法追溯构建过程。
# --- 4. 离线镜像导出与导入 (Image Save & Load) ---
# 逻辑:用于在无外网环境或物理隔离网络下,实现镜像的无损跨机器迁移。
docker save -o /path/to/my_image_bundle.tar my_backend:v1.0 nginx:latest
# 导出单个或多个镜像为 tar 归档文件。
# -o: 指定输出的文件路径与名称。
# 可以在同一条命令中追加多个镜像名称,Docker 会将它们打包进同一个归档文件中,共享底层相同的镜像层以节省空间。
docker load -i /path/to/my_image_bundle.tar
# -i: 指定输入的归档文件路径。
# Docker 引擎会解析 tar 包并还原镜像及其标签。导入完成后,可以使用 docker images 查看,并通过原本的标签直接启动。
# --- 5. 跨服务器直接迁移管道 (SSH Pipe) ---
# 逻辑:如果不希望在本地生成庞大的 tar 文件占用磁盘空间,可以直接通过 SSH 管道将导出的数据流直接传输并导入到目标服务器的 Docker 引擎中。
docker save my_backend:v1.0 | ssh user@remote_host 'docker load'
# 标准输出传递:docker save 将镜像数据流输出到标准输出。
# SSH 管道:通过 SSH 连接到远程服务器,并在远程端执行 docker load 命令接收标准输入的数据流。空间清理
如果发现系统中 /var/lib/containerd 目录占用过大,这可能是 Docker 容器中产生了大量的虚空镜像和废弃的构建缓存等历史垃圾。
用以下这条命令,可以直观查看占用的空间信息:
docker system df
接着,使用这条命令进行全面空间回收:
docker system prune -a --volumes这条命令会清理所有停止运行的容器中使用的网络,以及各种未使用的镜像和构建缓存。

更多 system 指令
