Add blank lines around headers

This commit is contained in:
yeasy
2026-03-24 09:27:04 -07:00
parent 2f7985225a
commit 76c2ae50fe
112 changed files with 468 additions and 0 deletions
+4
View File
@@ -30,6 +30,7 @@ COPY . . # 复制到 /app/
RUN cd /app
RUN echo "hello" > world.txt # 文件在根目录!
```
#### 原因分析
```dockerfile
@@ -110,6 +111,7 @@ RUN npm install
COPY . .
CMD ["node", "server.js"]
```
#### 2. 使用绝对路径
```docker
@@ -121,6 +123,7 @@ WORKDIR /app
WORKDIR app
```
#### 3. 不要用 RUN cd
```docker
@@ -133,6 +136,7 @@ RUN cd /app && echo "hello" > world.txt
WORKDIR /app
RUN echo "hello" > world.txt
```
#### 4. 适时重置 WORKDIR
```docker
+6
View File
@@ -55,6 +55,7 @@ USER appuser
CMD ["node", "server.js"]
```
#### 使用 UID/GID
```docker
@@ -80,6 +81,7 @@ USER nonexistent
RUN useradd -r -s /bin/false appuser
USER appuser
```
#### 创建用户的方式
**Debian/Ubuntu**
@@ -139,6 +141,7 @@ chown -R redis:redis /data
exec gosu redis "$@"
```
#### 为什么不用 su/sudo
| 问题 | su/sudo | gosu |
@@ -208,6 +211,7 @@ CMD ["myapp"]
CMD ["myapp"] # 以 root 运行
```
#### 2. 使用固定 UID/GID
便于在宿主机和容器间共享文件
@@ -219,6 +223,7 @@ RUN addgroup -g 1000 -S appgroup && \
adduser -u 1000 -S -G appgroup appuser
USER 1000:1000
```
#### 3. 多阶段构建中的 USER
```docker
@@ -252,6 +257,7 @@ permission denied: '/app/data.log'
```docker
RUN mkdir -p /app/data && chown appuser:appuser /app/data
```
#### Q无法绑定低于 1024 的端口
root 用户无法绑定 80443 等端口
+4
View File
@@ -40,6 +40,7 @@ RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -fs http://localhost/ || exit 1
```
#### 命令返回值
- `0`成功 (healthy)
@@ -82,6 +83,7 @@ HEALTHCHECK CMD curl -f http://localhost/ || exit 1
HEALTHCHECK CMD wget -q --spider http://localhost/ || exit 1
```
#### 数据库
```docker
@@ -93,6 +95,7 @@ HEALTHCHECK CMD mysqladmin ping -h localhost || exit 1
HEALTHCHECK CMD redis-cli ping || exit 1
```
#### 自定义脚本
```docker
@@ -178,6 +181,7 @@ $ docker inspect --format '{{json .State.Health}}' mycontainer | jq
HEALTHCHECK --start-period=60s CMD curl -f http://localhost/ || exit 1
```
#### 4. 只检查核心依赖
健康检查应主要关注 **当前服务** 是否可用而不是检查其下游依赖 (数据库等)下游依赖的检查应由应用逻辑处理
+3
View File
@@ -76,6 +76,7 @@ FROM 基础镜像 ──build──> 读取基础镜像触发器 ──> 执行
ONBUILD COPY requirements.txt ./
ONBUILD RUN pip install -r requirements.txt
```
#### 2. 自动编译代码
```docker
@@ -84,6 +85,7 @@ ONBUILD RUN pip install -r requirements.txt
ONBUILD COPY . .
ONBUILD RUN go build -o app main.go
```
#### 3. 处理静态资源
```docker
@@ -127,6 +129,7 @@ ONBUILD COPY dist/ /usr/share/nginx/html/
node:20-onbuild
python:3.12-onbuild
```
#### 2. 避免执行耗时操作
尽量不要在 `ONBUILD` 中执行过于耗时或不确定的操作 (如更新系统软件)这会让子镜像构建变得缓慢且不可控
+2
View File
@@ -26,6 +26,7 @@ LABEL <key>=<value> <key>=<value> ...
LABEL version="1.0"
LABEL description="这是一个 Web 应用服务器"
```
#### 定义多个标签推荐
```docker
@@ -119,6 +120,7 @@ $ docker inspect nginx --format '{{json .Config.Labels}}' | jq
"maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
}
```
#### 过滤器
可以使用标签过滤镜像
+3
View File
@@ -31,6 +31,7 @@ SHELL ["/bin/bash", "-c"]
RUN echo {a..z}
```
#### 2. 增强错误处理
默认情况下管道命令 `cmd1 | cmd2` 只要 `cmd2` 成功整个指令就视为成功这可能掩盖构建错误
@@ -51,6 +52,7 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN wget -O - https://invalid-url | tar xz
```
#### 3. Windows 环境
Windows 容器中经常需要在 `cmd` `powershell` 之间切换
@@ -122,6 +124,7 @@ RUN echo "Using sh again"
```docker
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
```
#### 2. 明确意图
如果由于脚本需求必须更改 shell最好在 Dockerfile 中显式声明而不是依赖默认行为
+3
View File
@@ -46,6 +46,7 @@ CMD ["./app"]
```bash
$ docker build -t go/helloworld:1 -f Dockerfile.one .
```
### 7.17.2 分散到多个 Dockerfile
另一种方式就是我们事先在一个 `Dockerfile` 将项目及其依赖库编译测试打包好后再将其拷贝到运行环境中这种方式需要我们编写两个 `Dockerfile` 和一些编译脚本才能将其两个阶段自动整合起来这种方式虽然可以很好地规避第一种方式存在的风险但明显部署过程较复杂
@@ -110,6 +111,7 @@ REPOSITORY TAG IMAGE ID CREATED SIZE
go/helloworld 2 f7cf3465432c 22 seconds ago 6.47MB
go/helloworld 1 f55d3e16affc 2 minutes ago 295MB
```
### 7.17.3 使用多阶段构建
为解决以上问题Docker v17.05 开始支持多阶段构建 (`multistage builds`)使用多阶段构建我们就可以很容易解决前面提到的问题并且只需要编写一个 `Dockerfile`
@@ -168,6 +170,7 @@ FROM golang:alpine as builder
```bash
$ docker build --target builder -t username/imagename:tag .
```
### 7.17.5 构建时从其他镜像复制文件
上面例子中我们使用 `COPY --from=0 /go/src/github.com/go/helloworld/app .` 从上一阶段的镜像中复制文件我们也可以复制任意镜像中的文件
@@ -54,6 +54,7 @@ server {
}
}
```
### 7.18.2 前端构建
第一阶段进行前端构建
@@ -74,6 +75,7 @@ RUN set -x ; cd /app \
&& mkdir -p public \
&& npm run production
```
### 7.18.3 安装 Composer 依赖
第二阶段安装 Composer 依赖
@@ -93,6 +95,7 @@ RUN set -x ; cd /app \
--no-scripts \
--prefer-dist
```
### 7.18.4 整合以上阶段所生成的文件
第三阶段对以上阶段生成的文件进行整合
@@ -118,6 +121,7 @@ RUN set -x ; cd ${LARAVEL_PATH} \
&& chmod -R 777 storage \
&& php artisan package:discover
```
### 7.18.5 最后一个阶段构建 NGINX 镜像
```docker
@@ -128,6 +132,7 @@ ARG LARAVEL_PATH=/app/laravel
COPY laravel.conf /etc/nginx/conf.d/
COPY --from=laravel ${LARAVEL_PATH}/public ${LARAVEL_PATH}/public
```
### 7.18.6 构建 Laravel Nginx 镜像
使用 `docker build` 命令构建镜像
@@ -137,6 +142,7 @@ $ docker build -t my/laravel --target=laravel .
$ docker build -t my/nginx --target=nginx .
```
### 7.18.7 启动容器并测试
新建 Docker 网络
+3
View File
@@ -55,6 +55,7 @@ RUN apt-get update && \
apt-get install -y nginx && \
rm -rf /var/lib/apt/lists/*
```
#### 2. 清理缓存
在安装完软件后立即清除缓存可以显著减小镜像体积
@@ -103,6 +104,7 @@ RUN touch hello.txt
WORKDIR /app
RUN touch hello.txt
```
#### Q环境变量不生效
```docker
@@ -136,6 +138,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
RUN --mount=type=cache,target=/go/pkg/mod \
go build -o app
```
#### 2. 挂载密钥
安全地使用 SSH 密钥或 Token而不将其记录在镜像中
+7
View File
@@ -23,6 +23,7 @@ COPY package.json /app/
COPY config.json /app/settings.json
```
#### 复制多个文件
```docker
@@ -35,6 +36,7 @@ COPY package.json package-lock.json /app/
COPY *.json /app/
COPY src/*.js /app/src/
```
#### 复制目录
```docker
@@ -77,6 +79,7 @@ COPY app[0-9].js /app/ # app0.js ~ app9.js
```docker
COPY app.js /usr/src/app/
```
#### 相对路径基于 WORKDIR
```docker
@@ -84,6 +87,7 @@ WORKDIR /app
COPY package.json ./ # 复制到 /app/package.json
COPY src/ ./src/ # 复制到 /app/src/
```
#### 自动创建目录
如果目标目录不存在Docker 会自动创建
@@ -174,6 +178,7 @@ RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
```
#### 使用 --link 优化缓存
```docker
@@ -227,6 +232,7 @@ COPY . .
COPY . .
RUN npm install
```
#### 2. 使用 .dockerignore
```docker
@@ -238,6 +244,7 @@ COPY . .
...
```
#### 3. 明确复制路径
```docker
+6
View File
@@ -51,6 +51,7 @@ ADD 会识别并解压以下格式:
FROM scratch
ADD ubuntu-noble-core-cloudimg-amd64-root.tar.gz /
```
#### 解压过程
```bash
@@ -76,6 +77,7 @@ app.tar.gz 包含: /app/ 目录结果:
ADD https://example.com/app.zip /app/app.zip
```
#### 为什么不推荐
| 问题 | 说明 |
@@ -127,6 +129,7 @@ ADD rootfs.tar.gz /
ADD dist.tar.gz /app/
```
#### 不适合使用 ADD
```docker
@@ -180,6 +183,7 @@ ADD app.tar.gz /app/
COPY . /app/
```
#### 2. 仅在需要解压时使用 ADD
```docker
@@ -187,6 +191,7 @@ COPY . /app/
ADD app.tar.gz /app/
```
#### 3. 不要用 ADD 下载文件
```docker
@@ -198,6 +203,7 @@ ADD https://example.com/file.tar.gz /tmp/
RUN curl -fsSL https://example.com/file.tar.gz | tar -xz -C /app
```
#### 4. 解压后清理
```docker
+8
View File
@@ -111,6 +111,7 @@ CMD ["/bin/bash"] + cat /etc/os-release
CMD service nginx start
```
#### 原因分析
```bash
@@ -126,6 +127,7 @@ CMD service nginx start
6. 容器主进程sh退出 容器停止
```
#### 正确做法
```docker
@@ -153,6 +155,7 @@ CMD ["curl", "-s", "http://example.com"]
$ docker run myimage # 执行默认命令
$ docker run myimage curl -v ... # 完全覆盖
```
#### 搭配 ENTRYPOINT
```docker
@@ -182,6 +185,7 @@ CMD ["python", "app.py"]
CMD ["sh", "-c", "echo $PATH && python app.py"]
```
#### 2. 确保应用在前台运行
```docker
@@ -196,6 +200,7 @@ CMD ["java", "-jar", "app.jar"]
CMD service nginx start
CMD systemctl start nginx
```
#### 3. 使用双引号
```docker
@@ -207,6 +212,7 @@ CMD ["node", "server.js"]
CMD ['node', 'server.js']
```
#### 4. 配合 ENTRYPOINT 使用
```docker
@@ -233,6 +239,7 @@ $ docker run myapp --port 9000
CMD ["echo", "first"]
CMD ["echo", "second"] # 只有这个生效
```
#### Q如何在 CMD 中使用环境变量
```docker
@@ -244,6 +251,7 @@ CMD echo "Port is $PORT"
CMD ["sh", "-c", "echo Port is $PORT"]
```
#### Q为什么我的容器不响应 Ctrl+C
可能是使用了 shell 格式信号被 sh 吃掉了
+7
View File
@@ -95,6 +95,7 @@ exec: "-i": executable file not found
...
```
#### 使用 ENTRYPOINT 解决
```docker
@@ -111,6 +112,7 @@ HTTP/1.1 200 OK
...
当前 IP61.148.226.66
```
#### 交互图示
```bash
@@ -160,6 +162,7 @@ fi
exec "$@"
```
#### 工作流程
```bash
@@ -173,6 +176,7 @@ docker-entrypoint.sh redis-server docker-entrypoint.sh bash
exec gosu redis redis-server exec bash
( redis 用户运行) ( root 用户运行)
```
#### 关键点
1. **exec $@**用传入的参数替换当前进程确保信号正确传递
@@ -261,12 +265,14 @@ ENTRYPOINT ["python", "app.py"]
ENTRYPOINT python app.py
```
#### 2. 提供有意义的默认参数
```docker
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]
```
#### 3. 入口脚本使用 exec
```bash
@@ -278,6 +284,7 @@ CMD ["-g", "daemon off;"]
exec "$@"
```
#### 4. 处理信号
确保 ENTRYPOINT 脚本能正确传递信号
+8
View File
@@ -21,6 +21,7 @@ ENV <key1>=<value1> <key2>=<value2> ...
ENV NODE_VERSION 20.10.0
ENV APP_ENV production
```
#### 设置多个变量
```docker
@@ -53,6 +54,7 @@ WORKDIR $APP_HOME
COPY . $APP_HOME
```
#### 2. 容器运行时使用
```docker
@@ -106,6 +108,7 @@ $ docker run -e APP_ENV=development -e DEBUG=true myimage
$ docker run --env-file .env myimage
```
#### .env 文件格式
```bash
@@ -165,6 +168,7 @@ RUN apt-get install nginx=${NGINX_VERSION}
RUN apt-get install nginx=1.25.0
```
#### 2. 不要存储敏感信息
```docker
@@ -178,6 +182,7 @@ ENV DB_PASSWORD=secret123
...
```
#### 3. 为应用提供合理默认值
```docker
@@ -185,6 +190,7 @@ ENV APP_ENV=production \
APP_PORT=8080 \
LOG_LEVEL=info
```
#### 4. 使用有意义的变量名
```docker
@@ -215,12 +221,14 @@ CMD ["python", "app.py", "--port", "$PORT"]
CMD ["sh", "-c", "python app.py --port $PORT"]
```
#### Q如何查看容器的环境变量
```bash
$ docker inspect mycontainer --format '{{json .Config.Env}}'
$ docker exec mycontainer env
```
#### Q多行 ENV 还是多个 ENV
```docker
+8
View File
@@ -43,6 +43,7 @@ ARG NODE_VERSION=20
FROM node:${NODE_VERSION}-alpine
RUN echo "Using Node.js $NODE_VERSION"
```
#### 构建时覆盖
```bash
@@ -72,6 +73,7 @@ FROM ${REGISTRY}/${IMAGE_NAME}:20
RUN echo $REGISTRY # 输出空
```
#### FROM 之后重新声明
```docker
@@ -84,6 +86,7 @@ FROM node:${NODE_VERSION}-alpine
ARG NODE_VERSION
RUN echo "Node version: $NODE_VERSION"
```
#### 多阶段构建中的 ARG
```docker
@@ -116,6 +119,7 @@ FROM alpine:${ALPINE_VERSION}
```bash
$ docker build --build-arg ALPINE_VERSION=3.18 .
```
#### 2. 设置软件版本
```docker
@@ -123,6 +127,7 @@ ARG NGINX_VERSION=1.25.0
RUN curl -fsSL https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz | tar -xz
```
#### 3. 配置构建环境
```docker
@@ -135,6 +140,7 @@ RUN if [ "$ENABLE_DEBUG" = "true" ]; then \
npm install --production; \
fi
```
#### 4. 配置私有仓库
```docker
@@ -199,6 +205,7 @@ ARG NODE_VERSION=20
ARG NODE_VERSION
```
#### 2. 不要用 ARG 存储敏感信息
```docker
@@ -211,6 +218,7 @@ RUN echo "password=$DB_PASSWORD" > /app/.env
...
```
#### 3. 使用 ARG 提高构建灵活性
```docker
+7
View File
@@ -47,6 +47,7 @@ flowchart LR
FROM mysql:8.0
VOLUME /var/lib/mysql
```
#### 定义多个卷
```docker
@@ -67,6 +68,7 @@ $ docker volume ls
DRIVER VOLUME NAME
local a1b2c3d4e5f6... # 自动创建的匿名卷
```
#### 2. 可被命名卷覆盖
```bash
@@ -74,6 +76,7 @@ local a1b2c3d4e5f6... # 自动创建的匿名卷
$ docker run -v mysql_data:/var/lib/mysql mysql:8.0
```
#### 3. 可被 Bind Mount 覆盖
```bash
@@ -120,12 +123,14 @@ VOLUME /data
FROM postgres:16
VOLUME /var/lib/postgresql/data
```
#### 日志目录
```docker
FROM nginx
VOLUME /var/log/nginx
```
#### 上传文件目录
```docker
@@ -212,6 +217,7 @@ $ docker run -v mysql_data:/var/lib/mysql mysql:8.0
FROM postgres:16
VOLUME /var/lib/postgresql/data
```
#### 2. 不要在 VOLUME 后修改目录
```docker
@@ -225,6 +231,7 @@ RUN cp init-data.json /app/data/
RUN mkdir -p /app/data && cp init-data.json /app/data/
VOLUME /app/data
```
#### 3. 文档中说明 VOLUME 用途
```docker
+4
View File
@@ -44,6 +44,7 @@ EXPOSE 80 443
$ docker inspect nginx --format '{{.Config.ExposedPorts}}'
map[80/tcp:{}]
```
#### 2. 配合 -P 使用
使用 `docker run -P` Docker 会自动映射 EXPOSE 的端口到宿主机随机端口
@@ -75,6 +76,7 @@ flowchart TD
Run["docker run -p<br/>实际端口映射<br/>宿主机 ←→ 容器"]
Expose ~~~ Run
```
#### 没有 EXPOSE 也能 -p
```docker
@@ -145,6 +147,7 @@ EXPOSE 5432
FROM redis
EXPOSE 6379
```
#### 2. 使用明确的协议
```docker
@@ -160,6 +163,7 @@ EXPOSE 53/udp
EXPOSE 53/tcp 53/udp
```
#### 3. 与应用实际端口保持一致
```docker