From 63377d04318158da2fc7909bc4280a101cf183d2 Mon Sep 17 00:00:00 2001 From: baohua Date: Mon, 9 Feb 2026 11:34:35 -0800 Subject: [PATCH] Fix and update --- .gitattributes | 2 +- .github/ISSUE_TEMPLATE/Bug_report.md | 3 + .github/ISSUE_TEMPLATE/Custom.md | 3 + .gitignore | 2 + 01_introduction/1.1_quickstart.md | 5 +- 01_introduction/1.2_what.md | 2 + 01_introduction/1.3_why.md | 18 ++++ 01_introduction/README.md | 5 + 02_basic_concept/2.1_image.md | 20 ++++ 02_basic_concept/2.2_container.md | 30 ++++++ 02_basic_concept/2.3_repository.md | 60 +++++++++++- 03_install/3.10_experimental.md | 2 + 03_install/3.1_ubuntu.md | 23 ++++- 03_install/3.2_debian.md | 24 ++++- 03_install/3.3_fedora.md | 26 ++++- 03_install/3.4_centos.md | 27 +++++- 03_install/3.5_raspberry-pi.md | 33 ++++++- 03_install/3.6_offline.md | 37 ++++++- 03_install/3.7_mac.md | 2 + 03_install/3.8_windows.md | 6 +- 03_install/3.9_mirror.md | 4 +- 03_install/README.md | 14 +++ 04_image/4.1_pull.md | 38 ++++++++ 04_image/4.2_list.md | 47 +++++++++ 04_image/4.3_rm.md | 57 ++++++++++- 04_image/4.5_build.md | 7 ++ 04_image/README.md | 14 ++- 04_image/dockerfile/README.md | 2 +- 04_image/dockerfile/add.md | 41 ++++++++ 04_image/dockerfile/arg.md | 49 ++++++++++ 04_image/dockerfile/cmd.md | 57 ++++++++++- 04_image/dockerfile/copy.md | 46 +++++++++ 04_image/dockerfile/entrypoint.md | 47 ++++++++- 04_image/dockerfile/env.md | 52 ++++++++++ 04_image/dockerfile/expose.md | 42 ++++++++ 04_image/dockerfile/healthcheck.md | 19 +++- 04_image/dockerfile/label.md | 15 ++- 04_image/dockerfile/onbuild.md | 18 ++++ 04_image/dockerfile/run.md | 13 +++ 04_image/dockerfile/shell.md | 15 ++- 04_image/dockerfile/user.md | 34 +++++++ 04_image/dockerfile/volume.md | 46 +++++++++ 04_image/dockerfile/workdir.md | 33 +++++++ 04_image/multistage-builds/README.md | 14 +-- 04_image/multistage-builds/laravel.md | 5 + 05_container/5.1_run.md | 30 ++++++ 05_container/5.2_daemon.md | 27 ++++++ 05_container/5.3_stop.md | 45 +++++++++ 05_container/5.4_attach_exec.md | 32 ++++++ 05_container/5.5_import_export.md | 2 + 05_container/5.6_rm.md | 45 +++++++++ 06_repository/6.1_dockerhub.md | 24 ++++- 06_repository/6.2_registry.md | 8 +- 06_repository/6.3_registry_auth.md | 10 +- 06_repository/6.4_nexus3_registry.md | 8 +- 07_data_network/data/README.md | 4 +- 07_data_network/data/bind-mounts.md | 52 +++++++++- 07_data_network/data/volume.md | 62 +++++++++++- 07_data_network/network/README.md | 92 +++++++++++++----- 07_data_network/network/dns.md | 7 +- 07_data_network/network/port_mapping.md | 23 ++++- 08_buildx/8.1_buildkit.md | 11 +++ 08_buildx/8.2_buildx.md | 4 + 08_buildx/8.3_multi-arch-images.md | 16 ++- 08_buildx/README.md | 8 ++ 09_compose/9.2_install.md | 6 +- 09_compose/9.3_usage.md | 22 +++++ 09_compose/9.4_commands.md | 3 + 09_compose/9.5_compose_file.md | 2 + 09_compose/9.6_django.md | 27 ++++++ 09_compose/9.7_rails.md | 19 ++++ 09_compose/9.8_wordpress.md | 7 +- 10_ops/logs/README.md | 6 +- 10_ops/logs/elk.md | 10 +- 10_ops/monitor/README.md | 4 +- 10_ops/monitor/prometheus.md | 8 ++ 10_ops/security/README.md | 118 +++++++++++++++++------ 10_ops/security/kernel_capability.md | 4 + 10_ops/security/kernel_ns.md | 4 + 10_ops/security/other_feature.md | 4 + 10_ops/security/summary.md | 4 + 11_orchestration/etcd/README.md | 2 +- 11_orchestration/etcd/etcdctl.md | 2 + 11_orchestration/etcd/install.md | 5 + 11_orchestration/etcd/intro.md | 2 + 11_orchestration/kubectl/README.md | 38 ++++---- 11_orchestration/kubernetes/README.md | 2 +- 11_orchestration/kubernetes/advanced.md | 4 +- 11_orchestration/kubernetes/concepts.md | 25 +++++ 11_orchestration/kubernetes/design.md | 2 + 11_orchestration/kubernetes/intro.md | 19 ++-- 11_orchestration/kubernetes/practice.md | 2 +- 11_orchestration/setup/README.md | 2 +- 11_orchestration/setup/docker-desktop.md | 2 + 11_orchestration/setup/k3s.md | 8 ++ 11_orchestration/setup/kind.md | 11 ++- 11_orchestration/setup/kubeadm-docker.md | 25 ++++- 11_orchestration/setup/kubeadm.md | 34 ++++++- 12_ecosystem/cloud/README.md | 2 +- 12_ecosystem/cloud/alicloud.md | 2 + 12_ecosystem/cloud/aws.md | 2 + 12_ecosystem/cloud/intro.md | 6 +- 12_ecosystem/cloud/multicloud.md | 8 +- 12_ecosystem/cloud/tencentCloud.md | 2 + 12_ecosystem/coreos/README.md | 2 +- 12_ecosystem/coreos/install.md | 5 + 12_ecosystem/coreos/intro.md | 2 +- 12_ecosystem/podman/README.md | 39 +++++--- 13_implementation/13.1_arch.md | 23 +++-- 13_implementation/13.2_namespace.md | 42 ++++++++ 13_implementation/13.3_cgroups.md | 59 +++++++++++- 13_implementation/13.4_ufs.md | 20 +++- 13_implementation/13.6_network.md | 3 + 14_cases/ci/README.md | 8 +- 14_cases/ci/actions/README.md | 4 +- 14_cases/ci/devops_workflow.md | 14 ++- 14_cases/ci/drone/README.md | 14 +-- 14_cases/ci/drone/install.md | 5 + 14_cases/ide/README.md | 2 +- 14_cases/ide/vsCode.md | 1 + 14_cases/os/README.md | 5 +- 14_cases/os/alpine.md | 7 +- 14_cases/os/busybox.md | 1 + 14_cases/os/centos.md | 8 +- 14_cases/os/debian.md | 10 +- 15_appendix/15.1_best_practices.md | 2 + 15_appendix/15.2_debug.md | 2 + 15_appendix/README.md | 2 +- 15_appendix/command/README.md | 4 +- 15_appendix/command/docker.md | 2 + 15_appendix/command/dockerd.md | 2 +- 15_appendix/faq/README.md | 66 ++++++------- 15_appendix/repo/README.md | 2 +- 15_appendix/repo/nodejs.md | 1 + README.md | 5 +- SUMMARY.md | 22 ++--- 136 files changed, 2146 insertions(+), 262 deletions(-) diff --git a/.gitattributes b/.gitattributes index 5308bd5..ef633d5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,4 @@ -* text=auto +* text=auto eol=lf *.sh text eol=lf diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md index 4db514e..421e28a 100644 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -7,6 +7,7 @@ about: Create a report to help us improve * [ ] Have u googled the problem? If no, pls do that first! ### Environment + @@ -21,6 +22,7 @@ about: Create a report to help us improve * [x] Others (Pls describe below) ### Docker Version + @@ -29,6 +31,7 @@ about: Create a report to help us improve * [x] 1.13.0 or Before ### Problem Description + diff --git a/.github/ISSUE_TEMPLATE/Custom.md b/.github/ISSUE_TEMPLATE/Custom.md index 6db0f8f..7c713ce 100644 --- a/.github/ISSUE_TEMPLATE/Custom.md +++ b/.github/ISSUE_TEMPLATE/Custom.md @@ -7,6 +7,7 @@ about: Create a issue about Docker * [ ] Have u googled the problem? If no, pls do that first! ### Environment + @@ -21,6 +22,7 @@ about: Create a issue about Docker * [x] Others (Pls describe below) ### Docker Version + @@ -29,6 +31,7 @@ about: Create a issue about Docker * [x] 1.13.0 or Before ### Problem Description + diff --git a/.gitignore b/.gitignore index f825f2a..94eaf02 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ docker-compose.override.yml # Editor configs .obsidian/ .vscode/ + +.agent/ \ No newline at end of file diff --git a/01_introduction/1.1_quickstart.md b/01_introduction/1.1_quickstart.md index 15801e4..1961b4a 100644 --- a/01_introduction/1.1_quickstart.md +++ b/01_introduction/1.1_quickstart.md @@ -1,4 +1,4 @@ -## 快速上手 (5分钟) +## 快速上手(5分钟) 本节将通过一个简单的 Web 应用例子,带你快速体验 Docker 的核心流程:构建镜像、运行容器。 @@ -53,12 +53,15 @@ $ docker run -d -p 8080:80 my-hello-world ```bash ## 查看正在运行的容器 ID + $ docker ps ## 停止容器 + $ docker stop ## 删除容器 + $ docker rm ``` diff --git a/01_introduction/1.2_what.md b/01_introduction/1.2_what.md index 908b60b..c072989 100644 --- a/01_introduction/1.2_what.md +++ b/01_introduction/1.2_what.md @@ -1,5 +1,7 @@ ## 什么是 Docker +Docker 是彻底改变了软件开发和交付方式的革命性技术。本节将从核心概念、与传统虚拟机的对比、技术基础以及历史生态等多个维度,带你深入理解什么是 Docker。 + ### 一句话理解 Docker > **Docker 是一种轻量级的虚拟化技术,它让应用程序及其依赖环境可以被打包成一个标准化的单元,在任何地方都能一致地运行。** diff --git a/01_introduction/1.3_why.md b/01_introduction/1.3_why.md index 33a25e0..cb7ec7b 100644 --- a/01_introduction/1.3_why.md +++ b/01_introduction/1.3_why.md @@ -4,8 +4,12 @@ ### 没有 Docker 的世界 +在 Docker 出现之前,软件开发和运维面临着诸多棘手的问题。我们先来看看以下三个典型的痛点场景。 + #### 场景一:"在我电脑上明明能跑" +具体内容如下: + ``` 周五下午 5:00 ├── 开发者:代码写完了,本地测试通过,提交!🎉 @@ -23,6 +27,8 @@ #### 场景二:环境配置的噩梦 +具体内容如下: + ``` 新同事入职 ├── Day 1:领电脑,配环境 @@ -34,6 +40,8 @@ #### 场景三:服务器迁移的恐惧 +具体内容如下: + ``` 运维:"我们需要把服务迁移到新服务器" 开发:"旧服务器上的配置文档在哪?" @@ -43,8 +51,12 @@ ### Docker 如何解决这些问题 +Docker 的出现为上述问题提供了完美的解决方案。它通过"一次构建,到处运行"的核心理念,从根本上改变了软件交付的方式。 + #### 核心理念:一次构建,到处运行 +具体内容如下: + ``` 开发环境 测试环境 生产环境 │ │ │ @@ -59,6 +71,8 @@ ### Docker 的核心优势 +除了解决上述痛点,Docker 还拥有诸多显著的技术优势,包括环境一致性、秒级启动、高效的资源利用等。 + #### 1. 环境一致性 Docker 镜像包含了应用运行所需的**一切**:代码、运行时、系统工具、库、配置。这意味着: @@ -69,9 +83,13 @@ Docker 镜像包含了应用运行所需的**一切**:代码、运行时、系 ```bash ## 新同事入职第一天 + $ git clone https://github.com/company/project.git $ docker compose up ## 完整的开发环境就准备好了 + +具体内容如下: + ``` #### 2. 秒级启动 diff --git a/01_introduction/README.md b/01_introduction/README.md index a415be5..ff35a2b 100644 --- a/01_introduction/README.md +++ b/01_introduction/README.md @@ -4,6 +4,10 @@ ## 本章内容 + +* [快速上手](1.1_quickstart.md) + * 通过一个简单的 Web 应用例子,带你快速体验 Docker 的核心流程:构建镜像、运行容器。 + * [什么是 Docker](1.2_what.md) * 介绍 Docker 的起源、发展历程以及其背后的核心技术(Cgroups, Namespaces, UnionFS)。 * 了解 Docker 是如何改变软件交付方式的。 @@ -12,6 +16,7 @@ * 对比传统虚拟机技术,阐述 Docker 在启动速度、资源利用率、交付效率等方面的巨大优势。 * 探讨 Docker 在 DevOps、微服务架构中的关键作用。 + ## 学习目标 通过本章的学习,你将能够: diff --git a/02_basic_concept/2.1_image.md b/02_basic_concept/2.1_image.md index 32a90d4..a24bfb5 100644 --- a/02_basic_concept/2.1_image.md +++ b/02_basic_concept/2.1_image.md @@ -1,5 +1,9 @@ ## Docker 镜像 +## Docker 镜像 + +Docker 镜像作为容器运行的基石,其设计理念和实现机制至关重要。本节将深入探讨镜像的本质、与操作系统的关系、内容构成以及核心的分层存储机制。 + ### 一句话理解镜像 > **Docker 镜像是一个只读的模板,包含了运行应用所需的一切:代码、运行时、库、环境变量和配置文件。** @@ -46,6 +50,10 @@ Docker 镜像是一个特殊的文件系统,包含: ### 分层存储:镜像的核心设计 +### 分层存储:镜像的核心设计 + +镜像的分层存储机制是 Docker 最具创新性的特性之一。通过 Union FS 技术,Docker 能够高效地构建和管理镜像。 + #### 为什么需要分层? 笔者认为,分层存储是 Docker 最巧妙的设计之一。 @@ -114,16 +122,20 @@ COPY app.conf /etc/nginx/ # 第 4 层:复制配置文件 ```docker ## 错误示范 ❌ + FROM ubuntu:24.04 RUN apt-get update RUN apt-get install -y build-essential # 安装编译工具(约 200MB) RUN make && make install # 编译应用 RUN apt-get remove build-essential # 试图删除编译工具 +## 结果:镜像仍然包含 200MB 的编译工具! + ## 结果:镜像仍然包含 200MB 的编译工具! ``` ```docker ## 正确做法 ✅ + FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y build-essential && \ @@ -132,12 +144,17 @@ RUN apt-get update && \ apt-get autoremove -y && \ rm -rf /var/lib/apt/lists/* ## 在同一层完成安装、使用、清理 + +## 在同一层完成安装、使用、清理 ``` #### 查看镜像的分层 +运行以下命令: + ```bash ## 查看镜像的历史(每层的构建记录) + $ docker history nginx:latest IMAGE CREATED CREATED BY SIZE @@ -159,13 +176,16 @@ Docker 镜像有多种标识方式: ```bash ## 完整格式 + registry.example.com/myproject/myapp:v1.2.3 ## 简写(使用 Docker Hub) + nginx:1.25 ubuntu:24.04 ## 省略标签(默认使用 latest) + nginx # 等同于 nginx:latest ``` diff --git a/02_basic_concept/2.2_container.md b/02_basic_concept/2.2_container.md index 5604560..d53cbbc 100644 --- a/02_basic_concept/2.2_container.md +++ b/02_basic_concept/2.2_container.md @@ -1,5 +1,9 @@ ## Docker 容器 +## Docker 容器 + +容器是 Docker 技术的核心,是应用实际运行的载体。本节将从容器的本质、与虚拟机的区别、存储层机制以及生命周期管理等方面,全面解析 Docker 容器。 + ### 一句话理解容器 > **容器是镜像的运行实例。如果把镜像比作程序,那么容器就是进程。** @@ -69,6 +73,10 @@ ### 容器的存储层 +### 容器的存储层 + +理解容器的存储层机制对于数据的持久化和镜像的优化至关重要。本节将介绍容器的可写层以及 Copy-on-Write 机制。 + #### 镜像层 + 容器层 当容器运行时,Docker 会在镜像的只读层之上创建一个**可写层**(容器存储层): @@ -109,13 +117,17 @@ ```bash ## 创建容器,写入数据 + $ docker run -it ubuntu bash root@abc123:/# echo "important data" > /data.txt root@abc123:/# exit ## 删除容器 + $ docker rm abc123 +## 数据丢了!没有任何办法恢复! + ## 数据丢了!没有任何办法恢复! ``` @@ -130,9 +142,11 @@ $ docker rm abc123 ```bash ## 使用数据卷(推荐) + $ docker run -v mydata:/var/lib/mysql mysql ## 使用绑定挂载 + $ docker run -v /host/path:/container/path nginx ``` @@ -140,6 +154,10 @@ $ docker run -v /host/path:/container/path nginx ### 容器的生命周期 +### 容器的生命周期 + +掌握容器的生命周期对于管理和调试 Docker 应用非常重要。下图展示了容器从创建到删除的完整状态流转。 + ``` ┌──────────────────────────────────────────────────┐ │ 容器生命周期 │ @@ -169,23 +187,30 @@ $ docker run -v /host/path:/container/path nginx #### 常用生命周期命令 +运行以下命令: + ```bash ## 创建并启动容器(最常用) + $ docker run nginx ## 分步操作 + $ docker create nginx # 创建容器(不启动) $ docker start abc123 # 启动容器 ## 停止容器 + $ docker stop abc123 # 优雅停止(发送 SIGTERM,等待后发送 SIGKILL) $ docker kill abc123 # 强制停止(直接发送 SIGKILL) ## 暂停/恢复(不常用,但有时有用) + $ docker pause abc123 # 暂停容器内所有进程 $ docker unpause abc123 # 恢复 ## 删除容器 + $ docker rm abc123 # 删除已停止的容器 $ docker rm -f abc123 # 强制删除运行中的容器 ``` @@ -196,6 +221,9 @@ $ docker rm -f abc123 # 强制删除运行中的容器 ```bash ## 主进程运行,容器运行 + +## 主进程退出,容器停止 + ## 主进程退出,容器停止 ``` @@ -203,9 +231,11 @@ $ docker rm -f abc123 # 强制删除运行中的容器 ```bash ## 这个容器会立即退出(bash 没有输入就退出了) + $ docker run ubuntu ## 这个容器会持续运行(nginx 作为守护进程持续运行) + $ docker run nginx ``` diff --git a/02_basic_concept/2.3_repository.md b/02_basic_concept/2.3_repository.md index 263c980..f511549 100644 --- a/02_basic_concept/2.3_repository.md +++ b/02_basic_concept/2.3_repository.md @@ -1,5 +1,9 @@ ## Docker Registry +## Docker Registry + +Docker Registry 是镜像分发和管理的核心组件。本节将介绍 Registry 的基本概念、公共和私有服务的选择,以及镜像的安全管理。 + ### 一句话理解 Registry > **Docker Registry 是存储和分发 Docker 镜像的服务,类似于代码的 GitHub 或包管理的 npm。** @@ -10,6 +14,14 @@ #### Registry、仓库、标签的关系 +### 核心概念 + +要熟练使用 Docker Registry,首先需要理清它与仓库(Repository)、标签(Tag)之间的关系。 + +#### Registry、仓库、标签的关系 + +Docker Registry 中可以包含多个 Repository,每个 Repository 可以包含多个 Tag。下图清晰地展示了它们之间的层级关系。 + ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Docker Registry │ @@ -39,6 +51,10 @@ #### 镜像的完整名称 +#### 镜像的完整名称 + +一个完整的 Docker 镜像名称由 Registry 地址、用户名/组织名、仓库名和标签组成。了解其结构有助于我们更准确地定位镜像。 + ``` [registry地址/][用户名/]仓库名[:标签] ``` @@ -47,6 +63,7 @@ ```bash ## 完整格式 + registry.example.com/mycompany/myapp:v1.2.3 │ │ │ │ │ │ │ └── 标签 @@ -55,13 +72,16 @@ registry.example.com/mycompany/myapp:v1.2.3 └── Registry 地址 ## Docker Hub 官方镜像(省略 registry 和用户名) + nginx:1.25 ubuntu:24.04 ## Docker Hub 用户镜像 + jwilder/nginx-proxy:latest ## 其他 Registry + ghcr.io/username/myapp:v1.0 gcr.io/google-containers/pause:3.6 ``` @@ -70,6 +90,10 @@ gcr.io/google-containers/pause:3.6 ### 公共 Registry 服务 +### 公共 Registry 服务 + +公共 Registry 服务为开发者提供了便捷的镜像获取途径。其中最著名的是 Docker Hub。 + #### Docker Hub(默认) [Docker Hub](https://hub.docker.com/) 是最大的公共 Registry,也是 Docker 的默认 Registry。 @@ -81,10 +105,12 @@ gcr.io/google-containers/pause:3.6 ```bash ## 从 Docker Hub 拉取镜像 + $ docker pull nginx # 官方镜像 $ docker pull bitnami/redis # 第三方镜像 ## 推送镜像到 Docker Hub + $ docker login $ docker push username/myapp:v1.0 ``` @@ -118,7 +144,9 @@ $ docker push username/myapp:v1.0 ### 私有 Registry -对于企业用户,通常需要搭建私有 Registry 来存储内部镜像。 +出于安全和隐私的考虑,企业往往需要搭建自己的私有 Registry。以下是几种常见的搭建方案。 + +#### 官方 Registry 镜像 #### 官方 Registry 镜像 @@ -126,13 +154,16 @@ Docker 官方提供了 [registry](https://hub.docker.com/_/registry/) 镜像, ```bash ## 启动一个本地 Registry + $ docker run -d -p 5000:5000 --name registry registry:2 ## 推送镜像到本地 Registry + $ docker tag myapp:v1.0 localhost:5000/myapp:v1.0 $ docker push localhost:5000/myapp:v1.0 ## 从本地 Registry 拉取 + $ docker pull localhost:5000/myapp:v1.0 ``` @@ -155,6 +186,14 @@ $ docker pull localhost:5000/myapp:v1.0 #### 完整工作流程 +### 镜像的推送和拉取 + +掌握镜像的推送(Push)和拉取(Pull)是使用 Docker Registry 的基本功。 + +#### 完整工作流程 + +下图展示了从开发环境构建镜像,推送到 Registry,再到生产环境拉取运行的完整流程。 + ``` 开发者机器 Registry 生产服务器 │ │ │ @@ -173,37 +212,50 @@ $ docker pull localhost:5000/myapp:v1.0 #### 常用命令 +运行以下命令: + ```bash ## 登录 Registry + $ docker login # 登录 Docker Hub $ docker login registry.example.com # 登录其他 Registry ## 拉取镜像 + $ docker pull nginx:1.25 ## 标记镜像(准备推送) + $ docker tag myapp:latest registry.example.com/myteam/myapp:v1.0 ## 推送镜像 + $ docker push registry.example.com/myteam/myapp:v1.0 ## 登出 + $ docker logout ``` ### 镜像的安全性 +### 镜像的安全性 + +在使用公共镜像或维护私有镜像时,安全性是不容忽视的重要环节。 + #### 使用官方镜像 Docker Hub 的[官方镜像](https://hub.docker.com/search?q=&type=image&image_filter=official)(标有 "Official Image" 标识)经过 Docker 团队审核,相对更安全。 ```bash ## 官方镜像示例 + nginx # ✅ 官方 mysql # ✅ 官方 redis # ✅ 官方 ## 第三方镜像(需要自行评估可信度) + bitnami/redis # ⚠️ 需要评估 someuser/myapp # ⚠️ 需要评估 ``` @@ -214,19 +266,25 @@ someuser/myapp # ⚠️ 需要评估 ```bash ## 启用镜像签名验证 + $ export DOCKER_CONTENT_TRUST=1 ## 此后的 pull/push 会验证签名 + $ docker pull nginx:latest ``` #### 漏洞扫描 +运行以下命令: + ```bash ## 使用 Docker Scout 扫描镜像漏洞 + $ docker scout cves nginx:latest ## 使用 Trivy(开源工具) + $ trivy image nginx:latest ``` diff --git a/03_install/3.10_experimental.md b/03_install/3.10_experimental.md index 4253e48..c8f7bf5 100644 --- a/03_install/3.10_experimental.md +++ b/03_install/3.10_experimental.md @@ -4,6 +4,8 @@ ### Docker CLI 的实验特性 +CLI 的实验特性通常包含仍在开发中的新功能。幸运的是,在较新版本中这些特性已经更加易用。 + 从 `v20.10` 版本开始,Docker CLI 所有实验特性的命令均默认开启,无需再进行配置或设置系统环境变量。 ### 开启 dockerd 的实验特性 diff --git a/03_install/3.1_ubuntu.md b/03_install/3.1_ubuntu.md index e2c1ea6..d1ec12d 100644 --- a/03_install/3.1_ubuntu.md +++ b/03_install/3.1_ubuntu.md @@ -1,9 +1,17 @@ ## Ubuntu 安装 Docker +## Ubuntu 安装 Docker + +Ubuntu 是 Docker 最常用的运行环境之一。本节将介绍如何在 Ubuntu 系统上安装 Docker,并配置国内镜像加速。 + >警告:切勿在没有配置 Docker APT 源的情况下直接使用 apt 命令安装 Docker. ### 准备工作 +### 准备工作 + +在开始安装之前,我们需要确认系统版本是否满足要求,并清理可能存在的旧版本。 + #### 系统要求 Docker 支持诸多版本的 [Ubuntu](https://ubuntu.com/server) 操作系统。但是较旧的版本上将不会有 Docker 新版本的持续更新,以截至 2026 年初的几个 Ubuntu LTS(Long Term Support,长期支持)版本为例: @@ -57,6 +65,7 @@ $ curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg -- ## 官方源 + ## $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg ``` @@ -69,9 +78,14 @@ $ echo \ ## 官方源 + ## $ echo \ + ## "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ -## $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + +## $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + + ``` >以上命令会添加稳定版本的 Docker APT 镜像源,如果需要测试版本的 Docker 请将 stable 改为 test。 @@ -94,15 +108,20 @@ $ sudo apt install docker-ce docker-ce-cli containerd.io ```bash ## $ curl -fsSL test.docker.com -o get-docker.sh + $ curl -fsSL get.docker.com -o get-docker.sh $ sudo sh get-docker.sh --mirror Aliyun ## $ sudo sh get-docker.sh --mirror AzureChinaCloud + + ``` 执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 的稳定(stable)版本安装在系统中。 ### 启动 Docker +运行以下命令: + ```bash $ sudo systemctl enable docker $ sudo systemctl start docker @@ -128,6 +147,8 @@ $ sudo usermod -aG docker $USER ### 测试 Docker 是否安装正确 +运行以下命令: + ```bash $ docker run --rm hello-world diff --git a/03_install/3.2_debian.md b/03_install/3.2_debian.md index 97c88de..b2ebdc4 100644 --- a/03_install/3.2_debian.md +++ b/03_install/3.2_debian.md @@ -1,9 +1,17 @@ ## Debian 安装 Docker +## Debian 安装 Docker + +Debian 以其稳定性著称,是 Docker 的理想宿主系统。本节将指导你在 Debian 上完成 Docker 的安装。 + >警告:切勿在没有配置 Docker APT 源的情况下直接使用 apt 命令安装 Docker. ### 准备工作 +### 准备工作 + +安装前请仔细检查 Debian 版本支持情况,并卸载旧版本以避免冲突。 + #### 系统要求 Docker 支持以下版本的 [Debian](https://www.debian.org/intro/about) 操作系统: @@ -46,7 +54,10 @@ $ curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | sudo gpg -- ## 官方源 + ## $ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg + + ``` 然后,我们需要向 `sources.list` 中添加 Docker 软件源: @@ -60,9 +71,13 @@ $ echo \ ## 官方源 + ## $ echo \ + ## "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \ -## $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + +## $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + ``` @@ -86,15 +101,20 @@ $ sudo apt-get install docker-ce docker-ce-cli containerd.io ```bash ## $ curl -fsSL test.docker.com -o get-docker.sh + $ curl -fsSL get.docker.com -o get-docker.sh $ sudo sh get-docker.sh --mirror Aliyun ## $ sudo sh get-docker.sh --mirror AzureChinaCloud + + ``` 执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 的稳定(stable)版本安装在系统中。 ### 启动 Docker +运行以下命令: + ```bash $ sudo systemctl enable docker $ sudo systemctl start docker @@ -120,6 +140,8 @@ $ sudo usermod -aG docker $USER ### 测试 Docker 是否安装正确 +运行以下命令: + ```bash $ docker run --rm hello-world diff --git a/03_install/3.3_fedora.md b/03_install/3.3_fedora.md index fd80d6b..38b3720 100644 --- a/03_install/3.3_fedora.md +++ b/03_install/3.3_fedora.md @@ -1,9 +1,17 @@ ## Fedora 安装 Docker +## Fedora 安装 Docker + +Fedora 作为技术前沿的 Linux 发行版,对 Docker 有着良好的支持。本节介绍在 Fedora 上的安装步骤。 + >警告:切勿在没有配置 Docker dnf 源的情况下直接使用 dnf 命令安装 Docker. ### 准备工作 +### 准备工作 + +确保你的 Fedora 版本在支持列表中,并清理旧版本。 + #### 系统要求 Docker 支持以下版本的 [Fedora](https://getfedora.org/) 操作系统: @@ -31,6 +39,10 @@ $ sudo dnf remove docker \ ### 使用 dnf 安装 +### 使用 dnf 安装 + +使用 dnf 包管理器安装是推荐的方式,便于后续的更行和管理。 + 执行以下命令安装依赖包: ```bash @@ -49,9 +61,14 @@ $ sudo dnf config-manager \ $ sudo sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/yum.repos.d/docker-ce.repo ## 官方源 + ## $ sudo dnf config-manager \ + ## --add-repo \ + ## https://download.docker.com/linux/fedora/docker-ce.repo + + ``` 如果需要测试版本的 Docker 请使用以下命令: @@ -87,21 +104,26 @@ $ sudo dnf -y install docker-ce-18.06.1.ce ### 使用脚本自动安装 -在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Debian 系统上可以使用这套脚本安装,另外可以通过 `--mirror` 选项使用国内源进行安装: +在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Fedora 系统上可以使用这套脚本安装,另外可以通过 `--mirror` 选项使用国内源进行安装: > 若你想安装测试版的 Docker, 请从 test.docker.com 获取脚本 ```bash ## $ curl -fsSL test.docker.com -o get-docker.sh + $ curl -fsSL get.docker.com -o get-docker.sh $ sudo sh get-docker.sh --mirror Aliyun ## $ sudo sh get-docker.sh --mirror AzureChinaCloud + + ``` 执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 最新稳定(stable)版本安装在系统中。 ### 启动 Docker +运行以下命令: + ```bash $ sudo systemctl enable docker $ sudo systemctl start docker @@ -127,6 +149,8 @@ $ sudo usermod -aG docker $USER ### 测试 Docker 是否安装正确 +运行以下命令: + ```bash $ docker run --rm hello-world diff --git a/03_install/3.4_centos.md b/03_install/3.4_centos.md index 786e01a..caff8ad 100644 --- a/03_install/3.4_centos.md +++ b/03_install/3.4_centos.md @@ -1,12 +1,20 @@ ## CentOS 安装 Docker +## CentOS 安装 Docker + +CentOS(及其替代品 Rocky Linux、AlmaLinux)是企业级服务器常用的操作系统。本节介绍在这些系统上安装 Docker 的步骤。 + >警告:切勿在没有配置 Docker YUM 源的情况下直接使用 yum 命令安装 Docker. ### 准备工作 +### 准备工作 + +安装前请确认系统版本和内核版本满足 Docker 的运行要求。 + #### 系统要求 -> ⚠️ **重要提示**:CentOS 8 已于 2021 年 12 月 31 日停止维护,CentOS 7 已于 2024 年 6 月 30 日结束支持。建议新项目使用 **Rocky Linux** 或 **AlmaLinux** 作为替代。 +> ⚠️ **重要提示**:CentOS 8 已于 2021 年 12 月 31 日停止维护,CentOS 7 已于 2024 年 6 月 30 日结束支持。建议新项目使用**Rocky Linux**或**AlmaLinux** 作为替代。 Docker 支持 64 位版本 CentOS Stream 9、Rocky Linux 8/9、AlmaLinux 8/9,并且要求内核版本不低于 3.10。 @@ -33,6 +41,10 @@ $ sudo yum remove docker \ ### 使用 yum 安装 +### 使用 yum 安装 + +使用 yum/dnf 安装是管理 Docker 生命周期的标准方式。 + 执行以下命令安装依赖包: ```bash @@ -51,9 +63,14 @@ $ sudo dnf config-manager \ $ sudo sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/dnf.repos.d/docker-ce.repo ## 官方源 + ## $ sudo dnf config-manager \ + ## --add-repo \ + ## https://download.docker.com/linux/centos/docker-ce.repo + + ``` 如果需要测试版本的 Docker 请执行以下命令: @@ -78,6 +95,7 @@ $ sudo dnf install docker-ce docker-ce-cli containerd.io ```bash ## FirewallBackend=nftables + FirewallBackend=iptables ``` @@ -97,15 +115,20 @@ $ firewall-cmd --reload ```bash ## $ curl -fsSL test.docker.com -o get-docker.sh + $ curl -fsSL get.docker.com -o get-docker.sh $ sudo sh get-docker.sh --mirror Aliyun ## $ sudo sh get-docker.sh --mirror AzureChinaCloud + + ``` 执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 的稳定(stable)版本安装在系统中。 ### 启动 Docker +运行以下命令: + ```bash $ sudo systemctl enable docker $ sudo systemctl start docker @@ -131,6 +154,8 @@ $ sudo usermod -aG docker $USER ### 测试 Docker 是否安装正确 +运行以下命令: + ```bash $ docker run --rm hello-world diff --git a/03_install/3.5_raspberry-pi.md b/03_install/3.5_raspberry-pi.md index f7422b0..ed20285 100644 --- a/03_install/3.5_raspberry-pi.md +++ b/03_install/3.5_raspberry-pi.md @@ -1,9 +1,15 @@ ## 树莓派卡片电脑安装 Docker +## 树莓派卡片电脑安装 Docker + +树莓派等 ARM 架构设备在物联网和边缘计算领域应用广泛。本节介绍如何在树莓派上安装 Docker。 + >警告:切勿在没有配置 Docker APT 源的情况下直接使用 apt 命令安装 Docker. ### 系统要求 +Docker 对 ARM 架构有着良好的支持。 + Docker 不仅支持 `x86_64` 架构的计算机,同时也支持 `ARM` 架构的计算机,本小节内容以树莓派单片电脑为例讲解 `ARM` 架构安装 Docker。 Docker 支持以下版本的 [Raspberry Pi OS](https://www.raspberrypi.org/software/operating-systems/) 操作系统: @@ -16,6 +22,8 @@ Docker 支持以下版本的 [Raspberry Pi OS](https://www.raspberrypi.org/softw ### 使用 APT 安装 +推荐使用 APT 包管理器进行安装,以确保版本的稳定性和安全性。 + 由于 apt 源使用 HTTPS 以确保软件下载过程中不被篡改。因此,我们首先需要添加使用 HTTPS 传输的软件包以及 CA 证书。 ```bash @@ -39,7 +47,10 @@ $ curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/raspbian/gpg | sudo apt- ## 官方源 + ## $ curl -fsSL https://download.docker.com/linux/raspbian/gpg | sudo apt-key add - + + ``` 然后,我们需要向 `sources.list` 中添加 Docker 软件源: @@ -52,15 +63,21 @@ $ sudo add-apt-repository \ ## 官方源 + ## $ sudo add-apt-repository \ + ## "deb [arch=armhf] https://download.docker.com/linux/raspbian \ -## $(lsb_release -cs) \ + +## $(lsb_release -cs) \ + ## stable" + + ``` >以上命令会添加稳定版本的 Docker APT 源,如果需要测试版本的 Docker 请将 stable 改为 test。 -##### 报错解决办法 +#### 报错解决办法 在 `Raspberry Pi OS Bullseye/Bookworm` 中,添加 Docker 软件源的步骤可能会出现如下报错: @@ -84,7 +101,10 @@ $ sudo echo "deb [arch=armhf] https://mirrors.aliyun.com/docker-ce/linux/raspbia ## 官方源 -## $ sudo echo "deb [arch=armhf] https://download.docker.com/linux/raspbian $(lsb_release -cs) stable" | sudo tee -a /etc/apt/sources.list + +## $ sudo echo "deb [arch=armhf] https://download.docker.com/linux/raspbian $(lsb_release -cs) stable" | sudo tee -a /etc/apt/sources.list + + ``` #### 安装 Docker @@ -105,15 +125,20 @@ $ sudo apt-get install docker-ce ```bash ## $ curl -fsSL test.docker.com -o get-docker.sh + $ curl -fsSL get.docker.com -o get-docker.sh $ sudo sh get-docker.sh --mirror Aliyun ## $ sudo sh get-docker.sh --mirror AzureChinaCloud + + ``` 执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 的稳定(stable)版本安装在系统中。 ### 启动 Docker +运行以下命令: + ```bash $ sudo systemctl enable docker $ sudo systemctl start docker @@ -139,6 +164,8 @@ $ sudo usermod -aG docker $USER ### 测试 Docker 是否安装正确 +运行以下命令: + ```bash $ docker run --rm hello-world diff --git a/03_install/3.6_offline.md b/03_install/3.6_offline.md index b060004..329c16b 100644 --- a/03_install/3.6_offline.md +++ b/03_install/3.6_offline.md @@ -10,13 +10,17 @@ ### CentOS/Rocky/AlmaLinux 离线安装Docker +在无法连接外网的安全环境中,离线安装是唯一的选择。本节介绍如何在 RHEL 系发行版中进行离线安装。 + > 注意:以下命令以 CentOS 7 为例。对于 CentOS Stream 9、Rocky Linux 9 或 AlmaLinux 9,请将 `yum` 替换为 `dnf`,并将软件包后缀 `el7` 替换为 `el9`。 #### YUM本地文件安装(推荐) 推荐这种方式,是因为在生产环境种一般会选定某个指定的文档软件版本使用。 -##### 查询可用的软件版本(A) +##### 查询可用的软件版本(A) + +运行以下命令: ```bash #下载清华的镜像源文件 @@ -43,7 +47,9 @@ docker-ce.x86_64 3:19.03.1-3.el7 docker-ce-stable .... ``` -##### 下载到指定文件夹(A) +##### 下载到指定文件夹(A) + +运行以下命令: ```bash sudo yum install --downloadonly --downloaddir=/tmp/docker24_offline_install/ docker-ce-24.0.4-1.el7 docker-ce-cli-24.0.4-1.el7 @@ -78,7 +84,7 @@ Total exiting because "Download Only" specified ``` -##### 复制到目标服务器之后进入文件夹安装(C-N) +##### 复制到目标服务器之后进入文件夹安装(C-N) * 离线安装时,必须使用rpm命令不检查依赖的方式安装 @@ -86,7 +92,7 @@ exiting because "Download Only" specified rpm -Uvh *.rpm --nodeps --force ``` -##### 锁定软件版本(C-N) +##### 锁定软件版本(C-N) **下载锁定版本软件** @@ -147,15 +153,20 @@ sudo yum versionlock delete all ##### 挂载 ISO 镜像搭建本地 File 源(AB) +运行以下命令: + ```bash ## 删除其他网络源 + rm -f /etc/yum.repo.d/* ## 挂载光盘或者iso镜像 + mount /dev/cdrom /mnt ``` ```bash ## 添加本地源 + cat >/etc/yum.repos.d/local_files.repo<< EOF [Local_Files] name=Local_Files @@ -168,20 +179,27 @@ EOF ```bash ## 测试刚才的本地源,安装createrepo软件 + yum clean all yum install createrepo -y ``` ##### 根据本地文件搭建BASE网络源(B) +运行以下命令: + ```bash ## 安装apache 服务器 + yum install httpd -y ## 挂载光盘 + mount /dev/cdrom /mnt ## 新建centos目录 + mkdir /var/www/html/base ## 复制光盘内的文件到刚才新建的目录 + cp -R /mnt/Packages/* /var/www/html/base/ createrepo /var/www/html/centos/ systemctl enable httpd @@ -194,14 +212,17 @@ systemctl start httpd ```bash ## 下载清华的镜像源文件 + wget -O /etc/yum.repos.d/docker-ce.repo https://download.docker.com/linux/centos/docker-ce.repo sudo sed -i 's+download.docker.com+mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo ``` ```bash ## 新建 docker-ce目录 + mkdir /tmp/docker-ce/ ## 把镜像源同步到镜像文件中 + reposync -r docker-ce-stable -p /tmp/docker-ce/ ``` @@ -211,18 +232,23 @@ reposync -r docker-ce-stable -p /tmp/docker-ce/ ```bash ## 把docker-ce 文件夹复制到/var/www/html/docker-ce + ## 重建索引 + createrepo /var/www/html/docker-ce/ ``` ##### YUM 客户端设置(C...N) +运行以下命令: + ```bash rm -f /etc/yum.repo.d/* cat >/etc/yum.repos.d/local_files.repo<< EOF [local_base] name=local_base ## 改成B服务器地址 + baseurl=http://x.x.x.x/base enable=1 gpgcheck=0 @@ -230,6 +256,7 @@ proxy=_none_ [docker_ce] name=docker_ce ## 改成B服务器地址 + baseurl=http://x.x.x.x/base enable=1 gpgcheck=0 @@ -240,6 +267,8 @@ EOF ##### Docker 安装(C...N) +运行以下命令: + ```bash sudo yum makecache fast sudo yum install docker-ce docker-ce-cli containerd.io diff --git a/03_install/3.7_mac.md b/03_install/3.7_mac.md index 8c09ded..1c9ed93 100644 --- a/03_install/3.7_mac.md +++ b/03_install/3.7_mac.md @@ -6,6 +6,8 @@ ### 安装 +Docker Desktop 为 Mac 用户提供了无缝的 Docker 体验。你可以选择使用 Homebrew 或手动下载安装包进行安装。 + #### 使用 Homebrew 安装 [Homebrew](https://brew.sh/) 的 [Cask](https://github.com/Homebrew/homebrew-cask) 已经支持 Docker Desktop for Mac,因此可以很方便的使用 Homebrew Cask 来进行安装: diff --git a/03_install/3.8_windows.md b/03_install/3.8_windows.md index 4baf68d..a9eb565 100644 --- a/03_install/3.8_windows.md +++ b/03_install/3.8_windows.md @@ -1,5 +1,7 @@ ## Windows 10/11 +在 Windows 平台上,Docker Desktop 提供了完整的 Docker 开发环境。本节介绍在 Windows 10/11 上的安装和配置。 + ### 系统要求 [Docker Desktop for Windows](https://docs.docker.com/docker-for-windows/install/) 支持 64 位版本的 Windows 11 或 Windows 10(需开启 Hyper-V),推荐使用 Windows 11。 @@ -12,7 +14,7 @@ 下载好之后双击 `Docker Desktop Installer.exe` 开始安装。 -**使用** [**winget**](https://docs.microsoft.com/zh-cn/windows/package-manager/) **安装** +**使用**[**winget**](https://docs.microsoft.com/zh-cn/windows/package-manager/)**安装** ```powershell $ winget install Docker.DockerDesktop @@ -24,7 +26,7 @@ $ winget install Docker.DockerDesktop ### 运行 -在 Windows 搜索栏输入 **Docker** 点击 **Docker Desktop** 开始运行。 +在 Windows 搜索栏输入 **Docker**点击**Docker Desktop** 开始运行。 ![](../_images/install-win-docker-app-search.png) diff --git a/03_install/3.9_mirror.md b/03_install/3.9_mirror.md index be30fad..ae337ff 100644 --- a/03_install/3.9_mirror.md +++ b/03_install/3.9_mirror.md @@ -6,6 +6,8 @@ ### 推荐配置方案 +针对不同的使用场景,我们推荐以下几种镜像加速配置方案,以确保最佳的拉取速度。 + 1. **云服务器用户**:优先使用所在云平台提供的内部加速器(见本页末尾) 2. **本地开发用户**:使用阿里云个人加速器或其他可用的公共加速器 3. **代理方案**:如有条件,可配置 HTTP 代理直接访问 Docker Hub @@ -82,7 +84,7 @@ Registry Mirrors: ### `k8s.gcr.io` 镜像 -可以登录 [阿里云 容器镜像服务](https://www.aliyun.com/product/acr?source=5176.11533457&userCode=8lx5zmtu&type=copy) **镜像中心** -> **镜像搜索** 查找。 +可以登录 [阿里云 容器镜像服务](https://www.aliyun.com/product/acr?source=5176.11533457&userCode=8lx5zmtu&type=copy) **镜像中心**->**镜像搜索** 查找。 例如 `k8s.gcr.io/coredns:1.6.7` 镜像可以用 `registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:1.6.7` 代替。 diff --git a/03_install/README.md b/03_install/README.md index 7f51f98..ef06b37 100644 --- a/03_install/README.md +++ b/03_install/README.md @@ -3,3 +3,17 @@ Docker 分为 `stable` `test` 和 `nightly` 三个更新频道。 官方网站上有各种环境下的 [安装指南](https://docs.docker.com/get-docker/),这里主要介绍 Docker 在 `Linux` 、`Windows 10` 和 `macOS` 上的安装。 + +## 详细安装指南 + +* [Ubuntu](3.1_ubuntu.md) +* [Debian](3.2_debian.md) +* [Fedora](3.3_fedora.md) +* [CentOS](3.4_centos.md) +* [Raspberry Pi](3.5_raspberry-pi.md) +* [Linux 离线安装](3.6_offline.md) +* [macOS](3.7_mac.md) +* [Windows 10/11](3.8_windows.md) +* [镜像加速器](3.9_mirror.md) +* [开启实验特性](3.10_experimental.md) + diff --git a/04_image/4.1_pull.md b/04_image/4.1_pull.md index edaab42..10d9b62 100644 --- a/04_image/4.1_pull.md +++ b/04_image/4.1_pull.md @@ -1,5 +1,9 @@ ## 获取镜像 +## 获取镜像 + +从 Docker 镜像仓库获取镜像可谓是 Docker 运作的第一步。本节将介绍如何使用 `docker pull` 命令下载镜像,以及如何理解下载过程。 + ### docker pull 命令 从镜像仓库获取镜像的命令是 `docker pull`: @@ -10,6 +14,10 @@ docker pull [选项] [Registry地址/]仓库名[:标签] #### 镜像名称格式 +#### 镜像名称格式 + +Docker 镜像名称由 Registry 地址、用户名、仓库名和标签组成。其标准格式如下: + ``` docker.io / library / ubuntu : 24.04 ────┬──── ───┬─── ──┬─── ──┬── @@ -27,23 +35,31 @@ Registry地址 用户名 仓库名 标签 #### 示例 +运行以下命令: + ```bash ## 完整格式 + $ docker pull docker.io/library/ubuntu:24.04 ## 省略 Registry(默认 Docker Hub) + $ docker pull library/ubuntu:24.04 ## 省略 library(官方镜像) + $ docker pull ubuntu:24.04 ## 省略标签(默认 latest) + $ docker pull ubuntu ## 拉取第三方镜像 + $ docker pull bitnami/redis:latest ## 从其他 Registry 拉取 + $ docker pull ghcr.io/username/myapp:v1.0 ``` @@ -51,6 +67,10 @@ $ docker pull ghcr.io/username/myapp:v1.0 ### 下载过程解析 +当我们执行 `docker pull` 命令时,Docker 会输出详细的下载进度。让我们以 `ubuntu:24.04` 为例来解析这些信息。 + +运行以下命令: + ```bash $ docker pull ubuntu:24.04 24.04: Pulling from library/ubuntu @@ -93,6 +113,8 @@ docker.io/library/ubuntu:24.04 ### 常用选项 +`docker pull` 命令支持多种选项来满足不同的下载需求,例如下载所有标签、指定平台架构等。 + | 选项 | 说明 | 示例 | |------|------|------| | `--all-tags, -a` | 拉取所有标签 | `docker pull -a ubuntu` | @@ -115,9 +137,11 @@ $ docker pull --platform linux/amd64 nginx ```bash ## 拉取镜像 + $ docker pull ubuntu:24.04 ## 运行容器 + $ docker run -it --rm ubuntu:24.04 bash root@e7009c6ce357:/# cat /etc/os-release PRETTY_NAME="Ubuntu 24.04 LTS" @@ -155,6 +179,8 @@ root@e7009c6ce357:/# exit ```bash $ sudo systemctl restart docker # Linux +## 或在 Docker Desktop 中重启 + ## 或在 Docker Desktop 中重启 ``` @@ -164,8 +190,12 @@ $ sudo systemctl restart docker # Linux ### 验证镜像完整性 +为了确保下载的镜像没有被篡改且内容一致,我们可以校验镜像的摘要(Digest)。 + #### 查看镜像摘要 +运行以下命令: + ```bash $ docker images --digests ubuntu REPOSITORY TAG DIGEST IMAGE ID @@ -186,6 +216,8 @@ $ docker pull ubuntu@sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9 ### 常见问题 +在使用 `docker pull` 过程中,可能会遇到下载速度慢、镜像不存在或磁盘空间不足等问题。以下是一些常见问题的排查思路。 + #### Q: 下载速度很慢 1. 配置镜像加速器 @@ -194,6 +226,8 @@ $ docker pull ubuntu@sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9 #### Q: 提示镜像不存在 +运行以下命令: + ```bash Error: pull access denied, repository does not exist ``` @@ -205,11 +239,15 @@ Error: pull access denied, repository does not exist #### Q: 磁盘空间不足 +运行以下命令: + ```bash ## 清理未使用的镜像 + $ docker image prune ## 清理所有未使用资源 + $ docker system prune ``` diff --git a/04_image/4.2_list.md b/04_image/4.2_list.md index 07c0be0..cb47e32 100644 --- a/04_image/4.2_list.md +++ b/04_image/4.2_list.md @@ -1,5 +1,9 @@ ## 列出镜像 +## 列出镜像 + +在下载了镜像后,我们可以使用 `docker image ls` 命令列出本地主机上的镜像。 + ### 基本用法 查看本地已下载的镜像: @@ -19,6 +23,8 @@ ubuntu noble 329ed837d508 3 days ago 78MB ### 输出字段说明 +`docker image ls` 命令默认输出的列表包含仓库名、标签、镜像 ID、创建时间和占用空间等信息。 + | 字段 | 说明 | |------|------| | **REPOSITORY** | 仓库名 | @@ -35,6 +41,8 @@ ubuntu noble 329ed837d508 3 days ago 78MB ### 理解镜像大小 +Docker 镜像的大小可能与我们通常理解的文件大小有所不同,这涉及到分层存储的概念。 + #### 本地大小 vs Hub 显示大小 | 位置 | 显示大小 | 说明 | @@ -58,6 +66,8 @@ ubuntu:24.04 nginx:latest redis:latest #### 查看实际空间占用 +运行以下命令: + ```bash $ docker system df TYPE TOTAL ACTIVE SIZE RECLAIMABLE @@ -71,10 +81,15 @@ Build Cache 0 0 0B 0B ### 过滤镜像 +随着本地镜像数量的增加,我们需要更有效的方式来查找特定的镜像。Docker 提供了多种过滤方式。 + #### 按仓库名过滤 +运行以下命令: + ```bash ## 列出所有 ubuntu 镜像 + $ docker images ubuntu REPOSITORY TAG IMAGE ID SIZE ubuntu 24.04 329ed837d508 78MB @@ -84,6 +99,8 @@ ubuntu 22.04 a1b2c3d4e5f6 72MB #### 按仓库名和标签过滤 +运行以下命令: + ```bash $ docker images ubuntu:24.04 REPOSITORY TAG IMAGE ID SIZE @@ -102,12 +119,15 @@ ubuntu 24.04 329ed837d508 78MB ```bash ## 列出 nginx 之后创建的镜像 + $ docker images -f since=nginx:latest ## 列出所有带 latest 标签的镜像 + $ docker images -f reference='*:latest' ## 列出带特定 LABEL 的镜像 + $ docker images -f label=maintainer=example@email.com ``` @@ -115,6 +135,8 @@ $ docker images -f label=maintainer=example@email.com ### 虚悬镜像(Dangling Images) +在镜像列表里,你可能会看到一些仓库名和标签都为 `` 的镜像,这类镜像被称为虚悬镜像。 + #### 什么是虚悬镜像 仓库名和标签都显示为 `` 的镜像: @@ -132,11 +154,15 @@ REPOSITORY TAG IMAGE ID SIZE #### 处理虚悬镜像 +运行以下命令: + ```bash ## 列出虚悬镜像 + $ docker images -f dangling=true ## 删除虚悬镜像 + $ docker image prune ``` @@ -144,8 +170,12 @@ $ docker image prune ### 中间层镜像 +除了虚悬镜像,`docker image ls` 默认列出的只是顶层镜像。还有一种镜像是为了加速镜像构建、重复利用资源而存在的中间层镜像。 + #### 查看所有镜像(包含中间层) +运行以下命令: + ```bash $ docker images -a ``` @@ -158,8 +188,12 @@ $ docker images -a ### 格式化输出 +为了配合脚本使用或展示更关注的信息,我们可以使用 `--format` 参数来自定义输出格式。 + #### 只输出 ID +运行以下命令: + ```bash $ docker images -q 5f515359c7f8 @@ -171,20 +205,26 @@ $ docker images -q ```bash ## 删除所有镜像 + $ docker rmi $(docker images -q) ## 删除所有 redis 镜像 + $ docker rmi $(docker images -q redis) ``` #### 显示完整 ID +运行以下命令: + ```bash $ docker images --no-trunc ``` #### 显示摘要 +运行以下命令: + ```bash $ docker images --digests REPOSITORY TAG DIGEST IMAGE ID @@ -197,12 +237,14 @@ nginx latest sha256:b4f0e0bdeb5... e43d811ce2f4 ```bash ## 只显示 ID 和仓库名 + $ docker images --format "{{.ID}}: {{.Repository}}" 5f515359c7f8: redis 05a60462f8ba: nginx 329ed837d508: ubuntu ## 表格形式(带标题) + $ docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" REPOSITORY TAG SIZE redis latest 183MB @@ -226,14 +268,19 @@ ubuntu 24.04 78MB ### 常用命令组合 +运行以下命令: + ```bash ## 列出所有镜像及其大小,按大小排序(需要系统 sort 命令) + $ docker images --format "{{.Size}}\t{{.Repository}}:{{.Tag}}" | sort -h ## 查找大于 500MB 的镜像 + $ docker images --format "{{.Size}}\t{{.Repository}}:{{.Tag}}" | grep -E "^[0-9]+GB|^[5-9][0-9]{2}MB" ## 导出镜像列表 + $ docker images --format "{{.Repository}}:{{.Tag}}" > images.txt ``` diff --git a/04_image/4.3_rm.md b/04_image/4.3_rm.md index 2647f19..25d3ba5 100644 --- a/04_image/4.3_rm.md +++ b/04_image/4.3_rm.md @@ -1,5 +1,7 @@ ## 删除本地镜像 +当不再需要某个镜像时,我们可以将其删除以释放存储空间。本节介绍删除镜像的常用方法。 + ### 基本用法 使用 `docker image rm` 删除本地镜像: @@ -25,6 +27,8 @@ $ docker image rm [选项] <镜像1> [<镜像2> ...] #### 使用短 ID 删除 +运行以下命令: + ```bash $ docker image ls REPOSITORY TAG IMAGE ID SIZE @@ -32,6 +36,7 @@ redis alpine 501ad78535f0 30MB nginx latest e43d811ce2f4 142MB ## 只需输入足够区分的前几位 + $ docker rmi 501 Untagged: redis:alpine Deleted: sha256:501ad78535f0... @@ -39,6 +44,8 @@ Deleted: sha256:501ad78535f0... #### 使用镜像名删除 +运行以下命令: + ```bash $ docker rmi redis:alpine Untagged: redis:alpine @@ -51,11 +58,13 @@ Deleted: sha256:501ad78535f0... ```bash ## 查看镜像摘要 + $ docker images --digests REPOSITORY TAG DIGEST IMAGE ID nginx latest sha256:b4f0e0bdeb5... e43d811ce2f4 ## 使用摘要删除 + $ docker rmi nginx@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228 ``` @@ -63,7 +72,9 @@ $ docker rmi nginx@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b1 ### 理解输出信息 -删除镜像时会看到两类信息:**Untagged** 和 **Deleted** +执行删除命令后,Docker 会输出一系列的操作记录,理解这些信息有助于我们掌握镜像删除的机制。 + +删除镜像时会看到两类信息:**Untagged**和**Deleted** ```bash $ docker rmi redis:alpine @@ -83,6 +94,10 @@ Deleted: sha256:32770d1dcf835f192cafd6b9263b7b597a1778a403a109e2cc2ee866f74adf23 #### 删除流程 +#### 删除流程 + +Docker 会检测镜像是否有容器依赖或其他标签指向,只有在确认为无用资源时才会真正删除存储层。 + ``` docker rmi redis:alpine │ @@ -108,41 +123,55 @@ docker rmi redis:alpine ### 批量删除 +手动一个一个删除镜像非常繁琐,Docker 提供了 `image prune` 命令和 shell 组合命令来实现批量清理。 + #### 删除所有虚悬镜像 虚悬镜像(dangling):没有标签的镜像,通常是旧版本被新版本覆盖后产生的 ```bash ## 查看虚悬镜像 + $ docker images -f dangling=true ## 删除虚悬镜像 + $ docker image prune ## 不提示确认 + $ docker image prune -f ``` #### 删除所有未使用的镜像 +运行以下命令: + ```bash ## 删除所有没有被容器使用的镜像 + $ docker image prune -a ## 保留最近 24 小时的 + $ docker image prune -a --filter "until=24h" ``` #### 按条件删除 +运行以下命令: + ```bash ## 删除所有 redis 镜像 + $ docker rmi $(docker images -q redis) ## 删除 mongo:8.0 之前的所有镜像 + $ docker rmi $(docker images -q -f before=mongo:8.0) ## 删除某个时间之前的镜像 + $ docker image prune -a --filter "until=168h" # 7天前 ``` @@ -150,8 +179,12 @@ $ docker image prune -a --filter "until=168h" # 7天前 ### 删除失败的常见原因 +在删除镜像时,Docker 可能会提示错误并拒绝执行。这通常是为了防止误删正在使用的资源。 + #### 原因一:有容器依赖 +运行以下命令: + ```bash $ docker rmi nginx Error: conflict: unable to remove repository reference "nginx" @@ -162,15 +195,19 @@ Error: conflict: unable to remove repository reference "nginx" ```bash ## 方案1:先删除依赖的容器 + $ docker rm abc123 $ docker rmi nginx ## 方案2:强制删除镜像(容器仍可运行,但无法再创建新容器) + $ docker rmi -f nginx ``` #### 原因二:多个标签指向同一镜像 +运行以下命令: + ```bash $ docker images REPOSITORY TAG IMAGE ID @@ -180,10 +217,17 @@ ubuntu latest ca2b0f26964c # 同一个镜像 $ docker rmi ubuntu:24.04 Untagged: ubuntu:24.04 ## 只是移除标签,镜像仍存在(因为还有 ubuntu:latest 指向它) + +#### 原因二:多个标签指向同一镜像 + +当同一个镜像有多个标签时,`docker rmi` 只是删除指定的标签,不会删除镜像本身。 + ``` #### 原因三:被其他镜像依赖(中间层) +运行以下命令: + ```bash $ docker rmi some_base_image Error: image has dependent child images @@ -207,25 +251,36 @@ Error: image has dependent child images ### 清理策略 +针对不同的环境(开发环境 vs 生产环境),我们应该采用不同的镜像清理策略。 + #### 开发环境 +运行以下命令: + ```bash ## 定期清理虚悬镜像 + $ docker image prune -f ## 一键清理所有未使用资源 + $ docker system prune -a ``` #### CI/CD 环境 +运行以下命令: + ```bash ## 只保留最近使用的镜像 + $ docker image prune -a --filter "until=72h" -f ``` #### 查看空间占用 +运行以下命令: + ```bash $ docker system df TYPE TOTAL ACTIVE SIZE RECLAIMABLE diff --git a/04_image/4.5_build.md b/04_image/4.5_build.md index 513ddba..1fcaffe 100644 --- a/04_image/4.5_build.md +++ b/04_image/4.5_build.md @@ -190,6 +190,7 @@ Sending build context to Docker daemon 2.048 kB ```bash ## $env:DOCKER_BUILDKIT=0 + ## export DOCKER_BUILDKIT=0 $ docker build -t hello-world https://github.com/docker-library/hello-world.git#master:amd64/hello-world @@ -209,6 +210,8 @@ Successfully built 038ad4142d2b #### 用给定的 tar 压缩包构建 +运行以下命令: + ```bash $ docker build http://server/context.tar.gz ``` @@ -217,6 +220,8 @@ $ docker build http://server/context.tar.gz #### 从标准输入中读取 Dockerfile 进行构建 +运行以下命令: + ```bash docker build - < Dockerfile ``` @@ -231,6 +236,8 @@ cat Dockerfile | docker build - #### 从标准输入中读取上下文压缩包进行构建 +运行以下命令: + ```bash $ docker build - < context.tar.gz ``` diff --git a/04_image/README.md b/04_image/README.md index 9aeaed7..171a145 100644 --- a/04_image/README.md +++ b/04_image/README.md @@ -4,10 +4,14 @@ Docker 运行容器前需要本地存在对应的镜像,如果本地不存在该镜像,Docker 会从镜像仓库下载该镜像。 +## 本章内容 + 本章将介绍更多关于镜像的内容,包括: -* 从仓库获取镜像; - -* 管理本地主机上的镜像; - -* 介绍镜像实现的基本原理。 +* [从仓库获取镜像](4.1_pull.md) +* [列出镜像](4.2_list.md) +* [删除本地镜像](4.3_rm.md) +* [利用 commit 理解镜像构成](4.4_commit.md) +* [使用 Dockerfile 定制镜像](4.5_build.md) +* [其它制作镜像的方式](4.6_other.md) +* [镜像的实现原理](4.7_internal.md) diff --git a/04_image/dockerfile/README.md b/04_image/dockerfile/README.md index fa4d01f..15f5d4f 100644 --- a/04_image/dockerfile/README.md +++ b/04_image/dockerfile/README.md @@ -1,3 +1,3 @@ -## Dockerfile 指令详解 +# Dockerfile 指令详解 我们已经介绍了 `FROM`,`RUN`,还提及了 `COPY`, `ADD`,其实 `Dockerfile` 功能很强大,它提供了十多个指令。下面我们继续讲解其他的指令。 diff --git a/04_image/dockerfile/add.md b/04_image/dockerfile/add.md index 1c4d66b..5a25cb0 100644 --- a/04_image/dockerfile/add.md +++ b/04_image/dockerfile/add.md @@ -2,6 +2,8 @@ ### 基本语法 +具体内容如下: + ```docker ADD [选项] <源路径>... <目标路径> ADD [选项] ["<源路径>", ... "<目标路径>"] @@ -31,8 +33,11 @@ ADD [选项] ["<源路径>", ... "<目标路径>"] #### 基本用法 +具体内容如下: + ```docker ## 自动解压 tar.gz 到目标目录 + ADD app.tar.gz /app/ ``` @@ -53,6 +58,8 @@ ADD ubuntu-noble-core-cloudimg-amd64-root.tar.gz / #### 解压过程 +具体内容如下: + ``` ADD app.tar.gz /app/ │ @@ -72,8 +79,11 @@ app.tar.gz 包含: /app/ 目录结果: #### 基本用法 +具体内容如下: + ```docker ## 从 URL 下载文件 + ADD https://example.com/app.zip /app/app.zip ``` @@ -88,12 +98,16 @@ ADD https://example.com/app.zip /app/app.zip #### 推荐替代方案 +具体内容如下: + ```docker ## ❌ 不推荐:使用 ADD 下载 + ADD https://example.com/app.tar.gz /tmp/ RUN tar -xzf /tmp/app.tar.gz -C /app && rm /tmp/app.tar.gz ## ✅ 推荐:使用 RUN + curl + RUN curl -fsSL https://example.com/app.tar.gz | tar -xz -C /app ``` @@ -106,6 +120,8 @@ RUN curl -fsSL https://example.com/app.tar.gz | tar -xz -C /app ### 修改文件所有者 +具体内容如下: + ```docker ADD --chown=node:node app.tar.gz /app/ ADD --chown=1000:1000 files/ /app/ @@ -117,27 +133,36 @@ ADD --chown=1000:1000 files/ /app/ #### ✅ 适合使用 ADD +具体内容如下: + ```docker ## 解压本地 tar 文件 + FROM scratch ADD rootfs.tar.gz / ## 解压应用包 + ADD dist.tar.gz /app/ ``` #### ❌ 不适合使用 ADD +具体内容如下: + ```docker ## 复制普通文件(用 COPY) + ADD package.json /app/ # ❌ COPY package.json /app/ # ✅ ## 下载文件(用 RUN + curl) + ADD https://example.com/file / # ❌ RUN curl -fsSL ... -o /file # ✅ ## 需要保留 tar 不解压(用 COPY) + ADD archive.tar.gz /archives/ # ❌ 会解压 COPY archive.tar.gz /archives/ # ✅ 保持原样 ``` @@ -150,6 +175,7 @@ ADD 可能导致构建缓存失效: ```docker ## 如果 app.tar.gz 内容变化,此层及后续层都需重建 + ADD app.tar.gz /app/ RUN npm install ``` @@ -158,10 +184,12 @@ RUN npm install ```docker ## 先复制依赖文件 + COPY package*.json /app/ RUN npm install ## 再添加应用代码 + ADD app.tar.gz /app/ ``` @@ -171,32 +199,45 @@ ADD app.tar.gz /app/ #### 1. 默认使用 COPY +具体内容如下: + ```docker ## ✅ 大多数场景使用 COPY + COPY . /app/ ``` #### 2. 仅在需要解压时使用 ADD +具体内容如下: + ```docker ## ✅ 自动解压场景 + ADD app.tar.gz /app/ ``` #### 3. 不要用 ADD 下载文件 +具体内容如下: + ```docker ## ❌ 避免 + ADD https://example.com/file.tar.gz /tmp/ ## ✅ 推荐 + RUN curl -fsSL https://example.com/file.tar.gz | tar -xz -C /app ``` #### 4. 解压后清理 +具体内容如下: + ```docker ## 如果需要控制解压过程 + COPY app.tar.gz /tmp/ RUN tar -xzf /tmp/app.tar.gz -C /app && \ rm /tmp/app.tar.gz diff --git a/04_image/dockerfile/arg.md b/04_image/dockerfile/arg.md index 3c670ef..5bc4cd8 100644 --- a/04_image/dockerfile/arg.md +++ b/04_image/dockerfile/arg.md @@ -2,6 +2,8 @@ ### 基本语法 +具体内容如下: + ```docker ARG <参数名>[=<默认值>] ``` @@ -35,22 +37,30 @@ ARG <参数名>[=<默认值>] #### 定义和使用 +具体内容如下: + ```docker ## 定义有默认值的 ARG + ARG NODE_VERSION=20 ## 使用 ARG + FROM node:${NODE_VERSION}-alpine RUN echo "Using Node.js $NODE_VERSION" ``` #### 构建时覆盖 +运行以下命令: + ```bash ## 使用默认值 + $ docker build -t myapp . ## 覆盖默认值 + $ docker build --build-arg NODE_VERSION=18 -t myapp . ``` @@ -60,41 +70,52 @@ $ docker build --build-arg NODE_VERSION=18 -t myapp . #### FROM 之前的 ARG +具体内容如下: + ```docker ## FROM 之前的 ARG 只能用于 FROM 指令 + ARG REGISTRY=docker.io ARG IMAGE_NAME=node FROM ${REGISTRY}/${IMAGE_NAME}:20 ## ❌ 这里无法使用上面的 ARG + RUN echo $REGISTRY # 输出空 ``` #### FROM 之后重新声明 +具体内容如下: + ```docker ARG NODE_VERSION=20 FROM node:${NODE_VERSION}-alpine ## 需要再次声明才能使用 + ARG NODE_VERSION RUN echo "Node version: $NODE_VERSION" ``` #### 多阶段构建中的 ARG +具体内容如下: + ```docker ARG BASE_VERSION=alpine FROM node:20-${BASE_VERSION} AS builder ## 需要重新声明 + ARG NODE_VERSION=20 RUN echo "Building with Node $NODE_VERSION" FROM node:20-${BASE_VERSION} ## 每个阶段都需要重新声明 + ARG NODE_VERSION=20 RUN echo "Running with Node $NODE_VERSION" ``` @@ -105,6 +126,8 @@ RUN echo "Running with Node $NODE_VERSION" #### 1. 控制基础镜像版本 +具体内容如下: + ```docker ARG ALPINE_VERSION=3.19 FROM alpine:${ALPINE_VERSION} @@ -116,6 +139,8 @@ $ docker build --build-arg ALPINE_VERSION=3.18 . #### 2. 设置软件版本 +具体内容如下: + ```docker ARG NGINX_VERSION=1.25.0 @@ -124,6 +149,8 @@ RUN curl -fsSL https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz | tar -x #### 3. 配置构建环境 +具体内容如下: + ```docker ARG BUILD_ENV=production ARG ENABLE_DEBUG=false @@ -137,6 +164,8 @@ RUN if [ "$ENABLE_DEBUG" = "true" ]; then \ #### 4. 配置私有仓库 +具体内容如下: + ```docker ARG NPM_TOKEN @@ -147,6 +176,7 @@ RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc && \ ```bash ## 构建时传入 token + $ docker build --build-arg NPM_TOKEN=xxx . ``` @@ -160,9 +190,11 @@ $ docker build --build-arg NPM_TOKEN=xxx . ARG VERSION=1.0.0 ## 将 ARG 传递给 ENV + ENV APP_VERSION=$VERSION ## 运行时可用 + CMD echo "App version: $APP_VERSION" ``` @@ -181,6 +213,7 @@ Docker 提供了一些预定义的 ARG,无需声明即可使用: ```bash ## 构建时使用代理 + $ docker build --build-arg HTTP_PROXY=http://proxy:8080 . ``` @@ -190,32 +223,48 @@ $ docker build --build-arg HTTP_PROXY=http://proxy:8080 . #### 1. 为 ARG 提供合理默认值 +具体内容如下: + ```docker ## ✅ 好:有默认值 + ARG NODE_VERSION=20 ## ⚠️ 需要每次传入 + ARG NODE_VERSION ``` #### 2. 不要用 ARG 存储敏感信息 +具体内容如下: + ```docker ## ❌ 错误:密码会被记录在镜像历史中 + ARG DB_PASSWORD RUN echo "password=$DB_PASSWORD" > /app/.env ## ✅ 正确:使用 secrets 或运行时环境变量 + +具体内容如下: + ``` #### 3. 使用 ARG 提高构建灵活性 +具体内容如下: + ```docker ARG BASE_IMAGE=python:3.12-slim FROM ${BASE_IMAGE} ## 可以构建不同基础镜像的版本 + ## docker build --build-arg BASE_IMAGE=python:3.11-alpine . + +具体内容如下: + ``` --- diff --git a/04_image/dockerfile/cmd.md b/04_image/dockerfile/cmd.md index e63da2e..34e1f70 100644 --- a/04_image/dockerfile/cmd.md +++ b/04_image/dockerfile/cmd.md @@ -14,12 +14,14 @@ CMD 有三种格式: | 格式 | 语法 | 推荐程度 | |------|------|---------| -| **exec 格式** | `CMD ["可执行文件", "参数1", "参数2"]` | ✅ **推荐** | +| **exec 格式**| `CMD ["可执行文件", "参数1", "参数2"]` | ✅**推荐** | | **shell 格式** | `CMD 命令 参数1 参数2` | ⚠️ 简单场景 | | **参数格式** | `CMD ["参数1", "参数2"]` | 配合 ENTRYPOINT | #### exec 格式(推荐) +具体内容如下: + ```docker CMD ["nginx", "-g", "daemon off;"] CMD ["python", "app.py"] @@ -33,6 +35,8 @@ CMD ["node", "server.js"] #### shell 格式 +具体内容如下: + ```docker CMD echo "Hello World" CMD nginx -g "daemon off;" @@ -42,9 +46,11 @@ CMD nginx -g "daemon off;" ```docker ## 你写的 + CMD echo $HOME ## 实际执行的 + CMD ["sh", "-c", "echo $HOME"] ``` @@ -64,15 +70,23 @@ CMD ["sh", "-c", "echo $HOME"] #### 信号传递问题示例 +具体内容如下: + ```docker ## ❌ shell 格式:docker stop 会超时 + CMD node server.js ## 实际是 sh -c "node server.js" + ## SIGTERM 发给 sh,不会传递给 node ## ✅ exec 格式:docker stop 正常工作 + CMD ["node", "server.js"] ## SIGTERM 直接发给 node + +具体内容如下: + ``` --- @@ -83,6 +97,7 @@ CMD ["node", "server.js"] ```bash ## ubuntu 默认 CMD 是 /bin/bash + $ docker run -it ubuntu # 进入 bash $ docker run ubuntu cat /etc/os-release # 覆盖为 cat 命令 ``` @@ -102,13 +117,18 @@ CMD ["/bin/bash"] + cat /etc/os-release #### 错误示例 +具体内容如下: + ```docker ## ❌ 容器启动后立即退出 + CMD service nginx start ``` #### 原因分析 +具体内容如下: + ``` 1. CMD service nginx start ↓ 被转换为 @@ -125,8 +145,11 @@ CMD service nginx start #### 正确做法 +具体内容如下: + ```docker ## ✅ 让 nginx 在前台运行 + CMD ["nginx", "-g", "daemon off;"] ``` @@ -136,13 +159,16 @@ CMD ["nginx", "-g", "daemon off;"] | 指令 | 用途 | 运行时行为 | |------|------|-----------| -| **CMD** | 默认命令 | `docker run` 参数会**覆盖**它 | -| **ENTRYPOINT** | 入口点 | `docker run` 参数会**追加**到它后面 | +| **CMD**| 默认命令 | `docker run` 参数会**覆盖**它 | +| **ENTRYPOINT**| 入口点 | `docker run` 参数会**追加**到它后面 | #### 单独使用 CMD +具体内容如下: + ```docker ## Dockerfile + CMD ["curl", "-s", "http://example.com"] ``` @@ -153,8 +179,11 @@ $ docker run myimage curl -v ... # 完全覆盖 #### 搭配 ENTRYPOINT +具体内容如下: + ```docker ## Dockerfile + ENTRYPOINT ["curl", "-s"] CMD ["http://example.com"] ``` @@ -172,45 +201,61 @@ $ docker run myimage http://other.com # curl -s http://other.com(参数覆盖 #### 1. 优先使用 exec 格式 +具体内容如下: + ```docker ## ✅ 推荐 + CMD ["python", "app.py"] ## ⚠️ 仅在需要 shell 特性时使用 + CMD ["sh", "-c", "echo $PATH && python app.py"] ``` #### 2. 确保应用在前台运行 +具体内容如下: + ```docker ## ✅ 前台运行 + CMD ["nginx", "-g", "daemon off;"] CMD ["apache2ctl", "-D", "FOREGROUND"] CMD ["java", "-jar", "app.jar"] ## ❌ 不要使用后台服务命令 + CMD service nginx start CMD systemctl start nginx ``` #### 3. 使用双引号 +具体内容如下: + ```docker ## ✅ 正确:双引号 + CMD ["node", "server.js"] ## ❌ 错误:单引号(JSON 不支持) + CMD ['node', 'server.js'] ``` #### 4. 配合 ENTRYPOINT 使用 +具体内容如下: + ```docker ## 用于可配置参数的场景 + ENTRYPOINT ["python", "app.py"] CMD ["--port", "8080"] ## 运行时可以覆盖端口 + $ docker run myapp --port 9000 ``` @@ -229,11 +274,15 @@ CMD ["echo", "second"] # 只有这个生效 #### Q: 如何在 CMD 中使用环境变量? +具体内容如下: + ```docker ## 方法1:使用 shell 格式 + CMD echo "Port is $PORT" ## 方法2:显式使用 sh -c + CMD ["sh", "-c", "echo Port is $PORT"] ``` @@ -243,9 +292,11 @@ CMD ["sh", "-c", "echo Port is $PORT"] ```docker ## ❌ 信号无法传递 + CMD python app.py ## ✅ 信号正确传递 + CMD ["python", "app.py"] ``` diff --git a/04_image/dockerfile/copy.md b/04_image/dockerfile/copy.md index 880310c..8b4a631 100644 --- a/04_image/dockerfile/copy.md +++ b/04_image/dockerfile/copy.md @@ -2,6 +2,8 @@ ### 基本语法 +具体内容如下: + ```docker COPY [选项] <源路径>... <目标路径> COPY [选项] ["<源路径1>", "<源路径2>", ... "<目标路径>"] @@ -15,29 +17,40 @@ COPY [选项] ["<源路径1>", "<源路径2>", ... "<目标路径>"] #### 复制单个文件 +具体内容如下: + ```docker ## 复制文件到指定目录 + COPY package.json /app/ ## 复制文件并重命名 + COPY config.json /app/settings.json ``` #### 复制多个文件 +具体内容如下: + ```docker ## 复制多个指定文件 + COPY package.json package-lock.json /app/ ## 使用通配符 + COPY *.json /app/ COPY src/*.js /app/src/ ``` #### 复制目录 +具体内容如下: + ```docker ## 复制整个目录的内容(不是目录本身) + COPY src/ /app/src/ ``` @@ -75,12 +88,16 @@ COPY app[0-9].js /app/ # app0.js ~ app9.js #### 绝对路径 +具体内容如下: + ```docker COPY app.js /usr/src/app/ ``` #### 相对路径(基于 WORKDIR) +具体内容如下: + ```docker WORKDIR /app COPY package.json ./ # 复制到 /app/package.json @@ -93,6 +110,7 @@ COPY src/ ./src/ # 复制到 /app/src/ ```docker ## /app/config/ 不存在也会自动创建 + COPY settings.json /app/config/ ``` @@ -104,12 +122,15 @@ COPY settings.json /app/config/ ```docker ## 使用用户名和组名 + COPY --chown=node:node package.json /app/ ## 使用 UID 和 GID + COPY --chown=1000:1000 . /app/ ## 只指定用户 + COPY --chown=node . /app/ ``` @@ -127,6 +148,7 @@ COPY 会保留源文件的元数据: ```docker ## start.sh 的可执行权限会被保留 + COPY start.sh /app/ ``` @@ -143,10 +165,12 @@ COPY start.sh /app/ ```docker ## 推荐:使用 COPY + COPY app.tar.gz /app/ RUN tar -xzf /app/app.tar.gz ## ADD 会自动解压(行为不明显,不推荐) + ADD app.tar.gz /app/ ``` @@ -158,8 +182,11 @@ ADD app.tar.gz /app/ #### 从其他构建阶段复制 +具体内容如下: + ```docker ## 构建阶段 + FROM node:20 AS builder WORKDIR /app COPY package*.json ./ @@ -168,14 +195,18 @@ COPY . . RUN npm run build ## 生产阶段 + FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html ``` #### 使用 --link 优化缓存(BuildKit) +具体内容如下: + ```docker ## 使用 --link 后,文件以独立层添加,不依赖前序指令 + COPY --link --from=builder /app/dist /usr/share/nginx/html ``` @@ -192,6 +223,7 @@ COPY --link --from=builder /app/dist /usr/share/nginx/html ```gitignore ## .dockerignore + node_modules .git .env @@ -211,33 +243,47 @@ Dockerfile #### 1. 利用缓存,先复制依赖文件 +具体内容如下: + ```docker ## ✅ 好:先复制依赖定义,再安装,最后复制代码 + COPY package.json package-lock.json ./ RUN npm install COPY . . ## ❌ 差:一次性复制所有文件,代码变更会导致重新 npm install + COPY . . RUN npm install ``` #### 2. 使用 .dockerignore +具体内容如下: + ```docker ## 确保 node_modules 不被复制 + COPY . . ## .dockerignore 中应包含 node_modules + +具体内容如下: + ``` #### 3. 明确复制路径 +具体内容如下: + ```docker ## ✅ 好:明确的路径 + COPY src/ /app/src/ COPY package.json /app/ ## ❌ 差:过于宽泛 + COPY . . ``` diff --git a/04_image/dockerfile/entrypoint.md b/04_image/dockerfile/entrypoint.md index 46973d9..ed34816 100644 --- a/04_image/dockerfile/entrypoint.md +++ b/04_image/dockerfile/entrypoint.md @@ -12,14 +12,16 @@ | 格式 | 语法 | 推荐程度 | |------|------|---------| -| **exec 格式** | `ENTRYPOINT ["可执行文件", "参数1"]` | ✅ **推荐** | +| **exec 格式**| `ENTRYPOINT ["可执行文件", "参数1"]` | ✅**推荐** | | **shell 格式** | `ENTRYPOINT 命令 参数` | ⚠️ 不推荐 | ```docker ## exec 格式(推荐) + ENTRYPOINT ["nginx", "-g", "daemon off;"] ## shell 格式(不推荐) + ENTRYPOINT nginx -g "daemon off;" ``` @@ -38,8 +40,11 @@ ENTRYPOINT nginx -g "daemon off;" #### 行为对比 +具体内容如下: + ```docker ## 只用 CMD + CMD ["curl", "-s", "http://example.com"] ``` @@ -51,6 +56,7 @@ $ docker run myimage curl -v ... # curl -v ...(完全替换) ```docker ## 只用 ENTRYPOINT + ENTRYPOINT ["curl", "-s"] ``` @@ -61,6 +67,7 @@ $ docker run myimage http://example.com # curl -s http://example.com ✓ ```docker ## ENTRYPOINT + CMD 组合(推荐) + ENTRYPOINT ["curl", "-s"] CMD ["http://example.com"] ``` @@ -81,6 +88,8 @@ $ docker run myimage -v http://other.com # curl -s -v http://other.com ✓ #### 使用 CMD 的问题 +具体内容如下: + ```docker FROM ubuntu:24.04 RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* @@ -94,10 +103,15 @@ $ docker run myip # ✓ 正常工作 $ docker run myip -i # ✗ 错误! exec: "-i": executable file not found ## -i 替换了整个 CMD,被当作可执行文件 + +具体内容如下: + ``` #### 使用 ENTRYPOINT 解决 +具体内容如下: + ```docker FROM ubuntu:24.04 RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* @@ -116,6 +130,8 @@ HTTP/1.1 200 OK #### 交互图示 +具体内容如下: + ``` ENTRYPOINT ["curl", "-s", "http://myip.ipip.net"] │ @@ -137,6 +153,8 @@ curl -s http://myip.ipip.net -i #### 实现方式 +具体内容如下: + ```docker FROM redis:7-alpine COPY docker-entrypoint.sh /usr/local/bin/ @@ -151,20 +169,25 @@ CMD ["redis-server"] set -e ## 准备工作 + echo "Initializing..." ## 如果第一个参数是 redis-server,以 redis 用户运行 + if [ "$1" = 'redis-server' ]; then chown -R redis:redis /data exec gosu redis "$@" fi ## 其他命令直接执行 + exec "$@" ``` #### 工作流程 +具体内容如下: + ``` docker run redis docker run redis bash │ │ @@ -187,6 +210,8 @@ docker-entrypoint.sh redis-server docker-entrypoint.sh bash ### 场景三:带参数的应用 +具体内容如下: + ```docker FROM python:3.12-slim WORKDIR /app @@ -199,16 +224,22 @@ CMD ["--host", "0.0.0.0", "--port", "8080"] ```bash ## 使用默认参数 + $ docker run myapp ## 执行: python app.py --host 0.0.0.0 --port 8080 ## 覆盖参数 + $ docker run myapp --host 0.0.0.0 --port 9000 ## 执行: python app.py --host 0.0.0.0 --port 9000 ## 完全不同的参数 + $ docker run myapp --help ## 执行: python app.py --help + +具体内容如下: + ``` --- @@ -219,12 +250,15 @@ $ docker run myapp --help ```bash ## 正常运行 + $ docker run myimage ## 覆盖 ENTRYPOINT 进入 shell 调试 + $ docker run --entrypoint /bin/sh myimage ## 覆盖 ENTRYPOINT 并传入参数 + $ docker run --entrypoint /bin/cat myimage /etc/os-release ``` @@ -248,16 +282,22 @@ $ docker run --entrypoint /bin/cat myimage /etc/os-release #### 1. 使用 exec 格式 +具体内容如下: + ```docker ## ✅ 推荐 + ENTRYPOINT ["python", "app.py"] ## ❌ 避免 shell 格式 + ENTRYPOINT python app.py ``` #### 2. 提供有意义的默认参数 +具体内容如下: + ```docker ENTRYPOINT ["nginx"] CMD ["-g", "daemon off;"] @@ -265,11 +305,14 @@ CMD ["-g", "daemon off;"] #### 3. 入口脚本使用 exec +运行以下命令: + ```bash #!/bin/sh ## 准备工作... ## 使用 exec 替换当前进程 + exec "$@" ``` @@ -282,10 +325,12 @@ exec "$@" trap 'kill -TERM $PID' TERM INT ## 启动应用 + app "$@" & PID=$! ## 等待应用退出 + wait $PID ``` diff --git a/04_image/dockerfile/env.md b/04_image/dockerfile/env.md index f747a80..8050b4a 100644 --- a/04_image/dockerfile/env.md +++ b/04_image/dockerfile/env.md @@ -2,11 +2,15 @@ ### 基本语法 +具体内容如下: + ```docker ## 格式一:单个变量 + ENV ## 格式二:多个变量(推荐) + ENV = = ... ``` @@ -16,6 +20,8 @@ ENV = = ... #### 设置单个变量 +具体内容如下: + ```docker ENV NODE_VERSION 20.10.0 ENV APP_ENV production @@ -23,6 +29,8 @@ ENV APP_ENV production #### 设置多个变量 +具体内容如下: + ```docker ENV NODE_VERSION=20.10.0 \ APP_ENV=production \ @@ -37,23 +45,30 @@ ENV NODE_VERSION=20.10.0 \ #### 1. 后续指令中使用 +具体内容如下: + ```docker ENV NODE_VERSION=20.10.0 ## 在 RUN 中使用 + RUN curl -fsSL https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz \ | tar -xJ -C /usr/local --strip-components=1 ## 在 WORKDIR 中使用 + ENV APP_HOME=/app WORKDIR $APP_HOME ## 在 COPY 中使用 + COPY . $APP_HOME ``` #### 2. 容器运行时使用 +具体内容如下: + ```docker ENV DATABASE_URL=postgres://localhost/mydb ``` @@ -97,19 +112,25 @@ const dbUrl = process.env.DATABASE_URL; ```bash ## 覆盖单个变量 + $ docker run -e APP_ENV=development myimage ## 覆盖多个变量 + $ docker run -e APP_ENV=development -e DEBUG=true myimage ## 从环境变量文件读取 + $ docker run --env-file .env myimage ``` #### .env 文件格式 +运行以下命令: + ```bash ## .env + APP_ENV=development DEBUG=true DATABASE_URL=postgres://localhost/mydb @@ -128,19 +149,25 @@ DATABASE_URL=postgres://localhost/mydb #### 组合使用 +具体内容如下: + ```docker ## ARG 接收构建时参数 + ARG NODE_VERSION=20 ## ENV 保存到运行时 + ENV NODE_VERSION=$NODE_VERSION ## 后续指令使用 + RUN curl -fsSL https://nodejs.org/dist/v${NODE_VERSION}/... ``` ```bash ## 构建时指定版本 + $ docker build --build-arg NODE_VERSION=18 -t myapp . ``` @@ -150,8 +177,11 @@ $ docker build --build-arg NODE_VERSION=18 -t myapp . #### 1. 统一管理版本号 +具体内容如下: + ```docker ## ✅ 好:版本集中管理 + ENV NGINX_VERSION=1.25.0 \ NODE_VERSION=20.10.0 \ PYTHON_VERSION=3.12.0 @@ -159,21 +189,31 @@ ENV NGINX_VERSION=1.25.0 \ RUN apt-get install nginx=${NGINX_VERSION} ## ❌ 差:版本分散在各处 + RUN apt-get install nginx=1.25.0 ``` #### 2. 不要存储敏感信息 +具体内容如下: + ```docker ## ❌ 错误:密码写入镜像 + ENV DB_PASSWORD=secret123 ## ✅ 正确:运行时传入 + ## docker run -e DB_PASSWORD=xxx myimage + +具体内容如下: + ``` #### 3. 为应用提供合理默认值 +具体内容如下: + ```docker ENV APP_ENV=production \ APP_PORT=8080 \ @@ -182,12 +222,16 @@ ENV APP_ENV=production \ #### 4. 使用有意义的变量名 +具体内容如下: + ```docker ## ✅ 好:清晰的命名 + ENV REDIS_HOST=localhost \ REDIS_PORT=6379 ## ❌ 差:模糊的命名 + ENV HOST=localhost \ PORT=6379 ``` @@ -202,14 +246,18 @@ exec 格式不会自动展开环境变量: ```docker ## ❌ 不会展开 $PORT + CMD ["python", "app.py", "--port", "$PORT"] ## ✅ 使用 shell 格式或显式调用 sh + CMD ["sh", "-c", "python app.py --port $PORT"] ``` #### Q: 如何查看容器的环境变量 +运行以下命令: + ```bash $ docker inspect mycontainer --format '{{json .Config.Env}}' $ docker exec mycontainer env @@ -217,13 +265,17 @@ $ docker exec mycontainer env #### Q: 多行 ENV 还是多个 ENV +具体内容如下: + ```docker ## ✅ 推荐:减少层数 + ENV VAR1=value1 \ VAR2=value2 \ VAR3=value3 ## ⚠️ 多个 ENV 会创建多层 + ENV VAR1=value1 ENV VAR2=value2 ENV VAR3=value3 diff --git a/04_image/dockerfile/expose.md b/04_image/dockerfile/expose.md index 966bbff..2f595e8 100644 --- a/04_image/dockerfile/expose.md +++ b/04_image/dockerfile/expose.md @@ -2,6 +2,8 @@ ### 基本语法 +具体内容如下: + ```docker EXPOSE <端口> [<端口>/<协议>...] ``` @@ -12,14 +14,19 @@ EXPOSE <端口> [<端口>/<协议>...] ### 基本用法 +具体内容如下: + ```docker ## 声明单个端口 + EXPOSE 80 ## 声明多个端口 + EXPOSE 80 443 ## 声明 TCP 和 UDP 端口 + EXPOSE 80/tcp EXPOSE 53/udp ``` @@ -34,11 +41,13 @@ EXPOSE 53/udp ```docker ## 使用者一看就知道这是 web 应用 + EXPOSE 80 443 ``` ```bash ## 查看镜像暴露的端口 + $ docker inspect nginx --format '{{.Config.ExposedPorts}}' map[80/tcp:{}] ``` @@ -49,6 +58,7 @@ map[80/tcp:{}] ```docker ## Dockerfile + EXPOSE 80 ``` @@ -87,14 +97,21 @@ $ docker port $(docker ps -q) #### 没有 EXPOSE 也能 -p +具体内容如下: + ```docker ## 即使没有 EXPOSE,也可以使用 -p + FROM nginx ## 没有 EXPOSE + +具体内容如下: + ``` ```bash ## 仍然可以映射端口 + $ docker run -p 8080:80 mynginx ``` @@ -104,8 +121,11 @@ $ docker run -p 8080:80 mynginx #### 误解:EXPOSE 会打开端口 +具体内容如下: + ```docker ## ❌ 错误理解:这不会让容器可从外部访问 + EXPOSE 80 ``` @@ -118,14 +138,18 @@ EXPOSE 只是元数据声明。容器是否实际监听该端口,取决于容 #### 正确理解 +具体内容如下: + ```docker ## Dockerfile + FROM nginx EXPOSE 80 # 1. 声明:这个容器会在 80 端口提供服务 ``` ```bash ## 运行:需要 -p 才能从外部访问 + $ docker run -p 8080:80 nginx # 2. 映射:宿主机 8080 → 容器 80 ``` @@ -135,42 +159,56 @@ $ docker run -p 8080:80 nginx # 2. 映射:宿主机 8080 → 容器 80 #### 1. 总是声明应用使用的端口 +具体内容如下: + ```docker ## Web 服务 + FROM nginx EXPOSE 80 443 ## 数据库 + FROM postgres EXPOSE 5432 ## Redis + FROM redis EXPOSE 6379 ``` #### 2. 使用明确的协议 +具体内容如下: + ```docker ## 默认是 TCP + EXPOSE 80 ## 明确指定 UDP + EXPOSE 53/udp ## 同时支持 TCP 和 UDP + EXPOSE 53/tcp 53/udp ``` #### 3. 与应用实际端口保持一致 +具体内容如下: + ```docker ## ✅ 好:EXPOSE 与应用端口一致 + ENV PORT=3000 EXPOSE 3000 CMD ["node", "server.js"] ## ❌ 差:EXPOSE 与应用端口不一致(误导) + EXPOSE 80 CMD ["node", "server.js"] # 实际监听 3000 ``` @@ -179,6 +217,8 @@ CMD ["node", "server.js"] # 实际监听 3000 ### 使用环境变量 +具体内容如下: + ```docker ARG PORT=80 EXPOSE $PORT @@ -188,6 +228,8 @@ EXPOSE $PORT ### 在 Compose 中 +在 Compose 中 配置如下: + ```yaml services: web: diff --git a/04_image/dockerfile/healthcheck.md b/04_image/dockerfile/healthcheck.md index a4bbc66..e5e79cc 100644 --- a/04_image/dockerfile/healthcheck.md +++ b/04_image/dockerfile/healthcheck.md @@ -2,6 +2,8 @@ ### 基本语法 +具体内容如下: + ```docker HEALTHCHECK [选项] CMD <命令> HEALTHCHECK NONE @@ -36,6 +38,8 @@ Starting ──成功──> Healthy ──失败N次──> Unhealthy #### Web 服务检查 +具体内容如下: + ```docker FROM nginx RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* @@ -80,24 +84,32 @@ HEALTHCHECK NONE ```docker ## 使用 curl + HEALTHCHECK CMD curl -f http://localhost/ || exit 1 -## 使用 wget (Alpine 默认包含) +## 使用 wget(Alpine 默认包含) + HEALTHCHECK CMD wget -q --spider http://localhost/ || exit 1 ``` #### 数据库 +具体内容如下: + ```docker ## MySQL + HEALTHCHECK CMD mysqladmin ping -h localhost || exit 1 ## Redis + HEALTHCHECK CMD redis-cli ping || exit 1 ``` #### 自定义脚本 +具体内容如下: + ```docker COPY healthcheck.sh /usr/local/bin/ HEALTHCHECK CMD ["healthcheck.sh"] @@ -139,14 +151,18 @@ services: ### 查看健康状态 +运行以下命令: + ```bash ## 查看容器状态(包含健康信息) + $ docker ps CONTAINER ID STATUS abc123 Up 1 minute (healthy) def456 Up 2 minutes (unhealthy) ## 查看详细健康日志 + $ docker inspect --format '{{json .State.Health}}' mycontainer | jq { "Status": "healthy", @@ -180,6 +196,7 @@ $ docker inspect --format '{{json .State.Health}}' mycontainer | jq ```docker ## 给应用 1 分钟启动时间 + HEALTHCHECK --start-period=60s CMD curl -f http://localhost/ || exit 1 ``` diff --git a/04_image/dockerfile/label.md b/04_image/dockerfile/label.md index ab0ca5c..affb587 100644 --- a/04_image/dockerfile/label.md +++ b/04_image/dockerfile/label.md @@ -2,6 +2,8 @@ ### 基本语法 +具体内容如下: + ```docker LABEL = = ... ``` @@ -23,6 +25,8 @@ LABEL = = ... #### 定义单个标签 +具体内容如下: + ```docker LABEL version="1.0" LABEL description="这是一个 Web 应用服务器" @@ -30,6 +34,8 @@ LABEL description="这是一个 Web 应用服务器" #### 定义多个标签(推荐) +具体内容如下: + ```docker LABEL maintainer="user@example.com" \ version="1.2.0" \ @@ -41,7 +47,7 @@ LABEL maintainer="user@example.com" \ --- -### 常用标签规范 (OCI Annotations) +### 常用标签规范(OCI Annotations) 为了标准和互操作性,推荐使用 [OCI Image Format Specification](https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys) 定义的标准标签: @@ -59,6 +65,8 @@ LABEL maintainer="user@example.com" \ #### 示例 +具体内容如下: + ```docker LABEL org.opencontainers.image.authors="yeasy" \ org.opencontainers.image.documentation="https://yeasy.gitbooks.io" \ @@ -74,6 +82,7 @@ LABEL org.opencontainers.image.authors="yeasy" \ ```docker ## ❌ 已弃用 + MAINTAINER user@example.com ``` @@ -81,8 +90,10 @@ MAINTAINER user@example.com ```docker ## ✅ 推荐 + LABEL maintainer="user@example.com" ## 或 + LABEL org.opencontainers.image.authors="user@example.com" ``` @@ -130,9 +141,11 @@ $ docker inspect nginx --format '{{json .Config.Labels}}' | jq ```bash ## 列出作者是 yeasy 的所有镜像 + $ docker images --filter "label=org.opencontainers.image.authors=yeasy" ## 删除所有带有特定标签的镜像 + $ docker rmi $(docker images -q --filter "label=stage=builder") ``` diff --git a/04_image/dockerfile/onbuild.md b/04_image/dockerfile/onbuild.md index e3c2de6..2aca9a3 100644 --- a/04_image/dockerfile/onbuild.md +++ b/04_image/dockerfile/onbuild.md @@ -2,6 +2,8 @@ ### 基本语法 +具体内容如下: + ```docker ONBUILD <其它指令> ``` @@ -34,6 +36,7 @@ FROM node:20-alpine WORKDIR /app ## 这些指令将在子镜像构建时执行 + ONBUILD COPY package*.json ./ ONBUILD RUN npm install ONBUILD COPY . . @@ -46,13 +49,19 @@ CMD ["npm", "start"] ```docker FROM my-node-base ## 只需要一行! + ## 构建时会自动执行 COPY 和 RUN + +具体内容如下: + ``` --- ### 执行机制 +具体内容如下: + ``` 基础镜像构建: Dockerfile (含 ONBUILD) ──build──> 基础镜像 (记录了 ONBUILD 触发器) @@ -68,24 +77,33 @@ FROM 基础镜像 ──build──> 读取基础镜像触发器 ──> 执行 #### 1. 自动处理依赖安装 +具体内容如下: + ```docker ## Python 基础镜像 + ONBUILD COPY requirements.txt ./ ONBUILD RUN pip install -r requirements.txt ``` #### 2. 自动编译代码 +具体内容如下: + ```docker ## Go 基础镜像 + ONBUILD COPY . . ONBUILD RUN go build -o app main.go ``` #### 3. 处理静态资源 +具体内容如下: + ```docker ## Nginx 静态网站基础镜像 + ONBUILD COPY dist/ /usr/share/nginx/html/ ``` diff --git a/04_image/dockerfile/run.md b/04_image/dockerfile/run.md index 29871aa..4ed5d96 100644 --- a/04_image/dockerfile/run.md +++ b/04_image/dockerfile/run.md @@ -2,6 +2,8 @@ ### 基本语法 +具体内容如下: + ```docker RUN RUN ["executable", "param1", "param2"] @@ -15,6 +17,8 @@ RUN ["executable", "param1", "param2"] #### 1. Shell 格式 +具体内容如下: + ```docker RUN apt-get update ``` @@ -28,6 +32,8 @@ RUN apt-get update #### 2. Exec 格式 +具体内容如下: + ```docker RUN ["apt-get", "update"] ``` @@ -82,6 +88,7 @@ RUN apt-get update && \ ```docker ## 如果下载失败,gzip 可能会报错,但如果不影响后续,构建可能继续 + RUN wget http://error-url | gzip -d > file ``` @@ -98,6 +105,8 @@ RUN wget http://url | gzip -d > file #### Q: 为什么 `RUN cd /app` 不生效? +具体内容如下: + ```docker RUN cd /app RUN touch hello.txt @@ -116,6 +125,8 @@ RUN touch hello.txt #### Q: 环境变量不生效? +具体内容如下: + ```docker RUN export MY_VAR=hello RUN echo $MY_VAR @@ -142,6 +153,7 @@ BuildKit 支持在 `RUN` 指令中使用 `--mount` 挂载缓存,加速构建 ```docker ## 缓存 apt 包 + RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \ apt-get update && apt-get install -y gcc @@ -149,6 +161,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ ```docker ## 缓存 Go 模块 + RUN --mount=type=cache,target=/go/pkg/mod \ go build -o app ``` diff --git a/04_image/dockerfile/shell.md b/04_image/dockerfile/shell.md index 5a9dd70..bfce1f4 100644 --- a/04_image/dockerfile/shell.md +++ b/04_image/dockerfile/shell.md @@ -2,6 +2,8 @@ ### 基本语法 +具体内容如下: + ```docker SHELL ["executable", "parameters"] ``` @@ -24,18 +26,21 @@ SHELL ["executable", "parameters"] FROM ubuntu:24.04 ## 切换到 bash + SHELL ["/bin/bash", "-c"] ## 现在可以使用 bash 特性了 + RUN echo {a..z} ``` -#### 2. 增强错误处理 (pipefail) +#### 2. 增强错误处理(pipefail) 默认情况下,管道命令 `cmd1 | cmd2` 只要 `cmd2` 成功,整个指令就视为成功。这可能掩盖构建错误。 ```docker ## ❌ 这里的 wget 失败了,但构建继续(因为 tar 成功了) + RUN wget -O - https://invalid-url | tar xz ``` @@ -43,9 +48,11 @@ RUN wget -O - https://invalid-url | tar xz ```docker ## ✅ 启用 pipefail + SHELL ["/bin/bash", "-o", "pipefail", "-c"] ## 如果 wget 失败,整个 RUN 就会失败 + RUN wget -O - https://invalid-url | tar xz ``` @@ -57,13 +64,16 @@ RUN wget -O - https://invalid-url | tar xz FROM mcr.microsoft.com/windows/servercore:ltsc2022 ## 默认是 cmd + RUN echo Default shell is cmd ## 切换到 powershell + SHELL ["powershell", "-command"] RUN Write-Host "Hello from PowerShell" ## 切回 cmd + SHELL ["cmd", "/S", "/C"] ``` @@ -77,14 +87,17 @@ SHELL ["cmd", "/S", "/C"] FROM ubuntu:24.04 ## 使用默认 sh + RUN echo "Using sh" SHELL ["/bin/bash", "-c"] ## 使用 bash + RUN echo "Using bash" SHELL ["/bin/sh", "-c"] ## 回到 sh + RUN echo "Using sh again" ``` diff --git a/04_image/dockerfile/user.md b/04_image/dockerfile/user.md index 068aaa6..99aa978 100644 --- a/04_image/dockerfile/user.md +++ b/04_image/dockerfile/user.md @@ -2,6 +2,8 @@ ### 基本语法 +具体内容如下: + ```docker USER <用户名>[:<用户组>] USER [:] @@ -37,28 +39,37 @@ root 用户运行的风险: #### 创建并切换用户 +具体内容如下: + ```docker FROM node:20-alpine ## 1. 创建用户和组 + RUN addgroup -g 1001 appgroup && \ adduser -u 1001 -G appgroup -D appuser ## 2. 设置目录权限 + WORKDIR /app COPY --chown=appuser:appgroup . . ## 3. 切换用户 + USER appuser ## 4. 后续命令以 appuser 身份运行 + CMD ["node", "server.js"] ``` #### 使用 UID/GID +具体内容如下: + ```docker ## 也可以使用数字 + USER 1001:1001 ``` @@ -70,10 +81,12 @@ USER 1001:1001 ```docker ## ❌ 错误:用户不存在 + USER nonexistent ## Error: unable to find user nonexistent ## ✅ 正确:先创建用户 + RUN useradd -r -s /bin/false appuser USER appuser ``` @@ -114,9 +127,11 @@ RUN addgroup -g 1001 -S appgroup && \ FROM debian:bookworm ## 创建用户 + RUN groupadd -r redis && useradd -r -g redis redis ## 安装 gosu + RUN apt-get update && apt-get install -y gosu && rm -rf /var/lib/apt/lists/* COPY docker-entrypoint.sh /usr/local/bin/ @@ -131,9 +146,11 @@ CMD ["redis-server"] set -e ## 以 root 执行初始化 + chown -R redis:redis /data ## 用 gosu 切换到 redis 用户运行服务 + exec gosu redis "$@" ``` @@ -154,9 +171,11 @@ exec gosu redis "$@" ```bash ## 以指定用户运行 + $ docker run -u 1001:1001 myimage ## 以 root 运行(调试时) + $ docker run -u root myimage ``` @@ -170,15 +189,19 @@ $ docker run -u root myimage FROM node:20-alpine ## 创建用户 + RUN adduser -D -u 1001 appuser WORKDIR /app ## 方式1:使用 --chown + COPY --chown=appuser:appuser . . ## 方式2:手动 chown(减少层数) + ## COPY . . + ## RUN chown -R appuser:appuser /app USER appuser @@ -191,13 +214,17 @@ CMD ["node", "server.js"] #### 1. 始终使用非 root 用户 +具体内容如下: + ```docker ## ✅ 推荐 + RUN adduser -D appuser USER appuser CMD ["myapp"] ## ❌ 避免 + CMD ["myapp"] # 以 root 运行 ``` @@ -207,6 +234,7 @@ CMD ["myapp"] # 以 root 运行 ```docker ## 使用常见的非 root UID + RUN addgroup -g 1000 -S appgroup && \ adduser -u 1000 -S -G appgroup appuser USER 1000:1000 @@ -214,14 +242,18 @@ USER 1000:1000 #### 3. 多阶段构建中的 USER +具体内容如下: + ```docker ## 构建阶段可以用 root + FROM node:20 AS builder WORKDIR /app COPY . . RUN npm install && npm run build ## 生产阶段用非 root + FROM node:20-alpine RUN adduser -D appuser WORKDIR /app @@ -236,6 +268,8 @@ CMD ["node", "server.js"] #### Q: 权限被拒绝 +运行以下命令: + ```bash permission denied: '/app/data.log' ``` diff --git a/04_image/dockerfile/volume.md b/04_image/dockerfile/volume.md index 2f49d4a..deb6fd6 100644 --- a/04_image/dockerfile/volume.md +++ b/04_image/dockerfile/volume.md @@ -2,6 +2,8 @@ ### 基本语法 +具体内容如下: + ```docker VOLUME ["/路径1", "/路径2"] VOLUME /路径 @@ -38,6 +40,8 @@ VOLUME /路径 #### 定义单个卷 +具体内容如下: + ```docker FROM mysql:8.0 VOLUME /var/lib/mysql @@ -45,6 +49,8 @@ VOLUME /var/lib/mysql #### 定义多个卷 +具体内容如下: + ```docker FROM myapp VOLUME ["/data", "/logs", "/config"] @@ -67,15 +73,21 @@ local a1b2c3d4e5f6... # 自动创建的匿名卷 #### 2. 可被命名卷覆盖 +运行以下命令: + ```bash ## 使用命名卷替代匿名卷 + $ docker run -v mysql_data:/var/lib/mysql mysql:8.0 ``` #### 3. 可被 Bind Mount 覆盖 +运行以下命令: + ```bash ## 使用宿主机目录替代 + $ docker run -v /my/data:/var/lib/mysql mysql:8.0 ``` @@ -90,6 +102,7 @@ FROM ubuntu VOLUME /data ## ❌ 这个文件不会出现在镜像中! + RUN echo "hello" > /data/test.txt ``` @@ -97,13 +110,17 @@ RUN echo "hello" > /data/test.txt #### 正确做法 +具体内容如下: + ```docker FROM ubuntu ## ✅ 先写入文件 + RUN mkdir -p /data && echo "hello" > /data/test.txt ## 再声明 VOLUME + VOLUME /data ``` @@ -113,6 +130,8 @@ VOLUME /data #### 数据库持久化 +具体内容如下: + ```docker FROM postgres:15 VOLUME /var/lib/postgresql/data @@ -120,6 +139,8 @@ VOLUME /var/lib/postgresql/data #### 日志目录 +具体内容如下: + ```docker FROM nginx VOLUME /var/log/nginx @@ -127,6 +148,8 @@ VOLUME /var/log/nginx #### 上传文件目录 +具体内容如下: + ```docker FROM myapp VOLUME /app/uploads @@ -136,14 +159,18 @@ VOLUME /app/uploads ### 查看 VOLUME 定义 +运行以下命令: + ```bash ## 查看镜像定义的 VOLUME + $ docker inspect mysql:8.0 --format '{{json .Config.Volumes}}' | jq { "/var/lib/mysql": {} } ## 查看容器挂载的卷 + $ docker inspect mycontainer --format '{{json .Mounts}}' | jq ``` @@ -162,6 +189,8 @@ $ docker inspect mycontainer --format '{{json .Mounts}}' | jq ### 在 Compose 中 +在 Compose 中 配置如下: + ```yaml services: db: @@ -182,10 +211,16 @@ volumes: #### 匿名卷可能导致数据丢失 +运行以下命令: + ```bash ## 使用 --rm 运行的容器,匿名卷会在容器删除时一起删除 + $ docker run --rm mysql:8.0 ## 容器停止后,数据丢失! + +具体内容如下: + ``` **解决**:始终使用命名卷 @@ -200,31 +235,42 @@ $ docker run -v mysql_data:/var/lib/mysql mysql:8.0 #### 1. 定义必须持久化的路径 +具体内容如下: + ```docker ## 数据库必须使用卷 + FROM postgres:15 VOLUME /var/lib/postgresql/data ``` #### 2. 不要在 VOLUME 后修改目录 +具体内容如下: + ```docker ## ❌ 避免 + VOLUME /app/data RUN cp init-data.json /app/data/ ## ✅ 正确 + RUN mkdir -p /app/data && cp init-data.json /app/data/ VOLUME /app/data ``` #### 3. 文档中说明 VOLUME 用途 +具体内容如下: + ```docker ## 持久化用户上传的文件 + VOLUME /app/uploads ## 持久化数据库数据 + VOLUME /var/lib/mysql ``` diff --git a/04_image/dockerfile/workdir.md b/04_image/dockerfile/workdir.md index e271629..d46ca03 100644 --- a/04_image/dockerfile/workdir.md +++ b/04_image/dockerfile/workdir.md @@ -2,6 +2,8 @@ ### 基本语法 +具体内容如下: + ```docker WORKDIR <工作目录路径> ``` @@ -12,6 +14,8 @@ WORKDIR <工作目录路径> ### 基本用法 +具体内容如下: + ```docker WORKDIR /app @@ -26,14 +30,19 @@ COPY . . # 复制到 /app/ #### 常见错误 +具体内容如下: + ```docker ## ❌ 错误:cd 在下一个 RUN 中无效 + RUN cd /app RUN echo "hello" > world.txt # 文件在根目录! ``` #### 原因分析 +具体内容如下: + ``` RUN cd /app ↓ @@ -49,8 +58,11 @@ RUN echo "hello" > world.txt #### 正确做法 +具体内容如下: + ```docker ## ✅ 正确:使用 WORKDIR + WORKDIR /app RUN echo "hello" > world.txt # 创建 /app/world.txt ``` @@ -73,6 +85,8 @@ RUN pwd # 输出 /a/b/c ### 使用环境变量 +具体内容如下: + ```docker ENV APP_HOME=/app WORKDIR $APP_HOME @@ -84,8 +98,11 @@ RUN pwd # 输出 /app ### 多阶段构建中的 WORKDIR +具体内容如下: + ```docker ## 构建阶段 + FROM node:20 AS builder WORKDIR /build COPY package*.json ./ @@ -94,6 +111,7 @@ COPY . . RUN npm run build ## 生产阶段 + FROM nginx:alpine WORKDIR /usr/share/nginx/html COPY --from=builder /build/dist . @@ -105,6 +123,8 @@ COPY --from=builder /build/dist . #### 1. 尽早设置 WORKDIR +具体内容如下: + ```docker FROM node:20 WORKDIR /app # 尽早设置 @@ -117,33 +137,46 @@ CMD ["node", "server.js"] #### 2. 使用绝对路径 +具体内容如下: + ```docker ## ✅ 推荐:绝对路径,意图明确 + WORKDIR /app ## ⚠️ 避免:相对路径可能造成混淆 + WORKDIR app ``` #### 3. 不要用 RUN cd +具体内容如下: + ```docker ## ❌ 避免 + RUN cd /app && echo "hello" > world.txt ## ✅ 推荐 + WORKDIR /app RUN echo "hello" > world.txt ``` #### 4. 适时重置 WORKDIR +具体内容如下: + ```docker WORKDIR /app ## ... 应用相关操作 ... WORKDIR /data ## ... 数据相关操作 ... + +具体内容如下: + ``` --- diff --git a/04_image/multistage-builds/README.md b/04_image/multistage-builds/README.md index be1b375..b446c82 100644 --- a/04_image/multistage-builds/README.md +++ b/04_image/multistage-builds/README.md @@ -1,10 +1,10 @@ -## 多阶段构建 +# 多阶段构建 -### 之前的做法 +## 之前的做法 在 Docker 17.05 版本之前,我们构建 Docker 镜像时,通常会采用两种方式: -#### 全部放入一个 Dockerfile +### 全部放入一个 Dockerfile 一种方式是将所有的构建过程编包含在一个 `Dockerfile` 中,包括项目及其依赖库的编译、测试、打包等流程,这里可能会带来的一些问题: @@ -51,7 +51,7 @@ CMD ["./app"] $ docker build -t go/helloworld:1 -f Dockerfile.one . ``` -#### 分散到多个 Dockerfile +### 分散到多个 Dockerfile 另一种方式,就是我们事先在一个 `Dockerfile` 将项目及其依赖库编译测试打包好后,再将其拷贝到运行环境中,这种方式需要我们编写两个 `Dockerfile` 和一些编译脚本才能将其两个阶段自动整合起来,这种方式虽然可以很好地规避第一种方式存在的风险,但明显部署过程较复杂。 @@ -120,7 +120,7 @@ go/helloworld 2 f7cf3465432c 22 seconds ago 6.47MB go/helloworld 1 f55d3e16affc 2 minutes ago 295MB ``` -### 使用多阶段构建 +## 使用多阶段构建 为解决以上问题,Docker v17.05 开始支持多阶段构建 (`multistage builds`)。使用多阶段构建我们就可以很容易解决前面提到的问题,并且只需要编写一个 `Dockerfile`: @@ -169,7 +169,7 @@ go/helloworld 1 f55d3e16affc 2 minutes ago 295MB 很明显使用多阶段构建的镜像体积小,同时也完美解决了上边提到的问题。 -#### 只构建某一阶段的镜像 +### 只构建某一阶段的镜像 我们可以使用 `as` 来为某一阶段命名,例如 @@ -183,7 +183,7 @@ FROM golang:alpine as builder $ docker build --target builder -t username/imagename:tag . ``` -#### 构建时从其他镜像复制文件 +### 构建时从其他镜像复制文件 上面例子中我们使用 `COPY --from=0 /go/src/github.com/go/helloworld/app .` 从上一阶段的镜像中复制文件,我们也可以复制任意镜像中的文件。 diff --git a/04_image/multistage-builds/laravel.md b/04_image/multistage-builds/laravel.md index a858d36..05dd0e9 100644 --- a/04_image/multistage-builds/laravel.md +++ b/04_image/multistage-builds/laravel.md @@ -26,6 +26,9 @@ bootstrap/cache/* storage/ ## 自行添加其他需要排除的文件,例如 .env.* 文件 + +具体内容如下: + ``` 在 `laravel.conf` 文件中写入 nginx 配置。 @@ -120,6 +123,8 @@ RUN set -x ; cd ${LARAVEL_PATH} \ ### 最后一个阶段构建 NGINX 镜像 +具体内容如下: + ```docker FROM nginx:alpine as nginx diff --git a/05_container/5.1_run.md b/05_container/5.1_run.md index cc8a95c..88a0aaa 100644 --- a/05_container/5.1_run.md +++ b/05_container/5.1_run.md @@ -1,5 +1,7 @@ ## 启动容器 +本节将详细介绍 Docker 容器的启动方式,包括新建启动和重新启动已停止的容器。 + ### 启动方式概述 启动容器有两种方式: @@ -12,6 +14,8 @@ #### 基本语法 +运行以下命令: + ```bash docker run [选项] 镜像 [命令] [参数...] ``` @@ -97,47 +101,65 @@ root@af8bae53bdd3:/# exit # 退出容器 #### 端口映射 +运行以下命令: + ```bash ## 将容器的 80 端口映射到宿主机的 8080 端口 + $ docker run -d -p 8080:80 nginx ## 随机映射端口 + $ docker run -d -P nginx ## 只绑定到 localhost + $ docker run -d -p 127.0.0.1:8080:80 nginx ``` #### 数据卷挂载 +运行以下命令: + ```bash ## 挂载命名卷 + $ docker run -v mydata:/data nginx ## 挂载宿主机目录 + $ docker run -v /host/path:/container/path nginx ## 只读挂载 + $ docker run -v /host/path:/container/path:ro nginx ``` #### 环境变量 +运行以下命令: + ```bash ## 设置单个环境变量 + $ docker run -e MYSQL_ROOT_PASSWORD=secret mysql ## 从文件加载环境变量 + $ docker run --env-file .env myapp ``` #### 资源限制 +运行以下命令: + ```bash ## 限制内存 + $ docker run -m 512m nginx ## 限制 CPU + $ docker run --cpus=1.5 nginx ``` @@ -147,14 +169,17 @@ $ docker run --cpus=1.5 nginx ```bash ## 查看所有容器(包括已停止的) + $ docker ps -a CONTAINER ID IMAGE STATUS NAMES af8bae53bdd3 ubuntu Exited (0) 2 minutes ago myubuntu ## 重新启动 + $ docker start myubuntu ## 启动并附加终端 + $ docker start -ai myubuntu ``` @@ -181,9 +206,11 @@ root@ba267838cc1b:/# ps ```bash ## 这个容器会立即退出(echo 执行完就结束了) + $ docker run ubuntu echo "hello" ## 解决:使用能持续运行的命令 + $ docker run -d nginx # nginx 是持续运行的服务 ``` @@ -195,9 +222,11 @@ $ docker run -d nginx # nginx 是持续运行的服务 ```bash ## 错误:没有 -p 参数,外部无法访问 + $ docker run -d nginx ## 正确:映射端口 + $ docker run -d -p 80:80 nginx ``` @@ -207,6 +236,7 @@ $ docker run -d -p 80:80 nginx ```bash ## 使用数据卷持久化 + $ docker run -v mydata:/app/data myapp ``` diff --git a/05_container/5.2_daemon.md b/05_container/5.2_daemon.md index 5cec654..80c0083 100644 --- a/05_container/5.2_daemon.md +++ b/05_container/5.2_daemon.md @@ -15,6 +15,8 @@ Docker 容器默认是**前台运行**的。使用 `-d`(detach)参数可以 #### 前台运行(默认) +运行以下命令: + ```bash $ docker run ubuntu:24.04 /bin/sh -c "while true; do echo hello world; sleep 1; done" hello world @@ -30,6 +32,8 @@ hello world #### 后台运行(使用 -d 参数) +运行以下命令: + ```bash $ docker run -d ubuntu:24.04 /bin/sh -c "while true; do echo hello world; sleep 1; done" 77b2dc01fe0f3f1265df143181e7b9af5e05279a884f4776ee75350ea9d8017a @@ -55,6 +59,8 @@ $ docker run -d ubuntu:24.04 #### 核心原理:容器的生命周期与主进程绑定 +具体内容如下: + ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Docker 容器的生命周期 = 容器内 PID 1 进程的生命周期 │ @@ -87,6 +93,8 @@ $ docker run -d ubuntu:24.04 #### 查看运行中的容器 +运行以下命令: + ```bash $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES @@ -95,6 +103,8 @@ CONTAINER ID IMAGE COMMAND CREATED STATUS PO #### 查看容器输出日志 +运行以下命令: + ```bash $ docker container logs 77b2dc01fe0f hello world @@ -111,6 +121,8 @@ $ docker container logs -f 77b2dc01fe0f #### 查看已停止的容器 +运行以下命令: + ```bash $ docker container ls -a ``` @@ -121,14 +133,19 @@ $ docker container ls -a #### 1. 长期运行的服务使用 -d +运行以下命令: + ```bash ## Web 服务器 + $ docker run -d -p 80:80 nginx ## 数据库 + $ docker run -d -p 3306:3306 mysql:8 ## 缓存服务 + $ docker run -d -p 6379:6379 redis ``` @@ -138,6 +155,7 @@ $ docker run -d -p 6379:6379 redis ```bash ## 有问题的容器,先前台运行看看发生了什么 + $ docker run myimage:latest ``` @@ -149,21 +167,30 @@ $ docker run myimage:latest $ docker run --rm ubuntu:24.04 echo "Hello, World!" Hello, World! ## 容器执行完后自动删除 + +具体内容如下: + ``` #### 4. 配合日志查看 +运行以下命令: + ```bash ## 后台启动 + $ docker run -d --name myapp myimage:latest ## 查看最近 100 行日志 + $ docker logs --tail 100 myapp ## 实时跟踪日志 + $ docker logs -f myapp ## 查看带时间戳的日志 + $ docker logs -t myapp ``` diff --git a/05_container/5.3_stop.md b/05_container/5.3_stop.md index ef5baf8..4e2b323 100644 --- a/05_container/5.3_stop.md +++ b/05_container/5.3_stop.md @@ -1,5 +1,7 @@ ## 终止容器 +本节将介绍如何终止一个运行中的容器,以及几种不同的终止方式及其区别。 + ### 终止方式概述 终止容器有三种方式: @@ -16,12 +18,16 @@ #### 基本用法 +运行以下命令: + ```bash $ docker stop 容器名或ID ``` #### 工作原理 +具体内容如下: + ``` docker stop mycontainer │ @@ -37,21 +43,29 @@ docker stop mycontainer #### 自定义超时时间 +运行以下命令: + ```bash ## 等待 30 秒后强制终止 + $ docker stop -t 30 mycontainer ## 立即发送 SIGKILL(相当于 docker kill) + $ docker stop -t 0 mycontainer ``` #### 停止多个容器 +运行以下命令: + ```bash ## 停止多个指定容器 + $ docker stop container1 container2 container3 ## 停止所有运行中的容器 + $ docker stop $(docker ps -q) ``` @@ -61,6 +75,8 @@ $ docker stop $(docker ps -q) #### 基本用法 +运行以下命令: + ```bash $ docker kill 容器名或ID ``` @@ -74,11 +90,15 @@ $ docker kill 容器名或ID #### 发送自定义信号 +运行以下命令: + ```bash ## 发送 SIGHUP(让进程重新加载配置) + $ docker kill -s HUP mycontainer ## 发送 SIGTERM + $ docker kill -s TERM mycontainer ``` @@ -90,10 +110,12 @@ $ docker kill -s TERM mycontainer ```bash ## 主进程是交互式 bash + $ docker run -it ubuntu bash root@abc123:/# exit # 退出 bash → 容器停止 ## 主进程执行完毕 + $ docker run ubuntu echo "Hello" # echo 执行完 → 容器停止 ``` @@ -101,6 +123,8 @@ $ docker run ubuntu echo "Hello" # echo 执行完 → 容器停止 ### 查看已停止的容器 +运行以下命令: + ```bash $ docker ps -a CONTAINER ID IMAGE COMMAND STATUS NAMES @@ -124,20 +148,27 @@ c5d3a5e8f7b2 nginx "nginx" Up 5 minutes mynginx #### 启动已停止的容器 +运行以下命令: + ```bash $ docker start 容器名或ID ## 启动并附加终端 + $ docker start -ai 容器名 ``` #### 重启运行中的容器 +运行以下命令: + ```bash ## 先停止再启动 + $ docker restart 容器名 ## 自定义停止超时 + $ docker restart -t 30 容器名 ``` @@ -145,6 +176,8 @@ $ docker restart -t 30 容器名 ### 生命周期状态图 +具体内容如下: + ``` docker create │ @@ -186,18 +219,24 @@ $ docker restart -t 30 容器名 #### 停止所有容器 +运行以下命令: + ```bash $ docker stop $(docker ps -q) ``` #### 删除所有已停止的容器 +运行以下命令: + ```bash $ docker container prune ``` #### 停止并删除所有容器 +运行以下命令: + ```bash $ docker stop $(docker ps -q) && docker container prune -f ``` @@ -221,19 +260,25 @@ $ docker stop $(docker ps -q) && docker container prune -f ```dockerfile ## Dockerfile 示例 + FROM node:22 ... ## 使用 exec 形式确保信号能传递给 node 进程 + CMD ["node", "server.js"] ``` #### Q: 容器无法停止 +运行以下命令: + ```bash ## 强制终止 + $ docker kill 容器名 ## 如果仍无法停止,检查系统资源 + $ docker inspect 容器名 ``` diff --git a/05_container/5.4_attach_exec.md b/05_container/5.4_attach_exec.md index 3cd0a33..460c946 100644 --- a/05_container/5.4_attach_exec.md +++ b/05_container/5.4_attach_exec.md @@ -26,11 +26,15 @@ Docker 提供两种进入容器的命令: #### 基本用法 +运行以下命令: + ```bash ## 进入容器并启动交互式 shell + $ docker exec -it 容器名 /bin/bash ## 或使用 sh(适用于 Alpine 等精简镜像) + $ docker exec -it 容器名 /bin/sh ``` @@ -47,18 +51,23 @@ $ docker exec -it 容器名 /bin/sh #### 示例 +运行以下命令: + ```bash ## 启动一个后台容器 + $ docker run -dit --name myubuntu ubuntu 69d137adef7a... ## 进入容器(交互式 shell) + $ docker exec -it myubuntu bash root@69d137adef7a:/# ls bin boot dev etc home lib ... root@69d137adef7a:/# exit ## 容器仍在运行! + $ docker ps CONTAINER ID IMAGE STATUS NAMES 69d137adef7a ubuntu Up 2 minutes myubuntu @@ -70,19 +79,25 @@ CONTAINER ID IMAGE STATUS NAMES ```bash ## 查看容器内进程 + $ docker exec myubuntu ps aux ## 查看配置文件 + $ docker exec myubuntu cat /etc/nginx/nginx.conf ## 以 root 用户执行 + $ docker exec -u root myubuntu apt update ``` #### 只用 -i 不用 -t 的区别 +运行以下命令: + ```bash ## 只用 -i:可以执行命令,但没有提示符 + $ docker exec -i myubuntu bash ls # 输入命令 bin # 输出结果 @@ -91,6 +106,7 @@ dev ... ## 用 -it:有完整的终端体验 + $ docker exec -it myubuntu bash root@69d137adef7a:/# # 有提示符 ``` @@ -103,6 +119,8 @@ root@69d137adef7a:/# # 有提示符 #### 基本用法 +运行以下命令: + ```bash $ docker attach 容器名 ``` @@ -123,12 +141,16 @@ $ docker attach 容器名 #### 示例 +运行以下命令: + ```bash ## 启动容器 + $ docker run -dit --name myubuntu ubuntu 243c32535da7... ## 附加到容器 + $ docker attach myubuntu root@243c32535da7:/# ``` @@ -156,6 +178,7 @@ CONTAINER ID IMAGE STATUS NAMES $ docker attach myubuntu root@243c32535da7:/# ## 按 Ctrl+P 然后 Ctrl+Q + read escape sequence $ docker ps # 容器仍在运行 @@ -194,14 +217,19 @@ docker exec docker attach #### 1. 首选 docker exec +运行以下命令: + ```bash ## 进入容器调试 + $ docker exec -it myapp bash ## 查看日志 + $ docker exec myapp tail -f /var/log/app.log ## 执行数据库迁移 + $ docker exec myapp python manage.py migrate ``` @@ -218,10 +246,12 @@ $ docker exec myapp python manage.py migrate ```bash ## 这会失败 + $ docker exec -it myapp bash OCI runtime exec failed: exec failed: unable to start container process: exec: "bash": executable file not found ## 解决方案:使用调试容器(Docker Desktop 或 Kubernetes debug) + $ docker debug myapp ``` @@ -243,6 +273,8 @@ $ docker exec -it myapp /bin/sh #### Q: 需要 root 权限 +运行以下命令: + ```bash $ docker exec -u root -it myapp bash ``` diff --git a/05_container/5.5_import_export.md b/05_container/5.5_import_export.md index b5154e9..1cc12e8 100644 --- a/05_container/5.5_import_export.md +++ b/05_container/5.5_import_export.md @@ -1,5 +1,7 @@ ## 导出和导入容器 +当我们需要迁移容器或者备份容器时,可以使用 Docker 的导入和导出功能。本节将介绍这两个命令的使用方法。 + ### 导出容器 如果要导出本地某个容器,可以使用 `docker export` 命令。 diff --git a/05_container/5.6_rm.md b/05_container/5.6_rm.md index c2578bf..e9665de 100644 --- a/05_container/5.6_rm.md +++ b/05_container/5.6_rm.md @@ -1,5 +1,7 @@ ## 删除容器 +随着容器的创建和停止,系统中会积累大量的容器。本节将介绍如何删除不再需要的容器,以及如何清理所有停止的容器。 + ### 基本用法 使用 `docker rm` 删除已停止的容器: @@ -22,6 +24,8 @@ $ docker rm 容器名或ID #### 删除已停止的容器 +运行以下命令: + ```bash $ docker rm mycontainer mycontainer @@ -29,12 +33,16 @@ mycontainer #### 强制删除运行中的容器 +运行以下命令: + ```bash ## 不加 -f 会报错 + $ docker rm running_container Error: cannot remove running container ## 加 -f 强制删除 + $ docker rm -f running_container running_container ``` @@ -43,8 +51,11 @@ running_container #### 删除容器及其数据卷 +运行以下命令: + ```bash ## 删除容器时同时删除其匿名卷 + $ docker rm -v mycontainer ``` @@ -56,8 +67,11 @@ $ docker rm -v mycontainer #### 删除所有已停止的容器 +运行以下命令: + ```bash ## 方式一:使用 prune 命令(推荐) + $ docker container prune WARNING! This will remove all stopped containers. @@ -68,30 +82,40 @@ def456... Total reclaimed space: 150MB ## 方式二:不提示确认 + $ docker container prune -f ``` #### 删除所有容器(包括运行中的) +运行以下命令: + ```bash ## 先停止所有容器,再删除 + $ docker stop $(docker ps -q) $ docker rm $(docker ps -aq) ## 或者直接强制删除 + $ docker rm -f $(docker ps -aq) ``` #### 按条件删除 +运行以下命令: + ```bash ## 删除所有已退出的容器 + $ docker rm $(docker ps -aq -f status=exited) ## 删除名称包含 "test" 的容器 + $ docker rm $(docker ps -aq -f name=test) ## 删除 24 小时前创建的容器 + $ docker container prune --filter "until=24h" ``` @@ -112,11 +136,15 @@ $ docker container prune --filter "until=24h" #### 示例 +运行以下命令: + ```bash ## 删除所有基于 nginx 镜像的容器 + $ docker rm $(docker ps -aq -f ancestor=nginx) ## 删除所有创建后未启动的容器 + $ docker rm $(docker ps -aq -f status=created) ``` @@ -128,10 +156,12 @@ $ docker rm $(docker ps -aq -f status=created) ```bash ## 尝试删除有容器依赖的镜像 + $ docker image rm nginx Error: image is being used by stopped container abc123 ## 需要先删除依赖该镜像的容器 + $ docker rm abc123 $ docker image rm nginx ``` @@ -142,27 +172,37 @@ $ docker image rm nginx #### 开发环境 +运行以下命令: + ```bash ## 定期清理已停止的容器 + $ docker container prune -f ## 一键清理所有未使用资源 + $ docker system prune -f ``` #### 生产环境 +运行以下命令: + ```bash ## 使用 --rm 参数运行临时容器 + $ docker run --rm ubuntu echo "Hello" ## 容器退出后自动删除 ## 定期清理(设置保留时间) + $ docker container prune --filter "until=168h" # 保留 7 天内的 ``` #### 完整清理脚本 +运行以下命令: + ```bash #!/bin/bash ## cleanup.sh - Docker 资源清理脚本 @@ -189,6 +229,8 @@ docker system df #### Q: 容器无法删除 +运行以下命令: + ```bash Error: container is running ``` @@ -199,6 +241,7 @@ Error: container is running $ docker stop mycontainer $ docker rm mycontainer ## 或 + $ docker rm -f mycontainer ``` @@ -213,9 +256,11 @@ $ docker rm -f mycontainer ```bash ## 查看空间占用 + $ docker system df ## 完整清理 + $ docker system prune -a --volumes ``` diff --git a/06_repository/6.1_dockerhub.md b/06_repository/6.1_dockerhub.md index aebee21..702f5bd 100644 --- a/06_repository/6.1_dockerhub.md +++ b/06_repository/6.1_dockerhub.md @@ -2,6 +2,9 @@ ### 什么是 Docker Hub +Docker Hub 是 Docker 的中央镜像仓库,通过它您可以轻松地分享和获取 Docker 镜像。 + + [Docker Hub](https://hub.docker.com/) 是 Docker 官方维护的公共镜像仓库,也是全球最大的容器镜像库。 它提供了: @@ -16,6 +19,9 @@ #### 1. 搜索镜像 +我们可以通过 `docker search` 命令来查找官方仓库中的镜像,并利用 `docker pull` 命令来将它下载到本地。 + + 除了网页搜索,也可以使用命令行: ```bash @@ -28,6 +34,8 @@ centos The official build of CentOS. 7000+ [OK] #### 2. 拉取镜像 +运行以下命令: + ```bash $ docker pull nginx:alpine ``` @@ -39,23 +47,28 @@ $ docker pull nginx:alpine ```bash $ docker login ## 输入用户名和密码 + +具体内容如下: + ``` 打标签并推送: ```bash ## 1. 标记镜像 + $ docker tag myapp:v1 username/myapp:v1 ## 2. 推送 + $ docker push username/myapp:v1 ``` --- -### 限制与配额(重要) +### 限制与配额 -#### 镜像拉取限制 (Rate Limiting) +#### 镜像拉取限制 自 2020 年 11 月起,Docker Hub 对匿名和免费用户实施了拉取速率限制: @@ -74,7 +87,10 @@ $ docker push username/myapp:v1 ### 安全最佳实践 -#### 1. 启用 2FA (双因素认证) +#### 1. 启用 2FA(双因素认证) + +为了保护您的 Docker Hub 账号安全,我们建议采取以下措施。 + 在 Account Settings -> Security 中启用 2FA,保护账号安全。启用后,CLI 登录需要使用 **Access Token** 而非密码。 @@ -103,7 +119,7 @@ Docker Hub 会对官方镜像和付费用户的镜像进行安全扫描。在镜 --- -### 自动构建 (Automated Builds) +### 自动构建 > ⚠️ 目前仅限付费用户 (Pro/Team) 使用。 diff --git a/06_repository/6.2_registry.md b/06_repository/6.2_registry.md index b3c0f26..1ccef47 100644 --- a/06_repository/6.2_registry.md +++ b/06_repository/6.2_registry.md @@ -10,6 +10,9 @@ #### 容器运行 +如果您需要搭建私有仓库,可以通过官方提供的 `registry` 镜像快速部署。 + + 你可以使用官方 `registry` 镜像来运行。 ```bash @@ -97,7 +100,10 @@ REPOSITORY TAG IMAGE ID CREAT 这是因为 Docker 默认不允许非 `HTTPS` 方式推送镜像。我们可以通过 Docker 的配置选项来取消这个限制,或者查看下一节配置能够通过 `HTTPS` 访问的私有仓库。 -#### Linux (systemd) +#### Linux(systemd) + +默认情况下,Docker 强制使用 HTTPS 协议推送镜像。如果您搭建的私有仓库是 HTTP 协议,需要进行如下配置。 + 对于使用 `systemd` 的系统,请在 `/etc/docker/daemon.json` 中写入如下内容(如果文件不存在请新建该文件) diff --git a/06_repository/6.3_registry_auth.md b/06_repository/6.3_registry_auth.md index 8d316c6..08d4f1c 100644 --- a/06_repository/6.3_registry_auth.md +++ b/06_repository/6.3_registry_auth.md @@ -125,6 +125,8 @@ threshold: 3 ### 生成 http 认证文件 +运行以下命令: + ```bash $ mkdir auth @@ -136,7 +138,9 @@ $ docker run --rm \ > 将上面的 `username` `password` 替换为你自己的用户名和密码。 -### 编辑 `docker-compose.yml` +### 编辑 Docker Compose 配置 + +编辑 `docker-compose.yml` 配置如下: ```yaml @@ -154,7 +158,7 @@ volumes: registry-data: ``` -### 修改 hosts +### 修改 Hosts 文件 编辑 `/etc/hosts` @@ -164,6 +168,8 @@ volumes: ### 启动 +运行以下命令: + ```bash $ docker compose up -d ``` diff --git a/06_repository/6.4_nexus3_registry.md b/06_repository/6.4_nexus3_registry.md index 172a50a..f254a76 100644 --- a/06_repository/6.4_nexus3_registry.md +++ b/06_repository/6.4_nexus3_registry.md @@ -4,6 +4,8 @@ ### 启动 Nexus 容器 +运行以下命令: + ```bash $ docker run -d --name nexus3 --restart=always \ -p 8081:8081 \ @@ -44,7 +46,7 @@ $ docker exec nexus3 cat /nexus-data/admin.password * **Name**: 仓库的名称 * **HTTP**: 仓库单独的访问端口(例如:**5001**) -* **Hosted -> Deployment pollcy**: 请选择 **Allow redeploy** 否则无法上传 Docker 镜像。 +* **Hosted -> Deployment policy**: 请选择**Allow redeploy** 否则无法上传 Docker 镜像。 其它的仓库创建方法请各位自己摸索,还可以创建一个 `docker (proxy)` 类型的仓库链接到 DockerHub 上。再创建一个 `docker (group)` 类型的仓库把刚才的 `hosted` 与 `proxy` 添加在一起。主机在访问的时候默认下载私有仓库中的镜像,如果没有将链接到 DockerHub 中下载并缓存到 Nexus 中。 @@ -52,11 +54,11 @@ $ docker exec nexus3 cat /nexus-data/admin.password 菜单 `Security->Realms` 把 Docker Bearer Token Realm 移到右边的框中保存。 -添加用户规则:菜单 `Security->Roles`->`Create role` 在 `Privlleges` 选项搜索 docker 把相应的规则移动到右边的框中然后保存。 +添加用户规则:菜单 `Security->Roles`->`Create role` 在 `Privileges` 选项搜索 docker 把相应的规则移动到右边的框中然后保存。 添加用户:菜单 `Security->Users`->`Create local user` 在 `Roles` 选项中选中刚才创建的规则移动到右边的窗口保存。 -### NGINX 加密代理 +### NGINX 反向代理配置 证书的生成请参见 [`私有仓库高级配置`](6.3_registry_auth.md) 里面证书生成一节。 diff --git a/07_data_network/data/README.md b/07_data_network/data/README.md index 8756576..af74208 100644 --- a/07_data_network/data/README.md +++ b/07_data_network/data/README.md @@ -1,4 +1,6 @@ -## 数据管理 +# 数据管理 + +数据管理 示意图如下: ![](../_images/types-of-mounts.png) diff --git a/07_data_network/data/bind-mounts.md b/07_data_network/data/bind-mounts.md index b934e6e..616e83f 100644 --- a/07_data_network/data/bind-mounts.md +++ b/07_data_network/data/bind-mounts.md @@ -1,6 +1,6 @@ -## 挂载主机目录(Bind Mounts) +## 挂载主机目录 -### 什么是 Bind Mount +### 什么是绑定挂载 Bind Mount(绑定挂载)将**宿主机的目录或文件**直接挂载到容器中。容器可以读写宿主机的文件系统。 @@ -29,6 +29,8 @@ Bind Mount(绑定挂载)将**宿主机的目录或文件**直接挂载到容 #### 选择建议 +具体内容如下: + ``` 需求 推荐方案 ───────────────────────────────────────── @@ -46,6 +48,8 @@ Bind Mount(绑定挂载)将**宿主机的目录或文件**直接挂载到容 #### 使用 --mount(推荐) +运行以下命令: + ```bash $ docker run -d \ --mount type=bind,source=/宿主机路径,target=/容器路径 \ @@ -54,6 +58,8 @@ $ docker run -d \ #### 使用 -v(简写) +运行以下命令: + ```bash $ docker run -d \ -v /宿主机路径:/容器路径 \ @@ -74,22 +80,32 @@ $ docker run -d \ #### 场景一:开发环境代码同步 +运行以下命令: + ```bash ## 将本地代码目录挂载到容器 + $ docker run -d \ -p 8080:80 \ --mount type=bind,source=$(pwd)/src,target=/usr/share/nginx/html \ nginx ## 修改本地文件,容器内立即生效(热更新) + $ echo "Hello" > src/index.html ## 浏览器刷新即可看到变化 + +具体内容如下: + ``` #### 场景二:配置文件挂载 +运行以下命令: + ```bash ## 挂载自定义 nginx 配置 + $ docker run -d \ --mount type=bind,source=/path/to/nginx.conf,target=/etc/nginx/nginx.conf,readonly \ nginx @@ -97,8 +113,11 @@ $ docker run -d \ #### 场景三:日志收集 +运行以下命令: + ```bash ## 将容器日志输出到宿主机目录 + $ docker run -d \ --mount type=bind,source=/var/log/myapp,target=/app/logs \ myapp @@ -106,8 +125,11 @@ $ docker run -d \ #### 场景四:共享 SSH 密钥 +运行以下命令: + ```bash ## 挂载 SSH 密钥(只读) + $ docker run --rm -it \ --mount type=bind,source=$HOME/.ssh,target=/root/.ssh,readonly \ alpine ssh user@remote @@ -121,11 +143,13 @@ $ docker run --rm -it \ ```bash ## --mount 语法 + $ docker run -d \ --mount type=bind,source=/config,target=/app/config,readonly \ myapp ## -v 语法 + $ docker run -d \ -v /config:/app/config:ro \ myapp @@ -142,13 +166,17 @@ touch: /app/config/new.txt: Read-only file system ### 挂载单个文件 +运行以下命令: + ```bash ## 挂载 bash 历史记录 + $ docker run --rm -it \ --mount type=bind,source=$HOME/.bash_history,target=/root/.bash_history \ ubuntu bash ## 挂载自定义配置文件 + $ docker run -d \ --mount type=bind,source=/path/to/my.cnf,target=/etc/mysql/my.cnf \ mysql @@ -160,6 +188,8 @@ $ docker run -d \ ### 查看挂载信息 +运行以下命令: + ```bash $ docker inspect mycontainer --format '{{json .Mounts}}' | jq ``` @@ -193,6 +223,8 @@ $ docker inspect mycontainer --format '{{json .Mounts}}' | jq #### Q: 路径不存在报错 +运行以下命令: + ```bash $ docker run --mount type=bind,source=/not/exist,target=/app nginx docker: Error response from daemon: invalid mount config for type "bind": @@ -207,12 +239,15 @@ bind source path does not exist: /not/exist ```bash ## 方法1:确保宿主机文件权限允许容器用户访问 + $ chmod -R 755 /path/to/data ## 方法2:以 root 运行容器 + $ docker run -u root ... ## 方法3:使用相同的 UID + $ docker run -u $(id -u):$(id -g) ... ``` @@ -222,6 +257,7 @@ $ docker run -u $(id -u):$(id -g) ... ```bash ## 使用 :cached 或 :delegated 提高性能(macOS) + $ docker run -v /host/path:/container/path:cached myapp ``` @@ -237,31 +273,43 @@ $ docker run -v /host/path:/container/path:cached myapp #### 1. 开发环境使用 Bind Mount +运行以下命令: + ```bash ## 代码热更新 + $ docker run -v $(pwd):/app -p 3000:3000 node npm run dev ``` #### 2. 生产环境使用 Volume +运行以下命令: + ```bash ## 数据持久化 + $ docker run -v mysql_data:/var/lib/mysql mysql ``` #### 3. 配置文件使用只读挂载 +运行以下命令: + ```bash $ docker run -v /config/nginx.conf:/etc/nginx/nginx.conf:ro nginx ``` #### 4. 注意路径安全 +运行以下命令: + ```bash ## ❌ 危险:挂载根目录或敏感目录 + $ docker run -v /:/host ... ## ✅ 只挂载必要的目录 + $ docker run -v /app/data:/data ... ``` diff --git a/07_data_network/data/volume.md b/07_data_network/data/volume.md index 07468e8..69caf7c 100644 --- a/07_data_network/data/volume.md +++ b/07_data_network/data/volume.md @@ -29,7 +29,9 @@ flowchart LR ### 数据卷 vs 容器存储层 -##### 容器存储层(不推荐存储重要数据) +#### 容器存储层(不推荐存储重要数据) + +具体内容如下: ```mermaid graph TD @@ -43,7 +45,9 @@ graph TD Delete[容器删除] -->|导致| DataLost[数据丢失 ❌] ``` -##### 数据卷(推荐) +#### 数据卷(推荐) + +具体内容如下: ```mermaid graph TD @@ -65,12 +69,16 @@ graph TD #### 创建数据卷 +运行以下命令: + ```bash $ docker volume create my-vol ``` #### 列出所有数据卷 +运行以下命令: + ```bash $ docker volume ls DRIVER VOLUME NAME @@ -81,6 +89,8 @@ local redis_data #### 查看数据卷详情 +运行以下命令: + ```bash $ docker volume inspect my-vol [ @@ -106,6 +116,8 @@ $ docker volume inspect my-vol #### 方式一:--mount(推荐) +运行以下命令: + ```bash $ docker run -d \ --name web \ @@ -123,6 +135,8 @@ $ docker run -d \ #### 方式二:-v(简写) +运行以下命令: + ```bash $ docker run -d \ --name web \ @@ -142,13 +156,17 @@ $ docker run -d \ #### 只读挂载 +运行以下命令: + ```bash ## --mount 方式 + $ docker run -d \ --mount source=my-vol,target=/data,readonly \ nginx ## -v 方式 + $ docker run -d \ -v my-vol:/data:ro \ nginx @@ -160,11 +178,15 @@ $ docker run -d \ #### 场景一:数据库持久化 +运行以下命令: + ```bash ## 创建数据卷 + $ docker volume create postgres_data ## 启动 PostgreSQL,数据存储在数据卷中 + $ docker run -d \ --name postgres \ -e POSTGRES_PASSWORD=secret \ @@ -172,9 +194,11 @@ $ docker run -d \ postgres:16 ## 即使删除容器,数据仍然保留 + $ docker rm -f postgres ## 重新启动,数据还在 + $ docker run -d \ --name postgres \ -e POSTGRES_PASSWORD=secret \ @@ -184,16 +208,21 @@ $ docker run -d \ #### 场景二:多容器共享数据 +运行以下命令: + ```bash ## 创建共享数据卷 + $ docker volume create shared-data ## 容器 A 写入数据 + $ docker run -d --name writer \ -v shared-data:/data \ alpine sh -c "while true; do date >> /data/log.txt; sleep 5; done" ## 容器 B 读取数据 + $ docker run --rm \ -v shared-data:/data \ alpine cat /data/log.txt @@ -201,8 +230,11 @@ $ docker run --rm \ #### 场景三:配置文件持久化 +运行以下命令: + ```bash ## 将 nginx 配置存储在数据卷中 + $ docker run -d \ -v nginx-config:/etc/nginx/conf.d \ -v nginx-logs:/var/log/nginx \ @@ -216,24 +248,33 @@ $ docker run -d \ #### 删除数据卷 +运行以下命令: + ```bash ## 删除指定数据卷 + $ docker volume rm my-vol ## 删除容器时同时删除数据卷 + $ docker rm -v container_name ``` #### 清理未使用的数据卷 +运行以下命令: + ```bash ## 查看未被任何容器使用的数据卷 + $ docker volume ls -f dangling=true ## 删除所有未使用的数据卷 + $ docker volume prune ## 强制删除(不提示确认) + $ docker volume prune -f ``` @@ -245,8 +286,11 @@ $ docker volume prune -f #### 备份数据卷 +运行以下命令: + ```bash ## 使用临时容器挂载数据卷,打包备份 + $ docker run --rm \ -v my-vol:/source:ro \ -v $(pwd):/backup \ @@ -261,11 +305,15 @@ $ docker run --rm \ #### 恢复数据卷 +运行以下命令: + ```bash ## 创建新数据卷 + $ docker volume create my-vol-restored ## 解压备份到新数据卷 + $ docker run --rm \ -v my-vol-restored:/target \ -v $(pwd):/backup:ro \ @@ -274,6 +322,8 @@ $ docker run --rm \ #### 备份脚本示例 +运行以下命令: + ```bash #!/bin/bash ## backup-volume.sh @@ -306,9 +356,11 @@ Docker 有两种主要的数据持久化方式: ```bash ## 数据卷 + $ docker run -v mydata:/app/data nginx ## 绑定挂载 + $ docker run -v /host/path:/app/data nginx ``` @@ -320,17 +372,23 @@ $ docker run -v /host/path:/app/data nginx #### Q: 如何知道容器使用了哪些数据卷? +运行以下命令: + ```bash $ docker inspect container_name --format '{{json .Mounts}}' | jq ``` #### Q: 数据卷的数据在哪里? +运行以下命令: + ```bash ## 查看数据卷详情 + $ docker volume inspect my-vol ## Mountpoint 字段显示实际路径 + "Mountpoint": "/var/lib/docker/volumes/my-vol/_data" ``` diff --git a/07_data_network/network/README.md b/07_data_network/network/README.md index 45b09a7..8fd99a8 100644 --- a/07_data_network/network/README.md +++ b/07_data_network/network/README.md @@ -1,6 +1,6 @@ -## 网络配置 +# 网络配置 -### Docker 网络概述 +## Docker 网络概述 Docker 容器需要网络来: - 与外部世界通信(访问互联网、被外部访问) @@ -9,7 +9,7 @@ Docker 容器需要网络来: Docker 在安装时会自动配置网络基础设施,大多数情况下开箱即用。 -### 默认网络架构 +## 默认网络架构 Docker 启动时自动创建以下网络组件: @@ -36,7 +36,7 @@ graph TD Internet((互联网)) <--> eth0 ``` -#### 核心组件 +### 核心组件 | 组件 | 说明 | |------|------| @@ -45,7 +45,9 @@ graph TD | **容器 eth0** | 容器内的网卡 | | **IP 地址** | 自动从 172.17.0.0/16 网段分配 | -#### 数据流向 +### 数据流向 + +具体内容如下: ``` 容器 A (172.17.0.2) → docker0 → 容器 B (172.17.0.3) (容器间通信) @@ -55,7 +57,7 @@ graph TD --- -### Docker 网络类型 +## Docker 网络类型 查看默认网络: @@ -77,9 +79,9 @@ ghi789... none null local --- -### 用户自定义网络(推荐) +## 用户自定义网络(推荐) -#### 为什么要用自定义网络 +### 为什么要用自定义网络 默认 bridge 网络的局限: @@ -89,30 +91,38 @@ ghi789... none null local | 所有容器在同一网络 | 更好的隔离性 | | 需要 --link(已废弃) | 原生支持服务发现 | -#### 创建自定义网络 +### 创建自定义网络 + +运行以下命令: ```bash ## 创建网络 + $ docker network create mynet ## 查看网络详情 + $ docker network inspect mynet ``` -#### 使用自定义网络 +### 使用自定义网络 + +运行以下命令: ```bash ## 启动容器并连接到自定义网络 + $ docker run -d --name web --network mynet nginx $ docker run -d --name db --network mynet postgres ## 在 web 容器中可以直接用容器名访问 db + $ docker exec web ping db PING db (172.18.0.3): 56 data bytes 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.083 ms ``` -#### 容器名 DNS 解析 +### 容器名 DNS 解析 自定义网络自动提供 DNS 服务: @@ -131,45 +141,57 @@ PING db (172.18.0.3): 56 data bytes --- -### 容器互联 +## 容器互联 -#### 同一网络内的容器 +### 同一网络内的容器 同一自定义网络内的容器可以直接通信: ```bash ## 创建网络 + $ docker network create app-net ## 启动应用和数据库 + $ docker run -d --name redis --network app-net redis $ docker run -d --name app --network app-net myapp ## app 容器中可以用 redis:6379 连接 Redis + +具体内容如下: + ``` -#### 连接到多个网络 +### 连接到多个网络 一个容器可以连接到多个网络: ```bash ## 启动容器 + $ docker run -d --name multi-net-container --network frontend nginx ## 再连接到另一个网络 + $ docker network connect backend multi-net-container ## 查看容器的网络 + $ docker inspect multi-net-container --format '{{json .NetworkSettings.Networks}}' ``` -#### ⚠️ --link 已废弃 +### ⚠️ --link 已废弃 + +运行以下命令: ```bash ## 旧方式(不推荐) + $ docker run --link db:database myapp ## 新方式(推荐) + $ docker network create mynet $ docker run --network mynet --name db postgres $ docker run --network mynet --name app myapp @@ -177,18 +199,21 @@ $ docker run --network mynet --name app myapp --- -### 端口映射 +## 端口映射 容器默认只能在 Docker 网络内访问。要从外部访问容器,需要端口映射: -#### 基本语法 +### 基本语法 + +运行以下命令: ```bash ## -p 宿主机端口:容器端口 + $ docker run -d -p 8080:80 nginx ``` -#### 映射方式 +### 映射方式 | 参数 | 说明 | 示例 | |------|------|------| @@ -198,14 +223,18 @@ $ docker run -d -p 8080:80 nginx | `-p 127.0.0.1:8080:80` | 只绑定本地 | 仅本机可访问 | | `-p 8080:80/udp` | UDP 端口 | UDP 协议 | -#### 查看端口映射 +### 查看端口映射 + +运行以下命令: ```bash $ docker port mycontainer 80/tcp -> 0.0.0.0:8080 ``` -#### 端口映射示意图 +### 端口映射示意图 + +具体内容如下: ``` 外部请求 http://宿主机IP:8080 @@ -222,22 +251,26 @@ $ docker port mycontainer --- -### 网络隔离 +## 网络隔离 不同网络之间默认隔离: ```bash ## 创建两个网络 + $ docker network create frontend $ docker network create backend ## 容器 A 在 frontend + $ docker run -d --name web --network frontend nginx ## 容器 B 在 backend + $ docker run -d --name db --network backend postgres ## web 无法直接访问 db(不同网络) + $ docker exec web ping db ping: db: Name or service not known ``` @@ -246,34 +279,43 @@ ping: db: Name or service not known --- -### 常用命令 +## 常用命令 + +运行以下命令: ```bash ## 列出网络 + $ docker network ls ## 创建网络 + $ docker network create mynet ## 查看网络详情 + $ docker network inspect mynet ## 连接容器到网络 + $ docker network connect mynet mycontainer ## 断开网络连接 + $ docker network disconnect mynet mycontainer ## 删除网络 + $ docker network rm mynet ## 清理未使用的网络 + $ docker network prune ``` --- -### 本章小结 +## 本章小结 | 概念 | 要点 | |------|------| @@ -283,9 +325,9 @@ $ docker network prune | **网络隔离** | 不同网络默认隔离,增强安全性 | | **--link** | 已废弃,使用自定义网络替代 | -### 延伸阅读 +## 延伸阅读 - [高级网络配置](linking.md):容器互联详解 - [配置 DNS](dns.md):自定义 DNS 设置 -- [端口映射](port_bindbindbindport.md):高级端口配置 +- [端口映射](port_mapping.md):高级端口配置 - [Compose 网络](../compose/9.5_compose_file.md):Compose 中的网络配置 diff --git a/07_data_network/network/dns.md b/07_data_network/network/dns.md index cf89798..4881564 100644 --- a/07_data_network/network/dns.md +++ b/07_data_network/network/dns.md @@ -9,18 +9,21 @@ Docker 容器的 DNS 配置有两种情况: --- -### 嵌入式 DNS (Embedded DNS) +### 嵌入式 DNS 这是 Docker 网络最强大的功能之一。在自定义网络中,容器可以通过"名字"找到彼此,而不需要知道对方的 IP(因为 IP 可能会变)。 ```bash ## 1. 创建自定义网络 + $ docker network create mynet ## 2. 启动容器 web 并加入网络 + $ docker run -d --name web --network mynet nginx ## 3. 启动容器 client 并尝试 ping web + $ docker run -it --rm --network mynet alpine ping web PING web (172.18.0.2): 56 data bytes 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.074 ms @@ -52,7 +55,7 @@ nameserver 114.114.114.114 $ docker run --dns-search=example.com myapp ``` -#### 3. --hostname (-h) +#### 3. --hostname(-h) 设置容器的主机名。 diff --git a/07_data_network/network/port_mapping.md b/07_data_network/network/port_mapping.md index 6498e95..1aa85c9 100644 --- a/07_data_network/network/port_mapping.md +++ b/07_data_network/network/port_mapping.md @@ -28,12 +28,16 @@ ### 端口映射方式 -#### 1. 指定映射 (-p) +#### 1. 指定映射 + +Docker 提供了多种方式来指定端口映射,最常用的是 `-p` 参数。 + 使用 `-p <宿主机端口>:<容器端口>` 格式。 ```bash ## 将宿主机的 8080 端口映射到容器的 80 端口 + $ docker run -d -p 8080:80 nginx ``` @@ -48,7 +52,10 @@ $ docker run -d -p 8080:80 nginx | `hostPort:containerPort` | 绑定所有 IP (0.0.0.0) 的特定端口 | `-p 8080:80` (默认) | | `containerPort` | 绑定所有 IP 的随机端口 | `-p 80` | -#### 2. 随机映射 (-P) +#### 2. 随机映射 + +如果您不关心宿主机使用哪个端口,可以使用随机映射功能。 + 使用 `-P` (大写) 参数,Docker 会随机映射 Dockerfile 中 `EXPOSE` 指令暴露的所有端口到宿主机的高端口(49000-49900)。 @@ -72,6 +79,11 @@ abc123456 0.0.0.0:49153->80/tcp #### docker port +我们可以使用 `docker port` 命令来查看当前容器的端口映射规则。 + + +运行以下命令: + ```bash $ docker port mycontainer 80/tcp -> 0.0.0.0:8080 @@ -80,6 +92,8 @@ $ docker port mycontainer #### docker ps +运行以下命令: + ```bash $ docker ps CONTAINER ID IMAGE PORTS NAMES @@ -92,12 +106,16 @@ abc123456 nginx 0.0.0.0:8080->80/tcp web #### 1. 限制监听 IP +为了保证服务的安全性,我们应该谨慎选择绑定的 IP 地址。 + + 默认情况下,`-p 8080:80` 会监听 `0.0.0.0:8080`,这意味着任何人只要能连接你的宿主机 IP,就能访问该服务。 如果不希望对外暴露(例如数据库服务),应绑定到 `127.0.0.1`: ```bash ## 仅允许本机访问 + $ docker run -d -p 127.0.0.1:3306:3306 mysql ``` @@ -127,6 +145,7 @@ Docker 使用 `docker-proxy` 进程(用户态)或 `iptables` DNAT 规则( ```bash ## 简化的 iptables 逻辑 + iptables -t nat -A DOCKER -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80 ``` diff --git a/08_buildx/8.1_buildkit.md b/08_buildx/8.1_buildkit.md index 93c1865..aaad475 100644 --- a/08_buildx/8.1_buildkit.md +++ b/08_buildx/8.1_buildkit.md @@ -8,6 +8,8 @@ ### `Dockerfile` 新增指令详解 +BuildKit 引入了多项新指令,旨在优化构建缓存和安全性。以下将详细介绍这些指令的用法。 + 使用 BuildKit 后,我们可以使用下面几个新的 `Dockerfile` 指令来加快镜像构建。 要使用最新的 Dockerfile 语法特性,建议在 Dockerfile 开头添加语法指令: @@ -51,6 +53,7 @@ COPY --from=builder /app/dist /app/dist ```docker ## syntax=docker/dockerfile:1 + FROM node:alpine as builder WORKDIR /app @@ -65,6 +68,7 @@ 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 FROM nginx:alpine @@ -72,6 +76,7 @@ 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 @@ -101,6 +106,7 @@ RUN --mount=type=cache,target=/tmp/dist,from=builder,source=/app/dist \ ```docker ## syntax=docker/dockerfile:1 + RUN --mount=type=bind,from=php:alpine,source=/usr/local/bin/docker-php-entrypoint,target=/docker-php-entrypoint \ cat /docker-php-entrypoint ``` @@ -111,6 +117,7 @@ RUN --mount=type=bind,from=php:alpine,source=/usr/local/bin/docker-php-entrypoin ```docker ## syntax=docker/dockerfile:1 + RUN --mount=type=tmpfs,target=/temp \ mount | grep /temp ``` @@ -121,6 +128,7 @@ RUN --mount=type=tmpfs,target=/temp \ ```docker ## syntax=docker/dockerfile:1 + RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \ cat /root/.aws/credentials ``` @@ -135,6 +143,7 @@ $ docker build -t test --secret id=aws,src=$HOME/.aws/credentials . ```docker ## syntax=docker/dockerfile:1 + FROM alpine RUN apk add --no-cache openssh-client RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan gitlab.com >> ~/.ssh/known_hosts @@ -150,6 +159,8 @@ $ docker build -t test --ssh default=$SSH_AUTH_SOCK . ### docker compose build 使用 BuildKit +Docker Compose 同样支持 BuildKit,这使得多服务应用的构建更加高效。 + 自 Docker 23.0 起,BuildKit 已默认启用,无需额外配置。如果使用旧版本,可设置 `DOCKER_BUILDKIT=1` 环境变量启用。 ### 官方文档 diff --git a/08_buildx/8.2_buildx.md b/08_buildx/8.2_buildx.md index d4ea615..31da56e 100644 --- a/08_buildx/8.2_buildx.md +++ b/08_buildx/8.2_buildx.md @@ -2,6 +2,8 @@ ### 使用 +Buildx 的使用非常直观,绝大多数情况下可以替代 `docker build` 命令。 + 你可以直接使用 `docker buildx build` 命令构建镜像。 ```bash @@ -18,9 +20,11 @@ Buildx 使用 [BuildKit 引擎](8.1_buildkit.md) 进行构建,支持许多新 ```bash ## 从 docker-compose.yml 构建所有服务 + $ docker buildx bake ## 仅构建指定目标 + $ docker buildx bake web ``` diff --git a/08_buildx/8.3_multi-arch-images.md b/08_buildx/8.3_multi-arch-images.md index 4235c3e..be31708 100644 --- a/08_buildx/8.3_multi-arch-images.md +++ b/08_buildx/8.3_multi-arch-images.md @@ -4,6 +4,8 @@ Docker 镜像可以支持多种系统架构,这意味着你可以在 `x86_64` ### Manifest List 是什么? +为了理解多架构镜像的原理,我们需要先了解 Manifest List 的概念。 + Manifest list 是一个包含了多个指向不同架构镜像的 manifest 的文件。当你拉取一个支持多架构的镜像时,Docker 会自动根据你当前的系统架构选择并拉取对应的镜像。 例如,官方的 `hello-world` 镜像就支持多种架构。你可以使用 `docker manifest inspect` 命令来查看它的 manifest list: @@ -40,6 +42,8 @@ $ docker manifest inspect hello-world ### 使用 `docker buildx` 构建多架构镜像 +`docker buildx` 是构建多架构镜像的最佳实践工具,它屏蔽了底层的复杂性,提供了一键构建多架构镜像的能力。 + 在 Docker 19.03+ 版本中,`docker buildx` 是推荐的用于构建多架构镜像的工具。它使用 `BuildKit` 作为后端,可以大大简化构建过程。 #### 新建 `builder` 实例 @@ -57,6 +61,7 @@ $ docker buildx inspect --bootstrap ```dockerfile ## Dockerfile + FROM --platform=$TARGETPLATFORM alpine RUN uname -a > /os.txt @@ -96,26 +101,33 @@ COPY bin/dist-${TARGETOS}-${TARGETARCH} /dist ENTRYPOINT ["/dist"] ``` -### 使用 `docker manifest` (底层工具) +### 使用 `docker manifest`(底层工具) + +除了 `docker buildx`,我们也可以直接操作 Manifest List 来手动组合不同架构的镜像。 `docker manifest` 是一个更底层的命令,可以用来创建、检查和推送 manifest list。虽然 `docker buildx` 在大多数情况下更方便,但了解 `docker manifest` 仍然有助于理解其工作原理。 #### 创建 manifest list +运行以下命令: + ```bash ## 首先,为每个架构构建并推送镜像 + $ docker buildx build --platform linux/amd64 -t your-username/my-app:amd64 . --push $ docker buildx build --platform linux/arm64 -t your-username/my-app:arm64 . --push ## 然后,创建一个 manifest list,将它们组合在一起 + $ docker manifest create your-username/my-app:latest \ --amend your-username/my-app:amd64 \ --amend your-username/my-app:arm64 ## 最后,推送 manifest list + $ docker manifest push your-username/my-app:latest ``` #### 检查 manifest list -你可以使用 `docker manifest inspect` 来查看一个 manifest list 的详细信息,如上文所示。 \ No newline at end of file +你可以使用 `docker manifest inspect` 来查看一个 manifest list 的详细信息,如上文所示。 diff --git a/08_buildx/README.md b/08_buildx/README.md index e7ce247..70fda46 100644 --- a/08_buildx/README.md +++ b/08_buildx/README.md @@ -3,3 +3,11 @@ Docker Buildx 是一个 docker CLI 插件,其扩展了 docker 命令,支持 [Moby BuildKit](8.1_buildkit.md) 提供的功能。提供了与 docker build 相同的用户体验,并增加了许多新功能。 > 该功能仅适用于 Docker v19.03+ 版本 + +## 本章内容 + +本章将详细介绍 Docker Buildx 的使用,包括: + +* [使用 BuildKit 构建镜像](8.1_buildkit.md) +* [使用 Buildx 构建镜像](8.2_buildx.md) +* [构建多种系统架构支持的 Docker 镜像](8.3_multi-arch-images.md) diff --git a/09_compose/9.2_install.md b/09_compose/9.2_install.md index 42f6261..51e82a6 100644 --- a/09_compose/9.2_install.md +++ b/09_compose/9.2_install.md @@ -34,6 +34,8 @@ $ chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose ### 测试安装 +运行以下命令: + ```bash $ docker compose version Docker Compose version v2.40.3 @@ -41,6 +43,8 @@ Docker Compose version v2.40.3 ### bash 补全命令 +运行以下命令: + ```bash $ curl -L https://raw.githubusercontent.com/docker/compose/v2.40.3/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose ``` @@ -51,4 +55,4 @@ $ curl -L https://raw.githubusercontent.com/docker/compose/v2.40.3/contrib/compl ```bash $ rm $DOCKER_CONFIG/cli-plugins/docker-compose -``` \ No newline at end of file +``` diff --git a/09_compose/9.3_usage.md b/09_compose/9.3_usage.md index 10e2ed4..f54d765 100644 --- a/09_compose/9.3_usage.md +++ b/09_compose/9.3_usage.md @@ -1,5 +1,7 @@ ## 使用 +本节将通过一个具体的 Web 应用案例,介绍 Docker Compose 的基本概念和使用方法。 + ### 术语 首先介绍几个术语。 @@ -67,6 +69,8 @@ services: #### 运行 compose 项目 +运行以下命令: + ```bash $ docker compose up ``` @@ -78,18 +82,24 @@ $ docker compose up #### 后台运行 +运行以下命令: + ```bash $ docker compose up -d ``` #### 停止 +运行以下命令: + ```bash $ docker compose stop ``` #### 进入服务 +运行以下命令: + ```bash $ docker compose exec redis sh /data # redis-cli @@ -99,36 +109,48 @@ $ docker compose exec redis sh #### 查看日志 +运行以下命令: + ```bash $ docker compose logs -f ``` #### 构建镜像 +运行以下命令: + ```bash $ docker compose build ``` #### 启动服务 +运行以下命令: + ```bash $ docker compose start ``` #### 运行一次性命令 +运行以下命令: + ```bash $ docker compose run web python app.py ``` #### 验证 `docker-compose.yml` +运行以下命令: + ```bash $ docker compose config ``` #### 删除项目 +运行以下命令: + ```bash $ docker compose down ``` diff --git a/09_compose/9.4_commands.md b/09_compose/9.4_commands.md index 1c786a0..ac07f18 100644 --- a/09_compose/9.4_commands.md +++ b/09_compose/9.4_commands.md @@ -1,5 +1,7 @@ ## Compose 命令说明 +Docker Compose 提供了丰富的命令来管理项目和容器。本节将详细介绍这些命令的使用格式和常用选项。 + ### 命令对象与格式 对于 Compose 来说,大部分命令的对象既可以是项目本身,也可以指定为项目中的服务或者容器。如果没有特别的说明,命令对象将是项目,这意味着项目中所有的服务都会受到命令影响。 @@ -147,6 +149,7 @@ $ docker compose kill -s SIGINT * `-v` 删除容器所挂载的数据卷。 #### `run` + 格式为 `docker compose run [options] [-p PORT...] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...]`。 在指定服务上执行一个命令。 diff --git a/09_compose/9.5_compose_file.md b/09_compose/9.5_compose_file.md index 87dfb1d..57a37cc 100644 --- a/09_compose/9.5_compose_file.md +++ b/09_compose/9.5_compose_file.md @@ -204,6 +204,7 @@ env_file: ```bash ## common.env: Set development environment + PROG_ENV=development ``` @@ -568,6 +569,7 @@ db: ```bash ## 支持 # 号注释 + MONGO_VERSION=3.6 ``` diff --git a/09_compose/9.6_django.md b/09_compose/9.6_django.md index 835aa3d..3859ea3 100644 --- a/09_compose/9.6_django.md +++ b/09_compose/9.6_django.md @@ -46,22 +46,29 @@ $ mkdir django-docker && cd django-docker ### Step 1: 创建 Dockerfile +具体内容如下: + ```docker FROM python:3.12-slim ## 防止 Python 缓冲 stdout/stderr,让日志实时输出 + ENV PYTHONUNBUFFERED=1 ## 设置工作目录 + WORKDIR /code ## 先复制依赖文件,利用 Docker 缓存加速构建 + COPY requirements.txt /code/ ## 安装依赖 + RUN pip install --no-cache-dir -r requirements.txt ## 复制项目代码 + COPY . /code/ ``` @@ -79,6 +86,8 @@ COPY . /code/ ### Step 2: 创建 requirements.txt +具体内容如下: + ```txt Django>=5.0,<6.0 psycopg[binary]>=3.1,<4.0 @@ -95,6 +104,8 @@ gunicorn>=21.0,<22.0 ### Step 3: 创建 docker-compose.yml +Step 3: 创建 docker-compose.yml 配置如下: + ```yaml services: db: @@ -132,6 +143,8 @@ volumes: #### db 服务 +db 服务 配置如下: + ```yaml db: image: postgres:16 # 使用官方 PostgreSQL 16 镜像 @@ -150,6 +163,8 @@ db: #### web 服务 +web 服务 配置如下: + ```yaml web: build: . # 从当前目录的 Dockerfile 构建 @@ -222,6 +237,7 @@ DATABASES = { } ## 允许的主机(开发环境) + ALLOWED_HOSTS = ['*'] ``` @@ -231,6 +247,8 @@ ALLOWED_HOSTS = ['*'] ### Step 6: 启动应用 +运行以下命令: + ```bash $ docker compose up ``` @@ -255,15 +273,19 @@ web-1 | Starting development server at http://0.0.0.0:8000/ ```bash ## 执行数据库迁移 + $ docker compose exec web python manage.py migrate ## 创建超级用户 + $ docker compose exec web python manage.py createsuperuser ## 进入 Django shell + $ docker compose exec web python manage.py shell ## 进入 PostgreSQL 命令行 + $ docker compose exec db psql -U django_user -d django_db ``` @@ -285,6 +307,7 @@ $ docker compose exec db psql -U django_user -d django_db ```bash ## 调试:检查数据库是否正常运行 + $ docker compose ps $ docker compose logs db ``` @@ -299,8 +322,11 @@ $ docker compose logs db #### Q3: 权限问题(Linux) +运行以下命令: + ```bash ## 如果容器内创建的文件 root 用户所有 + $ sudo chown -R $USER:$USER . ``` @@ -320,6 +346,7 @@ $ sudo chown -R $USER:$USER . ```yaml ## docker-compose.prod.yml + services: web: build: . diff --git a/09_compose/9.7_rails.md b/09_compose/9.7_rails.md index 9cf1044..4a6ac3c 100644 --- a/09_compose/9.7_rails.md +++ b/09_compose/9.7_rails.md @@ -6,6 +6,8 @@ ### 架构概览 +具体内容如下: + ``` ┌─────────────────────────────────────────────────────────────┐ │ Docker Compose 网络 │ @@ -37,23 +39,29 @@ $ mkdir rails-docker && cd rails-docker ### Step 1: 创建 Dockerfile +具体内容如下: + ```docker FROM ruby:3.2 ## 安装系统依赖 + RUN apt-get update -qq && \ apt-get install -y build-essential libpq-dev nodejs && \ rm -rf /var/lib/apt/lists/* ## 设置工作目录 + WORKDIR /myapp ## 先复制 Gemfile,利用缓存加速构建 + COPY Gemfile /myapp/Gemfile COPY Gemfile.lock /myapp/Gemfile.lock RUN bundle install ## 复制应用代码 + COPY . /myapp ``` @@ -83,6 +91,8 @@ $ touch Gemfile.lock ### Step 3: 创建 docker-compose.yml +Step 3: 创建 docker-compose.yml 配置如下: + ```yaml services: db: @@ -176,6 +186,8 @@ production: ### Step 7: 启动应用 +运行以下命令: + ```bash $ docker compose up ``` @@ -206,20 +218,27 @@ Created database 'myapp_test' ### 常用开发命令 +运行以下命令: + ```bash ## 数据库迁移 + $ docker compose exec web rails db:migrate ## Rails 控制台 + $ docker compose exec web rails console ## 运行测试 + $ docker compose exec web rails test ## 生成脚手架 + $ docker compose exec web rails generate scaffold Post title:string body:text ## 进入容器 Shell + $ docker compose exec web bash ``` diff --git a/09_compose/9.8_wordpress.md b/09_compose/9.8_wordpress.md index 394760d..f0a67ae 100644 --- a/09_compose/9.8_wordpress.md +++ b/09_compose/9.8_wordpress.md @@ -1,13 +1,13 @@ ## 实战 WordPress -### 简介 - WordPress 是全球最流行的内容管理系统(CMS)。使用 Docker Compose 可以在几分钟内搭建一个包含数据库、Web 服务和持久化存储的生产级 WordPress 环境。 --- ### 项目结构 +具体内容如下: + ``` wordpress/ ├── docker-compose.yml @@ -77,7 +77,7 @@ networks: ### 配置文件详解 -#### 1. 环境变量 (.env) +#### 1. 环境变量(.env) 为了安全,不要在 `docker-compose.yml` 中直接写密码。创建 `.env` 文件: @@ -135,6 +135,7 @@ $ docker compose logs -f ```bash ## 导出 SQL + $ docker exec wordpress_db mysqldump -u wordpress -pwordpress wordpress > backup.sql ``` diff --git a/10_ops/logs/README.md b/10_ops/logs/README.md index 768ed8c..b27a7ba 100644 --- a/10_ops/logs/README.md +++ b/10_ops/logs/README.md @@ -1,8 +1,8 @@ -## 日志管理 +# 日志管理 在容器化环境中,日志管理比传统环境更为复杂。容器是短暂的,意味着容器内的日志文件可能会随着容器的销毁而丢失。因此,我们需要一种集中式的日志管理方案来收集、存储和分析容器日志。 -### Docker 日志驱动 +## Docker 日志驱动 Docker 提供了多种日志驱动(Log Driver)机制,允许我们将容器日志转发到不同的后端。 @@ -15,7 +15,7 @@ Docker 提供了多种日志驱动(Log Driver)机制,允许我们将容器 * `gelf`: 支持 GELF 协议的日志后端(如 Graylog)。 * `awslogs`: 发送到 Amazon CloudWatch Logs。 -### 日志管理方案 +## 日志管理方案 对于大规模的容器集群,我们通常会采用 EFK (Elasticsearch + Fluentd + Kibana) 或 ELK (Elasticsearch + Logstash + Kibana) 方案。 diff --git a/10_ops/logs/elk.md b/10_ops/logs/elk.md index c505d81..3d756a9 100644 --- a/10_ops/logs/elk.md +++ b/10_ops/logs/elk.md @@ -1,5 +1,7 @@ ## ELK/EFK 堆栈 +## ELK/EFK 堆栈 + ELK (Elasticsearch, Logstash, Kibana) 是目前业界最流行的开源日志解决方案。而在容器领域,由于 Fluentd 更加轻量级且对容器支持更好,EFK (Elasticsearch, Fluentd, Kibana) 组合也变得非常流行。 ### 方案架构 @@ -13,8 +15,14 @@ ELK (Elasticsearch, Logstash, Kibana) 是目前业界最流行的开源日志解 ### 部署流程 +### 部署流程 + +我们将使用 Docker Compose 来一键部署整个日志堆栈。 + #### 1. 编写 docker-compose.yml +1. 编写 docker-compose.yml 配置如下: + ```yaml version: '3' services: @@ -117,7 +125,7 @@ docker run -d \ #### 4. 在 Kibana 中查看日志 1. 访问 `http://localhost:5601`。 -2. 进入 **Management** -> **Kibana** -> **Index Patterns**。 +2. 进入 **Management**->**Kibana**->**Index Patterns**。 3. 创建新的 Index Pattern,输入 `docker-*` (我们在 fluent.conf 中配置的前缀)。 4. 选择 `@timestamp` 作为时间字段。 5. 去 **Discover** 页面,你就能看到 Nginx 容器的日志了。 diff --git a/10_ops/monitor/README.md b/10_ops/monitor/README.md index 2b6eea1..502fd63 100644 --- a/10_ops/monitor/README.md +++ b/10_ops/monitor/README.md @@ -1,10 +1,10 @@ -## 容器监控 +# 容器监控 容器化技术的普及使得应用部署变得更加灵活和高效,但也给监控带来了新的挑战。 在传统架构中,我们通常关注主机的 CPU、内存、磁盘 IO 等指标。而在容器环境下,除了主机层面的监控,我们更关注容器级别的资源使用情况、服务的运行状态以及编排系统的健康状况。 -### 常见的监控方案 +## 常见的监控方案 目前主流的容器监控方案包括: diff --git a/10_ops/monitor/prometheus.md b/10_ops/monitor/prometheus.md index cb08b54..6633c33 100644 --- a/10_ops/monitor/prometheus.md +++ b/10_ops/monitor/prometheus.md @@ -1,5 +1,9 @@ ## Prometheus + Grafana +## Prometheus + Grafana + +Prometheus 和 Grafana 是目前最流行的开源监控组合,前者负责数据采集与存储,后者负责数据可视化。 + [Prometheus](https://prometheus.io/) 是一个开源的系统监控和报警工具包。它受 Google Borgmon 的启发,由 SoundCloud 在 2012 年创建。 ### 架构简介 @@ -13,6 +17,8 @@ Prometheus 的主要组件包括: ### 快速部署 +### 快速部署 + 我们可以使用 Docker Compose 快速部署一套 Prometheus + Grafana 监控环境。 #### 1. 准备配置文件 @@ -90,6 +96,8 @@ networks: #### 3. 启动服务 +运行以下命令: + ```bash $ docker-compose up -d ``` diff --git a/10_ops/security/README.md b/10_ops/security/README.md index 202da67..4481999 100644 --- a/10_ops/security/README.md +++ b/10_ops/security/README.md @@ -1,8 +1,8 @@ -## 安全 +# 安全 容器安全是生产环境部署的核心考量。本章介绍 Docker 的安全机制和最佳实践。 -### 容器安全的本质 +## 容器安全的本质 > **核心问题**:容器共享宿主机内核,隔离性弱于虚拟机。如何在便利性和安全性之间取得平衡? @@ -23,9 +23,9 @@ --- -### 核心安全机制 +## 核心安全机制 -#### 1. 命名空间(Namespace) +### 1. 命名空间(Namespace) 提供进程、网络、文件系统等资源的隔离: @@ -40,22 +40,25 @@ 详见 [命名空间](../13_implementation/13.2_namespace.md) 章节。 -#### 2. 控制组(Cgroups) +### 2. 控制组(Cgroups) 限制容器的资源使用,防止资源耗尽攻击: ```bash ## 限制内存(超出会被 OOM Kill) + $ docker run -m 512m myapp ## 限制 CPU + $ docker run --cpus=1.5 myapp ## 限制磁盘 I/O + $ docker run --device-write-bps /dev/sda:10mb myapp ``` -#### 3. 能力机制(Capabilities) +### 3. 能力机制(Capabilities) Linux 将 root 权限拆分为多个细粒度的能力。Docker 默认禁用危险能力: @@ -69,62 +72,74 @@ Linux 将 root 权限拆分为多个细粒度的能力。Docker 默认禁用危 ```bash ## 删除所有能力,只添加需要的 + $ docker run --cap-drop=all --cap-add=NET_BIND_SERVICE myapp ## 查看容器的能力 + $ docker exec myapp cat /proc/1/status | grep Cap ``` --- -### 镜像安全 +## 镜像安全 -#### 使用可信镜像 +### 使用可信镜像 + +运行以下命令: ```bash ## ✅ 使用官方镜像 + $ docker pull nginx ## ✅ 使用经过验证的镜像 + $ docker pull bitnami/nginx ## ⚠️ 谨慎使用未知来源镜像 + $ docker pull randomuser/suspicious-image ``` -#### 漏洞扫描 +### 漏洞扫描 扫描镜像中的已知安全漏洞: ```bash ## Docker Scout(官方工具) + $ docker scout cves nginx:latest $ docker scout recommendations nginx:latest ## Trivy(开源工具) + $ trivy image nginx:latest ## Snyk(商业工具) + $ snyk container test nginx:latest ``` -#### 镜像签名验证 +### 镜像签名验证 使用 Docker Content Trust (DCT) 验证镜像来源: ```bash ## 启用镜像签名验证 + $ export DOCKER_CONTENT_TRUST=1 ## 此后的 pull/push 会验证签名 + $ docker pull myregistry/myimage:latest ``` --- -### 运行时安全 +## 运行时安全 -#### 1. 非 root 用户运行 +### 1. 非 root 用户运行 > 笔者强调:这是最重要的安全实践之一。 @@ -132,14 +147,17 @@ $ docker pull myregistry/myimage:latest FROM node:22-alpine ## 创建非 root 用户 + RUN addgroup -g 1001 appgroup && \ adduser -u 1001 -G appgroup -D appuser ## 设置工作目录权限 + WORKDIR /app COPY --chown=appuser:appgroup . . ## 切换用户 + USER appuser CMD ["node", "server.js"] @@ -151,27 +169,37 @@ CMD ["node", "server.js"] $ docker run -u 1001:1001 myapp ``` -#### 2. 只读文件系统 +### 2. 只读文件系统 + +运行以下命令: ```bash ## 根文件系统只读 + $ docker run --read-only myapp ## 需要写入的目录使用 tmpfs + $ docker run --read-only --tmpfs /tmp --tmpfs /var/run myapp ``` -#### 3. 禁用特权模式 +### 3. 禁用特权模式 + +运行以下命令: ```bash ## ❌ 绝对不要在生产环境使用 + $ docker run --privileged myapp ## ✅ 只添加必要的能力 + $ docker run --cap-add=SYS_TIME myapp ``` -#### 4. 限制资源 +### 4. 限制资源 + +运行以下命令: ```bash $ docker run \ @@ -182,75 +210,98 @@ $ docker run \ myapp ``` -#### 5. 网络隔离 +### 5. 网络隔离 + +运行以下命令: ```bash ## 禁用网络(适用于不需要网络的任务) + $ docker run --network=none myapp ## 使用自定义网络隔离 + $ docker network create --internal isolated_net $ docker run --network=isolated_net myapp ``` --- -### Dockerfile 安全实践 +## Dockerfile 安全实践 -#### 1. 使用精简基础镜像 +### 1. 使用精简基础镜像 + +Dockerfile 内容如下: ```dockerfile ## ✅ 好:使用精简镜像 + FROM node:22-alpine # ~50MB FROM gcr.io/distroless/nodejs # ~20MB ## ❌ 差:使用完整镜像 + FROM node:22 # ~1GB FROM ubuntu:24.04 # ~78MB ``` -#### 2. 多阶段构建 +### 2. 多阶段构建 + +Dockerfile 内容如下: ```dockerfile ## 构建阶段 + FROM node:22 AS builder WORKDIR /app COPY . . RUN npm install && npm run build ## 生产阶段(不包含开发依赖和源码) + FROM node:22-alpine COPY --from=builder /app/dist /app USER node CMD ["node", "/app/server.js"] ``` -#### 3. 不存储敏感信息 +### 3. 不存储敏感信息 + +Dockerfile 内容如下: ```dockerfile ## ❌ 错误:敏感信息写入镜像 + ENV DB_PASSWORD=secret123 COPY .env /app/ ## ✅ 正确:运行时传入 + ## docker run -e DB_PASSWORD=xxx 或使用 Docker Secrets + +具体内容如下: + ``` -#### 4. 固定依赖版本 +### 4. 固定依赖版本 + +Dockerfile 内容如下: ```dockerfile ## ✅ 固定版本 + FROM node:22.12.0-alpine3.21 RUN apk add --no-cache curl=8.5.0-r0 ## ❌ 使用 latest + FROM node:latest RUN apk add curl ``` --- -### 安全扫描清单 +## 安全扫描清单 部署前检查: @@ -267,9 +318,9 @@ RUN apk add curl --- -### 高级安全方案 +## 高级安全方案 -#### Seccomp 系统调用过滤 +### Seccomp 系统调用过滤 限制容器可以使用的系统调用: @@ -277,7 +328,7 @@ RUN apk add curl $ docker run --security-opt seccomp=/path/to/profile.json myapp ``` -#### AppArmor / SELinux +### AppArmor / SELinux 使用强制访问控制: @@ -285,48 +336,51 @@ $ docker run --security-opt seccomp=/path/to/profile.json myapp $ docker run --security-opt apparmor=docker-default myapp ``` -#### 安全容器(gVisor / Kata) +### 安全容器(gVisor / Kata) 需要更强隔离时: ```bash ## 使用 gVisor 运行时 + $ docker run --runtime=runsc myapp ``` --- -### 软件供应链安全 +## 软件供应链安全 随着软件供应链攻击日益频繁,仅保障运行时安全已不足够。 -#### 1. SBOM (软件物料清单) +### 1. SBOM(软件物料清单) SBOM 类似于食品的配料表,列出了容器镜像中包含的所有软件包及其版本。 - **生成 SBOM**: 使用 `docker buildx build --sbom` 或 `docker scout sbom`。 - **管理 SBOM**: 确保持续监控 SBOM 中的组件是否存在新披露的漏洞。 -#### 2. 镜像签名 (Sigstore / Notary v2) +### 2. 镜像签名(Sigstore / Notary v2) 确保镜像在构建后未被篡改,且确实来自可信的发布者。 - **Cosign**: Sigstore 项目的一部分,用于签署和验证容器镜像。 ```bash ## 签署镜像 + $ cosign sign --key cosign.key myimage:tag ## 验证镜像 + $ cosign verify --key cosign.pub myimage:tag ``` -#### 3. SLSA (Supply-chain Levels for Software Artifacts) +### 3. SLSA(Supply-chain Levels for Software Artifacts) 遵循 SLSA 框架,确保构建过程的完整性,例如使用 GitHub Actions 等受控环境进行构建,而非在开发者本地机器上构建发布。 --- -### 本章小结 +## 本章小结 | 安全措施 | 重要程度 | 实现方式 | |---------|---------|---------| @@ -337,7 +391,7 @@ $ cosign verify --key cosign.pub myimage:tag | 最小能力 | ⭐⭐ | `--cap-drop=all` | | 镜像签名 | ⭐⭐ | Docker Content Trust | -### 延伸阅读 +## 延伸阅读 - [命名空间](../13_implementation/13.2_namespace.md):隔离机制详解 - [控制组](../13_implementation/13.3_cgroups.md):资源限制详解 diff --git a/10_ops/security/kernel_capability.md b/10_ops/security/kernel_capability.md index a11528a..49b6420 100644 --- a/10_ops/security/kernel_capability.md +++ b/10_ops/security/kernel_capability.md @@ -1,5 +1,9 @@ ## 内核能力机制 +## 内核能力机制 + +Docker 利用 Linux 的能力机制(Capabilities)来限制容器的权限,从而提高系统的安全性。 + [能力机制(Capability)](https://man7.org/linux/man-pages/man7/capabilities.7.html) 是 Linux 内核一个强大的特性,可以提供细粒度的权限访问控制。 Linux 内核自 2.2 版本起就支持能力机制,它将权限划分为更加细粒度的操作能力,既可以作用在进程上,也可以作用在文件上。 diff --git a/10_ops/security/kernel_ns.md b/10_ops/security/kernel_ns.md index ae7f5ff..2c5390f 100644 --- a/10_ops/security/kernel_ns.md +++ b/10_ops/security/kernel_ns.md @@ -1,5 +1,9 @@ ## 内核命名空间 +## 内核命名空间 + +命名空间(Namespace)是 Linux 容器隔离的基础,它确保了容器内的进程无法干扰主机或其他容器。 + Docker 容器和 LXC 容器很相似,所提供的安全特性也差不多。当用 `docker run` 启动一个容器时,在后台 Docker 为容器创建了一个独立的命名空间和控制组集合。 命名空间提供了最基础也是最直接的隔离,在容器中运行的进程不会被运行在主机上的进程和其它容器发现和作用。 diff --git a/10_ops/security/other_feature.md b/10_ops/security/other_feature.md index 4f098ce..a12eea7 100644 --- a/10_ops/security/other_feature.md +++ b/10_ops/security/other_feature.md @@ -1,5 +1,9 @@ ## 其它安全特性 +## 其它安全特性 + +除了上述机制,Linux 内核还提供了一系列安全增强功能,可以进一步保护容器环境。 + 除了能力机制之外,还可以利用一些现有的安全机制来增强使用 Docker 的安全性,例如 TOMOYO, AppArmor, Seccomp, SELinux, GRSEC 等。 Docker 当前默认只启用了能力机制。用户可以采用多种方案来加强 Docker 主机的安全,例如: diff --git a/10_ops/security/summary.md b/10_ops/security/summary.md index 4ca50e9..5aa7721 100644 --- a/10_ops/security/summary.md +++ b/10_ops/security/summary.md @@ -1,5 +1,9 @@ ## 总结 +## 总结 + +Docker 的安全性依赖于多层隔离机制的协同工作,同时需要用户遵循最佳实践。 + 总体来看,Docker 容器还是十分安全的,特别是在容器内不使用 root 权限来运行进程的话。 另外,用户可以使用现有工具,比如 [Apparmor](https://docs.docker.com/engine/security/apparmor/), [Seccomp](https://docs.docker.com/engine/security/seccomp/), SELinux, GRSEC 来增强安全性;甚至自己在内核中实现更复杂的安全机制。 diff --git a/11_orchestration/etcd/README.md b/11_orchestration/etcd/README.md index 8eda09c..e5664d5 100644 --- a/11_orchestration/etcd/README.md +++ b/11_orchestration/etcd/README.md @@ -1,3 +1,3 @@ -## etcd +# etcd `etcd` 是 `CoreOS` 团队发起的一个管理配置信息和服务发现(`Service Discovery`)的项目,在这一章里面,我们将基于 `etcd 3.x` 版本介绍该项目的目标,安装和使用,以及实现的技术。 diff --git a/11_orchestration/etcd/etcdctl.md b/11_orchestration/etcd/etcdctl.md index e9d398a..69549f7 100644 --- a/11_orchestration/etcd/etcdctl.md +++ b/11_orchestration/etcd/etcdctl.md @@ -91,6 +91,8 @@ etcd 在键的组织上采用了层次化的空间结构(类似于文件系统 #### put +运行以下命令: + ```bash $ etcdctl put /testdir/testkey "Hello world" OK diff --git a/11_orchestration/etcd/install.md b/11_orchestration/etcd/install.md index cae1960..81cf5f0 100644 --- a/11_orchestration/etcd/install.md +++ b/11_orchestration/etcd/install.md @@ -1,5 +1,7 @@ ## 安装 +本节将介绍 etcd 的几种常见安装方式,包括二进制安装、Docker 镜像运行以及在 macOS 上的安装。 + `etcd` 基于 `Go` 语言实现,因此,用户可以从 [项目主页](https://github.com/etcd-io/etcd) 下载源代码自行编译,也可以下载编译好的二进制文件,甚至直接使用制作好的 `Docker` 镜像文件来体验。 >注意:本章节内容基于 etcd `3.4.x` 版本 @@ -14,6 +16,7 @@ $ curl -L https://github.com/etcd-io/etcd/releases/download/v3.4.0/etcd-v3.4.0-linux-amd64.tar.gz -o etcd-v3.4.0-linux-amd64.tar.gz ## 国内用户可以使用以下方式加快下载 + $ curl -L https://download.fastgit.org/etcd-io/etcd/releases/download/v3.4.0/etcd-v3.4.0-linux-amd64.tar.gz -o etcd-v3.4.0-linux-amd64.tar.gz $ tar xzvf etcd-v3.4.0-linux-amd64.tar.gz @@ -90,6 +93,8 @@ quay.io/coreos/etcd:v3.4.0 \ ### macOS 中运行 +运行以下命令: + ```bash $ brew install etcd diff --git a/11_orchestration/etcd/intro.md b/11_orchestration/etcd/intro.md index 9aba55b..b2e61df 100644 --- a/11_orchestration/etcd/intro.md +++ b/11_orchestration/etcd/intro.md @@ -1,5 +1,7 @@ ## 简介 +简介 示意图如下: + ![](../_images/etcd_logo.png) `etcd` 是 `CoreOS` 团队于 2013 年 6 月发起的开源项目,它的目标是构建一个高可用的分布式键值(`key-value`)数据库,基于 `Go` 语言实现。我们知道,在分布式系统中,各种服务的配置信息的管理分享,服务的发现是一个很基本同时也是很重要的问题。`CoreOS` 项目就希望基于 `etcd` 来解决这一问题。 diff --git a/11_orchestration/kubectl/README.md b/11_orchestration/kubectl/README.md index 493a096..19e16a9 100644 --- a/11_orchestration/kubectl/README.md +++ b/11_orchestration/kubectl/README.md @@ -1,4 +1,4 @@ -## kubectl 使用 +# kubectl 使用 [kubectl](https://github.com/kubernetes/kubernetes) 是 Kubernetes 自带的客户端,可以用它来直接操作 Kubernetes。 @@ -8,74 +8,74 @@ kubectl [flags] kubectl [command] ``` -### get +## get 显示一个或多个资源 -### describe +## describe 显示资源详情 -### create +## create 从文件或标准输入创建资源 -### update +## update 从文件或标准输入更新资源 -### delete +## delete 通过文件名、标准输入、资源名或者 label selector 删除资源 -### log +## log 输出 pod 中一个容器的日志 -### rolling-update +## rolling-update 对指定的 replication controller 执行滚动升级 -### exec +## exec 在容器内部执行命令 -### port-forward +## port-forward 将本地端口转发到Pod -### proxy +## proxy 为 Kubernetes API server 启动代理服务器 -### run +## run 在集群中使用指定镜像启动容器 -### expose +## expose 将 replication controller service 或 pod 暴露为新的 kubernetes service -### label +## label 更新资源的 label -### config +## config 修改 kubernetes 配置文件 -### cluster-info +## cluster-info 显示集群信息 -### api-versions +## api-versions 以 "组/版本" 的格式输出服务端支持的 API 版本 -### version +## version 输出服务端和客户端的版本信息 -### help +## help 显示各个命令的帮助信息 diff --git a/11_orchestration/kubernetes/README.md b/11_orchestration/kubernetes/README.md index 5362b76..d54cbb5 100644 --- a/11_orchestration/kubernetes/README.md +++ b/11_orchestration/kubernetes/README.md @@ -1,4 +1,4 @@ -## Kubernetes +# Kubernetes `Kubernetes` 是 Google 团队发起并维护的基于 Docker 的开源容器集群管理系统,它不仅支持常见的云平台,而且支持内部数据中心。 diff --git a/11_orchestration/kubernetes/advanced.md b/11_orchestration/kubernetes/advanced.md index b16b4ca..f1b27b2 100644 --- a/11_orchestration/kubernetes/advanced.md +++ b/11_orchestration/kubernetes/advanced.md @@ -20,7 +20,7 @@ Service 虽然提供了负载均衡,但通常是 4 层(TCP/UDP)。**Ingres 常见的 Ingress Controller有 Nginx Ingress Controller, Traefik, Istio Gateway 等。 -### Persistent Volume (PV) 与 StorageClass +### Persistent Volume(PV) 与 StorageClass 容器内的文件是临时的。对于有状态应用(如数据库),需要持久化存储。 @@ -28,7 +28,7 @@ Service 虽然提供了负载均衡,但通常是 4 层(TCP/UDP)。**Ingres * **PV (Persistent Volume)**:实际的存储资源(NFS, AWS EBS, Ceph 等)。 * **StorageClass**:定义存储类,支持动态创建 PV。 -### Horizontal Pod Autoscaling (HPA) +### Horizontal Pod Autoscaling(HPA) HPA 根据 CPU 利用率或其他指标(如内存、自定义指标)自动扩缩 Deployment 或 ReplicaSet 中的 Pod 数量。 diff --git a/11_orchestration/kubernetes/concepts.md b/11_orchestration/kubernetes/concepts.md index f3ca6db..8222b5f 100644 --- a/11_orchestration/kubernetes/concepts.md +++ b/11_orchestration/kubernetes/concepts.md @@ -1,5 +1,7 @@ ## 基本概念 +基本概念 示意图如下: + ![](../_images/kubernetes_design.jpg) * 节点(`Node`):一个节点是一个运行 Kubernetes 中的主机。 @@ -73,6 +75,8 @@ Kubernetes 校验节点可用依赖于 ID。在当前的版本中,有两个接 #### 容器组设计的初衷 +容器组(Pod)的设计主要是为了解决应用间的紧密协作和资源共享问题。 + #### 资源共享和通信 容器组主要是为了数据共享和它们之间的通信。 @@ -175,14 +179,35 @@ Kubernetes 校验节点可用依赖于 ID。在当前的版本中,有两个接 ### Replication Controllers +> [!NOTE] +> Replication Controller 保证指定数量的 Pod 副本在任何时候都处于运行状态。 + ### 服务 +> [!NOTE] +> 服务(Service)定义一组 Pod 的逻辑集合和访问它们的策略。 + ### 卷 +> [!NOTE] +> 卷(Volume)包含可被 Pod 中容器访问的数据的目录。 + ### 标签 +> [!NOTE] +> 标签(Label)是附加到对象(如 Pods)上的键值对,用于组织和选择对象子集。 + ### 接口权限 +> [!NOTE] +> 接口权限通过认证、授权和准入控制来保护 Kubernetes API 的访问。 + ### web界面 +> [!NOTE] +> Kubernetes Dashboard 是一个基于 Web 的用户界面,用于管理集群。 + ### 命令行操作 + +> [!NOTE] +> kubectl 是 Kubernetes 的命令行工具,用于与集群进行交互。 diff --git a/11_orchestration/kubernetes/design.md b/11_orchestration/kubernetes/design.md index b3f5c42..28ae7d0 100644 --- a/11_orchestration/kubernetes/design.md +++ b/11_orchestration/kubernetes/design.md @@ -25,6 +25,8 @@ ### 控制平面 +控制平面(Control Plane)是 Kubernetes 集群的大脑,负责做出全局决策(如调度)以及检测和响应集群事件。 + #### 主节点服务 主节点上需要提供如下的管理服务: diff --git a/11_orchestration/kubernetes/intro.md b/11_orchestration/kubernetes/intro.md index d98d220..980b070 100644 --- a/11_orchestration/kubernetes/intro.md +++ b/11_orchestration/kubernetes/intro.md @@ -1,5 +1,7 @@ ## Kubernetes 简介 +Kubernetes 简介 示意图如下: + ![](../_images/kubernetes_logo.png) ### 什么是 Kubernetes @@ -28,19 +30,24 @@ Kubernetes 完美解决了这些问题。 ### 核心概念 -#### Pod (豆荚) +#### Pod(豆荚) + Kubernetes 的最小调度单位。一个 Pod 可以包含一个或多个紧密协作的容器(共享网络和存储)。就像豌豆荚里的豌豆一样。 -#### Node (节点) +#### Node(节点) + 运行 Pod 的物理机或虚拟机。 -#### Deployment (部署) +#### Deployment(部署) + 定义应用的期望状态(如:需要 3 个副本,镜像版本为 v1)。K8s 会持续确保当前状态符合期望状态。 -#### Service (服务) +#### Service(服务) + 定义一组 Pod 的访问策略。提供稳定的 Cluster IP 和 DNS 名称,负责负载均衡。 -#### Namespace (命名空间) +#### Namespace(命名空间) + 用于多租户资源隔离。 --- @@ -60,7 +67,7 @@ Kubernetes 的最小调度单位。一个 Pod 可以包含一个或多个紧密 ### 架构 -Kubernetes 也是 C/S 架构,由 **Master (控制平面)** 和 **Worker (工作节点)** 组成: +Kubernetes 也是 C/S 架构,由 **Master (控制平面)**和**Worker (工作节点)** 组成: - **Control Plane**:负责决策(API Server, Scheduler, Controller Manager, etcd) - **Worker Node**:负责干活(Kubelet, Kube-proxy, Container Runtime) diff --git a/11_orchestration/kubernetes/practice.md b/11_orchestration/kubernetes/practice.md index abbdcd0..f0fc08f 100644 --- a/11_orchestration/kubernetes/practice.md +++ b/11_orchestration/kubernetes/practice.md @@ -75,7 +75,7 @@ kubectl get svc nginx-service 如果输出端口是 `80:30080/TCP`,你可以通过 `http://:30080` 访问 Nginx。 -### 步骤 3:模拟滚动更新 (Rolling Update) +### 步骤 3:模拟滚动更新(Rolling Update) 修改 `nginx-deployment.yaml`,将镜像版本改为 `nginx:latest`。 diff --git a/11_orchestration/setup/README.md b/11_orchestration/setup/README.md index 101db67..4275d0d 100644 --- a/11_orchestration/setup/README.md +++ b/11_orchestration/setup/README.md @@ -1,4 +1,4 @@ -## 部署 Kubernetes +# 部署 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) 等)。 diff --git a/11_orchestration/setup/docker-desktop.md b/11_orchestration/setup/docker-desktop.md index f32b186..6a0da62 100644 --- a/11_orchestration/setup/docker-desktop.md +++ b/11_orchestration/setup/docker-desktop.md @@ -12,6 +12,8 @@ ### 测试 +运行以下命令: + ```bash $ kubectl version ``` diff --git a/11_orchestration/setup/k3s.md b/11_orchestration/setup/k3s.md index c750858..6a4b45e 100644 --- a/11_orchestration/setup/k3s.md +++ b/11_orchestration/setup/k3s.md @@ -11,6 +11,8 @@ ### 安装 +K3s 的安装非常简单,官方提供了便捷的安装脚本。 + #### 脚本安装(Linux) K3s 提供了极为便捷的安装脚本: @@ -23,6 +25,8 @@ curl -sfL https://get.k3s.io | sh - #### 查看状态 +运行以下命令: + ```bash sudo k3s kubectl get nodes ``` @@ -39,14 +43,18 @@ K3s 内置了 `kubectl` 命令(通过 `k3s kubectl` 调用),为了方便 ```bash ## 读取 K3s 的配置文件 + export KUBECONFIG=/etc/rancher/k3s/k3s.yaml ## 现在可以直接使用 kubectl + kubectl get pods -A ``` ### 清理卸载 +运行以下命令: + ```bash /usr/local/bin/k3s-uninstall.sh ``` diff --git a/11_orchestration/setup/kind.md b/11_orchestration/setup/kind.md index 202d481..750191f 100644 --- a/11_orchestration/setup/kind.md +++ b/11_orchestration/setup/kind.md @@ -4,6 +4,8 @@ ### 为什么选择 Kind +Kind 相比其他本地集群方案(如 Minikube)有以下显著优势: + * **轻量便捷**:只要有 Docker 环境即可,无需额外虚拟机。 * **多集群支持**:可以轻松在本地启动多个集群。 * **多版本支持**:支持指定 Kubernetes 版本进行测试。 @@ -11,18 +13,23 @@ ### 安装 Kind +Kind 是一个二进制文件,并在 PATH 中即可使用。以下是不同系统的安装方法。 + #### macOS +运行以下命令: + ```bash brew install kind ``` -#### Linux / Windows (WSL2) +#### Linux / Windows(WSL2) 可以下载二进制文件: ```bash ## Linux AMD64 + curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64 chmod +x ./kind sudo mv ./kind /usr/local/bin/kind @@ -76,6 +83,8 @@ kind create cluster --config kind-config.yaml ### 删除集群 +运行以下命令: + ```bash kind delete cluster ``` diff --git a/11_orchestration/setup/kubeadm-docker.md b/11_orchestration/setup/kubeadm-docker.md index facfd61..5d44bc0 100644 --- a/11_orchestration/setup/kubeadm-docker.md +++ b/11_orchestration/setup/kubeadm-docker.md @@ -1,4 +1,4 @@ -## 使用 kubeadm 部署 kubernetes(使用 Docker) +## 使用 kubeadm 部署 kubernetes(使用 Docker) `kubeadm` 提供了 `kubeadm init` 以及 `kubeadm join` 这两个命令作为快速创建 `kubernetes` 集群的最佳实践。 @@ -8,8 +8,12 @@ ### 安装 **kubelet** **kubeadm** **kubectl** +需要在每台机器上安装以下的软件包: + #### Ubuntu/Debian +运行以下命令: + ```bash $ apt-get update && apt-get install -y apt-transport-https $ curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add - @@ -24,6 +28,8 @@ $ apt-get install -y kubelet kubeadm kubectl #### CentOS/Fedora +运行以下命令: + ```bash $ cat < example.ign ``` @@ -41,6 +44,8 @@ $ sudo coreos-installer install /dev/sda --ignition-file example.ign ### 使用 +运行以下命令: + ```bash $ ssh core@虚拟机IP diff --git a/12_ecosystem/coreos/intro.md b/12_ecosystem/coreos/intro.md index 47799c3..3f9cb6f 100644 --- a/12_ecosystem/coreos/intro.md +++ b/12_ecosystem/coreos/intro.md @@ -20,7 +20,7 @@ FCOS 使用 rpm-ostree 系统进行事务性升级。无需像 yum 升级那样 #### 容器工具 -对于诸如构建,复制和其他管理容器的任务,FCOS 用一组容器工具代替了 **Docker CLI**。**podman CLI** 工具支持许多容器运行时功能,例如运行,启动,停止,列出和删除容器和镜像。**skopeo CLI** 工具可以复制,认证和签名镜像。您还可以使用 **crictl CLI** 工具来处理 CRI-O 容器引擎中的容器和镜像。 +对于诸如构建,复制和其他管理容器的任务,FCOS 用一组容器工具代替了 **Docker CLI**。**podman CLI**工具支持许多容器运行时功能,例如运行,启动,停止,列出和删除容器和镜像。**skopeo CLI**工具可以复制,认证和签名镜像。您还可以使用**crictl CLI** 工具来处理 CRI-O 容器引擎中的容器和镜像。 ### 参考文档 diff --git a/12_ecosystem/podman/README.md b/12_ecosystem/podman/README.md index 15c2958..2ad2566 100644 --- a/12_ecosystem/podman/README.md +++ b/12_ecosystem/podman/README.md @@ -1,8 +1,10 @@ -## podman +# podman [`podman`](https://github.com/containers/podman) 是一个无守护进程、与 Docker 命令高度兼容的下一代 Linux 容器工具。它由 Red Hat 开发,旨在提供一个更安全的容器运行环境。 -### Podman vs Docker +## Podman vs Docker + +Podman 和 Docker 在设计理念上存在显著差异,主要体现在架构和权限模型上。 | 特性 | Docker | Podman | | :--- | :--- | :--- | @@ -11,15 +13,19 @@ | **生态** | 完整的生态系统 (Compose, Swarm) | 专注单机容器,配合 Kubernetes 使用 | | **镜像构建** | `docker build` | `podman build` 或 `buildah` | -### 安装 +## 安装 -#### CentOS / RHEL +Podman 支持多种操作系统,安装过程也相对简单。 + +### CentOS / RHEL + +运行以下命令: ```bash $ sudo yum -y install podman ``` -#### macOS +### macOS macOS 上需要安装 Podman Desktop 或通过 Homebrew 安装: @@ -29,11 +35,13 @@ $ podman machine init $ podman machine start ``` -### 使用 +## 使用 `podman` 的命令行几乎与 `docker` 完全兼容,大多数情况下,你只需将 `docker` 替换为 `podman` 即可。 -#### 运行容器 +### 运行容器 + +运行以下命令: ```bash ## $ docker run -d -p 80:80 nginx:alpine @@ -41,31 +49,37 @@ $ podman machine start $ podman run -d -p 80:80 nginx:alpine ``` -#### 列出容器 +### 列出容器 + +运行以下命令: ```bash $ podman ps ``` -#### 构建镜像 +### 构建镜像 + +运行以下命令: ```bash $ podman build -t myimage . ``` -### Pods 的概念 +## Pods 的概念 与 Docker 不同,Podman 支持 "Pod" 的概念(类似于 Kubernetes 的 Pod),允许你在同一个网络命名空间中运行多个容器。 ```bash ## 创建一个 Pod + $ podman pod create --name mypod -p 8080:80 ## 在 Pod 中运行容器 + $ podman run -d --pod mypod --name webbing nginx ``` -### 迁移到 Podman +## 迁移到 Podman 如果你习惯使用 `docker` 命令,可以简单地设置别名: @@ -80,12 +94,15 @@ Podman 可以生成 systemd 单元文件,让容器像普通系统服务一样 ```bash ## 创建容器 + $ podman run -d --name myweb -p 8080:80 nginx ## 生成 systemd 文件 + $ podman generate systemd --name myweb --files --new ## 启用并启动服务 + $ systemctl --user enable --now container-myweb.service ``` diff --git a/13_implementation/13.1_arch.md b/13_implementation/13.1_arch.md index 906b245..9019a35 100644 --- a/13_implementation/13.1_arch.md +++ b/13_implementation/13.1_arch.md @@ -1,5 +1,7 @@ ## 基本架构 +Docker 的架构设计简洁而高效,主要由客户端和服务端两部分组成。 + ### 核心架构图 Docker 采用了 **C/S (客户端/服务端)** 架构。Client 向 Daemon 发送请求,Daemon 负责构建、运行和分发容器。 @@ -25,29 +27,34 @@ graph LR Docker 的内部架构如同洋葱一样分层,每一层专注解决特定问题: -#### 1. Docker CLI (客户端) +#### 1. Docker CLI(客户端) + 用户与 Docker 交互的主要方式。它将用户命令(如 `docker run`)转换为 API 请求发送给 dockerd。 -#### 2. Dockerd (守护进程) +#### 2. Dockerd(守护进程) + Docker 的大脑。 - 监听 API 请求 - 管理 Docker 对象(镜像、容器、网络、卷) - 编排下层组件完成工作 -#### 3. Containerd (高级运行时) +#### 3. Containerd(高级运行时) + 行业标准的容器运行时(CNCF 毕业项目)。 - 管理容器的完整生命周期(启动、停止) - 镜像拉取与存储 - **不包含** 复杂的与容器无关的功能(如构建、API) - Kubernetes 也可以直接使用 containerd(跳过 Docker) -#### 4. Runc (低级运行时) +#### 4. Runc(低级运行时) + 用于创建和运行容器的 CLI 工具。 - 直接与内核交互(Namespaces, Cgroups) - 遵循 OCI (Open Container Initiative) 规范 - **主要职责**:根据配置启动一个容器,然后退出(将控制权交给容器进程) #### 5. Shim + 每个容器都有一个 shim 进程。 - **解耦**:允许 dockerd 重启而不影响容器运行 - **保持 IO**:维持容器的标准输入输出 @@ -88,11 +95,11 @@ flowchart TD Shim -.-> |8. Monitor IO/Exit| Container ``` -1. **CLI** 发送请求给 **Dockerd** -2. **Dockerd** 解析请求,调用 **Containerd** +1. **CLI**发送请求给**Dockerd** +2. **Dockerd**解析请求,调用**Containerd** 3. **Containerd** 准备镜像,转换为 OCI Bundle -4. **Containerd** 创建 **Shim** 进程 -5. **Shim** 调用 **Runc** +4. **Containerd**创建**Shim** 进程 +5. **Shim**调用**Runc** 6. **Runc** 与系统内核交互,创建 Namespaces 和 Cgroups 7. **Runc** 启动 nginx 进程后退出 8. **Shim** 接管容器 IO 和生命周期监控 diff --git a/13_implementation/13.2_namespace.md b/13_implementation/13.2_namespace.md index f01a5bc..c794062 100644 --- a/13_implementation/13.2_namespace.md +++ b/13_implementation/13.2_namespace.md @@ -1,5 +1,7 @@ ## 命名空间 +命名空间(Namespace)是 Linux 内核的一个强大特性,为容器提供了隔离的运行环境。 + ### 什么是 Namespace > **Namespace 是 Linux 内核提供的资源隔离机制,它让容器内的进程仿佛运行在独立的操作系统中。** @@ -35,19 +37,25 @@ Linux 内核提供了以下几种 Namespace,Docker 容器使用了全部: ### PID Namespace +PID Namespace 负责进程 ID 的隔离,使得容器内的进程彼此不可见。 + #### 作用 隔离进程 ID,让每个容器有自己的进程编号空间。 #### 效果 +运行以下命令: + ```bash ## 宿主机上查看进程 + $ ps aux | grep nginx root 12345 0.0 0.1 nginx: master process root 12346 0.0 0.1 nginx: worker process ## 容器内查看进程 + $ docker exec mycontainer ps aux PID USER COMMAND 1 root nginx: master process ← 在容器内是 PID 1 @@ -64,12 +72,16 @@ PID USER COMMAND ### NET Namespace +NET Namespace 负责网络栈的隔离,包括网卡、路由表和 iptables 规则等。 + #### 作用 隔离网络栈,每个容器拥有独立的网络环境。 #### 效果 +具体内容如下: + ``` 宿主机 容器 ┌─────────────────────┐ ┌─────────────────────┐ @@ -89,12 +101,16 @@ PID USER COMMAND ### MNT Namespace +MNT Namespace 负责文件系统挂载点的隔离,确保容器看到独立的文件系统视图。 + #### 作用 隔离文件系统挂载点,每个容器有自己的根目录。 #### 效果 +具体内容如下: + ``` 宿主机文件系统: 容器内看到的: / / ← 容器的根目录 @@ -120,18 +136,24 @@ PID USER COMMAND ### UTS Namespace +UTS Namespace 主要用于隔离主机名和域名。 + #### 作用 隔离主机名和域名,让每个容器可以有自己的主机名。 #### 效果 +运行以下命令: + ```bash ## 宿主机 + $ hostname my-server ## 容器内 + $ docker run --hostname mycontainer ubuntu hostname mycontainer ``` @@ -142,6 +164,8 @@ UTS = "UNIX Time-sharing System",是历史遗留的名称。 ### IPC Namespace +IPC Namespace 用于隔离进程间通信资源,如 System V IPC 和 POSIX 消息队列。 + #### 作用 隔离 System V IPC 和 POSIX 消息队列。 @@ -161,12 +185,16 @@ UTS = "UNIX Time-sharing System",是历史遗留的名称。 ### USER Namespace +USER Namespace 允许将容器内的用户 ID 映射到宿主机的不同用户 ID。 + #### 作用 隔离用户和组 ID,实现权限隔离。 #### 效果 +具体内容如下: + ``` 容器内 宿主机 ┌─────────────────┐ ┌─────────────────┐ @@ -189,16 +217,21 @@ UTS = "UNIX Time-sharing System",是历史遗留的名称。 #### 实验 1:UTS Namespace +运行以下命令: + ```bash ## 创建新的 UTS namespace 并启动 shell + $ sudo unshare --uts /bin/bash ## 修改主机名(只影响这个 namespace) + $ hostname container-test $ hostname container-test ## 退出后查看宿主机主机名(未改变) + $ exit $ hostname my-server @@ -206,14 +239,19 @@ my-server #### 实验 2:PID Namespace +运行以下命令: + ```bash ## 创建新的 PID 和 MNT namespace + $ sudo unshare --pid --mount --fork /bin/bash ## 挂载新的 /proc + $ mount -t proc proc /proc ## 查看进程(只能看到当前 shell) + $ ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 8960 4516 pts/0 S 10:00 0:00 /bin/bash @@ -222,11 +260,15 @@ root 8 0.0 0.0 10072 3200 pts/0 R+ 10:00 0:00 ps aux #### 实验 3:NET Namespace +运行以下命令: + ```bash ## 创建新的网络 namespace + $ sudo unshare --net /bin/bash ## 查看网络接口(只有 lo) + $ ip addr 1: lo: mtu 65536 qdisc noop state DOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 diff --git a/13_implementation/13.3_cgroups.md b/13_implementation/13.3_cgroups.md index f103c6d..15dde7e 100644 --- a/13_implementation/13.3_cgroups.md +++ b/13_implementation/13.3_cgroups.md @@ -1,5 +1,7 @@ ## 控制组 +控制组(Cgroups)是 Linux 内核提供的另一种关键机制,主要用于资源的限制和审计。 + ### 什么是控制组 控制组(Control Groups,简称 cgroups)是 Linux 内核的一个特性,用于**限制、记录和隔离**进程组的资源使用(CPU、内存、磁盘 I/O、网络等)。 @@ -46,16 +48,23 @@ ### Docker 中的资源限制 +Docker 提供了丰富的参数来配置容器的资源限制,主要包括内存、CPU、磁盘 I/O 等。 + #### 内存限制 +运行以下命令: + ```bash ## 限制容器最多使用 512MB 内存 + $ docker run -m 512m myapp ## 限制内存 + swap + $ docker run -m 512m --memory-swap 1g myapp ## 软限制(超过时警告,不会 OOM Kill) + $ docker run --memory-reservation 256m myapp ``` @@ -68,14 +77,19 @@ $ docker run --memory-reservation 256m myapp #### CPU 限制 +运行以下命令: + ```bash ## 限制使用 1.5 个 CPU 核心 + $ docker run --cpus=1.5 myapp ## 限制使用 CPU 0 和 1 + $ docker run --cpuset-cpus="0,1" myapp ## 设置 CPU 使用权重(相对值,默认 1024) + $ docker run --cpu-shares=512 myapp ``` @@ -88,21 +102,29 @@ $ docker run --cpu-shares=512 myapp #### 磁盘 I/O 限制 +运行以下命令: + ```bash ## 限制设备写入速度为 10MB/s + $ docker run --device-write-bps /dev/sda:10mb myapp ## 限制设备读取速度 + $ docker run --device-read-bps /dev/sda:10mb myapp ## 限制 IOPS + $ docker run --device-write-iops /dev/sda:100 myapp ``` #### 进程数限制 +运行以下命令: + ```bash ## 限制最多 100 个进程 + $ docker run --pids-limit=100 myapp ``` @@ -110,17 +132,22 @@ $ docker run --pids-limit=100 myapp ### 查看容器资源使用 +运行以下命令: + ```bash ## 实时监控所有容器的资源使用 + $ docker stats CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O abc123 web 0.50% 45.5MiB / 512MiB 8.89% 1.2kB / 0B 0B / 0B def456 db 2.30% 256MiB / 1GiB 25.00% 5.6kB / 3.2kB 4.1MB / 2.3MB ## 查看特定容器 + $ docker stats mycontainer ## 查看容器的 cgroup 配置 + $ docker inspect mycontainer --format '{{json .HostConfig}}' | jq ``` @@ -130,28 +157,42 @@ $ docker inspect mycontainer --format '{{json .HostConfig}}' | jq #### 内存超限 +运行以下命令: + ```bash ## 启动限制 100MB 内存的容器 + $ docker run -m 100m stress --vm 1 --vm-bytes 200M ## 容器会被 OOM Killer 杀死 + $ docker ps -a CONTAINER ID STATUS NAMES abc123 Exited (137) 5 seconds ago hopeful_darwin -## 137 = 128 + 9,表示被 SIGKILL (9) 杀死 +## 137 = 128 + 9,表示被 SIGKILL(9) 杀死 + +具体内容如下: + ``` #### CPU 限制验证 +运行以下命令: + ```bash ## 不限制 CPU + $ docker run --rm stress --cpu 4 ## 占满所有 CPU ## 限制为 1 个核心 + $ docker run --rm --cpus=1 stress --cpu 4 ## 只能使用约 100% CPU(1 个核心) + +具体内容如下: + ``` --- @@ -168,13 +209,17 @@ $ docker run --rm --cpus=1 stress --cpu 4 #### 检查系统使用的版本 +运行以下命令: + ```bash ## 查看 cgroup 版本 + $ mount | grep cgroup cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime) ## 如果显示 cgroup2 表示 v2 ## 或者 + $ cat /proc/filesystems | grep cgroup nodev cgroup nodev cgroup2 @@ -184,6 +229,8 @@ nodev cgroup2 ### 在 Compose 中设置限制 +在 Compose 中设置限制 配置如下: + ```yaml services: web: @@ -202,23 +249,33 @@ services: ### 最佳实践 +在使用 Cgroups 限制资源时,遵循一些最佳实践可以避免潜在的问题。 + #### 1. 始终设置内存限制 +运行以下命令: + ```bash ## 防止 OOM 影响宿主机 + $ docker run -m 1g myapp ``` #### 2. 为关键应用设置 CPU 保证 +运行以下命令: + ```bash $ docker run --cpus=2 --cpu-shares=2048 critical-app ``` #### 3. 监控资源使用 +运行以下命令: + ```bash ## 配合 Prometheus + cAdvisor 监控 + $ docker run -d --name cadvisor \ -v /:/rootfs:ro \ -v /var/run:/var/run:ro \ diff --git a/13_implementation/13.4_ufs.md b/13_implementation/13.4_ufs.md index 3df7e1a..01889bb 100644 --- a/13_implementation/13.4_ufs.md +++ b/13_implementation/13.4_ufs.md @@ -1,5 +1,7 @@ ## 联合文件系统 +联合文件系统(UnionFS)是 Docker 镜像分层存储的基础,它允许将多个目录挂载为同一个虚拟文件系统。 + ### 什么是联合文件系统 联合文件系统(UnionFS)是一种**分层、轻量级**的文件系统,它将多个目录"联合"挂载到同一个虚拟目录,形成一个统一的文件系统视图。 @@ -31,8 +33,12 @@ ### 为什么 Docker 使用联合文件系统 +Docker 选择联合文件系统作为其存储驱动,主要基于以下几个核心优势。 + #### 1. 镜像分层复用 +具体内容如下: + ``` nginx:alpine myapp:latest │ │ @@ -94,7 +100,7 @@ Docker 可使用多种联合文件系统实现: | 存储驱动 | 说明 | 推荐程度 | |---------|------|---------| -| **overlay2** | 现代 Linux 默认驱动,性能优秀 | ✅ **推荐** | +| **overlay2**| 现代 Linux 默认驱动,性能优秀 | ✅**推荐** | | **aufs** | 早期默认,兼容性好 | 遗留系统 | | **btrfs** | 使用 Btrfs 子卷 | 特定场景 | | **zfs** | 使用 ZFS 数据集 | 特定场景 | @@ -113,6 +119,8 @@ Docker 可使用多种联合文件系统实现: #### 查看当前存储驱动 +运行以下命令: + ```bash $ docker info | grep "Storage Driver" Storage Driver: overlay2 @@ -161,8 +169,11 @@ overlay2 是目前最推荐的存储驱动: ### 查看镜像层 +运行以下命令: + ```bash ## 查看镜像的层信息 + $ docker history nginx:alpine IMAGE CREATED CREATED BY SIZE a6eb2a334a9f 2 weeks ago CMD ["nginx" "-g" "daemon off;"] 0B @@ -173,6 +184,7 @@ a6eb2a334a9f 2 weeks ago CMD ["nginx" "-g" "daemon off;"] 0B ... ## 查看层的存储位置 + $ docker inspect nginx:alpine --format '{{json .GraphDriver.Data}}' | jq { "LowerDir": "/var/lib/docker/overlay2/.../diff:/var/lib/docker/overlay2/.../diff", @@ -186,15 +198,21 @@ $ docker inspect nginx:alpine --format '{{json .GraphDriver.Data}}' | jq ### 最佳实践 +为了构建高效、轻量的镜像,我们在使用联合文件系统时应注意以下几点。 + #### 1. 减少镜像层数 +具体内容如下: + ```docker ## ❌ 每条命令创建一层 + RUN apt-get update RUN apt-get install -y nginx RUN rm -rf /var/lib/apt/lists/* ## ✅ 合并为一层 + RUN apt-get update && \ apt-get install -y nginx && \ rm -rf /var/lib/apt/lists/* diff --git a/13_implementation/13.6_network.md b/13_implementation/13.6_network.md index 4a0c200..3031912 100644 --- a/13_implementation/13.6_network.md +++ b/13_implementation/13.6_network.md @@ -3,6 +3,7 @@ Docker 的网络实现其实就是利用了 Linux 上的网络命名空间和虚拟网络设备(特别是 veth pair)。建议先熟悉了解这两部分的基本概念再阅读本章。 ### 基本原理 + 首先,要实现网络通信,机器需要至少一个网络接口(物理接口或虚拟接口)来收发数据包;此外,如果不同子网之间要进行通信,需要路由机制。 Docker 中的网络接口默认都是虚拟的接口。虚拟接口的优势之一是转发效率较高。 @@ -11,6 +12,7 @@ Linux 通过在内核中进行数据复制来实现虚拟接口之间的数据 Docker 容器网络就利用了这项技术。它在本地主机和容器内分别创建一个虚拟接口,并让它们彼此连通(这样的一对接口叫做 `veth pair`)。 ### 创建网络参数 + Docker 创建一个容器的时候,会执行如下操作: * 创建一对虚拟接口,分别放到本地主机和新容器中; * 本地主机一端桥接到默认的 docker0 或指定网桥上,并具有一个唯一的名字,如 veth65f9; @@ -26,6 +28,7 @@ Docker 创建一个容器的时候,会执行如下操作: * `--net=none` 让 Docker 将新容器放到隔离的网络栈中,但是不进行网络配置。之后,用户可以自己进行配置。 ### 网络配置细节 + 用户使用 `--net=none` 后,可以自行配置网络,让容器达到跟平常一样具有访问网络的权限。通过这个过程,可以了解 Docker 配置网络的细节。 首先,启动一个 `/bin/bash` 容器,指定 `--net=none` 参数。 diff --git a/14_cases/ci/README.md b/14_cases/ci/README.md index 49155c9..69052c8 100644 --- a/14_cases/ci/README.md +++ b/14_cases/ci/README.md @@ -1,7 +1,9 @@ -## CI/CD +# CI/CD -**持续集成(Continuous integration)** 是一种软件开发实践,每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。 +**持续集成(Continuous integration)** 是一种软件开发实践,每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。 + + +**持续部署(continuous deployment)** 是通过自动化的构建、测试和部署循环来快速交付高质量的产品。 -**持续部署(continuous deployment)** 是通过自动化的构建、测试和部署循环来快速交付高质量的产品。 与 `Jenkins` 不同的是,基于 Docker 的 CI/CD 每一步都运行在 Docker 容器中,所以理论上支持所有的编程语言。 diff --git a/14_cases/ci/actions/README.md b/14_cases/ci/actions/README.md index 9ca67a3..2048652 100644 --- a/14_cases/ci/actions/README.md +++ b/14_cases/ci/actions/README.md @@ -1,4 +1,4 @@ -## GitHub Actions +# GitHub Actions GitHub [Actions](https://github.com/features/actions) 是 GitHub 推出的一款 CI/CD 工具。 @@ -23,6 +23,6 @@ jobs: args: go version ``` -### 参考资料 +## 参考资料 * [Actions Docs](https://docs.github.com/en/actions) diff --git a/14_cases/ci/devops_workflow.md b/14_cases/ci/devops_workflow.md index b72905a..c9798a3 100644 --- a/14_cases/ci/devops_workflow.md +++ b/14_cases/ci/devops_workflow.md @@ -14,23 +14,33 @@ ### 关键配置示例 -#### 1. Dockerfile (多阶段构建) +#### 1. Dockerfile 多阶段构建 + +使用 Docker 多阶段构建可以有效减小镜像体积。 + + +Dockerfile 内容如下: ```dockerfile ## Build stage + FROM golang:1.18 AS builder WORKDIR /app COPY . . RUN go build -o main . ## Final stage + FROM alpine:latest WORKDIR /app COPY --from=builder /app/main . CMD ["./main"] ``` -#### 2. GitLab CI (.gitlab-ci.yml) +#### 2. GitLab CI 配置 + +GitLab CI(.gitlab-ci.yml)配置如下: + ```yaml stages: diff --git a/14_cases/ci/drone/README.md b/14_cases/ci/drone/README.md index 9585430..5a388d6 100644 --- a/14_cases/ci/drone/README.md +++ b/14_cases/ci/drone/README.md @@ -1,4 +1,4 @@ -## Drone +# Drone 基于 `Docker` 的 `CI/CD` 工具 `Drone` 所有编译、测试的流程都在 `Docker` 容器中进行。 @@ -6,13 +6,13 @@ 本小节以 `GitHub` + `Drone` 来演示 `Drone` 的工作流程。当然在实际开发过程中,你的代码也许不在 GitHub 托管,那么你可以尝试使用 `Gogs` + `Drone` 来进行 `CI/CD`。 -### Drone 关联项目 +## Drone 关联项目 在 Github 新建一个名为 `drone-demo` 的仓库。 打开我们已经 [部署好的 Drone 网站](9.2_install.md) 或者 [Drone Cloud](https://cloud.drone.io),使用 GitHub 账号登录,在界面中关联刚刚新建的 `drone-demo` 仓库。 -### 编写项目源代码 +## 编写项目源代码 初始化一个 git 仓库 @@ -72,7 +72,9 @@ trigger: └── app.go ``` -### 推送项目源代码到 GitHub +## 推送项目源代码到 GitHub + +运行以下命令: ```bash $ git add . @@ -82,7 +84,7 @@ $ git commit -m "test drone ci" $ git push origin master ``` -### 查看项目构建过程及结果 +## 查看项目构建过程及结果 打开我们部署好的 `Drone` 网站或者 Drone Cloud,即可看到构建结果。 @@ -92,7 +94,7 @@ $ git push origin master 本书 GitBook 也使用 Drone 进行 CI/CD,具体配置信息请查看本书根目录 [`.drone.yml`](../../../.drone.yml) 文件。 -### 参考链接 +## 参考链接 * [Drone Github](https://github.com/drone/drone) * [Drone 文档](https://docs.drone.io/) diff --git a/14_cases/ci/drone/install.md b/14_cases/ci/drone/install.md index aca3845..724baa4 100644 --- a/14_cases/ci/drone/install.md +++ b/14_cases/ci/drone/install.md @@ -69,18 +69,23 @@ volumes: ```bash ## 必填 服务器地址,例如 drone.domain.com + DRONE_SERVER_HOST= DRONE_SERVER_PROTO=https DRONE_RPC_SECRET=secret HOSTNAME=demo ## 必填 在 GitHub 应用页面查看 + DRONE_GITHUB_CLIENT_ID= ## 必填 在 GitHub 应用页面查看 + DRONE_GITHUB_CLIENT_SECRET= ``` #### 启动 Drone +运行以下命令: + ```bash $ docker-compose up -d ``` diff --git a/14_cases/ide/README.md b/14_cases/ide/README.md index e402d8f..a0bb743 100644 --- a/14_cases/ide/README.md +++ b/14_cases/ide/README.md @@ -1,3 +1,3 @@ -## 在 IDE 中使用 Docker +# 在 IDE 中使用 Docker 使用 IDE 进行开发,往往要求本地安装好工具链。一些 IDE 支持 Docker 容器中的工具链,这样充分利用了 Docker 的优点,而无需在本地安装。 diff --git a/14_cases/ide/vsCode.md b/14_cases/ide/vsCode.md index a85a280..f4e1e79 100644 --- a/14_cases/ide/vsCode.md +++ b/14_cases/ide/vsCode.md @@ -1,5 +1,6 @@ ## VS Code 中使用 Docker + ### 将 Docker 容器作为远程开发环境 无需本地安装开发工具,直接将 Docker 容器作为开发环境,具体参考 [官方文档](https://code.visualstudio.com/docs/remote/containers)。 diff --git a/14_cases/os/README.md b/14_cases/os/README.md index 2e4da03..70717eb 100644 --- a/14_cases/os/README.md +++ b/14_cases/os/README.md @@ -1,4 +1,4 @@ -## 操作系统 +# 操作系统 目前常用的 Linux 发行版主要包括 `Debian/Ubuntu` 系列和 `CentOS/Fedora` 系列。 @@ -6,4 +6,5 @@ 使用 Docker,读者只需要一个命令就能快速获取一个 Linux 发行版镜像,这是以往包括各种虚拟化技术都难以实现的。这些镜像一般都很精简,但是可以支持完整 Linux 系统的大部分功能。 -本章将介绍如何使用 Docker 安装和使用 `Busybox`、`Alphine`、`Debian/Ubuntu`、`CentOS/Fedora` 等操作系统。 +本章将介绍如何使用 Docker 安装和使用 `Busybox`、`Alpine`、`Debian/Ubuntu`、`CentOS/Fedora` 等操作系统。 + diff --git a/14_cases/os/alpine.md b/14_cases/os/alpine.md index acfe7f8..38c57c1 100644 --- a/14_cases/os/alpine.md +++ b/14_cases/os/alpine.md @@ -4,7 +4,9 @@ ![Alpine Linux 操作系统](../../_images/alpinelinux-logo.png) -`Alpine` 操作系统是一个面向安全的轻型 `Linux` 发行版。它不同于通常 `Linux` 发行版,`Alpine` 采用了 `musl libc` 和 `busybox` 以减小系统的体积和运行时资源消耗,但功能上比 `busybox` 又完善的多,因此得到开源社区越来越多的青睐。在保持瘦身的同时,`Alpine` 还提供了自己的包管理工具 `apk`,可以通过 `https://pkgs.alpinelinux.org/packages` 网站上查询包信息,也可以直接通过 `apk` 命令直接查询和安装各种软件。 + +`Alpine` 操作系统是一个面向安全的轻型 `Linux` 发行版。它不同于通常 `Linux` 发行版,`Alpine` 采用了 `musl libc` 和 `busybox` 以减小系统的体积和运行时资源消耗,但功能上比 `busybox` 又完善的多,因此得到开源社区越来越多的青睐。在保持瘦身的同时,`Alpine` 还提供了自己的包管理工具 `apk`,可以通过 [Alpine Packages](https://pkgs.alpinelinux.org/packages) 网站上查询包信息,也可以直接通过 `apk` 命令直接查询和安装各种软件。 + `Alpine` 由非商业组织维护的,支持广泛场景的 `Linux`发行版,它特别为资深/重度`Linux`用户而优化,关注安全,性能和资源效能。`Alpine` 镜像可以适用于更多常用场景,并且是一个优秀的可以适用于生产的基础系统/环境。 @@ -31,7 +33,8 @@ $ docker run alpine echo '123' 123 ``` -### 迁移至 `Alpine` 基础镜像 +### 迁移至 Alpine 基础镜像 + 目前,大部分 Docker 官方镜像都已经支持 `Alpine` 作为基础镜像,可以很容易进行迁移。 diff --git a/14_cases/os/busybox.md b/14_cases/os/busybox.md index 3d5ebff..f10fe09 100644 --- a/14_cases/os/busybox.md +++ b/14_cases/os/busybox.md @@ -4,6 +4,7 @@ ![Busybox - Linux 瑞士军刀](../../_images/busybox-logo.png) + `BusyBox` 是一个集成了一百多个最常用 Linux 命令和工具(如 `cat`、`echo`、`grep`、`mount`、`telnet` 等)的精简工具箱,它只需要几 MB 的大小,很方便进行各种快速验证,被誉为“Linux 系统的瑞士军刀”。 `BusyBox` 可运行于多款 `POSIX` 环境的操作系统中,如 `Linux`(包括 `Android`)、`Hurd`、`FreeBSD` 等。 diff --git a/14_cases/os/centos.md b/14_cases/os/centos.md index 5aee0d0..18ef41d 100644 --- a/14_cases/os/centos.md +++ b/14_cases/os/centos.md @@ -1,4 +1,5 @@ -## CentOS Fedora +## CentOS 和 Fedora + ### CentOS 系统简介 @@ -6,10 +7,14 @@ ![CentOS 操作系统](../../_images/centos-logo.png) + CentOS(Community Enterprise Operating System,中文意思是:社区企业操作系统),它是基于 `Red Hat Enterprise Linux` 源代码编译而成。由于 `CentOS` 与 `Redhat Linux` 源于相同的代码基础,所以很多成本敏感且需要高稳定性的公司就使用 `CentOS` 来替代商业版 `Red Hat Enterprise Linux`。`CentOS` 自身不包含闭源软件。 #### 使用 CentOS 官方镜像 +CentOS 官方镜像的使用非常简单。 + + **注意:CentOS 8 已于 2021 年 12 月 31 日停止维护(EOL)。对于新部署,推荐使用 CentOS Stream,或 Rocky Linux、AlmaLinux 等替代发行版。** 使用 `docker run` 直接运行 `CentOS 7` 镜像,并登录 `bash`。 @@ -29,6 +34,7 @@ CentOS Linux release 7.9.2009 (Core) ![Fedora 操作系统](../../_images/fedora-logo.png) + `Fedora` 由 `Fedora Project` 社区开发,红帽公司赞助的 `Linux` 发行版。它的目标是创建一套新颖、多功能并且自由和开源的操作系统。`Fedora` 的功能对于用户而言,它是一套功能完备的,可以更新的免费操作系统,而对赞助商 `Red Hat` 而言,它是许多新技术的测试平台。被认为可用的技术最终会加入到 `Red Hat Enterprise Linux` 中。 #### 使用 Fedora 官方镜像 diff --git a/14_cases/os/debian.md b/14_cases/os/debian.md index 7443e81..1b06498 100644 --- a/14_cases/os/debian.md +++ b/14_cases/os/debian.md @@ -6,7 +6,8 @@ ![Debian 操作系统](../../_images/debian-logo.png) -`Debian` 是由 `GPL` 和其他自由软件许可协议授权的自由软件组成的操作系统,由 **Debian 计划(Debian Project)** 组织维护。**Debian 计划** 是一个独立的、分散的组织,由 `3000` 人志愿者组成,接受世界多个非盈利组织的资金支持,`Software in the Public Interest` 提供支持并持有商标作为保护机构。`Debian` 以其坚守 `Unix` 和自由软件的精神,以及其给予用户的众多选择而闻名。现时 `Debian` 包括了超过 `25,000` 个软件包并支持 `12` 个计算机系统结构。 + +`Debian` 是由 `GPL` 和其他自由软件许可协议授权的自由软件组成的操作系统,由 **Debian 计划(Debian Project)**组织维护。**Debian 计划** 是一个独立的、分散的组织,由 `3000` 人志愿者组成,接受世界多个非盈利组织的资金支持,`Software in the Public Interest` 提供支持并持有商标作为保护机构。`Debian` 以其坚守 `Unix` 和自由软件的精神,以及其给予用户的众多选择而闻名。现时 `Debian` 包括了超过 `25,000` 个软件包并支持 `12` 个计算机系统结构。 `Debian` 作为一个大的系统组织框架,其下有多种不同操作系统核心的分支计划,主要为采用 `Linux` 核心的 `Debian GNU/Linux` 系统,其他还有采用 `GNU Hurd` 核心的 `Debian GNU/Hurd` 系统、采用 `FreeBSD` 核心的 `Debian GNU/kFreeBSD` 系统,以及采用 `NetBSD` 核心的 `Debian GNU/NetBSD` 系统。甚至还有利用 `Debian` 的系统架构和工具,采用 `OpenSolaris` 核心构建而成的 `Nexenta OS` 系统。在这些 `Debian` 系统中,以采用 `Linux` 核心的 `Debian GNU/Linux` 最为著名。 @@ -14,6 +15,9 @@ #### 使用 Debian 官方镜像 +Debian 是一个也是一个常用的基础镜像。 + + 官方提供了大家熟知的 `debian` 镜像以及面向科研领域的 `neurodebian` 镜像。可以使用 `docker run` 直接运行 `Debian` 镜像。 ```bash @@ -28,10 +32,14 @@ Debian GNU/Linux 8 ![Ubuntu 操作系统](../../_images/ubuntu-logo.jpg) + `Ubuntu` 是一个以桌面应用为主的 `GNU/Linux` 操作系统,其名称来自非洲南部祖鲁语或豪萨语的“ubuntu”一词(官方译名“友帮拓”,另有“吾帮托”、“乌班图”、“有奔头”或“乌斑兔”等译名)。`Ubuntu` 意思是“人性”以及“我的存在是因为大家的存在”,是非洲传统的一种价值观,类似华人社会的“仁爱”思想。 `Ubuntu` 基于 `Debian` 发行版和 `GNOME/Unity` 桌面环境,与 `Debian` 的不同在于它每 6 个月会发布一个新版本,每 2 年推出一个长期支持 **(Long Term Support,LTS)** 版本,一般支持 3 年时间。 #### 使用 Ubuntu 官方镜像 +Ubuntu 是目前最流行的 Linux 发行版之一。 + + 下面以 `ubuntu:24.04` 为例,演示如何使用该镜像安装一些常用软件。 首先使用 `-ti` 参数启动容器,登录 `bash`,查看 `ubuntu` 的发行版本号。 diff --git a/15_appendix/15.1_best_practices.md b/15_appendix/15.1_best_practices.md index 36b97af..d0cc115 100644 --- a/15_appendix/15.1_best_practices.md +++ b/15_appendix/15.1_best_practices.md @@ -74,6 +74,7 @@ RUN apt-get update && apt-get install -y \ ```docker ## Set one or more individual labels + LABEL com.example.version="0.0.1-beta" LABEL vendor="ACME Incorporated" @@ -87,6 +88,7 @@ LABEL com.example.version.is-production="" ```docker ## Set multiple labels at once, using line-continuation characters to break long lines + LABEL vendor=ACME\ Incorporated \ com.example.is-beta= \ com.example.is-production="" \ diff --git a/15_appendix/15.2_debug.md b/15_appendix/15.2_debug.md index 55aab31..10e2020 100644 --- a/15_appendix/15.2_debug.md +++ b/15_appendix/15.2_debug.md @@ -20,6 +20,8 @@ $ sudo kill -SIGHUP $(pidof dockerd) ### 检查内核日志 +运行以下命令: + ```bash $ sudo dmesg |grep dockerd $ sudo dmesg |grep runc diff --git a/15_appendix/README.md b/15_appendix/README.md index 44fbe62..9d9af59 100644 --- a/15_appendix/README.md +++ b/15_appendix/README.md @@ -9,4 +9,4 @@ * [**Docker 命令查询**](command/README.md):速查 Docker 客户端和服务端的常用命令。 * [**Dockerfile 最佳实践**](15.1_best_practices.md):提供编写高效、安全 Dockerfile 的指导原则。 * [**如何调试 Docker**](15.2_debug.md):介绍 Docker 调试技巧和工具。 -* [**资源链接**](15.3_resources.md):推荐更多 Docker 相关的学习资源。 \ No newline at end of file +* [**资源链接**](15.3_resources.md):推荐更多 Docker 相关的学习资源。 diff --git a/15_appendix/command/README.md b/15_appendix/command/README.md index be0a563..5bea731 100644 --- a/15_appendix/command/README.md +++ b/15_appendix/command/README.md @@ -1,6 +1,6 @@ -## Docker 命令查询 +# Docker 命令查询 -### 基本语法 +## 基本语法 Docker 命令有两大类,客户端命令和服务端命令。前者是主要的操作接口,后者用来启动 Docker Daemon。 diff --git a/15_appendix/command/docker.md b/15_appendix/command/docker.md index a1e63b3..cc889cf 100644 --- a/15_appendix/command/docker.md +++ b/15_appendix/command/docker.md @@ -64,6 +64,8 @@ ### 一张图总结 Docker 的命令 +一张图总结 Docker 的命令 示意图如下: + ![Docker 命令总结](../../_images/cmd_logic.png) ### 参考 diff --git a/15_appendix/command/dockerd.md b/15_appendix/command/dockerd.md index 365ec51..9240930 100644 --- a/15_appendix/command/dockerd.md +++ b/15_appendix/command/dockerd.md @@ -1,4 +1,4 @@ -## 服务端命令(dockerd) +## 服务端命令(dockerd) ### dockerd 命令选项 diff --git a/15_appendix/faq/README.md b/15_appendix/faq/README.md index b98a3fe..31e87c6 100644 --- a/15_appendix/faq/README.md +++ b/15_appendix/faq/README.md @@ -1,20 +1,20 @@ -## 附录一:常见问题总结 +# 附录一:常见问题总结 -### 镜像相关 +## 镜像相关 -#### 如何批量清理临时镜像文件? +### 如何批量清理临时镜像文件? 答:可以使用 `docker image prune` 命令。 -#### 如何查看镜像支持的环境变量? +### 如何查看镜像支持的环境变量? 答:可以使用 `docker run IMAGE env` 命令。 -#### 本地的镜像文件都存放在哪里? +### 本地的镜像文件都存放在哪里? 答:与 Docker 相关的本地资源默认存放在 `/var/lib/docker/` 目录下,以 `overlay2` 文件系统为例,其中 `containers` 目录存放容器信息,`image` 目录存放镜像信息,`overlay2` 目录下存放具体的镜像层文件。 -#### 构建 Docker 镜像应该遵循哪些原则? +### 构建 Docker 镜像应该遵循哪些原则? 答:整体原则上,尽量保持镜像功能的明确和内容的精简,要点包括 @@ -27,25 +27,25 @@ 更多内容请查看 [Dockerfile 最佳实践](../15.1_best_practices.md) -#### 碰到网络问题,无法 pull 镜像,命令行指定 http\_proxy 无效? +### 碰到网络问题,无法 pull 镜像,命令行指定 http\_proxy 无效? 答:在 Docker 配置文件中添加 `export http_proxy="http://:"`,之后重启 Docker 服务即可。 -### 容器相关 +## 容器相关 -#### 容器退出后,通过 docker container ls 命令查看不到,数据会丢失么? +### 容器退出后,通过 docker container ls 命令查看不到,数据会丢失么? 答:容器退出后会处于终止(exited)状态,此时可以通过 `docker container ls -a` 查看。其中的数据也不会丢失,还可以通过 `docker start` 命令来启动它。只有删除掉容器才会清除所有数据。 -#### 如何停止所有正在运行的容器? +### 如何停止所有正在运行的容器? 答:可以使用 `docker stop $(docker container ls -q)` 命令。 -#### 如何批量清理已经停止的容器? +### 如何批量清理已经停止的容器? 答:可以使用 `docker container prune` 命令。 -#### 如何获取某个容器的 PID 信息? +### 如何获取某个容器的 PID 信息? 答:可以使用 @@ -53,7 +53,7 @@ docker inspect --format '{{ .State.Pid }}' ``` -#### 如何获取某个容器的 IP 地址? +### 如何获取某个容器的 IP 地址? 答:可以使用 @@ -61,7 +61,7 @@ docker inspect --format '{{ .State.Pid }}' docker inspect --format '{{ .NetworkSettings.IPAddress }}' ``` -#### 如何给容器指定一个固定 IP 地址,而不是每次重启容器 IP 地址都会变? +### 如何给容器指定一个固定 IP 地址,而不是每次重启容器 IP 地址都会变? 答:使用以下命令启动容器可以使容器 IP 固定不变 @@ -71,40 +71,40 @@ $ 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 ``` -#### 如何临时退出一个正在交互的容器的终端,而不终止它? +### 如何临时退出一个正在交互的容器的终端,而不终止它? 答:按 `Ctrl-p Ctrl-q`。如果按 `Ctrl-c` 往往会让容器内应用进程终止,进而会终止容器。 -#### 使用 `docker port` 命令映射容器的端口时,系统报错“Error: No public port '80' published for xxx”? +### 使用 `docker port` 命令映射容器的端口时,系统报错“Error: No public port '80' published for xxx”? 答: * 创建镜像时 `Dockerfile` 要通过 `EXPOSE` 指定正确的开放端口; * 容器启动时指定 `PublishAllPort = true`。 -#### 可以在一个容器中同时运行多个应用进程么? +### 可以在一个容器中同时运行多个应用进程么? 答:一般并不推荐在同一个容器内运行多个应用进程。如果有类似需求,可以通过一些额外的进程管理机制,比如 `supervisord` 来管理所运行的进程。可以参考 https://docs.docker.com/config/containers/multi-service\_container/ 。 -#### 如何控制容器占用系统资源(CPU、内存)的份额? +### 如何控制容器占用系统资源(CPU、内存)的份额? 答:在使用 `docker create` 命令创建容器或使用 `docker run` 创建并启动容器的时候,可以使用 -c|--cpu-shares\[=0] 参数来调整容器使用 CPU 的权重;使用 -m|--memory\[=MEMORY] 参数来调整容器使用内存的大小。 -### 仓库相关 +## 仓库相关 -#### 仓库(Repository)、注册服务器(Registry)、注册索引(Index) 有何关系? +### 仓库(Repository)、注册服务器(Registry)、注册索引(Index) 有何关系? 首先,仓库是存放一组关联镜像的集合,比如同一个应用的不同版本的镜像。 注册服务器是存放实际的镜像文件的地方。注册索引则负责维护用户的账号、权限、搜索、标签等的管理。因此,注册服务器利用注册索引来实现认证等管理。 -### 配置相关 +## 配置相关 -#### Docker 的配置文件放在哪里,如何修改配置? +### Docker 的配置文件放在哪里,如何修改配置? 答:使用 `systemd` 的系统(如 Ubuntu 16.04、Centos 等)的配置文件在 `/etc/docker/daemon.json`。 -#### 如何更改 Docker 的默认存储位置? +### 如何更改 Docker 的默认存储位置? 答:Docker 的默认存储位置是 `/var/lib/docker`,如果希望将 Docker 的本地文件存储到其他分区,可以使用 Linux 软连接的方式来完成,或者在启动 daemon 时通过 `-g` 参数指定,或者修改配置文件 `/etc/docker/daemon.json` 的 "data-root" 项 。可以使用 `docker system info | grep "Root Dir"` 查看当前使用的存储位置。 @@ -127,7 +127,7 @@ lrwxrwxrwx. 1 root root 15 11月 17 13:43 docker -> /storage/docker [root@s26 lib]# service docker start ``` -#### 使用内存和 swap 限制启动容器时候报警告:"WARNING: Your kernel does not support cgroup swap limit. WARNING: Your kernel does not support swap limit capabilities. Limitation discarded."? +### 使用内存和 swap 限制启动容器时候报警告:"WARNING: Your kernel does not support cgroup swap limit. WARNING: Your kernel does not support swap limit capabilities. Limitation discarded."? 答:这是因为系统默认没有开启对内存和 swap 使用的统计功能,引入该功能会带来性能的下降。要开启该功能,可以采取如下操作: @@ -135,9 +135,9 @@ lrwxrwxrwx. 1 root root 15 11月 17 13:43 docker -> /storage/docker * 更新 grub:`$ sudo update-grub` * 重启系统,即可。 -### Docker 与虚拟化 +## Docker 与虚拟化 -#### Docker 与 LXC(Linux Container)有何不同? +### Docker 与 LXC(Linux Container)有何不同? 答:LXC 利用 Linux 上相关技术实现了容器。Docker 则在如下的几个方面进行了改进: @@ -147,7 +147,7 @@ lrwxrwxrwx. 1 root root 15 11月 17 13:43 docker -> /storage/docker * 仓库系统:仓库系统大大降低了镜像的分发和管理的成本; * 周边工具:各种现有工具(配置管理、云平台)对 Docker 的支持,以及基于 Docker的 PaaS、CI 等系统,让 Docker 的应用更加方便和多样化。 -#### Docker 与 Vagrant 有何不同? +### Docker 与 Vagrant 有何不同? 答:两者的定位完全不同。 @@ -156,7 +156,7 @@ lrwxrwxrwx. 1 root root 15 11月 17 13:43 docker -> /storage/docker 简单说:Vagrant 适合用来管理虚拟机,而 Docker 适合用来管理应用环境。 -#### 开发环境中 Docker 和 Vagrant 该如何选择? +### 开发环境中 Docker 和 Vagrant 该如何选择? 答:Docker 不是虚拟机,而是进程隔离,对于资源的消耗很少,但是目前需要 Linux 环境支持。Vagrant 是虚拟机上做的封装,虚拟机本身会消耗资源。 @@ -164,17 +164,17 @@ lrwxrwxrwx. 1 root root 15 11月 17 13:43 docker -> /storage/docker 如果本地使用的是 macOS 或者 Windows 环境,那就需要开虚拟机,单一开发环境下 Vagrant 更简单;多环境开发下推荐在 Vagrant 里面再使用 Docker 进行环境隔离。 -### 其它 +## 其它 -#### Docker 能在非 Linux 平台(比如 Windows 或 macOS )上运行么? +### Docker 能在非 Linux 平台(比如 Windows 或 macOS )上运行么? 答:完全可以。安装方法请查看 [安装 Docker](../../install/) 一节 -#### 如何将一台宿主主机的 Docker 环境迁移到另外一台宿主主机? +### 如何将一台宿主主机的 Docker 环境迁移到另外一台宿主主机? 答:停止 Docker 服务。将整个 Docker 存储文件夹复制到另外一台宿主主机,然后调整另外一台宿主主机的配置即可。 -#### 如何进入 Docker 容器的网络命名空间? +### 如何进入 Docker 容器的网络命名空间? 答:Docker 在创建容器后,删除了宿主主机上 `/var/run/netns` 目录中的相关的网络命名空间文件。因此,在宿主主机上是无法看到或访问容器的网络命名空间的。 @@ -206,7 +206,7 @@ $ sudo ip netns show $ sudo ip netns exec 1234 ifconfig eth0 172.17.0.100/16 ``` -#### 如何获取容器绑定到本地那个 veth 接口上? +### 如何获取容器绑定到本地那个 veth 接口上? 答:Docker 容器启动后,会通过 veth 接口对连接到本地网桥,veth 接口命名跟容器命名毫无关系,十分难以找到对应关系。 diff --git a/15_appendix/repo/README.md b/15_appendix/repo/README.md index 61efbbe..bc840d2 100644 --- a/15_appendix/repo/README.md +++ b/15_appendix/repo/README.md @@ -1,3 +1,3 @@ -## 热门镜像介绍 +# 热门镜像介绍 本章将介绍一些热门镜像的功能,使用方法等。包括 Ubuntu、CentOS、MySQL、MongoDB、Redis、Nginx、Wordpress、Node.js 等。 diff --git a/15_appendix/repo/nodejs.md b/15_appendix/repo/nodejs.md index 1b52611..b0c3c10 100644 --- a/15_appendix/repo/nodejs.md +++ b/15_appendix/repo/nodejs.md @@ -13,6 +13,7 @@ ```docker FROM node:12 ## replace this with your application's default port + EXPOSE 8888 ``` diff --git a/README.md b/README.md index 4513748..584a582 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![](https://img.shields.io/github/stars/yeasy/docker_practice.svg?style=social&label=Stars)](https://github.com/yeasy/docker_practice) [![](https://img.shields.io/github/release/yeasy/docker_practice/all.svg)](https://github.com/yeasy/docker_practice/releases) [![](https://img.shields.io/badge/Based-Docker%20CE%20v30.x-blue.svg)](https://github.com/docker/docker-ce) [![](https://img.shields.io/badge/Docker%20%E6%8A%80%E6%9C%AF%E5%85%A5%E9%97%A8%E4%B8%8E%E5%AE%9E%E6%88%98-jd.com-red.svg)][1] -**v1.5.1** +**v1.5.2** [Docker](https://www.docker.com) 是个划时代的开源项目,它彻底释放了计算虚拟化的威力,极大提高了应用的维护效率,降低了云计算应用开发的成本!使用 Docker,可以让应用的部署、测试和分发都变得前所未有的高效和轻松! @@ -21,6 +21,7 @@ ## 阅读方式 ### 在线阅读 + > 推荐访问官方 GitBook,体验最佳。 * **GitBook**: [yeasy.gitbook.io/docker_practice](https://yeasy.gitbook.io/docker_practice/) @@ -30,6 +31,7 @@ ### 本地阅读 #### 方式 1:Docker 镜像(推荐) + 无需安装任何依赖,一条命令即可启动。 ```bash @@ -39,6 +41,7 @@ docker run -it --rm -p 4000:80 ccr.ccs.tencentyun.com/dockerpracticesig/docker_p [详情参考](https://github.com/yeasy/docker_practice/wiki/%E7%A6%BB%E7%BA%BF%E9%98%85%E8%AF%BB%E5%8A%9F%E8%83%BD%E8%AF%A6%E8%A7%A3) #### 方式 2:本地构建(HonKit) + 适合想要修改内容或深度定制的读者。需要安装 Node.js 环境。 ```bash diff --git a/SUMMARY.md b/SUMMARY.md index a43116d..d539251 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -1,4 +1,4 @@ -# [Docker — 从入门到实践](https://github.com/yeasy/docker_practice/blob/master/SUMMARY.md) +## Docker — 从入门到实践 * [前言](README.md) * [修订记录](CHANGELOG.md) @@ -32,7 +32,7 @@ * [利用 commit 理解镜像构成](04_image/4.4_commit.md) * [使用 Dockerfile 定制镜像](04_image/4.5_build.md) * [Dockerfile 指令详解](04_image/dockerfile/README.md) - * [RUN 执行命令](04_image/dockerfile/5.1_run.md) + * [RUN 执行命令](04_image/dockerfile/run.md) * [COPY 复制文件](04_image/dockerfile/copy.md) * [ADD 更高级的复制文件](04_image/dockerfile/add.md) * [CMD 容器启动命令](04_image/dockerfile/cmd.md) @@ -58,7 +58,7 @@ * [终止](05_container/5.3_stop.md) * [进入容器](05_container/5.4_attach_exec.md) * [导出和导入](05_container/5.5_import_export.md) - * [删除](05_container/4.3_rm.md) + * [删除](05_container/5.6_rm.md) * [第六章 访问仓库](06_repository/README.md) * [Docker Hub](06_repository/6.1_dockerhub.md) * [私有仓库](06_repository/6.2_registry.md) @@ -106,7 +106,7 @@ * [第十一章 容器编排](11_orchestration/README.md) * [Etcd 项目](11_orchestration/etcd/README.md) * [简介](11_orchestration/etcd/intro.md) - * [安装](11_orchestration/etcd/9.2_install.md) + * [安装](11_orchestration/etcd/install.md) * [集群](11_orchestration/etcd/cluster.md) * [使用 etcdctl](11_orchestration/etcd/etcdctl.md) * [Kubernetes - 开源容器编排引擎](11_orchestration/kubernetes/README.md) @@ -127,7 +127,7 @@ * [第十二章 容器生态](12_ecosystem/README.md) * [Fedora CoreOS](12_ecosystem/coreos/README.md) * [简介](12_ecosystem/coreos/intro.md) - * [安装](12_ecosystem/coreos/9.2_install.md) + * [安装](12_ecosystem/coreos/install.md) * [容器与云计算](12_ecosystem/cloud/README.md) * [简介](12_ecosystem/cloud/intro.md) * [腾讯云](12_ecosystem/cloud/tencentCloud.md) @@ -150,27 +150,27 @@ * [实战案例 - 操作系统](14_cases/os/README.md) * [Busybox](14_cases/os/busybox.md) * [Alpine](14_cases/os/alpine.md) - * [Debian Ubuntu](14_cases/os/3.2_debian.md) - * [CentOS Fedora](14_cases/os/3.4_centos.md) + * [Debian Ubuntu](14_cases/os/debian.md) + * [CentOS Fedora](14_cases/os/centos.md) * [本章小结](14_cases/os/summary.md) * [实战案例 - CI/CD](14_cases/ci/README.md) * [DevOps 完整工作流](14_cases/ci/devops_workflow.md) * [GitHub Actions](14_cases/ci/actions/README.md) * [Drone](14_cases/ci/drone/README.md) - * [部署 Drone](14_cases/ci/drone/9.2_install.md) + * [部署 Drone](14_cases/ci/drone/install.md) * [在 IDE 中使用 Docker](14_cases/ide/README.md) * [VS Code](14_cases/ide/vsCode.md) * [第十五章 附录](15_appendix/README.md) * [附录一:常见问题总结](15_appendix/faq/README.md) * [常见错误速查表](15_appendix/faq/errors.md) * [附录二:热门镜像介绍](15_appendix/repo/README.md) - * [Ubuntu](15_appendix/repo/3.1_ubuntu.md) - * [CentOS](15_appendix/repo/3.4_centos.md) + * [Ubuntu](15_appendix/repo/ubuntu.md) + * [CentOS](15_appendix/repo/centos.md) * [Nginx](15_appendix/repo/nginx.md) * [PHP](15_appendix/repo/php.md) * [Node.js](15_appendix/repo/nodejs.md) * [MySQL](15_appendix/repo/mysql.md) - * [WordPress](15_appendix/repo/9.8_wordpress.md) + * [WordPress](15_appendix/repo/wordpress.md) * [MongoDB](15_appendix/repo/mongodb.md) * [Redis](15_appendix/repo/redis.md) * [Minio](15_appendix/repo/minio.md)