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]#