本文最后更新于 2025年1月8日
Dockerfile概述
Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
从应用软件的角度来看,Dockerfile,Docker镜像,Docker容器分别代表软件的三个不同阶段
- Dockerfile是软件的原材料
- Docker镜像是软件的交付品
- Docker容器可以认为是软件的运行态
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及运维和部署,合力充当Docker体系的基石。
Dockerfile定义了进程需要的一切东西,Dockerfile涉及的内容包括执行代码或者文件,环境变量,依赖包,运行时环境,动态链接库,操作系统发行版,服务进程和内核进程(当应用程序需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等。
Docker镜像,在用Dockerfile定义了一个构建文件之后,docker build
时会产生一个Docker镜像,当运行Docker镜像时,会开始真正的提供服务。
Docker容器,是直接提供服务的进程。
Dockerfile构建过程:
- docker从基础镜像运行一个容器
- 执行一条指令,并对容器进行修改
- 执行类似
docker commit
的操作,提交一个新的镜像层
- docker再基于刚刚提交的镜像运行一个新容器
- 继续执行Dockerfile的下一条指令,直到所有指令都执行完成
Dockerfile的保留字指令
Dockerfile每个保留字指令均为大写,且后面至少跟随一个参数,指令从上到下顺序执行,用#
表示注释。
FROM
基本出现在第一行,意思是要构建的新镜像继承于或者说基于哪个已存在的镜像。
MAINTAINR
维护者信息(姓名和邮箱地址)
ENV
用于在构建镜像的过程中设置环境变量,这个环境变量可以在后续的任何RUN
指令中使用,就像在命令前面指定了环境变量一样,也可以在其他指令中直接使用这些环境变量,比如WORKDIR $JAVA_HOME
RUN
容器构建(docker build)时需要运行的命令,分为shell
和exec
两种格式
shell
exec
EXPOSE
声明容器运行时应该开放的端口。它不会自动开启端口,但为外部用户或其他容器提供信息
WORKDIR
指定在创建容器后,终端默认登录进来的工作目录,当执行docker run -it 镜像ID /bash
进入容器内部的时候,会默认落脚在哪个目录里
USER
指定镜像以什么用户去执行,如果不指定,默认是root
VOLUME
容器数据卷,用于数据的保存和持久化,声明容器内的哪个目录需要在运行时挂载数据卷到宿主机上
ADD
ADD
功能相比COPY
更加强大,将宿主机内的文件拷贝进镜像,如果源文件是.tar
、.tar.gz
等压缩格式的文件,ADD
会自动解压到目标路径。ADD
还可以从指定的URL下载文件并复制到容器内。
COPY
仅仅执行文件的复制,不支持自动解压或下载
CMD
指定容器启动后要做的事情,支持shell
和exec
两种格式,还支持参数列表格式,如果指定了ENTRYPOINT
指令,CMD
就会被用来指定具体的运行参数
注意事项
1.RUN
和CMD
的区别: RUN
是构建镜像时执行,CMD
是docker run
容器启动时执行
2.Dockerfile中可以有多个CMD
指令,但只有最后一个生效,CMD
会被docker run
之后的参数替换
例如:tomcat的Dockerfile的最后一行是CMD ["catalina.sh", "run"]
,那么使用docker run -it tomcat /bin/bash
命令启动这个镜像时,容器会启动,但是tomcat就不会被启动,因为被run
后的命令/bin/bash
替换掉了,故容器启动后会运行/bin/bash
ENTRYPOINT
类似于CMD
命令,但是不会被docker run
后的命令覆盖,而且还会把docker run
后的命令当作命令行参数传递给ENTRYPOINT
指令指定的程序
ENTRYPOINT
可以和CMD
一起用,一般是变参才会使用到CMD
,这里的CMD
等同于是在给ENTRYPOINT
传参,当指定了ENTRYPOINT
后,CMD
的含义就发生了变化,不再是直接运行其命令而是将CMD
的内容作为参数传递给ENTRYPOINT
指令,它们两个组合后会变成<ENTRYPOINT> "<CMD>"
案例:
|
按照Dockerfile原样执行 |
传参运行 |
Docker命令 |
docker run nginx |
docker run nginx /etc/nginx/kms.conf |
容器实际执行 |
nginx -c /etc/nginx/nginx.conf |
nginx -c /etc/nginx/kms.conf |
如果写成docker run nginx -c /etc/nginx/kms.conf
也可以实现参数替换,-c
不会被重复的叠加成docker run nginx -c -c /etc/nginx/kms.conf
,因为ENTRYPOINT本身未包含-c
,而CMD提供了-c
的值
用Dockerfile构建镜像
编写一个Dockerfile,用于构建一个自带Java17环境的RockyLinux9镜像,构建的镜像基于发行版rockylinux:8.9
,新镜像内新增vim
,net-tools
组件,并将下载好的jdk17拷贝进去,并设置jdk相关的环境变量,让这个镜像构建的容器自带原版镜像不默认安装的一些工具,并且自带jdk17
找到一个空文件夹,vim Dockerfile
编辑文件将构建命令写进去
编写完成后,再将要打包进去的jdk-17.0.12_linux-x64_bin.tar.gz
放在同级目录,然后在这个目录内执行docker build
命令,会用当前目录(.
)下的Dockerfile构建镜像,镜像名称和标签是rockey8_jdk17:1.0.0
执行输出
提示构建成功,查看一下自己构建的镜像
用交互模式用刚刚构建成的镜像运行一个容器,执行命令java -version
验证打包进去的jdk和环境变量,构建成功!
虚悬镜像
定义:REPOSITORY
和TAG
都是<none>
的镜像(dangling image),是由于构建和删除镜像时产生一些错误导致的,虚悬镜像会占用空间,因此需要清理掉它们
查出
清理