Dockerfile
基本结构
Dockerfile 是一个文本格式的配置文件,用户可以使用 Dockerfile 快速创建自定义镜像。
Dockerfile 由一行行命令语句组成,并且支持以 # 开头的注释行。
Docker分为四部分:
- 基础镜像信息
- 维护者信息
- 镜像操作指令
- 容器启动时默认要执行的指令
例如:
# This dockerfile uses the ubuntu image
# VERSION 2 - EDITION 1
# Author: seancheng
# Command format: Instruction [arguments / command] ...
# 第一行必须指定基于的基础镜像
FROM ubuntu
# 维护者信息
LABEL MAINTAINER='seancheng xianshangxian@126.com'
# 镜像操作指令
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
# 容器启动时默认要执行的指令
CMD /usr/sbin/nginx
其中,一开始必须指明所基于的镜像名称,接下来一般会说明维护者信息。
后面则是镜像操作指令,例如RUN指令,RUN指令将对镜像执行跟随的命令。每运行一条RUN指令,镜像添加新的一层,并提交。
最后是CMD指令来指定运行容器时的操作指令。
指令
指令的一般格式为INSTRUCTION arguments
,指令包括:
- FROM
- LABEL MAINTAINER
- RUN
- CMD
- EXPOSE
- ENV
- ADD
- COPY
- ENTRYPOINT
- VOLUME
- USER
- WORKDIR
- ONBUILD
指令名字 | 作用 |
---|---|
FROM | 基础镜像,一切从这里开始构建 |
MAINTAINER | 镜像是谁写的,姓名+邮箱 |
RUN | 镜像构建的时候需要运行的命 |
ADD | 提供安装包位置 |
WORKDIR | 镜像的工作目录 |
VOLUME | 挂载的目录 |
EXPOSE | 暴露端口配置 |
CMD | 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代 |
ENTRYPOINT | 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代 |
ENTRYPOINT | 当构建一个被继承 Dockerfile 这个时候就会运行ONBUILD 的指令 |
COPY | 类似ADD,将我们文件拷贝到镜像中 |
ENV | ENV |
FROM
格式为FROM <image>
或FROM <image>:<tag>
。
第一条指令必须为FROM指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令(每个镜像一次)。
FROM centos:8(默认是最新版本)
LABEL MAINTAINER
格式为LABEL MAINTAINER <name email_address>
,指定维护者信息
LABEL MAINTAINER='syblyw0806 123@qq.com'
RUN
格式为RUN <command>
或RUN ["executable","param1","param2"]
。
前者将在shell终端中运行命令,即/bin/sh -c;后者则使用exec执行。指定使用其他终端可以通过第二种方式实现,例如:
RUN ["/bin/bash","-c","echo hello"]
[root@localhost ~]# mkdir test
[root@localhost ~]# cd test/
[root@localhost test]# cat Dockerfile
FROM centos
RUN mkdir abc
[root@localhost test]# docker build -t test:v0.1 /root/test/
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM centos
---> 5d0da3dc9764
Step 2/2 : RUN mkdir abc
---> Running in 1cc3cd5aa69d
Removing intermediate container 1cc3cd5aa69d
---> 37ec05f5a1ac
Successfully built 37ec05f5a1ac
Successfully tagged test:v0.1
[root@localhost test]# docker run -it --rm test:v0.1
[root@95d5cf5be279 /]# ls
abc etc lib64 mnt root srv usr
bin home lost+found opt run sys var
dev lib media proc sbin tmp
[root@localhost test]# cat Dockerfile
FROM centos
RUN ["/usr/bin/mkdir","-p","/hehe/xixi/haha"]
[root@localhost test]# docker build -t test:v0.2 /root/test/
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM centos
---> 5d0da3dc9764
Step 2/2 : RUN ["/usr/bin/mkdir","-p","/hehe/xixi/haha"]
---> Running in 36392aa44fb9
Removing intermediate container 36392aa44fb9
---> baf7fce2f1d7
Successfully built baf7fce2f1d7
Successfully tagged test:v0.2
[root@localhost test]# docker run -it --rm test:v0.2
[root@4d9d5dfddfc7 /]# ls
bin hehe lib64 mnt root srv usr
dev home lost+found opt run sys var
etc lib media proc sbin tmp
[root@4d9d5dfddfc7 /]# cd hehe/
[root@4d9d5dfddfc7 hehe]# ls xixi/
haha
每条RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行,例如:
RUN echo "hello world\nhello tom" > /tmp/abc && \
cat /tmp/abc
[root@localhost test]# cat Dockerfile
FROM centos
RUN echo "hello world\nhello tom" > /tmp/abc && \
cat /tmp/abc
CMD
CMD支持三种格式:
CMD ["executable","param1","param2"]
使用exec执行,推荐方式CMD command param1 param2
在/bin/sh中执行,提供给需要交互的应用CMD ["param1","param2"]
提供给ENTRYPOINT的默认参数
CMD用于指定启动容器时默认要执行的命令,每个Dockerfile只能有一条CMD命令。如果指定了多条命令,只有最后一条会被执行。
// 使用CMD第二种格式
[root@localhost test]# cat Dockerfile
FROM centos
CMD sleep 600 // 当CMD只有这一条的时候就执行当前命令
[root@localhost test]# docker build -t test:v0.4 /root/test
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM centos
---> 5d0da3dc9764
Step 2/2 : CMD sleep 600
---> Running in c8334041d0d8
Removing intermediate container c8334041d0d8
---> 04b29b18007f
Successfully built 04b29b18007f
Successfully tagged test:v0.4
[root@localhost test]# docker run -itd --rm test:v0.4
e332f6d2b7e49bfd1b536ba8d4c2dd8fa2473b84b2fd33280ba5d503b493f429
[root@localhost test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e332f6d2b7e4 test:v0.4 "/bin/sh -c 'sleep 6…" 3 seconds ago Up 2 seconds trusting_chaplygin
[root@localhost test]# cat Dockerfile
FROM centos
CMD sleep 600
CMD sleep 700
CMD sleep 800 // 当CMD有三条的时候,只会执行最后一条命令
[root@localhost test]# docker build -t test:v0.5 /root/test/
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos
---> 5d0da3dc9764
Step 2/4 : CMD sleep 600
---> Using cache
---> 04b29b18007f
Step 3/4 : CMD sleep 700
---> Running in 0894d1cb0ee8
Removing intermediate container 0894d1cb0ee8
---> c8dc64c9276e
Step 4/4 : CMD sleep 800
---> Running in a8d504b7b9b1
Removing intermediate container a8d504b7b9b1
---> a1bb66d8c5d2
Successfully built a1bb66d8c5d2
Successfully tagged test:v0.5
[root@localhost test]# docker run -itd --rm test:v0.5
f95fb66e5c16a446984a2e88648a85465deb7569e82664997eebc7dad960064d
[root@localhost test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f95fb66e5c16 test:v0.5 "/bin/sh -c 'sleep 8…" 2 seconds ago Up 2 seconds vigorous_ritchie
如果用户启动容器时指定了运行的命令,则会覆盖掉CMD指定的命令。
[root@localhost test]# docker images
[root@localhost test]# cat Dockerfile
FROM centos
CMD ["sleep","400"]
[root@localhost test]# docker build -t test:v0.8 /root/test/
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM centos
---> 5d0da3dc9764
Step 2/2 : CMD ["sleep","400"]
---> Running in faffd15f9944
Removing intermediate container faffd15f9944
---> 0c1864ac64c6
Successfully built 0c1864ac64c6
Successfully tagged test:v0.8
// 没有覆盖是这样的
[root@localhost test]# docker run -itd --rm test:v0.8
b4e6f4625d04b824cf7dc324c50ef603c31e3366464006bc067ba9b5a4a7288d
[root@localhost test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b4e6f4625d04 test:v0.8 "sleep 400" 5 seconds ago Up 4 seconds strange_chandrasekhar
[root@localhost test]# docker rm -f b4e6f4625d04
b4e6f4625d04
// 覆盖之后 sleep 400 变成 /bin/bash
[root@localhost test]# docker run -itd --rm test:v0.8 /bin/bash
fbf0ec0e58fdf49358aca74efd2575464724fef5afa15890cc93193916016e65
[root@localhost test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fbf0ec0e58fd test:v0.8 "/bin/bash" 5 seconds ago Up 4 seconds naughty_albattani
使用CMD第一种格式在前台运行httpd(推荐使用这种格式)
[root@localhost test]# cat Dockerfile
FROM centos
RUN ["/usr/bin/dnf","-y","install","httpd"]
CMD ["/usr/sbin/httpd","-D","FOREGROUND"]
[root@localhost test]# docker build -t test:v0.7 /root/test/
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM centos
---> 5d0da3dc9764
Step 2/3 : RUN ["/usr/bin/dnf","-y","install","httpd"]
---> Using cache
---> e044e1eda4ef
Step 3/3 : CMD ["/usr/sbin/httpd","-D","FOREGROUND"]
---> Running in b717a91a43cc
Removing intermediate container b717a91a43cc
---> db064b1650f0
Successfully built db064b1650f0
Successfully tagged test:v0.7
// 在前台运行
[root@localhost test]# docker run -it --rm test:v0.7
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6ac21f0b46b6 test:v0.7 "/usr/sbin/httpd -D …" 5 seconds ago Up 4 seconds sleepy_wu
[root@localhost test]# docker inspect b1c2a92754ec
"Cmd": [
"/usr/sbin/httpd",
"-D",
"FOREGROUND"
EXPOSE
格式为EXPOSE <port> [<port>...]
。
例如:
EXPOSE 22 80 8443
EXPOSE用于告诉Docker服务器容器暴露的端口号,供互联系统使用。
[root@localhost test]# cat Dockerfile
FROM centos
RUN ["/usr/bin/dnf","-y","install","httpd"]
CMD ["/usr/sbin/httpd","-D","FOREGROUND"]
EXPOSE 80 // 只是用来暴露端口,用来看的
[root@localhost test]# docker build -t test:v0.1 /root/test/
[root@localhost test]# docker run -it --rm test:v0.1
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0fb783f7177e test:v0.1 "/usr/sbin/httpd -D …" 5 seconds ago Up 3 seconds 80/tcp adoring_sutherland // 80端口已暴露
[root@localhost ~]# docker inspect 0fb783f7177e
"ExposedPorts": {
"80/tcp": {}
[root@localhost test]# cat Dockerfile
FROM centos
RUN ["/usr/bin/dnf","-y","install","httpd"]
CMD ["/usr/sbin/httpd","-D","FOREGROUND"]
EXPOSE 80 443 // 暴露80端口和443端口
[root@localhost test]# docker build -t test:v0.2 /root/test/
Sending build context to Docker daemon 9.878MB
Step 1/4 : FROM centos
---> 5d0da3dc9764
Step 2/4 : RUN ["/usr/bin/dnf","-y","install","httpd"]
---> Using cache
---> 1f572fe047ea
Step 3/4 : CMD ["/usr/sbin/httpd","-D","FOREGROUND"]
---> Using cache
---> aee89390c009
Step 4/4 : EXPOSE 80 443
---> Running in 9c07b2de3205
Removing intermediate container 9c07b2de3205
---> 9851cc87915a
Successfully built 9851cc87915a
Successfully tagged test:v0.2
[root@localhost test]# docker run -d test:v0.2
00cef3fbd5a27ac9c9c26ad2bc00378ef74a77a4747dce53ddc4a82fdcd3868d
[root@localhost test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
00cef3fbd5a2 test:v0.2 "/usr/sbin/httpd -D …" 7 seconds ago Up 6 seconds 80/tcp, 443/tcp laughing_snyder // 虽然暴露了443端口,但是实际主机没有443端口,无法访问。所以EXPOSE主要是用来暴露以后用的到端口
在启动容器时通过-P,Docker主机会自动分配一个端口转发到指定的端口;
使用-p则可以具体指定哪个本地端口映射过来。
ENV
格式为ENV <key> <value>
。指定一个环境变量,会被后续RUN指令使用,并在容器运行时保持。例如:
ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4 // 定义变量
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && ...
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH // 定义环境变量
指定一个环境变量,会被后续RUN指令使用,并在容器运行时保持。例如:
[root@localhost test]# cat Dockerfile
FROM centos
ENV NAME syb // 创建一个变量NAME
EXPOSE 80 443
[root@localhost test]# docker build -t test:v0.3 /root/test/
Sending build context to Docker daemon 9.878MB
Step 1/3 : FROM centos
---> 5d0da3dc9764
Step 2/3 : ENV NAME syb
---> Running in 1b6de8792c77
Removing intermediate container 1b6de8792c77
---> 53e1f2c60b44
Step 3/3 : EXPOSE 80 443
---> Running in bec56994993a
Removing intermediate container bec56994993a
---> 79c1d18361d4
Successfully built 79c1d18361d4
Successfully tagged test:v0.3
[root@localhost test]# docker run -it --rm test:v0.3
[root@f1ecb8394940 /]# echo $NAME
syb
[root@localhost test]# cat Dockerfile
FROM centos
ENV PATH /usr/local/apache/bin:$PATH // 创建一个环境变量
[root@localhost test]# docker build -t test:v0.4 /root/test/
Sending build context to Docker daemon 9.878MB
Step 1/2 : FROM centos
---> 5d0da3dc9764
Step 2/2 : ENV PATH /usr/local/apache/bin:$PATH
---> Running in 23e518f2d5c2
Removing intermediate container 23e518f2d5c2
---> b4f926e2cc3b
Successfully built b4f926e2cc3b
Successfully tagged test:v0.4
[root@localhost test]# docker run -it --rm test:v0.4
[root@7a0d85cdd435 /]# echo $PATH
/usr/local/apache/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ADD
格式为ADD <src> <dest>
。
ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
该命令将复制指定的到容器中的。其中可以是Dockerfile所在目录的一个相对路径(文件或目录);也可以是一个URL;还可以是一个tar文件(会自动解压为目录)。
ADD指令跟COPY类似,不过它还支持使用tar文件和URL路径。
当拷贝的源文件是tar文件时,会自动展开为一个目录并拷贝进新的镜像中;然而通过URL获取到的tar文件不会自动展开。
主机可以联网的情况下,docker build可以将网络上的某文件引用下载并打包到新的镜像
# 转移文件
// 创建一个abc文件
[root@localhost test]# echo "hello syb" > abc
// 创建files目录,上传httpd包上去
[root@localhost test]# mkdir files
[root@localhost test]# cd files/
[root@localhost files]# ls
httpd-2.4.51.tar.gz
[root@localhost test]# ls
Dockerfile abc files
[root@localhost test]# cp -r files/httpd-2.4.51.tar.gz .
[root@localhost test]# ls
Dockerfile abc files httpd-2.4.51.tar.gz
// 运行dockerfile创建一个test:v0.5镜像
[root@localhost ~]# docker build -t test:v0.5 /root/test/
Sending build context to Docker daemon 19.75MB
Step 1/2 : FROM centos
---> 5d0da3dc9764
Step 2/2 : ADD abc /opt
---> 957a71bf1809
Successfully built 957a71bf1809
Successfully tagged test:v0.5
[root@localhost test]# cat Dockerfile
FROM centos
ADD abc /opt
/ / abc文件已放到容器opt目录里面
[root@localhost ~]# docker run -it --rm test:v0.5
[root@0b6780cd1e88 /]# ls /opt/
abc
[root@0b6780cd1e88 /]# cat /opt/abc
hello syb
# 转移目录里面的内容
[root@localhost test]# cat Dockerfile
FROM centos
ADD files /opt // 同步文件里面的内容
[root@localhost ~]# docker build -t test:v0.6 /root/test/
Sending build context to Docker daemon 19.75MB
Step 1/2 : FROM centos
---> 5d0da3dc9764
Step 2/2 : ADD files /opt
---> fcddfc756666
Successfully built fcddfc756666
Successfully tagged test:v0.6
[root@localhost ~]# docker run -it --rm test:v0.6
[root@4ce0cef18abb /]# ls /opt/ // files目录里面的httpd安装包已放到容器的opt里面
httpd-2.4.51.tar.gz
# 同步tar文件,会自动解压为目录
[root@localhost test]# cat Dockerfile
FROM centos
ADD httpd-2.4.51.tar.gz /opt
[root@localhost ~]# docker build -t test:v0.7 /root/test/
Sending build context to Docker daemon 19.75MB
Step 1/2 : FROM centos
---> 5d0da3dc9764
Step 2/2 : ADD httpd-2.4.51.tar.gz /opt
---> 14ec6f6ac9c5
Successfully built 14ec6f6ac9c5
Successfully tagged test:v0.7
[root@localhost ~]# docker run -it --rm test:v0.7
[root@d83e68526471 /]# ls /opt/
httpd-2.4.51 // 安装包自动解压为目录
# url
[root@localhost test]# cat Dockerfile
FROM centos
ADD https://downloads.apache.org/httpd/httpd-2.4.51.tar.gz /opt // 写入url地址
[root@localhost ~]# docker build -t test:v0.8 /root/test/
Sending build context to Docker daemon 19.75MB
Step 1/2 : FROM centos
---> 5d0da3dc9764
Step 2/2 : ADD https://downloads.apache.org/httpd/httpd-2.4.51.tar.gz /opt
Downloading 9.874MB/9.874MB
---> 76db49dd904f
Successfully built 76db49dd904f
Successfully tagged test:v0.8
[root@localhost ~]# docker run -it --rm test:v0.8
[root@1aef8e2649b1 /]# ls /opt/
httpd-2.4.51.tar.gz // 直接下载,把下载好的安装包放到容器里面
// 还可以配置ENV使用,以后下载包直接更换版本就行
[root@localhost test]# cat Dockerfile
FROM centos
ENV version 2.4.48
ADD https://downloads.apache.org/httpd/httpd-${version}.tar.gz /opt
[root@localhost ~]# docker build -t test:v0.9 /root/test/
Sending build context to Docker daemon 19.75MB
Step 1/3 : FROM centos
---> 5d0da3dc9764
Step 2/3 : ENV version 2.4.48
---> Using cache
---> 75f478b3f205
Step 3/3 : ADD https://downloads.apache.org/httpd/httpd-${version}.tar.gz /opt
Downloading 9.174MB/9.174MB
---> 22f807c2e840
Successfully built 22f807c2e840
Successfully tagged test:v0.9
[root@localhost ~]# docker run -it --rm test:v0.9
[root@f36ea252908c /]# ls /opt/
httpd-2.4.48.tar.gz
COPY
格式为COPY <src> <dest>
。
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
复制本地主机的(为Dockerfile所在目录的相对路径,文件或目录)为容器中的。目标路径不存在时会自动创建。
使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等
如果是目录,只复制目录内容,而非目录本身
当使用本地目录为源目录时,推荐使用COPY。
[root@localhost test]# ls
Dockerfile abc files httpd-2.4.51.tar.gz
// 编写COPY指令
[root@localhost test]# cat Dockerfile
FROM centos
COPY abc /opt
COPY files /opt
// 执行Dockerfile
[root@localhost test]# docker build -t test:v0.1 /root/test
Sending build context to Docker daemon 9.878MB
Step 1/3 : FROM centos
---> 5d0da3dc9764
Step 2/3 : COPY abc /opt
---> 1348d8d8d436
Step 3/3 : COPY files /opt
---> ecb883e5c2f6
Successfully built ecb883e5c2f6
Successfully tagged test:v0.1
// 运行容器查看
[root@localhost test]# docker run -it --rm test:v0.1 /bin/bash
[root@3962b08df6b7 /]# ls
bin home lost+found opt run sys var
dev lib media proc sbin tmp
etc lib64 mnt root srv usr
[root@3962b08df6b7 /]# ls /opt/
abc httpd-2.4.51.tar.gz
[root@3962b08df6b7 /]# cat /opt/abc
hello syb // copy成功将abc文件和files目录的安装包复制过去了
copy复制tar安装包不会解压,是原封不动复制过去
[root@localhost test]# cat Dockerfile
FROM centos
COPY httpd-2.4.51.tar.gz /opt
[root@localhost ~]# docker build -t test:v0.10 /root/test/
Sending build context to Docker daemon 19.75MB
Step 1/2 : FROM centos
---> 5d0da3dc9764
Step 2/2 : COPY httpd-2.4.51.tar.gz /opt
---> 461119937a33
Successfully built 461119937a33
Successfully tagged test:v0.10
[root@localhost ~]# docker run -it --rm test:v0.10
[root@e3ab18c4c712 /]# ls /opt/
httpd-2.4.51.tar.gz
[root@localhost test]# cat Dockerfile
FROM centos
COPY httpd-2.4.51.tar.gz /files // 把一个压缩包放在一个不存在的目录,没有加上/files/左斜线,他会以为你把它放到根下面,改名为files
# COPY httpd-2.4.51.tar.gz /files/:我们需要这么写
[root@localhost ~]# docker build -t test:v0.1 /root/test/
Sending build context to Docker daemon 19.75MB
Step 1/2 : FROM centos
---> 5d0da3dc9764
Step 2/2 : COPY httpd-2.4.51.tar.gz /files
---> 80cc38ca09c5
Successfully built 80cc38ca09c5
Successfully tagged test:v0.1
[root@localhost ~]# docker run -it --rm test:v0.1
[root@36e10cefa2d3 /]# ls
bin files lib64 mnt root srv usr
dev home lost+found opt run sys var
etc lib media proc sbin tmp
[root@36e10cefa2d3 /]# ls -l /files
-rw-r--r--. 1 root root 9873874 Dec 8 08:07 /files
[root@36e10cefa2d3 /]# mv files tmp/
[root@36e10cefa2d3 /]# ls /tmp/
files ks-script-o23i7rc2
ks-script-4luisyla ks-script-x6ei4wuu
[root@36e10cefa2d3 /]# cd tmp/
[root@36e10cefa2d3 tmp]# tar xf files
[root@36e10cefa2d3 tmp]# ls
files ks-script-4luisyla ks-script-x6ei4wuu
httpd-2.4.51 ks-script-o23i7rc2
ENTRYPOINT
ENTRYPOINT有两种格式:
- ENTRYPOINT [“executable”,“param1”,“param2”]
- ENTRYPOINT command param1 param2(在shell中执行)
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,如果在docker run的后面提供了参数会被当作参数传递给 ENTRYPOINT 指令指定的程序。
每个Dockerfile中只能有一个ENTRYPOINT,当指定多个ENTRYPOINT时,只有最后一个生效。
但是, 如果运行 docker run 时使用了 --entrypoint 选项,此选项的参数可当作要运行的程序覆盖 ENTRYPOINT 指令指定的程序。
不希望程序被修改我们要使用 ENTRYPOINT指定;希望程序可以被修改用CMD指定
// 使用第二种格式
[root@localhost test]# cat Dockerfile
FROM centos
RUN rm -rf /etc/yum.repos.d/* && \
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-$(awk -F'"' 'NR==2{print $2}' /etc/os-release).repo && \
sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo && \
dnf clean all && \
dnf -y install httpd
ENTRYPOINT /usr/sbin/httpd -D FOREGROUND
[root@localhost ~]# docker build -t test:v0.3 /root/test/
......以上省略
Removing intermediate container 6ba4992806c8
---> 74e2e4ee1976
Step 3/3 : ENTRYPOINT /usr/sbin/httpd -D FOREGROUND
---> Running in 29ff973fff66
Removing intermediate container 29ff973fff66
---> e784c6e2a463
Successfully built e784c6e2a463
Successfully tagged test:v0.3
[root@localhost ~]# docker run -it --rm test:v0.3
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d9607d467c21 test:v0.3 "/bin/sh -c '/usr/sb…" 8 seconds ago Up 7 seconds stupefied_buck // 第二种格式使用的/bin/sh 运行
// 使用第一种格式(推荐使用这一种)
[root@localhost test]# cat Dockerfile
FROM centos
RUN rm -rf /etc/yum.repos.d/* && \
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-$(awk -F'"' 'NR==2{print $2}' /etc/os-release).repo && \
sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo && \
dnf clean all && \
dnf -y install httpd
ENTRYPOINT ["/usr/sbin/httpd","-D","FOREGROUND"]
[root@localhost ~]# docker build -t test:v0.4 /root/test/
Sending build context to Docker daemon 19.75MB
Step 1/3 : FROM centos
---> 5d0da3dc9764
Step 2/3 : RUN rm -rf /etc/yum.repos.d/* && curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-$(awk -F'"' 'NR==2{print $2}' /etc/os-release).repo && sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo && dnf clean all && dnf -y install httpd
---> Using cache
---> 74e2e4ee1976
Step 3/3 : ENTRYPOINT ["/usr/sbin/httpd","-D","FOREGROUND"]
---> Running in 765b40148b47
Removing intermediate container 765b40148b47
---> fad18b563a3b
Successfully built fad18b563a3b
Successfully tagged test:v0.4
[root@localhost ~]# docker run -it --rm test:v0.4
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
96aa97853703 test:v0.4 "/usr/sbin/httpd -D …" 5 seconds ago Up 4 seconds cool_swanson // 直接使用/usr/sbin/httpd 启动
// 第一种格式还可以配合CMD这样写
[root@localhost test]# cat Dockerfile
FROM centos
RUN rm -rf /etc/yum.repos.d/* && \
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-$(awk -F'"' 'NR==2{print $2}' /etc/os-release).repo && \
sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo && \
dnf clean all && \
dnf -y install httpd
CMD ["-D","FOREGROUND"] // 如果这里注释掉CMD,服务将会在后台运行
ENTRYPOINT ["/usr/sbin/httpd"] // 以为ENTRYPOINT是入口点,CMD写在前面也没事
[root@localhost ~]# docker build -t test:v0.5 /root/test/
Sending build context to Docker daemon 19.75MB
Step 1/4 : FROM centos
---> 5d0da3dc9764
Step 2/4 : RUN rm -rf /etc/yum.repos.d/* && curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-$(awk -F'"' 'NR==2{print $2}' /etc/os-release).repo && sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo && dnf clean all && dnf -y install httpd
---> Using cache
---> 74e2e4ee1976
Step 3/4 : CMD ["-D","FOREGROUND"]
---> Running in a29ef29af0e1
Removing intermediate container a29ef29af0e1
---> 3320917ce061
Step 4/4 : ENTRYPOINT ["/usr/sbin/httpd"]
---> Running in c3cd93e9b5ca
Removing intermediate container c3cd93e9b5ca
---> 2ca91ccaa9bf
Successfully built 2ca91ccaa9bf
Successfully tagged test:v0.5
// 前台运行
[root@localhost ~]# docker run -it --rm test:v0.5
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
24d76ce0c59c test:v0.5 "/usr/sbin/httpd -D …" 17 seconds ago Up 15 seconds flamboyant_zhukovsky // 直接使用/usr/sbin/httpd 启动
// 单独使用CMD启动容器时指定了运行的命令,则会覆盖掉CMD指定的命令
// 配合ENTRYPOINT则无法指定,无法改变,会报错(ENTRYPOINT里面写了什么运行方式,就只能用这个运行方式)
[root@localhost ~]# docker run -it --rm test:v0.5 /bin/bash
Usage: /usr/sbin/httpd [-D name] [-d directory] [-f file]
// 加上-v查看版本
[root@localhost ~]# docker run -it --rm test:v0.5 -v
Server version: Apache/2.4.37 (centos)
Server built: Nov 12 2021 04:57:27
VOLUME
格式为VOLUME ["/data"]
。
创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。
USER
格式为USER daemon
。
指定运行容器时的用户名或UID,后续的RUN也会使用指定用户。
当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户,例如:
RUN groupadd -r postgres && useradd -r -g postgres postgres
要临时获取管理员权限可以使用gosu,而不推荐sudo。如果不指定,容器默认是root运行。
WORKDIR
格式为WORKDIR /path/to/workdir
。
为后续的RUN、CMD、ENTRYPOINT指令配置工作目录。
可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
则最终路径为/a/b/c。
ONBUILD
格式为ONBUILD [INSTRUCTION]
。
配置当所创建的镜像作为其他镜像的基础镜像时,所执行的操作指令。
例如,Dockerfile使用如下的内容创建了镜像image-A
[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]
此时,如果基于image-A创建新的镜像时,新的Dockerfile中使用FROM image-A指定基础镜像时,会自动执行ONBUILD指令的内容,等价于在后面添加了两条指令。
FROM image-A
# Automatically run the following
ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src
使用ONBUILD指令的镜像,推荐在标签中注明,例如ruby:1.9-onbuild。
[root@localhost opt]# tree test/
test/
|-- Dockerfile
`-- files
`-- httpd-2.4.51.tar.gz
1 directory, 2 files
[root@localhost opt]# ls
apache containerd test
[root@localhost opt]# cat test/Dockerfile
FROM centos
ONBUILD ADD files/httpd-2.4.51.tar.gz /usr/src
[root@localhost opt]# docker build -t download_httpd:v0.2 test
Sending build context to Docker daemon 9.877MB
Step 1/2 : FROM centos
---> 5d0da3dc9764
Step 2/2 : ONBUILD ADD files/httpd-2.4.51.tar.gz /usr/src
---> Running in b300c5e6a190
Removing intermediate container b300c5e6a190
---> 921bd96ab3f3
Successfully built 921bd96ab3f3
Successfully tagged download_httpd:v0.2
[root@localhost opt]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
download_httpd v0.2 921bd96ab3f3 2 minutes ago 231MB
[root@localhost opt]# docker run -it --rm download_httpd:v0.2 /bin/sh
sh-4.4# ls /usr/src/
debug kernels // 目录里面并没有httpd解压目录
[root@localhost opt]# cp -r test/files/ apache/
[root@localhost opt]# cat apache/Dockerfile
FROM download_httpd:v0.2 // 来自于ownload_httpd:v0.2镜像
[root@localhost opt]# docker build -t httpd:v0.2 apacheSending build context to Docker daemon 9.877MB
Step 1/1 : FROM download_httpd:v0.2
# Executing 1 build trigger
---> 75406791769a
Successfully built 75406791769a
Successfully tagged httpd:v0.2
[root@localhost opt]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd v0.2 75406791769a 18 seconds ago 273MB
download_httpd v0.2 921bd96ab3f3 4 minutes ago 231MB
[root@localhost opt]# rm -rf test/files/
[root@localhost opt]# tree
.
|-- apache
| |-- Dockerfile
| `-- files
| `-- httpd-2.4.51.tar.gz
|-- containerd
| |-- bin
| `-- lib
`-- test
`-- Dockerfile
[root@localhost opt]# docker build -t httpd:v0.3 apache
Sending build context to Docker daemon 9.877MB
Step 1/1 : FROM download_httpd:v0.2
# Executing 1 build trigger
---> Using cache
---> 75406791769a
Successfully built 75406791769a
Successfully tagged httpd:v0.3
[root@localhost opt]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd v0.2 75406791769a About a minute ago 273MB
httpd v0.3 75406791769a About a minute ago 273MB
download_httpd v0.2 921bd96ab3f3 5 minutes ago 231MB
[root@localhost opt]# docker run -it --rm httpd:v0.2
[root@1822cc3cd822 /]# ls /usr/s
ls: cannot access '/usr/s': No such file or directory
[root@1822cc3cd822 /]# ls /usr/src/
debug httpd-2.4.51 kernels // 添加了httpd解压目录
[root@localhost opt]# docker run -it --rm httpd:v0.3
[root@f12844caa8ef /]# ls /usr/src/
debug httpd-2.4.51 kernels
创建镜像
编写完成Dockerfile后,可以通过docker build命令来创建镜像。
基本的格式为docker build [选项] 路径
,该命令将读取指定路径下(包括子目录)的Dockerfile,并将该路径下所有内容发送给Docker服务端,由服务端来创建镜像。因此一般建议放置Dockerfile的目录为空目录。
另外,可以通过 .dockerignore
文件(每一行添加一条匹配模式)来让Docker忽略路径下的目录和文件。
要指定镜像的标签信息,可以通过-t选项。
例如,指定Dockerfile所在路径为/tmp/docker_builder/,并且希望生成镜像标签为build_repo/first_image,可以使用下面的命令:
docker build -t build_repo/first_image /tmp/docker_builder/