服务热线
135-6963-3175
Dockerfile
用于构建镜像的文本文件,包含一条条指令。
主要关键字有:FROM RUN COPY ADD CMD ENTRYPOINT ENV ARG VOLUME EXPOSE WORKDIR USER HEALTHCHECK ONBUILD等
1、编写镜像文件
以下定制一个mysql镜像文件名为Dockerfile内容如下:
FROM mysql:5.7.17 MAINTAINER 1json RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ENV LANG=C.UTF-8
2、构建镜像
在Dockerfile文件的目录下执行:
$ docker build -t mysql:test .
注:.表示当前上下文路径,mysql:test为镜像名:镜像标签名称
.上下文路径不要放无用文件,因为会一起打包发送给docker引擎,文件过多会缓慢。
[root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE my/mysql v2 fc126db17f99 About an hour ago 563MB my/mysql v1 b53c20aab1d8 4 hours ago 544MB mysql latest 0d64f46acfd1 2 weeks ago 544MB hello-world latest bf756fb1ae65 7 months ago 13.3kB [root@localhost ~]# docker build -t mysql:test . Sending build context to Docker daemon 16.9kB Step 1/4 : FROM mysql:5.7.17 5.7.17: Pulling from library/mysql 6d827a3ef358: Downloading 3fe11378d5c0: Download complete ....... Status: Downloaded newer image for mysql:5.7.17 ---> 9546ca122d3a Step 2/4 : MAINTAINER 1json ---> Running in b81402cc770e Removing intermediate container b81402cc770e ---> 184e14e337a8 Step 3/4 : RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ---> Running in 8019e7b30f4d Removing intermediate container 8019e7b30f4d ---> 3499d618d686 Step 4/4 : ENV.UTF-8 ---> Running in 2307c3bf9e34 Removing intermediate container 2307c3bf9e34 ---> 8cab1fc0d50b Successfully built 8cab1fc0d50b Successfully tagged mysql:test [root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE mysql test 8cab1fc0d50b 10 minutes ago 407MB my/mysql v2 fc126db17f99 About an hour ago 563MB my/mysql v1 b53c20aab1d8 4 hours ago 544MB mysql latest 0d64f46acfd1 2 weeks ago 544MB hello-world latest bf756fb1ae65 7 months ago 13.3kB mysql 5.7.17 9546ca122d3a 3 years ago 407MB
指令说明:
FROM:指明基于FROM的镜像,后续的操作都是基于此镜像,例如上面后续操作都是基于mysql:5.7.17
MAINTAINER:是作者
RUN:用于执行命令,等同于在shell终端操作的命令。
命令过长可用 \ 换行和&&连接:例如:
RUN yum install wget RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" RUN tar -xvf redis.tar.gz 以上执行会创建 3 层镜像。可简化为以下格式: FROM centos RUN yum install wget \ && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \ && tar -xvf redis.tar.gz
COPY:复制指令,从上下文目录中复制文件或者目录到容器里指定路径。
COPY [--chown=<user>:<group>] <源路径1>... <目标路径> COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
[--chown=<user>:<group>]:可选参数,用户改变复制到容器内文件的拥有者和属组。
<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:
COPY hom* /mydir/ COPY hom?.txt /mydir/
<目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
ADD:和COPY使用格式一致。推荐COPY
ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
CMD:类似与RUN,不同在于:
时间点不同:CMD在docker run启动容器时运行,RUN在docker build构建镜像时
一般其作用于:为启动的容器指定默认要运行的程序,程序结束容器也结束。CMD指定的参数可被docker run命令所指定的参数覆盖。若存在多个CMD指令,则仅最后一个生效。
格式:
CMD <shell命令>
CMD ["<可执行文件或命令>","<param1>","<param2>",...]
CMD ["<param1>","<param2>",...] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数。
ENTRYPOINT
类似于CMD,但不会被docker run命令行参数指定的指令覆盖,且会当作参数传递给ENTRYPOINT 指令指定的程序。
如果运行 docker run 时使用了 --entrypoint 选项,此选项的参数可当作要运行的程序覆盖 ENTRYPOINT 指令指定的程序。
优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。
注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。
示例:
FROM nginx
ENTRYPOINT ["nginx", "-c"] # 定参CMD ["/etc/nginx/nginx.conf"] # 变参
1、不传参运行
$ docker run nginx:test
容器内会默认运行以下命令,启动主进程。
nginx -c /etc/nginx/nginx.conf
2、传参运行
$ docker run nginx:test -c /etc/nginx/new.conf
容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)
nginx -c /etc/nginx/new.conf
ENV
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
格式:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:
ENV NODE_VERSION 7.2.0RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \ && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"
ARGS
构建参数,与 ENV 作用一至。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。
格式:
ARG <参数名>[=<默认值>]
EXPOSE:声明开放容器端口,只是一个声明,并不一定是实际开放的端口
注意如下情况:
FROM nginx COPY ./index.html /usr/share/nginx/html EXPOSE 3000 构建完成后执行:docker run -p 3000:3000 -d nginx:v0在浏览器中输入localhost:3000,访问不到服务。关于EXPOSE的解释,官方文档给出的是:EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。 nginx运行的时候对外提供的端口默认是80,即便你在这里声明了3000,也不会改变默认的端口80。 因此,在声明EXPOSE的时候,一定要实现查明当前容器默认的服务端口。
VOLUME:创建容器挂载点映射容器目录。
因为容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中
为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。
VOLUME /data
这里的 /data 目录就会在运行时自动挂载为匿名卷。
任何向 /data 中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。当然,运行时可以覆盖这个挂载设置。
例子:
VOLUME /tmp /usr/tmp
"Mounts": [ { "Type": "volume", "Name": "3c18486ccfe419156ef62d346d29f6668ec34a236497c47f7e7907e95c310d0e", "Source": "/var/lib/docker/volumes/3c18486ccfe419156ef62d346d29f6668ec34a236497c47f7e7907e95c310d0e/_data", "Destination": "/tmp", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" }, { "Type": "volume", "Name": "c5b6e1e0f6db6e70f15d836caa9663173e4bd8e23db1817146c31348d931a43b", "Source": "/var/lib/docker/volumes/c5b6e1e0f6db6e70f15d836caa9663173e4bd8e23db1817146c31348d931a43b/_data", "Destination": "/usr/tmp", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ]
将容器中的/tmp和/usr/tmp目录映射到宿主机的目录
volume 在生成的时候如果不指定名称,便会随机生成。
volume 在容器停止或删除的时候会继续存在,如需删除需要显示声明。
$ docker rm -v <container_id>
$ docker volume rm <volume_name>
命令行挂载法:
例子:
docker run -it -v /home/dock/Downloads:/usr/Downloads ubuntu64 /bin/bash
冒号前为宿主机目录,必须为绝对路径,冒号后为镜像内挂载的路径。
现在镜像内就可以共享宿主机里的文件了。
默认挂载的路径权限为读写。如果指定为只读可以用:ro
docker run -it -v /home/dock/Downloads:/usr/Downloads:ro ubuntu64 /bin/bash
指定命名卷挂载:
docker run -d -v mydata:/data xxxx
在这行命令中,就使用了 mydata 这个命名卷挂载到了 /data 这个位置,替代了 Dockerfile 中定义的匿名卷的挂载配置。
使用 dokcer inspect mycontainer 可以查看到具体的挂载情况:
"Mounts": [ { "Type": "volume", "Name": "65df74449969fff0764c32e20f0862fdd65c3d509e9f012a26e17e6244cbece8", "Source": "/var/lib/docker/volumes/mydata/_data", "Destination": "/var/lib/mysql", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], ]
表示容器中的"/var/lib/mysql" 被自动匿名挂载到了本地机器上的 /var/lib/docker/volumes/***
创建管理 volume
# 创建一个卷 $ docker volume create my-vol # 卷列表 $ docker volume ls local my-vol # 卷信息 $ docker volume inspect my-vol [ { "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/my-vol/_data", "Name": "my-vol", "Options": {}, "Scope": "local" }] # 删除卷 $ docker volume rm my-vol
用卷启动容器
下例,将卷 myvol2 挂载到容器 /app/。-v 和 --mount 产生的效果相同,但下面命令不能同时执行,会冲突:
# --mount # 使用 --mount source=myvol2,target/app,readonly 创建只读的 $ docker run -d \ -it \ --name devtest \ --mount source=myvol2,target=/app \ nginx:latest # -v # 使用 -v myvol2:/app:ro 创建只读的 $ docker run -d \ -it \ --name devtest \ -v myvol2:/app \ nginx:latest
你可以执行 docker inspect devtest 验证卷是否创建并且挂载正确:
"Mounts": [ { "Type": "volume", "Name": "myvol2", "Source": "/var/lib/docker/volumes/myvol2/_data", "Destination": "/app", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ],
停止容器和清理卷:
$ docker container stop devtest
$ docker container rm devtest
$ docker volume rm myvol2
WORKDIR
用于指定容器的一个目录为工作目录, 容器启动时执行的命令会在该目录下执行,相当于设置容器的工作目录了。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。当使用相对目录的情况下,采用上一个WORKDIR指定的目录作为基准,相当与cd 命令,但不同的是指定了WORKDIR后,容器启动时执行的命令会在该目录下执行。
格式:
WORKDIR <工作目录路径>
可以在 docker run命令中用 -w参数覆盖掉WORKDIR指令的设置,如:
执行 docker run -w / myimage
USER
用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
格式:
USER <用户名>[:<用户组>]
HEALTHCHECK
用于指定某个程序或者指令来监控 docker 容器服务的运行状态。
格式:
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令,意思是禁止从父镜像继承的HEALTHCHECK生效。
HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。
注:
在Dockerfile中只能有一个HEALTHCHECK指令。如果您列出多个,则只有最后一个HEALTHCHECK将生效。
options的可设定参数:
interval:间隔(s秒、m分钟、h小时),从容器运行起来开始计时interval秒(或者分钟小时)进行第一次健康检查,随后每间隔interval秒进行一次健康检查;还有一种特例请看timeout解析。
--start-period=DURATION 启动时间, 默认 0s, 如果指定这个参数, 则必须大于 0s ;--start-period 为需要启动的容器提供了初始化的时间段, 在这个时间段内如果检查失败, 则不会记录失败次数。 如果在启动时间内成功执行了健康检查, 则容器将被视为已经启动, 如果在启动时间内再次出现检查失败, 则会记录失败次数。
timeout:执行command需要时间,比如curl 一个地址,如果超过timeout秒则认为超时是错误的状态,此时每次健康检查的时间是timeout+interval秒。
retries:连续检查retries次,如果结果都是失败状态,则认为这个容器是unhealth的
例子1:
FROM nginx:latest
HEALTHCHECK –interval=10s –timeout=3s –retries=3 CMD /bin/bash /opt/test.sh
#!/bin/bash ss -ant | grep 80 if [ $?==0 ] then echo 0 exlt 0 else echo 1 exit 1 fi
通过Dockerfile可以预计,容器启动10s内HEALTCHECK的状态为starting,10s后为healthy状态。脚本是监听容器的80端口,存在返回0,不存在返回1。
例子2:
HEALTHCHECK –interval=10s –timeout=3s –retries=3 CMD curl http://192.168.30.5:5000/v2
ONBUILD
用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这是执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。
格式:
ONBUILD <其它指令>