文章目录
一、基本结构
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://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse" >> /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 | 基础镜像,一切从这里开始构建 |
MAINTAINER | 镜像是谁写的,姓名+邮箱 |
RUN | 镜像构建的时候需要运行的命 |
ADD | 提供安装包位置 |
WORKDIR | 镜像的工作目录 |
VOLUME | 挂载的目录 |
EXPOSE | 暴露端口配置 |
CMD | 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代 |
ENTRYPOINT | 指定这个容器启动的时候要运行的命令,可以追加命令 |
ONBUILD | 当构建一个被继承 Dockerfile 这个时候就会运行ONBUILD 的指令 |
COPY | 类似ADD,将我们文件拷贝到镜像中 |
ENV | 构建的时候设置环境变量 |
2.1 FROM
格式为FROM <image>
或FROM <image>:<tag>
。
第一条指令必须为FROM指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令(每个镜像一次)。
FROM centos:8(默认是最新版本)
2.2 LABEL MAINTAINER(维护者)
格式为LABEL MAINTAINER <name email_address>
,指定维护者信息
用户名字+邮箱
LABEL MAINTAINER='amu 123@qq.com'
2.3 RUN
格式为RUN <command>
或RUN ["executable","param1","param2"]
。
前者将在shell终端中运行命令,即/bin/sh -c;后者则使用exec执行。指定使用其他终端可以通过第二种方式实现,例如:
[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指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行,例如:
[root@localhost test]# cat Dockerfile
FROM centos
RUN echo "hello world\nhello tom" > /tmp/abc && \
cat /tmp/abc
2.4 CMD
CMD支持三种格式:
CMD ["executable","param1","param2"]
使用exec执行,推荐方式CMD command param1 param2
在/bin/sh中执行,提供给需要交互的应用CMD ["param1","param2"]
提供给ENTRYPOINT的默认参数
CMD用于指定启动容器时默认要执行的命令,如果docker run没有指定任何的执行命令或者dockerfile里面也没有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"
2.5 EXPOSE
格式为EXPOSE <port> [<port>...]
。
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则可以具体指定哪个本地端口映射过来。
2.6 ENV
格式为ENV <key> <value>
。
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 amu // 创建一个变量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 amu
---> 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
amu
[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
2.7 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 amu" > 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 amu
# 转移目录里面的内容
[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
2.8 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 amu // 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
2.9 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
2.10 VOLUME
格式为VOLUME ["/data"]
。
VOLUME ["<容器内路径1>", "<容器内路径2>"...]
VOLUME <路径>
创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。
2.11 USER
格式为USER daemon
。
USER <user>[:<group>]
USER <UID>[:<GID>]
指定运行容器时的用户名或UID,后续的RUN也会使用指定用户。
当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户
RUN groupadd -r mysql && useradd -r -g mysql mysql
USER mysql
要临时获取管理员权限可以使用gosu,而不推荐sudo。如果不指定,容器默认是root运行。
2.12 WORKDIR
- 同docker run -w
- 指定工作目录,可以指多个,每个WORKDIR只影响他下面的指令,直到遇见下一个WORKDIR为止。
- WORKDIR也可以调用由ENV指令定义的变量。
格式为WORKDIR /path/to/workdir
。
WORKDIR <工作目录路径>
为后续的RUN、CMD、ENTRYPOINT指令配置工作目录。
可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
则最终路径为/a/b/c。
2.13 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/
四、Dockerfile编译安装apache镜像
// 创建apache目录
[root@localhost ~]# mkdir apache
[root@localhost ~]# cd apache/
[root@localhost apache]# ls
// 创建dockerfile文件以及安装包存放目录
[root@localhost apache]# touch Dockerfile
[root@localhost apache]# mkdir files
// 移动安装包当当前目录下
[root@localhost apache]# cd files/
[root@localhost files]# mv /usr/src/httpd-2.4.51.tar.gz .
[root@localhost files]# mv /usr/src/apr-util-1.6.1.tar.gz .
[root@localhost files]# mv /usr/src/apr-1.7.0.tar.gz .
[root@localhost files]# cd
[root@localhost ~]# tree apache/
apache/
|-- Dockerfile
`-- files
|-- apr-1.7.0.tar.gz
|-- apr-util-1.6.1.tar.gz
`-- httpd-2.4.51.tar.gz
1 directory, 4 files
// 编写Dockerfile
[root@localhost ~]# cat apache/Dockerfile
FROM centos // 基础镜像
LABEL MAINTAINER='gaofan1225 123@qq.com' // 作者信息
ENV apr_version=1.7.0
ENV apr_util_version=1.6.1
ENV httpd_version=2.4.51 // 定义安装包版本变量
ADD files/* /usr/src/ // 传输安装包,会自动解压
WORKDIR /usr/src/ // 切换当前所在目录
RUN yum -y install openssl-devel pcre-devel expat-devel libtool gcc gcc-c++ make libxml2-devel && \
yum groups mark install 'Development Tools' -y && \ // 安装依赖包和编译工具
useradd -r -M -s /sbin/nologin apache && \ // 创建apache用户
cd apr-${apr_version} && \ // 编译安装
sed -i '/$RM "$cfgfile"/d' configure && \
./configure --prefix=/usr/local/apr && make && make install && \
cd ../apr-util-${apr_util_version} && \
./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr && \
make && make install && \
cd ../httpd-${httpd_version} && \
./configure --prefix=/usr/local/apache \
--enable-so \
--enable-ssl \
--enable-cgi \
--enable-rewrite \
--with-zlib \
--with-pcre \
--with-apr=/usr/local/apr \
--with-apr-util=/usr/local/apr-util/ \
--enable-modules=most \
--enable-mpms-shared=all \
--with-mpm=prefork && \
make && make install && \
sed -i '/#ServerName/s/#//g' /usr/local/apache/conf/httpd.conf // 修改配置文件
EXPOSE 80 443 // 暴露端口
VOLUME ["/usr/local/apache/htdocs/"] // 做存储卷
CMD ["-D","FOREGROUND"]
ENTRYPOINT ["/usr/local/apache/bin/apachectl"] // 启动服务
// 创建镜像
[root@localhost ~]# docker build -t gaofan1225/httpd:latest /root/apache/
Sending build context to Docker daemon 11.54MB
......以上省略
make[1]: Leaving directory '/usr/src/httpd-2.4.51'
Removing intermediate container 53d4489b1a22
---> b5f980d289af
Step 7/9 : EXPOSE 80 443
---> Running in f3c66243bcb9
Removing intermediate container f3c66243bcb9
---> f0fa153b8eae
Step 8/9 : VOLUME ["/usr/local/apache/htdocs/"]
---> Running in 661760b461cf
Removing intermediate container 661760b461cf
---> b9f7587ba4be
Step 9/9 : CMD ["/usr/local/apache/bin/apachectl","-D","FOREGROUND"]
---> Running in 408270ece823
Removing intermediate container 408270ece823
---> 951f8194cf5b
Successfully built 951f8194cf5b
Successfully tagged gaofan1225/httpd:latest
// 使用刚刚创建的镜像启动容器,映射端口
[root@localhost ~]# docker run --name httpd -itd -p 80:80 gaofan1225/httpd:latest
a37cb3ef36f0e124e076f2f8565e092240867984e680fb9eceb110ceddce5a8c
// 查看容器运行情况
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a37cb3ef36f0 gaofan1225/httpd:latest "/usr/local/apache/b…" 7 seconds ago Up 6 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp, 443/tcp httpd
// 登入容器查看80端口是否启动
[root@localhost ~]# docker exec -it httpd /bin/bash
[root@a37cb3ef36f0 src]# ss -antl
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:80 0.0.0.0:*
页面访问
上传到 docker hub 仓库
上传之前先去网页上面创建一个仓库 gaofan1225/httpd
// 登录 docker hub 仓库
[root@localhost ~]# docker login
Authenticating with existing credentials...
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
// 上传
[root@localhost ~]# docker push gaofan1225/httpd:latest
The push refers to repository [docker.io/gaofan1225/httpd]
74729c5f37dc: Pushed
cfaf4ece959c: Pushed
74ddd0ec08fa: Layer already exists
latest: digest: sha256:18350a676a843b0b88d512436f110b8cbea0b7c1766b00912fb46d855e5ac613 size: 954
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/5579.html