Docker-Dockerfile方式镜像的构建
1. 创建一个Dockerfile
默认在构建的时候会把当前目录所有数据发送到docker引擎,如果构建在根目录,会把跟目录所有数据发送给docker引擎进行构建,所以,创建Dockerfile尽量不要在根目录。
mkdir docker
cd docker
vim Dockerfile
FROM busybox
RUN echo helloword > testfile
• 构建镜像
[root@vm2 demo]# docker build -t busybox:v2 .
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM busybox
---> beae173ccac6
Step 2/2 : RUN echo helloword > testfile
---> Running in 33889fdfb36c
Removing intermediate container 33889fdfb36c
---> af46689dc5b5
Successfully built af46689dc5b5
Successfully tagged busybox:v2
• 查看镜像的分层结构
[root@vm2 demo]# docker history busybox:v2
IMAGE CREATED CREATED BY SIZE COMMENT
af46689dc5b5 11 minutes ago /bin/sh -c echo helloword > testfile 10B
beae173ccac6 5 months ago /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> 5 months ago /bin/sh -c #(nop) ADD file:6db446a57cbd2b7f4… 1.24MB
• 镜像的缓存特性
构建镜像中有相同的镜像层时,会使用缓存来加速构建。
[root@vm2 demo]# vim Dockerfile
FROM busybox
RUN echo helloword > testfile
COPY file /
[root@vm2 demo]# vim file
FROM busybox
RUN echo helloword > testfile
[root@vm2 demo]# docker build -t busybox:v3 .
Sending build context to Docker daemon 3.072kB
Step 1/3 : FROM busybox
---> beae173ccac6
Step 2/3 : RUN echo helloword > testfile
---> Using cache
---> af46689dc5b5
Step 3/3 : COPY file /
---> 972a56410e72
Successfully built 972a56410e72
Successfully tagged busybox:v3
通过Dockerfile来构建镜像,可以清除的看到每一层都干了什么,有安全审计的功能。而通过docker commit 构建新镜像的方式则无法知晓具体在镜像内做了什么操作,无法对镜像进行审计,存在安全隐患。
• dockerfile 最佳实践
dockerfile常用指令 | |
FROM | 指定base镜像,如果本地不存在会从远程仓库下载。 |
MAINTAINER | 设置镜像的作者,比如用户邮箱等。 |
COPY | 把文件从build context复制到镜像 支持两种形式:COPY src dest 和 COPY ["src", "dest"] src必须指定build context中的文件或目录 |
ADD | 用法与COPY类似,不同的是src可以是归档压缩文件,文件会被自动解压到 dest,也可以自动下载URL并拷贝到镜像: ADD html.tar /var/www ADD http://ip/html.tar /var/www |
ENV | 设置环境变量,变量可以被后续的指令使用: ENV HOSTNAME sevrer1.example.com |
EXPOSE | 如果容器中运行应用服务,可以把服务端口暴露出去: EXPOSE 80 |
VOLUME | 申明数据卷,通常指定的是应用的数据挂在点: VOLUME ["/var/www/html"] |
WORKDIR | 为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当 前工作目录,如果目录不存在会自动创建。 |
RUN | 在容器中运行命令并创建新的镜像层,常用于安装软件包: RUN yum install -y vim |
CMD 与 ENTRYPOINT | 这两个指令都是用于设置容器启动后执行的命令,但CMD会被docker run后面的命令行覆盖,而ENTRYPOINT不会被忽略,一定会被执行。 docker run后面的参数可以传递给ENTRYPOINT指令当作参数。 Dockerfile中只能指定一个ENTRYPOINT,如果指定了很多,只有最 后一个有效。 |
2. 常用指令实践
2.1 COPY 把文件从build context复制到镜像
[root@vm2 ~]# cd docker/demo/
[root@vm2 demo]# ls
Dockerfile file
[root@vm2 demo]# vim Dockerfile
FROM busybox
COPY file /
[root@vm2 demo]# vim file
hello docker
root@vm2 demo]# docker build -t busybox:v3 .
Sending build context to Docker daemon 1.077MB
Step 1/2 : FROM busybox
---> beae173ccac6
Step 2/2 : COPY file /
---> 609f28019307
Successfully built 609f28019307
Successfully tagged busybox:v3
[root@vm2 demo]# docker run -it --rm busybox:v3
/ # ls
bin dev etc file home proc root sys tmp usr var
/ # cat file
hello docker
/ #
2.2 ADD 用法与COPY类似,不同的是src可以是归档压缩文件,文件会被自动解压到
dest,也可以自动下载URL并拷贝到镜像
[root@vm2 demo]# ls
Dockerfile file nginx-1.21.6.tar.gz
[root@vm2 demo]# vim Dockerfile
FROM busybox
ADD nginx-1.21.6.tar.gz /
[root@vm2 demo]# docker build -t busybox:v4 .
Sending build context to Docker daemon 1.077MB
Step 1/2 : FROM busybox
---> beae173ccac6
Step 2/2 : ADD nginx-1.21.6.tar.gz /
---> Using cache
---> 0ec99bc72f19
Successfully built 0ec99bc72f19
Successfully tagged busybox:v4
[root@vm2 demo]# docker run -it --rm busybox:v4
/ # ls
bin etc nginx-1.21.6 root tmp var
dev home proc sys usr
/ # cd nginx-1.21.6/
/nginx-1.21.6 # ls
CHANGES LICENSE auto configure html src
CHANGES.ru README conf contrib man
2.3 ENV 设置环境变量,变量可以被后续的指令使用
[root@vm2 demo]# ls
Dockerfile file nginx-1.21.6.tar.gz
[root@vm2 demo]# vim Dockerfile
FROM busybox
ENV hostname vm2
ADD nginx-1.21.6.tar.gz /
[root@vm2 demo]# docker build -t busybox:v5 .
Sending build context to Docker daemon 1.077MB
Step 1/3 : FROM busybox
---> beae173ccac6
Step 2/3 : ENV hostname vm2
---> Running in 5c5ba3805525
Removing intermediate container 5c5ba3805525
---> cebb03891923
Step 3/3 : ADD nginx-1.21.6.tar.gz /
---> e9aa8cc15264
Successfully built e9aa8cc15264
Successfully tagged busybox:v5
[root@vm2 demo]# docker run -it --rm busybox:v5
/ # env
HOSTNAME=57164b2b12e9
SHLVL=1
HOME=/root
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
hostname=vm2
PWD=/
/ #
2.4 VOLUME:申明数据卷,通常指定的是应用的数据挂载点
2.4.1 编辑Dockerkile文件,构建镜像
[root@vm2 demo]# ls
Dockerfile file nginx-1.21.6.tar.gz
[root@vm2 demo]# vim Dockerfile
FROM busybox
ENV hostname vm2
ADD nginx-1.21.6.tar.gz /
VOLUME ["/data"]
[root@vm2 demo]# docker build -t busybox:v6 .
Sending build context to Docker daemon 1.077MB
Step 1/4 : FROM busybox
---> beae173ccac6
Step 2/4 : ENV hostname vm2
---> Using cache
---> cebb03891923
Step 3/4 : ADD nginx-1.21.6.tar.gz /
---> Using cache
---> e9aa8cc15264
Step 4/4 : VOLUME ["/data"]
---> Running in d5212c93a723
Removing intermediate container d5212c93a723
---> aaa7d50b9466
Successfully built aaa7d50b9466
Successfully tagged busybox:v6
2.4.2 查看镜像的创建历史,进入容器,创建文件
[root@vm2 demo]# docker history busybox:v6
IMAGE CREATED CREATED BY SIZE COMMENT
aaa7d50b9466 About a minute ago /bin/sh -c #(nop) VOLUME [/data] 0B
e9aa8cc15264 5 minutes ago /bin/sh -c #(nop) ADD file:8e86f7dae7bf3e74b… 6.46MB
cebb03891923 5 minutes ago /bin/sh -c #(nop) ENV hostname=vm2 0B
beae173ccac6 5 months ago /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> 5 months ago /bin/sh -c #(nop) ADD file:6db446a57cbd2b7f4… 1.24MB
[root@vm2 demo]# docker run -it --rm busybox:v6
/ # cd data/
/data # ls
/data # touch file
##ctrl+p+q退出
2.4.3 查看挂载信息,找到并进入挂载目录,编辑之前在镜像内创建的文件file(挂载的目录和镜像内的目录是同步的,编辑挂载目录的文件,镜像内的文件同样会被更改)
[root@vm2 demo]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5f4abc5a3f53 busybox:v6 "sh" 39 seconds ago Up 38 seconds frosty_burnell
[root@vm2 demo]# docker inspect 5f4abc5a3f53
......
"Mounts": [
{
"Type": "volume",
"Name": "ab9ce083e6c488a9d0758ca147381bed63ff56e46469ce365b9e1975c9e85a32",
"Source": "/var/lib/docker/volumes/ab9ce083e6c488a9d0758ca147381bed63ff56e46469ce365b9e1975c9e85a32/_data",
"Destination": "/data",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
......
[root@vm2 demo]# cd /var/lib/docker/volumes/ab9ce083e6c488a9d0758ca147381bed63ff56e46469ce365b9e1975c9e85a32/_data
[root@vm2 _data]# ls
file
[root@vm2 _data]# echo hello > file
[root@vm2 _data]# cat file
hello
2.4.4 用id重新启动镜像,查看镜像内的文件变化,之后删除镜像内的文件
[root@vm2 _data]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5f4abc5a3f53 busybox:v6 "sh" 3 minutes ago Up 3 minutes frosty_burnell
[root@vm2 _data]# docker attach 5f4abc5a3f53
/data # ls
file
/data # cat file
hello
/data # rm -rf file
/data #
##ctrl+p+q退出
2.4.5 释放数据卷
[root@vm2 demo]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5f4abc5a3f53 busybox:v6 "sh" 39 seconds ago Up 38 seconds frosty_burnell
[root@vm2 demo]# docker rm -f 5f4abc5a3f53
5f4abc5a3f53
[root@vm2 ~]# docker volume ls
DRIVER VOLUME NAME
local 4e845a124d5f7f442b48c0af033bcb0c0d47cadf7e810693b6c5faef02ca5a6f
local 4e94218a40e8e7e7032d46875f3d017812beded488a583bb0f7c79962721f07f
local 09df272ed7af46dd81c4b73d02065002a4ec5b26df93e6872d062436b0e855d2
local 71fead7e8d08a2517d51fca07b65550c78d9c2eb458217d6e161ec533fe98964
local a70ac57ff1d5cdd3c0e386c75783fdea4f2ab8847b4553c5d7163b71452c950f
local c213a62a6f11a530e55d1625055debb756935155ed0049c744ac0d9b0db6a19b
local cb3f2b87f9c47c02a413ed0b89c5190bd63b691a0515f89488e447903781ff8f
local e2eab2b9fd7f5245f93c8912e64ab03048060441ad826c1f3301a9db19fe02ba
local e68f0462ac4c0f488fa369965a88a71ab8d09624cf68ef7fdf920f9cf7a5dcd5
[root@vm2 ~]# docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
4e94218a40e8e7e7032d46875f3d017812beded488a583bb0f7c79962721f07f
c213a62a6f11a530e55d1625055debb756935155ed0049c744ac0d9b0db6a19b
e2eab2b9fd7f5245f93c8912e64ab03048060441ad826c1f3301a9db19fe02ba
Total reclaimed space: 40B
2.5 WORKDIR 为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在会自动创建。
[root@vm2 demo]# vim Dockerfile
FROM busybox
ENV hostname vm2
WORKDIR /nginx
ADD nginx-1.21.6.tar.gz /nginx
VOLUME ["/data"]
[root@vm2 demo]# docker build -t busybox:v7 .
Sending build context to Docker daemon 1.077MB
Step 1/5 : FROM busybox
---> beae173ccac6
Step 2/5 : ENV hostname vm2
---> Using cache
---> cebb03891923
Step 3/5 : WORKDIR /nginx
---> Running in 13d5345cb0fb
Removing intermediate container 13d5345cb0fb
---> 46333adf45d3
Step 4/5 : ADD nginx-1.21.6.tar.gz /nginx
---> bbe7bb3a02d6
Step 5/5 : VOLUME ["/data"]
---> Running in a5db4a665710
Removing intermediate container a5db4a665710
---> 6972165107ed
Successfully built 6972165107ed
Successfully tagged busybox:v7
[root@vm2 demo]# docker run -it --rm busybox:v7
/nginx # ls
nginx-1.21.6
/nginx #
进入容器镜像时就默认在/nginx这个目录下,而将nginx的包解压在了这个目录中,这个目录之前并不存在,是WORKDIR自动创建的
2.6 这两个指令都是用于设置容器启动后执行的命令,但CMD会被dockerrun后面的命令行覆盖,而ENTRYPOINT不会被忽略,一定会被执行。docker run后面的参数可以传递给ENTRYPOINT指令当作参数。Dockerfile中只能指定一个ENTRYPOINT,如果指定了很多,只有最后一个有效
2.6.1 CMD编辑方式,docker run后面的命令行会覆盖文件中echo所要输出的内容
[root@vm2 demo]# vim Dockerfile
ENV hostname vm2
WORKDIR /nginx
ADD nginx-1.21.6.tar.gz /nginx
VOLUME ["/data"]
CMD echo hello docker
[root@vm2 demo]# docker build -t busybox:v8 .
Sending build context to Docker daemon 1.077MB
Step 1/6 : FROM busybox
---> beae173ccac6
Step 2/6 : ENV hostname vm2
---> Using cache
---> cebb03891923
Step 3/6 : WORKDIR /nginx
---> Using cache
---> 46333adf45d3
Step 4/6 : ADD nginx-1.21.6.tar.gz /nginx
---> Using cache
---> bbe7bb3a02d6
Step 5/6 : VOLUME ["/data"]
---> Using cache
---> 6972165107ed
Step 6/6 : CMD echo hello docker
---> Running in 31994c2b2989
Removing intermediate container 31994c2b2989
---> 6ee395d6f7b5
Successfully built 6ee395d6f7b5
Successfully tagged busybox:v8
[root@vm2 demo]# docker run --rm busybox:v8 ##执行了文件中CMD后的echo命令
hello docker
[root@vm2 demo]# docker run --rm busybox:v8 ls ##运行容器时ls覆盖了文件中CMD后echo命令, CMD后的命令不会输出
nginx-1.21.6
2.6.2 ENTRYPOINT编辑方式,docker run后面的命令行不会覆盖文件中echo所要输出的内容
[root@vm2 demo]# vim Dockerfile
FROM busybox
ENV hostname vm2
WORKDIR /nginx
ADD nginx-1.21.6.tar.gz /nginx
VOLUME ["/data"]
ENTRYPOINT echo hello docker
[root@vm2 demo]# docker build -t busybox:v9 .
Sending build context to Docker daemon 1.077MB
Step 1/6 : FROM busybox
---> beae173ccac6
Step 2/6 : ENV hostname vm2
---> Using cache
---> cebb03891923
Step 3/6 : WORKDIR /nginx
---> Using cache
---> 46333adf45d3
Step 4/6 : ADD nginx-1.21.6.tar.gz /nginx
---> Using cache
---> bbe7bb3a02d6
Step 5/6 : VOLUME ["/data"]
---> Using cache
---> 6972165107ed
Step 6/6 : ENTRYPOINT echo hello docker
---> Running in 715694ec8a58
Removing intermediate container 715694ec8a58
---> 87b3a373d13c
Successfully built 87b3a373d13c
Successfully tagged busybox:v9
[root@vm2 demo]# docker run -it --rm busybox:v9
hello docker
[root@vm2 demo]# docker run -it --rm busybox:v9 ls ##用ENTRYPOINT方式编辑后,echo后的输出内容不会被覆盖
hello docker
2.7 RUN 在容器中运行命令并创建新的镜像层,常用于安装软件包
[root@vm2 demo]# vim Dockerfile
FROM centos:7
RUN yum install -y pcre-devel
[root@vm2 demo]# docker build -t centos:v1 .
.....
Complete!
Removing intermediate container 1f8aa8292c49
---> 4f7c0b7f02c1
Successfully built 4f7c0b7f02c1
Successfully tagged centos:v1
[root@vm2 demo]# docker history centos:v1
IMAGE CREATED CREATED BY SIZE COMMENT
4f7c0b7f02c1 About a minute ago /bin/sh -c yum install -y pcre-devel 171MB
eeb6ee3f44bd 9 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 9 months ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 9 months ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
3. Shell和exec格式的区别
3.1 Shell格式底层会调用/bin/sh -c来执行命令,可以解析变量
[root@vm2 demo]# vim Dockerfile
FROM centos:7
RUN yum install -y pcre-devel
ENV HOSTNAME vm2
CMD echo "hello $HOSTNAME"
[root@vm2 demo]# docker build -t centos:v2 .
Sending build context to Docker daemon 1.077MB
Step 1/4 : FROM centos:7
---> eeb6ee3f44bd
Step 2/4 : RUN yum install -y pcre-devel
---> Using cache
---> 4f7c0b7f02c1
Step 3/4 : ENV HOSTNAME vm2
---> Running in 27a73e988532
Removing intermediate container 27a73e988532
---> 3afd2ae3e8cd
Step 4/4 : CMD echo "hello $HOSTNAME"
---> Running in db45d44d800a
Removing intermediate container db45d44d800a
---> 95a0bfc8780e
Successfully built 95a0bfc8780e
Successfully tagged centos:v2
[root@vm2 demo]# docker run -it --rm centos:v2
hello vm2
3.2 exec格式则不会调用/bin/sh -c来执行命令,不会解析变量
[root@vm2 demo]# vim Dockerfile
FROM centos:7
RUN yum install -y pcre-devel
ENV HOSTNAME vm2
CMD ["/usr/bin/echo", "hello $HOSTNAME"]
[root@vm2 demo]# docker build -t centos:v3 .
Sending build context to Docker daemon 1.077MB
Step 1/4 : FROM centos:7
---> eeb6ee3f44bd
Step 2/4 : RUN yum install -y pcre-devel
---> Using cache
---> 4f7c0b7f02c1
Step 3/4 : ENV HOSTNAME vm2
---> Using cache
---> 3afd2ae3e8cd
Step 4/4 : CMD ["/usr/bin/echo", "hello $HOSTNAME"]
---> Running in d779e71086d9
Removing intermediate container d779e71086d9
---> 2771036a6065
Successfully built 2771036a6065
Successfully tagged centos:v3
[root@vm2 demo]# docker run -it --rm centos:v3
hello $HOSTNAME ##直接输出了变量的字符,没有解析
3. 3 exec格式如果需要解析变量,则需要手动调用
[root@vm2 demo]# vim Dockerfile
[root@vm2 demo]# cat Dockerfile
FROM centos:7
RUN yum install -y pcre-devel
ENV HOSTNAME vm2
CMD ["/bin/sh", "-c","echo hello $HOSTNAME"] ##通过手动来调用
[root@vm2 demo]# docker build -t centos:v
v1 v2 v3
[root@vm2 demo]# docker build -t centos:v4 .
Sending build context to Docker daemon 1.077MB
Step 1/4 : FROM centos:7
---> eeb6ee3f44bd
Step 2/4 : RUN yum install -y pcre-devel
---> Using cache
---> 4f7c0b7f02c1
Step 3/4 : ENV HOSTNAME vm2
---> Using cache
---> 3afd2ae3e8cd
Step 4/4 : CMD ["/bin/sh", "-c","echo hello $HOSTNAME"]
---> Running in 7497b4af118a
Removing intermediate container 7497b4af118a
---> 49c388eaa47e
Successfully built 49c388eaa47e
Successfully tagged centos:v4
[root@vm2 demo]# docker run -it --rm centos:v4
hello vm2 ##通过手动调用后,解析成功
3.4 Exec格式时,ENTRYPOINT可以通过CMD提供额外参数,CMD的额外参数可以在容器启动时动态替换。在shell格式时ENTRYPOINT会忽略任何CMD或docker run提供的参数。
[root@vm2 demo]# vim Dockerfile
FROM centos:7
RUN yum install -y pcre-devel
ENV HOSTNAME vm2
ENTRYPOINT ["/bin/echo", "hello"]
CMD ["world"]
[root@vm2 demo]# docker build -t centos:v5 .
Sending build context to Docker daemon 1.077MB
Error response from daemon: dockerfile parse error line 4: unknown instruction: INT
[root@vm2 demo]# vim Dockerfile
[root@vm2 demo]# docker build -t centos:v5 .
Sending build context to Docker daemon 1.077MB
Step 1/5 : FROM centos:7
---> eeb6ee3f44bd
Step 2/5 : RUN yum install -y pcre-devel
---> Using cache
---> 4f7c0b7f02c1
Step 3/5 : ENV HOSTNAME vm2
---> Using cache
---> 3afd2ae3e8cd
Step 4/5 : ENTRYPOINT ["/bin/echo", "hello"]
---> Running in ea01406169bf
Removing intermediate container ea01406169bf
---> 7f9fe55cd861
Step 5/5 : CMD ["world"]
---> Running in 87c795be89e2
Removing intermediate container 87c795be89e2
---> 493b16943da0
Successfully built 493b16943da0
Successfully tagged centos:v5
[root@vm2 demo]# docker run -it --rm centos:v5
hello world
3.5 Exec格式时,ENTRYPOINT可以通过CMD提供额外参数,CMD的额外参数可以在容器启动时动态替换。在shell格式时ENTRYPOINT会忽略任何CMD或docker run提供的参数,更直观的感受到上面2.6中,CMD 与 ENTRYPOINT的区别
[root@vm2 demo]# docker run -it --rm centos:v5 westos
hello westos
[root@vm2 demo]# docker run -it --rm centos:v5 linux
hello linux
[root@vm2 demo]# docker run -it --rm centos:v5 redhat
hello redhat
[root@vm2 demo]#