mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-03-24 10:45:23 +00:00
Add blank lines before headers
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user