mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-03-11 04:14:38 +00:00
Add more content and fix format
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
## 1.3 为什么要使用 Docker?
|
||||
## 1.3 为什么要用 Docker
|
||||
|
||||
在回答 “为什么用 Docker” 之前,笔者想先问一个问题:**你有没有经历过这些场景?**
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 1.4 本章小结
|
||||
## 本章小结
|
||||
|
||||
- Docker 是一种轻量级虚拟化技术,核心价值是 **环境一致性**
|
||||
- 与虚拟机相比,Docker 更轻量、更快速、资源利用率更高
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 2.1 Docker 镜像
|
||||
## 2.1 镜像
|
||||
|
||||
Docker 镜像作为容器运行的基石,其设计理念和实现机制至关重要。本节将深入探讨镜像的本质、与操作系统的关系、内容构成以及核心的分层存储机制。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 2.2 Docker 容器
|
||||
## 2.2 容器
|
||||
|
||||
容器是 Docker 技术的核心,是应用实际运行的载体。本节将从容器的本质、与虚拟机的区别、存储层机制以及生命周期管理等方面,全面解析 Docker 容器。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 2.3 Docker Registry
|
||||
## 2.3 仓库
|
||||
|
||||
Docker Registry 是镜像分发和管理的核心组件。本节将介绍 Registry 的基本概念、公共和私有服务的选择,以及镜像的安全管理。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 2.4 本章小结
|
||||
## 本章小结
|
||||
|
||||
| 概念 | 要点 |
|
||||
|------|------|
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
- [获取镜像](../04_image/4.1_pull.md):从 Registry 下载镜像
|
||||
- [使用 Dockerfile 定制镜像](../04_image/4.5_build.md):创建自己的镜像
|
||||
- [Dockerfile 最佳实践](../appendix/20.1_best_practices.md):构建高质量镜像的技巧
|
||||
- [Dockerfile 最佳实践](../appendix/best_practices.md):构建高质量镜像的技巧
|
||||
- [底层实现 - 联合文件系统](../12_implementation/12.4_ufs.md):深入理解分层存储的技术原理
|
||||
|
||||
| 概念 | 要点 |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 3.1 Ubuntu 安装 Docker
|
||||
## 3.1 Ubuntu
|
||||
|
||||
Ubuntu 是 Docker 最常用的运行环境之一。本节将介绍如何在 Ubuntu 系统上安装 Docker,并配置国内镜像加速。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 3.2 Debian 安装 Docker
|
||||
## 3.2 Debian
|
||||
|
||||
Debian 以其稳定性著称,是 Docker 的理想宿主系统。本节将指导你在 Debian 上完成 Docker 的安装。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 3.3 Fedora 安装 Docker
|
||||
## 3.3 Fedora
|
||||
|
||||
Fedora 作为技术前沿的 Linux 发行版,对 Docker 有着良好的支持。本节介绍在 Fedora 上的安装步骤。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 3.4 CentOS 安装 Docker
|
||||
## 3.4 CentOS
|
||||
|
||||
CentOS (及其替代品 Rocky Linux、AlmaLinux) 是企业级服务器常用的操作系统。本节介绍在这些系统上安装 Docker 的步骤。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 3.5 树莓派卡片电脑安装 Docker
|
||||
## 3.5 Raspberry Pi
|
||||
|
||||
树莓派等 ARM 架构设备在物联网和边缘计算领域应用广泛。本节介绍如何在树莓派上安装 Docker。
|
||||
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
|
||||
### 3.7.2 安装
|
||||
|
||||
> [!WARNING]
|
||||
> **商业许可限制**:自 2021 年起,Docker Desktop 对微型企业(少于 250 名员工且年收入少于 1000 万美元)、个人使用、教育和非商业开源项目仍然免费。对于其他商业用途,需要付费订阅。企业用户请注意合规风险,或考虑使用开源替代方案。
|
||||
|
||||
Docker Desktop 为 Mac 用户提供了无缝的 Docker 体验。你可以选择使用 Homebrew 或手动下载安装包进行安装。
|
||||
|
||||
#### 使用 Homebrew 安装
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
### 3.8.2 安装
|
||||
|
||||
> [!WARNING]
|
||||
> **商业许可限制**:自 2021 年起,Docker Desktop 对微型企业(少于 250 名员工且年收入少于 1000 万美元)、个人使用、教育和非商业开源项目仍然免费。对于其他商业用途,需要付费订阅。企业用户请注意合规风险,或考虑使用开源替代方案。
|
||||
|
||||
**手动下载安装**
|
||||
|
||||
点击以下[链接](https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe)下载 Docker Desktop for Windows。
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 3.11 本章小结
|
||||
## 本章小结
|
||||
|
||||
Docker 支持在多种平台上安装和使用,选择合适的安装方式是顺利使用 Docker 的第一步。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 4.8 本章小结
|
||||
## 本章小结
|
||||
|
||||
| 操作 | 命令 |
|
||||
|------|------|
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 5.1 启动容器
|
||||
## 5.1 启动
|
||||
|
||||
本节将详细介绍 Docker 容器的启动方式,包括新建启动和重新启动已停止的容器。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 5.2 后台运行
|
||||
## 5.2 守护态运行
|
||||
|
||||
在生产环境中,我们通常需要容器持续运行,不受终端关闭的影响。本节将深入讲解如何让容器在后台运行,以及理解容器生命周期的核心概念。
|
||||
|
||||
@@ -57,8 +57,6 @@ $ docker run -d ubuntu:24.04
|
||||
|
||||
#### 核心原理:容器的生命周期与主进程绑定
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
subgraph Lifecycle ["Docker 容器的生命周期 = 容器内 PID 1 进程的生命周期"]
|
||||
@@ -190,7 +188,7 @@ $ docker logs -t myapp
|
||||
1. **查看退出状态码**:
|
||||
```bash
|
||||
$ docker ps -a --filter "name=mycontainer"
|
||||
# 查看 STATUS 列,如 "Exited (1)" 表示异常退出
|
||||
# 查看 STATUS 列,如 “Exited (1)” 表示异常退出
|
||||
|
||||
```
|
||||
|
||||
@@ -231,6 +229,6 @@ $ docker attach mycontainer
|
||||
### 5.2.7 延伸阅读
|
||||
|
||||
- [进入容器](5.4_attach_exec.md):如何进入正在运行的容器执行命令
|
||||
- [容器日志](../appendix/20.1_best_practices.md):生产环境的日志管理最佳实践
|
||||
- [容器日志](../appendix/best_practices.md):生产环境的日志管理最佳实践
|
||||
- [HEALTHCHECK 健康检查](../07_dockerfile/7.12_healthcheck.md):自动检测容器内服务是否正常
|
||||
- [Docker Compose](../11_compose/README.md):管理多个后台容器的更好方式
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 5.3 终止容器
|
||||
## 5.3 终止
|
||||
|
||||
本节将介绍如何终止一个运行中的容器,以及几种不同的终止方式及其区别。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 5.5 导出和导入容器
|
||||
## 5.5 导出和导入
|
||||
|
||||
当我们需要迁移容器或者备份容器时,可以使用 Docker 的导入和导出功能。本节将介绍这两个命令的使用方法。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 5.6 删除容器
|
||||
## 5.6 删除
|
||||
|
||||
随着容器的创建和停止,系统中会积累大量的容器。本节将介绍如何删除不再需要的容器,以及如何清理所有停止的容器。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 5.7 本章小结
|
||||
## 本章小结
|
||||
|
||||
| 操作 | 命令 | 说明 |
|
||||
|------|------|------|
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 6.5 本章小结
|
||||
## 本章小结
|
||||
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
### 7.10.1 基本语法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
WORKDIR <工作目录路径>
|
||||
```
|
||||
@@ -14,8 +12,6 @@ WORKDIR <工作目录路径>
|
||||
|
||||
### 7.10.2 基本用法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
WORKDIR /app
|
||||
|
||||
@@ -30,8 +26,6 @@ COPY . . # 复制到 /app/
|
||||
|
||||
#### 常见错误
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ❌ 错误:cd 在下一个 RUN 中无效
|
||||
|
||||
@@ -41,8 +35,6 @@ RUN echo "hello" > world.txt # 文件在根目录!
|
||||
|
||||
#### 原因分析
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```dockerfile
|
||||
RUN cd /app
|
||||
↓
|
||||
@@ -58,8 +50,6 @@ RUN echo "hello" > world.txt
|
||||
|
||||
#### 正确做法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ✅ 正确:使用 WORKDIR
|
||||
|
||||
@@ -85,8 +75,6 @@ RUN pwd # 输出 /a/b/c
|
||||
|
||||
### 7.10.5 使用环境变量
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ENV APP_HOME=/app
|
||||
WORKDIR $APP_HOME
|
||||
@@ -98,8 +86,6 @@ RUN pwd # 输出 /app
|
||||
|
||||
### 7.10.6 多阶段构建中的 WORKDIR
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 构建阶段
|
||||
|
||||
@@ -123,8 +109,6 @@ COPY --from=builder /build/dist .
|
||||
|
||||
#### 1. 尽早设置 WORKDIR
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
FROM node:20
|
||||
WORKDIR /app # 尽早设置
|
||||
@@ -137,8 +121,6 @@ CMD ["node", "server.js"]
|
||||
|
||||
#### 2. 使用绝对路径
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ✅ 推荐:绝对路径,意图明确
|
||||
|
||||
@@ -151,8 +133,6 @@ WORKDIR app
|
||||
|
||||
#### 3. 不要用 RUN cd
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ❌ 避免
|
||||
|
||||
@@ -166,8 +146,6 @@ RUN echo "hello" > world.txt
|
||||
|
||||
#### 4. 适时重置 WORKDIR
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
WORKDIR /app
|
||||
## ... 应用相关操作 ...
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
### 7.11.1 基本语法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
USER <用户名>[:<用户组>]
|
||||
USER <UID>[:<GID>]
|
||||
@@ -38,8 +36,6 @@ flowchart LR
|
||||
|
||||
#### 创建并切换用户
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
FROM node:20-alpine
|
||||
|
||||
@@ -64,8 +60,6 @@ CMD ["node", "server.js"]
|
||||
|
||||
#### 使用 UID/GID
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 也可以使用数字
|
||||
|
||||
@@ -213,8 +207,6 @@ CMD ["node", "server.js"]
|
||||
|
||||
#### 1. 始终使用非 root 用户
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ✅ 推荐
|
||||
|
||||
@@ -241,8 +233,6 @@ USER 1000:1000
|
||||
|
||||
#### 3. 多阶段构建中的 USER
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 构建阶段可以用 root
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
### 7.12.1 基本语法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
HEALTHCHECK [选项] CMD <命令>
|
||||
HEALTHCHECK NONE
|
||||
@@ -37,8 +35,6 @@ Starting ──成功──> Healthy ──失败N次──> Unhealthy
|
||||
|
||||
#### Web 服务检查
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
FROM nginx
|
||||
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
|
||||
@@ -93,8 +89,6 @@ HEALTHCHECK CMD wget -q --spider http://localhost/ || exit 1
|
||||
|
||||
#### 数据库
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## MySQL
|
||||
|
||||
@@ -107,8 +101,6 @@ HEALTHCHECK CMD redis-cli ping || exit 1
|
||||
|
||||
#### 自定义脚本
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
COPY healthcheck.sh /usr/local/bin/
|
||||
HEALTHCHECK CMD ["healthcheck.sh"]
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
## 7.13 ONBUILD 为他人做嫁衣裳
|
||||
## 7.13 ONBUILD 为他人作嫁衣裳
|
||||
|
||||
### 7.13.1 基本语法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ONBUILD <其它指令>
|
||||
```
|
||||
@@ -60,8 +58,6 @@ FROM my-node-base
|
||||
|
||||
### 7.13.3 执行机制
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```bash
|
||||
基础镜像构建:
|
||||
Dockerfile (含 ONBUILD) ──build──> 基础镜像 (记录了 ONBUILD 触发器)
|
||||
@@ -77,8 +73,6 @@ FROM 基础镜像 ──build──> 读取基础镜像触发器 ──> 执行
|
||||
|
||||
#### 1. 自动处理依赖安装
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## Python 基础镜像
|
||||
|
||||
@@ -88,8 +82,6 @@ ONBUILD RUN pip install -r requirements.txt
|
||||
|
||||
#### 2. 自动编译代码
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## Go 基础镜像
|
||||
|
||||
@@ -99,8 +91,6 @@ ONBUILD RUN go build -o app main.go
|
||||
|
||||
#### 3. 处理静态资源
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## Nginx 静态网站基础镜像
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
### 7.14.1 基本语法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
LABEL <key>=<value> <key>=<value> ...
|
||||
```
|
||||
@@ -25,8 +23,6 @@ LABEL <key>=<value> <key>=<value> ...
|
||||
|
||||
#### 定义单个标签
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
LABEL version="1.0"
|
||||
LABEL description="这是一个 Web 应用服务器"
|
||||
@@ -34,8 +30,6 @@ LABEL description="这是一个 Web 应用服务器"
|
||||
|
||||
#### 定义多个标签 (推荐)
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
LABEL maintainer="user@example.com" \
|
||||
version="1.2.0" \
|
||||
@@ -65,8 +59,6 @@ LABEL maintainer="user@example.com" \
|
||||
|
||||
#### 示例
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
LABEL org.opencontainers.image.authors="yeasy" \
|
||||
org.opencontainers.image.documentation="https://yeasy.gitbooks.io" \
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
### 7.15.1 基本语法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
SHELL ["executable", "parameters"]
|
||||
```
|
||||
|
||||
@@ -125,8 +125,6 @@ RUN set -x ; cd ${LARAVEL_PATH} \
|
||||
|
||||
### 7.18.5 最后一个阶段构建 NGINX 镜像
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
FROM nginx:alpine as nginx
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
### 7.1.1 基本语法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
RUN <command>
|
||||
RUN ["executable", "param1", "param2"]
|
||||
@@ -17,8 +15,6 @@ RUN ["executable", "param1", "param2"]
|
||||
|
||||
#### 1. Shell 格式
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
RUN apt-get update
|
||||
```
|
||||
@@ -32,8 +28,6 @@ RUN apt-get update
|
||||
|
||||
#### 2. Exec 格式
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
RUN ["apt-get", "update"]
|
||||
```
|
||||
@@ -106,8 +100,6 @@ RUN wget http://url | gzip -d > file
|
||||
|
||||
#### Q:为什么 `RUN cd /app` 不生效?
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
RUN cd /app
|
||||
RUN touch hello.txt
|
||||
@@ -122,8 +114,6 @@ RUN touch hello.txt
|
||||
|
||||
#### Q:环境变量不生效?
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
RUN export MY_VAR=hello
|
||||
RUN echo $MY_VAR
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
### 7.2.1 基本语法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
COPY [选项] <源路径>... <目标路径>
|
||||
COPY [选项] ["<源路径1>", "<源路径2>", ... "<目标路径>"]
|
||||
@@ -17,8 +15,6 @@ COPY [选项] ["<源路径1>", "<源路径2>", ... "<目标路径>"]
|
||||
|
||||
#### 复制单个文件
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 复制文件到指定目录
|
||||
|
||||
@@ -31,8 +27,6 @@ COPY config.json /app/settings.json
|
||||
|
||||
#### 复制多个文件
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 复制多个指定文件
|
||||
|
||||
@@ -46,8 +40,6 @@ COPY src/*.js /app/src/
|
||||
|
||||
#### 复制目录
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 复制整个目录的内容(不是目录本身)
|
||||
|
||||
@@ -88,16 +80,12 @@ 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
|
||||
@@ -183,8 +171,6 @@ ADD app.tar.gz /app/
|
||||
|
||||
#### 从其他构建阶段复制
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 构建阶段
|
||||
|
||||
@@ -203,8 +189,6 @@ COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
#### 使用 --link 优化缓存
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 使用 --link 后,文件以独立层添加,不依赖前序指令
|
||||
|
||||
@@ -246,8 +230,6 @@ Dockerfile
|
||||
|
||||
#### 1. 利用缓存,先复制依赖文件
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ✅ 好:先复制依赖定义,再安装,最后复制代码
|
||||
|
||||
@@ -263,8 +245,6 @@ RUN npm install
|
||||
|
||||
#### 2. 使用 .dockerignore
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 确保 node_modules 不被复制
|
||||
|
||||
@@ -276,8 +256,6 @@ COPY . .
|
||||
|
||||
#### 3. 明确复制路径
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ✅ 好:明确的路径
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
### 7.3.1 基本语法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ADD [选项] <源路径>... <目标路径>
|
||||
ADD [选项] ["<源路径>", ... "<目标路径>"]
|
||||
@@ -34,8 +32,6 @@ ADD [选项] ["<源路径>", ... "<目标路径>"]
|
||||
|
||||
#### 基本用法 (自动解压本地 tar)
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 自动解压 tar.gz 到目标目录
|
||||
|
||||
@@ -60,8 +56,6 @@ ADD ubuntu-noble-core-cloudimg-amd64-root.tar.gz /
|
||||
|
||||
#### 解压过程
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```bash
|
||||
ADD app.tar.gz /app/
|
||||
│
|
||||
@@ -81,8 +75,6 @@ app.tar.gz 包含: /app/ 目录结果:
|
||||
|
||||
#### 基本用法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 从 URL 下载文件
|
||||
|
||||
@@ -100,8 +92,6 @@ ADD https://example.com/app.zip /app/app.zip
|
||||
|
||||
#### 推荐替代方案
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ❌ 不推荐:使用 ADD 下载
|
||||
|
||||
@@ -123,8 +113,6 @@ RUN curl -fsSL https://example.com/app.tar.gz | tar -xz -C /app
|
||||
|
||||
### 7.3.5 修改文件所有者
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ADD --chown=node:node app.tar.gz /app/
|
||||
ADD --chown=1000:1000 files/ /app/
|
||||
@@ -136,8 +124,6 @@ ADD --chown=1000:1000 files/ /app/
|
||||
|
||||
#### ✅ 适合使用 ADD
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 解压本地 tar 文件
|
||||
|
||||
@@ -151,8 +137,6 @@ ADD dist.tar.gz /app/
|
||||
|
||||
#### ❌ 不适合使用 ADD
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 复制普通文件(用 COPY)
|
||||
|
||||
@@ -202,8 +186,6 @@ ADD app.tar.gz /app/
|
||||
|
||||
#### 1. 默认使用 COPY
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ✅ 大多数场景使用 COPY
|
||||
|
||||
@@ -212,8 +194,6 @@ COPY . /app/
|
||||
|
||||
#### 2. 仅在需要解压时使用 ADD
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ✅ 自动解压场景
|
||||
|
||||
@@ -222,8 +202,6 @@ ADD app.tar.gz /app/
|
||||
|
||||
#### 3. 不要用 ADD 下载文件
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ❌ 避免
|
||||
|
||||
@@ -236,8 +214,6 @@ RUN curl -fsSL https://example.com/file.tar.gz | tar -xz -C /app
|
||||
|
||||
#### 4. 解压后清理
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 如果需要控制解压过程
|
||||
|
||||
|
||||
@@ -20,8 +20,6 @@ CMD 有三种格式:
|
||||
|
||||
#### exec 格式 (推荐)
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
CMD ["python", "app.py"]
|
||||
@@ -36,8 +34,6 @@ CMD ["node", "server.js"]
|
||||
|
||||
#### shell 格式
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
CMD echo "Hello World"
|
||||
CMD nginx -g "daemon off;"
|
||||
@@ -70,8 +66,6 @@ CMD ["sh", "-c", "echo $HOME"]
|
||||
|
||||
#### 信号传递问题示例
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ❌ shell 格式:docker stop 会超时
|
||||
|
||||
@@ -116,8 +110,6 @@ CMD ["/bin/bash"] + cat /etc/os-release
|
||||
|
||||
#### 错误示例
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ❌ 容器启动后立即退出
|
||||
|
||||
@@ -126,8 +118,6 @@ CMD service nginx start
|
||||
|
||||
#### 原因分析
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```bash
|
||||
1. CMD service nginx start
|
||||
↓ 被转换为
|
||||
@@ -144,8 +134,6 @@ CMD service nginx start
|
||||
|
||||
#### 正确做法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ✅ 让 nginx 在前台运行
|
||||
|
||||
@@ -163,8 +151,6 @@ CMD ["nginx", "-g", "daemon off;"]
|
||||
|
||||
#### 单独使用 CMD
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## Dockerfile
|
||||
|
||||
@@ -178,8 +164,6 @@ $ docker run myimage curl -v ... # 完全覆盖
|
||||
|
||||
#### 搭配 ENTRYPOINT
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## Dockerfile
|
||||
|
||||
@@ -200,8 +184,6 @@ $ docker run myimage http://other.com # curl -s http://other.com(参数覆盖
|
||||
|
||||
#### 1. 优先使用 exec 格式
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ✅ 推荐
|
||||
|
||||
@@ -214,8 +196,6 @@ CMD ["sh", "-c", "echo $PATH && python app.py"]
|
||||
|
||||
#### 2. 确保应用在前台运行
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ✅ 前台运行
|
||||
|
||||
@@ -231,8 +211,6 @@ CMD systemctl start nginx
|
||||
|
||||
#### 3. 使用双引号
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ✅ 正确:双引号
|
||||
|
||||
@@ -245,8 +223,6 @@ CMD ['node', 'server.js']
|
||||
|
||||
#### 4. 配合 ENTRYPOINT 使用
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 用于可配置参数的场景
|
||||
|
||||
@@ -275,8 +251,6 @@ CMD ["echo", "second"] # 只有这个生效
|
||||
|
||||
#### Q:如何在 CMD 中使用环境变量?
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 方法1:使用 shell 格式
|
||||
|
||||
|
||||
@@ -40,8 +40,6 @@ ENTRYPOINT nginx -g "daemon off;"
|
||||
|
||||
#### 行为对比
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 只用 CMD
|
||||
|
||||
@@ -88,8 +86,6 @@ $ 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/*
|
||||
@@ -109,8 +105,6 @@ exec: "-i": executable file not found
|
||||
|
||||
#### 使用 ENTRYPOINT 解决
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
FROM ubuntu:24.04
|
||||
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
|
||||
@@ -129,8 +123,6 @@ HTTP/1.1 200 OK
|
||||
|
||||
#### 交互图示
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```bash
|
||||
ENTRYPOINT ["curl", "-s", "http://myip.ipip.net"]
|
||||
│
|
||||
@@ -152,8 +144,6 @@ curl -s http://myip.ipip.net -i
|
||||
|
||||
#### 实现方式
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
FROM redis:7-alpine
|
||||
COPY docker-entrypoint.sh /usr/local/bin/
|
||||
@@ -185,8 +175,6 @@ exec "$@"
|
||||
|
||||
#### 工作流程
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```bash
|
||||
docker run redis docker run redis bash
|
||||
│ │
|
||||
@@ -209,8 +197,6 @@ docker-entrypoint.sh redis-server docker-entrypoint.sh bash
|
||||
|
||||
### 7.5.6 场景三:带参数的应用
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
FROM python:3.12-slim
|
||||
WORKDIR /app
|
||||
@@ -280,8 +266,6 @@ $ docker run --entrypoint /bin/cat myimage /etc/os-release
|
||||
|
||||
#### 1. 使用 exec 格式
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ✅ 推荐
|
||||
|
||||
@@ -294,8 +278,6 @@ ENTRYPOINT python app.py
|
||||
|
||||
#### 2. 提供有意义的默认参数
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ENTRYPOINT ["nginx"]
|
||||
CMD ["-g", "daemon off;"]
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
### 7.6.1 基本语法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 格式一:单个变量
|
||||
|
||||
@@ -20,8 +18,6 @@ ENV <key1>=<value1> <key2>=<value2> ...
|
||||
|
||||
#### 设置单个变量
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ENV NODE_VERSION 20.10.0
|
||||
ENV APP_ENV production
|
||||
@@ -29,8 +25,6 @@ ENV APP_ENV production
|
||||
|
||||
#### 设置多个变量
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ENV NODE_VERSION=20.10.0 \
|
||||
APP_ENV=production \
|
||||
@@ -45,8 +39,6 @@ ENV NODE_VERSION=20.10.0 \
|
||||
|
||||
#### 1. 后续指令中使用
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ENV NODE_VERSION=20.10.0
|
||||
|
||||
@@ -67,8 +59,6 @@ COPY . $APP_HOME
|
||||
|
||||
#### 2. 容器运行时使用
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ENV DATABASE_URL=postgres://localhost/mydb
|
||||
```
|
||||
@@ -147,8 +137,6 @@ DATABASE_URL=postgres://localhost/mydb
|
||||
|
||||
#### 组合使用
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ARG 接收构建时参数
|
||||
|
||||
@@ -175,8 +163,6 @@ $ docker build --build-arg NODE_VERSION=18 -t myapp .
|
||||
|
||||
#### 1. 统一管理版本号
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ✅ 好:版本集中管理
|
||||
|
||||
@@ -193,8 +179,6 @@ RUN apt-get install nginx=1.25.0
|
||||
|
||||
#### 2. 不要存储敏感信息
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ❌ 错误:密码写入镜像
|
||||
|
||||
@@ -209,8 +193,6 @@ ENV DB_PASSWORD=secret123
|
||||
|
||||
#### 3. 为应用提供合理默认值
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ENV APP_ENV=production \
|
||||
APP_PORT=8080 \
|
||||
@@ -219,8 +201,6 @@ ENV APP_ENV=production \
|
||||
|
||||
#### 4. 使用有意义的变量名
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ✅ 好:清晰的命名
|
||||
|
||||
@@ -260,8 +240,6 @@ $ docker exec mycontainer env
|
||||
|
||||
#### Q:多行 ENV 还是多个 ENV
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ✅ 推荐:减少层数
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
### 7.7.1 基本语法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ARG <参数名>[=<默认值>]
|
||||
```
|
||||
@@ -37,8 +35,6 @@ ARG <参数名>[=<默认值>]
|
||||
|
||||
#### 定义和使用
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 定义有默认值的 ARG
|
||||
|
||||
@@ -68,8 +64,6 @@ $ docker build --build-arg NODE_VERSION=18 -t myapp .
|
||||
|
||||
#### FROM 之前的 ARG
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## FROM 之前的 ARG 只能用于 FROM 指令
|
||||
|
||||
@@ -85,8 +79,6 @@ RUN echo $REGISTRY # 输出空
|
||||
|
||||
#### FROM 之后重新声明
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ARG NODE_VERSION=20
|
||||
|
||||
@@ -100,8 +92,6 @@ RUN echo "Node version: $NODE_VERSION"
|
||||
|
||||
#### 多阶段构建中的 ARG
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ARG BASE_VERSION=alpine
|
||||
|
||||
@@ -124,8 +114,6 @@ RUN echo "Running with Node $NODE_VERSION"
|
||||
|
||||
#### 1. 控制基础镜像版本
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ARG ALPINE_VERSION=3.19
|
||||
FROM alpine:${ALPINE_VERSION}
|
||||
@@ -137,8 +125,6 @@ $ docker build --build-arg ALPINE_VERSION=3.18 .
|
||||
|
||||
#### 2. 设置软件版本
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ARG NGINX_VERSION=1.25.0
|
||||
|
||||
@@ -147,8 +133,6 @@ RUN curl -fsSL https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz | tar -x
|
||||
|
||||
#### 3. 配置构建环境
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ARG BUILD_ENV=production
|
||||
ARG ENABLE_DEBUG=false
|
||||
@@ -162,8 +146,6 @@ RUN if [ "$ENABLE_DEBUG" = "true" ]; then \
|
||||
|
||||
#### 4. 配置私有仓库
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ARG NPM_TOKEN
|
||||
|
||||
@@ -221,8 +203,6 @@ $ docker build --build-arg HTTP_PROXY=http://proxy:8080 .
|
||||
|
||||
#### 1. 为 ARG 提供合理默认值
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ✅ 好:有默认值
|
||||
|
||||
@@ -235,8 +215,6 @@ ARG NODE_VERSION
|
||||
|
||||
#### 2. 不要用 ARG 存储敏感信息
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ❌ 错误:密码会被记录在镜像历史中
|
||||
|
||||
@@ -250,8 +228,6 @@ RUN echo "password=$DB_PASSWORD" > /app/.env
|
||||
|
||||
#### 3. 使用 ARG 提高构建灵活性
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ARG BASE_IMAGE=python:3.12-slim
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
### 7.8.1 基本语法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
VOLUME ["/路径1", "/路径2"]
|
||||
VOLUME /路径
|
||||
@@ -47,8 +45,6 @@ flowchart LR
|
||||
|
||||
#### 定义单个卷
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
FROM mysql:8.0
|
||||
VOLUME /var/lib/mysql
|
||||
@@ -56,8 +52,6 @@ VOLUME /var/lib/mysql
|
||||
|
||||
#### 定义多个卷
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
FROM myapp
|
||||
VOLUME ["/data", "/logs", "/config"]
|
||||
@@ -113,8 +107,6 @@ RUN echo "hello" > /data/test.txt
|
||||
|
||||
#### 正确做法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
FROM ubuntu
|
||||
|
||||
@@ -133,8 +125,6 @@ VOLUME /data
|
||||
|
||||
#### 数据库持久化
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
FROM postgres:15
|
||||
VOLUME /var/lib/postgresql/data
|
||||
@@ -142,8 +132,6 @@ VOLUME /var/lib/postgresql/data
|
||||
|
||||
#### 日志目录
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
FROM nginx
|
||||
VOLUME /var/log/nginx
|
||||
@@ -151,8 +139,6 @@ VOLUME /var/log/nginx
|
||||
|
||||
#### 上传文件目录
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
FROM myapp
|
||||
VOLUME /app/uploads
|
||||
@@ -235,8 +221,6 @@ $ docker run -v mysql_data:/var/lib/mysql mysql:8.0
|
||||
|
||||
#### 1. 定义必须持久化的路径
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 数据库必须使用卷
|
||||
|
||||
@@ -246,8 +230,6 @@ VOLUME /var/lib/postgresql/data
|
||||
|
||||
#### 2. 不要在 VOLUME 后修改目录
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ❌ 避免
|
||||
|
||||
@@ -262,8 +244,6 @@ VOLUME /app/data
|
||||
|
||||
#### 3. 文档中说明 VOLUME 用途
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 持久化用户上传的文件
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
## 7.9 EXPOSE 声明端口
|
||||
## 7.9 EXPOSE 暴露端口
|
||||
|
||||
### 7.9.1 基本语法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
EXPOSE <端口> [<端口>/<协议>...]
|
||||
```
|
||||
@@ -14,8 +12,6 @@ EXPOSE <端口> [<端口>/<协议>...]
|
||||
|
||||
### 7.9.2 基本用法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 声明单个端口
|
||||
|
||||
@@ -88,8 +84,6 @@ flowchart TD
|
||||
|
||||
#### 没有 EXPOSE 也能 -p
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 即使没有 EXPOSE,也可以使用 -p
|
||||
|
||||
@@ -111,8 +105,6 @@ $ docker run -p 8080:80 mynginx
|
||||
|
||||
#### 误解:EXPOSE 会打开端口
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ❌ 错误理解:这不会让容器可从外部访问
|
||||
|
||||
@@ -129,8 +121,6 @@ EXPOSE 只是元数据声明。容器是否实际监听该端口,取决于容
|
||||
|
||||
#### 正确理解
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## Dockerfile
|
||||
|
||||
@@ -150,8 +140,6 @@ $ docker run -p 8080:80 nginx # 2. 映射:宿主机 8080 → 容器 80
|
||||
|
||||
#### 1. 总是声明应用使用的端口
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## Web 服务
|
||||
|
||||
@@ -171,8 +159,6 @@ EXPOSE 6379
|
||||
|
||||
#### 2. 使用明确的协议
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## 默认是 TCP
|
||||
|
||||
@@ -189,8 +175,6 @@ EXPOSE 53/tcp 53/udp
|
||||
|
||||
#### 3. 与应用实际端口保持一致
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ✅ 好:EXPOSE 与应用端口一致
|
||||
|
||||
@@ -208,8 +192,6 @@ CMD ["node", "server.js"] # 实际监听 3000
|
||||
|
||||
### 7.9.7 使用环境变量
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
ARG PORT=80
|
||||
EXPOSE $PORT
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 7.19 本章小结
|
||||
## 本章小结
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
- [COPY 复制文件](7.2_copy.md):文件复制
|
||||
- [RUN 执行命令](../04_image/4.5_build.md):执行构建命令
|
||||
- [最佳实践](../appendix/20.1_best_practices.md):Dockerfile 编写指南
|
||||
- [最佳实践](../appendix/best_practices.md):Dockerfile 编写指南
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
- [安全](../18_security/README.md):容器安全实践
|
||||
- [ENTRYPOINT](7.5_entrypoint.md):入口脚本中的用户切换
|
||||
- [最佳实践](../appendix/20.1_best_practices.md):Dockerfile 安全
|
||||
- [最佳实践](../appendix/best_practices.md):Dockerfile 安全
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
- [CMD 容器启动命令](7.4_cmd.md):启动主进程
|
||||
- [Compose 模板文件](../11_compose/11.5_compose_file.md):Compose 中的健康检查
|
||||
- [Docker 调试](../appendix/20.2_debug.md):容器排障
|
||||
- [Docker 调试](../appendix/debug.md):容器排障
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
@@ -53,7 +53,7 @@
|
||||
### 7.19.4 延伸阅读
|
||||
|
||||
- [COPY 指令](7.2_copy.md):文件复制
|
||||
- [Dockerfile 最佳实践](../appendix/20.1_best_practices.md):基础镜像设计
|
||||
- [Dockerfile 最佳实践](../appendix/best_practices.md):基础镜像设计
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
@@ -66,7 +66,7 @@
|
||||
### 7.19.5 延伸阅读
|
||||
|
||||
- [OCI 标签规范](https://github.com/opencontainers/image-spec/blob/main/annotations.md)
|
||||
- [Dockerfile 最佳实践](../appendix/20.1_best_practices.md)
|
||||
- [Dockerfile 最佳实践](../appendix/best_practices.md)
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
@@ -79,7 +79,7 @@
|
||||
### 7.19.6 延伸阅读
|
||||
|
||||
- [RUN 指令](../04_image/4.5_build.md):执行命令
|
||||
- [Dockerfile 最佳实践](../appendix/20.1_best_practices.md):错误处理与调试
|
||||
- [Dockerfile 最佳实践](../appendix/best_practices.md):错误处理与调试
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
@@ -93,7 +93,7 @@
|
||||
|
||||
- [CMD 容器启动命令](7.4_cmd.md):容器启动时的命令
|
||||
- [WORKDIR 指定工作目录](7.10_workdir.md):改变目录
|
||||
- [Dockerfile 最佳实践](../appendix/20.1_best_practices.md)
|
||||
- [Dockerfile 最佳实践](../appendix/best_practices.md)
|
||||
|
||||
| 操作 | 示例 |
|
||||
|------|------|
|
||||
@@ -108,7 +108,7 @@
|
||||
- [ADD 指令](7.3_add.md):复制和解压
|
||||
- [WORKDIR 指令](7.10_workdir.md):设置工作目录
|
||||
- [多阶段构建](7.17_multistage_builds.md):优化镜像大小
|
||||
- [最佳实践](../appendix/20.1_best_practices.md):Dockerfile 编写指南
|
||||
- [最佳实践](../appendix/best_practices.md):Dockerfile 编写指南
|
||||
|
||||
| 场景 | 推荐指令 |
|
||||
|------|---------|
|
||||
@@ -122,7 +122,7 @@
|
||||
|
||||
- [COPY 复制文件](7.2_copy.md):基本复制操作
|
||||
- [多阶段构建](7.17_multistage_builds.md):减少镜像体积
|
||||
- [最佳实践](../appendix/20.1_best_practices.md):Dockerfile 编写指南
|
||||
- [最佳实践](../appendix/best_practices.md):Dockerfile 编写指南
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
@@ -136,7 +136,7 @@
|
||||
|
||||
- [ENTRYPOINT 入口点](7.5_entrypoint.md):固定的启动命令
|
||||
- [后台运行](../05_container/5.2_daemon.md):容器前台/后台概念
|
||||
- [最佳实践](../appendix/20.1_best_practices.md):Dockerfile 编写指南
|
||||
- [最佳实践](../appendix/best_practices.md):Dockerfile 编写指南
|
||||
|
||||
| ENTRYPOINT | CMD | 适用场景 |
|
||||
|------------|-----|---------|
|
||||
@@ -147,7 +147,7 @@
|
||||
### 7.19.11 延伸阅读
|
||||
|
||||
- [CMD 容器启动命令](7.4_cmd.md):默认命令
|
||||
- [最佳实践](../appendix/20.1_best_practices.md):启动命令设计
|
||||
- [最佳实践](../appendix/best_practices.md):启动命令设计
|
||||
- [后台运行](../05_container/5.2_daemon.md):前台/后台概念
|
||||
|
||||
| 要点 | 说明 |
|
||||
@@ -162,7 +162,7 @@
|
||||
|
||||
- [ARG 构建参数](7.7_arg.md):构建时变量
|
||||
- [Compose 环境变量](../11_compose/11.5_compose_file.md):Compose 中的环境变量
|
||||
- [最佳实践](../appendix/20.1_best_practices.md):Dockerfile 编写指南
|
||||
- [最佳实践](../appendix/best_practices.md):Dockerfile 编写指南
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## 8.2 数据卷
|
||||
## 8.1 数据卷
|
||||
|
||||
### 8.2.1 为什么需要数据卷
|
||||
### 8.1.1 为什么需要数据卷
|
||||
|
||||
容器的存储层有一个关键问题:**容器删除后,数据就没了**。
|
||||
|
||||
@@ -15,7 +15,7 @@ flowchart LR
|
||||
|
||||
---
|
||||
|
||||
### 8.2.2 数据卷的特性
|
||||
### 8.1.2 数据卷的特性
|
||||
|
||||
| 特性 | 说明 |
|
||||
|------|------|
|
||||
@@ -27,12 +27,10 @@ flowchart LR
|
||||
|
||||
---
|
||||
|
||||
### 8.2.3 数据卷 vs 容器存储层
|
||||
### 8.1.3 数据卷 vs 容器存储层
|
||||
|
||||
#### 容器存储层 (不推荐存储重要数据)
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph Container [容器]
|
||||
@@ -47,8 +45,6 @@ graph TD
|
||||
|
||||
#### 数据卷 (推荐)
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph Container [容器]
|
||||
@@ -65,7 +61,7 @@ graph TD
|
||||
|
||||
---
|
||||
|
||||
### 8.2.4 数据卷基本操作
|
||||
### 8.1.4 数据卷基本操作
|
||||
|
||||
#### 创建数据卷
|
||||
|
||||
@@ -107,7 +103,7 @@ $ docker volume inspect my-vol
|
||||
|
||||
---
|
||||
|
||||
### 8.2.5 挂载数据卷
|
||||
### 8.1.5 挂载数据卷
|
||||
|
||||
#### 方式一:--mount (推荐)
|
||||
|
||||
@@ -163,7 +159,7 @@ $ docker run -d \
|
||||
|
||||
---
|
||||
|
||||
### 8.2.6 使用场景示例
|
||||
### 8.1.6 使用场景示例
|
||||
|
||||
#### 场景一:数据库持久化
|
||||
|
||||
@@ -227,7 +223,7 @@ $ docker run -d \
|
||||
|
||||
---
|
||||
|
||||
### 8.2.7 数据卷管理
|
||||
### 8.1.7 数据卷管理
|
||||
|
||||
#### 删除数据卷
|
||||
|
||||
@@ -261,7 +257,7 @@ $ docker volume prune -f
|
||||
|
||||
---
|
||||
|
||||
### 8.2.8 数据卷备份与恢复
|
||||
### 8.1.8 数据卷备份与恢复
|
||||
|
||||
#### 备份数据卷
|
||||
|
||||
@@ -316,7 +312,7 @@ echo "Backed up ${VOLUME_NAME} to ${BACKUP_DIR}/${VOLUME_NAME}_${TIMESTAMP}.tar.
|
||||
|
||||
---
|
||||
|
||||
### 8.2.9 数据卷 vs 绑定挂载
|
||||
### 8.1.9 数据卷 vs 绑定挂载
|
||||
|
||||
Docker 有两种主要的数据持久化方式:
|
||||
|
||||
@@ -342,7 +338,7 @@ $ docker run -v /host/path:/app/data nginx
|
||||
|
||||
---
|
||||
|
||||
### 8.2.10 常见问题
|
||||
### 8.1.10 常见问题
|
||||
|
||||
#### Q:如何知道容器使用了哪些数据卷?
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## 8.3 挂载主机目录
|
||||
## 8.2 挂载主机目录
|
||||
|
||||
### 8.3.1 什么是绑定挂载
|
||||
### 8.2.1 什么是绑定挂载
|
||||
|
||||
Bind Mount (绑定挂载) 将 **宿主机的目录或文件** 直接挂载到容器中。容器可以读写宿主机的文件系统。
|
||||
|
||||
@@ -21,7 +21,7 @@ flowchart LR
|
||||
|
||||
---
|
||||
|
||||
### 8.3.2 Bind Mount vs Volume
|
||||
### 8.2.2 Bind Mount vs Volume
|
||||
|
||||
| 特性 | Bind Mount | Volume |
|
||||
|------|------------|--------|
|
||||
@@ -45,7 +45,7 @@ flowchart LR
|
||||
|
||||
---
|
||||
|
||||
### 8.3.3 基本语法
|
||||
### 8.2.3 基本语法
|
||||
|
||||
#### 使用 --mount (推荐)
|
||||
|
||||
@@ -73,7 +73,7 @@ $ docker run -d \
|
||||
|
||||
---
|
||||
|
||||
### 8.3.4 使用场景
|
||||
### 8.2.4 使用场景
|
||||
|
||||
#### 场景一:开发环境代码同步
|
||||
|
||||
@@ -125,7 +125,7 @@ $ docker run --rm -it \
|
||||
|
||||
---
|
||||
|
||||
### 8.3.5 只读挂载
|
||||
### 8.2.5 只读挂载
|
||||
|
||||
防止容器修改宿主机文件:
|
||||
|
||||
@@ -152,7 +152,7 @@ touch: /app/config/new.txt: Read-only file system
|
||||
|
||||
---
|
||||
|
||||
### 8.3.6 挂载单个文件
|
||||
### 8.2.6 挂载单个文件
|
||||
|
||||
```bash
|
||||
## 挂载 bash 历史记录
|
||||
@@ -172,7 +172,7 @@ $ docker run -d \
|
||||
|
||||
---
|
||||
|
||||
### 8.3.7 查看挂载信息
|
||||
### 8.2.7 查看挂载信息
|
||||
|
||||
```bash
|
||||
$ docker inspect mycontainer --format '{{json .Mounts}}' | jq
|
||||
@@ -203,7 +203,7 @@ $ docker inspect mycontainer --format '{{json .Mounts}}' | jq
|
||||
|
||||
---
|
||||
|
||||
### 8.3.8 常见问题
|
||||
### 8.2.8 常见问题
|
||||
|
||||
#### Q:路径不存在报错
|
||||
|
||||
@@ -251,7 +251,7 @@ $ docker run -v /host/path:/container/path:cached myapp
|
||||
|
||||
---
|
||||
|
||||
### 8.3.9 最佳实践
|
||||
### 8.2.9 最佳实践
|
||||
|
||||
#### 1. 开发环境使用 Bind Mount
|
||||
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
## 8.4 tmpfs 挂载
|
||||
## 8.3 tmpfs 挂载
|
||||
|
||||
`tmpfs` 挂载会把数据放在宿主机内存中,而不是写入容器可写层或数据卷。
|
||||
|
||||
### 8.4.1 适用场景
|
||||
### 8.3.1 适用场景
|
||||
|
||||
- 临时缓存
|
||||
- 会话数据
|
||||
- 不希望落盘的敏感中间文件
|
||||
|
||||
### 8.4.2 基本用法
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
### 8.3.2 基本用法
|
||||
|
||||
```bash
|
||||
$ docker run --tmpfs /run:rw,noexec,nosuid,size=64m nginx
|
||||
@@ -22,13 +20,13 @@ $ docker run --tmpfs /run:rw,noexec,nosuid,size=64m nginx
|
||||
$ docker run --mount type=tmpfs,destination=/run,tmpfs-size=67108864 nginx
|
||||
```
|
||||
|
||||
### 8.4.3 注意事项
|
||||
### 8.3.3 注意事项
|
||||
|
||||
- 容器停止后,`tmpfs` 数据会丢失。
|
||||
- `tmpfs` 占用宿主机内存,建议显式限制大小。
|
||||
- 不适合需要持久化的数据。
|
||||
|
||||
### 8.4.4 与 Volume / Bind Mount 对比
|
||||
### 8.3.4 与 Volume / Bind Mount 对比
|
||||
|
||||
| 类型 | 数据位置 | 持久化 | 典型用途 |
|
||||
|------|---------|-------|---------|
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 8.5 本章小结
|
||||
## 本章小结
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
@@ -8,7 +8,7 @@
|
||||
| **适用场景** | 开发环境、配置文件、日志 |
|
||||
| **vs Volume** | Bind 更灵活,Volume 更适合生产 |
|
||||
|
||||
### 8.5.1 延伸阅读
|
||||
### 8.4.1 延伸阅读
|
||||
|
||||
- [数据卷](8.1_volume.md):Docker 管理的持久化存储
|
||||
- [tmpfs 挂载](8.3_tmpfs.md):内存临时存储
|
||||
@@ -23,7 +23,7 @@
|
||||
| 清理未用 | `docker volume prune` |
|
||||
| 挂载数据卷 | `-v name:/path` 或 `--mount source=name,target=/path` |
|
||||
|
||||
### 8.5.2 延伸阅读
|
||||
### 8.4.2 延伸阅读
|
||||
|
||||
- [绑定挂载](8.2_bind-mounts.md):挂载宿主机目录
|
||||
- [tmpfs 挂载](8.3_tmpfs.md):内存中的临时存储
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
## 9.2 配置 DNS
|
||||
## 9.1 配置 DNS
|
||||
|
||||
Docker 容器的 DNS 配置决定了容器如何解析域名。理解 DNS 机制对于容器网络的正确配置至关重要。
|
||||
Docker 1.10.0 以后,内建了一个 DNS 服务器,使得容器可以直接通过容器名称通信。方法很简单,只要在创建容器时使用 `--name` 为容器命名即可。
|
||||
|
||||
但是使用 Docker DNS 有个前提条件,就是它只能在 **自定义网络** 中使用。也就是说,如果使用的是默认的 `bridge` 网络,是无法使用 DNS 的,所以我们就需要自定义网络。
|
||||
|
||||
### 9.2.1 容器的 DNS 机制
|
||||
|
||||
@@ -13,7 +15,7 @@ Docker 容器的 DNS 配置有两种情况:
|
||||
|
||||
### 9.2.2 嵌入式 DNS
|
||||
|
||||
这是 Docker 网络最强大的功能之一。在自定义网络中,容器可以通过 "名字" 找到彼此,而不需要知道对方的 IP (因为 IP 可能会变)。
|
||||
这是 Docker 网络最强大的功能之一。在自定义网络中,容器可以通过 “名字” 找到彼此,而不需要知道对方的 IP (因为 IP 可能会变)。
|
||||
|
||||
```bash
|
||||
## 1. 创建自定义网络
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 9.3 Docker 网络类型
|
||||
## 9.2 网络类型
|
||||
|
||||
Docker 提供了多种网络驱动来满足不同的使用场景。安装 Docker 后,系统会自动创建三个默认网络:
|
||||
|
||||
@@ -10,7 +10,7 @@ def456... host host local
|
||||
ghi789... none null local
|
||||
```
|
||||
|
||||
### 9.3.1 网络类型对比
|
||||
### 9.2.1 网络类型对比
|
||||
|
||||
各网络类型的特点和适用场景如下:
|
||||
|
||||
@@ -22,7 +22,7 @@ ghi789... none null local
|
||||
| **overlay** | 跨主机网络 | Docker Swarm 集群 |
|
||||
| **macvlan** | 容器拥有独立 MAC 地址 | 需要直接接入物理网络 |
|
||||
|
||||
### 9.3.2 Bridge 网络 (默认)
|
||||
### 9.2.2 Bridge 网络 (默认)
|
||||
|
||||
Bridge 是 Docker 默认使用的网络模式。Docker 启动时会自动创建 `docker0` 虚拟网桥,所有未指定网络的容器都会连接到这个网桥上。
|
||||
|
||||
@@ -35,7 +35,7 @@ Bridge 是 Docker 默认使用的网络模式。Docker 启动时会自动创建
|
||||
| **容器 eth0** | 容器内的网卡 |
|
||||
| **IP 地址** | 自动从 172.17.0.0/16 网段分配 |
|
||||
|
||||
### 9.3.3 Host 网络
|
||||
### 9.2.3 Host 网络
|
||||
|
||||
使用 `--network host` 参数启动的容器会直接使用宿主机的网络栈,不再拥有独立的网络命名空间。容器内的端口就是宿主机的端口,无需端口映射。
|
||||
|
||||
@@ -45,7 +45,7 @@ $ docker run -d --network host nginx
|
||||
|
||||
这种模式下网络性能最高,但容器之间和宿主机之间没有网络隔离。
|
||||
|
||||
### 9.3.4 None 网络
|
||||
### 9.2.4 None 网络
|
||||
|
||||
使用 `--network none` 参数启动的容器只有 `lo` 回环网卡,完全没有外部网络连接。适用于只需要运行计算任务、不需要网络的容器。
|
||||
|
||||
@@ -55,7 +55,7 @@ $ docker run -it --network none alpine ip addr
|
||||
inet 127.0.0.1/8 scope host lo
|
||||
```
|
||||
|
||||
### 9.3.5 数据流向
|
||||
### 9.2.5 数据流向
|
||||
|
||||
容器网络中的数据流向可以分为以下几种情况:
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 9.4 用户自定义网络 (推荐)
|
||||
## 9.3 自定义网络
|
||||
|
||||
在生产环境中,推荐使用用户自定义网络代替默认的 bridge 网络。自定义网络提供了更好的隔离性和服务发现能力。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 9.5 容器互联
|
||||
## 9.4 容器互联
|
||||
|
||||
容器之间的网络通信是 Docker 网络的核心功能之一。本节介绍容器互联的几种方式。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 9.6 外部访问容器
|
||||
## 9.5 外部访问容器
|
||||
|
||||
容器运行在自己的隔离网络环境中 (通常是 Bridge 模式)。为了让外部网络访问容器内的服务,我们需要将容器的端口映射到宿主机的端口。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 9.7 网络隔离
|
||||
## 9.6 网络隔离
|
||||
|
||||
Docker 网络提供了天然的隔离能力,不同网络之间的容器默认无法通信。这是 Docker 网络安全的重要基础。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 9.8 本章小结
|
||||
## 本章小结
|
||||
|
||||
本章介绍了 Docker 网络配置的各个方面:
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 10.1 使用 `BuildKit` 构建镜像
|
||||
## 10.1 BuildKit
|
||||
|
||||
**BuildKit** 是下一代的镜像构建组件,在 https://github.com/moby/buildkit 开源。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 10.2 使用 Buildx 构建镜像
|
||||
## 10.2 使用 buildx 构建镜像
|
||||
|
||||
### 10.2.1 使用
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 10.3 构建多种系统架构支持的 Docker 镜像
|
||||
## 10.3 使用 buildx 构建多种系统架构支持的 Docker 镜像
|
||||
|
||||
Docker 镜像可以支持多种系统架构,这意味着你可以在 `x86_64`、`arm64` 等不同架构的机器上运行同一个镜像。这是通过一个名为 “manifest list” (或称为 “fat manifest”) 的文件来实现的。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 10.4 本章小结
|
||||
## 本章小结
|
||||
|
||||
Docker Buildx 是 Docker 构建系统的重要进化,提供了高效、安全且支持多平台的镜像构建能力。
|
||||
|
||||
@@ -16,4 +16,4 @@ Docker Buildx 是 Docker 构建系统的重要进化,提供了高效、安全
|
||||
|
||||
- [Dockerfile 指令详解](../07_dockerfile/README.md):Dockerfile 编写基础
|
||||
- [多阶段构建](../07_dockerfile/7.17_multistage_builds.md):优化镜像体积
|
||||
- [Dockerfile 最佳实践](../appendix/20.1_best_practices.md):编写高效 Dockerfile
|
||||
- [Dockerfile 最佳实践](../appendix/best_practices.md):编写高效 Dockerfile
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 11.1 Compose 简介
|
||||
## 11.1 简介
|
||||
|
||||
`Compose` 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。从功能上看,跟 `OpenStack` 中的 `Heat` 十分类似。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 11.4 Compose 命令说明
|
||||
## 11.4 命令说明
|
||||
|
||||
Docker Compose 提供了丰富的命令来管理项目和容器。本节将详细介绍这些命令的使用格式和常用选项。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 11.6 使用 Django
|
||||
## 11.6 实战 Django
|
||||
|
||||
> 本小节内容适合 `Python` 开发人员阅读。
|
||||
|
||||
@@ -52,8 +52,6 @@ $ mkdir django-docker && cd django-docker
|
||||
|
||||
### 11.6.3 步骤 1:创建 Dockerfile
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
FROM python:3.12-slim
|
||||
|
||||
@@ -92,8 +90,6 @@ COPY . /code/
|
||||
|
||||
### 11.6.4 步骤 2:创建 requirements.txt
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```txt
|
||||
Django>=5.0,<6.0
|
||||
psycopg[binary]>=3.1,<4.0
|
||||
@@ -364,5 +360,5 @@ services:
|
||||
|
||||
- [Compose 模板文件详解](11.5_compose_file.md):深入理解 Compose 文件的所有配置项
|
||||
- [使用 WordPress](11.8_wordpress.md):另一个 Compose 实战案例
|
||||
- [Dockerfile 最佳实践](../appendix/20.1_best_practices.md):构建更小、更安全的镜像
|
||||
- [Dockerfile 最佳实践](../appendix/best_practices.md):构建更小、更安全的镜像
|
||||
- [数据管理](../08_data/README.md):Volume 和数据持久化详解
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 11.7 使用 Rails
|
||||
## 11.7 实战 Rails
|
||||
|
||||
> 本小节内容适合 Ruby 开发人员阅读。
|
||||
|
||||
@@ -45,8 +45,6 @@ $ mkdir rails-docker && cd rails-docker
|
||||
|
||||
### 11.7.3 步骤 1:创建 Dockerfile
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
FROM ruby:3.2
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@ WordPress 是全球最流行的内容管理系统 (CMS)。使用 Docker Compose
|
||||
|
||||
### 11.8.1 项目结构
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```bash
|
||||
wordpress/
|
||||
├── compose.yaml
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
## 11.9 使用 Compose 搭建 LNMP 环境
|
||||
## 11.9 实战 LNMP
|
||||
|
||||
本项目的维护者 [khs1994](https://github.com/khs1994) 的开源项目 [khs1994-docker/lnmp](https://github.com/khs1994-docker/lnmp) 使用 Docker Compose 搭建了一套 LNMP 环境,各位开发者可以参考该项目在 Docker 或 Kubernetes 中运行 LNMP。
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 11.10 本章小结
|
||||
## 本章小结
|
||||
|
||||
Docker Compose 是管理多容器应用的利器,通过 YAML 文件声明式地定义服务、网络和数据卷。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 12.2 命名空间(Namespace)
|
||||
## 12.2 命名空间
|
||||
|
||||
命名空间(Namespace)是 Linux 内核的一个强大特性,为容器提供了隔离的运行环境。
|
||||
命名空间是 Linux 内核一个强大的特性。每个容器都有自己单独的命名空间,运行在其中的应用都像是在独立的操作系统中运行一样。命名空间保证了容器之间彼此互不影响。
|
||||
|
||||
## 12.2 什么是 Namespace
|
||||
|
||||
@@ -85,8 +85,6 @@ NET Namespace 负责网络栈的隔离,包括网卡、路由表和 iptables
|
||||
|
||||
#### NET 隔离效果
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Host ["宿主机"]
|
||||
@@ -122,8 +120,6 @@ MNT Namespace 负责文件系统挂载点的隔离,确保容器看到独立的
|
||||
|
||||
#### MNT 隔离效果
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```bash
|
||||
宿主机文件系统: 容器内看到的:
|
||||
/ / ← 容器的根目录
|
||||
@@ -204,8 +200,6 @@ USER Namespace 允许将容器内的用户 ID 映射到宿主机的不同用户
|
||||
|
||||
#### USER 隔离效果
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Container ["容器内"]
|
||||
|
||||
@@ -30,8 +30,6 @@ Docker 选择联合文件系统作为其存储驱动,主要基于以下几个
|
||||
|
||||
#### 1. 镜像分层复用
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Nginx["nginx:alpine"] --> Alpine["alpine:3.19 (共享基础层)"]
|
||||
@@ -192,8 +190,6 @@ $ docker inspect nginx:alpine --format '{{json .GraphDriver.Data}}' | jq
|
||||
|
||||
#### 1. 减少镜像层数
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```docker
|
||||
## ❌ 每条命令创建一层
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 12.6 Docker 网络实现
|
||||
## 12.6 网络
|
||||
|
||||
Docker 的网络实现其实就是利用了 Linux 上的网络命名空间和虚拟网络设备 (特别是 veth pair)。建议先熟悉了解这两部分的基本概念再阅读本章。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 12.7 本章小结
|
||||
## 本章小结
|
||||
|
||||
| Namespace | 隔离内容 | 一句话说明 |
|
||||
|-----------|---------|-----------|
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
## 13.1 Kubernetes 简介
|
||||
## 13.1 简介
|
||||
|
||||
如图 12-1 所示,Kubernetes 使用舵手图标作为项目标识。
|
||||
如图 13-1 所示,Kubernetes 使用舵手图标作为项目标识。
|
||||
|
||||

|
||||
|
||||
图 12-1 Kubernetes 项目标识
|
||||
图 13-1 Kubernetes 项目标识
|
||||
|
||||
### 13.1.1 什么是 Kubernetes
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 13.4 Kubernetes 高级特性
|
||||
## 13.4 高级特性
|
||||
|
||||
掌握了 Kubernetes 的核心概念 (Pod,Service,Deployment) 后,我们需要了解更多高级特性以构建生产级应用。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 13.5 Kubernetes 实战练习
|
||||
## 13.5 实战练习
|
||||
|
||||
本章将通过一个具体的案例:部署一个 Nginx 网站,并为其配置 Service 和 Ingress,来串联前面学到的知识。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 13.6 本章小结
|
||||
## 本章小结
|
||||
|
||||
Kubernetes 是当前最主流的容器编排平台,其声明式管理模型和丰富的 API 为大规模容器化应用提供了坚实的基础。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 14.3 Docker Desktop 启用 Kubernetes
|
||||
## 14.3 在 Docker Desktop 使用
|
||||
|
||||
使用 Docker Desktop 可以很方便的启用 Kubernetes。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 14.7 Kubernetes Dashboard
|
||||
## 14.7 部署 Dashboard
|
||||
|
||||
[Kubernetes Dashboard](https://github.com/kubernetes/dashboard) 是基于网页的 Kubernetes 用户界面。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# kubectl 使用
|
||||
## 14.8 Kubernetes 命令行 kubectl
|
||||
|
||||
[kubectl](https://github.com/kubernetes/kubernetes) 是 Kubernetes 自带的客户端,可以用它来直接操作 Kubernetes。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 14.9 本章小结
|
||||
## 本章小结
|
||||
|
||||
部署 Kubernetes 集群有多种方式,应根据使用场景选择合适的方案。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 15.3 etcd 集群
|
||||
## 15.3 集群
|
||||
|
||||
下面我们使用 [Docker Compose](../11_compose/README.md) 模拟启动一个 3 节点的 `etcd` 集群。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 15.5 本章小结
|
||||
## 本章小结
|
||||
|
||||
etcd 是 Kubernetes 的核心存储组件,为分布式系统提供可靠的键值存储和服务发现能力。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 16.5 多云部署策略比较
|
||||
## 16.5 多云部署策略
|
||||
|
||||
企业在选择容器云平台时,通常会在 AWS EKS,Azure AKS,Google GKE 以及国内的阿里云 ACK,腾讯云 TKE 之间进行权衡。
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 16.6 本章小结
|
||||
## 本章小结
|
||||
|
||||
本章介绍了公有云服务对 Docker 的积极支持,以及新出现的容器云平台。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 17.1 Fedora CoreOS 介绍
|
||||
## 17.1 Fedora CoreOS 简介
|
||||
|
||||
[Fedora CoreOS](https://getfedora.org/coreos/) 是一个自动更新的,最小的,整体的,以容器为中心的操作系统,不仅适用于集群,而且可独立运行,并针对运行 Kubernetes 进行了优化。它旨在结合 CoreOS Container Linux 和 Fedora Atomic Host 的优点,将 Container Linux 中的 [Ignition](https://github.com/coreos/ignition) 与 [rpm-ostree](https://github.com/coreos/rpm-ostree) 和 Project Atomic 中的 SELinux 强化等技术相集成。其目标是提供最佳的容器主机,以安全,大规模地运行容器化的工作负载。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 17.2 安装 Fedora CoreOS
|
||||
## 17.2 Fedora CoreOS 安装
|
||||
|
||||
### 17.2.1 下载 ISO
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# podman
|
||||
## 17.3 podman - 下一代 Linux 容器工具
|
||||
|
||||
[`podman`](https://github.com/containers/podman) 是一个无守护进程、与 Docker 命令高度兼容的下一代 Linux 容器工具。它由 Red Hat 开发,旨在提供一个更安全的容器运行环境。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 17.4 本章小结
|
||||
## 本章小结
|
||||
|
||||
Docker 并非容器生态的唯一选择,了解其他工具有助于根据场景做出合适的技术选型。
|
||||
|
||||
|
||||
@@ -1,18 +1,85 @@
|
||||
## 18.1 内核命名空间
|
||||
|
||||
命名空间 (Namespace) 是 Linux 容器隔离的基础,它确保了容器内的进程无法干扰主机或其他容器。
|
||||
命名空间 (Namespace) 是 Linux 容器隔离的基础,它确保了容器内的进程无法直接干扰主机或其他容器。虽然在本书第 12 章中我们已经从底层实现的角度介绍了 Namespace,但在本节中,我们将重点探讨其**安全意义**及相关配置。
|
||||
|
||||
Docker 容器和 LXC 容器很相似,所提供的安全特性也差不多。当用 `docker run` 启动一个容器时,在后台 Docker 为容器创建了一个独立的命名空间和控制组集合。
|
||||
### 18.1.1 隔离的安全本质
|
||||
|
||||
命名空间提供了最基础也是最直接的隔离,在容器中运行的进程不会被运行在主机上的进程和其它容器发现和作用。
|
||||
Docker 守护进程在启动容器时,会在后台为容器创建一套独立的命名空间。命名空间提供了最基础也是最直接的隔离:
|
||||
|
||||
每个容器都有自己独有的网络栈,意味着它们不能访问其他容器的 sockets 或接口。不过,如果主机系统上做了相应的设置,容器可以像跟主机交互一样的和其他容器交互。当指定公共端口或使用 links 来连接 2 个容器时,容器就可以相互通信了 (可以根据配置来限制通信的策略)。
|
||||
- **PID Namespace**:防止容器内的进程查看或终止宿主机或其他容器的进程。恶意攻击者即使在容器内获得了 root 权限,也无法通过 `kill` 命令影响宿主机上的关键服务。
|
||||
- **NET Namespace**:每个容器都有自己独立的网络栈。如果没有显式地进行端口映射或将容器连接到同一网络,容器之间无法网络互通,从而限制了横向移动的能力。
|
||||
- **MNT Namespace**:为容器提供独立的文件系统视图。这可以防止容器不经意或恶意地修改宿主机的重要系统文件(如 `/etc/passwd`)。
|
||||
|
||||
从网络架构的角度来看,所有的容器通过本地主机的网桥接口相互通信,就像物理机器通过物理交换机通信一样。
|
||||
### 18.1.2 命名空间不是绝对安全的护城河
|
||||
|
||||
那么,内核中实现命名空间和私有网络的代码是否足够成熟?
|
||||
尽管命名空间提供了很好的隔离性,但我们必须认识到:**所有的容器依然共享同一个宿主机的 Linux 内核**。
|
||||
|
||||
内核命名空间从 2.6.15 版本 (2006 年 1 月发布) 之后被引入,数年间,这些机制的可靠性在诸多大型生产系统中被实践验证。
|
||||
这意味着,一旦宿主机的内核存在提权漏洞(如著名的 Dirty COW 漏洞),攻击者有可能通过突破 Namespace 的限制,直接在内核层面执行恶意代码,从而实现“容器逃逸”。
|
||||
|
||||
实际上,命名空间的想法和设计提出的时间要更早,最初是为了在内核中引入一种机制来实现 [OpenVZ](https://en.wikipedia.org/wiki/OpenVZ) 的特性。
|
||||
而 OpenVZ 项目早在 2005 年就发布了,其设计和实现都已经十分成熟。
|
||||
> [!WARNING]
|
||||
> 为了缓解内核漏洞带来的威胁,生产环境务必保持宿主机 Linux 内核的及时修补与更新,或者借助诸如 gVisor、Kata Containers 等提供了独立内核的安全容器技术。
|
||||
|
||||
通过命名空间,Docker 也能限制进程从外部环境获取信息。
|
||||
例如,由于进程环境被隔离,进程在内部其实是无法感知到外部宿主机的存在的。它既不能获取其他容器的进程列表,也无法通过网络与其他系统进行交互(除非经过配置)。
|
||||
|
||||
### 18.1.1 用户命名空间 与提权防护
|
||||
|
||||
在所有的 Namespace 中,**User Namespace** 对安全的影响尤为关键。
|
||||
|
||||
在默认情况下,容器内的 `root` 用户(UID=0)就是宿主机上的 `root` 用户。如果攻击者设法突破了容器的其他隔离机制获取了宿主机的访问权限,他将拥有宿主机的最高系统权限。
|
||||
|
||||
通过启用 **User Namespace Remapping (用户命名空间映射)**,我们可以将容器内的 `root` 用户映射到宿主机上的一个无特权普通用户。
|
||||
|
||||
#### 如何配置 User Namespace
|
||||
|
||||
要在 Docker 服务端启用这一特性,需要修改 Docker 的配置文件 `/etc/docker/daemon.json`。
|
||||
|
||||
1. **设置映射策略**
|
||||
|
||||
编辑配置文件,添加 `userns-remap` 配置项:
|
||||
|
||||
```json
|
||||
{
|
||||
"userns-remap": "default"
|
||||
}
|
||||
```
|
||||
|
||||
使用 `default` 值时,Docker 会自动在宿主机上创建一个名为 `dockremap` 的用户和用户组。
|
||||
|
||||
2. **验证子 UID 和子 GID 分配**
|
||||
|
||||
Docker 会通过 `/etc/subuid` 和 `/etc/subgid` 文件为 `dockremap` 分配一个高位的 UID 范围:
|
||||
|
||||
```bash
|
||||
$ cat /etc/subuid
|
||||
dockremap:165536:65536
|
||||
```
|
||||
这意味着:容器内的 UID `0`(root 用户)在宿主机上实际被映射成了 UID `165536`。如果是容器内的 UID `1`,对应宿主机的 `165537`,以此类推。
|
||||
|
||||
3. **重启 Docker 守护进程**
|
||||
|
||||
```bash
|
||||
$ sudo systemctl restart docker
|
||||
```
|
||||
|
||||
#### 验证映射效果
|
||||
|
||||
我们可以运行一个简单的容器并执行 `sleep` 命令,同时在宿主机上观察进程的所有者:
|
||||
|
||||
```bash
|
||||
## 在容器内以 root 身份运行
|
||||
$ docker run -d --name userns_test alpine sleep 3600
|
||||
|
||||
## 在宿主机上查看该 sleep 进程
|
||||
$ ps aux | grep sleep
|
||||
165536 12345 0.0 0.0 1568 4 ? Ss 14:20 0:00 sleep 3600
|
||||
```
|
||||
|
||||
你会发现,尽管在容器内该进程是由 root 启动的,但在宿主机上,它的属主是 `165536`(一个完全没有特权的用户)。
|
||||
|
||||
> [!TIP]
|
||||
> 启用 User Namespace 会对容器共享宿主机数据卷(Bind Mount)产生权限影响。你需要确保映射后的高位 UID 对宿主机上的挂载目录具有合适的读写权限。
|
||||
|
||||
### 18.1.4 总结
|
||||
|
||||
内核命名空间从 Linux 2.6.15 版本 (2006 年) 被引入,十余年间,这些机制的可靠性在诸多大型生产系统中被实践验证。通过合理利用命名空间(尤其是 User Namespace),可以极大地收窄攻击面,显著提升容器部署的安全性。
|
||||
|
||||
@@ -1,9 +1,102 @@
|
||||
## 18.2 控制组
|
||||
|
||||
控制组是 Linux 容器机制的另外一个关键组件,负责实现资源的审计和限制。
|
||||
控制组 (Cgroups) 是 Linux 容器机制的另外一个关键组件。如果说命名空间 (Namespace) 决定了容器能**看到**什么,那么控制组就决定了容器能**使用**多少资源。
|
||||
|
||||
它提供了很多有用的特性;以及确保各个容器可以公平地分享主机的内存、CPU、磁盘 IO 等资源;当然,更重要的是,控制组确保了当容器内的资源使用产生压力时不会连累主机系统。
|
||||
在安全领域中,资源的不可用性本身就是一种安全威胁。控制组负责实现资源的审计和限制,这对于抵御资源耗尽型攻击(如拒绝服务攻击 DoS)至关重要。
|
||||
|
||||
尽管控制组不负责隔离容器之间相互访问、处理数据和进程,它在防止拒绝服务 (DDOS) 攻击方面是必不可少的。尤其是在多用户的平台 (比如公有或私有的 PaaS) 上,控制组十分重要。例如,当某些应用程序表现异常的时候,可以保证一致地正常运行和性能。
|
||||
### 18.2.1 为什么资源限制关乎安全?
|
||||
|
||||
控制组机制始于 2006 年,内核从 2.6.24 版本开始被引入。
|
||||
默认情况下,Docker 容器对系统资源的使用是没有限制的:一个容器理论上可以使用宿主机所有的 CPU 计算能力、吃光所有的内存、耗尽所有的系统 PID。
|
||||
|
||||
想象一下以下场景:
|
||||
- 一个恶意用户向你暴露在公网的应用发起海量并发请求。
|
||||
- 应用程序逻辑中存在内存泄漏漏洞。
|
||||
- 黑客在入侵容器后,在里面运行了挖矿木马程序。
|
||||
|
||||
如果没有 Cgroups 的限制,某个容器内的异常行为(或恶意攻击)将会榨干宿主机的资源,导致宿主机上其他健康的容器甚至 Docker 守护进程自身因为 OOM(Out Of Memory)崩溃或 CPU 饥饿而停止响应。
|
||||
|
||||
### 18.2.2 核心资源限制实战
|
||||
|
||||
为了确保多租户平台(如公有或私有的 PaaS 平台)的稳定性,或者在生产环境防止服务级联故障,我们要养成在启动容器时**显式声明资源上限**的习惯。
|
||||
|
||||
#### 1. 内存限制
|
||||
|
||||
限制内存可以防止应用程序因内存泄漏或恶意载荷导致宿主机 OOM。
|
||||
|
||||
**关键参数:**
|
||||
- `-m, --memory=""`:硬限制,容器可使用的最大内存量。
|
||||
- `--memory-swap=""`:限制容器可使用的内存与 Swap 总量。
|
||||
|
||||
**实战示例:**
|
||||
|
||||
限制容器最多只能使用 512MB 内存,并且禁用 Swap(将 memory 和 memory-swap 设置成一样的值即可):
|
||||
|
||||
```bash
|
||||
$ docker run -d \
|
||||
--name web_app \
|
||||
--memory="512m" \
|
||||
--memory-swap="512m" \
|
||||
nginx:alpine
|
||||
```
|
||||
|
||||
如果该容器内的应用尝试分配超过 512MB 的内存,该进程将会被内核的 OOM Killer 杀掉,但绝不会波及到宿主机的其他部分。
|
||||
|
||||
#### 2. CPU 限制
|
||||
|
||||
限制 CPU 可以防止个别计算密集型的容器垄断 CPU 时间片,保证系统的调度公平性。
|
||||
|
||||
**关键参数:**
|
||||
- `--cpus=<value>`:指定容器可以使用的 CPU 核心数量(可以是小数)。
|
||||
- `-c, --cpu-shares=0`:软限制,设置容器使用 CPU 的相对权重(默认是 1024)。
|
||||
|
||||
**实战示例:**
|
||||
|
||||
限制容器最多使用 1.5 个 CPU 核心的算力:
|
||||
|
||||
```bash
|
||||
$ docker run -d \
|
||||
--name worker_app \
|
||||
--cpus="1.5" \
|
||||
busybox \
|
||||
md5sum /dev/urandom
|
||||
```
|
||||
|
||||
即使上面的命令是一个死循环的哈希计算进程,容器也永远无法吃满双核 CPU 系统的全部算力。
|
||||
|
||||
#### 3. 进程数限制
|
||||
|
||||
进程炸弹(Fork Bomb)是一种典型的拒绝服务攻击方式,它通过不断 `fork()` 新进程来耗尽系统的进程表条目,导致系统无法创建任何新任务。
|
||||
|
||||
**关键参数:**
|
||||
- `--pids-limit=<number>`:限制容器内允许创建的最大进程数。
|
||||
|
||||
**实战示例:**
|
||||
|
||||
一个常规的 Web 服务进程数通常在几十到上百之间。我们可以设定一个合理的上限来防范 Fork 炸弹:
|
||||
|
||||
```bash
|
||||
$ docker run -d \
|
||||
--name app_service \
|
||||
--pids-limit=100 \
|
||||
python:alpine python app.py
|
||||
```
|
||||
|
||||
当容器内的进程总数达到 100 时,任何尝试派生新进程的操作都会失败并返回 `Resource temporarily unavailable`,从而挫败相关的攻击行为。
|
||||
|
||||
### 18.2.3 最佳实践建议
|
||||
|
||||
在生产环境中,不仅要在单机使用 Docker 命令时设置这些参数,更应当在集群编排工具中将资源配额制度化。
|
||||
|
||||
例如,在 Kubernetes 中,强烈建议为每个 Pod 设置 `requests` 和 `limits`:
|
||||
|
||||
```yaml
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
cpu: "500m"
|
||||
```
|
||||
|
||||
通过 Cgroups 的资源边界控制,你可以从根本上切断一条导致整个系统雪崩的脆弱链路。这也进一步使得 Docker 以及容器技术成为了现代高可用服务的基础设施首选。
|
||||
|
||||
@@ -1,20 +1,86 @@
|
||||
## 18.3 Docker 服务端的防护
|
||||
## 18.3 服务端防护
|
||||
|
||||
运行一个容器或应用程序的核心是通过 Docker 服务端。Docker 服务的运行目前需要 root 权限,因此其安全性十分关键。
|
||||
Docker 守护进程(`dockerd`)是容器生命周期的核心驱动力。默认情况下,Docker 服务的运行需要极高的系统特权(root 权限),因此其安全性关系到整台宿主机的生死存亡。
|
||||
|
||||
首先,确保只有可信的用户才可以访问 Docker 服务。Docker 允许用户在主机和容器间共享文件夹,同时不需要限制容器的访问权限,这就容易让容器突破资源限制。例如,恶意用户启动容器的时候将主机的根目录 `/` 映射到容器的 `/host` 目录中,那么容器理论上就可以对主机的文件系统进行任意修改了。这听起来很疯狂?但是事实上几乎所有虚拟化系统都允许类似的资源共享,而没法禁止用户共享主机根文件系统到虚拟机系统。
|
||||
如果 Docker 守护进程的访问控制没有做好,恶意攻击者可以通过 Docker API 轻易地启动一个特权容器,并将宿主机的根目录(`/`)挂载到容器中,从而完全接管服务器。
|
||||
|
||||
这将会造成很严重的安全后果。因此,当提供容器创建服务时 (例如通过一个 web 服务器),要更加注意进行参数的安全检查,防止恶意的用户用特定参数来创建一些破坏性的容器。
|
||||
为了加强对服务端的保护,我们需要从访问控制、通信加密和权限最小化三个维度进行加固。
|
||||
|
||||
为了加强对服务端的保护,Docker 的 REST API (客户端用来跟服务端通信) 在 0.5.2 之后使用本地的 Unix 套接字机制替代了原先绑定在 127.0.0.1 上的 TCP 套接字,因为后者容易遭受跨站脚本攻击。现在用户使用 Unix 权限检查来加强套接字的访问安全。
|
||||
### 18.3.1 限制 API 访问
|
||||
|
||||
用户仍可以利用 HTTP 提供 REST API 访问。建议使用安全机制,确保只有可信的网络或 VPN,或证书保护机制 (例如受保护的 stunnel 和 ssl 认证) 下的访问可以进行。此外,还可以使用 [HTTPS 和证书](https://docs.docker.com/engine/security/https/)来加强保护。
|
||||
Docker 客户端(`docker` 命令)通过 REST API 与守护进程进行通信。
|
||||
|
||||
最近改进的 Linux 命名空间机制将可以实现使用非 root 用户来运行全功能的容器。这将从根本上解决了容器和主机之间共享文件系统而引起的安全问题。
|
||||
在早期版本中,Docker 有时会绑定在 `127.0.0.1` 的 TCP 套接字上,但这容易遭遇跨站脚本(跨协议)攻击。现在的发行版默认使用 Unix Domain Socket(`/var/run/docker.sock`)并依赖文件系统的权限控制。
|
||||
|
||||
终极目标是改进 2 个重要的安全特性:
|
||||
#### 原则 1:决不可将无认证的 TCP 端口暴露在公网
|
||||
|
||||
* 将容器的 root 用户[映射到本地主机上的非 root 用户](https://docs.docker.com/engine/security/userns-remap/),减轻容器和主机之间因权限提升而引起的安全问题;
|
||||
* 允许 Docker 服务端在[非 root 权限 (rootless 模式)](https://docs.docker.com/engine/security/rootless/) 下运行,利用安全可靠的子进程来代理执行需要特权权限的操作。这些子进程将只允许在限定范围内进行操作,例如仅仅负责虚拟网络设定或文件系统管理、配置操作等。
|
||||
这是最常见的 Docker 被入侵抓去挖矿的原因!绝不能在没有任何安全控制的情况下强行开启 `-H tcp://0.0.0.0:2375`。
|
||||
|
||||
最后,建议采用专用的服务器来运行 Docker 和相关的管理服务 (例如管理服务比如 ssh 监控和进程监控、管理工具 nrpe、collectd 等)。其它的业务服务都放到容器中去运行。
|
||||
如果业务确实需要远程访问 Docker 守护进程,**必须启用 TLS 认证机制**,让客户端和服务端互相进行证书校验。
|
||||
|
||||
#### 开启 TLS 认证双向加密
|
||||
|
||||
利用安全机制,确保只有经过授权的主机网络,并在强证书保护下进行通信:
|
||||
|
||||
1. 首先使用 `openssl` 或基于本地 CA 工具生成一套客户端与服务器的证书。
|
||||
2. 配置 Docker 守护进程(通常是 `daemon.json` 或 `dockerd` 启动参数),指定证书路径:
|
||||
|
||||
```bash
|
||||
dockerd \
|
||||
--tlsverify \
|
||||
--tlscacert=ca.pem \
|
||||
--tlscert=server-cert.pem \
|
||||
--tlskey=server-key.pem \
|
||||
-H=0.0.0.0:2376
|
||||
```
|
||||
|
||||
3. 客户端想要连接时,也必须出示客户端证书。
|
||||
|
||||
> [!TIP]
|
||||
> 配置 TLS 生成证书的完整步骤可以查阅 [Docker 官方 TLS 文档](https://docs.docker.com/engine/security/protect-access/)。在现代编排系统(如 Kubernetes)中,通常会有自动化方案管理这些凭据。
|
||||
|
||||
### 18.3.2 保护本地 Socket 访问
|
||||
|
||||
哪怕不开启网络端口,本地的 `/var/run/docker.sock` 也需要谨慎对待。
|
||||
|
||||
任何被授予该 Socket 读写权限的用户(通常被加入 `docker` 用户组),等同于拥有了对宿主机的零成本提权途径,即“无需密码的免密 `sudo` 权限”。
|
||||
|
||||
> [!CAUTION]
|
||||
> 永远不要将不可信的普通用户加入到 `docker` 用户组中。同样,在容器编排时尽量避免将宿主机的 `/var/run/docker.sock` 直接映射给普通容器使用,这种模式被称为 Docker-in-Docker (DinD) 或 Docker-out-of-Docker (DooD),存在极高的越权风险。
|
||||
|
||||
### 18.3.3 Rootless 模式 (非特权运行)
|
||||
|
||||
为了从根本上解决“拥有 Docker socket 就是 root”的问题,Docker 在近年推出了 **Rootless 模式**。
|
||||
|
||||
Rootless 模式允许在完全局限于非 `root` 用户的环境中运行 Docker 守护进程(`dockerd`)和容器。该模式利用了现代 Linux 内核的 User Namespace 技术和非特权网络命名空间实现。
|
||||
|
||||
#### 配置运行 Rootless Docker
|
||||
|
||||
要在非 root 环境中运行 Docker,只需要简单几步:
|
||||
|
||||
1. 安装必要的依赖(通常是 `uidmap` 工具包以便系统支持 `newuidmap` 和 `newgidmap`):
|
||||
```bash
|
||||
$ sudo apt-get install uidmap
|
||||
```
|
||||
|
||||
2. 切换到一个没有任何 `sudo` 权限的普通用户(假设用户名为 `testuser`):
|
||||
```bash
|
||||
$ su - testuser
|
||||
```
|
||||
|
||||
3. 运行 Docker 官方提供的 Rootless 安装脚本:
|
||||
```bash
|
||||
$ curl -fsSL https://get.docker.com/rootless | sh
|
||||
```
|
||||
|
||||
4. 配置环境变量指向新创建的私有 socket:
|
||||
```bash
|
||||
$ export DOCKER_HOST=unix:///run/user/1000/docker.sock
|
||||
$ docker version
|
||||
```
|
||||
|
||||
安装并暴露相应的配置后,该用户的环境将能独立启动属于他自己的 Docker Daemon。即使由于某些未知 0-Day 漏洞使得攻击者突破了容器,他们也只会受限于 `testuser` 这个非特权用户所在的有限系统环境内。
|
||||
|
||||
### 18.3.4 结语
|
||||
|
||||
保障 Docker 服务端的安全主要是做减法:关闭不必要的网络监听点,严管 Socket 访问权限。而一旦基础系统条件允许,**毫不犹豫地在生产环境启用 Rootless 模式**将是一项划算的安全加固选择。
|
||||
|
||||
@@ -1,30 +1,63 @@
|
||||
## 18.4 内核能力机制
|
||||
|
||||
Docker 利用 Linux 的能力机制 (Capabilities) 来限制容器的权限,从而提高系统的安全性。
|
||||
传统 Linux 的权限模型非常粗放:进程分为“特权进程”(以 root 用户 `UID 0` 运行)和“非特权进程”(其他 UID 运行)。这带来了一个致命问题——只要一个后台服务需要一个微小的特权(例如绑定低于 1024 的端口),就必须被赋予所有的 root 权限。一旦该服务被攻陷,系统便会全面沦陷。
|
||||
|
||||
[能力机制 (Capability)](https://man7.org/linux/man-pages/man7/capabilities.7.html) 是 Linux 内核一个强大的特性,可以提供细粒度的权限访问控制。
|
||||
Linux 内核自 2.2 版本起就支持能力机制,它将权限划分为更加细粒度的操作能力,既可以作用在进程上,也可以作用在文件上。
|
||||
为了解决这一问题,Linux 引入了 **能力机制(Capabilities)**。它将传统的全能 root 权限划分为几十个细粒度的操作能力。
|
||||
|
||||
例如,一个 Web 服务进程只需要绑定一个低于 1024 的端口的权限,并不需要 root 权限。那么它只需要被授权 `net_bind_service` 能力即可。此外,还有很多其他的类似能力来避免进程获取 root 权限。
|
||||
### 18.4.1 容器内置的 Capability 白名单
|
||||
|
||||
默认情况下,Docker 启动的容器被严格限制只允许使用内核的一部分能力。
|
||||
在默认情况下,即便一个容器是在以 `root` 用户运行,Docker 也只为其内核授予了所有可用能力中的**一小部分“白名单”能力**。
|
||||
|
||||
使用能力机制对加强 Docker 容器的安全有很多好处。通常,在服务器上会运行一堆需要特权权限的进程,包括有 ssh、cron、syslogd、硬件管理工具模块 (例如负载模块)、网络配置工具等等。容器跟这些进程是不同的,因为几乎所有的特权进程都由容器以外的支持系统来进行管理。
|
||||
常见的 Linux Capabilities 包含:
|
||||
- `CAP_CHOWN`: 修改文件所有者。
|
||||
- `CAP_NET_BIND_SERVICE`: 绑定特权端口(即 1024 以下的端口)。
|
||||
- `CAP_NET_ADMIN`: 网络管理的最高权限(例如调整路由配置,设置防火墙规则等)。
|
||||
- `CAP_SYS_ADMIN`: 被誉为“Linux 内核的特权网管”,允许各种高危操作(挂载磁盘、访问敏感设备等)。
|
||||
|
||||
* ssh 访问被主机上 ssh 服务来管理;
|
||||
* cron 通常应该作为用户进程执行,权限交给使用它服务的应用来处理;
|
||||
* 日志系统可由 Docker 或第三方服务管理;
|
||||
* 硬件管理无关紧要,容器中也就无需执行 udevd 以及类似服务;
|
||||
* 网络管理也都在主机上设置,除非特殊需求,容器不需要对网络进行配置。
|
||||
为了在**“最小特权原则”**的指导下加强安全,Docker 默认**移除了**大量可能导致容器大范围破坏宿主机的能力,例如:
|
||||
* 完全禁止了任何通过 `CAP_SYS_ADMIN` 进行的核心挂载或设备操作。
|
||||
* 禁止修改内核模块。
|
||||
* 禁止直接访问硬件套接字。
|
||||
|
||||
从上面的例子可以看出,大部分情况下,容器并不需要 “真正的” root 权限,容器只需要少数的能力即可。为了加强安全,容器可以禁用一些没必要的权限。
|
||||
这种“非完整”的 root 用户能保证大部分应用在拥有其所需权限的同时,把恶意行为对系统的影响降到最低。
|
||||
|
||||
* 完全禁止任何 mount 操作;
|
||||
* 禁止直接访问本地主机的套接字;
|
||||
* 禁止访问一些文件系统的操作,比如创建新的设备、修改文件属性等;
|
||||
* 禁止模块加载。
|
||||
### 18.4.2 实战:添加与剥夺能力
|
||||
|
||||
这样,就算攻击者在容器中取得了 root 权限,也不能获得本地主机的较高权限,能进行的破坏也有限。
|
||||
当启动一个 Docker 容器时,我们可以利用 `--cap-add`(增加特权)和 `--cap-drop`(剥夺特权)两个参数精细地控制进程环境。
|
||||
|
||||
默认情况下,Docker 采用[白名单](https://github.com/moby/moby/blob/master/oci/caps/defaults.go)机制,禁用必需功能之外的其它权限。
|
||||
当然,用户也可以根据自身需求来为 Docker 容器启用额外的权限。
|
||||
#### 实战场景一:构建极限安全的 Web 靶机
|
||||
|
||||
假设你正在提供一个公共的 Web 容器。你不希望里面的任何恶意脚本修改进程权限或者创建设备节点,你可以通过命令先移除**所有**默认能力,然后再按需授权该守护进程一个仅仅能绑端口的能力。
|
||||
|
||||
```bash
|
||||
$ docker run -d \
|
||||
--name max_secure_web \
|
||||
--cap-drop ALL \
|
||||
--cap-add NET_BIND_SERVICE \
|
||||
nginx:alpine
|
||||
```
|
||||
|
||||
这里的 `--cap-drop ALL` 是实现“特权最小化”的最强杀手锏。此时,即便某黑客利用 0-Day 手段拿到了 Web 服务的容器 root Shell,当他试图改变任何不属于他自己的进程配置或者所有权时,系统都会报错拒绝访问。
|
||||
|
||||
#### 实战场景二:需要捕获网络数据包的网络实验
|
||||
|
||||
假设容器内的主程序是一个网络嗅探器(如 tshark 或 tcpdump),这显然不在 Docker 提供的默认白名单之内,因为该程序试图直接操纵底层网卡流量,会触发 Permission Denied。
|
||||
|
||||
此时,我们需要给它适当补发缺失的部分核心管理能力:
|
||||
|
||||
```bash
|
||||
$ docker run -it --rm \
|
||||
--name network_sniffer \
|
||||
--cap-add NET_ADMIN \
|
||||
--cap-add NET_RAW \
|
||||
tshark-image /bin/bash
|
||||
```
|
||||
|
||||
我们只授予了所需的网络管理控制(NET_ADMIN)和侦听底层套接字的权限(NET_RAW),而免去了赋予整个容器终极杀器 `--privileged` 参数。
|
||||
|
||||
> [!WARNING]
|
||||
> 大量开发人员遇到了“权限遭到拒绝”的错误时,往往习惯性图省事添加 `--privileged` 这个核选项。但这将把**宿主机上一切特权和所有访问设备完全投射给容器内的根用户**,其危险性等价于根本没有做隔离!请务必查明进程出错的实际原因,精准施加必要的隔离 `CAP_*` 能力。
|
||||
|
||||
### 18.4.3 总结
|
||||
|
||||
利用能力机制(Capabilities)是进行精细化系统级访问控制的关键一环。遵循“**白名单剥夺一切不必要权利(--cap-drop ALL)**”的极端配置并不过分,这将使得即便程序本身漏洞百出,攻击面也被死死压缩在一个几乎毫无后续伸展潜力的受限维度中。
|
||||
|
||||
@@ -1,13 +1,88 @@
|
||||
## 18.5 其它安全特性
|
||||
|
||||
除了上述机制,Linux 内核还提供了一系列安全增强功能,可以进一步保护容器环境。
|
||||
除了上述的命名空间、控制组以及能力机制,Linux 内核与云原生生态还提供了大量安全增强功能,它们共同筑成了一道防御纵深的“马奇诺防线”。本节主要介绍强制访问控制、系统调用拦截以及自动化的容器漏洞扫描技术。
|
||||
|
||||
除了能力机制之外,还可以利用一些现有的安全机制来增强使用 Docker 的安全性,例如 TOMOYO,AppArmor,Seccomp,SELinux,GRSEC 等。
|
||||
### 18.5.1 系统调用过滤
|
||||
|
||||
Docker 当前默认只启用了能力机制。用户可以采用多种方案来加强 Docker 主机的安全,例如:
|
||||
`Seccomp`(Secure Computing mode)是 Linux 内核的一个安全机制,用于限制进程能够发起的系统调用数量。
|
||||
|
||||
* 在内核中启用 GRSEC 和 PAX,这将增加很多编译和运行时的安全检查;通过地址随机化避免恶意探测等。并且,启用该特性不需要 Docker 进行任何配置。
|
||||
* 使用一些有增强安全特性的容器模板,比如带 AppArmor 的模板和 Redhat 带 SELinux 策略的模板。这些模板提供了额外的安全特性。
|
||||
* 用户可以自定义访问控制机制来定制安全策略。
|
||||
一个普通的 Linux 内核提供了 300 多个系统调用,而一个正常运行的容器化应用(例如 Nginx 服务)通常只会用到几十个调用,这就给攻击者留下了大量的闲置入口点来进行内核层的缓冲区溢出攻击。
|
||||
|
||||
跟其它添加到 Docker 容器的第三方工具一样 (比如网络拓扑和文件系统共享),有很多类似的机制,在不改变 Docker 内核情况下就可以加固现有的容器。
|
||||
Docker 默认启用了 Seccomp 并利用预置的 [默认配置文件](https://github.com/moby/moby/blob/master/profiles/seccomp/default.json) 将可以利用的系统调用缩减到了不足一半(默认禁用了 44 个危险的统调用,比如修改时区或重启系统)。
|
||||
|
||||
如果你对应用的系统调用特征了如指掌,你可以为容器定制专属规则。
|
||||
|
||||
#### 实战:禁用 chmod 系统调用过滤
|
||||
|
||||
首先,编写一个 `no-chmod.json` 的策略文件:
|
||||
```json
|
||||
{
|
||||
"defaultAction": "SCMP_ACT_ALLOW",
|
||||
"syscalls": [
|
||||
{
|
||||
"name": "chmod",
|
||||
"action": "SCMP_ACT_ERRNO"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
在启动时告诉 Docker 载入这套过滤配置:
|
||||
|
||||
```bash
|
||||
$ docker run --rm -it \
|
||||
--security-opt seccomp=no-chmod.json \
|
||||
alpine sh
|
||||
|
||||
/ # chmod 777 /etc/passwd
|
||||
chmod: /etc/passwd: Operation not permitted
|
||||
```
|
||||
应用只要被劫持进行越界尝试,其操作系统层命令便会立刻吃瘪。
|
||||
|
||||
### 18.5.2 强制访问控制 (AppArmor / SELinux)
|
||||
|
||||
传统的 Linux 模型遵循 DAC(自主访问控制),这意味着如果一个文件被赋予了全员读写权限(`777`),普通隔离下任何人便都能修改。但 **MAC(强制访问控制)** 技术,诸如 `AppArmor` (常用于 Ubuntu/Debian) 或 `SELinux` (常用于 CentOS/RHEL),可以制定比“文件所有权”更宏观且优先的策略控制模块。
|
||||
|
||||
在开启了上述机制的机器上:
|
||||
- **AppArmor**: Docker 为所有启动的应用加载了一个默认的 `docker-default` 模板文件,如果你的某些异常写行为(比如往特殊的内核心脏目录写入配置)不在 AppArmor 许可列表之上,即使拥有物理 Root,写入同样失败。
|
||||
- **SELinux**: 所有的 Docker 操作强制附加特殊上下文标识标签。就算把主机的 `/` 绑定给了黑客的某服务,黑客对不属于 Docker 可见的标签的文件进行读写尝试亦会被阻止。
|
||||
|
||||
如果想为某些受信任应用施加特定的外部强化文件策略,可以通过如下方法指派规则表:
|
||||
|
||||
```bash
|
||||
$ docker run --rm -it \
|
||||
--security-opt apparmor=custom-nginx-profile \
|
||||
nginx
|
||||
```
|
||||
|
||||
### 18.5.3 容器镜像漏洞静态扫描
|
||||
|
||||
现代防护的防御已经不仅仅在运行阶段,而向“左”延伸至了构建与分发时期控制。很多安全隐患并不是用户代码中的直接逻辑异常,而是打包环境或者引入库的基础 `APT` 安装层面潜伏了开源界众所周知的历史漏洞。
|
||||
|
||||
#### 使用 Trivy 识别风险
|
||||
|
||||
[Trivy](https://github.com/aquasecurity/trivy) 是由 Aqua Security 发行的一款针对容器技术的快速镜像漏洞扫描利器。在分发应用前通过它的扫描可以规避绝大多数风险。
|
||||
|
||||
```bash
|
||||
## 如果使用本地命令行扫描容器镜像
|
||||
$ trivy image alpine:3.10
|
||||
|
||||
2024-03-01T10:05:07.124Z INFO Number of language-specific files: 1
|
||||
2024-03-01T10:05:07.124Z INFO Detecting vulnerabilities...
|
||||
|
||||
alpine:3.10 (alpine 3.10.3)
|
||||
===========================
|
||||
Total: 2 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 1, CRITICAL: 0)
|
||||
|
||||
+---------+------------------+----------+-------------------+---------------+---------------------------------------+
|
||||
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
|
||||
+---------+------------------+----------+-------------------+---------------+---------------------------------------+
|
||||
| busybox | CVE-2022-28391 | HIGH | 1.30.1-r3 | 1.30.1-r4 | busybox: out-of-bounds read in... |
|
||||
...
|
||||
```
|
||||
|
||||
只要确保所有上传给私有或公共仓库分发服务的产物先被引入至 CI/CD 流水线,如果出现 `HIGH` 及 `CRITICAL` 严重的报错记录强行阻拦部署,这本身便是构建环节极其有力的自动化安全大门保障。除 Trivy 外,最新的 Docker 版本也已内置支持官方扫描利刃 **Docker Scout**。
|
||||
|
||||
### 18.5.4 容器核心层基石结语
|
||||
|
||||
到这里,Docker 为保障宿主和容器界限安全的几个护城河:从**资源剥离限制** (`Cgroups`) 到**进程/网络/身份蒙蔽** (`Namespace`)、到**特权能力回收** (`Capabilities`) 再到**内核强制策略拦截管制** (`Seccomp`/`AppArmor`) 已悉数交代完毕。虽然绝没有“100% 免疫网络穿刺的防线”,只要开发者牢记 **权限最小化原则** ,容器的堡垒就可以做到令攻击者望洋兴叹。
|
||||
|
||||
@@ -391,4 +391,4 @@ $ cosign verify --key cosign.pub $IMAGE
|
||||
|
||||
- [命名空间](../12_implementation/12.2_namespace.md):隔离机制详解
|
||||
- [控制组](../12_implementation/12.3_cgroups.md):资源限制详解
|
||||
- [最佳实践](../appendix/20.1_best_practices.md):Dockerfile 安全配置
|
||||
- [最佳实践](../appendix/best_practices.md):Dockerfile 安全配置
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 18.6 总结
|
||||
## 本章小结
|
||||
|
||||
Docker 的安全性依赖于多层隔离机制的协同工作,同时需要用户遵循最佳实践。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 19.1 Prometheus + Grafana
|
||||
## 19.1 Prometheus
|
||||
|
||||
Prometheus 和 Grafana 是目前最流行的开源监控组合,前者负责数据采集与存储,后者负责数据可视化。
|
||||
|
||||
@@ -172,7 +172,7 @@ $ docker compose up -d
|
||||
4. **时间问题**:宿主机与容器时间偏差过大可能导致“数据看起来断档”,需要检查 NTP/时区配置。
|
||||
5. **目标本身异常**:确认 exporter 容器是否在重启,查看 `docker logs`。
|
||||
|
||||
#### 告警 (Alertmanager) 建议
|
||||
#### Alertmanager 告警建议
|
||||
|
||||
生产环境建议引入 Alertmanager 做告警聚合与路由,并在 Prometheus 中配置 `alerting` 与 `rule_files`。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 19.2 ELK/EFK 堆栈
|
||||
## 19.2 ELK 套件
|
||||
|
||||
ELK (Elasticsearch,Logstash,Kibana) 是目前业界最流行的开源日志解决方案。而在容器领域,由于 Fluentd 更加轻量级且对容器支持更好,EFK (Elasticsearch,Fluentd,Kibana) 组合也变得非常流行。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 20.2 Busybox
|
||||
## 20.1 Busybox
|
||||
|
||||
### 20.2.1 简介
|
||||
### 20.1.1 简介
|
||||
|
||||
下图直观地展示了本节内容:
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
`BusyBox` 可运行于多款 `POSIX` 环境的操作系统中,如 `Linux` (包括 `Android`)、`Hurd`、`FreeBSD` 等。
|
||||
|
||||
### 20.2.2 获取官方镜像
|
||||
### 20.1.2 获取官方镜像
|
||||
|
||||
可以使用 `docker pull` 指令下载 `busybox:latest` 镜像:
|
||||
|
||||
@@ -32,7 +32,7 @@ REPOSITORY TAG IMAGE ID CREATED
|
||||
busybox latest e72ac664f4f0 6 weeks ago 2.433 MB
|
||||
```
|
||||
|
||||
### 20.2.3 运行 busybox
|
||||
### 20.1.3 运行 busybox
|
||||
|
||||
启动一个 `busybox` 容器,并在容器中执行 `grep` 命令。
|
||||
|
||||
@@ -110,7 +110,7 @@ tmpfs on /sys/firmware type tmpfs (ro,relatime)
|
||||
|
||||
`busybox` 镜像虽然小巧,但包括了大量常见的 `Linux` 命令,读者可以用它快速熟悉 `Linux` 命令。
|
||||
|
||||
### 20.2.4 相关资源
|
||||
### 20.1.4 相关资源
|
||||
|
||||
* `Busybox` 官网:https://busybox.net/
|
||||
* `Busybox` 官方仓库:https://git.busybox.net/busybox/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 20.3 Alpine
|
||||
## 20.2 Alpine
|
||||
|
||||
### 20.3.1 简介
|
||||
### 20.2.1 简介
|
||||
|
||||
下图直观地展示了本节内容:
|
||||
|
||||
@@ -26,7 +26,7 @@ ubuntu latest b39b81afc8ca 188.3 MB
|
||||
centos latest 8efe422e6104 210 MB
|
||||
```
|
||||
|
||||
### 20.3.2 获取并使用官方镜像
|
||||
### 20.2.2 获取并使用官方镜像
|
||||
|
||||
由于镜像很小,下载时间往往很短,读者可以直接使用 `docker run` 指令直接运行一个 `Alpine` 容器,并指定运行的 Linux 指令,例如:
|
||||
|
||||
@@ -35,7 +35,7 @@ $ docker run alpine echo '123'
|
||||
123
|
||||
```
|
||||
|
||||
### 20.3.3 迁移至 Alpine 基础镜像
|
||||
### 20.2.3 迁移至 Alpine 基础镜像
|
||||
|
||||
目前,大部分 Docker 官方镜像都已经支持 `Alpine` 作为基础镜像,可以很容易进行迁移。
|
||||
|
||||
@@ -65,7 +65,7 @@ RUN sed -i "s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g" /etc/apk/repositories
|
||||
&& apk add --no-cache <package>
|
||||
```
|
||||
|
||||
### 20.3.4 相关资源
|
||||
### 20.2.4 相关资源
|
||||
|
||||
* `Alpine` 官网:https://www.alpinelinux.org/
|
||||
* `Alpine` 官方仓库:https://github.com/alpinelinux
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# 20.4 Debian Ubuntu
|
||||
## 20.3 Debian Ubuntu
|
||||
|
||||
`Debian` 和 `Ubuntu` 都是目前较为流行的 **Debian 系** 的服务器操作系统,十分适合研发场景。`Docker Hub` 上提供了官方镜像,国内各大容器云服务也基本都提供了相应的支持。
|
||||
|
||||
### 20.4.1 Debian 系统简介
|
||||
### 20.3.1 Debian 系统简介
|
||||
|
||||
下图直观地展示了本节内容:
|
||||
|
||||
@@ -30,7 +30,7 @@ Debian GNU/Linux 8
|
||||
|
||||
`Debian` 镜像很适合作为基础镜像,构建自定义镜像。
|
||||
|
||||
### 20.4.2 Ubuntu 系统简介
|
||||
### 20.3.2 Ubuntu 系统简介
|
||||
|
||||
下图直观地展示了本节内容:
|
||||
|
||||
@@ -135,7 +135,7 @@ root@7d93de07bf76:/# curl 127.0.0.1
|
||||
|
||||
配合使用 `-p` 参数对外映射服务端口,可以允许容器外来访问该服务。
|
||||
|
||||
### 20.4.3 相关资源
|
||||
### 20.3.3 相关资源
|
||||
|
||||
* `Debian` 官网:https://www.debian.org/
|
||||
* `Neuro Debian` 官网:http://neuro.debian.net/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 20.5 CentOS 和 Fedora
|
||||
## 20.4 CentOS Fedora
|
||||
|
||||
### 20.5.1 CentOS 系统简介
|
||||
### 20.4.1 CentOS 系统简介
|
||||
|
||||
`CentOS` 和 `Fedora` 都是基于 `Redhat` 的常见 Linux 分支。`CentOS` 是目前企业级服务器的常用操作系统;`Fedora` 则主要面向个人桌面用户。
|
||||
|
||||
@@ -29,7 +29,7 @@ Status: Downloaded newer image for centos:7
|
||||
CentOS Linux release 7.9.2009 (Core)
|
||||
```
|
||||
|
||||
### 20.5.2 Fedora 系统简介
|
||||
### 20.4.2 Fedora 系统简介
|
||||
|
||||
下图直观地展示了本节内容:
|
||||
|
||||
@@ -54,7 +54,7 @@ Fedora release 39 (Thirty Nine)
|
||||
```
|
||||
|
||||
|
||||
### 20.5.3 相关资源
|
||||
### 20.4.3 相关资源
|
||||
|
||||
* `Fedora` 官网:https://getfedora.org/
|
||||
* `Fedora` 官方仓库:https://github.com/fedora-infra
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# 20.6 本章小结
|
||||
## 本章小结
|
||||
|
||||
本章讲解了典型操作系统镜像的下载和使用。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# 21.1 DevOps 工作流完整示例
|
||||
## 21.1 DevOps 完整工作流
|
||||
|
||||
本章将演示一个基于 Docker、Kubernetes 和 Jenkins/GitLab CI 的完整 DevOps 工作流。
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
```dockerfile
|
||||
## Build stage
|
||||
|
||||
FROM golang:1.18 AS builder
|
||||
FROM golang:1.23 AS builder
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN go build -o main .
|
||||
@@ -48,7 +48,7 @@ stages:
|
||||
|
||||
unit_test:
|
||||
stage: test
|
||||
image: golang:1.18
|
||||
image: golang:1.23
|
||||
script:
|
||||
- go test ./...
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# 21.6 VS Code 中使用 Docker
|
||||
## 21.6 VS Code
|
||||
|
||||
VS Code 的 [Dev Containers](https://code.visualstudio.com/docs/devcontainers/containers)
|
||||
可以把“开发环境”放进容器,同时保留 VS Code 的编辑、补全、调试体验。
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# 第二十一章 实战案例 - Devops
|
||||
# 第二十一章 实战案例 - DevOps
|
||||
|
||||
本章将介绍 Docker 在 DevOps 场景下的实战案例。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# 21.7 本章小结
|
||||
## 本章小结
|
||||
|
||||
本章通过一个完整的 DevOps 工作流示例,串联了从代码提交、自动化测试、镜像构建、
|
||||
到部署发布的一整套实践路径。
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Docker — 从入门到实践
|
||||
# 前言
|
||||
|
||||
[](https://github.com/yeasy/docker_practice) [](https://github.com/yeasy/docker_practice/releases) [](https://docs.docker.com/engine/release-notes/) [][1]
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* **入门基础**:第 1 ~ 6 章为基础内容,帮助深入理解 Docker 的基本概念 (镜像、容器、仓库) 和核心操作。
|
||||
* **进阶应用**:第 7 ~ 11 章涵盖 Dockerfile 指令详解、数据与网络管理、Buildx、Compose 等高级配置和管理操作。
|
||||
* **深入原理**:第 12 ~ 17 章介绍其底层实现技术,深入探讨容器编排体系 (Kubernetes、Etcd),并延伸涉及容器与云计算及其它关键生态项目 (Fedora CoreOS、Podman 等)。
|
||||
* **实战扩展**:第 18 ~ 20 章重点讨论容器安全防护机制、监控与日志聚合系统 (Prometheus、ELK),并展示操作系统、CI/CD 自动化构建等典型实践案例。
|
||||
* **实战扩展**:第 18 ~ 21 章重点讨论容器安全防护机制、监控与日志聚合系统 (Prometheus、ELK),并展示操作系统、CI/CD 自动化构建等典型实践案例。
|
||||
|
||||
## 阅读方式
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user