1.什么是Dockerfile
Dockerfile 是一个用于指导 Docker 镜像构建过程的脚本文件。它通过一系列指令来详细描述了构建镜像所需的步骤和配置细节。利用 Dockerfile,我们可以精确地设定容器的运行环境,安装必要的软件,复制项目文件,以及配置环境变量等。
Dockerfile 的优势在于其可重复性和自动化,使得应用程序的容器化过程既高效又可靠。通过将构建过程代码化,我们能够对构建步骤进行版本控制,并在不同的环境中复现相同的镜像。
Dockerfile 的组成通常包括以下几个方面:指定基础镜像、提供维护者信息、执行镜像构建指令以及定义容器启动时要运行的命令。
在 Dockerfile 中,指令是按照从上到下的顺序执行的,且首个非注释指令必须是 FROM,用以指定基础镜像。Dockerfile 中的注释以"#"开头。
Dockerfile 支持多种指令,例如 RUN、CMD、FROM、EXPOSE、ENV 等,这些指令帮助我们定义镜像的操作系统、安装软件、设置环境变量等。
编写完 Dockerfile 后,我们可以通过执行 docker build 命令并指定 Dockerfile 的位置来构建镜像。Docker 引擎将按照 Dockerfile 中的指令逐步构建,最终生成一个新的镜像。
综上所述,Dockerfile 是一个关键工具,它通过简洁明了的文本指令,帮助我们自动化和标准化 Docker 镜像的构建过程,从而简化了容器化应用程序的部署工作。
2.Dockerfile 中常用的指令
|-------------|----------------------------------|
| 指令 | 说明 |
| FROM | 指定基础镜像 |
| MAINTAINER | 设置维护者信息 |
| RUN | 在镜像中执行命令 |
| CMD | 指定容器启动时要执行的命令 |
| ENTRYPOINT | 与 CMD 类似,但不会被 docker run 命令行参数覆盖 |
| COPY | 复制文件或目录到镜像中 |
| ADD | 复制文件或目录到镜像中,支持远程 URL 和解压缩功能 |
| ENV | 设置环境变量 |
| ARG | 定义构建时的变量,可以通过 --build-arg 参数传递 |
| WORKDIR | 设置工作目录 |
| USER | 指定运行容器时的用户名或 UID |
| EXPOSE | 声明容器运行时需要监听的端口 |
| HEALTHCHECK | 定义容器的健康检查命令 |
| VOLUME | 声明容器中的挂载点 |
| LABEL | 为镜像添加元数据 |
注意事项:
FROM
- 尽量使用官方镜像作为基础镜像,以确保稳定性和安全性。
- 指定镜像时,最好使用具体标签(例如
ubuntu:20.04
而不是ubuntu:latest
),以避免构建时的不一致性。MAINTAINER(已废弃,推荐使用 LABEL)
- 请注意,MAINTAINER 指令已被废弃,现在推荐使用 LABEL 指令来设置维护者信息。
RUN
- 为了保持 Dockerfile 的可读性和可维护性,尽量使用
&&
来链式执行命令,并使用\
来换行。- 尽可能使用
RUN apt-get clean
来清理缓存,减少镜像大小。CMD
- CMD 指令的目的是为执行容器提供默认值,如果
docker run
指定了命令,CMD 会被覆盖。- 当 Dockerfile 中有多个 CMD 指令时,只有最后一个 CMD 会生效。
ENTRYPOINT
- ENTRYPOINT 与 CMD 结合使用可以设置容器启动时要执行的默认命令和参数。
- 使用
ENTRYPOINT ["executable", "param1", "param2"]
的形式可以确保docker run
的参数被追加到param1
,param2
后面。COPY 和 ADD
- 尽可能使用 COPY 而不是 ADD,除非你需要 ADD 的额外功能(如解压缩)。
- 为了提高可读性,请明确指定源路径和目标路径。
ENV
- 使用 ENV 来设置环境变量,可以在后续的指令中使用这些变量。
- 尽量将环境变量设置在 Dockerfile 的顶部,以便于其他指令引用。
ARG
- ARG 指令定义的变量只在构建时有效,容器运行时不可用。
- 使用 ARG 定义的变量可以在
docker build
时通过--build-arg
传递。WORKDIR
- 使用 WORKDIR 而不是多个 RUN 指令中的
cd
,以确保路径的清晰性和一致性。USER
- 使用 USER 指令来指定运行容器的用户,以减少安全风险。
EXPOSE
- EXPOSE 指令只是声明容器将监听指定的端口,并不会自动映射端口到宿主机。
HEALTHCHECK
- 使用 HEALTHCHECK 来检测容器的健康状态,这对于自动重启失败的容器很有用。
VOLUME
- 使用 VOLUME 来管理容器的数据持久化,避免数据丢失。
LABEL
- 使用 LABEL 来添加元数据,便于组织镜像和记录版本信息。
这些指令可以根据需要灵活组合,构建出符合需求的 Docker 镜像。请注意,Dockerfile 中的指令顺序很重要,因为每个指令都会创建一个新的镜像层,而后续的指令将基于前面的镜像层进行操作。
更详细的指令说明和用法,请参考 Docker 官方文档:
Dockerfile reference | Docker Docs
3.dockerfile基本结构和构建镜像原则
3.1 基本结构

3.2 构建基本原则
dockerfile构建镜像需要遵循一下原则:
- 单一职责:每个层级只做每个层级的事
- 提供注释信息:最好提供注释信息,以便他人理解
- 保持容器最小化
- 合理选择基础镜像:基础镜像的选择很重要,尽量选择成熟易用的基础镜像版本
- 最小化镜像层数:镜像层数不宜过多,尽量精简,否则容易出错,也可能会影响加载速度

通过上面的示例图可以看出,每多一行命令,镜像的内容就多一层。
其他注意事项:
- 尽量减少镜像层数,可以通过合并 RUN 指令来实现。
- 使用
.dockerignore
文件排除不必要的文件和目录,减少构建上下文的大小。- 保持 Dockerfile 的简洁性,避免在其中执行复杂的操作,尽可能在构建上下文中准备数据。
- 定期更新基础镜像以包含最新的安全补丁。
4.Dockerfile使用示例
4.1 基于centos8镜像构建nginxWeb服务镜像
以下是一个简单的 Dockerfile示例,以构建一个基于 centos 的配置web服务的镜像:
1.创建构建上下文目录:
bash
[root@open-Euler3 ~]# mkdir dockerfile_test
2.本地添加nginx测试界面用于COPY
bash
[root@open-Euler3 ~]# echo "nginx test" > dockerfile_test/index.html
3.编写Dockerfile文件
bash
[root@open-Euler3 dockerfile_test]# cat Dockerfile
# 1. 第一行必须指定基础镜像信息
ARG VER=8
FROM centos:${VER}
# 2. 作者信息
LABEL maintainer="openlab <openlab@123.com>"
# 3. 安装 nginx
RUN mkdir -p /etc/yum.repos.d/bak_repo && \
mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bak_repo/ 2>/dev/null || true && \
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-8.repo && \
dnf clean all && \
dnf makecache && \
dnf install -y nginx
# 4. 复制静态文件
COPY index.html /usr/share/nginx/html
# 5. 暴露端口
EXPOSE 80 443
# 6. 启动服务
ENTRYPOINT ["/usr/sbin/nginx", "-g", "daemon off;"]
4.docker build 构建镜像

注意:-t选项指定构建出镜像的标签 最后的 "." 指定的是当前目录,也就是构建上下文目录,Dockerfile所在的目录
5.查看构建的镜像
bash
[root@open-Euler3 dockerfile_test]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos_nginx latest 7ca95c53855e 2 minutes ago 342MB
ubuntu 18.04 f9a80a55f492 21 months ago 63.2MB
reg.yym.com/openlab/ubuntu 18.04 f9a80a55f492 21 months ago 63.2MB
centos 8 5d0da3dc9764 3 years ago 231MB
6.启动容器并进行测试:

4.2 基于ubuntu镜像配置SSH服务
要求:
1、基础镜像ubuntu:18.04。
2、替换为国内的安装源(比如阿里或163)。
3、安装openssh-server。
4、允许root用户远程登录。
5、暴露端口22。
6、服务开机自启动。
1.创建构建上下文目录:
bash
[root@open-Euler3 dockerfile_ssh]# pwd #这是我的构建上下文位置
/root/dockerfile_ssh
2.文件准备
1)apt源:
bash
[root@open-Euler3 dockerfile_ssh]# cat 163.list
deb http://mirrors.163.com/ubuntu/ bionic main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ bionic-security main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ bionic-updates main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ bionic-backports main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ bionic main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ bionic-security main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ bionic-updates main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu/ bionic-backports main restricted universe multiverse
2)客户端公钥文件
bash
[root@open-Euler3 dockerfile_ssh]# ssh-keygen -f ~/.ssh/id_rsa -P '' -q #生成公私钥
[root@open-Euler3 dockerfile_ssh]# cp ~/.ssh/id_rsa.pub ./authorized_keys
3)准备启动脚本文件
bash
[root@open-Euler3 dockerfile_ssh]# cat run.sh
#!/bin/bash
/usr/sbin/sshd -D
[root@open-Euler3 dockerfile_ssh]# chmod +x run.sh
4)编写Dockerfile文件
bash
[root@open-Euler3 dockerfile_ssh]# vim Dockerfile
FROM ubuntu:18.04
MAINTAINER "kongd <kongd@11.com>"
RUN mv /etc/apt/sources.list /etc/apt/sources.bak
COPY aliyun.list /etc/apt/sources.list.d/aliyun.list
RUN apt update && apt install -y openssh-server && mkdir -p /var/run/sshd
RUN sed -ri 's/session required pam_loginuid.so/#session required pam_loginuid.so/' /etc/pam.d/sshd
COPY run.sh /run.sh
RUN chmod +x /run.sh
RUN mkdir /root/.ssh
COPY authorized_keys /root/.ssh/authorized_keys
EXPOSE 22/tcp
CMD ["/run.sh"]
docker build 构建镜像)

查看镜像:
bash
[root@open-Euler3 dockerfile_ssh]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ssh1_image latest 98ea77f917f0 4 minutes ago 248MB
centos_nginx latest fb1d61ed3b60 3 hours ago 342MB
ubuntu 18.04 f9a80a55f492 21 months ago 63.2MB
reg.yym.com/openlab/ubuntu 18.04 f9a80a55f492 21 months ago 63.2MB
centos 8 5d0da3dc9764 3 years ago 231MB
通过构建的镜像启动一个容器:
bash
[root@open-Euler3 dockerfile_ssh]# docker run -itd --name ssh1_c1 -p 10022:22 ssh1_image
cfec71666b634dfbfea43427cf1846d9516bcc3a9806f923a6391e560a721319
[root@open-Euler3 dockerfile_ssh]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cfec71666b63 ssh1_image "/run.sh" 3 seconds ago Up 3 seconds 0.0.0.0:10022->22/tcp, :::10022->22/tcp ssh1_c1
测试ssh免密登录:

可以看到直接通过映射后的宿主机IP+端口登录到容器的shell上。