mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-08-10 08:27:25 +00:00
Add blank lines before headers
This commit is contained in:
@@ -52,6 +52,7 @@ $ docker run -d -p 8080:80 my-hello-world
|
||||
停止并删除容器:
|
||||
|
||||
```bash
|
||||
|
||||
## 查看正在运行的容器 ID
|
||||
|
||||
$ docker ps
|
||||
|
||||
@@ -71,10 +71,12 @@ Docker 镜像包含了应用运行所需的 **一切**:代码、运行时、
|
||||
- ✅ 新人入职,一条命令就能启动开发环境
|
||||
|
||||
```bash
|
||||
|
||||
## 新同事入职第一天
|
||||
|
||||
$ git clone https://github.com/company/project.git
|
||||
$ docker compose up
|
||||
|
||||
## 完整的开发环境就准备好了
|
||||
|
||||
...
|
||||
|
||||
@@ -115,6 +115,7 @@ flowchart TD
|
||||
> ⚠️ **笔者特别提醒**:理解这一点可以帮你避免构建出臃肿的镜像。**关键原理**:每一层的文件变化会被记录,但 **删除操作只是标记,不会真正减小镜像体积**。
|
||||
|
||||
```docker
|
||||
|
||||
## 错误示范 ❌
|
||||
|
||||
FROM ubuntu:24.04
|
||||
@@ -122,10 +123,12 @@ RUN apt-get update
|
||||
RUN apt-get install -y build-essential # 安装编译工具(约 200MB)
|
||||
RUN make && make install # 编译应用
|
||||
RUN apt-get remove build-essential # 试图删除编译工具
|
||||
|
||||
## 结果:镜像仍然包含 200MB 的编译工具!
|
||||
```
|
||||
|
||||
```docker
|
||||
|
||||
## 正确做法 ✅
|
||||
|
||||
FROM ubuntu:24.04
|
||||
@@ -135,6 +138,7 @@ RUN apt-get update && \
|
||||
apt-get remove -y build-essential && \
|
||||
apt-get autoremove -y && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
## 在同一层完成安装、使用、清理
|
||||
|
||||
```
|
||||
@@ -142,6 +146,7 @@ RUN apt-get update && \
|
||||
#### 查看镜像的分层
|
||||
|
||||
```bash
|
||||
|
||||
## 查看镜像的历史(每层的构建记录)
|
||||
|
||||
$ docker history nginx:latest
|
||||
@@ -164,6 +169,7 @@ Docker 镜像有多种标识方式:
|
||||
格式:`[仓库地址/]仓库名[:标签]`
|
||||
|
||||
```bash
|
||||
|
||||
## 完整格式
|
||||
|
||||
registry.example.com/myproject/myapp:v1.2.3
|
||||
|
||||
@@ -113,6 +113,7 @@ flowchart TD
|
||||
> **笔者特别强调**:这是新手最容易踩的坑!**容器存储层与容器生命周期绑定。容器删除,数据就没了!**
|
||||
|
||||
```bash
|
||||
|
||||
## 创建容器,写入数据
|
||||
|
||||
$ docker run -it ubuntu bash
|
||||
@@ -137,6 +138,7 @@ $ docker rm abc123
|
||||
| **[绑定挂载 (Bind Mount) ](../08_data/8.2_bind-mounts.md)** | 挂载宿主机目录 | 开发时共享代码 |
|
||||
|
||||
```bash
|
||||
|
||||
## 使用数据卷(推荐)
|
||||
|
||||
$ docker run -v mydata:/var/lib/mysql mysql
|
||||
@@ -173,6 +175,7 @@ stateDiagram-v2
|
||||
#### 常用生命周期命令
|
||||
|
||||
```bash
|
||||
|
||||
## 创建并启动容器(最常用)
|
||||
|
||||
$ docker run nginx
|
||||
@@ -203,6 +206,7 @@ $ docker rm -f abc123 # 强制删除运行中的容器
|
||||
> **核心概念**:容器的生命周期 = 主进程 (PID 1) 的生命周期
|
||||
|
||||
```bash
|
||||
|
||||
## 主进程运行,容器运行
|
||||
|
||||
## 主进程退出,容器停止
|
||||
@@ -212,6 +216,7 @@ $ docker rm -f abc123 # 强制删除运行中的容器
|
||||
这就是为什么:
|
||||
|
||||
```bash
|
||||
|
||||
## 这个容器会立即退出(bash 没有输入就退出了)
|
||||
|
||||
$ docker run ubuntu
|
||||
|
||||
@@ -62,6 +62,7 @@ flowchart TB
|
||||
示例:
|
||||
|
||||
```bash
|
||||
|
||||
## 完整格式
|
||||
|
||||
registry.example.com/mycompany/myapp:v1.2.3
|
||||
@@ -103,6 +104,7 @@ gcr.io/google-containers/pause:3.6
|
||||
- 付费账户支持私有仓库
|
||||
|
||||
```bash
|
||||
|
||||
## 从 Docker Hub 拉取镜像
|
||||
|
||||
$ docker pull nginx # 官方镜像
|
||||
@@ -152,6 +154,7 @@ $ docker push username/myapp:v1.0
|
||||
Docker 官方提供了 [registry](https://hub.docker.com/_/registry/) 镜像,可以快速搭建私有 Registry:
|
||||
|
||||
```bash
|
||||
|
||||
## 启动一个本地 Registry
|
||||
|
||||
$ docker run -d -p 5000:5000 --name registry registry:2
|
||||
@@ -211,6 +214,7 @@ $ docker pull localhost:5000/myapp:v1.0
|
||||
#### 常用命令
|
||||
|
||||
```bash
|
||||
|
||||
## 登录 Registry
|
||||
|
||||
$ docker login # 登录 Docker Hub
|
||||
@@ -242,6 +246,7 @@ $ docker logout
|
||||
Docker Hub 的[官方镜像](https://hub.docker.com/search?q=&type=image&image_filter=official) (标有 “Official Image” 标识) 经过 Docker 团队审核,相对更安全。示例如下:
|
||||
|
||||
```bash
|
||||
|
||||
## 官方镜像示例
|
||||
|
||||
nginx # ✅ 官方
|
||||
@@ -261,6 +266,7 @@ someuser/myapp # ⚠️ 需要评估
|
||||
> 注意:Cosign 默认会把签名写回镜像所在仓库,请使用你有推送权限的镜像地址。
|
||||
|
||||
```bash
|
||||
|
||||
## 准备一个你有写权限的镜像地址
|
||||
$ export IMAGE=<你的仓库名>/nginx:1.27
|
||||
$ docker pull nginx:1.27
|
||||
@@ -278,6 +284,7 @@ $ cosign verify --key cosign.pub $IMAGE
|
||||
#### 漏洞扫描
|
||||
|
||||
```bash
|
||||
|
||||
## 使用 Docker Scout 扫描镜像漏洞
|
||||
|
||||
$ docker scout cves nginx:latest
|
||||
|
||||
@@ -95,10 +95,12 @@ $ sudo apt install docker-ce docker-ce-cli containerd.io
|
||||
> 若你想安装测试版的 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
|
||||
```
|
||||
|
||||
|
||||
@@ -86,10 +86,12 @@ $ sudo apt-get install docker-ce docker-ce-cli containerd.io
|
||||
> 若你想安装测试版的 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
|
||||
```
|
||||
|
||||
|
||||
@@ -98,10 +98,12 @@ $ sudo dnf -y install docker-ce-18.06.1.ce
|
||||
> 若你想安装测试版的 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
|
||||
```
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ CentOS 8/Stream 默认使用 `nftables`。Docker 在新版本中已提供 `nftab
|
||||
更改 `/etc/firewalld/firewalld.conf`
|
||||
|
||||
```bash
|
||||
|
||||
## FirewallBackend=nftables
|
||||
|
||||
FirewallBackend=iptables
|
||||
@@ -103,10 +104,12 @@ $ firewall-cmd --reload
|
||||
> 若你想安装测试版的 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
|
||||
|
||||
```
|
||||
|
||||
@@ -111,10 +111,12 @@ $ sudo apt-get install docker-ce
|
||||
> 若你想安装测试版的 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
|
||||
|
||||
```
|
||||
|
||||
@@ -148,15 +148,18 @@ sudo yum versionlock delete all
|
||||
##### 挂载 ISO 镜像搭建本地 File 源
|
||||
|
||||
```bash
|
||||
|
||||
## 删除其他网络源
|
||||
|
||||
rm -f /etc/yum.repos.d/*
|
||||
|
||||
## 挂载光盘或者iso镜像
|
||||
|
||||
mount /dev/cdrom /mnt
|
||||
```
|
||||
|
||||
```bash
|
||||
|
||||
## 添加本地源
|
||||
|
||||
cat >/etc/yum.repos.d/local_files.repo<< EOF
|
||||
@@ -170,6 +173,7 @@ EOF
|
||||
```
|
||||
|
||||
```bash
|
||||
|
||||
## 测试刚才的本地源,安装createrepo软件
|
||||
|
||||
yum clean all
|
||||
@@ -179,15 +183,19 @@ yum install createrepo -y
|
||||
##### 根据本地文件搭建 BASE 网络源
|
||||
|
||||
```bash
|
||||
|
||||
## 安装apache 服务器
|
||||
|
||||
yum install httpd -y
|
||||
|
||||
## 挂载光盘
|
||||
|
||||
mount /dev/cdrom /mnt
|
||||
|
||||
## 新建centos目录
|
||||
|
||||
mkdir /var/www/html/base
|
||||
|
||||
## 复制光盘内的文件到刚才新建的目录
|
||||
|
||||
cp -R /mnt/Packages/* /var/www/html/base/
|
||||
@@ -201,6 +209,7 @@ systemctl start httpd
|
||||
在有网络的服务器上下载 Docker-ce 镜像
|
||||
|
||||
```bash
|
||||
|
||||
## 下载清华的镜像源文件
|
||||
|
||||
wget -O /etc/yum.repos.d/docker-ce.repo https://download.docker.com/linux/centos/docker-ce.repo
|
||||
@@ -208,9 +217,11 @@ sudo sed -i 's+download.docker.com+mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc
|
||||
```
|
||||
|
||||
```bash
|
||||
|
||||
## 新建 docker-ce目录
|
||||
|
||||
mkdir /tmp/docker-ce/
|
||||
|
||||
## 把镜像源同步到镜像文件中
|
||||
|
||||
reposync -r docker-ce-stable -p /tmp/docker-ce/
|
||||
@@ -221,6 +232,7 @@ reposync -r docker-ce-stable -p /tmp/docker-ce/
|
||||
把下载的 docker-ce 文件夹复制到离线的服务器
|
||||
|
||||
```bash
|
||||
|
||||
## 把docker-ce 文件夹复制到/var/www/html/docker-ce
|
||||
|
||||
## 重建索引
|
||||
@@ -235,6 +247,7 @@ rm -f /etc/yum.repos.d/*
|
||||
cat >/etc/yum.repos.d/local_files.repo<< EOF
|
||||
[local_base]
|
||||
name=local_base
|
||||
|
||||
## 改成B服务器地址
|
||||
|
||||
baseurl=http://x.x.x.x/base
|
||||
@@ -243,6 +256,7 @@ gpgcheck=0
|
||||
proxy=_none_
|
||||
[docker_ce]
|
||||
name=docker_ce
|
||||
|
||||
## 改成B服务器地址
|
||||
|
||||
baseurl=http://x.x.x.x/docker-ce
|
||||
|
||||
@@ -32,6 +32,7 @@ Registry地址 用户名 仓库名 标签
|
||||
#### 示例
|
||||
|
||||
```bash
|
||||
|
||||
## 完整格式
|
||||
|
||||
$ docker pull docker.io/library/ubuntu:24.04
|
||||
@@ -127,6 +128,7 @@ $ docker pull --platform linux/amd64 nginx
|
||||
拉取镜像后,可以基于它启动容器:
|
||||
|
||||
```bash
|
||||
|
||||
## 拉取镜像
|
||||
|
||||
$ docker pull ubuntu:24.04
|
||||
@@ -170,6 +172,7 @@ root@e7009c6ce357:/# exit
|
||||
|
||||
```bash
|
||||
$ sudo systemctl restart docker # Linux
|
||||
|
||||
## 或在 Docker Desktop 中重启
|
||||
```
|
||||
|
||||
@@ -226,6 +229,7 @@ Error: pull access denied, repository does not exist
|
||||
#### Q:磁盘空间不足
|
||||
|
||||
```bash
|
||||
|
||||
## 清理未使用的镜像
|
||||
|
||||
$ docker image prune
|
||||
|
||||
@@ -82,6 +82,7 @@ Build Cache 0 0 0B 0B
|
||||
#### 按仓库名过滤
|
||||
|
||||
```bash
|
||||
|
||||
## 列出所有 ubuntu 镜像
|
||||
|
||||
$ docker images ubuntu
|
||||
@@ -110,6 +111,7 @@ ubuntu 24.04 329ed837d508 78MB
|
||||
| `reference=pattern` | 按名称模式 | `-f reference='*:latest'` |
|
||||
|
||||
```bash
|
||||
|
||||
## 列出 nginx 之后创建的镜像
|
||||
|
||||
$ docker images -f since=nginx:latest
|
||||
@@ -147,6 +149,7 @@ REPOSITORY TAG IMAGE ID SIZE
|
||||
#### 处理虚悬镜像
|
||||
|
||||
```bash
|
||||
|
||||
## 列出虚悬镜像
|
||||
|
||||
$ docker images -f dangling=true
|
||||
@@ -190,6 +193,7 @@ $ docker images -q
|
||||
常用于配合其他命令:
|
||||
|
||||
```bash
|
||||
|
||||
## 删除所有镜像
|
||||
|
||||
$ docker rmi $(docker images -q)
|
||||
@@ -218,6 +222,7 @@ nginx latest sha256:b4f0e0bdeb5... e43d811ce2f4
|
||||
使用 Go 模板语法自定义输出:
|
||||
|
||||
```bash
|
||||
|
||||
## 只显示 ID 和仓库名
|
||||
|
||||
$ docker images --format "{{.ID}}: {{.Repository}}"
|
||||
@@ -251,6 +256,7 @@ ubuntu 24.04 78MB
|
||||
### 4.2.8 常用命令组合
|
||||
|
||||
```bash
|
||||
|
||||
## 列出所有镜像及其大小,按大小排序(需要系统 sort 命令)
|
||||
|
||||
$ docker images --format "{{.Size}}\t{{.Repository}}:{{.Tag}}" | sort -h
|
||||
|
||||
@@ -53,6 +53,7 @@ Deleted: sha256:501ad78535f0...
|
||||
摘要删除最精确,适用于 CI/CD 场景:
|
||||
|
||||
```bash
|
||||
|
||||
## 查看镜像摘要
|
||||
|
||||
$ docker images --digests
|
||||
@@ -125,6 +126,7 @@ flowchart TD
|
||||
虚悬镜像 (dangling):没有标签的镜像,通常是旧版本被新版本覆盖后产生的
|
||||
|
||||
```bash
|
||||
|
||||
## 查看虚悬镜像
|
||||
|
||||
$ docker images -f dangling=true
|
||||
@@ -141,6 +143,7 @@ $ docker image prune -f
|
||||
#### 删除所有未使用的镜像
|
||||
|
||||
```bash
|
||||
|
||||
## 删除所有没有被容器使用的镜像
|
||||
|
||||
$ docker image prune -a
|
||||
@@ -153,6 +156,7 @@ $ docker image prune -a --filter "until=24h"
|
||||
#### 按条件删除
|
||||
|
||||
```bash
|
||||
|
||||
## 删除所有 redis 镜像
|
||||
|
||||
$ docker rmi $(docker images -q redis)
|
||||
@@ -183,6 +187,7 @@ Error: conflict: unable to remove repository reference "nginx"
|
||||
**解决方案**:
|
||||
|
||||
```bash
|
||||
|
||||
## 方案1:先删除依赖的容器
|
||||
|
||||
$ docker rm abc123
|
||||
@@ -203,6 +208,7 @@ ubuntu latest ca2b0f26964c # 同一个镜像
|
||||
|
||||
$ docker rmi ubuntu:24.04
|
||||
Untagged: ubuntu:24.04
|
||||
|
||||
## 只是移除标签,镜像仍存在(因为还有 ubuntu:latest 指向它)
|
||||
```
|
||||
|
||||
@@ -238,6 +244,7 @@ Error: image has dependent child images
|
||||
#### 开发环境
|
||||
|
||||
```bash
|
||||
|
||||
## 定期清理虚悬镜像
|
||||
|
||||
$ docker image prune -f
|
||||
@@ -250,6 +257,7 @@ $ docker system prune -a
|
||||
#### CI/CD 环境
|
||||
|
||||
```bash
|
||||
|
||||
## 只保留最近使用的镜像
|
||||
|
||||
$ docker image prune -a --filter "until=72h" -f
|
||||
|
||||
@@ -151,6 +151,7 @@ Sending build context to Docker daemon 2.048 kB
|
||||
或许你已经注意到了,`docker build` 还支持从 URL 构建,比如可以直接从 Git repo 中构建:
|
||||
|
||||
```bash
|
||||
|
||||
## $env:DOCKER_BUILDKIT=0
|
||||
|
||||
## export DOCKER_BUILDKIT=0
|
||||
|
||||
@@ -92,6 +92,7 @@ flowchart TD
|
||||
#### 端口映射
|
||||
|
||||
```bash
|
||||
|
||||
## 将容器的 80 端口映射到宿主机的 8080 端口
|
||||
|
||||
$ docker run -d -p 8080:80 nginx
|
||||
@@ -108,6 +109,7 @@ $ docker run -d -p 127.0.0.1:8080:80 nginx
|
||||
#### 数据卷挂载
|
||||
|
||||
```bash
|
||||
|
||||
## 挂载命名卷
|
||||
|
||||
$ docker run -v mydata:/data nginx
|
||||
@@ -124,6 +126,7 @@ $ docker run -v /host/path:/container/path:ro nginx
|
||||
#### 环境变量
|
||||
|
||||
```bash
|
||||
|
||||
## 设置单个环境变量
|
||||
|
||||
$ docker run -e MYSQL_ROOT_PASSWORD=secret mysql
|
||||
@@ -136,6 +139,7 @@ $ docker run --env-file .env myapp
|
||||
#### 资源限制
|
||||
|
||||
```bash
|
||||
|
||||
## 限制内存
|
||||
|
||||
$ docker run -m 512m nginx
|
||||
@@ -150,6 +154,7 @@ $ docker run --cpus=1.5 nginx
|
||||
使用 `docker start` 重新启动已停止的容器:
|
||||
|
||||
```bash
|
||||
|
||||
## 查看所有容器(包括已停止的)
|
||||
|
||||
$ docker ps -a
|
||||
@@ -187,6 +192,7 @@ root@ba267838cc1b:/# ps
|
||||
**原因**:主进程执行完毕或无法保持运行
|
||||
|
||||
```bash
|
||||
|
||||
## 这个容器会立即退出(echo 执行完就结束了)
|
||||
|
||||
$ docker run ubuntu echo "hello"
|
||||
@@ -203,6 +209,7 @@ $ docker run -d nginx # nginx 是持续运行的服务
|
||||
**原因**:未正确映射端口
|
||||
|
||||
```bash
|
||||
|
||||
## 错误:没有 -p 参数,外部无法访问
|
||||
|
||||
$ docker run -d nginx
|
||||
@@ -217,6 +224,7 @@ $ docker run -d -p 80:80 nginx
|
||||
**原因**:未使用数据卷,数据保存在容器存储层
|
||||
|
||||
```bash
|
||||
|
||||
## 使用数据卷持久化
|
||||
|
||||
$ docker run -v mydata:/app/data myapp
|
||||
|
||||
@@ -126,6 +126,7 @@ $ docker container ls -a
|
||||
#### 1. 长期运行的服务使用 -d
|
||||
|
||||
```bash
|
||||
|
||||
## Web 服务器
|
||||
|
||||
$ docker run -d -p 80:80 nginx
|
||||
@@ -144,6 +145,7 @@ $ docker run -d -p 6379:6379 redis
|
||||
当容器启动有问题时,**去掉 `-d` 参数** 可以直接看到输出和错误:
|
||||
|
||||
```bash
|
||||
|
||||
## 有问题的容器,先前台运行看看发生了什么
|
||||
|
||||
$ docker run myimage:latest
|
||||
@@ -156,6 +158,7 @@ $ docker run myimage:latest
|
||||
```bash
|
||||
$ docker run --rm ubuntu:24.04 echo "Hello, World!"
|
||||
Hello, World!
|
||||
|
||||
## 容器执行完后自动删除
|
||||
|
||||
...
|
||||
@@ -164,6 +167,7 @@ Hello, World!
|
||||
#### 4. 配合日志查看
|
||||
|
||||
```bash
|
||||
|
||||
## 后台启动
|
||||
|
||||
$ docker run -d --name myapp myimage:latest
|
||||
|
||||
@@ -34,6 +34,7 @@ flowchart TD
|
||||
#### 自定义超时时间
|
||||
|
||||
```bash
|
||||
|
||||
## 等待 30 秒后强制终止
|
||||
|
||||
$ docker stop -t 30 mycontainer
|
||||
@@ -46,6 +47,7 @@ $ docker stop -t 0 mycontainer
|
||||
#### 停止多个容器
|
||||
|
||||
```bash
|
||||
|
||||
## 停止多个指定容器
|
||||
|
||||
$ docker stop container1 container2 container3
|
||||
@@ -75,6 +77,7 @@ $ docker kill 容器名或ID
|
||||
#### 发送自定义信号
|
||||
|
||||
```bash
|
||||
|
||||
## 发送 SIGHUP(让进程重新加载配置)
|
||||
|
||||
$ docker kill -s HUP mycontainer
|
||||
@@ -91,6 +94,7 @@ $ docker kill -s TERM mycontainer
|
||||
容器的生命周期与主进程绑定。主进程退出时,容器自动停止:
|
||||
|
||||
```bash
|
||||
|
||||
## 主进程是交互式 bash
|
||||
|
||||
$ docker run -it ubuntu bash
|
||||
@@ -139,6 +143,7 @@ $ docker start -ai 容器名
|
||||
#### 重启运行中的容器
|
||||
|
||||
```bash
|
||||
|
||||
## 先停止再启动
|
||||
|
||||
$ docker restart 容器名
|
||||
@@ -209,10 +214,12 @@ $ docker stop $(docker ps -q) && docker container prune -f
|
||||
确保容器主进程正确处理信号:
|
||||
|
||||
```dockerfile
|
||||
|
||||
## Dockerfile 示例
|
||||
|
||||
FROM node:22
|
||||
...
|
||||
|
||||
## 使用 exec 形式确保信号能传递给 node 进程
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
@@ -221,6 +228,7 @@ CMD ["node", "server.js"]
|
||||
#### Q:容器无法停止
|
||||
|
||||
```bash
|
||||
|
||||
## 强制终止
|
||||
|
||||
$ docker kill 容器名
|
||||
|
||||
@@ -27,6 +27,7 @@ Docker 提供两种进入容器的命令:
|
||||
#### docker exec 基本用法
|
||||
|
||||
```bash
|
||||
|
||||
## 进入容器并启动交互式 shell
|
||||
|
||||
$ docker exec -it 容器名 /bin/bash
|
||||
@@ -50,6 +51,7 @@ $ docker exec -it 容器名 /bin/sh
|
||||
#### docker exec 示例
|
||||
|
||||
```bash
|
||||
|
||||
## 启动一个后台容器
|
||||
|
||||
$ docker run -dit --name myubuntu ubuntu
|
||||
@@ -74,6 +76,7 @@ CONTAINER ID IMAGE STATUS NAMES
|
||||
不进入交互模式,直接执行命令:
|
||||
|
||||
```bash
|
||||
|
||||
## 查看容器内进程
|
||||
|
||||
$ docker exec myubuntu ps aux
|
||||
@@ -90,6 +93,7 @@ $ docker exec -u root myubuntu apt update
|
||||
#### 只用 -i 不用 -t 的区别
|
||||
|
||||
```bash
|
||||
|
||||
## 只用 -i:可以执行命令,但没有提示符
|
||||
|
||||
$ docker exec -i myubuntu bash
|
||||
@@ -135,6 +139,7 @@ flowchart LR
|
||||
#### docker attach 示例
|
||||
|
||||
```bash
|
||||
|
||||
## 启动容器
|
||||
|
||||
$ docker run -dit --name myubuntu ubuntu
|
||||
@@ -168,6 +173,7 @@ CONTAINER ID IMAGE STATUS NAMES
|
||||
```bash
|
||||
$ docker attach myubuntu
|
||||
root@243c32535da7:/#
|
||||
|
||||
## 按 Ctrl+P 然后 Ctrl+Q
|
||||
|
||||
read escape sequence
|
||||
@@ -221,6 +227,7 @@ flowchart LR
|
||||
#### 1. 首选 docker exec
|
||||
|
||||
```bash
|
||||
|
||||
## 进入容器调试
|
||||
|
||||
$ docker exec -it myapp bash
|
||||
@@ -247,6 +254,7 @@ $ docker exec myapp python manage.py migrate
|
||||
某些精简镜像 (如基于 `scratch` 或 `distroless`) 没有 shell:
|
||||
|
||||
```bash
|
||||
|
||||
## 这会失败
|
||||
|
||||
$ docker exec -it myapp bash
|
||||
|
||||
@@ -32,6 +32,7 @@ mycontainer
|
||||
#### 强制删除运行中的容器
|
||||
|
||||
```bash
|
||||
|
||||
## 不加 -f 会报错
|
||||
|
||||
$ docker rm running_container
|
||||
@@ -48,6 +49,7 @@ running_container
|
||||
#### 删除容器及其数据卷
|
||||
|
||||
```bash
|
||||
|
||||
## 删除容器时同时删除其匿名卷
|
||||
|
||||
$ docker rm -v mycontainer
|
||||
@@ -62,6 +64,7 @@ $ docker rm -v mycontainer
|
||||
#### 删除所有已停止的容器
|
||||
|
||||
```bash
|
||||
|
||||
## 方式一:使用 prune 命令(推荐)
|
||||
|
||||
$ docker container prune
|
||||
@@ -81,6 +84,7 @@ $ docker container prune -f
|
||||
#### 删除所有容器:包括运行中的
|
||||
|
||||
```bash
|
||||
|
||||
## 先停止所有容器,再删除
|
||||
|
||||
$ docker stop $(docker ps -q)
|
||||
@@ -94,6 +98,7 @@ $ docker rm -f $(docker ps -aq)
|
||||
#### 按条件删除
|
||||
|
||||
```bash
|
||||
|
||||
## 删除所有已退出的容器
|
||||
|
||||
$ docker rm $(docker ps -aq -f status=exited)
|
||||
@@ -125,6 +130,7 @@ $ docker container prune --filter "until=24h"
|
||||
#### 示例
|
||||
|
||||
```bash
|
||||
|
||||
## 删除所有基于 nginx 镜像的容器
|
||||
|
||||
$ docker rm $(docker ps -aq -f ancestor=nginx)
|
||||
@@ -141,6 +147,7 @@ $ docker rm $(docker ps -aq -f status=created)
|
||||
> 有容器依赖的镜像无法删除。
|
||||
|
||||
```bash
|
||||
|
||||
## 尝试删除有容器依赖的镜像
|
||||
|
||||
$ docker image rm nginx
|
||||
@@ -159,6 +166,7 @@ $ docker image rm nginx
|
||||
#### 开发环境
|
||||
|
||||
```bash
|
||||
|
||||
## 定期清理已停止的容器
|
||||
|
||||
$ docker container prune -f
|
||||
@@ -171,9 +179,11 @@ $ docker system prune -f
|
||||
#### 生产环境
|
||||
|
||||
```bash
|
||||
|
||||
## 使用 --rm 参数运行临时容器
|
||||
|
||||
$ docker run --rm ubuntu echo "Hello"
|
||||
|
||||
## 容器退出后自动删除
|
||||
|
||||
## 定期清理(设置保留时间)
|
||||
@@ -185,6 +195,7 @@ $ docker container prune --filter "until=168h" # 保留 7 天内的
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
## cleanup.sh - Docker 资源清理脚本
|
||||
|
||||
echo "清理已停止的容器..."
|
||||
@@ -218,6 +229,7 @@ Error: container is running
|
||||
```bash
|
||||
$ docker stop mycontainer
|
||||
$ docker rm mycontainer
|
||||
|
||||
## 或
|
||||
|
||||
$ docker rm -f mycontainer
|
||||
@@ -234,6 +246,7 @@ $ docker rm -f mycontainer
|
||||
解决:
|
||||
|
||||
```bash
|
||||
|
||||
## 查看空间占用
|
||||
|
||||
$ docker system df
|
||||
|
||||
@@ -45,6 +45,7 @@ $ docker pull nginx:alpine
|
||||
|
||||
```bash
|
||||
$ docker login
|
||||
|
||||
## 默认情况下,不带其它参数进行 docker login 会自动走 Device Code Web Flow (浏览器认证)
|
||||
## 若在非交互 CI 环境中,推荐结合 --username 与 --password-stdin 参数使用
|
||||
|
||||
@@ -54,6 +55,7 @@ $ docker login
|
||||
打标签并推送:
|
||||
|
||||
```bash
|
||||
|
||||
## 1. 标记镜像
|
||||
|
||||
$ docker tag myapp:v1 username/myapp:v1
|
||||
|
||||
@@ -27,6 +27,7 @@ COPY . . # 复制到 /app/
|
||||
#### 常见错误
|
||||
|
||||
```docker
|
||||
|
||||
## ❌ 错误:cd 在下一个 RUN 中无效
|
||||
|
||||
RUN cd /app
|
||||
@@ -51,6 +52,7 @@ RUN echo "hello" > world.txt
|
||||
#### 正确做法
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 正确:使用 WORKDIR
|
||||
|
||||
WORKDIR /app
|
||||
@@ -87,6 +89,7 @@ RUN pwd # 输出 /app
|
||||
### 7.10.6 多阶段构建中的 WORKDIR
|
||||
|
||||
```docker
|
||||
|
||||
## 构建阶段
|
||||
|
||||
FROM node:20 AS builder
|
||||
@@ -122,6 +125,7 @@ CMD ["node", "server.js"]
|
||||
#### 2. 使用绝对路径
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 推荐:绝对路径,意图明确
|
||||
|
||||
WORKDIR /app
|
||||
@@ -134,6 +138,7 @@ WORKDIR app
|
||||
#### 3. 不要用 RUN cd
|
||||
|
||||
```docker
|
||||
|
||||
## ❌ 避免
|
||||
|
||||
RUN cd /app && echo "hello" > world.txt
|
||||
@@ -148,9 +153,11 @@ RUN echo "hello" > world.txt
|
||||
|
||||
```docker
|
||||
WORKDIR /app
|
||||
|
||||
## ... 应用相关操作 ...
|
||||
|
||||
WORKDIR /data
|
||||
|
||||
## ... 数据相关操作 ...
|
||||
|
||||
...
|
||||
|
||||
@@ -61,6 +61,7 @@ CMD ["node", "server.js"]
|
||||
#### 使用 UID/GID
|
||||
|
||||
```docker
|
||||
|
||||
## 也可以使用数字
|
||||
|
||||
USER 1001:1001
|
||||
@@ -73,9 +74,11 @@ USER 1001:1001
|
||||
`USER` 指令只能切换到 **已存在** 的用户:
|
||||
|
||||
```docker
|
||||
|
||||
## ❌ 错误:用户不存在
|
||||
|
||||
USER nonexistent
|
||||
|
||||
## Error: unable to find user nonexistent
|
||||
|
||||
## ✅ 正确:先创建用户
|
||||
@@ -163,6 +166,7 @@ exec gosu redis "$@"
|
||||
使用 `-u` 或 `--user` 参数:
|
||||
|
||||
```bash
|
||||
|
||||
## 以指定用户运行
|
||||
|
||||
$ docker run -u 1001:1001 myimage
|
||||
@@ -208,6 +212,7 @@ CMD ["node", "server.js"]
|
||||
#### 1. 始终使用非 root 用户
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 推荐
|
||||
|
||||
RUN adduser -D appuser
|
||||
@@ -224,6 +229,7 @@ CMD ["myapp"] # 以 root 运行
|
||||
便于在宿主机和容器间共享文件:
|
||||
|
||||
```docker
|
||||
|
||||
## 使用常见的非 root UID
|
||||
|
||||
RUN addgroup -g 1000 -S appgroup && \
|
||||
@@ -234,6 +240,7 @@ USER 1000:1000
|
||||
#### 3. 多阶段构建中的 USER
|
||||
|
||||
```docker
|
||||
|
||||
## 构建阶段可以用 root
|
||||
|
||||
FROM node:20 AS builder
|
||||
|
||||
@@ -78,6 +78,7 @@ HEALTHCHECK NONE
|
||||
使用 `curl` 或 `wget`:
|
||||
|
||||
```docker
|
||||
|
||||
## 使用 curl
|
||||
|
||||
HEALTHCHECK CMD curl -f http://localhost/ || exit 1
|
||||
@@ -90,6 +91,7 @@ HEALTHCHECK CMD wget -q --spider http://localhost/ || exit 1
|
||||
#### 数据库
|
||||
|
||||
```docker
|
||||
|
||||
## MySQL
|
||||
|
||||
HEALTHCHECK CMD mysqladmin ping -h localhost || exit 1
|
||||
@@ -143,6 +145,7 @@ services:
|
||||
### 7.12.7 查看健康状态
|
||||
|
||||
```bash
|
||||
|
||||
## 查看容器状态(包含健康信息)
|
||||
|
||||
$ docker ps
|
||||
@@ -184,6 +187,7 @@ $ docker inspect --format '{{json .State.Health}}' mycontainer | jq
|
||||
应用启动可能需要时间 (如 Java 应用)。设置 `--start-period` 可以防止在启动阶段因检查失败而误判。
|
||||
|
||||
```docker
|
||||
|
||||
## 给应用 1 分钟启动时间
|
||||
|
||||
HEALTHCHECK --start-period=60s CMD curl -f http://localhost/ || exit 1
|
||||
|
||||
@@ -47,6 +47,7 @@ CMD ["npm", "start"]
|
||||
|
||||
```docker
|
||||
FROM my-node-base
|
||||
|
||||
## 只需要一行!
|
||||
|
||||
## 构建时会自动执行 COPY 和 RUN
|
||||
@@ -74,6 +75,7 @@ FROM 基础镜像 ──build──> 读取基础镜像触发器 ──> 执行
|
||||
#### 1. 自动处理依赖安装
|
||||
|
||||
```docker
|
||||
|
||||
## Python 基础镜像
|
||||
|
||||
ONBUILD COPY requirements.txt ./
|
||||
@@ -83,6 +85,7 @@ ONBUILD RUN pip install -r requirements.txt
|
||||
#### 2. 自动编译代码
|
||||
|
||||
```docker
|
||||
|
||||
## Go 基础镜像
|
||||
|
||||
ONBUILD COPY . .
|
||||
@@ -92,6 +95,7 @@ ONBUILD RUN go build -o app main.go
|
||||
#### 3. 处理静态资源
|
||||
|
||||
```docker
|
||||
|
||||
## Nginx 静态网站基础镜像
|
||||
|
||||
ONBUILD COPY dist/ /usr/share/nginx/html/
|
||||
|
||||
@@ -73,6 +73,7 @@ LABEL org.opencontainers.image.authors="yeasy" \
|
||||
旧版本的 Dockerfile 中常看到 `MAINTAINER` 指令:
|
||||
|
||||
```docker
|
||||
|
||||
## ❌ 已弃用
|
||||
|
||||
MAINTAINER user@example.com
|
||||
@@ -81,9 +82,11 @@ MAINTAINER user@example.com
|
||||
现在推荐使用 `LABEL`:
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 推荐
|
||||
|
||||
LABEL maintainer="user@example.com"
|
||||
|
||||
## 或
|
||||
|
||||
LABEL org.opencontainers.image.authors="user@example.com"
|
||||
@@ -132,6 +135,7 @@ $ docker inspect nginx --format '{{json .Config.Labels}}' | jq
|
||||
可以使用标签过滤镜像:
|
||||
|
||||
```bash
|
||||
|
||||
## 列出作者是 yeasy 的所有镜像
|
||||
|
||||
$ docker images --filter "label=org.opencontainers.image.authors=yeasy"
|
||||
|
||||
@@ -38,6 +38,7 @@ RUN echo {a..z}
|
||||
默认情况下,管道命令 `cmd1 | cmd2` 只要 `cmd2` 成功,整个指令就视为成功。这可能掩盖构建错误。
|
||||
|
||||
```docker
|
||||
|
||||
## ❌ 这里的 wget 失败了,但构建继续(因为 tar 成功了)
|
||||
|
||||
RUN wget -O - https://invalid-url | tar xz
|
||||
@@ -46,6 +47,7 @@ RUN wget -O - https://invalid-url | tar xz
|
||||
使用 `SHELL` 启用 `pipefail`:
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 启用 pipefail
|
||||
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
@@ -90,11 +92,13 @@ FROM ubuntu:24.04
|
||||
RUN echo "Using sh"
|
||||
|
||||
SHELL ["/bin/bash", "-c"]
|
||||
|
||||
## 使用 bash
|
||||
|
||||
RUN echo "Using bash"
|
||||
|
||||
SHELL ["/bin/sh", "-c"]
|
||||
|
||||
## 回到 sh
|
||||
|
||||
RUN echo "Using sh again"
|
||||
|
||||
@@ -82,6 +82,7 @@ RUN apt-get update && \
|
||||
**❌ 隐蔽的错误**:
|
||||
|
||||
```docker
|
||||
|
||||
## 如果下载失败,gzip 可能会报错,但如果不影响后续,构建可能继续
|
||||
|
||||
RUN wget http://error-url | gzip -d > file
|
||||
@@ -135,6 +136,7 @@ RUN echo $MY_VAR
|
||||
BuildKit 支持在 `RUN` 指令中使用 `--mount` 挂载缓存,加速构建。
|
||||
|
||||
```docker
|
||||
|
||||
## 缓存 apt 包
|
||||
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
@@ -143,6 +145,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
```
|
||||
|
||||
```docker
|
||||
|
||||
## 缓存 Go 模块
|
||||
|
||||
RUN --mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
@@ -16,6 +16,7 @@ COPY [选项] ["<源路径1>", "<源路径2>", ... "<目标路径>"]
|
||||
#### 复制单个文件
|
||||
|
||||
```docker
|
||||
|
||||
## 复制文件到指定目录
|
||||
|
||||
COPY package.json /app/
|
||||
@@ -28,6 +29,7 @@ COPY config.json /app/settings.json
|
||||
#### 复制多个文件
|
||||
|
||||
```docker
|
||||
|
||||
## 复制多个指定文件
|
||||
|
||||
COPY package.json package-lock.json /app/
|
||||
@@ -41,6 +43,7 @@ COPY src/*.js /app/src/
|
||||
#### 复制目录
|
||||
|
||||
```docker
|
||||
|
||||
## 复制整个目录的内容(不是目录本身)
|
||||
|
||||
COPY src/ /app/src/
|
||||
@@ -97,6 +100,7 @@ COPY src/ ./src/ # 复制到 /app/src/
|
||||
如果目标目录不存在,Docker 会自动创建:
|
||||
|
||||
```docker
|
||||
|
||||
## /app/config/ 不存在也会自动创建
|
||||
|
||||
COPY settings.json /app/config/
|
||||
@@ -109,6 +113,7 @@ COPY settings.json /app/config/
|
||||
使用 `--chown` 选项设置文件的用户和组:
|
||||
|
||||
```docker
|
||||
|
||||
## 使用用户名和组名
|
||||
|
||||
COPY --chown=node:node package.json /app/
|
||||
@@ -136,6 +141,7 @@ COPY 会保留源文件的元数据:
|
||||
这对于脚本文件特别重要:
|
||||
|
||||
```docker
|
||||
|
||||
## start.sh 的可执行权限会被保留
|
||||
|
||||
COPY start.sh /app/
|
||||
@@ -153,6 +159,7 @@ COPY start.sh /app/
|
||||
| 推荐程度 | ✅ **推荐** | ⚠️ 特殊场景使用 |
|
||||
|
||||
```docker
|
||||
|
||||
## 推荐:使用 COPY
|
||||
|
||||
COPY app.tar.gz /app/
|
||||
@@ -172,6 +179,7 @@ ADD app.tar.gz /app/
|
||||
#### 从其他构建阶段复制
|
||||
|
||||
```docker
|
||||
|
||||
## 构建阶段
|
||||
|
||||
FROM node:20 AS builder
|
||||
@@ -190,6 +198,7 @@ COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
#### 使用 --link 优化缓存
|
||||
|
||||
```docker
|
||||
|
||||
## 使用 --link 后,文件以独立层添加,不依赖前序指令
|
||||
|
||||
COPY --link --from=builder /app/dist /usr/share/nginx/html
|
||||
@@ -208,6 +217,7 @@ COPY --link --from=builder /app/dist /usr/share/nginx/html
|
||||
使用 `.dockerignore` 排除不需要复制的文件:
|
||||
|
||||
```text
|
||||
|
||||
## .dockerignore
|
||||
|
||||
node_modules
|
||||
@@ -231,6 +241,7 @@ Dockerfile
|
||||
#### 1. 利用缓存,先复制依赖文件
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 好:先复制依赖定义,再安装,最后复制代码
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
@@ -246,9 +257,11 @@ RUN npm install
|
||||
#### 2. 使用 .dockerignore
|
||||
|
||||
```docker
|
||||
|
||||
## 确保 node_modules 不被复制
|
||||
|
||||
COPY . .
|
||||
|
||||
## .dockerignore 中应包含 node_modules
|
||||
|
||||
...
|
||||
@@ -257,6 +270,7 @@ COPY . .
|
||||
#### 3. 明确复制路径
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 好:明确的路径
|
||||
|
||||
COPY src/ /app/src/
|
||||
|
||||
@@ -33,6 +33,7 @@ ADD [选项] ["<源路径>", ... "<目标路径>"]
|
||||
#### 基本用法:自动解压本地 tar
|
||||
|
||||
```docker
|
||||
|
||||
## 自动解压 tar.gz 到目标目录
|
||||
|
||||
ADD app.tar.gz /app/
|
||||
@@ -76,6 +77,7 @@ app.tar.gz 包含: /app/ 目录结果:
|
||||
#### 基本用法
|
||||
|
||||
```docker
|
||||
|
||||
## 从 URL 下载文件
|
||||
|
||||
ADD https://example.com/app.zip /app/app.zip
|
||||
@@ -93,6 +95,7 @@ ADD https://example.com/app.zip /app/app.zip
|
||||
#### 推荐替代方案
|
||||
|
||||
```docker
|
||||
|
||||
## ❌ 不推荐:使用 ADD 下载
|
||||
|
||||
ADD https://example.com/app.tar.gz /tmp/
|
||||
@@ -125,6 +128,7 @@ ADD --chown=1000:1000 files/ /app/
|
||||
#### ✅ 适合使用 ADD
|
||||
|
||||
```docker
|
||||
|
||||
## 解压本地 tar 文件
|
||||
|
||||
FROM scratch
|
||||
@@ -138,6 +142,7 @@ ADD dist.tar.gz /app/
|
||||
#### ❌ 不适合使用 ADD
|
||||
|
||||
```docker
|
||||
|
||||
## 复制普通文件(用 COPY)
|
||||
|
||||
ADD package.json /app/ # ❌
|
||||
@@ -161,6 +166,7 @@ COPY archive.tar.gz /archives/ # ✅ 保持原样
|
||||
ADD 可能导致构建缓存失效:
|
||||
|
||||
```docker
|
||||
|
||||
## 如果 app.tar.gz 内容变化,此层及后续层都需重建
|
||||
|
||||
ADD app.tar.gz /app/
|
||||
@@ -170,6 +176,7 @@ RUN npm install
|
||||
**优化建议**:
|
||||
|
||||
```docker
|
||||
|
||||
## 先复制依赖文件
|
||||
|
||||
COPY package*.json /app/
|
||||
@@ -187,6 +194,7 @@ ADD app.tar.gz /app/
|
||||
#### 1. 默认使用 COPY
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 大多数场景使用 COPY
|
||||
|
||||
COPY . /app/
|
||||
@@ -195,6 +203,7 @@ COPY . /app/
|
||||
#### 2. 仅在需要解压时使用 ADD
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 自动解压场景
|
||||
|
||||
ADD app.tar.gz /app/
|
||||
@@ -203,6 +212,7 @@ ADD app.tar.gz /app/
|
||||
#### 3. 不要用 ADD 下载文件
|
||||
|
||||
```docker
|
||||
|
||||
## ❌ 避免
|
||||
|
||||
ADD https://example.com/file.tar.gz /tmp/
|
||||
@@ -215,6 +225,7 @@ RUN curl -fsSL https://example.com/file.tar.gz | tar -xz -C /app
|
||||
#### 4. 解压后清理
|
||||
|
||||
```docker
|
||||
|
||||
## 如果需要控制解压过程
|
||||
|
||||
COPY app.tar.gz /tmp/
|
||||
|
||||
@@ -42,6 +42,7 @@ CMD nginx -g "daemon off;"
|
||||
**实际执行**:会被包装为 `sh -c`
|
||||
|
||||
```docker
|
||||
|
||||
## 你写的
|
||||
|
||||
CMD echo $HOME
|
||||
@@ -67,9 +68,11 @@ CMD ["sh", "-c", "echo $HOME"]
|
||||
#### 信号传递问题示例
|
||||
|
||||
```docker
|
||||
|
||||
## ❌ shell 格式:docker stop 会超时
|
||||
|
||||
CMD node server.js
|
||||
|
||||
## 实际是 sh -c "node server.js"
|
||||
|
||||
## SIGTERM 发给 sh,不会传递给 node
|
||||
@@ -77,6 +80,7 @@ CMD node server.js
|
||||
## ✅ exec 格式:docker stop 正常工作
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
|
||||
## SIGTERM 直接发给 node
|
||||
|
||||
...
|
||||
@@ -89,6 +93,7 @@ CMD ["node", "server.js"]
|
||||
`docker run` 后的命令会覆盖 Dockerfile 中的 CMD:
|
||||
|
||||
```bash
|
||||
|
||||
## ubuntu 默认 CMD 是 /bin/bash
|
||||
|
||||
$ docker run -it ubuntu # 进入 bash
|
||||
@@ -111,6 +116,7 @@ CMD ["/bin/bash"] + cat /etc/os-release
|
||||
#### 错误示例
|
||||
|
||||
```docker
|
||||
|
||||
## ❌ 容器启动后立即退出
|
||||
|
||||
CMD service nginx start
|
||||
@@ -135,6 +141,7 @@ CMD service nginx start
|
||||
#### 正确做法
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 让 nginx 在前台运行
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -152,6 +159,7 @@ CMD ["nginx", "-g", "daemon off;"]
|
||||
#### 单独使用 CMD
|
||||
|
||||
```docker
|
||||
|
||||
## Dockerfile
|
||||
|
||||
CMD ["curl", "-s", "http://example.com"]
|
||||
@@ -165,6 +173,7 @@ $ docker run myimage curl -v ... # 完全覆盖
|
||||
#### 搭配 ENTRYPOINT
|
||||
|
||||
```docker
|
||||
|
||||
## Dockerfile
|
||||
|
||||
ENTRYPOINT ["curl", "-s"]
|
||||
@@ -185,6 +194,7 @@ $ docker run myimage http://other.com # curl -s http://other.com(参数覆盖
|
||||
#### 1. 优先使用 exec 格式
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 推荐
|
||||
|
||||
CMD ["python", "app.py"]
|
||||
@@ -197,6 +207,7 @@ CMD ["sh", "-c", "echo $PATH && python app.py"]
|
||||
#### 2. 确保应用在前台运行
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 前台运行
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -212,6 +223,7 @@ CMD systemctl start nginx
|
||||
#### 3. 使用双引号
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 正确:双引号
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
@@ -224,6 +236,7 @@ CMD ['node', 'server.js']
|
||||
#### 4. 配合 ENTRYPOINT 使用
|
||||
|
||||
```docker
|
||||
|
||||
## 用于可配置参数的场景
|
||||
|
||||
ENTRYPOINT ["python", "app.py"]
|
||||
@@ -252,6 +265,7 @@ CMD ["echo", "second"] # 只有这个生效
|
||||
#### Q:如何在 CMD 中使用环境变量?
|
||||
|
||||
```docker
|
||||
|
||||
## 方法1:使用 shell 格式
|
||||
|
||||
CMD echo "Port is $PORT"
|
||||
@@ -266,6 +280,7 @@ CMD ["sh", "-c", "echo Port is $PORT"]
|
||||
可能是使用了 shell 格式,信号被 sh 吃掉了:
|
||||
|
||||
```docker
|
||||
|
||||
## ❌ 信号无法传递
|
||||
|
||||
CMD python app.py
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
| **shell 格式** | `ENTRYPOINT 命令 参数` | ⚠️ 不推荐 |
|
||||
|
||||
```docker
|
||||
|
||||
## exec 格式(推荐)
|
||||
|
||||
ENTRYPOINT ["nginx", "-g", "daemon off;"]
|
||||
@@ -41,6 +42,7 @@ ENTRYPOINT nginx -g "daemon off;"
|
||||
#### 行为对比
|
||||
|
||||
```docker
|
||||
|
||||
## 只用 CMD
|
||||
|
||||
CMD ["curl", "-s", "http://example.com"]
|
||||
@@ -53,6 +55,7 @@ $ docker run myimage curl -v ... # curl -v ...(完全替换)
|
||||
```
|
||||
|
||||
```docker
|
||||
|
||||
## 只用 ENTRYPOINT
|
||||
|
||||
ENTRYPOINT ["curl", "-s"]
|
||||
@@ -64,6 +67,7 @@ $ docker run myimage http://example.com # curl -s http://example.com ✓
|
||||
```
|
||||
|
||||
```docker
|
||||
|
||||
## ENTRYPOINT + CMD 组合(推荐)
|
||||
|
||||
ENTRYPOINT ["curl", "-s"]
|
||||
@@ -98,6 +102,7 @@ $ docker run myip # ✓ 正常工作
|
||||
|
||||
$ docker run myip -i # ✗ 错误!
|
||||
exec: "-i": executable file not found
|
||||
|
||||
## -i 替换了整个 CMD,被当作可执行文件
|
||||
|
||||
...
|
||||
@@ -208,19 +213,23 @@ 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
|
||||
|
||||
...
|
||||
@@ -233,6 +242,7 @@ $ docker run myapp --help
|
||||
使用 `--entrypoint` 参数覆盖:
|
||||
|
||||
```bash
|
||||
|
||||
## 正常运行
|
||||
|
||||
$ docker run myimage
|
||||
@@ -267,6 +277,7 @@ $ docker run --entrypoint /bin/cat myimage /etc/os-release
|
||||
#### 1. 使用 exec 格式
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 推荐
|
||||
|
||||
ENTRYPOINT ["python", "app.py"]
|
||||
@@ -287,6 +298,7 @@ CMD ["-g", "daemon off;"]
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
|
||||
## 准备工作...
|
||||
|
||||
## 使用 exec 替换当前进程
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
### 7.6.1 基本语法
|
||||
|
||||
```docker
|
||||
|
||||
## 格式一:单个变量
|
||||
|
||||
ENV <key> <value>
|
||||
@@ -101,6 +102,7 @@ const dbUrl = process.env.DATABASE_URL;
|
||||
使用 `-e` 或 `--env` 覆盖 Dockerfile 中定义的环境变量:
|
||||
|
||||
```bash
|
||||
|
||||
## 覆盖单个变量
|
||||
|
||||
$ docker run -e APP_ENV=development myimage
|
||||
@@ -117,6 +119,7 @@ $ docker run --env-file .env myimage
|
||||
#### .env 文件格式
|
||||
|
||||
```bash
|
||||
|
||||
## .env
|
||||
|
||||
APP_ENV=development
|
||||
@@ -138,6 +141,7 @@ DATABASE_URL=postgres://localhost/mydb
|
||||
#### 组合使用
|
||||
|
||||
```docker
|
||||
|
||||
## ARG 接收构建时参数
|
||||
|
||||
ARG NODE_VERSION=20
|
||||
@@ -152,6 +156,7 @@ RUN curl -fsSL https://nodejs.org/dist/v${NODE_VERSION}/...
|
||||
```
|
||||
|
||||
```bash
|
||||
|
||||
## 构建时指定版本
|
||||
|
||||
$ docker build --build-arg NODE_VERSION=18 -t myapp .
|
||||
@@ -164,6 +169,7 @@ $ docker build --build-arg NODE_VERSION=18 -t myapp .
|
||||
#### 1. 统一管理版本号
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 好:版本集中管理
|
||||
|
||||
ENV NGINX_VERSION=1.25.0 \
|
||||
@@ -180,6 +186,7 @@ RUN apt-get install nginx=1.25.0
|
||||
#### 2. 不要存储敏感信息
|
||||
|
||||
```docker
|
||||
|
||||
## ❌ 错误:密码写入镜像
|
||||
|
||||
ENV DB_PASSWORD=secret123
|
||||
@@ -202,6 +209,7 @@ ENV APP_ENV=production \
|
||||
#### 4. 使用有意义的变量名
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 好:清晰的命名
|
||||
|
||||
ENV REDIS_HOST=localhost \
|
||||
@@ -222,6 +230,7 @@ ENV HOST=localhost \
|
||||
exec 格式不会自动展开环境变量:
|
||||
|
||||
```docker
|
||||
|
||||
## ❌ 不会展开 $PORT
|
||||
|
||||
CMD ["python", "app.py", "--port", "$PORT"]
|
||||
@@ -241,6 +250,7 @@ $ docker exec mycontainer env
|
||||
#### Q:多行 ENV 还是多个 ENV
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 推荐:减少层数
|
||||
|
||||
ENV VAR1=value1 \
|
||||
|
||||
@@ -36,6 +36,7 @@ ARG <参数名>[=<默认值>]
|
||||
#### 定义和使用
|
||||
|
||||
```docker
|
||||
|
||||
## 定义有默认值的 ARG
|
||||
|
||||
ARG NODE_VERSION=20
|
||||
@@ -49,6 +50,7 @@ RUN echo "Using Node.js $NODE_VERSION"
|
||||
#### 构建时覆盖
|
||||
|
||||
```bash
|
||||
|
||||
## 使用默认值
|
||||
|
||||
$ docker build -t myapp .
|
||||
@@ -65,6 +67,7 @@ $ docker build --build-arg NODE_VERSION=18 -t myapp .
|
||||
#### FROM 之前的 ARG
|
||||
|
||||
```docker
|
||||
|
||||
## FROM 之前的 ARG 只能用于 FROM 指令
|
||||
|
||||
ARG REGISTRY=docker.io
|
||||
@@ -96,12 +99,14 @@ RUN echo "Node version: $NODE_VERSION"
|
||||
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
|
||||
@@ -155,6 +160,7 @@ RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc && \
|
||||
```
|
||||
|
||||
```bash
|
||||
|
||||
## 构建时传入 token
|
||||
|
||||
$ docker build --build-arg NPM_TOKEN=xxx .
|
||||
@@ -192,6 +198,7 @@ Docker 提供了一些预定义的 ARG,无需声明即可使用:
|
||||
| `FTP_PROXY` | FTP 代理 |
|
||||
|
||||
```bash
|
||||
|
||||
## 构建时使用代理
|
||||
|
||||
$ docker build --build-arg HTTP_PROXY=http://proxy:8080 .
|
||||
@@ -204,6 +211,7 @@ $ docker build --build-arg HTTP_PROXY=http://proxy:8080 .
|
||||
#### 1. 为 ARG 提供合理默认值
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 好:有默认值
|
||||
|
||||
ARG NODE_VERSION=20
|
||||
@@ -216,6 +224,7 @@ ARG NODE_VERSION
|
||||
#### 2. 不要用 ARG 存储敏感信息
|
||||
|
||||
```docker
|
||||
|
||||
## ❌ 错误:密码会被记录在镜像历史中
|
||||
|
||||
ARG DB_PASSWORD
|
||||
|
||||
@@ -75,6 +75,7 @@ local a1b2c3d4e5f6... # 自动创建的匿名卷
|
||||
#### 2. 可被命名卷覆盖
|
||||
|
||||
```bash
|
||||
|
||||
## 使用命名卷替代匿名卷
|
||||
|
||||
$ docker run -v mysql_data:/var/lib/mysql mysql:8.0
|
||||
@@ -83,6 +84,7 @@ $ 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
|
||||
@@ -149,6 +151,7 @@ VOLUME /app/uploads
|
||||
### 7.8.7 查看 VOLUME 定义
|
||||
|
||||
```bash
|
||||
|
||||
## 查看镜像定义的 VOLUME
|
||||
|
||||
$ docker inspect mysql:8.0 --format '{{json .Config.Volumes}}' | jq
|
||||
@@ -201,9 +204,11 @@ volumes:
|
||||
#### 匿名卷可能导致数据丢失
|
||||
|
||||
```bash
|
||||
|
||||
## 使用 --rm 运行的容器,匿名卷会在容器删除时一起删除
|
||||
|
||||
$ docker run --rm mysql:8.0
|
||||
|
||||
## 容器停止后,数据丢失!
|
||||
|
||||
...
|
||||
@@ -222,6 +227,7 @@ $ docker run -v mysql_data:/var/lib/mysql mysql:8.0
|
||||
#### 1. 定义必须持久化的路径
|
||||
|
||||
```docker
|
||||
|
||||
## 数据库必须使用卷
|
||||
|
||||
FROM postgres:16
|
||||
@@ -231,6 +237,7 @@ VOLUME /var/lib/postgresql/data
|
||||
#### 2. 不要在 VOLUME 后修改目录
|
||||
|
||||
```docker
|
||||
|
||||
## ❌ 避免
|
||||
|
||||
VOLUME /app/data
|
||||
@@ -245,6 +252,7 @@ VOLUME /app/data
|
||||
#### 3. 文档中说明 VOLUME 用途
|
||||
|
||||
```docker
|
||||
|
||||
## 持久化用户上传的文件
|
||||
|
||||
VOLUME /app/uploads
|
||||
|
||||
@@ -13,6 +13,7 @@ EXPOSE <端口> [<端口>/<协议>...]
|
||||
### 7.9.2 基本用法
|
||||
|
||||
```docker
|
||||
|
||||
## 声明单个端口
|
||||
|
||||
EXPOSE 80
|
||||
@@ -36,12 +37,14 @@ EXPOSE 53/udp
|
||||
告诉镜像使用者,容器将在哪些端口提供服务:
|
||||
|
||||
```docker
|
||||
|
||||
## 使用者一看就知道这是 web 应用
|
||||
|
||||
EXPOSE 80 443
|
||||
```
|
||||
|
||||
```bash
|
||||
|
||||
## 查看镜像暴露的端口
|
||||
|
||||
$ docker inspect nginx --format '{{.Config.ExposedPorts}}'
|
||||
@@ -53,6 +56,7 @@ map[80/tcp:{}]
|
||||
使用 `docker run -P` 时,Docker 会自动映射 EXPOSE 的端口到宿主机随机端口:
|
||||
|
||||
```docker
|
||||
|
||||
## Dockerfile
|
||||
|
||||
EXPOSE 80
|
||||
@@ -85,15 +89,18 @@ flowchart TD
|
||||
#### 没有 EXPOSE 也能 -p
|
||||
|
||||
```docker
|
||||
|
||||
## 即使没有 EXPOSE,也可以使用 -p
|
||||
|
||||
FROM nginx
|
||||
|
||||
## 没有 EXPOSE
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
```bash
|
||||
|
||||
## 仍然可以映射端口
|
||||
|
||||
$ docker run -p 8080:80 mynginx
|
||||
@@ -106,6 +113,7 @@ $ docker run -p 8080:80 mynginx
|
||||
#### 误解:EXPOSE 会打开端口
|
||||
|
||||
```docker
|
||||
|
||||
## ❌ 错误理解:这不会让容器可从外部访问
|
||||
|
||||
EXPOSE 80
|
||||
@@ -122,6 +130,7 @@ EXPOSE 只是元数据声明。容器是否实际监听该端口,取决于容
|
||||
#### 正确理解
|
||||
|
||||
```docker
|
||||
|
||||
## Dockerfile
|
||||
|
||||
FROM nginx
|
||||
@@ -129,6 +138,7 @@ EXPOSE 80 # 1. 声明:这个容器会在 80 端口提供服务
|
||||
```
|
||||
|
||||
```bash
|
||||
|
||||
## 运行:需要 -p 才能从外部访问
|
||||
|
||||
$ docker run -p 8080:80 nginx # 2. 映射:宿主机 8080 → 容器 80
|
||||
@@ -141,6 +151,7 @@ $ docker run -p 8080:80 nginx # 2. 映射:宿主机 8080 → 容器 80
|
||||
#### 1. 总是声明应用使用的端口
|
||||
|
||||
```docker
|
||||
|
||||
## Web 服务
|
||||
|
||||
FROM nginx
|
||||
@@ -160,6 +171,7 @@ EXPOSE 6379
|
||||
#### 2. 使用明确的协议
|
||||
|
||||
```docker
|
||||
|
||||
## 默认是 TCP
|
||||
|
||||
EXPOSE 80
|
||||
@@ -176,6 +188,7 @@ EXPOSE 53/tcp 53/udp
|
||||
#### 3. 与应用实际端口保持一致
|
||||
|
||||
```docker
|
||||
|
||||
## ✅ 好:EXPOSE 与应用端口一致
|
||||
|
||||
ENV PORT=3000
|
||||
|
||||
@@ -147,6 +147,7 @@ $ docker run -d \
|
||||
#### 只读挂载
|
||||
|
||||
```bash
|
||||
|
||||
## --mount 方式
|
||||
|
||||
$ docker run -d \
|
||||
@@ -167,6 +168,7 @@ $ docker run -d \
|
||||
#### 场景一:数据库持久化
|
||||
|
||||
```bash
|
||||
|
||||
## 创建数据卷
|
||||
|
||||
$ docker volume create postgres_data
|
||||
@@ -195,6 +197,7 @@ $ docker run -d \
|
||||
#### 场景二:多容器共享数据
|
||||
|
||||
```bash
|
||||
|
||||
## 创建共享数据卷
|
||||
|
||||
$ docker volume create shared-data
|
||||
@@ -215,6 +218,7 @@ $ docker run --rm \
|
||||
#### 场景三:配置文件持久化
|
||||
|
||||
```bash
|
||||
|
||||
## 将 nginx 配置存储在数据卷中
|
||||
|
||||
$ docker run -d \
|
||||
@@ -231,6 +235,7 @@ $ docker run -d \
|
||||
#### 删除数据卷
|
||||
|
||||
```bash
|
||||
|
||||
## 删除指定数据卷
|
||||
|
||||
$ docker volume rm my-vol
|
||||
@@ -243,6 +248,7 @@ $ docker rm -v container_name
|
||||
#### 清理未使用的数据卷
|
||||
|
||||
```bash
|
||||
|
||||
## 查看未被任何容器使用的数据卷
|
||||
|
||||
$ docker volume ls -f dangling=true
|
||||
@@ -265,6 +271,7 @@ $ docker volume prune -f
|
||||
#### 备份数据卷
|
||||
|
||||
```bash
|
||||
|
||||
## 使用临时容器挂载数据卷,打包备份
|
||||
|
||||
$ docker run --rm \
|
||||
@@ -283,6 +290,7 @@ $ docker run --rm \
|
||||
#### 恢复数据卷
|
||||
|
||||
```bash
|
||||
|
||||
## 创建新数据卷
|
||||
|
||||
$ docker volume create my-vol-restored
|
||||
@@ -299,6 +307,7 @@ $ docker run --rm \
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
## backup-volume.sh
|
||||
|
||||
VOLUME_NAME=$1
|
||||
@@ -328,6 +337,7 @@ Docker 有两种主要的数据持久化方式:
|
||||
| **备份** | 需要工具 | 直接访问文件 |
|
||||
|
||||
```bash
|
||||
|
||||
## 数据卷
|
||||
|
||||
$ docker run -v mydata:/app/data nginx
|
||||
@@ -352,6 +362,7 @@ $ docker inspect container_name --format '{{json .Mounts}}' | jq
|
||||
#### Q:数据卷的数据在哪里?
|
||||
|
||||
```bash
|
||||
|
||||
## 查看数据卷详情
|
||||
|
||||
$ docker volume inspect my-vol
|
||||
|
||||
@@ -86,6 +86,7 @@ $ docker run -d \
|
||||
#### 场景一:开发环境代码同步
|
||||
|
||||
```bash
|
||||
|
||||
## 将本地代码目录挂载到容器
|
||||
|
||||
$ docker run -d \
|
||||
@@ -96,6 +97,7 @@ $ docker run -d \
|
||||
## 修改本地文件,容器内立即生效(热更新)
|
||||
|
||||
$ echo "Hello" > src/index.html
|
||||
|
||||
## 浏览器刷新即可看到变化
|
||||
|
||||
...
|
||||
@@ -104,6 +106,7 @@ $ echo "Hello" > src/index.html
|
||||
#### 场景二:配置文件挂载
|
||||
|
||||
```bash
|
||||
|
||||
## 挂载自定义 nginx 配置
|
||||
|
||||
$ docker run -d \
|
||||
@@ -114,6 +117,7 @@ $ docker run -d \
|
||||
#### 场景三:日志收集
|
||||
|
||||
```bash
|
||||
|
||||
## 将容器日志输出到宿主机目录
|
||||
|
||||
$ docker run -d \
|
||||
@@ -124,6 +128,7 @@ $ docker run -d \
|
||||
#### 场景四:共享 SSH 密钥
|
||||
|
||||
```bash
|
||||
|
||||
## 挂载 SSH 密钥(只读)
|
||||
|
||||
$ docker run --rm -it \
|
||||
@@ -138,6 +143,7 @@ $ docker run --rm -it \
|
||||
防止容器修改宿主机文件:
|
||||
|
||||
```bash
|
||||
|
||||
## --mount 语法
|
||||
|
||||
$ docker run -d \
|
||||
@@ -163,6 +169,7 @@ touch: /app/config/new.txt: Read-only file system
|
||||
### 8.2.6 挂载单个文件
|
||||
|
||||
```bash
|
||||
|
||||
## 挂载 bash 历史记录
|
||||
|
||||
$ docker run --rm -it \
|
||||
@@ -228,6 +235,7 @@ bind source path does not exist: /not/exist
|
||||
容器内用户可能无权访问挂载的文件:
|
||||
|
||||
```bash
|
||||
|
||||
## 方法1:确保宿主机文件权限允许容器用户访问
|
||||
|
||||
$ chmod -R 755 /path/to/data
|
||||
@@ -246,6 +254,7 @@ $ docker run -u $(id -u):$(id -g) ...
|
||||
在 Docker Desktop 上,Bind Mount 性能较差 (需要跨文件系统同步):
|
||||
|
||||
```bash
|
||||
|
||||
## 使用 :cached 或 :delegated 提高性能(macOS)
|
||||
|
||||
$ docker run -v /host/path:/container/path:cached myapp
|
||||
@@ -264,6 +273,7 @@ $ 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
|
||||
@@ -272,6 +282,7 @@ $ docker run -v $(pwd):/app -p 3000:3000 node npm run dev
|
||||
#### 2. 生产环境使用 Volume
|
||||
|
||||
```bash
|
||||
|
||||
## 数据持久化
|
||||
|
||||
$ docker run -v mysql_data:/var/lib/mysql mysql
|
||||
@@ -286,6 +297,7 @@ $ docker run -v /config/nginx.conf:/etc/nginx/nginx.conf:ro nginx
|
||||
#### 4. 注意路径安全
|
||||
|
||||
```bash
|
||||
|
||||
## ❌ 危险:挂载根目录或敏感目录
|
||||
|
||||
$ docker run -v /:/host ...
|
||||
|
||||
@@ -18,6 +18,7 @@ Docker 容器的 DNS 配置有两种情况:
|
||||
这是 Docker 网络最强大的功能之一。在自定义网络中,容器可以通过 “名字” 找到彼此,而不需要知道对方的 IP (因为 IP 可能会变)。
|
||||
|
||||
```bash
|
||||
|
||||
## 1. 创建自定义网络
|
||||
|
||||
$ docker network create mynet
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
使用 `docker network create` 命令可以创建自定义网络:
|
||||
|
||||
```bash
|
||||
|
||||
## 创建网络
|
||||
|
||||
$ docker network create mynet
|
||||
@@ -31,6 +32,7 @@ $ docker network inspect mynet
|
||||
启动容器时通过 `--network` 参数指定连接的网络:
|
||||
|
||||
```bash
|
||||
|
||||
## 启动容器并连接到自定义网络
|
||||
|
||||
$ docker run -d --name web --network mynet nginx
|
||||
@@ -63,6 +65,7 @@ flowchart LR
|
||||
以下是 Docker 网络管理中常用的命令:
|
||||
|
||||
```bash
|
||||
|
||||
## 列出网络
|
||||
|
||||
$ docker network ls
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
同一自定义网络内的容器可以直接通过容器名通信,这是推荐的容器互联方式:
|
||||
|
||||
```bash
|
||||
|
||||
## 创建网络
|
||||
|
||||
$ docker network create app-net
|
||||
@@ -26,6 +27,7 @@ $ docker run -d --name app --network app-net myapp
|
||||
一个容器可以同时连接到多个网络,这对于需要跨网络通信的中间件容器特别有用:
|
||||
|
||||
```bash
|
||||
|
||||
## 启动容器
|
||||
|
||||
$ docker run -d --name multi-net-container --network frontend nginx
|
||||
@@ -44,6 +46,7 @@ $ docker inspect multi-net-container --format '{{json .NetworkSettings.Networks}
|
||||
`--link` 是 Docker 早期用于容器互联的方式,**已经被废弃**,不建议在新项目中使用。请使用自定义网络替代:
|
||||
|
||||
```bash
|
||||
|
||||
## 旧方式(不推荐)
|
||||
|
||||
$ docker run --link db:database myapp
|
||||
|
||||
@@ -30,6 +30,7 @@ Docker 提供了多种方式来指定端口映射。
|
||||
使用 `-p <宿主机端口>:<容器端口>` 格式:
|
||||
|
||||
```bash
|
||||
|
||||
## 将宿主机的 8080 端口映射到容器的 80 端口
|
||||
|
||||
$ docker run -d -p 8080:80 nginx
|
||||
@@ -103,6 +104,7 @@ abc123456 nginx 0.0.0.0:8080->80/tcp web
|
||||
如果不希望对外暴露 (例如数据库服务),应绑定到 `127.0.0.1`:
|
||||
|
||||
```bash
|
||||
|
||||
## 仅允许本机访问
|
||||
|
||||
$ docker run -d -p 127.0.0.1:3306:3306 mysql
|
||||
@@ -134,6 +136,7 @@ Docker 使用 `docker-proxy` 进程 (用户态) 或 `iptables` DNAT 规则 (内
|
||||
当流量到达宿主机端口时,iptables 规则将其目标地址修改为容器 IP 并转发:
|
||||
|
||||
```bash
|
||||
|
||||
## 简化的 iptables 逻辑
|
||||
|
||||
iptables -t nat -A DOCKER -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80
|
||||
|
||||
@@ -7,6 +7,7 @@ Docker 网络提供了天然的隔离能力,不同网络之间的容器默认
|
||||
不同网络之间默认隔离,容器只能与同一网络中的容器直接通信:
|
||||
|
||||
```bash
|
||||
|
||||
## 创建两个网络
|
||||
|
||||
$ docker network create frontend
|
||||
@@ -42,6 +43,7 @@ ping: db: Name or service not known
|
||||
如果确实需要某个容器跨网络通信,可以将其同时连接到多个网络:
|
||||
|
||||
```bash
|
||||
|
||||
## 创建一个中间件容器,连接到两个网络
|
||||
|
||||
$ docker run -d --name api --network frontend myapi
|
||||
|
||||
@@ -35,6 +35,7 @@ veth 对
|
||||
**Docker Swarm 模式下的 Overlay 网络:**
|
||||
|
||||
```bash
|
||||
|
||||
# 初始化 Swarm(创建集群)
|
||||
docker swarm init
|
||||
|
||||
@@ -61,6 +62,7 @@ docker service ps web
|
||||
**单机 Overlay 网络模拟(Linux 容器):**
|
||||
|
||||
```bash
|
||||
|
||||
# 创建自定义 overlay 网络
|
||||
docker network create --driver overlay custom-overlay
|
||||
|
||||
@@ -79,6 +81,7 @@ docker network inspect custom-overlay
|
||||
#### Overlay 网络性能优化
|
||||
|
||||
```bash
|
||||
|
||||
# 调整 MTU(Maximum Transmission Unit)避免分片
|
||||
# VXLAN 开销 50 字节,物理 MTU 1500,建议设置为 1450
|
||||
docker network create --driver overlay \
|
||||
@@ -122,6 +125,7 @@ networks:
|
||||
Calico 使用 BGP 协议进行路由,支持网络策略和 eBPF 加速。
|
||||
|
||||
```yaml
|
||||
|
||||
# Kubernetes 中安装 Calico
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
@@ -156,6 +160,7 @@ data:
|
||||
Flannel 提供简单的 overlay 网络实现,适合小到中等规模的集群。
|
||||
|
||||
```bash
|
||||
|
||||
# 安装 Flannel
|
||||
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
|
||||
|
||||
@@ -202,6 +207,7 @@ EOF
|
||||
Cilium 使用 eBPF 在内核级别实现网络策略和可观测性,性能优异。
|
||||
|
||||
```bash
|
||||
|
||||
# 安装 Cilium
|
||||
helm repo add cilium https://helm.cilium.io
|
||||
helm install cilium cilium/cilium \
|
||||
@@ -222,6 +228,7 @@ helm upgrade cilium cilium/cilium \
|
||||
Weave 提供简单的跨主机通信,支持加密和多播。
|
||||
|
||||
```bash
|
||||
|
||||
# Docker 中使用 Weave 网络
|
||||
docker run -d --name weave \
|
||||
--net=host \
|
||||
@@ -269,6 +276,7 @@ DNS 响应 → 容器缓存 → 应用
|
||||
**在运行时指定 DNS:**
|
||||
|
||||
```bash
|
||||
|
||||
# 单个容器
|
||||
docker run -d \
|
||||
--dns 8.8.8.8 \
|
||||
@@ -334,6 +342,7 @@ networks:
|
||||
**使用 Docker 内建 DNS 的服务发现:**
|
||||
|
||||
```bash
|
||||
|
||||
# 创建自定义网络
|
||||
docker network create mynet
|
||||
|
||||
@@ -343,6 +352,7 @@ docker run -d --name db --network mynet postgres:latest
|
||||
|
||||
# 在其他容器中通过服务名访问
|
||||
docker run -it --network mynet busybox sh
|
||||
|
||||
# ping web # 自动解析到 web 容器 IP
|
||||
# ping db # 自动解析到 db 容器 IP
|
||||
```
|
||||
@@ -377,6 +387,7 @@ services:
|
||||
#### DNS 性能优化
|
||||
|
||||
```bash
|
||||
|
||||
# 检查 DNS 延迟
|
||||
time docker exec <container> nslookup www.example.com
|
||||
|
||||
@@ -494,6 +505,7 @@ spec:
|
||||
|
||||
```yaml
|
||||
---
|
||||
|
||||
# 拒绝所有默认
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
@@ -506,6 +518,7 @@ spec:
|
||||
- Egress
|
||||
|
||||
---
|
||||
|
||||
# Frontend 容器策略
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
@@ -550,6 +563,7 @@ spec:
|
||||
port: 53
|
||||
|
||||
---
|
||||
|
||||
# API 容器策略
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
@@ -590,6 +604,7 @@ spec:
|
||||
port: 53
|
||||
|
||||
---
|
||||
|
||||
# 数据库容器策略
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
@@ -660,6 +675,7 @@ spec:
|
||||
#### 选择建议
|
||||
|
||||
```bash
|
||||
|
||||
# 1. 开发环境:使用 Bridge 网络
|
||||
docker network create my-app
|
||||
docker compose up # 默认使用 bridge
|
||||
@@ -682,6 +698,7 @@ helm install cilium cilium/cilium --namespace kube-system
|
||||
**常见网络问题诊断:**
|
||||
|
||||
```bash
|
||||
|
||||
# 1. 容器无法访问外部网络
|
||||
docker exec <container> ping 8.8.8.8
|
||||
docker exec <container> cat /etc/resolv.conf
|
||||
|
||||
@@ -15,6 +15,7 @@ BuildKit 引入了多项新指令,旨在优化构建缓存和安全性。以
|
||||
要使用最新的 Dockerfile 语法特性,建议在 Dockerfile 开头添加语法指令:
|
||||
|
||||
```docker
|
||||
|
||||
## syntax=docker/dockerfile:1
|
||||
|
||||
```
|
||||
@@ -53,6 +54,7 @@ COPY --from=builder /app/dist /app/dist
|
||||
`BuildKit` 提供了 `RUN --mount=type=cache` 指令,可以实现上边的设想。
|
||||
|
||||
```docker
|
||||
|
||||
## syntax=docker/dockerfile:1
|
||||
|
||||
FROM node:alpine as builder
|
||||
@@ -68,6 +70,7 @@ RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=loc
|
||||
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
|
||||
@@ -107,6 +110,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 \
|
||||
@@ -118,6 +122,7 @@ RUN --mount=type=bind,from=php:alpine,source=/usr/local/bin/docker-php-entrypoin
|
||||
该指令可以将一个 `tmpfs` 文件系统挂载到指定位置。
|
||||
|
||||
```docker
|
||||
|
||||
## syntax=docker/dockerfile:1
|
||||
|
||||
RUN --mount=type=tmpfs,target=/temp \
|
||||
@@ -129,6 +134,7 @@ RUN --mount=type=tmpfs,target=/temp \
|
||||
该指令可以将一个文件 (例如密钥) 挂载到指定位置。
|
||||
|
||||
```docker
|
||||
|
||||
## syntax=docker/dockerfile:1
|
||||
|
||||
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
|
||||
@@ -144,6 +150,7 @@ $ docker build -t test --secret id=aws,src=$HOME/.aws/credentials .
|
||||
该指令可以挂载 `ssh` 密钥。
|
||||
|
||||
```docker
|
||||
|
||||
## syntax=docker/dockerfile:1
|
||||
|
||||
FROM alpine
|
||||
|
||||
@@ -19,6 +19,7 @@ Buildx 使用 [BuildKit 引擎](10.1_buildkit.md)进行构建,支持许多新
|
||||
`docker buildx bake` 是一个高级构建命令,支持从 HCL、JSON 或 Compose 文件中定义构建目标,实现复杂的流水线构建。
|
||||
|
||||
```bash
|
||||
|
||||
## 从 Compose 文件构建所有服务
|
||||
|
||||
$ docker buildx bake
|
||||
|
||||
@@ -60,6 +60,7 @@ $ docker buildx inspect --bootstrap
|
||||
使用 `docker buildx build` 命令并指定 `--platform` 参数,可以同时构建支持多种架构的镜像。`--push` 参数会将构建好的镜像和 manifest list 推送到 Docker 仓库。
|
||||
|
||||
```dockerfile
|
||||
|
||||
## Dockerfile
|
||||
|
||||
FROM --platform=$TARGETPLATFORM alpine
|
||||
@@ -110,6 +111,7 @@ ENTRYPOINT ["/dist"]
|
||||
#### 创建 manifest list
|
||||
|
||||
```bash
|
||||
|
||||
## 首先,为每个架构构建并推送镜像
|
||||
|
||||
$ docker buildx build --platform linux/amd64 -t your-username/my-app:amd64 . --push
|
||||
|
||||
@@ -195,6 +195,7 @@ env_file:
|
||||
环境变量文件中每一行必须符合格式,支持 `#` 开头的注释行。
|
||||
|
||||
```bash
|
||||
|
||||
## common.env: Set development environment
|
||||
|
||||
PROG_ENV=development
|
||||
@@ -558,6 +559,7 @@ db:
|
||||
在当前目录新建 `.env` 文件并写入以下内容。
|
||||
|
||||
```bash
|
||||
|
||||
## 支持 # 号注释
|
||||
|
||||
MONGO_VERSION=3.6
|
||||
|
||||
@@ -274,6 +274,7 @@ web-1 | Starting development server at http://0.0.0.0:8000/
|
||||
在另一个终端窗口执行:
|
||||
|
||||
```bash
|
||||
|
||||
## 执行数据库迁移
|
||||
|
||||
$ docker compose exec web python manage.py migrate
|
||||
@@ -306,6 +307,7 @@ $ docker compose exec db psql -U django_user -d django_db
|
||||
| 网络未创建 | 运行 `docker compose down` 后重新 `up` |
|
||||
|
||||
```bash
|
||||
|
||||
## 调试:检查数据库是否正常运行
|
||||
|
||||
$ docker compose ps
|
||||
@@ -323,6 +325,7 @@ $ docker compose logs db
|
||||
#### Q3:权限问题
|
||||
|
||||
```bash
|
||||
|
||||
## 如果容器内创建的文件 root 用户所有
|
||||
|
||||
$ sudo chown -R $USER:$USER .
|
||||
@@ -341,6 +344,7 @@ $ sudo chown -R $USER:$USER .
|
||||
| **ALLOWED_HOSTS**| `['*']` | 具体域名 |**生产环境 Compose 文件示例**:
|
||||
|
||||
```yaml
|
||||
|
||||
## compose.prod.yaml
|
||||
|
||||
services:
|
||||
|
||||
@@ -223,6 +223,7 @@ Created database 'myapp_test'
|
||||
### 11.7.11 常用开发命令
|
||||
|
||||
```bash
|
||||
|
||||
## 数据库迁移
|
||||
|
||||
$ docker compose exec web rails db:migrate
|
||||
|
||||
@@ -137,6 +137,7 @@ $ docker compose logs -f
|
||||
不要只依赖 Volume。建议定期备份数据库:
|
||||
|
||||
```bash
|
||||
|
||||
## 导出 SQL
|
||||
|
||||
$ docker exec wordpress_db mysqldump -u wordpress -pwordpress wordpress > backup.sql
|
||||
|
||||
@@ -53,6 +53,7 @@ PID Namespace 负责进程 ID 的隔离,使得容器内的进程彼此不可
|
||||
#### PID 隔离效果
|
||||
|
||||
```bash
|
||||
|
||||
## 宿主机上查看进程
|
||||
|
||||
$ ps aux | grep nginx
|
||||
@@ -154,6 +155,7 @@ UTS Namespace 主要用于隔离主机名和域名。
|
||||
#### UTS 隔离效果
|
||||
|
||||
```bash
|
||||
|
||||
## 宿主机
|
||||
|
||||
$ hostname
|
||||
@@ -233,6 +235,7 @@ flowchart LR
|
||||
#### 实验 1:UTS Namespace
|
||||
|
||||
```bash
|
||||
|
||||
## 创建新的 UTS namespace 并启动 shell
|
||||
|
||||
$ sudo unshare --uts /bin/bash
|
||||
@@ -253,6 +256,7 @@ my-server
|
||||
#### 实验 2:PID Namespace
|
||||
|
||||
```bash
|
||||
|
||||
## 创建新的 PID 和 MNT namespace
|
||||
|
||||
$ sudo unshare --pid --mount --fork /bin/bash
|
||||
@@ -272,6 +276,7 @@ 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
|
||||
|
||||
@@ -62,6 +62,7 @@ Docker 提供了丰富的参数来配置容器的资源限制,主要包括内
|
||||
#### 内存限制
|
||||
|
||||
```bash
|
||||
|
||||
## 限制容器最多使用 512MB 内存
|
||||
|
||||
$ docker run -m 512m myapp
|
||||
@@ -85,6 +86,7 @@ $ docker run --memory-reservation 256m myapp
|
||||
#### CPU 限制
|
||||
|
||||
```bash
|
||||
|
||||
## 限制使用 1.5 个 CPU 核心
|
||||
|
||||
$ docker run --cpus=1.5 myapp
|
||||
@@ -108,6 +110,7 @@ $ docker run --cpu-shares=512 myapp
|
||||
#### 磁盘 I/O 限制
|
||||
|
||||
```bash
|
||||
|
||||
## 限制设备写入速度为 10MB/s
|
||||
|
||||
$ docker run --device-write-bps /dev/sda:10mb myapp
|
||||
@@ -124,6 +127,7 @@ $ docker run --device-write-iops /dev/sda:100 myapp
|
||||
#### 进程数限制
|
||||
|
||||
```bash
|
||||
|
||||
## 限制最多 100 个进程
|
||||
|
||||
$ docker run --pids-limit=100 myapp
|
||||
@@ -134,6 +138,7 @@ $ docker run --pids-limit=100 myapp
|
||||
### 12.3.5 查看容器资源使用
|
||||
|
||||
```bash
|
||||
|
||||
## 实时监控所有容器的资源使用
|
||||
|
||||
$ docker stats
|
||||
@@ -157,6 +162,7 @@ $ docker inspect mycontainer --format '{{json .HostConfig}}' | jq
|
||||
#### 内存超限
|
||||
|
||||
```bash
|
||||
|
||||
## 启动限制 100MB 内存的容器
|
||||
|
||||
$ docker run -m 100m stress --vm 1 --vm-bytes 200M
|
||||
@@ -175,14 +181,17 @@ abc123 Exited (137) 5 seconds ago hopeful_darwin
|
||||
#### CPU 限制验证
|
||||
|
||||
```bash
|
||||
|
||||
## 不限制 CPU
|
||||
|
||||
$ docker run --rm stress --cpu 4
|
||||
|
||||
## 占满所有 CPU
|
||||
|
||||
## 限制为 1 个核心
|
||||
|
||||
$ docker run --rm --cpus=1 stress --cpu 4
|
||||
|
||||
## 只能使用约 100% CPU(1 个核心)
|
||||
|
||||
...
|
||||
@@ -215,10 +224,12 @@ Docker 19.03+ 默认优先使用 cgroups v2(如果系统支持),提供更
|
||||
#### 检查系统使用的版本
|
||||
|
||||
```bash
|
||||
|
||||
## 查看 cgroup 版本
|
||||
|
||||
$ mount | grep cgroup
|
||||
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime)
|
||||
|
||||
## 如果显示 cgroup2 表示 v2
|
||||
|
||||
## 或者
|
||||
@@ -257,6 +268,7 @@ services:
|
||||
#### 1. 始终设置内存限制
|
||||
|
||||
```bash
|
||||
|
||||
## 防止 OOM 影响宿主机
|
||||
|
||||
$ docker run -m 1g myapp
|
||||
@@ -271,6 +283,7 @@ $ docker run --cpus=2 --cpu-shares=2048 critical-app
|
||||
#### 3. 监控资源使用
|
||||
|
||||
```bash
|
||||
|
||||
## 配合 Prometheus + cAdvisor 监控
|
||||
|
||||
$ docker run -d --name cadvisor \
|
||||
|
||||
@@ -112,6 +112,7 @@ Docker 的存储驱动经历了从早期各式各样的机制(如 aufs, device
|
||||
#### 查看当前存储驱动与后端
|
||||
|
||||
```bash
|
||||
|
||||
## 查看默认存储驱动 (Storage Driver)
|
||||
$ docker info | grep "Storage Driver"
|
||||
Storage Driver: overlay2
|
||||
@@ -161,6 +162,7 @@ flowchart TD
|
||||
### 12.4.6 查看镜像层
|
||||
|
||||
```bash
|
||||
|
||||
## 查看镜像的层信息
|
||||
|
||||
$ docker history nginx:alpine
|
||||
@@ -192,6 +194,7 @@ $ docker inspect nginx:alpine --format '{{json .GraphDriver.Data}}' | jq
|
||||
#### 1. 减少镜像层数
|
||||
|
||||
```docker
|
||||
|
||||
## ❌ 每条命令创建一层
|
||||
|
||||
RUN apt-get update
|
||||
|
||||
@@ -77,6 +77,7 @@ status:
|
||||
节点控制器会持续监控节点的健康状态。当节点变为不可达时,控制器会等待一个超时期限,然后将该节点上的 Pod 标记为失败,并触发重新调度。可以使用 `kubectl` 来管理节点,例如标记节点为不可调度或排空节点上的工作负载:
|
||||
|
||||
```bash
|
||||
|
||||
## 标记节点为不可调度
|
||||
$ kubectl cordon worker-1
|
||||
|
||||
@@ -224,6 +225,7 @@ spec:
|
||||
标签 (Label) 是附加到 Kubernetes 对象上的键值对,用于组织和选择对象子集。标签是 Kubernetes 中实现松耦合的关键机制。
|
||||
|
||||
```bash
|
||||
|
||||
## 为 Pod 添加标签
|
||||
$ kubectl label pod my-pod env=production
|
||||
|
||||
@@ -250,6 +252,7 @@ Kubernetes Dashboard 是一个基于 Web 的用户界面,用于部署容器化
|
||||
`kubectl` 是 Kubernetes 的命令行工具,用于与集群进行交互。常用命令如下:
|
||||
|
||||
```bash
|
||||
|
||||
## 查看集群中的资源
|
||||
$ kubectl get pods,deployments,services,nodes
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
参考[安装 Docker](../03_install/README.md) 一节添加 apt/yum 源,之后执行如下命令。
|
||||
|
||||
```bash
|
||||
|
||||
## debian 系
|
||||
|
||||
$ sudo apt install containerd.io
|
||||
@@ -37,6 +38,7 @@ Delegate=yes
|
||||
KillMode=process
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
## Having non-zero Limit*s causes performance problems due to accounting overhead
|
||||
|
||||
## in the kernel. We recommend using cgroups to do container-local accounting.
|
||||
@@ -44,6 +46,7 @@ RestartSec=5
|
||||
LimitNPROC=infinity
|
||||
LimitCORE=infinity
|
||||
LimitNOFILE=infinity
|
||||
|
||||
## Comment TasksMax if your systemd version does not supports it.
|
||||
|
||||
## Only systemd 226 and above support this version.
|
||||
@@ -59,15 +62,18 @@ WantedBy=multi-user.target
|
||||
|
||||
```toml
|
||||
version = 2
|
||||
|
||||
## persistent data location
|
||||
|
||||
root = "/var/lib/cri-containerd"
|
||||
|
||||
## runtime state information
|
||||
|
||||
state = "/run/cri-containerd"
|
||||
plugin_dir = ""
|
||||
disabled_plugins = []
|
||||
required_plugins = []
|
||||
|
||||
## set containerd's OOM score
|
||||
|
||||
oom_score = 0
|
||||
@@ -315,6 +321,7 @@ $ sysctl --system
|
||||
`/etc/systemd/system/kubelet.service.d/10-proxy-ipvs.conf` 写入以下内容
|
||||
|
||||
```bash
|
||||
|
||||
## 启用 ipvs 相关内核模块
|
||||
|
||||
[Service]
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#### Ubuntu/Debian
|
||||
|
||||
```bash
|
||||
|
||||
## 安装 cri-dockerd
|
||||
|
||||
$ cd /tmp
|
||||
@@ -48,6 +49,7 @@ $ sudo /usr/local/bin/cri-dockerd --version
|
||||
#### CentOS/Fedora
|
||||
|
||||
```bash
|
||||
|
||||
## 安装 cri-dockerd
|
||||
|
||||
$ cd /tmp
|
||||
@@ -155,6 +157,7 @@ $ sysctl --system
|
||||
`/etc/systemd/system/kubelet.service.d/10-proxy-ipvs.conf` 写入以下内容
|
||||
|
||||
```bash
|
||||
|
||||
## 启用 ipvs 相关内核模块
|
||||
|
||||
[Service]
|
||||
|
||||
@@ -26,6 +26,7 @@ brew install kind
|
||||
可以下载二进制文件:
|
||||
|
||||
```bash
|
||||
|
||||
## Linux AMD64
|
||||
|
||||
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
|
||||
|
||||
@@ -40,6 +40,7 @@ k3s-master Ready control-plane,master 1m v1.35.1+k3s1
|
||||
K3s 内置了 `kubectl` 命令 (通过 `k3s kubectl` 调用),为了方便,通常会建立别名或配置 `KUBECONFIG`。
|
||||
|
||||
```bash
|
||||
|
||||
## 读取 K3s 的配置文件
|
||||
|
||||
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#### 常用命令
|
||||
|
||||
```bash
|
||||
|
||||
# 启动服务
|
||||
sudo systemctl start kubelet
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
- 完成创建后获得集群 kubeconfig 文件
|
||||
|
||||
```bash
|
||||
|
||||
# 下载 kubeconfig 文件后,配置本地环境
|
||||
export KUBECONFIG=/path/to/kubeconfig.yaml
|
||||
kubectl cluster-info
|
||||
@@ -75,6 +76,7 @@ kubectl get svc
|
||||
通过腾讯云容器镜像服务 (TCR) 存储和管理私有镜像:
|
||||
|
||||
```bash
|
||||
|
||||
# 登录腾讯云镜像仓库
|
||||
docker login ccr.ccs.tencentyun.com -u <username>
|
||||
|
||||
@@ -94,6 +96,7 @@ docker push ccr.ccs.tencentyun.com/namespace/my-app:latest
|
||||
编辑 `/etc/docker/daemon.json` 文件(如果不存在则创建):
|
||||
|
||||
```bash
|
||||
|
||||
# 创建或编辑配置文件
|
||||
sudo mkdir -p /etc/docker
|
||||
sudo nano /etc/docker/daemon.json
|
||||
@@ -120,6 +123,7 @@ sudo systemctl restart docker
|
||||
验证配置:
|
||||
|
||||
```bash
|
||||
|
||||
# 查看镜像源是否生效
|
||||
docker info | grep -A 5 "Registry Mirrors"
|
||||
```
|
||||
@@ -153,6 +157,7 @@ docker info | grep -A 5 "Registry Mirrors"
|
||||
#### 完整推送/拉取示例
|
||||
|
||||
```bash
|
||||
|
||||
# 登录到腾讯云 TCR(使用 API 密钥)
|
||||
docker login ccr.ccs.tencentyun.com \
|
||||
--username <腾讯云账号ID> \
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
- 完成创建,下载 kubeconfig 文件
|
||||
|
||||
```bash
|
||||
|
||||
# 配置本地 kubectl
|
||||
export KUBECONFIG=/path/to/kubeconfig.yaml
|
||||
kubectl get nodes
|
||||
@@ -151,6 +152,7 @@ docker info | grep -A 5 "Registry Mirrors"
|
||||
#### 测试加速效果
|
||||
|
||||
```bash
|
||||
|
||||
# 从加速器拉取镜像(速度应该明显提升)
|
||||
docker pull nginx:latest
|
||||
time docker pull alpine:latest
|
||||
@@ -170,6 +172,7 @@ time docker pull alpine:latest
|
||||
#### 完整推送/拉取示例
|
||||
|
||||
```bash
|
||||
|
||||
# 登录阿里云镜像仓库(使用 Docker 登录)
|
||||
# 使用阿里云账户 ID 和 RAM 访问密钥或密码
|
||||
docker login registry.cn-hangzhou.aliyuncs.com \
|
||||
@@ -250,6 +253,7 @@ spec:
|
||||
在 ACK 集群中创建 Secret,用于拉取私有镜像:
|
||||
|
||||
```bash
|
||||
|
||||
# 创建镜像拉取 Secret
|
||||
kubectl create secret docker-registry acr-secret \
|
||||
--docker-server=registry.cn-hangzhou.aliyuncs.com \
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
FCC 是 Fedora CoreOS Configuration (Fedora CoreOS 配置) 的简称。
|
||||
|
||||
```yaml
|
||||
|
||||
## example.fcc
|
||||
|
||||
variant: fcos
|
||||
|
||||
@@ -40,6 +40,7 @@ $ podman machine start
|
||||
#### 运行容器
|
||||
|
||||
```bash
|
||||
|
||||
## $ docker run -d -p 80:80 nginx:alpine
|
||||
|
||||
$ podman run -d -p 80:80 nginx:alpine
|
||||
@@ -62,6 +63,7 @@ $ podman build -t myimage .
|
||||
与 Docker 不同,Podman 支持“Pod”的概念 (类似于 Kubernetes 的 Pod),允许你在同一个网络命名空间中运行多个容器。
|
||||
|
||||
```bash
|
||||
|
||||
## 创建一个 Pod
|
||||
|
||||
$ podman pod create --name mypod -p 8080:80
|
||||
@@ -84,6 +86,7 @@ $ alias docker=podman
|
||||
Podman 可以生成 systemd 单元文件,让容器像普通系统服务一样管理。
|
||||
|
||||
```bash
|
||||
|
||||
## 创建容器
|
||||
|
||||
$ podman run -d --name myweb -p 8080:80 nginx
|
||||
|
||||
@@ -49,6 +49,7 @@ $ buildah bud -t my-app:latest .
|
||||
除了使用 Dockerfile,Buildah 最强大的功能来自于它的交互式和脚本化构建机制。我们可以从一个极简的镜像(或基础镜像)开始构建:
|
||||
|
||||
```bash
|
||||
|
||||
# 获取一个基础镜像
|
||||
$ container=$(buildah from alpine:latest)
|
||||
|
||||
@@ -78,6 +79,7 @@ $ buildah rm $container
|
||||
通过 `buildah images` 可以查看当前环境中的镜像。推送镜像到外部 Registry 也十分安全方便:
|
||||
|
||||
```bash
|
||||
|
||||
# 查看本地构建的镜像
|
||||
$ buildah images
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ Kubernetes 作为一个容器编排系统,为了屏蔽底层不同容器运行
|
||||
安装完 containerd 和 nerdctl 后,你可以体验到几乎与 Docker 完全一致的命令行:
|
||||
|
||||
```bash
|
||||
|
||||
# 启动一个 nginx 容器
|
||||
$ nerdctl run -d -p 8080:80 --name my-nginx nginx:alpine
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ $ sudo systemctl restart docker
|
||||
我们可以运行一个简单的容器并执行 `sleep` 命令,同时在宿主机上观察进程的所有者:
|
||||
|
||||
```bash
|
||||
|
||||
## 在容器内以 root 身份运行
|
||||
$ docker run -d --name userns_test alpine sleep 3600
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ $ docker run --rm -it \
|
||||
[Trivy](https://github.com/aquasecurity/trivy) 是由 Aqua Security 发行的一款针对容器技术的快速镜像漏洞扫描利器。在分发应用前通过它的扫描可以规避绝大多数风险。
|
||||
|
||||
```bash
|
||||
|
||||
## 如果使用本地命令行扫描容器镜像
|
||||
$ trivy image alpine:3.10
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ Trivy 是由 Aqua Security 开发的开源漏洞扫描器,以其轻量级、
|
||||
**安装与基本使用:**
|
||||
|
||||
```bash
|
||||
|
||||
# 安装 Trivy
|
||||
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
|
||||
|
||||
@@ -37,6 +38,7 @@ trivy repo https://github.com/aquasecurity/trivy
|
||||
**在 CI/CD 中集成:**
|
||||
|
||||
```bash
|
||||
|
||||
# 设置严重程度过滤
|
||||
trivy image --severity HIGH,CRITICAL \
|
||||
--exit-code 1 \
|
||||
@@ -56,6 +58,7 @@ Grype 由 Anchore 开发,支持更广泛的软件包管理器和语言。
|
||||
**安装与使用:**
|
||||
|
||||
```bash
|
||||
|
||||
# 安装 Grype
|
||||
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
|
||||
|
||||
@@ -83,6 +86,7 @@ Snyk 提供了商业级的安全扫描服务,特别适合企业环境。
|
||||
**基本使用:**
|
||||
|
||||
```bash
|
||||
|
||||
# 安装 Snyk CLI
|
||||
npm install -g snyk
|
||||
|
||||
@@ -124,6 +128,7 @@ curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -
|
||||
**生成 SBOM:**
|
||||
|
||||
```bash
|
||||
|
||||
# 从镜像生成 SBOM(多种格式)
|
||||
syft docker:nginx:latest -o json > sbom.json
|
||||
syft docker:nginx:latest -o spdx > sbom.spdx
|
||||
@@ -188,6 +193,7 @@ syft oci-archive:image.tar -o json > sbom.json
|
||||
当新的 CVE 被发现时,可快速查询受影响的应用:
|
||||
|
||||
```bash
|
||||
|
||||
# 使用 Grype 针对 SBOM 进行漏洞扫描
|
||||
grype sbom:sbom.json --add-cpes-if-none
|
||||
```
|
||||
@@ -220,12 +226,14 @@ sudo mv cosign-linux-amd64 /usr/local/bin/cosign
|
||||
|
||||
```bash
|
||||
cosign generate-key-pair
|
||||
|
||||
# 生成 cosign.key 和 cosign.pub
|
||||
```
|
||||
|
||||
**签名镜像:**
|
||||
|
||||
```bash
|
||||
|
||||
# 使用私钥签名(推送到仓库前)
|
||||
cosign sign --key cosign.key myregistry.com/myapp:v1.0.0
|
||||
|
||||
@@ -235,6 +243,7 @@ cosign sign --key cosign.key myregistry.com/myapp:v1.0.0
|
||||
**验证签名:**
|
||||
|
||||
```bash
|
||||
|
||||
# 使用公钥验证
|
||||
cosign verify --key cosign.pub myregistry.com/myapp:v1.0.0
|
||||
|
||||
@@ -253,6 +262,7 @@ cosign verify --key cosign.pub myregistry.com/myapp:v1.0.0
|
||||
**Keyless 签名(推荐用于 CI/CD):**
|
||||
|
||||
```bash
|
||||
|
||||
# 在 GitHub Actions 等 CI 中无需存储密钥
|
||||
cosign sign --yes myregistry.com/myapp:v1.0.0
|
||||
|
||||
@@ -269,11 +279,13 @@ Docker Content Trust 使用 Notary 实现镜像签名,是 Docker 官方的签
|
||||
**启用 DCT:**
|
||||
|
||||
```bash
|
||||
|
||||
# 在环境中启用 DCT
|
||||
export DOCKER_CONTENT_TRUST=1
|
||||
|
||||
# 此后所有 docker push/pull 都需要签名
|
||||
docker push myregistry.com/myapp:v1.0.0
|
||||
|
||||
# 如果镜像未签名,操作会被拒绝
|
||||
|
||||
# 禁用 DCT(仅用于特定操作)
|
||||
@@ -283,6 +295,7 @@ docker push --disable-content-trust myregistry.com/myapp:v1.0.0
|
||||
**签名密钥管理:**
|
||||
|
||||
```bash
|
||||
|
||||
# 首次推送时会提示创建 Delegation Key
|
||||
# 密钥存储在 ~/.docker/trust/private/root_keys/ 和 ~/.docker/trust/private/tuf_keys/
|
||||
|
||||
@@ -295,6 +308,7 @@ docker inspect --format='{{.RepoDigests}}' myregistry.com/myapp:v1.0.0
|
||||
#### 1. 基础镜像安全
|
||||
|
||||
```dockerfile
|
||||
|
||||
# ❌ 不推荐:使用 latest 标签
|
||||
FROM ubuntu:latest
|
||||
RUN apt-get update && apt-get install -y curl
|
||||
@@ -327,6 +341,7 @@ COPY --from=builder /app/app /app
|
||||
#### 3. 运行时镜像扫描策略
|
||||
|
||||
```bash
|
||||
|
||||
# 镜像构建完成后立即扫描
|
||||
trivy image --severity HIGH,CRITICAL \
|
||||
--exit-code 1 \
|
||||
@@ -342,6 +357,7 @@ trivy image --scanners vuln,misconfig registry:5000/myapp:latest
|
||||
**Harbor(私有镜像仓库)的安全扫描:**
|
||||
|
||||
```yaml
|
||||
|
||||
# harbor.yml 配置示例
|
||||
trivy:
|
||||
enabled: true
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
**基本使用:**
|
||||
|
||||
```bash
|
||||
|
||||
# 实时监控所有运行中的容器
|
||||
docker stats
|
||||
|
||||
@@ -89,6 +90,7 @@ done
|
||||
**性能指标解读:**
|
||||
|
||||
```bash
|
||||
|
||||
# CPU % 超过 80%:需要增加 CPU 限制或优化应用
|
||||
# MEM % 接近 100%:容器即将 OOM,需要增加内存或排查内存泄漏
|
||||
# 如果 NET I/O 中 dropped 为非零:网络拥塞或丢包
|
||||
@@ -132,6 +134,7 @@ networks:
|
||||
**从 cAdvisor 提取指标:**
|
||||
|
||||
```bash
|
||||
|
||||
# 获取所有容器的 JSON 格式性能数据
|
||||
curl http://localhost:8080/api/v1.3/machine | jq .
|
||||
|
||||
@@ -145,6 +148,7 @@ curl http://localhost:8080/api/v1.3/docker/abc123/ | jq '.stats[-1]'
|
||||
**与 Prometheus 集成:**
|
||||
|
||||
```yaml
|
||||
|
||||
# prometheus.yml 配置
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
@@ -259,6 +263,7 @@ scrape_configs:
|
||||
**常用的 Prometheus 查询(PromQL):**
|
||||
|
||||
```text
|
||||
|
||||
# 容器 CPU 使用百分比
|
||||
rate(container_cpu_usage_seconds_total[5m]) * 100
|
||||
|
||||
@@ -289,6 +294,7 @@ count(container_memory_usage_bytes) by (image)
|
||||
#### OOM 问题诊断
|
||||
|
||||
```bash
|
||||
|
||||
# 检查容器是否因 OOM 被杀死
|
||||
docker inspect <container_id> | grep OOMKilled
|
||||
|
||||
@@ -310,6 +316,7 @@ journalctl -u docker -n 100 | grep -i "oom"
|
||||
**Python 应用内存泄漏检测:**
|
||||
|
||||
```python
|
||||
|
||||
# Dockerfile
|
||||
FROM python:3.11-slim
|
||||
WORKDIR /app
|
||||
@@ -321,6 +328,7 @@ CMD ["python", "-m", "memory_profiler", "app.py"]
|
||||
```
|
||||
|
||||
```python
|
||||
|
||||
# app.py - 内存泄漏示例
|
||||
from memory_profiler import profile
|
||||
import tracemalloc
|
||||
@@ -347,6 +355,7 @@ print(f"Peak: {peak / 1024 / 1024:.2f} MB")
|
||||
**Java 应用内存分析:**
|
||||
|
||||
```bash
|
||||
|
||||
# 在容器中启用 JVM 远程调试
|
||||
docker run -e JAVA_OPTS="-Xmx512m -Xms256m -XX:+UseG1GC" \
|
||||
-p 5005:5005 \
|
||||
@@ -363,6 +372,7 @@ jstat -gc <pid> 1000 # 每秒采样一次
|
||||
#### 内存限制最佳实践
|
||||
|
||||
```bash
|
||||
|
||||
# 为容器设置内存限制
|
||||
docker run -m 512m --memory-swap 1g myapp:latest
|
||||
|
||||
@@ -386,6 +396,7 @@ services:
|
||||
**内存超额提交(Memory Overcommit):**
|
||||
|
||||
```bash
|
||||
|
||||
# 在 Docker Compose 中区分限制和预留
|
||||
# limits:绝不能超过的最大值
|
||||
# reservations:Compose 排期时的参考值
|
||||
@@ -407,6 +418,7 @@ services:
|
||||
**使用 dive 分析镜像层:**
|
||||
|
||||
```bash
|
||||
|
||||
# 安装 dive
|
||||
wget https://github.com/wagoodman/dive/releases/download/v0.11.0/dive_0.11.0_linux_amd64.deb
|
||||
sudo apt install ./dive_0.11.0_linux_amd64.deb
|
||||
@@ -420,6 +432,7 @@ dive myapp:latest
|
||||
**使用 Dockerfile 分析工具:**
|
||||
|
||||
```bash
|
||||
|
||||
# 安装 hadolint
|
||||
curl https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64 -L -o hadolint
|
||||
chmod +x hadolint
|
||||
@@ -433,6 +446,7 @@ chmod +x hadolint
|
||||
**Go 应用的最小化镜像构建:**
|
||||
|
||||
```dockerfile
|
||||
|
||||
# Stage 1: 构建阶段
|
||||
FROM golang:1.20-alpine AS builder
|
||||
|
||||
@@ -469,6 +483,7 @@ ENTRYPOINT ["/app"]
|
||||
**Node.js 应用的多阶段构建:**
|
||||
|
||||
```dockerfile
|
||||
|
||||
# Stage 1: 依赖安装
|
||||
FROM node:18-alpine AS dependencies
|
||||
|
||||
@@ -494,6 +509,7 @@ WORKDIR /app
|
||||
|
||||
# 从依赖阶段复制 node_modules
|
||||
COPY --from=dependencies /app/node_modules ./node_modules
|
||||
|
||||
# 从构建阶段复制构建产物
|
||||
COPY --from=builder /app/dist ./dist
|
||||
COPY --from=builder /app/package*.json ./
|
||||
@@ -514,6 +530,7 @@ CMD ["node", "dist/index.js"]
|
||||
**Python 应用的多阶段构建:**
|
||||
|
||||
```dockerfile
|
||||
|
||||
# Stage 1: 构建阶段
|
||||
FROM python:3.11-slim AS builder
|
||||
|
||||
@@ -550,6 +567,7 @@ CMD ["python", "app.py"]
|
||||
#### 镜像体积优化检查清单
|
||||
|
||||
```bash
|
||||
|
||||
# 检查清单
|
||||
□ 使用精简基础镜像(Alpine、Distroless)
|
||||
□ 清理包管理器缓存(apt-get clean、rm -rf /var/cache/*)
|
||||
@@ -585,6 +603,7 @@ RUN apt-get update && \
|
||||
症状:容器进程被无故杀死,exit code 137
|
||||
解决方案:
|
||||
```bash
|
||||
|
||||
# 增加内存限制
|
||||
docker update -m 1g <container_id>
|
||||
|
||||
@@ -603,6 +622,7 @@ docker run -m 512m --memory-swap 1g myapp:latest
|
||||
症状:应用性能突然下降,但 CPU 使用率不高
|
||||
诊断:
|
||||
```bash
|
||||
|
||||
# 查看 CPU 限流统计
|
||||
docker exec <container_id> cat /sys/fs/cgroup/cpu/cpu.stat
|
||||
|
||||
@@ -615,6 +635,7 @@ docker update --cpus 2 <container_id>
|
||||
|
||||
诊断:
|
||||
```bash
|
||||
|
||||
# 进入容器检查网络状态
|
||||
docker exec <container_id> ip -s link show
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
使用 Docker 多阶段构建可以有效减小镜像体积。
|
||||
|
||||
```dockerfile
|
||||
|
||||
## Build stage
|
||||
|
||||
FROM golang:1.23 AS builder
|
||||
|
||||
@@ -48,6 +48,7 @@ func main() {
|
||||
**多阶段 Dockerfile:**
|
||||
|
||||
```dockerfile
|
||||
|
||||
# Stage 1: 构建阶段
|
||||
FROM golang:1.20-alpine AS builder
|
||||
|
||||
@@ -91,6 +92,7 @@ ENTRYPOINT ["/app"]
|
||||
**构建和测试:**
|
||||
|
||||
```bash
|
||||
|
||||
# 构建镜像
|
||||
docker build -t go-app:latest .
|
||||
|
||||
@@ -105,6 +107,7 @@ curl http://localhost:8080/health | jq .
|
||||
|
||||
# 进入容器验证
|
||||
docker exec go-demo ls -la /
|
||||
|
||||
# 只包含 /app 和系统必要文件
|
||||
|
||||
# 镜像大小通常 < 10MB(相比 golang:1.20-alpine 的 ~1GB)
|
||||
@@ -246,6 +249,7 @@ serde_json = "1.0"
|
||||
**多阶段构建 Dockerfile:**
|
||||
|
||||
```dockerfile
|
||||
|
||||
# Stage 1: 编译
|
||||
FROM rust:1.75-alpine AS builder
|
||||
|
||||
@@ -490,6 +494,7 @@ HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
|
||||
|
||||
```ini
|
||||
[mysqld]
|
||||
|
||||
# 性能优化
|
||||
max_connections = 200
|
||||
default_storage_engine = InnoDB
|
||||
@@ -530,6 +535,7 @@ HEALTHCHECK --interval=5s --timeout=3s --retries=5 \
|
||||
**redis.conf 配置:**
|
||||
|
||||
```text
|
||||
|
||||
# 绑定地址
|
||||
bind 0.0.0.0
|
||||
|
||||
@@ -841,6 +847,7 @@ WORKDIR /workspace
|
||||
**Docker Compose 用于 Dev Containers:**
|
||||
|
||||
```yaml
|
||||
|
||||
# .devcontainer/docker-compose.yml
|
||||
version: '3.9'
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ $ cd docker_practice
|
||||
修改代码后提交,并推送到自己的仓库,注意修改提交消息为对应 Issue 号和描述。
|
||||
|
||||
```bash
|
||||
|
||||
# Update the content
|
||||
|
||||
$ git commit -a -s
|
||||
|
||||
@@ -73,6 +73,7 @@ RUN apt-get update && apt-get install -y \
|
||||
> 注意:如果你的字符串中包含空格,必须将字符串放入引号中或者对空格使用转义。如果字符串内容本身就包含引号,必须对引号使用转义。
|
||||
|
||||
```docker
|
||||
|
||||
## Set one or more individual labels
|
||||
|
||||
LABEL com.example.version="0.0.1-beta"
|
||||
@@ -87,6 +88,7 @@ LABEL com.example.version.is-production=""
|
||||
一个镜像可以包含多个标签,但建议将多个标签放入到一个 `LABEL` 指令中。
|
||||
|
||||
```docker
|
||||
|
||||
## Set multiple labels at once, using line-continuation characters to break long lines
|
||||
|
||||
LABEL vendor=ACME\ Incorporated \
|
||||
|
||||
@@ -48,6 +48,7 @@ Docker 安装配置
|
||||
|
||||
**验证学习成果:**
|
||||
```bash
|
||||
|
||||
# 完成以下任务说明基础入门完成
|
||||
1. 运行官方 nginx 镜像,访问 http://localhost
|
||||
2. 使用 docker exec 进入容器修改首页
|
||||
@@ -468,6 +469,7 @@ Kubernetes 进阶 (Week 24-36)
|
||||
|
||||
准备建议:
|
||||
```bash
|
||||
|
||||
# 1. 学习本书第 1-11 章(基础到中级)
|
||||
# 2. 完成 20+ 个实战项目
|
||||
# 3. 参考官方学习指南
|
||||
@@ -781,6 +783,7 @@ A(要点):
|
||||
### 学习进度跟踪模板
|
||||
|
||||
```markdown
|
||||
|
||||
# Docker 学习进度跟踪
|
||||
|
||||
## 第一阶段:基础入门(目标:2 周)
|
||||
@@ -831,6 +834,7 @@ A(要点):
|
||||
**常用命令速查:**
|
||||
|
||||
```bash
|
||||
|
||||
# 镜像管理
|
||||
docker build -t image:tag . # 构建镜像
|
||||
docker images # 列出镜像
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
```docker
|
||||
FROM node:20
|
||||
|
||||
## replace this with your application's default port
|
||||
|
||||
EXPOSE 8888
|
||||
|
||||
Reference in New Issue
Block a user