通过Dockerfile文件来定制Docker镜像
默认的Dockerfile文件名是Dockerfile,不带后缀 ,首字母大写。
通过Dockerfile文件构建过程是以一个镜像为基础,然后在其上进行定制其他东西。
Dockerfile文件里的每一行都是Dockerfile指令。
每一条Dockerfile命令构建一层。
注意:Docker 不是虚拟机,容器就是进程。
有了Dockerfile文件后只需要执行下面的命令就能构建并启动容器了:
~$ sudo docker build -t myubuntu:me . //别忘了最后的那个点,表示当前目录。
~$ sudo docker images //查看
- 1
- 2
Dockerfile 指令
1.FROM 指令
指定基础镜像,且必须是Dockerfile文件的第一条指令。指令格式:
FROM <image>
FROM <image>:<tag>
FROM <image>@<digest>
- 1
- 2
- 3
如:FROM nginx //以nginx 为基础镜像
如:FROM scratch //scratch是一个空白的镜像
2.MAINTAINER指令
设置维护者信息
MAINTAINER <name>
- 1
如:
MAINTAINER Jasper Xu
MAINTAINER sorex@163.com
MAINTAINER Jasper Xu sorex@163.com
3.RUN指令
执行构建命令,其格式有两种。
格式1:shell
RUN <命令>
- 1
如:
RUN echo ‘<h1>Hello, Docker!</h1>’ > /usr/share/nginx/html/index.html
RUN apk update
格式2:exec
RUN ["可执行文件", "参数1", "参数2"]
- 1
如:
RUN ["/etc/execfile", “arg1”, “arg1”]
4.ENV 指令
设置镜像环境变量,在镜像构建结束之后依旧存在镜像中 。
ENV <key> <value>
ENV <key>=<value> ...
- 1
- 2
如:
ENV TARGET_DIR /app //ENV类似于linux的export
使用环境变量:
WORKDIR $TARGET_DIR
延申:
注意:长命令可以用“\”符号来连接。遇到几个命令连在一起,可以用“&&”的方式连接,如上面这个命令:
ENV myName=“John Doe” myDog=Rex\ The\ Dog \
myCat=fluffy
上面这条命令等同于下面
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy
5.ARG指令
也是用于设置构建变量,与ENV类似,但ENV设置的环境变量在镜像构建结束之后依旧存在镜像中,而ARG则会消失。与docker build –build-arg =一样:
ARG <varname>=<value>
- 1
如:
ARG CODE_VERSION=latest
其实有些默认参数,无需指定,就可以直接使用,如:
HTTP_PROXY
http_proxy
HTTPS_PROXY
https_proxy
FTP_PROXY
ftp_proxy
NO_PROXY
no_proxy
6.ADD指令
添加文件,ADD与COPY相似,ADD指令可以从一个URL下载内容并复制到容器的文件系统中,也可以将压缩包解压后复制到容器的文件系统中,将本地文件添加到容器中,identity, gzip, bzip2,xz,tar.gz,tgz等类型的文件可以被tar -x命令解压。用ADD构建的镜像比用COPY的要大。
ADD <src>... <dest>
ADD ["<src>",... "<dest>"] 用于支持包含空格的路径
- 1
- 2
如:
ADD hom* /mydir/ //添加所有以"hom"开头的文件
ADD hom?.txt /mydir/ // ? 替代一个单字符,例如:“home.txt”
ADD test relativeDir/ //添加 “test” 到 WORKDIR
/relativeDir/
ADD test /absoluteDir/ //添加 “test” 到 /absoluteDir/
7.COPY指令
将本地文件或文件夹复制到镜像的指定路径下。
COPY ["<源路径1>",... "<目标路径>"]
- 1
如:
COPY /Local/Path/File /ImagesPath/File
8 .EXPOSE指令
暴露指定端口,用于指明这个镜像中的应用将会侦听某个端口,并且希望能将这个端口映射到主机的网络界面上。指定于外界交互的端口,在容器启动时用-p传递参数,例如docker run -p 3307:3306 …将容器内的3306绑定到本机的3307
EXPOSE <port> [<port>…]
- 1
如:
EXPOSE 80 443
EXPOSE 8080
9.CMD指令
设置镜像启动,Dockerfile只允许使用一次CMD指令。若使用多个,则只有最后一条生效,前面的都将被抵消。CMD 指令的格式和 RUN 相似,也是两种格式:
格式1:shell
CMD <命令>
- 1
格式2:exec
CMD ["可执行文件", "参数1", "参数2"…]
- 1
CMD命令会在构建容器并在容器启动后才被调用。命令使用如下:
CMD [“executable”,“param1”,“param2”] (执行可执行文件,优先)
CMD [“param1”,“param2”] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
CMD command param1 param2 (执行shell内部命令)
CMD echo “This is a test.” | wc -
CMD ["/usr/bin/wc","–help"]
10.ENTRYPOINT指令
设置容器接入点,使其可执行化。
格式1:
ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先)
- 1
格式2:
ENTRYPOINT command param1 param2 (shell内部命令)
- 1
命令使用例子:
在目录~/Desktop/test下创建Dockerfile文件,内容如下:
FROM ubuntu
ENTRYPOINT [“ls”, “-s”]
CMD ["-l"] //配合CMD用,CMD命令可省去"application"即executable可执行文件名(不需要指定),只使用参数
构建镜像:
~/Desktop/test$ sudo docker build -t haha:mama .
Sending build context to Docker daemon 2.048kB
Step 1/3 : From ubuntu
---> ea4c82dcd15a
Step 2/3 : ENTRYPOINT ["ls","-s"]
---> Running in b0d0c16a68e8
Removing intermediate container b0d0c16a68e8
---> 985846647a9b
Step 3/3 : CMD ["-l"]
---> Running in dd8b73f52b97
Removing intermediate container dd8b73f52b97
---> 58f8ca714eba
Successfully built 58f8ca714eba
Successfully tagged haha:mama
wong@wong-HP-ProDesk-480-G2-MT:~/Desktop/test$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
haha mama 58f8ca714eba 12 seconds ago 85.8MB
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
创建容器
~/Desktop/test$ sudo docker create -it --name hahamama haha:mama
e318527e4bb33fdce39edd3841252f0907631940cebe0213ee0384fed52b8a45
- 1
- 2
- 3
启动容器
~/Desktop/test$ sudo docker start -a -i hahamama
total 64
4 drwxr-xr-x 2 root root 4096 Oct 18 21:03 bin
4 drwxr-xr-x 2 root root 4096 Apr 24 2018 boot
0 drwxr-xr-x 5 root root 360 Mar 12 04:07 dev
4 drwxr-xr-x 1 root root 4096 Mar 12 04:07 etc
4 drwxr-xr-x 2 root root 4096 Apr 24 2018 home
4 drwxr-xr-x 8 root root 4096 Oct 18 21:02 lib
4 drwxr-xr-x 2 root root 4096 Oct 18 21:02 lib64
4 drwxr-xr-x 2 root root 4096 Oct 18 21:02 media
4 drwxr-xr-x 2 root root 4096 Oct 18 21:02 mnt
4 drwxr-xr-x 2 root root 4096 Oct 18 21:02 opt
0 dr-xr-xr-x 303 root root 0 Mar 12 04:07 proc
4 drwx------ 2 root root 4096 Oct 18 21:03 root
4 drwxr-xr-x 1 root root 4096 Oct 19 00:47 run
4 drwxr-xr-x 1 root root 4096 Oct 19 00:47 sbin
4 drwxr-xr-x 2 root root 4096 Oct 18 21:02 srv
0 dr-xr-xr-x 13 root root 0 Mar 12 04:07 sys
4 drwxrwxrwt 2 root root 4096 Oct 18 21:03 tmp
4 drwxr-xr-x 1 root root 4096 Oct 18 21:02 usr
4 drwxr-xr-x 1 root root 4096 Oct 18 21:03 var
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
瞧!容器一启动就执行了ls -s -l这个shell命令。
但是很可惜,一启动完输入以上信息后,容器也停了。所以不建议使用ENTRYPOINT指令。
11.VOLUME指令
设置数据卷,用于指定持久化目录,向基于镜像创建的容器添加数据卷(在容器中设置一个挂载点,可以用来让其他容器挂载或让宿主机访问,以实现数据共享或对容器数据的备份、恢复或迁移)。数据卷可以在容器间共享和重用,数据卷的修改是立即生效的,数据卷的修改不会对更新镜像产生影响。数据卷会一直存在,直到没有任何容器使用它(没有容器使用的,它也会存在于宿主机上,只是此时和普通文件一样。)
可以通过命令在创建容器时用-v创建数据卷,如:
sudo docker create -it --name myContainer -v /hostVol:/ContainerV myv:2018 bash
也可以通过如下命令创建数据卷(不建议用这种方式):
sudo docker run -v ~/opt/data/mysql:/var/lib/mysql container // 将宿主机~/opt/data/mysql和容器内的/var/lib/mysql做持久化关联,容器启动时会加载,容器关闭后会回写。
dockerfile中只能指定容器中的路径
使用方法如下:
VOLUME ["/data"]
VOLUME ["/data"]
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
- 1
- 2
- 3
一个小实例:
在目录~/Desktop/test下创建Dockerfile文件,内容如下
From ubuntu
VOLUME ["/wong/folder1","/wong/folder2","/wong/folder3"]
VOLUME "/wong/haha"
- 1
- 2
- 3
构建镜像
~/Desktop/test$ sudo docker build . -t haha:2019
Sending build context to Docker daemon 2.048kB
Step 1/3 : From ubuntu
---> ea4c82dcd15a
Step 2/3 : VOLUME ["/wong/folder1","/wong/folder2","/wong/folder3"]
---> Running in 97682b2376c0
Removing intermediate container 97682b2376c0
---> ba1e74e3af36
Step 3/3 : VOLUME "/wong/haha"
---> Running in cea037f06ff3
Removing intermediate container cea037f06ff3
---> 31a88002ab49
Successfully built 31a88002ab49
Successfully tagged haha:2019
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
利用构建出来的镜像创建容器
~/Desktop/test$ sudo docker create -it --name haha2019 haha:2019 bash
ce71292add38fa529bb23d08b380e9de50a437709af6c13ace54ec18f8ac1335
- 1
- 2
运行容器
~/Desktop/test$ sudo docker start -a -i haha2019
- 1
在容器上看创建的数据卷目录
root@ce71292add38:/wong# ls
folder1 folder2 folder3 haha
- 1
- 2
查看docker实例的数据卷配置信息
可以清楚看到容器的数据卷与宿主机上的相应目录的对应关系。
~$ sudo docker inspect haha2019 | grep -A 41 Mounts "Mounts": [ { "Type": "volume", "Name": "00f2086ccd364f670195b2596fdad84a91621d10a5382b487675074dce7a2296", "Source": "/var/lib/docker/volumes/00f2086ccd364f670195b2596fdad84a91621d10a5382b487675074dce7a2296/_data", "Destination": "/wong/haha", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" }, { "Type": "volume", "Name": "3fe567723e348f942588ae5cdec57da99441d332ff5637f87343dffd518b03ab", "Source": "/var/lib/docker/volumes/3fe567723e348f942588ae5cdec57da99441d332ff5637f87343dffd518b03ab/_data", "Destination": "/wong/folder1", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" }, { "Type": "volume", "Name": "509b7466faa23da3803aae40004d8ed88bd0e74c954374ea6c66f139463a0452", "Source": "/var/lib/docker/volumes/509b7466faa23da3803aae40004d8ed88bd0e74c954374ea6c66f139463a0452/_data", "Destination": "/wong/folder2", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" }, { "Type": "volume", "Name": "2199971d80e01b186ee533c53ef00e755d0e7a71e21797e505a2f3e2af8d7049", "Source": "/var/lib/docker/volumes/2199971d80e01b186ee533c53ef00e755d0e7a71e21797e505a2f3e2af8d7049/_data", "Destination": "/wong/folder3", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ],
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
在容器上创建一个文件测试一下:
root@ce71292add38:/wong# cd haha
root@ce71292add38:/wong/haha# echo "hello world" > ht.txt
root@ce71292add38:/wong/haha# ls
ht.txt
- 1
- 2
- 3
- 4
根据前面得到的docker的配置信息,查看在宿主机上的文件
~$ su root
Password:
root@wong-HP-ProDesk-480-G2-MT:/home/wong# cd /var/lib/docker/volumes/00f2086ccd364f670195b2596fdad84a91621d10a5382b487675074dce7a2296/_data
root@wong-HP-ProDesk-480-G2-MT:/var/lib/docker/volumes/00f2086ccd364f670195b2596fdad84a91621d10a5382b487675074dce7a2296/_data# ls
ht.txt
root@wong-HP-ProDesk-480-G2-MT:/var/lib/docker/volumes/00f2086ccd364f670195b2596fdad84a91621d10a5382b487675074dce7a2296/_data# cat ht.txt
hello world
- 1
- 2
- 3
- 4
- 5
- 6
- 7
注意:Dockerfile中只能指定容器中的路径
12 .USER指令
设置构建用户,指定运行容器时的用户名或UID(默认为root),RUN, CMD 、 ENTRYPOINT都将用该用户执行。可以用docker run -u选项来覆盖。
USER user
USER user:group
USER uid:gid
- 1
- 2
- 3
指定的用户需要在USER指令之前创建:
RUN groupadd -r newuser && -r -g newuser newuser
USER newuser
- 1
- 2
13.WORKDIR指令
设置工具目录,Dockerfile中的WORKDIR指令用于指定容器的一个目录,容器启动时执行的命令会在该目录下执行,指定了指定RUN、CMD、ENTERYPOINT命令的工作目录。通过一个实例来讲解:
在~/Desktop/test/目录下创建一个Dockerfile文件,内容如下:
FROM ubuntu
MAINTAINER hello
RUN mkdir /mydir && echo hello world > /mydir/test.txt
WORKDIR /mydir
CMD ["more" ,"test.txt"]
- 1
- 2
- 3
- 4
- 5
构建镜像
~/Desktop/test$ sudo docker build . -t hello:2019
[sudo] password for wong:
Sending build context to Docker daemon 14.85kB
Step 1/5 : From ubuntu
---> ea4c82dcd15a
Step 2/5 : MAINTAINER wongkyunban
---> Running in 25583fe9afb3
Removing intermediate container 25583fe9afb3
---> 59ca2e940204
Step 3/5 : RUN mkdir /workspace && echo "hello world" > /workspace/hello.txt
---> Running in 66cc630275cd
Removing intermediate container 66cc630275cd
---> eb144d163ffb
Step 4/5 : WORKDIR /workspace
---> Running in 7ea79f4611d1
Removing intermediate container 7ea79f4611d1
---> a52b4a7f79f4
Step 5/5 : CMD ["more","hello.txt"]
---> Running in bf81ea9073c5
Removing intermediate container bf81ea9073c5
---> 1cdc460f1bb9
Successfully built 1cdc460f1bb9
Successfully tagged hello:2019
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
创建容器
~/Desktop/test$ sudo docker create -it --name hello2019 hello:2019 bash
a9d93f4fde2757eece21914f1a172c85e8fc5d1ef68c5ccafa4fb3fe432907af
- 1
- 2
启动容器
wong@wong-HP-ProDesk-480-G2-MT:~/Desktop/test$ sudo docker start -a -i hello2019
root@a9d93f4fde27:/workspace#
- 1
- 2
- 3
- 4
没有指定工作目录的容器启动后是这样的:
root@ce71292add38:/#
- 1
我们可以看到一启动容器后,工作目录由“/”变为了“/workspace”。
我们从其他三种运行方式运行一下我们的镜像:
第一种:
~/Desktop/test$ sudo docker run hello:2019
::::::::::::::
hello.txt
::::::::::::::
hello world
- 1
- 2
- 3
- 4
- 5
- 6
第二种:
~/Desktop/test$ sudo docker run hello:2019 more hello.txt
::::::::::::::
hello.txt
::::::::::::::
hello world
- 1
- 2
- 3
- 4
- 5
- 6
可以看到两种方式都输出同样的东西,可以看出,more的参数是hello.txt,但没有指定路径却能成功,说明当前路径就是上面WORKDIR指令设置的。
如果我们在上面的Dockerfile中把WORKDIR指令去掉,创建容器运行会报文件不存在错误。
可以在docker run命令中用-w参数覆盖掉WORKDIR指令的设置,如:
~/Desktop/test$ sudo docker run -w / hello:2019
more: stat of hello.txt failed: No such file or directory
- 1
- 2
上面的-w参数把容器的工作目录设置成了根目录,而根目录下没有hello.txt文件。所以结果显示:
more: stat of hello.txt failed: No such file or directory。
可以使用多个WORKDIR指令,后续命令的参数是相对路径,则会基于之前的命令指定的路径,如
WORKDIR /a
WORKDIR b
WORKDIR c
- 1
- 2
- 3
则最终路径为/a/b/c
14.LABEL指令
设置元数据,给镜像添加信息。使用docker inspect可查看镜像的相关信息,标签信息会保存到镜像中,如果某个值已经存在,新的标签元素会覆盖它。
LABEL =<”value”>
如:
LABEL “com.example.vendor”=“ACME Incorporated”
LABEL com.example.label-with-value=“foo”
LABEL version=“1.0”
LABEL description=“This text illustrates
that label-values can span multiple lines.”
在~/Desktop/test/目录下创建一个Dockerfile文件,内容如下:
From ubuntu
LABEL "HELLO_WORLD"="This is me!"
RUN mkdir /workspace && echo "hello world" > /workspace/hello.txt
WORKDIR /workspace
CMD ["more","hello.txt"]
- 1
- 2
- 3
- 4
- 5
- 6
构建镜像:
~/Desktop/test$ sudo docker build . -t hatest:2019
- 1
- 2
使用docker inspect查看镜像信息
~/Desktop/test$ sudo docker inspect hatest:2019 | grep -A 10 Labels "Labels": { "HELLO_WORLD": "This is me!" }
- 1
- 2
- 3
- 4
- 5
15 .STOPSIGNAL指令
设置停止信号STOPSIGNAL SIGKILL ,当启动的容器在停止时,就会发送SIGKILL信号
STOPSIGNAL指令设置系统调用信号,当容器退出时,系统就会把信号发给容器。这个信号可以是合法的unsigned类型的整数,这个整数对应着内核系统调用表的索引。例如9, 或者用一个信号名如SIGKILL。
Dockerfile可以这么写
From ubuntu
STOPSIGNAL SIGKILL
- 1
- 2
- 3
16.HEALTHCHECK指令
检查镜像状态,检查容器启动运行时是否正常
HEALTHCHECK [OPTIONS] CMD command
- 1
如:
检查容器的CMD指令运行是否正常
HEALTHCHECK –interval=5m –timeout=3s \
CMD curl -f http://localhost/ || exit 1
- 1
- 2
17.SHELL指令
设置命令执行环境。默认使用/bin/sh作为shell环境。
SHELL ["executable", "parameters"]
- 1
如:
SHELL ["powershell", "-command"]
RUN Execute-MyCmdlet -param1 "c:\foo.txt"
- 1
- 2
- 3
等价于
powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
- 1
文章来源: blog.csdn.net,作者:WongKyunban,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/weixin_40763897/article/details/88417249
- 点赞
- 收藏
- 关注作者
评论(0)