Docker Dockerfile | 菜鸟教程 (runoob.com)
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
构建步骤:
1、编写 DockerFile 文件
2、docker build 构建镜像
3、docker run 运行镜像
4、docker push 发布镜像(DockerHub,阿里云镜像仓库)
查看一下官方是怎么做的
在 dockerHub 上搜索 centos,选个 tag点进去 ,就可以看到 DockerFile 文件了:
sig-cloud-instance-images/Dockerfile at b2d195220e1c5b181427c3172829c23ab9cd27eb · CentOS/sig-cloud-instance-images · GitHub
很多官方镜像都是基础包,很多功能没有,我们通常自己搭建自己的镜像!如:CentOS + JDK + Tomcat + MySQL + Redis
基础知识:
1、每条保留关键字(指令)都必须为大写字母
2、指令按照从上到下的顺序执行
3、# 表示注释
4、每条指令都会创建一个新的镜像层,并提交这个镜像层
DockerFile 是面向开发者的,以后要发布项目,做镜像,就需要编写 DockerFile 文件,这个文件十分简单!
Docker 逐渐成为企业交付的标准,尽量学会吧!!卷啊,摆烂和躺平真香!!!
步骤: 开发,部署,运维!!
DockerFile:构建文件,定义了一切的步骤,源代码!
DockerImages:通过 DockerFile 构建生成的镜像,最终发布和运行的产品!
Docker容器 :容器就是镜像运行起来提供服务的!
说明:
从应用软件的角度来看,DockerFile,Docker镜像与Docker容器分别代表软件的三个不同阶段。
DockerFile 是软件的原材料 (源代码)
Docker 镜像 则是软件的交付品 (.apk 应用文件)
Docker 容器 则是软件的运行状态 (客户下载安装运行)
DockerFile 面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可!
指令 | 命令摘要 |
---|---|
FROM | 构建镜像基于哪个镜像 |
MAINTAINER | 镜像维护者信息,如姓名或邮箱地址 |
RUN | 构建镜像时运行的指令,每一次RUN都会构建一层 |
CMD | 运行容器时执行的 shell 环境。如果有多个则以最后一个为准,也可以为 ENTRYPOINT 提供参数 |
ENTRYPOINT | 运行容器时执行的 shell 命令。容器进入时执行的命令。可以追加命令。 |
COPY | 拷贝文件或目录到容器中,跟ADD类似,但不具备自动下载或解压的功能。以复制的形式 |
ADD | 拷贝文件或目录到容器中,如果是URL或压缩包便会自动下载或自动解压。 |
ENV | 设置容器环境变量。变量属性值,容器内部也会起作用 |
ARG | 构建时指定的一些参数。变量属性值,但不在容器内部起作用 |
VOLUME | 指定容器挂载点到宿主机自动生成的目录或其他容器。如果没有定义则使用默认 |
EXPOSE | 声明容器的服务端口(仅仅是声明)。暴露端口 |
USER | 为RUN、CMD、和 ENTRYPOINT 执行命令指定运行用户 |
WORKDIR | 镜像的工作目录。为 RUN、CMD、ENTRYPOINT、COPY 和 ADD 设置工作目录,就是切换目录 |
HEALTHCHECH | 健康检测指令 |
ONBUILD | 当构建一个被继承的 DockerFile 时运行命令,父镜像在被子镜像继承后,父镜像的 ONBUILD 被触发。触发指令 |
FROM # 基础镜像,一切从这里开始构建,当前新镜像是基于哪个镜像的
MAINTAINER # 镜像作者的姓名+邮箱地址
RUN # 容器构建时需要运行的命令
EXPOSE # 当前容器对外保留出的端口。暴露端口配置!
WORKDIR # 指定在创建容器后,终端默认登录的进来工作目录。
ENV # 用来在构建镜像过程中设置环境变量!构建时设置环境变量!Mysql密码,JVM参数等!
ADD # 将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包。如添加 Tomcat 压缩包。
COPY # 类似ADD,拷贝文件和目录到镜像中!将我们的文件拷贝到镜像中!
VOLUME # 容器数据卷,用于数据保存和持久化工作。挂载的目录!
CMD # 指定一个容器启动时要运行的命令,dockerFile中可以有多个CMD指令,但只有最后一个生效,可被替代!
ENTRYPOINT # 指定一个容器启动时要运行的命令!和CMD一样!可以追加命令!
ONBUILD # 当构建一个被继承的DockerFile时运行命令,父镜像在被子镜像继承后,父镜像的ONBUILD被触发。触发指令!
FROM:定制的镜像都是基于 FROM 的镜像。
# 基于基础镜像
FROM scratch
# 基于centos
FROM centos
LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法如下:
# 格式:
LABEL = = = ...
# 比如我们可以添加镜像的作者:
LABEL org.opencontainers.image.authors="mianbao"
RUN:用于执行后面跟着的命令行命令。
# shell 格式
RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。
# exec 格式
RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline
注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:
FROM centos
RUN yum -y install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz
以上执行会创建 3 层镜像。可简化为以下格式:
FROM centos
RUN yum -y install wget \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& tar -xvf redis.tar.gz
如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。
类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
# 格式:
CMD # 这种格式实际上在运行的过程中会自动转换成第二种格式运行
CMD ["<可执行文件或命令>","","",...] # 推荐使用格式,执行过程比较明确。默认可执行文件是 .sh。
CMD ["","",...] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
但是, 如果运行 docker run 时使用了 --entrypoint
选项,将覆盖 ENTRYPOINT 指令指定的程序。
优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。
注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
# 格式:
ENTRYPOINT ["","","",...]
可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。
**示例:**假设已通过 Dockerfile 构建了 nginx:test 镜像:
FROM nginx
ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参
1、不传参运行
$ docker run nginx:test
# 容器内会默认运行以下命令,启动主进程。
$ nginx -c /etc/nginx/nginx.conf
2、传参运行
$ docker run nginx:test -c /etc/nginx/new.conf
# 容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)
$ nginx -c /etc/nginx/new.conf
复制指令,从上下文目录中复制文件或者目录到容器里指定路径。
# 格式:
COPY [--chown=:] <源路径1>... <目标路径>
COPY [--chown=:] ["<源路径1>",... "<目标路径>"]
# [--chown=:]:可选参数,用户改变复制到容器内文件的拥有者和属组。
<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。
<目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
COPY hom* /mydir/
COPY hom?.txt /mydir/
ADD 指令和 COPY 的使用格式类似(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
# 格式:
ENV
ENV = =...
示例: 设置 NODE_VERSION = 7.2.0 ,在后续的指令中可以通过 $NODE_VERSION 引用:
ENV NODE_VERSION 7.2.0
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"
构建参数,与 ENV 作用一致。不过作用域不同。ARG 设置的环境变量仅对 Dockerfile 内有效,即只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。构建命令 docker build 中可以用 –build-arg <参数名>=<值> 来覆盖。
# 格式:
ARG <参数名>[=<默认值>]
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。作用:避免重要的数据,因容器重启而丢失,这是非常致命的;避免容器不断变大。
在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
# 格式:
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
仅仅只是声明端口。作用:
# 格式:
EXPOSE <端口1> [<端口2>...]
指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。
docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。
# 格式:
WORKDIR <工作目录路径>
用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
# 格式:
USER <用户名>[:<用户组>]
用于指定某个程序或者指令来监控 docker 容器服务的运行状态。
# 格式:
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。
用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。
# 格式:
ONBUILD <其它指令>
CMD 指定一个容器启动时要运行的命令,但只有最后一个生效,可被替代!
ENTRYPOINT 指定一个容器启动时要运行的命令,可以追加命令!
CMD 命令测试
# 创建 dockerfile
[root@localhost dockerfile]$ vim dockerfile-cmd-test
[root@localhost dockerfile]$ cat dockerfile-cmd-test
FROM centos:centos7
CMD ["ls", "-a"]
# 构建镜像
[root@localhost dockerfile]$ docker build -f dockerfile-cmd-test -t cmd-test:1.0 .
Sending build context to Docker daemon 4.096kB
Step 1/2 : FROM centos:centos7
---> eeb6ee3f44bd
Step 2/2 : CMD ["ls", "-a"]
---> Running in 1a5ca4268543
Removing intermediate container 1a5ca4268543
---> 4f1c5614fc97
Successfully built 4f1c5614fc97
Successfully tagged cmd-test:1.0
# 运行测试, 直接运行 ls -a 这个命令
[root@localhost dockerfile]$ docker run 4f1c5614fc97
.
..
.dockerenv
anaconda-post.log
bin
dev
etc
home
............
usr
var
# 想追加一个命令 -l ,理想是实现 ls -al 这个命令
[root@localhost dockerfile]$ docker run 4f1c5614fc97 -l
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "-l": executable file not found in $PATH: unknown.
# -l 替换了 CMD ["ls","-a"] 命令,-l 不是命令,所以报错了
# 替换需要写完整的命令
[root@localhost dockerfile]$ docker run 4f1c5614fc97 ls -al
total 12
drwxr-xr-x. 1 root root 6 Jul 5 15:09 .
drwxr-xr-x. 1 root root 6 Jul 5 15:09 ..
-rwxr-xr-x. 1 root root 0 Jul 5 15:09 .dockerenv
-rw-r--r--. 1 root root 12114 Nov 13 2020 anaconda-post.log
lrwxrwxrwx. 1 root root 7 Nov 13 2020 bin -> usr/bin
drwxr-xr-x. 5 root root 340 Jul 5 15:09 dev
drwxr-xr-x. 1 root root 66 Jul 5 15:09 etc
drwxr-xr-x. 2 root root 6 Apr 11 2018 home
................................................
drwxr-xr-x. 13 root root 155 Nov 13 2020 usr
drwxr-xr-x. 18 root root 238 Nov 13 2020 var
ENTRYPOINT 命令测试
# 创建 dockerfile
[root@localhost dockerfile]$ vim dockerfile-entrypoint-test
[root@localhost dockerfile]$ cat dockerfile-entrypoint-test
FROM centos:centos7
ENTRYPOINT ["ls", "-a"]
# 构建镜像
[root@localhost dockerfile]$ docker build -f dockerfile-entrypoint-test -t entrypoint-test:1.0 .
Sending build context to Docker daemon 5.12kB
Step 1/2 : FROM centos:centos7
---> eeb6ee3f44bd
Step 2/2 : ENTRYPOINT ["ls", "-a"]
---> Using cache
---> 7806e33422a8
Successfully built 7806e33422a8
Successfully tagged entrypoint-test:1.0
# 运行了 ls -a 命令
[root@localhost dockerfile]$ docker run 7806e33422a8
......
# 运行了 ls -al 命令。
[root@localhost dockerfile]# docker run 7806e33422a8 -l
......
# 这里就是一种追加,我们可以明显的知道 CMD 和ENTRYPOINT 的区别了
总结
DockerFile 中很多命令都十分相似,需要详细了解它们的区别,最好的学习就是对比然后测试效果!