diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index eb977b4..94fd9eb 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -11,12 +11,9 @@ "forwardPorts": [ 4000 ], - "runArgs": [ - "--cap-add=SYS_ADMIN" - ], "postStartCommand": [ "sh", "-cx", - "pwd ; cd /workspaces/docker_practice ; mkdir -p ${PWD}/node_modules; mkdir -p ${PWD}/_book; mount --bind /srv/gitbook/node_modules ${PWD}/node_modules ; mount --bind /mnt ${PWD}/_book" + "pwd ; cd /workspaces/docker_practice ; mkdir -p ${PWD}/node_modules ${PWD}/_book" ] } diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml index d696a20..922eb91 100644 --- a/.github/workflows/auto-release.yml +++ b/.github/workflows/auto-release.yml @@ -15,6 +15,12 @@ jobs: steps: - uses: actions/checkout@v6 + - name: Check project rules + run: python3 check_project_rules.py + + - name: Check release metadata + run: npm test + - name: Install Chromium and CJK fonts uses: browser-actions/setup-chrome@v2 with: diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c9418b0..2290b49 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,6 +18,8 @@ jobs: - uses: actions/checkout@v6 - name: Check project rules run: python3 check_project_rules.py + - name: Check release metadata + run: npm test - name: Install Chromium and CJK fonts uses: browser-actions/setup-chrome@v2 with: diff --git a/.github/workflows/preview-pdf.yml b/.github/workflows/preview-pdf.yml index c30cbf2..fb72d8e 100644 --- a/.github/workflows/preview-pdf.yml +++ b/.github/workflows/preview-pdf.yml @@ -22,6 +22,12 @@ jobs: steps: - uses: actions/checkout@v6 + - name: Check project rules + run: python3 check_project_rules.py + + - name: Check release metadata + run: npm test + - name: Install Chromium and CJK fonts uses: browser-actions/setup-chrome@v2 with: diff --git a/.gitignore b/.gitignore index 1a24a15..ab75c67 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ package-lock.json docker-compose.override.yml 06_repository/demo/auth/nginx.htpasswd +11_compose/demo/wordpress/secrets/ # Editor configs .obsidian/ diff --git a/01_introduction/1.1_quickstart.md b/01_introduction/1.1_quickstart.md index e65183f..b53ef61 100644 --- a/01_introduction/1.1_quickstart.md +++ b/01_introduction/1.1_quickstart.md @@ -2,11 +2,13 @@ > **版本说明**:本节示例基于 Docker v29.x 编写。示例中使用的 `nginx:alpine` 镜像标签为演示用途,请查阅 [Docker Hub - nginx](https://hub.docker.com/_/nginx) 确认最新可用版本。 +开始前请先完成 [第 3 章安装 Docker](../03_install/README.md),并确认 `docker version` 与 `docker run hello-world` 可以正常执行。若你只是先浏览流程,可以读完本节后再回到安装章实践。 + 本节将通过一个简单的 Web 应用例子,带你快速体验 Docker 的核心流程:构建镜像、运行容器。 ### 为什么选择 Nginx + HTML 作为入门例子? -在学习 Docker 之前,我们先来理解为什么这个例子是最适合初学者的。Docker 的核心价值在于**一致性交付**——无论你在本地、云端还是他人的机器上运行容器,应用的行为都是完全一致的。这个 Nginx + 静态 HTML 的例子之所以被广泛采用,是因为它展现了 Docker 工作流的三个核心阶段: +在学习 Docker 之前,我们先来理解为什么这个例子适合初学者。Docker 的核心价值在于**一致性交付**:在相同镜像、CPU 架构、内核能力、配置和外部依赖都满足的前提下,应用行为可以保持高度一致。这个 Nginx + 静态 HTML 的例子之所以被广泛采用,是因为它展现了 Docker 工作流的三个核心阶段: 1. **镜像定义(Image Layer)**:通过 Dockerfile 描述如何把应用打包成一个自包含的单元 2. **镜像构建(Build)**:执行 `docker build`,Docker 根据 Dockerfile 逐层构建镜像 diff --git a/01_introduction/1.2_what.md b/01_introduction/1.2_what.md index 3998dd8..038faa6 100644 --- a/01_introduction/1.2_what.md +++ b/01_introduction/1.2_what.md @@ -4,11 +4,11 @@ Docker 是彻底改变了软件开发和交付方式的革命性技术。本节 ### 1.2.1 一句话理解 Docker -> **Docker 是一种轻量级的虚拟化技术,它让应用程序及其依赖环境可以被打包成一个标准化的单元,在任何地方都能一致地运行。** 如果用一个生活中的类比:**Docker 之于软件,就像集装箱之于货物**。 +> **Docker 是一种轻量级的虚拟化技术,它让应用程序及其依赖环境可以被打包成一个标准化的单元,在满足架构、内核能力和外部依赖前提的环境中高度一致地运行。** 如果用一个生活中的类比:**Docker 之于软件,就像集装箱之于货物**。 在集装箱发明之前,货物的运输是一件麻烦的事情——不同的货物需要不同的包装、不同的装卸方式,换一种运输工具就要重新装卸。集装箱的出现改变了这一切:无论里面装的是什么,集装箱的外形是标准的,可以用同样的方式装卸、堆放和运输。 -Docker 做的事情类似:无论你的应用是用 Python、Java、Node.js 还是其他语言写的,无论它需要什么样的依赖库和环境,一旦被打包成 Docker 镜像,就可以用同样的方式在任何支持 Docker 的机器上运行。 +Docker 做的事情类似:无论你的应用是用 Python、Java、Node.js 还是其他语言写的,无论它需要什么样的依赖库和环境,一旦被打包成 Docker 镜像,就可以用同样的方式在兼容的 Docker 环境中运行。 ### 1.2.2 Docker 的核心价值 diff --git a/01_introduction/1.3_why.md b/01_introduction/1.3_why.md index d28bd18..d8449bd 100644 --- a/01_introduction/1.3_why.md +++ b/01_introduction/1.3_why.md @@ -63,10 +63,10 @@ flowchart LR #### 1. 环境一致性 -Docker 镜像包含了应用运行所需的 **一切**:代码、运行时、系统工具、库、配置。这意味着: +Docker 镜像包含了应用运行所需的大部分用户态依赖:代码、运行时、系统工具、库和默认配置。它不包含宿主机内核,也不能消除 CPU 架构、内核能力、外部服务、网络、卷和运行时配置差异。这意味着: -- ✅ 开发环境和生产环境完全一致 -- ✅ 不会再有 “在我机器上能跑” 的问题 +- ✅ 开发环境和生产环境可以显著减少差异 +- ✅ 大幅降低 “在我机器上能跑” 的问题 - ✅ 新人入职,一条命令就能启动开发环境 ```bash diff --git a/03_install/3.3_fedora.md b/03_install/3.3_fedora.md index b109840..262e7ae 100644 --- a/03_install/3.3_fedora.md +++ b/03_install/3.3_fedora.md @@ -50,9 +50,7 @@ $ sudo dnf -y install dnf-plugins-core 执行下面的命令添加 `dnf` 软件源: ```bash -$ sudo dnf config-manager \ - --add-repo \ - https://download.docker.com/linux/fedora/docker-ce.repo +$ sudo dnf config-manager addrepo --from-repofile https://download.docker.com/linux/fedora/docker-ce.repo ``` 如果需要测试版本的 Docker 请使用以下命令: diff --git a/03_install/3.9_mirror.md b/03_install/3.9_mirror.md index 96cdcac..b569009 100644 --- a/03_install/3.9_mirror.md +++ b/03_install/3.9_mirror.md @@ -80,7 +80,7 @@ Registry Mirrors: ### 3.9.6 Kubernetes 官方镜像地址迁移 -可以登录 [阿里云容器镜像服务](https://www.aliyun.com/product/acr?source=5176.11533457&userCode=8lx5zmtu&type=copy),在 **镜像中心** -> **镜像搜索** 中查找。 +可以登录 [阿里云容器镜像服务](https://www.aliyun.com/product/acr),在 **镜像中心** -> **镜像搜索** 中查找。 Kubernetes 社区已将官方镜像地址从 `k8s.gcr.io` 迁移到 `registry.k8s.io`。建议优先使用新地址。 @@ -108,4 +108,4 @@ $ docker pull registry.k8s.io/xxx 某些云服务商提供了 **仅供内部** 访问的镜像服务,当您的 Docker 运行在云平台时可以选择它们。 -* [腾讯云 `https://mirror.ccs.tencentyun.com`](https://cloud.tencent.com/act/cps/redirect?redirect=10058&cps_key=3a5255852d5db99dcd5da4c72f05df61) +* [腾讯云 `https://mirror.ccs.tencentyun.com`](https://cloud.tencent.com/product/tke) diff --git a/03_install/README.md b/03_install/README.md index f1ccdff..8de4693 100644 --- a/03_install/README.md +++ b/03_install/README.md @@ -18,7 +18,7 @@ Docker Engine 主要提供 `stable` 和 `test` 两个更新频道;`test.docker **开发环境**(本地开发机、测试服务器): -- 使用**脚本自动安装**或**包管理器直接安装** +- 配置 **Docker 官方源后** 使用包管理器安装,或在一次性测试环境使用官方脚本自动安装 - 如果你想快速上手,官方脚本(`get.docker.com`)是最便捷的选择 - 国内用户注意:这一步一定要选对镜像源,否则网络卡顿会严重影响体验 diff --git a/04_image/demo/buildkit/Dockerfile.buildkit b/04_image/demo/buildkit/Dockerfile.buildkit index 9bbe399..855640a 100644 --- a/04_image/demo/buildkit/Dockerfile.buildkit +++ b/04_image/demo/buildkit/Dockerfile.buildkit @@ -1,4 +1,4 @@ -# syntax = docker/dockerfile:experimental +# syntax=docker/dockerfile:1 FROM node:alpine as builder @@ -6,24 +6,16 @@ WORKDIR /app COPY package.json /app/ -RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=locked \ - --mount=type=cache,target=/root/.npm,id=npm_cache \ - npm i --registry=https://registry.npmmirror.com +RUN --mount=type=cache,target=/root/.npm,id=npm_cache \ + npm install --registry=https://registry.npmmirror.com COPY src /app/src -RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=locked \ -# --mount=type=cache,target=/app/dist,id=my_app_dist,sharing=locked \ - npm run build +RUN npm run build FROM nginx:alpine -# COPY --from=builder /app/dist /app/dist - -# 为了更直观的说明 from 和 source 指令,这里使用 RUN 指令 -RUN --mount=type=cache,target=/tmp/dist,from=builder,source=/app/dist \ - # --mount=type=cache,target/tmp/dist,from=my_app_dist,sharing=locked \ - mkdir -p /app/dist && cp -r /tmp/dist/* /app/dist +COPY --from=builder /app/dist /app/dist RUN --mount=type=bind,from=php:alpine,source=/usr/local/bin/docker-php-entrypoint,target=/docker-php-entrypoint \ cat /docker-php-entrypoint @@ -32,6 +24,6 @@ RUN --mount=type=tmpfs,target=/temp \ mount | grep /temp RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \ - cat /root/.aws/credentials + test -s /root/.aws/credentials && echo "credentials mounted" # docker build -t test --secret id=aws,src=$PWD/aws.txt --progress=plain -f Dockerfile.buildkit . diff --git a/06_repository/6.2_registry.md b/06_repository/6.2_registry.md index 2ae5459..dccf96e 100644 --- a/06_repository/6.2_registry.md +++ b/06_repository/6.2_registry.md @@ -4,7 +4,7 @@ 本节介绍如何使用本地仓库。 -[Docker Registry](https://docs.docker.com/registry/) 是官方提供的工具,可以用于构建私有的镜像仓库。本文内容基于 [distribution/distribution](https://github.com/distribution/distribution) v2.x 版本。 +[Docker Registry](https://docs.docker.com/registry/) 是官方提供的工具,可以用于构建私有的镜像仓库。本文示例沿用 [distribution/distribution](https://github.com/distribution/distribution) v2.x 兼容路径;新生产部署应评估 Distribution 3.x,并核对配置路径、迁移说明和生态兼容性。 ### 6.2.1 安装运行 docker-registry @@ -18,7 +18,7 @@ $ docker run -d -p 5000:5000 --restart=always --name registry registry:2 ``` -> **版本说明**:使用 `registry:2` 表示 Docker Registry 2.x 版本,这是当前推荐的版本。旧版本 Registry 1.x 已停止维护,不建议使用。 +> **版本说明**:使用 `registry:2` 表示 Docker Registry 2.x 兼容示例。Distribution 3.x 已发布稳定版本;不要直接把本章 v2 配置原样套到 v3 生产环境,升级前应阅读迁移说明并做兼容测试。旧版本 Registry 1.x 已停止维护,不建议使用。 这将使用官方的 `registry` 镜像来启动私有仓库。默认情况下,仓库会被创建在容器的 `/var/lib/registry` 目录下。你可以通过 `-v` 参数来将镜像文件存放在本地的指定路径。例如下面的例子将上传的镜像放到本地的 `/opt/data/registry` 目录。 ```bash diff --git a/06_repository/6.3_registry_auth.md b/06_repository/6.3_registry_auth.md index 43eeb77..c431af7 100644 --- a/06_repository/6.3_registry_auth.md +++ b/06_repository/6.3_registry_auth.md @@ -116,7 +116,7 @@ health: storagedriver: enabled: true interval: 10s -threshold: 3 + threshold: 3 ``` ### 6.3.3 生成 http 认证文件 @@ -156,7 +156,7 @@ volumes: 本书配套的 `06_repository/demo/` 也采用同样约定:容器内 registry 监听 `:5000`,宿主机通过 `443:5000` 暴露 HTTPS 服务。这样可以避免在容器内占用特权端口,同时仍让客户端使用 `https://docker.domain.com` 访问。 -> **版本说明**:Compose 配置中明确指定 `registry:2` 版本。生产环境建议固定版本号(如 `registry:2.8.3`)而非使用 `latest`,以保证部署的可重复性。 +> **版本说明**:Compose 配置中明确指定 `registry:2` 版本。生产环境建议固定具体补丁版本(如 `registry:2.8.x`),并在新部署时评估 Distribution 3.x;不要使用 `latest`,以保证部署的可重复性。 ### 6.3.5 修改 Hosts 文件 diff --git a/06_repository/README.md b/06_repository/README.md index 6370a88..3c253dd 100644 --- a/06_repository/README.md +++ b/06_repository/README.md @@ -10,7 +10,7 @@ 本章涉及的 Registry 和相关工具版本说明: -- **Docker Registry**:使用 `registry:2` 推荐版本,已停止维护的 `registry:1` 不建议使用 +- **Docker Registry / CNCF Distribution**:本章示例使用 `registry:2` 兼容路径;新生产部署应评估 Distribution 3.x,并核对配置路径、迁移说明和生态兼容性。已停止维护的 `registry:1` 不建议使用 - **Nexus 3**:建议指定具体版本(如 `sonatype/nexus3:3.69`)而非 `latest`,避免自动升级带来的兼容性问题 - **镜像标签规范**: - 生产环境推送至仓库时应明确指定版本号(如 `myapp:v1.0.0`) diff --git a/07_dockerfile/7.14_label.md b/07_dockerfile/7.14_label.md index c7a7303..8f07301 100644 --- a/07_dockerfile/7.14_label.md +++ b/07_dockerfile/7.14_label.md @@ -59,7 +59,7 @@ LABEL maintainer="user@example.com" \ ```docker LABEL org.opencontainers.image.authors="yeasy" \ - org.opencontainers.image.documentation="https://yeasy.gitbooks.io" \ + org.opencontainers.image.documentation="https://yeasy.gitbook.io/docker_practice/" \ org.opencontainers.image.source="https://github.com/yeasy/docker_practice" \ org.opencontainers.image.licenses="MIT" ``` diff --git a/07_dockerfile/7.16_references.md b/07_dockerfile/7.16_references.md index 821f18f..41395cd 100644 --- a/07_dockerfile/7.16_references.md +++ b/07_dockerfile/7.16_references.md @@ -2,9 +2,9 @@ ### 官方文档 -* `Dockerfile` 官方参考手册:https://docs.docker.com/engine/reference/builder/ +* `Dockerfile` 官方参考手册:https://docs.docker.com/reference/dockerfile/ -* `Dockerfile` 最佳实践指南:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ +* `Dockerfile` 最佳实践指南:https://docs.docker.com/build/building/best-practices/ * `Docker` 官方镜像 `Dockerfile` 库:https://github.com/docker-library/docs diff --git a/07_dockerfile/7.3_add.md b/07_dockerfile/7.3_add.md index d7f41d7..f0d5e56 100644 --- a/07_dockerfile/7.3_add.md +++ b/07_dockerfile/7.3_add.md @@ -4,12 +4,12 @@ 在开始前,让我们直言不讳:**在大多数情况下,你应该使用 COPY,而不是 ADD**。 -`ADD` 在 `COPY` 基础上增加了两个额外功能,但这些功能往往引入复杂性而非便利: +`ADD` 在 `COPY` 基础上增加了两个额外功能。它不是 `COPY` 的通用替代品,但在少数场景中更合适: 1. 自动解压 tar 压缩包(有时你想复制一个 .tar.gz 本身,而 ADD 会意外地解压它) -2. 支持从 URL 下载文件(这个功能由于网络不稳定已被广泛认为是反模式) +2. 支持从 URL 下载公开远程文件,并可配合 `--checksum` 做校验 -**实践中的建议**:除非你明确需要自动解压功能(比如官方基础镜像构建根文件系统),否则始终使用 COPY。原因很简单——显式优于隐式。你的 Dockerfile 在 6 个月后被接手维护时,清晰的意图会让团队少走很多弯路。 +**实践中的建议**:本地普通文件默认用 COPY;本地 tar 自动解压或公开远程 artifact 下载并校验时用 ADD;需要认证、请求头、重试或自定义解压流程时用 `RUN curl/wget`。 ### 7.3.1 基本语法 @@ -20,7 +20,7 @@ ADD [选项] ["<源路径>", ... "<目标路径>"] `ADD` 在 `COPY` 基础上增加了两个功能: 1. 自动解压 tar 压缩包 -2. 支持从 URL 下载文件 (不推荐) +2. 支持从 URL 下载文件 --- @@ -30,11 +30,11 @@ ADD [选项] ["<源路径>", ... "<目标路径>"] |------|------|-----| | 复制本地文件 | ✅ | ✅ | | 自动解压 tar | ❌ | ✅ | -| 支持 URL | ❌ | ✅ (不推荐)| +| 支持 URL | ❌ | ✅ (公开 artifact 可配合校验使用)| | 行为可预测性 | ✅ 高 | ⚠️ 低 | -| 推荐程度 | ✅ **优先使用** | 仅解压场景 | +| 推荐程度 | ✅ **普通复制优先使用** | 解压、本地 Git/公开远程 artifact | -> **笔者建议**:除非需要自动解压 tar 文件,否则始终使用 COPY。明确的行为比隐式的魔法更好。 +> **笔者建议**:普通复制始终优先 COPY;只有当你明确需要 ADD 的额外语义时再使用 ADD,并把意图写清楚。 --- @@ -79,7 +79,7 @@ app.tar.gz 包含: /app/ 目录结果: ``` --- -### 7.3.4 URL 下载功能:不推荐 +### 7.3.4 URL 下载功能:谨慎使用 #### 基本用法 @@ -89,32 +89,29 @@ app.tar.gz 包含: /app/ 目录结果: ADD https://example.com/app.zip /app/app.zip ``` -#### 为什么不推荐 +#### 使用边界 -| 问题 | 说明 | +| 场景 | 建议 | |------|------| -| 权限固定 | 下载的文件权限为 600,通常需要额外 RUN 修改 | -| 不会解压 | URL 下载的压缩包不会自动解压 | -| 缓存问题 | URL 内容变化时不会重新下载 | -| 层数增加 | 需要额外 RUN 清理 | +| 公开、版本固定的远程 artifact | 使用 `ADD --checksum=sha256:... URL dest` | +| 需要认证、请求头或复杂重试 | 使用 `RUN curl/wget` | +| 下载后需要复杂解压、校验或清理 | 使用 `RUN curl/wget`,把流程显式写出 | +| URL 内容可变但无校验 | 不建议直接写入 Dockerfile | -#### 推荐替代方案 +#### 推荐写法 ```docker -## ❌ 不推荐:使用 ADD 下载 +## ✅ 公开 artifact:使用 ADD 并固定校验值 -ADD https://example.com/app.tar.gz /tmp/ +ADD --checksum=sha256: https://example.com/app.tar.gz /tmp/app.tar.gz RUN tar -xzf /tmp/app.tar.gz -C /app && rm /tmp/app.tar.gz -## ✅ 推荐:使用 RUN + curl +## ✅ 需要认证、请求头或特殊处理:使用 RUN + curl RUN curl -fsSL https://example.com/app.tar.gz | tar -xz -C /app ``` -优势: +`ADD --checksum` 的优势是缓存更精确,并且校验值直接绑定到 Dockerfile。`RUN curl/wget` 的优势是控制力更强,适合企业内网、认证下载或复杂处理。 -- 一条 RUN 完成下载、解压、清理 -- 减少镜像层数 -- 更清晰的构建意图 --- @@ -139,6 +136,10 @@ ADD rootfs.tar.gz / ## 解压应用包 ADD dist.tar.gz /app/ + +## 下载公开 artifact 并校验 + +ADD --checksum=sha256: https://example.com/app.tar.gz /tmp/app.tar.gz ``` #### ❌ 不适合使用 ADD @@ -149,9 +150,9 @@ ADD dist.tar.gz /app/ ADD package.json /app/ # ❌ COPY package.json /app/ # ✅ -## 下载文件(用 RUN + curl) +## 需要认证或复杂下载逻辑(用 RUN + curl/wget) -ADD https://example.com/file / # ❌ +ADD https://example.com/file / # ❌ 无法传认证信息,也没有显式处理 RUN curl -fsSL ... -o /file # ✅ ## 需要保留 tar 不解压(用 COPY) @@ -203,14 +204,14 @@ COPY . /app/ ADD app.tar.gz /app/ ``` -#### 3. 不要用 ADD 下载文件 +#### 3. 远程 artifact 使用 ADD 时必须固定校验值 ```docker -## ❌ 避免 +## ✅ 公开 artifact -ADD https://example.com/file.tar.gz /tmp/ +ADD --checksum=sha256: https://example.com/file.tar.gz /tmp/file.tar.gz -## ✅ 推荐 +## ✅ 认证下载或复杂处理 RUN curl -fsSL https://example.com/file.tar.gz | tar -xz -C /app ``` diff --git a/07_dockerfile/7.4_cmd.md b/07_dockerfile/7.4_cmd.md index 9c0a69c..cfd5081 100644 --- a/07_dockerfile/7.4_cmd.md +++ b/07_dockerfile/7.4_cmd.md @@ -65,7 +65,7 @@ CMD echo $HOME CMD ["sh", "-c", "echo $HOME"] ``` -**优点**:可以使用环境变量、管道等 shell 特性 +**优点**:可以使用 `$HOME` 这类 shell 变量展开、管道等 shell 特性 **缺点**:主进程是 sh,信号无法正确传递给应用 @@ -77,7 +77,7 @@ CMD ["sh", "-c", "echo $HOME"] |------|----------|-----------| | 主进程 | 指定的程序 | `/bin/sh` | | 信号传递 | ✅ 正确 | ❌ 无法传递 | -| 环境变量 | ❌ 需要 shell 包装 | ✅ 自动解析 | +| `$VAR` shell 展开 | ❌ 不自动展开;环境变量仍会传入进程 | ✅ 自动展开 | | 推荐使用 | ✅ 大多数场景 | 需要 shell 特性时 | #### 信号传递问题示例 diff --git a/07_dockerfile/7.6_env.md b/07_dockerfile/7.6_env.md index 4e3d1b7..f6eafb4 100644 --- a/07_dockerfile/7.6_env.md +++ b/07_dockerfile/7.6_env.md @@ -212,7 +212,7 @@ ENV HOST=localhost \ #### Q:环境变量在 CMD 中不展开 -exec 格式不会自动展开环境变量: +exec 格式不会自动执行 shell 展开,因此命令参数里的 `$PORT` 会按字面值传给进程;但环境变量本身仍会注入进程环境,应用可以通过语言运行时读取。 ```docker ## ❌ 不会展开 $PORT diff --git a/07_dockerfile/7.8_volume.md b/07_dockerfile/7.8_volume.md index 0c96c5f..033ebd2 100644 --- a/07_dockerfile/7.8_volume.md +++ b/07_dockerfile/7.8_volume.md @@ -88,17 +88,17 @@ $ docker run -v /my/data:/var/lib/mysql mysql:8.4 ### 7.8.5 VOLUME 在构建时的特殊行为 -> ⚠️ **重要**:VOLUME 之后对该目录的修改会被丢弃! +> ⚠️ **重要**:`VOLUME` 之后再写入该目录的构建语义取决于 builder。legacy builder 会丢弃这些修改;BuildKit 会保留。但运行容器时,一旦该路径挂载了卷,卷会遮蔽镜像内同路径的内容。 ```docker FROM ubuntu VOLUME /data -## ❌ 这个文件不会出现在镜像中! +## ⚠️ legacy builder 会丢弃;BuildKit 会保留,但运行时挂载卷会遮蔽它 RUN echo "hello" > /data/test.txt ``` -**原因**:在构建过程中,VOLUME 指令会为该目录创建一个临时的匿名卷。后续 RUN 指令对该目录的写入实际发生在这个临时卷中,而非镜像层。当该 RUN 指令结束后,临时卷被丢弃,因此写入的内容不会保存到最终镜像中。注意:这与容器运行时创建的匿名卷是不同的——运行时创建的卷会在容器生命周期内持续存在。 +**原因**:旧 builder 会在构建过程中为该目录创建临时匿名卷,后续写入发生在临时卷中;BuildKit 则会把修改保留在镜像层。为了避免不同 builder 下出现不同结果,也为了避免运行时卷遮蔽镜像内初始化数据,不要把必须存在的初始化文件写在 `VOLUME` 之后。 #### 正确做法 diff --git a/07_dockerfile/summary.md b/07_dockerfile/summary.md index a224d77..3e652ad 100644 --- a/07_dockerfile/summary.md +++ b/07_dockerfile/summary.md @@ -7,12 +7,12 @@ | **FROM** | 指定基础镜像 | 必须是第一条指令 | | **RUN** | 在新层执行命令 | 合并命令、清理缓存以减小体积 | | **COPY** | 复制文件 | 优先使用,支持 `--from` | -| **ADD** | 更高级的复制 | 自动解压 tar,不推荐用于下载 | +| **ADD** | 更高级的复制 | 自动解压 tar;公开远程 artifact 应配合 `--checksum` | | **CMD** | 容器启动默认命令 | 可被 `docker run` 参数覆盖 | | **ENTRYPOINT** | 容器入口点 | 固定启动命令,CMD 作为默认参数 | | **ENV** | 设置环境变量 | 构建时 + 运行时均生效 | | **ARG** | 构建参数 | 仅构建时生效,FROM 后需重新声明 | -| **VOLUME** | 定义匿名卷 | VOLUME 之后的修改会丢失 | +| **VOLUME** | 定义匿名卷 | 运行时挂载会遮蔽镜像内目录;构建后续写入语义依赖 builder | | **EXPOSE** | 声明端口 | 仅文档作用,不自动映射 | | **WORKDIR** | 指定工作目录 | 替代 `RUN cd`,目录不存在会自动创建 | | **USER** | 指定运行用户 | 用户必须已存在,推荐 gosu | diff --git a/08_data/8.2_bind-mounts.md b/08_data/8.2_bind-mounts.md index c0e38c7..741d573 100644 --- a/08_data/8.2_bind-mounts.md +++ b/08_data/8.2_bind-mounts.md @@ -122,6 +122,8 @@ $ docker run -d \ #### 场景四:共享 SSH 密钥 +只读挂载可以防止容器修改主机密钥,但不能防止容器读取并外传密钥。只有在镜像完全可信、密钥作用域很窄且可随时轮换时,才考虑这种做法。更稳妥的方式是使用 SSH agent socket 转发、一次性 deploy key,或在 CI/构建场景中使用 BuildKit `--ssh`。 + ```bash ## 挂载 SSH 密钥(只读) diff --git a/09_network/9.2_network_types.md b/09_network/9.2_network_types.md index 0b9f48f..29739fa 100644 --- a/09_network/9.2_network_types.md +++ b/09_network/9.2_network_types.md @@ -20,7 +20,7 @@ ghi789... none null local | **host** | 容器直接使用宿主机网络栈 | 需要最高网络性能时 | | **none** | 禁用网络 | 完全隔离的容器 | | **overlay** | 跨主机网络 | Docker Swarm 集群 | -| **macvlan** | 容器拥有独立 MAC 地址 | 需要直接接入物理网络 | +| **macvlan** | 容器拥有独立 MAC 地址 | Linux 主机上需要直接接入物理网络 | | **ipvlan** | 容器共享父接口 MAC,独享 IP | 同网段大量容器、对 MAC 数量受限的网络 | ### 9.2.2 Bridge 网络:默认 @@ -45,6 +45,8 @@ $ docker run -d --network host nginx ``` 这种模式下网络性能最高,但容器之间和宿主机之间没有网络隔离。 +> 注意:host 网络优先用于明确需要高性能或大量端口的 Linux 主机场景。Docker Desktop 仅在较新版本中支持,且需要在设置中启用;使用 host 网络时 `-p` / `--publish` 端口映射不会生效。普通 Web 服务默认仍建议使用 bridge 网络并显式发布端口。 + ### 9.2.4 None 网络 使用 `--network none` 参数启动的容器只有 `lo` 回环网卡,完全没有外部网络连接。适用于只需要运行计算任务、不需要网络的容器。 @@ -55,7 +57,11 @@ $ docker run -it --network none alpine ip addr inet 127.0.0.1/8 scope host lo ``` -### 9.2.5 数据流向 +### 9.2.5 Macvlan 与平台限制 + +Macvlan 适合少数需要让容器像物理主机一样直接出现在二层网络中的场景。它只支持 Linux 主机,不支持 Docker Desktop for Mac / Windows,也不支持 rootless 模式;多数云厂商网络会阻断或限制 macvlan。默认情况下,macvlan 容器与宿主机直接通信也需要额外路由或接口配置。 + +### 9.2.6 数据流向 容器网络中的数据流向可以分为以下几种情况: diff --git a/09_network/9.5_port_mapping.md b/09_network/9.5_port_mapping.md index c85b22d..29c39c7 100644 --- a/09_network/9.5_port_mapping.md +++ b/09_network/9.5_port_mapping.md @@ -39,10 +39,10 @@ $ docker run -d -p 8080:80 nginx | 格式 | 含义 | 示例 | |------|------|------| -| `ip:hostPort:containerPort` | 绑定指定 IP 的特定端口 | `-p 127.0.0.1:8080:80` (仅本机访问) | +| `ip:hostPort:containerPort` | 绑定指定 IP 的特定端口 | `-p 127.0.0.1:8080:80` (仅 IPv4 本机访问) | | `ip::containerPort` | 绑定指定 IP 的随机端口 | `-p 127.0.0.1::80` | -| `hostPort:containerPort` | 绑定所有 IP (0.0.0.0) 的特定端口 | `-p 8080:80` (默认) | -| `containerPort` | 绑定所有 IP 的随机端口 | `-p 80` | +| `hostPort:containerPort` | 绑定所有地址(通常包括 `0.0.0.0` 和 `[::]`)的特定端口 | `-p 8080:80` (默认) | +| `containerPort` | 绑定所有地址的随机端口 | `-p 80` | #### 2. 随机映射 @@ -93,14 +93,15 @@ abc123456 nginx 0.0.0.0:8080->80/tcp web #### 1. 限制监听 IP -默认情况下,`-p 8080:80` 会监听 `0.0.0.0:8080`,这意味着任何人只要能连接你的宿主机 IP,就能访问该服务。 +默认情况下,`-p 8080:80` 会监听所有可用地址,常见输出包括 `0.0.0.0:8080` 和 `[::]:8080`。这意味着任何人只要能连接你的宿主机 IP,就能访问该服务。 -如果不希望对外暴露 (例如数据库服务),应绑定到 `127.0.0.1`: +如果不希望对外暴露 (例如数据库服务),应绑定到回环地址。IPv4 使用 `127.0.0.1`,IPv6 使用 `[::1]`: ```bash ## 仅允许本机访问 $ docker run -d -p 127.0.0.1:3306:3306 mysql +$ docker run -d -p '[::1]:3306:3306' mysql ``` #### 2. 避免端口冲突 diff --git a/10_buildx/10.1_buildkit.md b/10_buildx/10.1_buildkit.md index 180bc64..476d3e3 100644 --- a/10_buildx/10.1_buildkit.md +++ b/10_buildx/10.1_buildkit.md @@ -2,7 +2,7 @@ **BuildKit** 是下一代的镜像构建组件,在 [moby/buildkit](https://github.com/moby/buildkit) 开源。 -> **重要**:自 Docker 23 起,BuildKit 已成为 **默认稳定构建器**,无需手动启用。Docker Engine 29 进一步将 Containerd 镜像存储设为默认,提升与 Kubernetes 的互操作性。 +> **重要**:自 Docker 23 起,BuildKit 已成为 **默认稳定构建器**,无需手动启用。Docker Engine 29 在新安装场景中进一步将 containerd image store 设为默认,提升多平台镜像、SBOM/Provenance 等 OCI 元数据能力。 目前,Docker Hub 自动构建已经支持 BuildKit,具体请参考 [docker-practice/docker-hub-buildx](https://github.com/docker-practice/docker-hub-buildx)。 @@ -46,7 +46,7 @@ COPY --from=builder /app/dist /app/dist ``` 使用多阶段构建,构建的镜像中只包含了目标文件夹 `dist`,但仍然存在一些问题,当 `package.json` 文件变动时,`RUN npm i && rm -rf ~/.npm` 这一层会重新执行,变更多次后,生成了大量的中间层镜像。 -为解决这个问题,进一步的我们可以设想一个类似 **数据卷** 的功能,在镜像构建时把 `node_modules` 文件夹挂载上去,在构建完成后,这个 `node_modules` 文件夹会自动卸载,实际的镜像中并不包含 `node_modules` 这个文件夹,这样我们就省去了每次获取依赖的时间,大大增加了镜像构建效率,同时也避免了生成了大量的中间层镜像。 +为解决这个问题,可以把包管理器的下载缓存挂载到构建步骤中,例如 npm 的 `/root/.npm`。注意:`type=cache` 只能作为性能优化,不能成为构建正确性的前提。缓存目录可能被并发构建改写,也可能被 GC 清理,所以不要把 `node_modules`、编译产物等必须存在的内容只放在 cache mount 里。 `BuildKit` 提供了 `RUN --mount=type=cache` 指令,可以实现上边的设想。 @@ -59,35 +59,23 @@ WORKDIR /app COPY package.json /app/ -RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=locked \ - --mount=type=cache,target=/root/.npm,id=npm_cache \ - npm i --registry=https://registry.npmmirror.com +RUN --mount=type=cache,target=/root/.npm,id=npm_cache \ + npm install --registry=https://registry.npmmirror.com COPY src /app/src -RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=locked \ - -## --mount=type=cache,target=/app/dist,id=my_app_dist,sharing=locked \ - - npm run build +RUN npm run build FROM nginx:alpine -## COPY --from=builder /app/dist /app/dist - -## 为了更直观的说明 from 和 source 指令,这里使用 RUN 指令 - -RUN --mount=type=cache,target=/tmp/dist,from=builder,source=/app/dist \ - # --mount=type=cache,target=/tmp/dist,from=my_app_dist,sharing=locked \ - - mkdir -p /app/dist && cp -r /tmp/dist/* /app/dist +COPY --from=builder /app/dist /app/dist ``` -第一个 `RUN` 指令执行后,`id` 为 `my_app_npm_module` 的缓存文件夹挂载到了 `/app/node_modules` 文件夹中。多次执行也不会产生多个中间层镜像。 +第一个 `RUN` 指令执行后,`id` 为 `npm_cache` 的缓存文件夹挂载到了 `/root/.npm`,后续构建可复用下载缓存。 -第二个 `RUN` 指令执行时需要用到 `node_modules` 文件夹,`node_modules` 已经挂载,命令也可以正确执行。 +第二个 `RUN` 指令执行时,`node_modules` 已经作为上一层真实写入到 builder 阶段的文件系统中,构建不依赖缓存目录内容。 -第三个 `RUN` 指令将上一阶段产生的文件复制到指定位置,`from` 指明缓存的来源,这里 `builder` 表示缓存来源于构建的第一阶段,`source` 指明缓存来源的文件夹。 +最后使用 `COPY --from=builder` 将上一阶段产生的文件复制到最终镜像。跨阶段复制构建产物应使用 `COPY --from`;如果只是临时读取上一阶段文件,可使用 `RUN --mount=type=bind,from=builder,source=/app/dist,target=/tmp/dist,ro`。 上面的 `Dockerfile` 中 `--mount=type=cache,...` 中指令作用如下: diff --git a/10_buildx/10.2_buildx.md b/10_buildx/10.2_buildx.md index c62ae1f..4251d75 100644 --- a/10_buildx/10.2_buildx.md +++ b/10_buildx/10.2_buildx.md @@ -45,7 +45,7 @@ Buildx 支持在构建时直接生成 SBOM (Software Bill of Materials),这对 ```bash $ docker buildx build --sbom=true -t myimage . ``` -该命令会在构建结果中包含 SPDX 或 CycloneDX 格式的 SBOM 数据。 +该命令会把 SBOM 作为构建 attestation 附加到构建结果中;BuildKit 默认使用 SPDX SBOM attestation。需要 CycloneDX 文件时,可使用 Syft、Docker Scout 等工具另行生成或转换。 > **⚠️ 注意与失败模式**: > 要使 SBOM (或其它 attestation 元数据) 成功附着并可见,对底层的存储格式有前置要求:默认的 classic image store 不支持 manifest list/index 这种存放 attestation 的结构。 diff --git a/11_compose/11.2_install.md b/11_compose/11.2_install.md index b33aa28..d5dcff0 100644 --- a/11_compose/11.2_install.md +++ b/11_compose/11.2_install.md @@ -1,17 +1,32 @@ ## 11.2 安装与卸载 -`Compose` 是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。 +`Compose` 是 Docker 官方的开源项目,负责实现本地或单机多容器应用的快速编排。跨主机集群编排应使用 Swarm、Kubernetes 或云厂商托管服务。 当前的 Compose 以 `docker compose` 子命令的形式提供。Docker Desktop 在 macOS、Windows 和 Linux 上默认包含它;如果你已经在 Linux 上单独安装了 Docker Engine 和 Docker CLI,也可以再安装 Compose CLI 插件。 ### 11.2.1 Linux -在 Linux 上,你可以通过 Docker 官方发布页安装 Compose CLI 插件。把二进制文件保存到 `$DOCKER_CONFIG/cli-plugins/docker-compose`,并赋予执行权限即可。 +在 Linux 上,默认建议通过 Docker 官方软件仓库安装 Compose CLI 插件,这样可以随系统包管理器更新。 + +Ubuntu / Debian: + +```bash +$ sudo apt-get update +$ sudo apt-get install docker-compose-plugin +``` + +Fedora / CentOS / RHEL 兼容发行版: + +```bash +$ sudo dnf install docker-compose-plugin +``` + +如果是离线环境、需要锁定特定版本,或包管理器暂不覆盖你的架构,可以从 Docker 官方发布页手工安装。手工安装不会自动更新;下载 URL 中的版本号和架构(如 `x86_64`、`aarch64`)需要按目标机器替换。 ```bash $ DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker} $ mkdir -p $DOCKER_CONFIG/cli-plugins -$ curl -SL https://github.com/docker/compose/releases/latest/download/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose +$ curl -SL https://github.com/docker/compose/releases/download/v5.1.2/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose $ chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose ``` @@ -24,8 +39,12 @@ Docker Compose version v5.x.x ### 11.2.3 卸载 -如果是二进制包方式安装的,删除二进制文件即可。 +如果是仓库方式安装,使用包管理器卸载;如果是二进制包方式安装,删除二进制文件即可。 ```bash +$ sudo apt-get remove docker-compose-plugin +# 或 +$ sudo dnf remove docker-compose-plugin + $ rm $DOCKER_CONFIG/cli-plugins/docker-compose ``` diff --git a/11_compose/11.4_commands.md b/11_compose/11.4_commands.md index 98da8c6..ee0ca35 100644 --- a/11_compose/11.4_commands.md +++ b/11_compose/11.4_commands.md @@ -228,7 +228,7 @@ $ docker compose run --no-deps web python manage.py shell #### `scale` -在当前 Compose CLI 中,更稳妥的扩缩容写法是通过 `docker compose up --scale` 完成。 +当前 Compose CLI 仍支持 `docker compose scale`。实际使用中,更常见也更便于和创建/重建流程放在一起的写法是通过 `docker compose up --scale` 完成。 例如: @@ -238,7 +238,7 @@ $ docker compose up -d --scale web=3 --scale db=2 将启动 3 个容器运行 `web` 服务,2 个容器运行 `db` 服务。 -> **说明**:有些旧环境或实验性入口中仍可能出现 `docker compose scale`,但它不应再被视为当前 Compose 的通用稳定默认命令。 +> **说明**:如果 Compose 文件为服务指定了 `container_name`,该服务无法扩展到多个容器。需要扩缩容的服务应使用 Compose 自动生成的容器名,并通过服务名做 DNS 访问。 一般的,当指定数目多于该服务当前实际运行容器,将新创建并启动容器;反之,将停止容器。 diff --git a/11_compose/11.5_compose_file.md b/11_compose/11.5_compose_file.md index 1c44136..f563ea1 100644 --- a/11_compose/11.5_compose_file.md +++ b/11_compose/11.5_compose_file.md @@ -582,6 +582,14 @@ $ docker compose --profile debug up # 启动 web + debug $ docker compose up # 仅启动 web ``` +也可以通过环境变量激活: + +```bash +$ COMPOSE_PROFILES=debug,test docker compose up +``` + +如果在命令行里显式指定某个带 profile 的服务,Compose 会自动启动这个目标服务及其声明的依赖;但不会自动启动同一 profile 下的其它服务,除非也显式指定或通过 `--profile` / `COMPOSE_PROFILES` 启用。 + ### 11.5.35 读取变量 Compose 模板文件支持动态读取主机的系统环境变量和当前目录下的 `.env` 文件中的变量。 diff --git a/11_compose/11.8_wordpress.md b/11_compose/11.8_wordpress.md index a47ce3e..067e3e5 100644 --- a/11_compose/11.8_wordpress.md +++ b/11_compose/11.8_wordpress.md @@ -4,7 +4,7 @@ > - MySQL:8.4(可替换为其他 8.x 版本,或使用 MariaDB 替代) > - WordPress:latest(建议在生产环境指定具体版本,如 6.x) -WordPress 是全球最流行的内容管理系统 (CMS)。使用 Docker Compose 可以在几分钟内搭建一个包含数据库、Web 服务和持久化存储的生产级 WordPress 环境。 +WordPress 是全球最流行的内容管理系统 (CMS)。使用 Docker Compose 可以在几分钟内搭建一个包含数据库、Web 服务和持久化存储的本地练习/单机演示环境。 --- diff --git a/11_compose/README.md b/11_compose/README.md index 20e8149..299eb20 100644 --- a/11_compose/README.md +++ b/11_compose/README.md @@ -1,6 +1,6 @@ # 第十一章 Docker Compose -`Docker Compose` 是 Docker 官方编排 (Orchestration) 项目之一,负责快速的部署分布式应用。 +`Docker Compose` 是 Docker 官方编排 (Orchestration) 项目之一,负责快速定义和启动本地或单机多容器应用。跨主机集群编排应交给 Swarm、Kubernetes 或云厂商托管服务。 > ⚠️ **重要提示:Compose V1 已停止支持** > diff --git a/11_compose/demo/django/docker-compose.yml b/11_compose/demo/django/docker-compose.yml index 9871503..3c46f63 100644 --- a/11_compose/demo/django/docker-compose.yml +++ b/11_compose/demo/django/docker-compose.yml @@ -2,9 +2,18 @@ services: db: - image: postgres + image: postgres:16 environment: + POSTGRES_DB: django_db + POSTGRES_USER: django_user POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD} + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U django_user -d django_db"] + interval: 5s + timeout: 5s + retries: 5 web: build: . @@ -13,6 +22,13 @@ services: - .:/code ports: - "8000:8000" + depends_on: + db: + condition: service_healthy environment: # 与书中 11.6 节一致:settings.py 从环境变量读取数据库密码 POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD} + DATABASE_URL: postgres://django_user:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@db:5432/django_db + +volumes: + postgres_data: diff --git a/11_compose/demo/wordpress/docker-compose.yml b/11_compose/demo/wordpress/docker-compose.yml index a4bb50b..7eedb8f 100644 --- a/11_compose/demo/wordpress/docker-compose.yml +++ b/11_compose/demo/wordpress/docker-compose.yml @@ -24,7 +24,7 @@ services: - db image: wordpress:latest ports: - - "8000:80" + - "127.0.0.1:8000:80" restart: always environment: WORDPRESS_DB_HOST: db:3306 diff --git a/12_implementation/12.1_arch.md b/12_implementation/12.1_arch.md index a92b563..d520276 100644 --- a/12_implementation/12.1_arch.md +++ b/12_implementation/12.1_arch.md @@ -100,7 +100,7 @@ flowchart TD 从 Docker Engine v29.x 开始,架构进一步简化和标准化: - **Containerd 镜像存储 (Image Store)**:在 v29.x 的新安装场景中默认启用。Docker 直接使用 Containerd 的镜像管理能力,不再维护自己的一套 graphdriver。 - - **优势**:多平台镜像支持更好、镜像拉取更快 (lazy pulling)、与 K8s 共享镜像。 + - **优势**:多平台镜像支持更好,可保存 SBOM/Provenance 等 attestations,并可使用 containerd snapshotters 的 lazy pulling 等能力。 - **实验性 nftables 支持**:随着主流 Linux 发行版逐步弃用 iptables,Docker v29.x 引入了实验性 nftables 后端。启用方式为 `dockerd --firewall-backend=nftables`,可直接创建 nftables 规则而无需依赖 iptables-nft 转换层。生产环境请谨慎使用。 --- diff --git a/12_implementation/12.4_ufs.md b/12_implementation/12.4_ufs.md index b6f921f..9b41a93 100644 --- a/12_implementation/12.4_ufs.md +++ b/12_implementation/12.4_ufs.md @@ -92,11 +92,11 @@ Docker 的存储驱动经历了从早期各式各样的机制(如 aufs, device | 存储后端 / 驱动 | 核心特性说明 | 推荐程度 | |---------|------|---------| -| **containerd image store**| (v29.x 新一代默认后端,新装默认) 基于 containerd 的 snapshotters,原生支持 OCI image index、多架构镜像与 Attestations 构建溯源元数据存储。 | ✅**强烈推荐 (现代默认)** | +| **containerd image store**| (v29.x 新一代默认后端,新装默认) 基于 containerd 的 snapshotters,原生支持 OCI image index、多架构镜像与 Attestations 构建溯源元数据存储;启用 `userns-remap` 时不可用。 | ✅**强烈推荐 (现代默认)** | | **overlay2**| (经典 Graph Driver) 传统架构下的现代 Linux 默认驱动,性能优秀,但在处理复杂溯源元数据(索引)时受限。 | ✅**推荐 (主要后备)** | -| **aufs** | 早期默认,兼容性好 | 遗留系统 | +| **aufs** | 早期默认,已从现代 Docker Engine 移除 | 历史资料 | | **btrfs**/**zfs** | 使用原生稳定文件系统快照能力 | 特定场景 | -| **devicemapper** | 块设备级存储 | 遗留系统 (已被逐步弃用) | +| **devicemapper** | 块设备级存储,已从现代 Docker Engine 移除 | 历史资料 | | **vfs** | 不使用 CoW,每层完整复制 | 仅测试 | #### Classic Graph Drivers 与 Snapshotters 的核心差异 @@ -104,7 +104,7 @@ Docker 的存储驱动经历了从早期各式各样的机制(如 aufs, device 传统模型(如 `overlay2`)将镜像拉取解包的过程由 Docker 的 graph drivers 处理。而新的 `containerd image store` 则将这一职责彻底下放给了 `containerd` 自身的 `snapshotters`(底层在 Linux 发行版通常依然利用操作系统的 overlayfs)。这种架构改变带来了: 1. 本地免拉取查看多平台镜像 index manifest 与 attestations (SBOM、Provenance)。 -2. 避免了以前绕过 CRI 获取本地镜像的问题,带来更好的原生 Kubernetes 生态兼容性。 +2. 允许 Docker 使用 containerd snapshotters 管理镜像层,便于与现代 OCI 生态能力对齐。它不表示 kubelet/containerd 会自动复用 Docker 本地镜像;Kubernetes 镜像分发仍应以 registry、镜像拉取策略和运行时配置为准。 #### 查看当前存储驱动与后端 @@ -114,14 +114,14 @@ $ docker info | grep "Storage Driver" Storage Driver: overlay2 ## 在 Engine v29.x 中,可以通过如下输出验证是否开启了 containerd 镜像后端: -$ docker info | grep "containerd image store" - containerd image store: true +$ docker info -f '{{ .DriverStatus }}' +[[driver-type io.containerd.snapshotter.v1]] ``` --- ### 12.4.5 overlay2 工作原理 -overlay2 是目前最推荐的存储驱动: +在经典 graph driver 体系下,overlay2 仍是 Linux 上的主要推荐驱动;Docker Engine 29 新安装场景默认走 containerd image store/snapshotter。 ```mermaid flowchart TD diff --git a/12_implementation/summary.md b/12_implementation/summary.md index 23670d0..db319e7 100644 --- a/12_implementation/summary.md +++ b/12_implementation/summary.md @@ -4,9 +4,9 @@ | 技术 | 作用 | 要点 | |------|------|------| -| **Namespace** | 资源隔离 | PID、NET、MNT、UTS、IPC、USER 六种命名空间 | +| **Namespace** | 资源隔离 | 常见核心包括 PID、NET、MNT、UTS、IPC、USER、Cgroup;Time namespace 通常默认不启用 | | **Cgroups** | 资源限制 | 限制 CPU、内存、磁盘 I/O、进程数 | -| **Union FS** | 分层存储 | overlay2 为推荐驱动,支持 Copy-on-Write | +| **Union FS** | 分层存储 | 镜像分层与 Copy-on-Write 是核心;Engine 29 新装默认 containerd image store,overlay2 是经典 graph driver 场景的主要后备 | | Namespace | 隔离内容 | 一句话说明 | |-----------|---------|-----------| diff --git a/13_kubernetes_concepts/13.2_concepts.md b/13_kubernetes_concepts/13.2_concepts.md index befb9ff..a93aeff 100644 --- a/13_kubernetes_concepts/13.2_concepts.md +++ b/13_kubernetes_concepts/13.2_concepts.md @@ -7,13 +7,13 @@ 图 13-2:Kubernetes 基本概念示意图 * 节点 (`Node`):一个节点是一个运行 Kubernetes 中的主机。 -* 容器组 (`Pod`):一个 Pod 对应于由若干容器组成的一个容器组,同个组内的容器共享一个存储卷 (volume)。 +* 容器组 (`Pod`):Kubernetes 中最小的可部署和调度单元;一个 Pod 包含一个或多个紧密协作的容器,共享网络身份,并可共享一个或多个卷 (volume)。 * 容器组生命周期 (`pod-states`):包含所有容器状态集合,包括容器组状态类型,容器组生命周期,事件,重启策略。 * 服务 (`services`):一个 Kubernetes 服务是容器组逻辑的高级抽象,同时也对外提供访问容器组的策略。 * 卷 (`volumes`):一个卷就是一个目录,容器对其有访问权限。 * 标签 (`labels`):标签是用来连接一组对象的,比如容器组。标签可以被用来组织和选择子对象。 * 接口权限 (`accessing_the_api`):端口,IP 地址和代理的防火墙规则。 -* web 界面 (`ux`):用户可以通过 web 界面操作 Kubernetes。 +* web 界面 (`ux`):用户可以通过 Headlamp 等仍在维护的 web 界面观察和操作 Kubernetes;历史 Dashboard 已停止维护。 * 命令行操作 (`cli`):`kubectl` 命令。 ### 13.2.1 节点 @@ -82,7 +82,7 @@ $ kubectl drain worker-1 --ignore-daemonsets ### 13.2.2 容器组 -在 Kubernetes 中,使用的最小调度单位是容器组 (Pod),它是创建、调度、管理的最小单位。一个 Pod 包含一个或多个紧密协作的容器,它们共享网络命名空间和存储卷。 +在 Kubernetes 中,使用的最小调度单位是容器组 (Pod),它是创建、调度、管理的最小单位。一个 Pod 包含一个或多个紧密协作的容器,它们共享网络命名空间,并可共享一个或多个存储卷。 Pod 通常不会被直接创建,而是通过 Deployment 等控制器来管理。当节点发生故障时,控制器会在其他可用节点上重新创建 Pod。 @@ -96,7 +96,7 @@ Pod 通常不会被直接创建,而是通过 Deployment 等控制器来管理 在一个容器组中,容器都使用相同的网络地址和端口,可以通过本地网络来相互通信。每个容器组都有独立的 IP,可以通过网络来和其他物理主机或者容器通信。 -容器组有一组存储卷 (挂载点),主要是为了让容器在重启之后可以不丢失数据。 +容器组可以挂载一组存储卷 (挂载点)。卷不只用于持久化,也可用于 `emptyDir` 临时交换、ConfigMap/Secret 投射、日志旁路收集等场景。真正需要跨 Pod 生命周期保留的数据,应使用 PersistentVolume / PersistentVolumeClaim 等持久化机制。 #### 容器组管理 @@ -121,7 +121,7 @@ Pod 通常不会被直接创建,而是通过 Deployment 等控制器来管理 #### 容器组的生命状态 -包括若干状态值:`Pending`、`Running`、`Succeeded`、`Failed`。 +Pod phase 包括若干状态值:`Pending`、`Running`、`Succeeded`、`Failed`、`Unknown`。 | 状态 | 说明 | |------|------| @@ -129,6 +129,7 @@ Pod 通常不会被直接创建,而是通过 Deployment 等控制器来管理 | **Running** | Pod 已被调度到节点,并且所有容器都已启动。至少有一个容器处于运行状态。| | **Succeeded** | Pod 中的所有容器都正常退出,且不会被重启。| | **Failed** | Pod 中的所有容器都已终止,且至少有一个容器以失败状态退出。| +| **Unknown** | 集群无法获取 Pod 状态,常见原因是节点失联。| #### 容器组生命周期与重启策略 @@ -140,7 +141,7 @@ Pod 的重启策略 (`restartPolicy`) 决定了容器退出后的行为: | **OnFailure** | 不重启 | 重启容器 | | **Never** | 不重启 | 不重启 | -当节点故障或不可达时,节点控制器会将该节点上所有 Pod 的状态标记为 `Failed`。如果这些 Pod 由 Deployment 等控制器管理,控制器会自动在其他节点上重新创建。 +当节点故障或不可达时,Pod 可能先表现为 `Unknown`,之后根据控制器、驱逐策略和垃圾回收机制转为 `Failed` 或被重新创建。如果这些 Pod 由 Deployment 等控制器管理,控制器会自动在其他节点上重新创建。 ### 13.2.3 Deployment 与 ReplicaSet diff --git a/13_kubernetes_concepts/13.5_practice.md b/13_kubernetes_concepts/13.5_practice.md index d3e31b5..bfc10cf 100644 --- a/13_kubernetes_concepts/13.5_practice.md +++ b/13_kubernetes_concepts/13.5_practice.md @@ -1,12 +1,18 @@ ## 13.5 实战练习 -本章将通过一个具体的案例:部署一个 Nginx 网站,并为其配置 Service 和 Ingress,来串联前面学到的知识。 +本章将通过一个具体的案例:部署一个 Nginx 网站,并为其配置 Service,来串联前面学到的知识。 + +开始前请先准备好可用的 Kubernetes 集群和 `kubectl` 上下文。你可以先完成 [14.3 Docker Desktop](../14_kubernetes_setup/14.3_docker-desktop.md) 或 [14.4 Kind](../14_kubernetes_setup/14.4_kind.md),并确认: + +```bash +kubectl get nodes +``` ### 13.5.1 目标 1. 部署一个 Nginx Deployment。 2. 创建一个 Service 暴露 Nginx。 -3. (可选) 通过 Ingress 访问服务。 +3. 通过端口转发或 NodePort 访问服务。 ### 13.5.2 步骤 1:创建 Deployment @@ -69,7 +75,15 @@ kubectl apply -f nginx-service.yaml ```bash kubectl get svc nginx-service ``` -如果输出端口是 `80:30080/TCP`,你可以通过 `http://:30080` 访问 Nginx。 +如果输出端口是 `80:30080/TCP`,你可以通过 `http://:30080` 访问 Nginx。Docker Desktop、Kind 等本地集群中,NodePort 到宿主机的可达性取决于集群实现;更稳定的本地访问方式是端口转发: + +```bash +kubectl port-forward svc/nginx-service 8080:80 +``` + +然后访问 `http://localhost:8080`。 + +> Ingress 只有在集群中已安装 Ingress controller 且配置了 IngressClass 时才会生效。当前练习只覆盖 Service;Ingress/Gateway API 建议在完成第 14 章后再单独练习。 ### 13.5.4 步骤 3:模拟滚动更新 diff --git a/14_kubernetes_setup/14.1_kubeadm.md b/14_kubernetes_setup/14.1_kubeadm.md index b92d177..a4657db 100644 --- a/14_kubernetes_setup/14.1_kubeadm.md +++ b/14_kubernetes_setup/14.1_kubeadm.md @@ -171,13 +171,13 @@ $ sudo systemctl enable containerd $ sudo systemctl start containerd $ sudo kubeadm init \ - --image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \ --pod-network-cidr 10.244.0.0/16 \ --cri-socket unix:///run/containerd/containerd.sock \ --v 5 ``` * `--pod-network-cidr 10.244.0.0/16` 参数与后续 CNI 插件有关,这里以 `flannel` 为例,若后续部署其他类型的网络插件请更改此参数。 +* kubeadm 默认使用 `registry.k8s.io` 拉取 Kubernetes 控制平面镜像。受限网络环境可通过 kubeadm 配置文件中的 `imageRepository` 指向受信任镜像仓库;不要把第三方镜像仓库当成通用默认值。 > 若 `kubeadm` 预检失败,应按提示修复缺失依赖、内核参数、swap 或运行时配置。实验环境确需忽略预检时,只忽略明确理解且可接受的单项检查,不建议使用 `--ignore-preflight-errors=all`。 diff --git a/14_kubernetes_setup/14.2_kubeadm-docker.md b/14_kubernetes_setup/14.2_kubeadm-docker.md index bd0b924..b0d535f 100644 --- a/14_kubernetes_setup/14.2_kubeadm-docker.md +++ b/14_kubernetes_setup/14.2_kubeadm-docker.md @@ -197,14 +197,14 @@ $ sudo systemctl daemon-reload #### master ```bash -$ sudo kubeadm init --image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \ - --pod-network-cidr 10.244.0.0/16 \ +$ sudo kubeadm init --pod-network-cidr 10.244.0.0/16 \ --cri-socket unix:///var/run/cri-dockerd.sock \ --v 5 ``` * `--cri-socket unix:///var/run/cri-dockerd.sock` 参数指定使用 cri-dockerd 作为容器运行时接口。 * `--pod-network-cidr 10.244.0.0/16` 参数与后续 CNI 插件有关,这里以 `flannel` 为例,若后续部署其他类型的网络插件请更改此参数。 +* kubeadm 默认使用 `registry.k8s.io` 拉取 Kubernetes 控制平面镜像。受限网络环境可通过 kubeadm 配置文件中的 `imageRepository` 指向受信任镜像仓库;不要把第三方镜像仓库当成通用默认值。 > 若 `kubeadm` 预检失败,应按提示修复缺失依赖、内核参数、swap 或运行时配置。实验环境确需忽略预检时,只忽略明确理解且可接受的单项检查,不建议使用 `--ignore-preflight-errors=all`。 diff --git a/14_kubernetes_setup/14.3_docker-desktop.md b/14_kubernetes_setup/14.3_docker-desktop.md index 97744db..92db4cb 100644 --- a/14_kubernetes_setup/14.3_docker-desktop.md +++ b/14_kubernetes_setup/14.3_docker-desktop.md @@ -4,15 +4,17 @@ ### 14.3.1 启用 Kubernetes -在 Docker Desktop 设置页面,点击 `Kubernetes`,选择 `Enable Kubernetes`,稍等片刻,看到左下方 `Kubernetes` 变为 `running`,Kubernetes 启动成功。 +在 Docker Desktop 设置页面,进入 `Kubernetes`,创建或启用集群。较新的 Docker Desktop 可选择 `kind` 或 `kubeadm` 作为集群创建方式;日常本地开发优先选择 `kind`,因为它支持多节点和版本选择。 ![图](../_images/settings-kubernetes.png) -> 注意:Kubernetes 的镜像存储在 `registry.k8s.io`,如果国内网络无法直接访问,可以在 Docker Desktop 配置中的 `Docker Engine` 处配置镜像加速器,或者利用国内云服务商的镜像仓库手动拉取镜像并 retag。 +> 注意:Docker Desktop Kubernetes 的控制平面镜像默认从 Docker Hub 拉取,例如 `docker.io/docker/desktop-*` 或 `docker.io/kindest/node:`。如果企业网络不能访问 Docker Hub,应按 Docker Desktop 的 `KubernetesImagesRepository` 设置镜像仓库,并用 `docker desktop kubernetes images list`(Docker Desktop 4.44+)或 `docker ps` 确认实际镜像标签。普通 Docker Engine 的 `registry-mirrors` 不会自动改写这些控制平面镜像。 ### 14.3.2 测试 ```bash $ kubectl version +$ kubectl config use-context docker-desktop +$ kubectl get nodes ``` -如果正常输出信息,则证明 Kubernetes 成功启动。 +如果 `kubectl get nodes` 显示节点为 `Ready`,则证明 Kubernetes 成功启动。 diff --git a/14_kubernetes_setup/14.7_dashboard.md b/14_kubernetes_setup/14.7_dashboard.md index 45d8345..6105b3d 100644 --- a/14_kubernetes_setup/14.7_dashboard.md +++ b/14_kubernetes_setup/14.7_dashboard.md @@ -1,12 +1,27 @@ -## 14.7 部署 Dashboard +## 14.7 可视化管理界面 -[Kubernetes Dashboard](https://github.com/kubernetes/dashboard) 是基于网页的 Kubernetes 用户界面。 +[Kubernetes Dashboard](https://github.com/kubernetes-retired/dashboard) 是历史上常用的 Kubernetes Web UI,但项目已停止维护。 -> **注意**:原 `kubernetes/dashboard` 项目已于 2026 年 1 月 21 日归档停止维护。推荐使用 [Headlamp](https://headlamp.dev/) 等替代方案。以下内容仅供历史参考,基于归档前的最新 Helm 安装方式。 +> **注意**:Kubernetes 官方文档已将 Dashboard 标记为 deprecated and unmaintained,新安装建议考虑 [Headlamp](https://headlamp.dev/) 等仍在维护的替代方案。以下 Dashboard 内容仅供历史迁移或存量环境参考。 ![图](../_images/kubernetes-dashboard-ui.png) -### 14.7.1 部署 +### 14.7.1 推荐替代:Headlamp + +Headlamp 是 Kubernetes SIG UI 下的现代 Web UI,可通过 Helm 安装: + +```bash +$ helm repo add headlamp https://kubernetes-sigs.github.io/headlamp/ +$ helm install headlamp headlamp/headlamp --namespace kube-system +``` + +本地访问时优先使用端口转发,避免直接把管理界面暴露到公网: + +```bash +$ kubectl -n kube-system port-forward svc/headlamp 4466:80 +``` + +### 14.7.2 历史 Dashboard 部署 Dashboard 7.0+ 版本仅支持通过 Helm 安装: @@ -17,7 +32,7 @@ $ helm upgrade --install kubernetes-dashboard kubernetes-dashboard/kubernetes-da --create-namespace --namespace kubernetes-dashboard ``` -### 14.7.2 访问 +### 14.7.3 访问 通过端口转发访问 Dashboard: @@ -27,19 +42,15 @@ $ kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard-kong-pro 然后在浏览器打开 `https://localhost:8443` 即可访问。 -### 14.7.3 登录 +### 14.7.4 登录 为历史 Dashboard 创建只读服务账户并获取短期登录令牌。不要为 Dashboard 创建 `cluster-admin` 绑定;如果确实需要临时管理员权限,应走单独的 break-glass 审批和审计流程。 ```bash $ kubectl create sa dashboard-readonly -n kubernetes-dashboard -$ kubectl create clusterrole dashboard-readonly \ - --verb=get,list,watch \ - --resource=pods,deployments,services,configmaps,namespaces,nodes - $ kubectl create clusterrolebinding dashboard-readonly \ - --clusterrole=dashboard-readonly \ + --clusterrole=view \ --serviceaccount=kubernetes-dashboard:dashboard-readonly $ kubectl create token dashboard-readonly -n kubernetes-dashboard --duration=1h diff --git a/14_kubernetes_setup/README.md b/14_kubernetes_setup/README.md index 4bf04f7..4d70a9e 100644 --- a/14_kubernetes_setup/README.md +++ b/14_kubernetes_setup/README.md @@ -1,6 +1,6 @@ # 第十四章 部署 Kubernetes -目前,Kubernetes 支持在多种环境下使用,包括本地主机 (Ubuntu、Debian、CentOS、Fedora 等)、云服务 ([腾讯云](https://cloud.tencent.com/act/cps/redirect?redirect=10058&cps_key=3a5255852d5db99dcd5da4c72f05df61)、[阿里云](https://www.aliyun.com/product/kubernetes?source=5176.11533457&userCode=8lx5zmtu&type=copy)、[百度云](https://cloud.baidu.com/product/cce.html)等)。 +目前,Kubernetes 支持在多种环境下使用,包括本地主机 (Ubuntu、Debian、CentOS、Fedora 等)、云服务 ([腾讯云 TKE](https://cloud.tencent.com/product/tke)、[阿里云 ACK](https://cn.aliyun.com/product/ack)、[百度云](https://cloud.baidu.com/product/cce.html)等)。 你可以使用以下几种方式部署 Kubernetes,接下来的小节会对各种方式进行详细介绍。 @@ -11,7 +11,7 @@ * [Kind - Kubernetes IN Docker](14.4_kind.md) * [K3s - 轻量级 Kubernetes](14.5_k3s.md) * [一步步部署 Kubernetes 集群](14.6_systemd.md) -* [部署 Dashboard](14.7_dashboard.md) +* [可视化管理界面:Headlamp 与历史 Dashboard](14.7_dashboard.md) * [Kubernetes 命令行 kubectl](14.8_kubectl.md) 除了上述方式,企业生产环境中还有两个常见的部署工具值得关注: diff --git a/14_kubernetes_setup/summary.md b/14_kubernetes_setup/summary.md index 7d651f3..f85cd17 100644 --- a/14_kubernetes_setup/summary.md +++ b/14_kubernetes_setup/summary.md @@ -13,7 +13,7 @@ ### 延伸阅读 - [容器编排基础](../13_kubernetes_concepts/README.md):Kubernetes 核心概念 -- [Dashboard](14.7_dashboard.md):部署可视化管理界面 +- [可视化管理界面](14.7_dashboard.md):Headlamp 与历史 Dashboard 迁移参考 - [kubectl](14.8_kubectl.md):命令行工具使用指南 --- diff --git a/16_cloud/16.2_tencentCloud.md b/16_cloud/16.2_tencentCloud.md index 3ed4a7a..bd19d5b 100644 --- a/16_cloud/16.2_tencentCloud.md +++ b/16_cloud/16.2_tencentCloud.md @@ -136,7 +136,17 @@ docker push ccr.ccs.tencentyun.com/my-namespace/my-app:v1.0 #### TKE 集群中使用 TCR 镜像 -配置镜像拉取凭证后,在 Deployment 中直接引用 TCR 镜像: +配置镜像拉取凭证后,在 Deployment 中直接引用 TCR 镜像。Secret 必须创建在使用它的 namespace 中;下面示例使用 `default` namespace。 + +```bash +$ kubectl create secret docker-registry tcr-secret \ + --docker-server=ccr.ccs.tencentyun.com \ + --docker-username= \ + --docker-password= \ + --namespace=default +``` + +> 安全提示:在命令行直接输入密码或 token 可能进入 shell 历史记录。生产环境可先 `docker login`,再基于受保护的 `~/.docker/config.json` 创建 `kubernetes.io/dockerconfigjson` Secret,或使用云厂商提供的托管凭据集成。 ```yaml apiVersion: apps/v1 diff --git a/16_cloud/16.3_alicloud.md b/16_cloud/16.3_alicloud.md index 43f1714..098a5c7 100644 --- a/16_cloud/16.3_alicloud.md +++ b/16_cloud/16.3_alicloud.md @@ -6,11 +6,11 @@ 图 16-3:阿里云标识 -[阿里云](https://www.aliyun.com/?source=5176.11533457\&userCode=8lx5zmtu\&type=copy)创立于 2009 年,是中国较早的云计算平台。阿里云致力于提供安全、可靠的计算和数据处理能力。 +[阿里云](https://www.aliyun.com/)创立于 2009 年,是中国较早的云计算平台。阿里云致力于提供安全、可靠的计算和数据处理能力。 -[阿里云](https://www.aliyun.com/?source=5176.11533457\&userCode=8lx5zmtu\&type=copy)的客户群体中,活跃着微博、虎牙、魅族、优酷等一大批明星互联网公司。在天猫双 11 全球狂欢节等极富挑战的应用场景中,阿里云保持着良好的运行纪录。 +[阿里云](https://www.aliyun.com/)的客户群体中,活跃着微博、虎牙、魅族、优酷等一大批明星互联网公司。在天猫双 11 全球狂欢节等极富挑战的应用场景中,阿里云保持着良好的运行纪录。 -[阿里云容器服务 Kubernetes 版 ACK](https://www.aliyun.com/product/kubernetes?source=5176.11533457\&userCode=8lx5zmtu\&type=copy) 提供了高性能、可伸缩的容器应用管理服务,支持在一组云服务器上通过 Docker 容器来进行应用生命周期管理。容器服务极大简化了用户对容器管理集群的搭建工作,无缝整合了阿里云虚拟化、存储、网络和安全能力。容器服务提供了多种应用发布方式和流水线般的持续交付能力,原生支持微服务架构,助力用户无缝上云和跨云管理。 +[阿里云容器服务 Kubernetes 版 ACK](https://cn.aliyun.com/product/ack) 提供了高性能、可伸缩的容器应用管理服务,支持在一组云服务器上通过 Docker 容器来进行应用生命周期管理。容器服务极大简化了用户对容器管理集群的搭建工作,无缝整合了阿里云虚拟化、存储、网络和安全能力。容器服务提供了多种应用发布方式和流水线般的持续交付能力,原生支持微服务架构,助力用户无缝上云和跨云管理。 diff --git a/16_cloud/README.md b/16_cloud/README.md index 06b8980..3f82933 100644 --- a/16_cloud/README.md +++ b/16_cloud/README.md @@ -4,7 +4,7 @@ Docker 目前已经得到了众多公有云平台的支持,并成为除虚拟机之外的核心云业务。 -除了 AWS、Google、Azure 等,国内的各大公有云厂商,基本上都同时支持了虚拟机服务和基于 Kubernetes 的容器云业务。有的还推出了其他服务,例如[容器镜像服务](https://cloud.tencent.com/act/cps/redirect?redirect=11588&cps_key=3a5255852d5db99dcd5da4c72f05df61)让用户在云上享有安全高效的镜像托管、分发等服务。 +除了 AWS、Google、Azure 等,国内的各大公有云厂商,基本上都同时支持了虚拟机服务和基于 Kubernetes 的容器云业务。有的还推出了其他服务,例如[容器镜像服务](https://cloud.tencent.com/document/product/1141)让用户在云上享有安全高效的镜像托管、分发等服务。 ## 本章内容 diff --git a/17_ecosystem/17.1_coreos_intro.md b/17_ecosystem/17.1_coreos_intro.md index 75c4741..a23fd88 100644 --- a/17_ecosystem/17.1_coreos_intro.md +++ b/17_ecosystem/17.1_coreos_intro.md @@ -1,8 +1,8 @@ ## 17.1 Fedora CoreOS 简介 -> **版本说明**:Fedora CoreOS 定期发布更新。建议访问 [官方下载页面](https://getfedora.org/coreos/download/) 获取最新版本和兼容性信息。 +> **版本说明**:Fedora CoreOS 定期发布更新。建议访问 [官方下载页面](https://fedoraproject.org/coreos/download/) 获取最新版本和兼容性信息。 -[Fedora CoreOS](https://getfedora.org/coreos/) 是一个自动更新的,最小的,整体的,以容器为中心的操作系统,不仅适用于集群,而且可独立运行,并针对运行 Kubernetes 进行了优化。它旨在结合 CoreOS Container Linux 和 Fedora Atomic Host 的优点,将 Container Linux 中的 [Ignition](https://github.com/coreos/ignition) 与 [rpm-ostree](https://github.com/coreos/rpm-ostree) 和 Project Atomic 中的 SELinux 强化等技术相集成。其目标是提供最佳的容器主机,以安全,大规模地运行容器化的工作负载。 +[Fedora CoreOS](https://fedoraproject.org/coreos/) 是一个自动更新的,最小的,整体的,以容器为中心的操作系统,不仅适用于集群,而且可独立运行,并针对运行 Kubernetes 进行了优化。它旨在结合 CoreOS Container Linux 和 Fedora Atomic Host 的优点,将 Container Linux 中的 [Ignition](https://github.com/coreos/ignition) 与 [rpm-ostree](https://github.com/coreos/rpm-ostree) 和 Project Atomic 中的 SELinux 强化等技术相集成。其目标是提供最佳的容器主机,以安全,大规模地运行容器化的工作负载。 ### 17.1.1 FCOS 特性 diff --git a/17_ecosystem/17.2_coreos_install.md b/17_ecosystem/17.2_coreos_install.md index a770ebb..cbdf441 100644 --- a/17_ecosystem/17.2_coreos_install.md +++ b/17_ecosystem/17.2_coreos_install.md @@ -2,7 +2,7 @@ ### 17.2.1 下载 ISO -在[下载页面](https://getfedora.org/coreos/download/) `Bare Metal & Virtualized` 标签页下载 ISO。 +在[下载页面](https://fedoraproject.org/coreos/download/) `Bare Metal & Virtualized` 标签页下载 ISO。 ### 17.2.2 编写 Butane 配置 diff --git a/18_security/18.1_kernel_ns.md b/18_security/18.1_kernel_ns.md index 003d715..4457970 100644 --- a/18_security/18.1_kernel_ns.md +++ b/18_security/18.1_kernel_ns.md @@ -20,7 +20,7 @@ Docker 守护进程在启动容器时,会在后台为容器创建一套独立 > 为了缓解内核漏洞带来的威胁,生产环境务必保持宿主机 Linux 内核的及时修补与更新,或者借助诸如 gVisor、Kata Containers 等提供了独立内核的安全容器技术。同时,需要及时修补容器运行时(如 runC)的漏洞。2025 年 11 月披露的一系列 runC 容器逃逸漏洞(CVE-2025-31133、CVE-2025-52565、CVE-2025-52881)就表明,即使内核保持更新,运行时层的缺陷仍然可能导致容器隔离被突破。 通过命名空间,Docker 也能限制进程从外部环境获取信息。 -例如,由于进程环境被隔离,进程在内部其实是无法感知到外部宿主机的存在的。它既不能获取其他容器的进程列表,也无法通过网络与其他系统进行交互(除非经过配置)。 +例如,由于进程环境被隔离,进程在内部通常无法直接感知外部宿主机的进程和挂载命名空间。网络命名空间隔离的是网络栈;默认 bridge 网络通常允许容器主动访问外部网络,限制的是外部直接访问容器服务。若要限制出站访问,需要使用 `none` 网络、防火墙、Kubernetes NetworkPolicy 或运行时策略。 ### 18.1.3 用户命名空间与提权防护 diff --git a/18_security/18.6_image_security.md b/18_security/18.6_image_security.md index 0bc03eb..ef8ac3a 100644 --- a/18_security/18.6_image_security.md +++ b/18_security/18.6_image_security.md @@ -217,7 +217,7 @@ grype sbom:sbom.json --add-cpes-if-none ### 18.6.3 镜像签名与验证 -镜像签名确保镜像的来源可信且未被篡改。两种主流方案是 Cosign 和 Notary。 +镜像签名确保镜像的来源可信且未被篡改。新项目通常优先评估 Cosign (Sigstore) 或 Notary Project 的 Notation;Docker Content Trust / Notary v1 属于历史路径。 #### Cosign - 现代签名解决方案 @@ -269,13 +269,25 @@ cosign verify --key cosign.pub "$IMAGE_DIGEST" # 在 GitHub Actions 等 CI 中无需存储密钥 cosign sign --yes "$IMAGE_DIGEST" -# 验证时自动使用 OIDC 令牌验证身份 +# 验证时检查签名证书中的 OIDC 身份声明是否匹配预期 workflow 与 issuer cosign verify "$IMAGE_DIGEST" \ --certificate-identity https://github.com/myorg/myrepo/.github/workflows/build.yml@refs/heads/main \ --certificate-oidc-issuer https://token.actions.githubusercontent.com ``` -#### Docker Content Trust 与 Notary +#### Notary Project / Notation + +Notation 是 Notary Project 的 OCI 签名工具,适合希望采用 CNCF Notary Project 规范、或使用 registry/云厂商原生集成的团队。与 Cosign 类似,生产环境应围绕不可变 digest 做签名和策略校验。 + +```bash +# 签名已推送的镜像 digest +notation sign myregistry.com/myapp@sha256: + +# 验证签名 +notation verify myregistry.com/myapp@sha256: +``` + +#### Docker Content Trust 与 Notary v1 > **注意:DCT 退役时间线** > @@ -283,7 +295,7 @@ cosign verify "$IMAGE_DIGEST" \ > > 新项目应优先使用上文介绍的 **Cosign (Sigstore)** 或 registry 原生签名/证明能力;现有 DCT 用户应先盘点依赖、验证替代方案,再制定迁移计划。 -Docker Content Trust 使用 Notary 实现镜像签名,是 Docker 官方的传统签名解决方案。 +Docker Content Trust 使用 Notary v1 实现镜像签名,是 Docker 官方的传统签名解决方案,不建议新项目采用。 **历史用法示例(不建议新项目采用):** @@ -353,17 +365,7 @@ trivy image --scanners vuln,misconfig registry:5000/myapp:latest **Harbor(私有镜像仓库)的安全扫描:** -```yaml -# harbor.yml 配置示例 -trivy: - enabled: true - # 启用镜像扫描 - image_source: "Official" - -# 默认扫描配置 -scan_on_push: true # 推送时自动扫描 -scan_all: true # 扫描仓库中的所有镜像 -``` +Harbor 的扫描器应在管理界面的 **Interrogation Services / Scanner** 中配置;推送自动扫描通常在项目级 **Configuration** 中启用。不要把扫描策略误写成通用 `harbor.yml` 顶层字段。实际部署时应按所用 Harbor 版本文档配置 scanner、项目策略和漏洞阻断阈值。 #### 5. 政策执行 @@ -427,13 +429,33 @@ jobs: if: github.event_name == 'push' uses: sigstore/cosign-installer@v3 - - name: Build Docker image for scan + - name: Login to Registry + if: github.event_name == 'push' + uses: docker/login-action@v4 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Docker image + if: github.event_name == 'push' + id: build-push + uses: docker/build-push-action@v7 + with: + context: . + push: true + tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} + provenance: mode=max + sbom: true + + - name: Build Docker image for pull request scan + if: github.event_name == 'pull_request' uses: docker/build-push-action@v7 with: context: . push: false load: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + tags: local/${{ env.IMAGE_NAME }}:pr - name: Run Trivy vulnerability scan # 安全提醒:2026 年 3 月 19 日 Trivy GitHub Actions 遭受供应链攻击, @@ -441,7 +463,7 @@ jobs: # 使用前请到 https://github.com/aquasecurity/trivy-action/releases 核实 SHA 对应正确版本。 uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 with: - image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + image-ref: ${{ github.event_name == 'push' && format('{0}/{1}@{2}', env.REGISTRY, env.IMAGE_NAME, steps.build-push.outputs.digest) || format('local/{0}:pr', env.IMAGE_NAME) }} format: 'sarif' output: 'trivy-results.sarif' severity: 'HIGH,CRITICAL' @@ -454,7 +476,7 @@ jobs: - name: Generate SBOM uses: anchore/sbom-action@v0 with: - image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + image: ${{ github.event_name == 'push' && format('{0}/{1}@{2}', env.REGISTRY, env.IMAGE_NAME, steps.build-push.outputs.digest) || format('local/{0}:pr', env.IMAGE_NAME) }} format: cyclonedx-json output-file: sbom-cyclonedx.json @@ -464,23 +486,6 @@ jobs: name: sbom path: sbom-cyclonedx.json - - name: Login to Registry and Push - if: github.event_name == 'push' - uses: docker/login-action@v4 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Push image - if: github.event_name == 'push' - id: build-push - uses: docker/build-push-action@v7 - with: - context: . - push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest - - name: Sign image with Cosign if: github.event_name == 'push' run: | @@ -529,7 +534,9 @@ generate:sbom: - syft docker-archive://image.tar -o cyclonedx > sbom.xml artifacts: reports: - sbom: sbom.xml + cyclonedx: sbom.xml + +# 如需让 GitLab 安全面板摄取容器扫描结果,应输出 GitLab 兼容的 container_scanning 报告。 push: stage: push diff --git a/19_observability/19.1_prometheus.md b/19_observability/19.1_prometheus.md index 51424fa..7eb07ae 100644 --- a/19_observability/19.1_prometheus.md +++ b/19_observability/19.1_prometheus.md @@ -66,7 +66,7 @@ services: - ./rules.yml:/etc/prometheus/rules.yml - prometheus_data:/prometheus ports: - - "9090:9090" + - "127.0.0.1:9090:9090" command: - --config.file=/etc/prometheus/prometheus.yml - --storage.tsdb.path=/prometheus @@ -77,9 +77,9 @@ services: grafana: image: grafana/grafana:13.0.1 ports: - - "3000:3000" + - "127.0.0.1:3000:3000" environment: - - GF_SECURITY_ADMIN_PASSWORD=admin + - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:?set GRAFANA_ADMIN_PASSWORD} networks: - monitoring depends_on: @@ -88,14 +88,14 @@ services: node-exporter: image: prom/node-exporter:v1.11.1 ports: - - "9100:9100" + - "127.0.0.1:9100:9100" networks: - monitoring cadvisor: image: ghcr.io/google/cadvisor:v0.56.2 ports: - - "8080:8080" + - "127.0.0.1:8080:8080" volumes: - /:/rootfs:ro - /var/run:/var/run:ro @@ -119,7 +119,9 @@ $ docker compose up -d 启动后,访问以下地址: * Prometheus: `http://localhost:9090` -* Grafana:`http://localhost:3000` (默认账号密码:admin/admin,首次登录后务必立即修改密码) +* Grafana:`http://localhost:3000` (账号为 `admin`,密码来自 `GRAFANA_ADMIN_PASSWORD`) + +> 安全提示:cAdvisor 需要读取宿主机 `/sys`、`/var/run`、Docker 数据目录等路径才能采集容器指标;即使是只读挂载,也会暴露宿主机和容器元数据。只在受控监控节点使用,并把 Prometheus、Grafana、cAdvisor 端口绑定到本机或受保护网络。 ### 19.1.3 配置 Grafana 面板 diff --git a/19_observability/19.2_elk.md b/19_observability/19.2_elk.md index 8b441c7..548cd15 100644 --- a/19_observability/19.2_elk.md +++ b/19_observability/19.2_elk.md @@ -42,8 +42,6 @@ services: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 ports: - "5601:5601" - links: - - elasticsearch networks: - logging @@ -59,8 +57,6 @@ services: ports: - "24224:24224" - "24224:24224/udp" - links: - - elasticsearch volumes: - ./fluentd/conf:/fluentd/etc networks: diff --git a/19_observability/19.3_performance_optimization.md b/19_observability/19.3_performance_optimization.md index 7e4f4cf..9a2ead8 100644 --- a/19_observability/19.3_performance_optimization.md +++ b/19_observability/19.3_performance_optimization.md @@ -6,44 +6,18 @@ #### 核心性能指标体系 -容器性能监控涉及以下关键指标: +容器性能监控涉及 Docker CLI、Prometheus/cAdvisor 指标和底层 cgroup 文件。现代 Linux 与 Kubernetes 新版本通常使用 cgroup v2;旧系统或兼容环境仍可能看到 cgroup v1 名称。 -**CPU 相关指标:** - -- `cpu.usage_usec`:容器 CPU 使用时间(微秒) -- `cpu.stat.nr_throttled`:CPU 限流发生次数 -- `cpu.stat.throttled_usec`:CPU 限流总时间 -- `cpu_percent`:CPU 使用百分比 -- `cpu_quota`:CPU 配额设置(微秒) - -**内存相关指标:** - -- `memory.usage_bytes`:当前内存使用量 -- `memory.max_usage_bytes`:内存使用峰值 -- `memory.limit_in_bytes`:内存限制 -- `memory.fail_cnt`:OOM(Out of Memory)失败次数 -- `memory.stat.cache`:页面缓存占用 -- `memory.stat.rss`:实际内存占用(RSS) -- `memory.stat.swap`:SWAP 使用量 - -**网络相关指标:** - -- `rx_bytes`:接收字节数 -- `tx_bytes`:发送字节数 -- `rx_packets`:接收包数 -- `tx_packets`:发送包数 -- `rx_errors`:接收错误数 -- `tx_errors`:发送错误数 -- `rx_dropped`:接收丢包数 -- `tx_dropped`:发送丢包数 - -**I/O 相关指标:** - -- `io_service_bytes`:I/O 操作字节数 -- `io_service_time`:I/O 操作耗时 -- `io_queued`:I/O 队列长度 -- `fs_limit_bytes`:文件系统限制 -- `fs_usage_bytes`:文件系统使用量 +| 类型 | Docker / Prometheus 常见指标 | cgroup v2 文件 | cgroup v1 兼容名 | +|------|------------------------------|----------------|------------------| +| CPU 使用 | `CPU %`、`container_cpu_usage_seconds_total` | `cpu.stat` 中的 `usage_usec` | `cpuacct.usage` | +| CPU 限流 | `container_cpu_cfs_throttled_periods_total` | `cpu.stat` 中的 `nr_throttled`、`throttled_usec` | `cpu.stat.nr_throttled`、`cpu.stat.throttled_time` | +| 内存使用 | `MEM USAGE`、`container_memory_working_set_bytes` | `memory.current` | `memory.usage_in_bytes` | +| 内存限制 | `MEM USAGE / LIMIT` | `memory.max` | `memory.limit_in_bytes` | +| OOM 次数 | `container_oom_events_total` 或运行时事件 | `memory.events` 中的 `oom` / `oom_kill` | `memory.failcnt` | +| 网络收发 | `NET I/O`、`container_network_receive_bytes_total` / `transmit_bytes_total` | 网络命名空间接口计数 | `rx_bytes` / `tx_bytes` | +| 块 I/O | `BLOCK I/O`、`container_fs_*` / `container_blkio_*` | `io.stat` | `blkio.throttle.io_service_bytes` | +| 文件系统 | `container_fs_usage_bytes` / `container_fs_limit_bytes` | 运行时或文件系统采集 | `fs_usage_bytes` / `fs_limit_bytes` | ### 19.3.2 使用 docker stats 实时监控 @@ -246,6 +220,16 @@ networks: ``` **Prometheus 配置文件(prometheus.yml):** +如果需要采集 Docker daemon 自身指标,需要先在 Docker daemon 配置中开启 metrics: + +```json +{ + "metrics-addr": "127.0.0.1:9323" +} +``` + +Prometheus 运行在容器里并使用 `host.docker.internal:9323` 抓取时,daemon 必须监听容器可达的主机地址;若改为 `0.0.0.0:9323`,会把指标端口暴露给更大网络,必须配合防火墙和可信网络边界。 + ```yaml global: scrape_interval: 15s diff --git a/21_case_devops/21.2_github_actions.md b/21_case_devops/21.2_github_actions.md index 92815ab..823b107 100644 --- a/21_case_devops/21.2_github_actions.md +++ b/21_case_devops/21.2_github_actions.md @@ -72,6 +72,8 @@ jobs: ghcr.io/${{ github.repository }}:latest cache-from: type=gha cache-to: type=gha,mode=max + provenance: mode=max + sbom: true ``` 关键说明: @@ -79,6 +81,7 @@ jobs: * `docker/login-action` 负责认证,支持 Docker Hub、GHCR、ECR 等主流 Registry。 * `cache-from` / `cache-to` 使用 GitHub Actions 原生缓存(`type=gha`),无需额外配置即可加速增量构建。 * 标签同时使用 commit hash 和 `latest`,兼顾版本追溯与部署便利。 +* `provenance: mode=max` 和 `sbom: true` 会把构建来源证明和 SBOM 附加到推送的镜像上;只做本地 `load: true` 的构建无法完整保留这些 attestation。 ### 21.2.3 最佳实践 diff --git a/21_case_devops/21.3_drone.md b/21_case_devops/21.3_drone.md index 98616a7..fef8046 100644 --- a/21_case_devops/21.3_drone.md +++ b/21_case_devops/21.3_drone.md @@ -7,6 +7,8 @@ 本小节以 `GitHub` + `Drone` 来演示 `Drone` 的工作流程。 当然在实际开发过程中,你的代码也许不在 GitHub 托管,那么你可以尝试使用 `Gogs` + `Drone` 来进行 CI/CD。 +> 安全提示:Docker runner 如果挂载宿主机 `/var/run/docker.sock`,流水线就具备近似宿主机 root 的控制能力。下面配置只适合可信代码、单租户、本地演示环境;生产环境应使用隔离的临时 runner/虚拟机、Kubernetes runner、rootless 方案或更严格的权限边界,并为不同项目隔离密钥。 + ### 21.3.1 关联项目 在 GitHub 新建一个名为 `drone-demo` 的仓库。 diff --git a/21_case_devops/21.7_practical_examples.md b/21_case_devops/21.7_practical_examples.md index 23e4d4b..fbe5104 100644 --- a/21_case_devops/21.7_practical_examples.md +++ b/21_case_devops/21.7_practical_examples.md @@ -557,6 +557,8 @@ client-output-buffer-limit pubsub 32mb 8mb 60 **三层微服务架构示例:** +> 下面示例聚焦服务拓扑、网络、健康检查和资源限制。为便于阅读,密码仍通过环境变量串接;生产环境应改用 Compose secrets、外部密钥系统或云厂商密钥服务,并避免把敏感值写入 `DATABASE_URL` / `REDIS_URL`。 + ```yaml services: # 前端服务 @@ -564,7 +566,6 @@ services: build: context: ./frontend dockerfile: Dockerfile - container_name: frontend ports: - "3000:3000" environment: @@ -586,7 +587,6 @@ services: build: context: ./api dockerfile: Dockerfile - container_name: api ports: - "8000:8000" environment: @@ -619,7 +619,6 @@ services: # PostgreSQL 数据库 postgres: image: postgres:16-alpine - container_name: postgres environment: POSTGRES_DB: myappdb POSTGRES_USER: appuser @@ -641,7 +640,6 @@ services: # Redis 缓存 redis: image: redis:8-alpine - container_name: redis command: ["sh", "-c", "redis-server --appendonly yes --requirepass \"$$REDIS_PASSWORD\""] environment: REDIS_PASSWORD: ${REDIS_PASSWORD:?set REDIS_PASSWORD} @@ -659,7 +657,6 @@ services: # Nginx 反向代理 nginx: image: nginx:alpine - container_name: nginx ports: - "80:80" - "443:443" diff --git a/21_case_devops/drone_docker-compose.yml b/21_case_devops/drone_docker-compose.yml index 3b8a100..9ea13f7 100644 --- a/21_case_devops/drone_docker-compose.yml +++ b/21_case_devops/drone_docker-compose.yml @@ -25,6 +25,7 @@ services: depends_on: - drone-server volumes: + # Trusted single-tenant demo only: Docker socket access is host-root equivalent. - /var/run/docker.sock:/var/run/docker.sock:rw environment: - DRONE_RPC_PROTO=http diff --git a/README.md b/README.md index 02cc734..b90d6dd 100644 --- a/README.md +++ b/README.md @@ -48,10 +48,10 @@ graph LR Start[Docker 学习入口] --> Ch1[第1章:Docker 简介] - Ch1 --> Role1["运维新手
第1-4章"] - Ch1 --> Role2["开发者
第1-3章 → 第5-8章"] - Ch1 --> Role3["DevOps 工程师
第1章 → 第9-14章 → 第18章"] - Ch1 --> Role4["架构师
第1章 → 第15-21章"] + Ch1 --> Role1["运维新手
第1-6章"] + Ch1 --> Role2["开发者
第1-8章 → 第11章"] + Ch1 --> Role3["DevOps 工程师
第1-11章 → 第13-14章 → 第18-21章"] + Ch1 --> Role4["架构师
第1-6章 → 第12-17章 → 第18-19章"] Role1 --> End1["掌握基本操作"] Role2 --> End2["构建与部署应用"] @@ -60,14 +60,14 @@ graph LR ``` | 读者角色 | 学习重点 | 核心成果 | |---------|---------|---------| -| **运维新手** | 第1-4章 | 掌握容器的基本概念与操作 | -| **开发者** | 第1-3章 → 第5-8章 | 学会容器化应用的构建与部署 | -| **DevOps 工程师** | 第1章 → 第9-14章 → 第18章 | 实现容器编排与自动化部署流程 | -| **架构师** | 第1章 → 第15-21章 | 设计高可用、高性能的容器基础设施 | +| **运维新手** | 第1-6章 | 掌握容器的基本概念与操作 | +| **开发者** | 第1-8章 → 第11章 | 学会容器化应用的构建与部署 | +| **DevOps 工程师** | 第1-11章 → 第13-14章 → 第18-21章 | 实现容器编排与自动化部署流程 | +| **架构师** | 第1-6章 → 第12-17章 → 第18-19章 | 设计高可用、高性能的容器基础设施 | ## 在线阅读 -本书在线阅读,可直接访问 [GitBook](https://yeasy.gitbook.io/docker_practice/)。也可访问 [GitHub 仓库目录](https://github.com/yeasy/docker_practice/blob/master/SUMMARY.md) 或 [镜像站点](https://vuepress.mirror.docker-practice.com/)。 +本书在线阅读,可直接访问 [GitBook](https://yeasy.gitbook.io/docker_practice/)。也可访问 [GitHub 仓库目录](https://github.com/yeasy/docker_practice/blob/master/SUMMARY.md)。 ## 下载离线版本 diff --git a/SUMMARY.md b/SUMMARY.md index 28737e5..f90a78c 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -129,7 +129,7 @@ * [14.4 Kind - Kubernetes IN Docker](14_kubernetes_setup/14.4_kind.md) * [14.5 K3s - 轻量级 Kubernetes](14_kubernetes_setup/14.5_k3s.md) * [14.6 一步步部署 Kubernetes 集群](14_kubernetes_setup/14.6_systemd.md) - * [14.7 部署 Dashboard](14_kubernetes_setup/14.7_dashboard.md) + * [14.7 可视化管理界面](14_kubernetes_setup/14.7_dashboard.md) * [14.8 Kubernetes 命令行 kubectl](14_kubernetes_setup/14.8_kubectl.md) * [本章小结](14_kubernetes_setup/summary.md) * [第十五章 Etcd 项目](15_etcd/README.md) diff --git a/appendix/best_practices.md b/appendix/best_practices.md index eecff44..6beffdf 100644 --- a/appendix/best_practices.md +++ b/appendix/best_practices.md @@ -1,6 +1,6 @@ ## 附录四:Dockerfile 最佳实践 -本附录是笔者对 Docker 官方文档中 [Best practices for writing Dockerfiles](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/) 的理解与翻译。 +本附录是笔者对 Docker 官方文档中 [Building best practices](https://docs.docker.com/build/building/best-practices/) 的理解与翻译。 ### 一般性的指南和建议 diff --git a/appendix/faq/README.md b/appendix/faq/README.md index 6d29451..497f94c 100644 --- a/appendix/faq/README.md +++ b/appendix/faq/README.md @@ -73,6 +73,8 @@ $ docker network create -d bridge --subnet 172.25.0.0/16 my-net $ docker run --network=my-net --ip=172.25.3.3 -itd --name=my-container busybox ``` +这个固定 IP 主要用于同一 Docker daemon 内的容器间通信。Docker Desktop 上不要依赖宿主机直接访问 Linux 容器 IP;宿主机访问容器服务仍应使用端口映射或 `host.docker.internal` 等机制。 + ### 如何临时退出一个正在交互的容器的终端,而不终止它? 答:按 `Ctrl-p Ctrl-q`。如果按 `Ctrl-c` 往往会让容器内应用进程终止,进而会终止容器。 diff --git a/appendix/learning_roadmap.md b/appendix/learning_roadmap.md index b81d13f..22ac3fd 100644 --- a/appendix/learning_roadmap.md +++ b/appendix/learning_roadmap.md @@ -116,8 +116,8 @@ Docker Compose **学习资源:** - 本书第 4-11 章:进阶篇 -- [Docker 官方最佳实践](https://docs.docker.com/develop/dev-best-practices/) -- [Dockerfile 参考](https://docs.docker.com/engine/reference/builder/) +- [Docker 官方最佳实践](https://docs.docker.com/build/building/best-practices/) +- [Dockerfile 参考](https://docs.docker.com/reference/dockerfile/) **时间投入:** @@ -477,7 +477,7 @@ Kubernetes 进阶 (Week 24-36) # 1. 学习本书第 1-11 章(基础到中级) # 2. 完成 20+ 个实战项目 # 3. 参考官方学习指南 -# 参考 KodeKloud DCA 认证指南:https://kodekloud.com/blog/docker-certified-associate-guide/ +# 参考 Docker 官方学习入口:https://www.docker.com/resources/ # 4. 模拟考试 - Linux Academy DCA 练习题 diff --git a/appendix/repo/redis.md b/appendix/repo/redis.md index 59cd4e6..6b9816c 100644 --- a/appendix/repo/redis.md +++ b/appendix/repo/redis.md @@ -13,7 +13,7 @@ ```bash $ docker run --name some-redis -d -p 6379:6379 redis ``` -另外还可以启用[持久存储](https://redis.io/topics/persistence)。 +另外还可以启用[持久存储](https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/)。 ```bash $ docker run --name some-redis -d -p 6379:6379 redis redis-server --appendonly yes diff --git a/appendix/resources.md b/appendix/resources.md index 5439b23..96104a5 100644 --- a/appendix/resources.md +++ b/appendix/resources.md @@ -24,7 +24,7 @@ * [Docker CLI 参考](https://docs.docker.com/engine/reference/commandline/docker/) * [Dockerfile 参考](https://docs.docker.com/reference/dockerfile/) * [Docker 构建最佳实践](https://docs.docker.com/build/building/best-practices/) -* [Docker 远端应用 API](https://docs.docker.com/develop/sdk/) +* [Docker 远端应用 API](https://docs.docker.com/reference/api/engine/sdk/) * [Docker 存储文档](https://docs.docker.com/engine/storage/) * [Docker 网络文档](https://docs.docker.com/engine/network/) diff --git a/docker-compose.yml b/docker-compose.yml index f29b696..2037c30 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,15 +24,3 @@ services: vuepress-offline: << : *mdpress-offline image: dockerpracticesig/docker_practice:vuepress - - # developer test docker image - - development: - build: ./.travis - image: yeasy/docker_practice:latest - ports: - - 4000:4000 - volumes: - - ./:/srv/gitbook-src - command: server - # command: build