文章目录
①. DockerFile是什么?②. DockerFile构建过程解析③. 保留字指令①. FROM 基于哪个镜像②. LABEL 镜像的说明信息③. RUN 构建时期运行的指令④. CMD(运行时期)、ENTRYPOINT 指定启动容器、镜像的默认入口⑤. ARG 构建参数⑥. ENV 构建、运行都生效⑦. ADD 、COPY 复制文件⑧. WORKDIR 配置工作目录⑨. VOLUME 创建数据卷挂载点⑩. USER 指定运行容器时的用户名或UID⑩①. multi-stage builds 多阶段构建①. DockerFile是什么?
①. Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。
②. 构建三步骤(编写Dockerfile文件 | docker build | docker run)
③. 是什么样的?
④. 一般而言,Dockerfile可以分为四部分
基础镜像信息 维护者信息 镜像操作指令 启动时执行指令
# 这是我的第一个dockerfile镜像FROM alpine# 给镜像加注释信息LABEL maintainer="TANGZHI " \age=24# 运行的指令、安装了软件、修改了文件,默认使用id=0的用户,也就是root,这个基础系统的root# 代表镜像构建过程中的命令RUN echo hellodockerfile# 镜像启动要运行很长命令# 1.准备一个sh文件 大多情况下# 2.直接在CMD位置写即可# 容器启动会执行的命令CMD sleep 10;echo success
②. DockerFile构建过程解析
①. Dockerfile内容基础知识 每条保留字指令都必须为大写字母且后面要跟随至少一个参数指令按照从上到下,顺序执行#表示注释每条指令都会创建一个新的镜像层,并对镜像进行提交 ②. 从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段掌握
Dockerfile是软件的原材料Docker镜像是软件的交付品Docker容器则可以认为是软件的运行态③. 保留字指令
①. FROM 基于哪个镜像
①. 基础镜像,当前新镜像是基于哪个镜像的。必须为第一个命令
②. busybox:是一个集成了一百多个最常用Linux命令和工具的软件
③. Alpine:操作系统是一个面向安全的轻型Linux发行版经典最小镜像,基于busybox,功能比 Busybox完善(linux工具里的瑞士军刀)
④. slim:docker hub中有些镜像有slim标识,都是瘦身了的镜像
⑤. scratch:空镜像
②. LABEL 镜像的说明信息
标注镜像的一些说明信息LABEL maintainer="TANGZHI " \age=24
③. RUN 构建时期运行的指令
①. RUN指令有两种形式,一种是shell,另外一个是exec形式②. 在shell形式中,您可以使用(反斜杠)将一条RUN指令继续到下一行
FROM alpineLABEL maintainer="tangzhi"ARG prams=hellowordRUN echo $prams &&\echo tangzhiRUN echo "123456"RUN echo 123456789# 这种方式取不到环境变量RUN ["echo","$prams"]# 下面这种写法和RUN echo 123456789等价RUN ["/bin/sh","-c","echo $prams"]
[root@i-id8g0yu9 ~]# docker build -t mydockerfile4 -f dockerfile57 .Sending build context to Docker daemon 3.119MBStep 1/8 : FROM alpine---> 6dbb9cc54074Step 2/8 : LABEL maintainer="tangzhi"---> Using cache---> 3b6b777a2b23Step 3/8 : ARG prams=helloword---> Using cache---> 80bcc56f3aeeStep 4/8 : RUN echo $prams &&echo tangzhi---> Running in 9e1c545b68c9hellowordtangzhiRemoving intermediate container 9e1c545b68c9---> 93f7704f978bStep 5/8 : RUN echo "123456"---> Running in ae14d2044897123456Removing intermediate container ae14d2044897---> 32ed2861f3e5Step 6/8 : RUN echo 123456789---> Running in 84db90a766c4123456789Removing intermediate container 84db90a766c4---> d3fd8aeaec1fStep 7/8 : RUN ["echo","$prams"]---> Running in 99dddaaba442$pramsRemoving intermediate container 99dddaaba442---> 31ed024c8569Step 8/8 : RUN ["/bin/sh","-c","echo $prams"]---> Running in 4fdfca35b59fhellowordRemoving intermediate container 4fdfca35b59f---> a7457f8b7933Successfully built a7457f8b7933Successfully tagged mydockerfile4:latest[root@i-id8g0yu9 ~]#
④. CMD(运行时期)、ENTRYPOINT 指定启动容器、镜像的默认入口
①. ENTRYPOINT或者CMD作为唯一入口,只能写一个,最后一个生效#最终都是以ping 为准CMD ping CMD ping
②. [“echo”,"${param}"] 不是bash -c的方式,取不出环境变量性[]
echo $param 等价于 ["/bin/sh","-c",“多长的命令都写在这里 echo ${param}”]
# CMD ["ping",""]# CMD ["useradd","-u","1000","-g","2000"]# CMD ["ping","${url}"] 取不出变量# CMD ping ${url}
③. 官方都是建议使用[ ]方式(CMD ["/bin/sh","-c",“ping ${url}”]),变化的写CMD,固定不变的写ENTRYPO INT(未来他是容器启动的唯一入口)
# 一旦传递了cmd1,CMD指定的所有参数都会被覆盖# 在控制台输入 docker run imageName 6 # ping 5 -c CMD [ "5","" ]ENTRYPOINT [ "ping","-c" ]
④. 我们使用ENTRYPOINT ping 的形式输出,那么组合CMD怎么写都没用,容器启动都是以ENT RYPOINT的完整命令为准
# 最终都是以ping 为准ENTRYPOINT ping CMD ping
⑤. ARG 构建参数
①. 定义以后的剩下环节生效(不包括运行环节),取值$param不能使用在CMD或者ENTRYPO INT中
②. ARG指令定义了一个变量,用户可以在构建时使用–build-arg = 传递,docker build命令会将其传递给构建器。- -build-arg 指定参数会覆盖Dockerfile 中指定的同名参数
docker build --build-arg param=“xiaozhi” --build-arg message=“hellodockerbuild” --no-cache -t mydockerfile:v1 -f dockerfile3 .
③. 使用ENV指令定义的环境变量始终会覆盖同名的ARG指令
④. ARG不像ENV,不能并排写
⑤. dockerfile文件如下:
# 可以在任意位置使用,并在以后使用ARG version=3.13.4# 这是我的第一个dockerfile镜像FROM alpine:$version# 给镜像加注释信息LABEL maintainer="TANGZHI " \age=24# 运行的指令、安装了软件、修改了文件,默认使用id=0的用户,也就是root,这个基础系统的root# 代表镜像构建过程中的命令RUN echo hellodockerfileRUN echo $param# 定义以后的剩下环节生效(不包括运行环节),取值$param 不能使用在CMD或者ENTRYPOINT中# 可以在构建期间进行变化,比如我们使用如下的命令# docker build --build-arg param="xiaozhi" --build-arg message="hellodockerbuild" --no-cache -t mydockerfile:v1 -f dockerfile3 .# ARG不像ENV 不能并排写ARG param=helloparam ARG message=hellodocker# 构建时期会运行的指令(根据dockerfile创建一个镜像的整个过程时期)RUN echo 1111RUN echo $paramRUN echo $message# 运行时期,我们会运行的指令(根据之前创建的镜像启动一个容器,容器启动默认运行的命令)# docker run | docker start# CMD和ENTRYPOINT 都是指定运行时的指令# 当我们使用docker run -it 去执行的时候,发现只有1111输出CMD ["/bin/sh","-c","echo 1111;echo $param"]
[root@i-id8g0yu9 ~]# docker build --build-arg param="xiaozhi" --build-arg message="hellodockerbuild" --no-cache -t mydockerfile3:v1 -f dockerfile3 .Sending build context to Docker daemon 17.92kBStep 1/11 : ARG version=3.13.4Step 2/11 : FROM alpine:$version---> 49f356fa4513Step 3/11 : LABEL maintainer="TANGZHI "age=24---> Running in 382d67fbac27Removing intermediate container 382d67fbac27---> bfa9c16b967aStep 4/11 : RUN echo hellodockerfile---> Running in 5cc88771ed37hellodockerfileRemoving intermediate container 5cc88771ed37---> 337c6e0404bdStep 5/11 : RUN echo $param---> Running in b88d4af5b1faRemoving intermediate container b88d4af5b1fa---> e129628435ddStep 6/11 : ARG param=helloparam---> Running in 5f10ed5dfa16Removing intermediate container 5f10ed5dfa16---> 9904bb5f44dfStep 7/11 : ARG message=hellodocker---> Running in 50f117576dfaRemoving intermediate container 50f117576dfa---> e6c1c8a36097Step 8/11 : RUN echo 1111---> Running in 1ae844ed29a61111Removing intermediate container 1ae844ed29a6---> 5947099a85ecStep 9/11 : RUN echo $param---> Running in c543d2f3ea4cxiaozhiRemoving intermediate container c543d2f3ea4c---> 8353cd041e74Step 10/11 : RUN echo $message---> Running in d58ac7513eachellodockerbuildRemoving intermediate container d58ac7513eac---> 07f41021c095Step 11/11 : CMD ["/bin/sh","-c","echo 1111;echo $param"]---> Running in 5cacc787c157Removing intermediate container 5cacc787c157---> e9ed761f20bfSuccessfully built e9ed761f20bfSuccessfully tagged mydockerfile3:v1[root@i-id8g0yu9 ~]# docker run -it mydockerfile3:v1 #注意这里没有输入echo $param 1111[root@i-id8g0yu9 ~]#
⑥. ENV 构建、运行都生效
①. 构建期不能修改ENV的值(docker build)
②. 构建期+运行期都可以生效,但是只能在运行期进行修改
③. 运行期docker run -it -e message=runENV
# 这是我的第一个dockerfile镜像FROM alpine# 给镜像加注释信息LABEL maintainer="TANGZHI " \age=24ARG message=helloARG# 构建期+运行期都可以生效,但是只能在运行期进行修改# 构建期不能修改ENV的值(docker build)# 运行期docker run -it -e message=runENVENV message=helloENV# 构建时期会运行的指令(根据dockerfile创建一个镜像的整个过程时期)RUN echo $message# 运行时期,我们会运行的指令(根据之前创建的镜像启动一个容器,容器启动默认运行的命令)CMD ["/bin/sh","-c","echo 1111;echo app_$message"]
[root@i-id8g0yu9 ~]# docker build --no-cache -t dockerfilearg:v1 -f dockerfileArg .Sending build context to Docker daemon 20.99kBStep 1/6 : FROM alpinelatest: Pulling from library/alpine540db60ca938: Pull complete Digest: sha256:69e70a79f2d41ab5d637de98c1e0b055206ba40a8145e7bddb55ccc04e13cf8fStatus: Downloaded newer image for alpine:latest---> 6dbb9cc54074Step 2/6 : LABEL maintainer="TANGZHI "age=24---> Running in f4c6286d7edcRemoving intermediate container f4c6286d7edc---> 214a711d0c39Step 3/6 : ARG message=helloARG---> Running in a4e068cdd1a2Removing intermediate container a4e068cdd1a2---> d502358f547cStep 4/6 : ENV message=helloENV---> Running in 20fde633a7c2Removing intermediate container 20fde633a7c2---> 26bcd7c0386dStep 5/6 : RUN echo $message---> Running in 74d50778b66bhelloENV # 如果有ENV和ARY同时定义一个同名变量,我们使用的是ENVRemoving intermediate container 74d50778b66b---> 6867c5ca1d40Step 6/6 : CMD ["/bin/sh","-c","echo 1111;echo app_$message"]---> Running in 1980007e51e0Removing intermediate container 1980007e51e0---> a5015b515b34Successfully built a5015b515b34Successfully tagged dockerfilearg:v1[root@i-id8g0yu9 ~]# docker run -it -e message=runENV dockerfilearg:v11111app_runENV[root@i-id8g0yu9 ~]#
④. ENV在image阶段就会被解析并持久化(docker inspect image查看)参照下面示例
msg1=msg2没问题,如果我运行期间修改了msg1=66666的值,请问msg1、msg2输出什么?
结果输出 66666 hello
这是因为env坏境的信息会固化,直接在镜像配置里面就已经写死,msg1=hello msg2=hello,而-e只能修改当前env本身
# 这是我的第一个dockerfile镜像FROM alpine# 给镜像加注释信息LABEL maintainer="TANGZHI " \age=24# msg1=msg2没问题,如果我运行期间修改了msg1=66666的值,请问msg1、msg2输出什么?# 结果输出 66666 hello # 这是因为env坏境的信息会固化,直接在镜像配置里面就已经写死,msg1=hello msg2=hello,而-e只能修改当前env本身ENV msg1=helloENV msg2=$msg1# 构建时期会运行的指令(根据dockerfile创建一个镜像的整个过程时期)RUN echo $msg1RUN echo $msg2# 运行时期,我们会运行的指令(根据之前创建的镜像启动一个容器,容器启动默认运行的命令)CMD ["/bin/sh","-c","echo $msg1;echo $msg2"]
[root@i-id8g0yu9 ~]# docker build --no-cache -t dockerfilearg2:v1 -f dockerfileArg2 .Sending build context to Docker daemon 22.53kBStep 1/7 : FROM alpine---> 6dbb9cc54074Step 2/7 : LABEL maintainer="TANGZHI "age=24---> Running in 6f6be6d001e0Removing intermediate container 6f6be6d001e0---> d3cef1d085a5Step 3/7 : ENV msg1=hello---> Running in dd2be1e7c37cRemoving intermediate container dd2be1e7c37c---> 034e061f70ccStep 4/7 : ENV msg2=$msg1---> Running in 77908fc091f6Removing intermediate container 77908fc091f6---> 5c5499ac0a19Step 5/7 : RUN echo $msg1---> Running in 212c8ea2dcb2helloRemoving intermediate container 212c8ea2dcb2---> 5db13711e330Step 6/7 : RUN echo $msg2---> Running in 5e21ac6410e1helloRemoving intermediate container 5e21ac6410e1---> 4765e9d7d753Step 7/7 : CMD ["/bin/sh","-c","echo $msg1;echo $msg2"]---> Running in 67cb73e39262Removing intermediate container 67cb73e39262---> bf71cc3088eaSuccessfully built bf71cc3088eaSuccessfully tagged dockerfilearg2:v1[root@i-id8g0yu9 ~]# docker run -it -e msg1=66666 dockerfilearg2:v1 66666hello[root@i-id8g0yu9 ~]#
⑦. ADD 、COPY 复制文件
①. ADD和COPY的功能是一样的,ADD多了自动下载远程文件和解压的功能# 这是我的第一个dockerfile镜像FROM alpine# 把上下文context指定的内容复制到镜像中,如果是压缩包,自动解压,如果是远程文件,自动下载# 把当前内容复制到alpine小系统里面ADD https://download.redis.io/releases/redis-6.2.1.tar.gz /dest/RUN ls -l# RUN 指令上下并没有上下文关系RUN cd /dest# 当前还是列举的跟目录RUN ls -lRUN cd /dest && ls -l
[root@i-id8g0yu9 ~]# docker build --no-cache -t dockerfileadd:v1 -f dockerfileADD .Sending build context to Docker daemon 27.65kBStep 1/6 : FROM alpine---> 6dbb9cc54074Step 2/6 : ADD https://download.redis.io/releases/redis-6.2.1.tar.gz /dest/Downloading [==================================================>] 2.438MB/2.438MB---> 80aaa61dc520Step 3/6 : RUN ls -l---> Running in 1acdb19a9af4total 8drwxr-xr-x 2 rootroot4096 Apr 14 10:25 bindrwxr-xr-x 2 rootroot 32 Apr 18 12:53 destdrwxr-xr-x 5 rootroot 340 Apr 18 12:53 devdrwxr-xr-x 1 rootroot 66 Apr 18 12:53 etcdrwxr-xr-x 2 rootroot 6 Apr 14 10:25 homedrwxr-xr-x 7 rootroot 247 Apr 14 10:25 libdrwxr-xr-x 5 rootroot 44 Apr 14 10:25 mediadrwxr-xr-x 2 rootroot 6 Apr 14 10:25 mntdrwxr-xr-x 2 rootroot 6 Apr 14 10:25 optdr-xr-xr-x 114 rootroot 0 Apr 18 12:53 procdrwx------ 2 rootroot 6 Apr 14 10:25 rootdrwxr-xr-x 2 rootroot 6 Apr 14 10:25 rundrwxr-xr-x 2 rootroot4096 Apr 14 10:25 sbindrwxr-xr-x 2 rootroot 6 Apr 14 10:25 srvdr-xr-xr-x 13 rootroot 0 Apr 18 12:53 sysdrwxrwxrwt 2 rootroot 6 Apr 14 10:25 tmpdrwxr-xr-x 7 rootroot 66 Apr 14 10:25 usrdrwxr-xr-x 12 rootroot 137 Apr 14 10:25 varRemoving intermediate container 1acdb19a9af4---> aff230b986d5Step 4/6 : RUN cd /dest---> Running in e154c1af02e8Removing intermediate container e154c1af02e8---> ef4756ff7262Step 5/6 : RUN ls -l---> Running in 32c3f351c176total 8drwxr-xr-x 2 rootroot4096 Apr 14 10:25 bindrwxr-xr-x 2 rootroot 32 Apr 18 12:53 destdrwxr-xr-x 5 rootroot 340 Apr 18 12:53 devdrwxr-xr-x 1 rootroot 66 Apr 18 12:53 etcdrwxr-xr-x 2 rootroot 6 Apr 14 10:25 homedrwxr-xr-x 7 rootroot 247 Apr 14 10:25 libdrwxr-xr-x 5 rootroot 44 Apr 14 10:25 mediadrwxr-xr-x 2 rootroot 6 Apr 14 10:25 mntdrwxr-xr-x 2 rootroot 6 Apr 14 10:25 optdr-xr-xr-x 113 rootroot 0 Apr 18 12:53 procdrwx------ 2 rootroot 6 Apr 14 10:25 rootdrwxr-xr-x 2 rootroot 6 Apr 14 10:25 rundrwxr-xr-x 2 rootroot4096 Apr 14 10:25 sbindrwxr-xr-x 2 rootroot 6 Apr 14 10:25 srvdr-xr-xr-x 13 rootroot 0 Apr 18 12:53 sysdrwxrwxrwt 2 rootroot 6 Apr 14 10:25 tmpdrwxr-xr-x 7 rootroot 66 Apr 14 10:25 usrdrwxr-xr-x 12 rootroot 137 Apr 14 10:25 varRemoving intermediate container 32c3f351c176---> c45f1cca41d7Step 6/6 : RUN cd /dest && ls -l---> Running in c82e471ef25etotal 2384-rw------- 1 rootroot 2438367 Mar 2 06:35 redis-6.2.1.tar.gzRemoving intermediate container c82e471ef25e---> 5ac189b07621Successfully built 5ac189b07621Successfully tagged dockerfileadd:v1[root@i-id8g0yu9 ~]#
②. 这里能使用docker build -t demo:test .的方式构建,是由于这个Dockerfile的文件在当前目录下,如果不在,那么需要将. 变成指定的文件夹(.代表的是当前上下文坏境)
# 这是我的第一个dockerfile镜像FROM alpine# 把上下文context指定的内容复制到镜像中,如果是压缩包,自动解压,如果是远程文件,自动下载# 把当前内容复制到alpine小系统里面ADD https://download.redis.io/releases/redis-6.2.1.tar.gz /dest/# 本地linux系统的内容文件添加进去[宿主机--镜像内]# docker build -t demo:test .: .代表当前dockerfile指定的上下文坏境# 通过执行我们可以看到,redis进行了自动解压的处理ADD *.tar.gz /app/# RUN 指令上下并没有上下文关系RUN cd /dest && ls -lRUN cd /app && ls -l
[root@i-id8g0yu9 ~]# docker build --no-cache -t dockerfileadd2:v1 -f dockerfileADD2 .Sending build context to Docker daemon 2.468MBStep 1/5 : FROM alpine---> 6dbb9cc54074Step 2/5 : ADD https://download.redis.io/releases/redis-6.2.1.tar.gz /dest/Downloading [==================================================>] 2.438MB/2.438MB---> b7598fcec68bStep 3/5 : ADD *.tar.gz /app/---> 9b222d9290b5Step 4/5 : RUN cd /dest && ls -l---> Running in 4a32a2a9866btotal 2384-rw------- 1 rootroot 2438367 Mar 2 06:35 redis-6.2.1.tar.gzRemoving intermediate container 4a32a2a9866b---> f72d59644485Step 5/5 : RUN cd /app && ls -l---> Running in 48fe6f35756ftotal 4drwxrwxr-x 7 rootroot4096 Mar 2 06:14 redis-6.2.1Removing intermediate container 48fe6f35756f---> 762a609e68e9Successfully built 762a609e68e9Successfully tagged dockerfileadd2:v1
⑧. WORKDIR 配置工作目录
①. 根目录,WORKDIR指令可在Dockerfile中多次使用。 如果提供了相对路径,则它将相对于上一个WORK DIR指令的路径(如下面的/app/abc是根目录)FROM alpineRUN pwd && ls -l# 为以下所有命令运行指令了基础目录# /app/abcWORKDIR /app# 当我们使用docker exec 进入容器控制台,会发现根目录是 /app/abcWORKDIR abc# 复制到当前目录下COPY *.txt ./RUN pwd && ls -lCMD ping
[root@i-id8g0yu9 ~]# docker build --no-cache -t dockerfileworkdir:v1 -f dockerfileWORKDIR .Sending build context to Docker daemon 2.472MBStep 1/7 : FROM alpine---> 6dbb9cc54074Step 2/7 : RUN pwd && ls -l---> Running in 7ef554287c6f/total 8drwxr-xr-x 2 rootroot4096 Apr 14 10:25 bindrwxr-xr-x 5 rootroot 340 Apr 18 13:54 devdrwxr-xr-x 1 rootroot 66 Apr 18 13:54 etcdrwxr-xr-x 2 rootroot 6 Apr 14 10:25 homedrwxr-xr-x 7 rootroot 247 Apr 14 10:25 libdrwxr-xr-x 5 rootroot 44 Apr 14 10:25 mediadrwxr-xr-x 2 rootroot 6 Apr 14 10:25 mntdrwxr-xr-x 2 rootroot 6 Apr 14 10:25 optdr-xr-xr-x 111 rootroot 0 Apr 18 13:54 procdrwx------ 2 rootroot 6 Apr 14 10:25 rootdrwxr-xr-x 2 rootroot 6 Apr 14 10:25 rundrwxr-xr-x 2 rootroot4096 Apr 14 10:25 sbindrwxr-xr-x 2 rootroot 6 Apr 14 10:25 srvdr-xr-xr-x 13 rootroot 0 Apr 18 12:58 sysdrwxrwxrwt 2 rootroot 6 Apr 14 10:25 tmpdrwxr-xr-x 7 rootroot 66 Apr 14 10:25 usrdrwxr-xr-x 12 rootroot 137 Apr 14 10:25 varRemoving intermediate container 7ef554287c6f---> 27e092e104fbStep 3/7 : WORKDIR /app---> Running in ee015d4b2a18Removing intermediate container ee015d4b2a18---> 4419d4f77345Step 4/7 : WORKDIR abc---> Running in bc8172263488Removing intermediate container bc8172263488---> e29383588c07Step 5/7 : COPY *.txt ./---> 715b2d4db2d9Step 6/7 : RUN pwd && ls -l---> Running in 5e5c8d7ab9b8/app/abctotal 4-rw-r--r-- 1 rootroot 5 Apr 18 13:46 a.txtRemoving intermediate container 5e5c8d7ab9b8---> d196ffbdf968Step 7/7 : CMD ping ---> Running in e0b6b78b1eecRemoving intermediate container e0b6b78b1eec---> a1be08fec3d1Successfully built a1be08fec3d1Successfully tagged dockerfileworkdir:v1[root@i-id8g0yu9 ~]# docker run -d --name myworkdir dockerfileworkdir:v1b4d8744b6a920fa5eea4b2388ede0e04489905a8449d0c2e40ef8d3d298cfecb[root@i-id8g0yu9 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTSNAMESb4d8744b6a92 dockerfileworkdir:v1 "/bin/sh -c 'ping ba…" 3 seconds ago Up 3 seconds myworkdir[root@i-id8g0yu9 ~]# docker exec -it b4d8744b6a92 /bin/sh/app/abc #
⑨. VOLUME 创建数据卷挂载点
①. 把容器的某些文件夹映射到主机外部
②. 写法:这个一般写在最后
VOLUME ["/var/log/"] #可以是JSON数组
VOLUME /var/log #可以直接写
VOLUME /var/log /var/db #可以空格分割多个
③. 注意:用VOLUME声明了卷,那么以后对于卷内容的修改会被丢弃,所以一定在volume声明之前修改内容
FROM alpineRUN mkdir /hello && mkdir /appRUN echo 1111 > /hello/a.txtRUN echo 2222 > /app/b.txt# 挂在容器内的指定文件夹,如果不存在则创建# 指定了volume,即使启动容器没有指定-v参数,我们也会自动进行匿名卷挂载# 这里的 hello app 都是容器里面的文件夹,请你在使用镜像启动容器的时候,自动给宿主机上挂载VOLUME [ "/hello","/app"]# 用VOLUME声明了卷,那么以后对于卷内容的修改会被丢弃,所以一定在volume声明之前修改内容RUN echo 6666 > /hello/a.txtRUN echo 8888 > /app/b.txtCMD ping
[root@i-id8g0yu9 ~]# docker build --no-cache -t dockerfileworkvolume:v1 -f dockerfileVOLUME .Sending build context to Docker daemon 2.474MBStep 1/8 : FROM alpine---> 6dbb9cc54074Step 2/8 : RUN mkdir /hello && mkdir /app---> Running in 36ed19f5446dRemoving intermediate container 36ed19f5446d---> 42af237e9a7eStep 3/8 : RUN echo 1111 > /hello/a.txt---> Running in 662511d7ddb7Removing intermediate container 662511d7ddb7---> f744129965aeStep 4/8 : RUN echo 2222 > /app/b.txt---> Running in a8321f4f8d98Removing intermediate container a8321f4f8d98---> 1d03ca553eb7Step 5/8 : VOLUME [ "/hello","/app"]---> Running in 1d4ec1c1e8f7Removing intermediate container 1d4ec1c1e8f7---> 4e76b09577d3Step 6/8 : RUN echo 6666 > /hello/a.txt---> Running in 912d739bb4d4Removing intermediate container 912d739bb4d4---> da35323435ddStep 7/8 : RUN echo 8888 > /app/b.txt---> Running in bab5aceb4f7aRemoving intermediate container bab5aceb4f7a---> 73c45738db48Step 8/8 : CMD ping ---> Running in 05bedb917269Removing intermediate container 05bedb917269---> a01440e2a675Successfully built a01440e2a675Successfully tagged dockerfileworkvolume:v1[root@i-id8g0yu9 ~]# docker run -d dockerfileworkvolume:v156ef53c95a6c7f96a8cf308be8393ee53fb70a4802f7c43e4519cf5fab438abc[root@i-id8g0yu9 ~]# docker psCONTAINER ID IMAGE COMMAND CREATEDSTATUSPORTSNAMES56ef53c95a6c dockerfileworkvolume:v1 "/bin/sh -c 'ping ba…" 4 seconds ago Up 3 seconds stupefied_ptolemyb4d8744b6a92 dockerfileworkdir:v1"/bin/sh -c 'ping ba…" 49 minutes ago Up 49 minutes myworkdir[root@i-id8g0yu9 ~]# docker inspect 56ef53c95a6c[{"Id": "56ef53c95a6c7f96a8cf308be8393ee53fb70a4802f7c43e4519cf5fab438abc","Created": "-04-18T14:45:15.782034507Z","Path": "/bin/sh","Args": ["-c","ping "],"State": {"Status": "running","Running": true,"Paused": false,"Restarting": false,"OOMKilled": false,"Dead": false,"Pid": 8131,"ExitCode": 0,"Error": "","StartedAt": "-04-18T14:45:16.143344962Z","FinishedAt": "0001-01-01T00:00:00Z"},"Image": "sha256:a01440e2a675dab49c9fb9c788e890c81913e7f15de3a4071fec51a5a5475aea","ResolvConfPath": "/var/lib/docker/containers/56ef53c95a6c7f96a8cf308be8393ee53fb70a4802f7c43e4519cf5fab438abc/resolv.conf","HostnamePath": "/var/lib/docker/containers/56ef53c95a6c7f96a8cf308be8393ee53fb70a4802f7c43e4519cf5fab438abc/hostname","HostsPath": "/var/lib/docker/containers/56ef53c95a6c7f96a8cf308be8393ee53fb70a4802f7c43e4519cf5fab438abc/hosts","LogPath": "/var/lib/docker/containers/56ef53c95a6c7f96a8cf308be8393ee53fb70a4802f7c43e4519cf5fab438abc/56ef53c95a6c7f96a8cf308be8393ee53fb70a4802f7c43e4519cf5fab438abc-json.log","Name": "/stupefied_ptolemy","RestartCount": 0,"Driver": "overlay2","Platform": "linux","MountLabel": "","ProcessLabel": "","AppArmorProfile": "","ExecIDs": null,"HostConfig": {"Binds": null,"ContainerIDFile": "","LogConfig": {"Type": "json-file","Config": {}},"NetworkMode": "default","PortBindings": {},"RestartPolicy": {"Name": "no","MaximumRetryCount": 0},"AutoRemove": false,"VolumeDriver": "","VolumesFrom": null,"CapAdd": null,"CapDrop": null,"CgroupnsMode": "host","Dns": [],"DnsOptions": [],"DnsSearch": [],"ExtraHosts": null,"GroupAdd": null,"IpcMode": "private","Cgroup": "","Links": null,"OomScoreAdj": 0,"PidMode": "","Privileged": false,"PublishAllPorts": false,"ReadonlyRootfs": false,"SecurityOpt": null,"UTSMode": "","UsernsMode": "","ShmSize": 67108864,"Runtime": "runc","ConsoleSize": [0,0],"Isolation": "","CpuShares": 0,"Memory": 0,"NanoCpus": 0,"CgroupParent": "","BlkioWeight": 0,"BlkioWeightDevice": [],"BlkioDeviceReadBps": null,"BlkioDeviceWriteBps": null,"BlkioDeviceReadIOps": null,"BlkioDeviceWriteIOps": null,"CpuPeriod": 0,"CpuQuota": 0,"CpuRealtimePeriod": 0,"CpuRealtimeRuntime": 0,"CpusetCpus": "","CpusetMems": "","Devices": [],"DeviceCgroupRules": null,"DeviceRequests": null,"KernelMemory": 0,"KernelMemoryTCP": 0,"MemoryReservation": 0,"MemorySwap": 0,"MemorySwappiness": null,"OomKillDisable": false,"PidsLimit": null,"Ulimits": null,"CpuCount": 0,"CpuPercent": 0,"IOMaximumIOps": 0,"IOMaximumBandwidth": 0,"MaskedPaths": ["/proc/asound","/proc/acpi","/proc/kcore","/proc/keys","/proc/latency_stats","/proc/timer_list","/proc/timer_stats","/proc/sched_debug","/proc/scsi","/sys/firmware"],"ReadonlyPaths": ["/proc/bus","/proc/fs","/proc/irq","/proc/sys","/proc/sysrq-trigger"]},"GraphDriver": {"Data": {"LowerDir": "/var/lib/docker/overlay2/bca4693743c24765c88e89c05892e9b8f3f0b39918c5a400d58c9b9db5ec450c-init/diff:/var/lib/docker/overlay2/8623d3705ceea6e0f9349ac0645977e1fa8c45cc9ea6337115098c03d259a200/diff:/var/lib/docker/overlay2/960ab6c1f64fd999f44c90be57256371c1e5dd43f115e1d2ff11037408a8ffc8/diff:/var/lib/docker/overlay2/871b7ffab75435d24006f3f7bff690c903328b273764a7e4ab1922bece5b8ad7/diff:/var/lib/docker/overlay2/43d78cac3804ed1dc62283f315a185e8136796e5779d9ee8717fa9a2d99d6edd/diff","MergedDir": "/var/lib/docker/overlay2/bca4693743c24765c88e89c05892e9b8f3f0b39918c5a400d58c9b9db5ec450c/merged","UpperDir": "/var/lib/docker/overlay2/bca4693743c24765c88e89c05892e9b8f3f0b39918c5a400d58c9b9db5ec450c/diff","WorkDir": "/var/lib/docker/overlay2/bca4693743c24765c88e89c05892e9b8f3f0b39918c5a400d58c9b9db5ec450c/work"},"Name": "overlay2"},"Mounts": [{"Type": "volume","Name": "65adbd1e4997c8df05a05b30ab1a2c3df970e19b0dd38f579f428ec8442810b9","Source": "/var/lib/docker/volumes/65adbd1e4997c8df05a05b30ab1a2c3df970e19b0dd38f579f428ec8442810b9/_data","Destination": "/app","Driver": "local","Mode": "","RW": true,"Propagation": ""},{"Type": "volume","Name": "1c3739d31bd487d847d0101ac2d48bbdb661cc9cbe97799de86181c2f50d98db","Source": "/var/lib/docker/volumes/1c3739d31bd487d847d0101ac2d48bbdb661cc9cbe97799de86181c2f50d98db/_data","Destination": "/hello","Driver": "local","Mode": "","RW": true,"Propagation": ""}],"Config": {"Hostname": "56ef53c95a6c","Domainname": "","User": "","AttachStdin": false,"AttachStdout": false,"AttachStderr": false,"Tty": false,"OpenStdin": false,"StdinOnce": false,"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd": ["/bin/sh","-c","ping "],"Image": "dockerfileworkvolume:v1","Volumes": {"/app": {},"/hello": {}},"WorkingDir": "","Entrypoint": null,"OnBuild": null,"Labels": {}},"NetworkSettings": {"Bridge": "","SandboxID": "d4490ef3887d03e22812b820c963c82a8edfe45c5f3141676a03df8d7aecfc51","HairpinMode": false,"LinkLocalIPv6Address": "","LinkLocalIPv6PrefixLen": 0,"Ports": {},"SandboxKey": "/var/run/docker/netns/d4490ef3887d","SecondaryIPAddresses": null,"SecondaryIPv6Addresses": null,"EndpointID": "671b069ea364448c75dbbb4d9365c60b46abf392bdcca26bc9713cf9051baa2e","Gateway": "172.17.0.1","GlobalIPv6Address": "","GlobalIPv6PrefixLen": 0,"IPAddress": "172.17.0.3","IPPrefixLen": 16,"IPv6Gateway": "","MacAddress": "02:42:ac:11:00:03","Networks": {"bridge": {"IPAMConfig": null,"Links": null,"Aliases": null,"NetworkID": "24c026c0a26cfb78a82f033887c3669c4ccaf63060e02fefe51e958cb5037c32","EndpointID": "671b069ea364448c75dbbb4d9365c60b46abf392bdcca26bc9713cf9051baa2e","Gateway": "172.17.0.1","IPAddress": "172.17.0.3","IPPrefixLen": 16,"IPv6Gateway": "","GlobalIPv6Address": "","GlobalIPv6PrefixLen": 0,"MacAddress": "02:42:ac:11:00:03","DriverOpts": null}}}}][root@i-id8g0yu9 ~]# cd /var/lib/docker/volumes/65adbd1e4997c8df05a05b30ab1a2c3df970e19b0dd38f579f428ec8442810b9/_data[root@i-id8g0yu9 _data]# lsb.txt[root@i-id8g0yu9 _data]# cat b.txt # 注意这里还有追加6666或者88882222[root@i-id8g0yu9 _data]#
⑩. USER 指定运行容器时的用户名或UID
# 这是我的第一个dockerfile镜像FROM alpine# 相当于给当前容器开一个用户,以后的命令可以用这个用户运行 有可能没有执行权限# 容器中的ROOT虽然不是lunux宿主机的真实root,但是可以改掉这个镜像的所有USER 1000:1000# 不自动解压# 以linux主机的用户为准,默认是root用户,如果我们不指定权限将复制失败COPY --chown=1000:1000 *.txt /a.txt# RUN 指令上下并没有上下文关系RUN ls -l
[root@i-id8g0yu9 ~]# docker build --no-cache -t dockerfileworkuser:v1 -f dockerfileUSER .Sending build context to Docker daemon 2.473MBStep 1/4 : FROM alpine---> 6dbb9cc54074Step 2/4 : USER 1000:1000---> Running in 7d4fd2b2a54cRemoving intermediate container 7d4fd2b2a54c---> 2561ad4ce2c2Step 3/4 : COPY --chown=1000:1000 *.txt /a.txt---> a21c8da0fb0cStep 4/4 : RUN ls -l---> Running in c9cbef9eac65total 12-rw-r--r-- 1 10001000 5 Apr 18 13:46 a.txtdrwxr-xr-x 2 rootroot4096 Apr 14 10:25 bindrwxr-xr-x 5 rootroot 340 Apr 18 14:22 devdrwxr-xr-x 1 rootroot 66 Apr 18 14:22 etcdrwxr-xr-x 2 rootroot 6 Apr 14 10:25 homedrwxr-xr-x 7 rootroot 247 Apr 14 10:25 libdrwxr-xr-x 5 rootroot 44 Apr 14 10:25 mediadrwxr-xr-x 2 rootroot 6 Apr 14 10:25 mntdrwxr-xr-x 2 rootroot 6 Apr 14 10:25 optdr-xr-xr-x 115 rootroot 0 Apr 18 14:22 procdrwx------ 2 rootroot 6 Apr 14 10:25 rootdrwxr-xr-x 2 rootroot 6 Apr 14 10:25 rundrwxr-xr-x 2 rootroot4096 Apr 14 10:25 sbindrwxr-xr-x 2 rootroot 6 Apr 14 10:25 srvdr-xr-xr-x 13 rootroot 0 Apr 18 12:58 sysdrwxrwxrwt 2 rootroot 6 Apr 14 10:25 tmpdrwxr-xr-x 7 rootroot 66 Apr 14 10:25 usrdrwxr-xr-x 12 rootroot 137 Apr 14 10:25 varRemoving intermediate container c9cbef9eac65---> db89e3d275a2Successfully built db89e3d275a2Successfully tagged dockerfileworkuser:v1[root@i-id8g0yu9 ~]#
⑩①. multi-stage builds 多阶段构建
# 最终版本FROM maven:3.5.2-jdk-8-slim AS buildappWORKDIR /appCOPY src .COPY pom.xml .RUN mvn clean packageRUN cp target/*.jar app.jarRUN ls -lFROM openjdk:8u282-slimRUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezoneLABEL maintainer="845195485@"COPY --from=buildapp /app/app.jar /app.jar# COPY demo-0.0.1-SNAPSHOT.jar /app.jarEXPOSE 8080# CMD ["--server.prot=8080"]ENV JAVA_OPTS=""ENV PARAMS=""ENTRYPOINT [ "sh", "-c", "java -Djava.security.egd=file:/dev/./urandom $JAVA_OPTS -jar /app.jar $PARAMS" ]
如果觉得《DOCKER04_详解Dockerfile基本指令 FROM LABEL RUN CMD ENTRYPOINT ARG ENV VOLUME USER》对你有帮助,请点赞、收藏,并留下你的观点哦!