【Docker】Dockerfile从概念介绍到快速上手编写案例实战

请添加图片描述




1. Dockerfile介绍

Dockerfile 是用来构建 Docker 镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。(可以理解为 Linux 的 Shell 脚本)

Dockerfile 官网文档:https://docs.docker.com/engine/reference/builder/


1.1 Dockerfile的重要性

前面我的这篇博文【docker commit】中讲解过使用 docker commit 来构建一个带 Vim 命令的 Ubuntu 镜像。在镜像不复杂时可以胜任,但是在实际开发中,微服务代码随时变化和改动,如果我们想把开发的微服务及其所有复杂的中间件以及环境等打包成镜像,用 docker commit 来一条一条地构建镜像就力不从心了。因此我们需要 Dockerfile 来一次搞定所有镜像的构建。

image-20221214104602578

例如,Dockerfile 可以告诉 Docker 服务引擎,本镜像需要一次性添加 Vim 、ifconfig 、Tomcat 8.0 、JDK 1.8 … 只要按照 DockerFile 上的清单来添加,就可以做到构建镜像时一次成型。


1.2 构建三步骤

  1. 编写 Dockerfile 文件
  2. docker build 命令构建镜像
  3. docker run 命令按照镜像运行容器实例

2. Dockerfile构建过程


2.1 Dockerfile内容基础

  1. 每条保留字指令都必须为大写字母,且后面要跟随至少一个参数;
  2. 指令按照从上到下的顺序依次执行;
  3. # 表示注释;
  4. 每条指令都会创建一个新的镜像层,并对镜像进行 commit 提交;

2.2 Dockerfile执行流程

  1. Docker 从基础镜像运行一个容器;
  2. 执行一条指令,并对容器作出修改;
  3. 执行类似 docker commit 的操作,提交一个新的镜像层;
  4. Docker 再基于刚提交的镜像运行一个新容器;
  5. 执行 Dockerfile 中的下一条指令,直到所有指令执行完毕。

多个镜像层构成一个总的最终镜像提交版本供你使用。


2.3 总结

image-20221214110727677

从应用软件的角度看,Dockerfile 、Docker镜像 、Docker 容器分别代表软件的三个不同阶段:

  • Dockerfile 是软件的原材料;
  • Docker 镜像是软件的交付品;
  • Docker 容器则可以认为是软件的运行态,也即按照镜像运行的容器实例。

Dockerfile 面向开发,Docker 镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当 Docker 体系的基石。


3. Dockerfile常用保留字指令

这一节是本篇博文的核心内容,学会 Dockerfile 常用保留字,你就能看懂 Dockerfile 甚至亲自撰写 Dockerfile 。

开始之前,大家可以打开 Tomcat 官方的 Dockerfile 看一眼,有一个感性认识:[Tomcat Dockerfile]


3.1 Dockerfile常用保留字一览

保留字简介
FROM基础镜像
MAINTAINER镜像维护者的姓名和邮箱地址
RUN容器构建时需要执行的命令
EXPOSE当前容器对外暴露的端口
WORKDIR指定创建容器后,终端默认登录进来的工作目录,一个落脚点
USER指定该镜像以什么样的用户去执行,默认是root用户
ENV用来在构建镜像过程中设置环境变量
ADD将宿主机目录下的文件拷贝进镜像,且会自动处理URL和解压tar压缩包
COPY类似 ADD ,拷贝文件和目录到镜像中
VOLUME容器数据卷,用于数据保存和持久化工作
CMD指定容器启动后要干的事
ENTRYPOINT也是值得容器启动时要运行的命令

3.2 保留字讲解

【FROM】

基础镜像,当前镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,Dockerfile 的第一行必须是 FROM 。说人话就是你继承哪个镜像父类。


【RUN】

容器构建时需要执行的命令。即,当运行 docker build 时,就会读取 Dockerfile 中的 RUN 保留字的指令并执行。它有两种格式:Shell 格式和 Exec 格式。我个人更倾向于用 Shell 格式。

  • Shell 格式:

    # <命令行命令>等同于在终端操作的Shell命令
    RUN <命令行命令>
    

    举例:

    RUN yum -y install vim
    

    意思就是,在 FROM 指定的基础镜像创建的容器里,执行 yum -y install vim 这条 Linux Shell 命令,从而在基础镜像的容器中安装 Vim 。

  • Exec 格式:

    RUN ["可执行文件", "参数1", "参数2"]
    

    举例:

    RUN ["./test.php", "dev", "offline"]
    

    等价于

    RUN ./test.php dev offline
    

【WORKDIR】

举例演示 WORKDIR 指的是哪里。例如,我创建一个 Tomcat 容器,以前台交互式启动。

$ docker run -it -p 8080:8080 billygoo/tomcat8-jdk8:latest /bin/bash

image-20221214133633200

我们看到,一进入 Tomcat 容器实例,我们所在的工作目录就是 /usr/local/tomcat 。这就是 Dockerfile 保留字 WORKDIR 指定的。


【ENV】

举例:

ENV MY_PATH /usr/mytest

这个环境变量可以在后续的任何 RUN 命令中使用,这就如同在命令前面指定了环境变量前缀一样。也可以在其他指令中直接使用这些环境变量,例如:

WORKDIR $MY_PATH

【ADD】

将宿主机目录下的文件拷贝进镜像,且会自动处理URL和解压tar压缩包。粗浅地说,ADD 就是 docker cp + 解压命令的合体。我一般更常用 ADD 而不用 COPY

例如,我要在我构建的镜像中安装 JDK 8 ,那么就可以直接把 JDK 1.8 .tar.gz 这个压缩包直接从宿主机上拷贝进镜像中,并自动解压。


【COPY】

相当于 Docker 命令 docker cp 。粗浅地说,COPY 就是不带自动解压功能的 ADD 。将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 。


【CMD】

指定容器启动后要干的事。CMD 指令的格式和 RUN 相似,也是 Shell 格式和 Exec 格式两种格式:

  • Shell 格式:

    # <命令行命令>等同于在终端操作的Shell命令
    RUN <命令行命令>
    
  • Exec 格式:

    RUN ["可执行文件", "参数1", "参数2"]
    
  • 参数列表格式:

    CMD ["参数1", "参数2", ...]
    

    在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数。

注意:

  1. Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,且 CMD 会被 docker run 之后的参数替换。

举例:Tomcat 官网的 Dockerfile 中最后一行的命令:

image-20221214143531248

我们分别演示带/不带参数的情况来运行 Tomcat 容器的情况。

首先是不带任何参数的情况:

$ docker run -it -p 8080:8080 billygoo/tomcat8-jdk8:latest

image-20221214144130363

在 Windows 电脑上浏览器打开 http://192.168.168.101:8080

image-20221214144253232

是能正常访问 Tomcat 首页的。

接下来,我们演示 docker run 后面带有 /bin/bash 参数来启动 Tomcat 容器,这个参数就会替换 Tomcat 官方 Dockerfile 中最后一行的 CMD 命令,从而无法访问 Tomcat 首页。

$ docker run -it -p 8080:8080 billygoo/tomcat8-jdk8:latest /bin/bash

因为在 docker run 最后加了 /bin/bash 参数,Tomcat 的 Dockerfile 最后一行 CMD 命令就相当于被替换成:

CMD ["/bin/bash", "run"]

image-20221214144827199

此时再次在 Windows 电脑上浏览器打开 http://192.168.168.101:8080 就无法访问 Tomcat 首页,因为 docker run 最后加了 /bin/bash 参数替换了 Tomcat 的 Dockerfile 最后一行 CMD 命令。

image-20221214144908222


【ENTRYPOINT】

类似于 CMD 指令,区别是 ENTRYPOINT 不会被 docker run 后面的命令覆盖,且这些命令行参数会被当做参数传递给 ENTRYPOINT 指令指定的程序。

命令格式:

ENTRYPOINT ["可执行文件", "参数1", "参数2", ...]

ENTRYPOINT 可以与 CMD 一起用,一般是变参才会使用 CMD ,这里的 CMD 等于是给 ENTRYPOINT 传参。

当指定了 ENTRYPOINT 后,CMD 的含义就发生了变化,不再是直接运行其命令而是将 CMD 的内容作为参数传递给 ENTRYPOINT 指令,他两个组合会变成 ENTRYPOINT "<CMD>"

举例:假设已通过 Dockerfile 构建了 nginx:test 镜像:

FROM nginx

ENTRYPOINT ["nginx", "-c"] # 固定参数
CMD ["/etc/nginx/nginx.conf"] # 变参
是否传参按照Dockerfile编写执行传参运行
Docker命令docker run nginx:testdocker run nginx:test -c /etc/nginx/new.conf
生成的实际命令nginx -c /etc/nginx/nginx.confnginx -c /etc/nginx/new.conf

4. 案例演示-自定义CentOS镜像

在上面讲解中,如果仍然感到迷惑看不懂,这是非常正常的。下面我将通过一个 Dockerfile 的案例实际演示,来帮助大家更好地理解 Dockerfile 中常用保留字的使用。


4.1 前期准备

本次案例中,我们自定义一个带 JDK8 、Vim 、ifconfig 的 CentOS 7 镜像 mycentosjava8

从远程仓库中拉取 CentOS 7 的镜像。这个原始的 CentOS 镜像里是没有 JDK8 、Vim 、ifconfig 的。注意不要拉取 CentOS 的最新镜像。

$ docker pull centos:7

image-20221214155222057

Oracle 官网下载 JDK 8 。注意要下载 Linux 版的 .tar.gz 格式的压缩包。

image-20221214150900784

把这个压缩包上传至 Linux 宿主机。

image-20221214151232680


4.2 编写Dockerfile

在 Linux 宿主机上创建一个文件夹存放 Dockerfile 。

$ mkdir -p /xsh/myfiles
$ cd /xsh/myfiles

进入这个目录并创建 Dockerfile 。

$ vim Dockerfile

Dockerfile 内容如下:

# 基础镜像,刚刚拉取的centos7镜像
FROM centos:7
# 指定作者和邮箱
MAINTAINER xsh<xiesihang@stu.ouc.edu.cn>

# 指定环境变量
ENV MYPATH /usr/local
# 指定登录镜像容器后的工作目录,引用上面定义的环境变量MYPATH
WORKDIR $MYPATH

# 安装Vim编辑器
RUN yum -y install vim
# 安装ifconfig查看网络IP
RUN yum -y install net-tools
# 安装JDK8及其lib库
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
# ADD是相对路径,把jdk-8u351-linux-x64.tar.gz添加到容器中,安装包的相对路径取决于相对于你的Dockerfile的位置,为了方便与Dockerfile放在同一目录
ADD jdk-8u351-linux-x64.tar.gz /usr/local/java/
# 配置Java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_351
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH

# 对外暴露80端口
EXPOSE 80

# 打印环境变量MYPATH
CMD echo $MYPATH
# 走到这一条命令就打印出构建成功
CMD echo "success-------------ok"
# CentOS需要伪终端交互
CMD /bin/bash

:wq! 保存退出。我们就完成了 Dockerfile 的编写。


4.3 构建镜像

构建镜像的命令格式如下。

$ docker build -t 新镜像名字:TAG .

【注意】

  • 上面 TAG 后面要加一个空格和一个点。
  • 要在 Dockerfile 所在目录下执行该命令。

举例:

本次案例的构建命令这样写:

$ docker build -t centosjava8:1.0 .

image-20221214160210158

构建过程大概需要 10 分钟左右,如果看到上图,就说明构建成功了。如果失败了,则有可能是 yum 需要更新索引,这部分操作自行搜索即可。

查看自定义构建的镜像 centosjava8

$ docker images

image-20221214160609762

可以看见,由于加入了 JDK8 、Vim 、ifconfig ,自定义构建的新 CentOS 镜像从原始的 204 MB 膨胀到 1.24 GB 。


4.4 运行容器

接下来我们创建这个新镜像的容器,来验证是否安装了 JDK8 、Vim 、ifconfig 。

$ docker run -it centosjava8:1.0 /bin/bash

image-20221214161010468

登录进容器后,发现当前所在的工作目录就是 Dockerfile 中 WORKDIR 指定的目录 ENV MYPATH /usr/local

测试 Vim 编辑器是否可用。

$ vim a.txt

image-20221214161218020

测试 ifconfig 命令是否可用。

$ ifconfig

image-20221214161352727

测试 JDK8 是否可用。

$ java -version

image-20221214161458839

三个全部都可以成功使用。那么到这里,自定义的 CentOS 镜像就创建成功了。



专栏精选文章

  1. 《Docker是什么?Docker从介绍到Linux安装图文详细教程》
  2. 《30条Docker常用命令图文举例总结》
  3. 《Docker如何构建自己的镜像?从镜像构建到推送远程镜像仓库图文教程》
  4. 《Docker多个容器和宿主机之间如何进行数据同步和数据共享?容器数据卷从介绍到常用操作图文教程》
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

自牧君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值