👻创作者:丶重明
👻创作时间:2025年4月8日
👻擅长领域:运维
目录
- 1. Dockerfile编写原则
- 1.1.选择合适的基础镜像
- 1.2.镜像层优化
- 1.3.多阶段构建
- 1.4.安全增强
- 2. 关键指令与技巧
- 2.1.COPY vs ADD
- 2.2.ENTRYPOINT vs CMD
- 2.3.健康检查
- 2.4.环境变量管理
- 3. 实战:构建Prometheus镜像
- 4. 附页:Dockerfile指令
1. Dockerfile编写原则
1.1.选择合适的基础镜像
基础镜像的选择直接影响镜像的安全性、体积和可维护性。可以从这三个方面考虑:
- 最小化原则:优先使用轻量级镜像
- 安全扫描:定期检查基础镜像漏洞(使用 docker scan)
- 固定版本:避免使用
latest
标签,明确指定版本号
示例:
# 推荐,这个镜像很小,仅有8MB左右
alpine:3.21.3
# 不推荐,基础镜像过大,版本号不明确
ubuntu:latest
1.2.镜像层优化
Docker 镜像由只读层(Layer)堆叠而成,每一层对应 Dockerfile 中的一条指令。优化层的核心逻辑是减少层数和层体积。
- 合并指令:通过
&& \
合并多个RUN
命令 - 清理缓存:在同一个
RUN
层中删除临时文件 - 层顺序:将高频变化的层(如代码)放在最后
示例:
# 通过&& \这种方式将多个命令合并为一层
RUN apk add --no-cache curl tar && \
curl -LO https://example.com/pkg.tar.gz && \
tar -xzf pkg.tar.gz && \
rm pkg.tar.gz
1.3.多阶段构建
多阶段构建(Multi-stage Build)是减少生产镜像体积的杀手锏。其核心思想是:用“胖”镜像构建,用“瘦”镜像运行。
- 分离构建环境与运行时环境
- 减少最终镜像体积
1.4.安全增强
容器安全是生产环境的核心要求。以下是三个关键实践:
- 非root用户运行
- 限制文件系统写入权限
- 使用 .dockerignore 排除敏感文件
示例:
RUN addgroup -S appgroup && \
adduser -S appuser -G appgroup
USER appuser
2. 关键指令与技巧
2.1.COPY vs ADD
- 优先使用COPY:仅用于复制本地文件
- 谨慎使用ADD:自动解压压缩包,可能引入意外行为
2.2.ENTRYPOINT vs CMD
- ENTRYPOINT:定义容器主进程
- CMD:提供默认参数
示例:
ENTRYPOINT ["/bin/prometheus"]
CMD ["--config.file=/etc/prometheus/prometheus.yml"]
2.3.健康检查
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:9090/-/healthy || exit 1
这一层命令的含义是:
HEALTHCHECK
:为容器设定健康检查机制--interval=30s
:健康检查的时间间隔--timeout=3s
:健康检查命令的超时时间CMD ...
:具体的健康检查命令
每隔 30 秒就向http://localhost:9090/-/healthy
发送一个 HTTP 请求,并且要求在 3 秒内完成。
若请求成功(状态码为 200 - 399),则判定容器健康;若请求失败或者超时,就判定容器不健康。
2.4.环境变量管理
- 使用 ENV 定义常量
- 敏感数据通过 --env-file 或 Secrets 传递
3. 实战:构建Prometheus镜像
dockerfile目录结构:直接在外部目录解压
# tree /prom_docker/
/prom_docker/
├── dockerfile
└── prometheus
├── LICENSE
├── NOTICE
├── prometheus
├── prometheus.yml
└── promtool
1 directory, 6 files
完整的Dockerfile文件:
FROM alpine:3.21.3
# 创建非特权用户
RUN addgroup -S prometheus && \
adduser -S -D -H -s /bin/false -G prometheus prometheus && \
mkdir -p /etc/prometheus /prometheus && \
chown -R prometheus:prometheus /etc/prometheus /prometheus
# 复制必要文件
COPY prometheus/LICENSE prometheus/NOTICE .
COPY prometheus/prometheus \
prometheus/promtool \
/usr/local/bin/
COPY prometheus/prometheus.yml \
/etc/prometheus/
# 设置运行时参数
USER prometheus
WORKDIR /prometheus
EXPOSE 9090
VOLUME ["/prometheus"]
# 健康检查(使用 promtool 无依赖)
HEALTHCHECK --interval=30s --timeout=10s \
CMD ["/usr/local/bin/promtool", "check", "healthy", "--prometheus-url=http://localhost:9090"]
# 入口指令
ENTRYPOINT ["/usr/local/bin/prometheus"]
CMD [ \
"--config.file=/etc/prometheus/prometheus.yml", \
"--storage.tsdb.path=/prometheus", \
"--web.enable-lifecycle", \
"--web.external-url=/" \
]
构建镜像:
[root@localhost prom_docker]# docker build -t prometheus:v3.2.1 .
运行测试:
# docker run -d -p 9090:9090 --name prometheus-1 2c7c81224aa2
b91210a45af9f60c93c7e6652480da8d98a9077818cd2e75c769e3670ec1429d
4. 附页:Dockerfile指令
以下是 Dockerfile 中常见指令及其功能、语法和示例的表格:
指令 | 功能 | 语法 | 示例 |
---|---|---|---|
FROM | 指定基础镜像,是 Dockerfile 的起始指令 | FROM <image>[:<tag>][@<digest>] | FROM python:3.9 |
RUN | 在新的镜像层中执行命令,常用于安装软件包等操作 | RUN <command> (shell 形式)RUN ["executable", "param1", "param2"] (exec 形式) | RUN apt-get update && apt-get install -y python3 RUN ["pip", "install", "flask"] |
CMD | 为容器提供默认的执行命令,一个 Dockerfile 中只能有一个 CMD ,若有多个则只有最后一个生效 | CMD ["executable","param1","param2"] (exec 形式)CMD command param1 param2 (shell 形式)CMD ["param1","param2"] (为 ENTRYPOINT 提供默认参数) | CMD ["python", "app.py"] CMD python app.py |
LABEL | 为镜像添加元数据,如作者、版本等信息 | LABEL <key>=<value> <key>=<value> ... | LABEL maintainer="example@example.com" version="1.0" |
EXPOSE | 声明容器运行时监听的网络端口,但不进行端口映射 | EXPOSE <port> [<port>/<protocol> ...] | EXPOSE 8080 EXPOSE 80/tcp 443/tcp |
ENV | 设置环境变量,在容器运行时可使用 | ENV <key>=<value> ... | ENV APP_NAME=myapp ENV DB_HOST=localhost DB_PORT=5432 |
ADD | 将文件、目录或远程文件复制到镜像中,若复制的是压缩文件会自动解压 | ADD <src>... <dest> | ADD app.tar.gz /app ADD http://example.com/file.txt /tmp/ |
COPY | 将文件或目录从构建上下文复制到镜像中,不具备自动解压和远程文件处理功能 | COPY <src>... <dest> | COPY requirements.txt /app/ |
ENTRYPOINT | 配置容器启动时执行的命令,可与 CMD 结合使用 | ENTRYPOINT ["executable", "param1", "param2"] (exec 形式)ENTRYPOINT command param1 param2 (shell 形式) | ENTRYPOINT ["python", "app.py"] |
VOLUME | 创建挂载点,用于将主机目录或数据卷挂载到容器中 | VOLUME ["/data"] | VOLUME ["/var/lib/mysql"] |
USER | 指定后续 RUN 、CMD 和 ENTRYPOINT 指令执行时的用户和用户组 | USER <user>[:<group>] | USER myuser |
WORKDIR | 设置工作目录,后续的 RUN 、CMD 、ENTRYPOINT 、COPY 和 ADD 指令都会在该目录下执行 | WORKDIR /path/to/workdir | WORKDIR /app |
ARG | 定义构建时的变量,在构建镜像时可通过 --build-arg 传递值 | ARG <name>[=<default value>] | ARG VERSION=1.0 docker build --build-arg VERSION=2.0 . |
ONBUILD | 定义一个触发器,当该镜像被用作其他镜像的基础镜像时,这些指令会在后续的 FROM 指令之后执行 | ONBUILD <INSTRUCTION> | ONBUILD COPY . /app |
STOPSIGNAL | 设置停止容器时发送的系统调用信号 | STOPSIGNAL signal | STOPSIGNAL SIGTERM |
HEALTHCHECK | 配置容器的健康检查命令 | HEALTHCHECK [OPTIONS] CMD <command> HEALTHCHECK NONE | HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ || exit 1 |
SHELL | 覆盖默认的 shell 命令,用于 RUN 、CMD 和 ENTRYPOINT 指令的 shell 形式 | SHELL ["executable", "parameters"] | SHELL ["/bin/bash", "-c"] |