本文发布于Cylon的收藏册,转载请著名原文链接~
一、使用前提
通用镜像未必与应用程序和配置是符合我们需要的。
1.1 常见镜像制作方式
常见制作镜像方式有两种
- 基于容器
- 基于镜像制作:编辑一个Dockerfile,而后根据此文件制作;
二、Dockerfile概述
Dockerfile只是构建Docker镜像的源代码,docker可以通过读取Dockerfile中的指令自动构建图像。Dockerfile是一个文本文档,其中包含用户可以在命令行上调用以组合图像的所有命令。用户可以使用 docker build
创建连续执行多个命令行指令的自动构建。
2.1 Dockerfile的工作模式
基于Dockerfile制作镜像时,需在专用目录放置Dockerfile文件,并且文件首字母必须大写。基于Dockerfile中打包的文件必须奇基于工作目录往下走的路径。在打包镜像时,.dockeringore
文件本身与所有包含在 .dockeringore
文件中的路径,都不被打包进去。在Dockerfile制作环境为底层镜像启动容器时所能够提供的环境。
2.2 环境变量替换
制作镜像中还可以使用环境变量。环境变量(使用ENV语句声明)也可以在某些指令中使用,因为Dockerfile
环境变量在 Dockerfile
中以 $variable_name
或${variable_name}
标记。
语法还支持一些标准`bash修饰符
${variable:-word}
表示如果设置了变量,那么结果将是该值。如果未设置变量,那么word将是结果。${variable+word}
表示如果设置了变量,则word将是结果,否则结果为空字符串。
三、Dockerfile指令说明
特别说明:Dockerfile中每一条指令都会生成一个新的镜像层。
FROM
FROM指令(最重要的一个),必须为Dockerfile文件开篇的第一个非注释行,用于为镜像文件构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境。基准镜像可以是任何可用镜像文件,默认情况下,docker build
会在docker主机上查找指定的镜像文件,在其不存在时,则会从 Docker Hub Registry
上拉取所需的镜像文件。如果找不到指定的镜像文件,docker build
会返回一个错误信息
Syntax:
FROM repository[:tag]
FROM registry/repository[:tag]
FROM resository@[digest] #←相同名称时,可以使用resository@镜像hush码指定镜像。
参数 | 说明- |
---|---|
reposotiry | 某一个镜像的仓库,如redis镜像仓库。 |
registry | docker镜像仓库,如docker hub,docker registry包含很多reposotiry,如nginx php tomcat等。不指定registry,默认从docker hub下载。 |
tag | image的标签,为可选项,省略时默认为latest。 |
MAINTANIER(depreacted)
MAINTANIER(depreacted)用于让Dockerfile制作者提供本人的详细信息。Dockerfile并不限制MAINTAINER指令可在出现的位置,但推荐将其放置于FROM指令之后。
Syntax
MAINTAINER <authtor's detail>
<author’s detail> 可是任何文本信息,但约定俗成地使用作者名称及邮箱地址
MAINTAINER "lc <12399.com@gmail.com>"
LABLE
LABLE可以提供Key value信息,比MAINTANIER具有更宽泛的使用领域。LABLE让用户提供格式各样的元数据,都是键值格式。如果在LABEL值中包含空格,请使用引号和反斜杠。image可以有多个tag。您可以在一行上指定多个tag。docker17+增加此指令。
Syntax:
LABEL <key>=<value> <key>=<value> <key>=<value>...
LABEL maintainer="lc <12399.com@gmail.com>"
COPY
用于从宿主机工作目录将文件复制至到镜像的文件系统中。
Syntax:
COPY src...dest
COPY "src"...."dest"
参数 | 说明 |
---|---|
src | 要复制的源文件或目录,支持使用通配符。 |
dest | 目标路径,即正在创建的image的文件系统路径;建议为dest使用绝对路径,否则,COPY指定则以WORKDIR为其起始路径。 |
注意:在路径中有空白字符时,通常使用第二种格式。
文件复制准则
src
必须是build上下文中的路径,不能是其父目录中的文件。- 如果src是目录,则其内部文件或子目录会被递归复制,但src目录自身不会被复制。 等同于
cp a/*
而不是cp -r a
- 如果指定了多个src,或在src中使用了通配符,则dest必须是一个目录,且必须以
/
结尾。 - 如果dest事先不存在,它将会被自动创建,这包括其父目录路径。
ADD
ADD指令类似于COPY指令,ADD支持使用TAR文件和URL路径。
add官方解释:ADD
如果src是以
Syntax:
ADD src dest
ADD ["src"…"dest"]
操作准则同COPY指令
-
如果
<src>
为URL且<dest>
不以/
结尾,则<src>
指定的文件将被下载并直接被创建为dest;如果dest以/
结尾,则文件名URL指定的文件将被直接下载并保存为dest/filename
-
如果src是一个本地系统上的可识别的压缩格式(identity,gzip,bzip2或xz)的本地 tar存档,则将其解压缩为目录。,其行为类似于
tar -xf
命令;然而,从URL远程网址不会自动解压。 -
如果src有多个,或其间接或直接使用了通配符,则dest必须是一个以
/
结尾的目录路径;如果dest不以/
结尾,则其被视作一个普通文件,src的内容将被直接写入到dest。
Dockerfile中每一条指令都会生成一个新的镜像层。尽量避免很多指令
WORKDIR
用于为Dockerfile中所有的 RUN
、CMD
、ENTRYPOINT
、COPY
和 ADD
指定设定工作目录
Syntax:
WORKDIR dirpath
在Dockerfile文件中,WORKDIR指令可出现多次,其路径也可以为相对路径,不过,其是相对此前一个WORKDR指令指定的路径。另外,WORKDIR也可满用由ENV指定定义的变量
例如
WORKDIR /var/log
WORKDIR $STATEPATH
VOLUME
用于在image中创建一个挂载点目录,以挂载Docker host上的卷或其它容器上的卷,在Dockerfile中的镜像自动指定VOLUME时,一般只能指定挂载点,不能指定宿主机文件。被称之为docker管理的卷。
Syntax:
VOLUME mountpoint
VOLUME ["mountpoint"]
如果挂载点目录路径下此前在文件存在,docker run命令会在卷挂载完成后将此前的所有文件复制到新挂载的卷中。
EXPOSE
用于为容器打开指定要监听的端口以实现与外部通信,写在文件中的端口暴露并不会直接暴露,当docker run -P
时不用声明端口,会自动读取镜像中指定要暴露的端口,动态分配到宿主机端口上。
Syntax:
EXPOSE port[/protocol] [port[/protocol]
protocol用于指定传输层协议,可为tcp或udp二者之一,默认为TCP协议。
EXPOSE指令可一次指定多个端口,例如
EXPOSE 11211/udp 11211/tcp
ENV
用于为镜像定义新需的环境变量,并可被Dockerfile文件中位于其后的其它指令(如ENV、ADD、COPY等)所调用格式为 $variable_name
或 ${variable_name}
。在Dockerfile中所定义的所有环境变量,是可以在启动容器后直接在容器中使用的变量。在运行容器时更改ENV并不会影响docker build
的值。
Syntax:
ENV key value
ENV key1=value1 key2=value2....
第一位格式中。key之后的所有内容均会被视作其value的组成部分,因此,一次只能设置一个变量。第二种格式可用一次设置多个变量,每个变量为一个 key=value
的键值对,如果value中包含空格,可以以反斜线(\)进行转义,也可通过对value加引号递行标识;另外,反斜线也可用于续行。
在定义多个变量时,建议使用第二种方式,以便在同一层中完成所有功能。
运行命令。
RUN
用于指定 dodker build
过程中运行的程序,其可以是任何命令。RUN可以运行多次的,如果多个命令彼此间有关联关系,建议在一条RUN中将多个Command写进来。
Syntax:
RUN command
RUN ["executable","param1","param2"]
第一种格式中,command通常是一个shell命令,且以 /bin/sh -c
来运行它,这意味着此进程在容器中的PID不为1,不能接枚Unix信号,因此,当使用 docker stop container
命令停止容器时,此进程接收不到SIGTERM信号;
第二种语法格式中的参数是一个JSON格式的数组,其中executable为要运行的命令,后面的 paramN
为传递给命令的选项或参数;然而,此种格式指定的命令不会以 /bin/sh -c
来发起,因此常见的shell操作如变量替换以及通配符(,*等)替换将不会进行;不过,如果要运行的命令依赖于此shell特性的话,可以将其替换为奏似下面的格式。
RUN ["/bin/bash" , "-c","executable", "param1"]
CMD是在镜像运行为容器时没有指定默认运行命令时所运行的命令。 RUN是在基于Dockerfile构建镜像时要运行的命令。将在docker build中运行。
CMD
类似于RUN指令,CMD指令也可用于运行任何命令或应用程序,不过,二者的运行时间点不同。RUN指令运行于镜像文件构建过程中,而CMD指令运行于基于Dockerfile构建出的新映像文件启动一个容器时
CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止;不过,CMD指定的命令其可以被docker run
的命令行选项所覆盖。在Dockerfile中可以存在多个CMD指令,但仅最后一个会生效。
Syntax:
CMD command
CMD ["executable" , "param1" , "param2"]
CMD ["param1" , "param2"]
- 使用第一种方式默认使用bin/sh -c
- 前两种语法格式的意义同RUN
- 第三种则用于为ENTRYPOINT指令提供默认参数
ENTRYPOINT
在docker run
时明明指定的运行命令为nginx,但是可以执行docker run -it --rm busybox ls /
,这表示了更改了镜像中默认要运行的程序。没有运行默认程序,转而运行了指定的命令。
对于自定义的镜像而言,默认在运行容器时运行的命令是可以被覆盖的。而不允许在运行命令是改变默认命令CMD就无法完成,而ENTRYPOINT
可以做到
类似CMD指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序。但是与CMD不同的是,。由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,而且,这些命令行参数会被当作参数传递给ENTRYPOINT指定的程序。当CMD和ENTRYPOINT同时存在时,CMD的内容会当做参数传给ENTRYPOINT。不过,docker run命令的–entrypoint选项的参教可覆盖ENTRYPOINT指令指定的程序。
Syntax:
ENTRYPOINT command
ENTRYPOINT ["executable","paraml","param2"]
docker run命令传入的命令参数会覆盖CMD指令的内容并且附加到ENTRYPOINT命令最后做为其参数使用,Dockerfile文件中也可以存在多个ENTRYPOINT指令,但仅有最后一个会生效
当同时CMD与ENTRYPOINT,在运行容器时传入参数会覆盖CMD,除非使用--entrypoint选项
否则ENTRYPOINT不能够被覆盖。
CMD ["/bin/httpd" , "-f" , "-h ${WEB00C_ROOT}" ]
ENTRYPOINT ["/bin/sh","-c"]
为什么非要同时使用CMD与ENTRYPOINT?
- 多数情况下ENTRYPOINT是用来指定一个shell,指定一个谁用来作为启动别的进程的服务进程。在命令行中的参数会当做他的子进程来启动。这样就可以灵活传参数被shell所解析了。
- 容器接受配置要靠环境变量,要想让应用镜像(如,nginx)在run时能够通过环境变量接受参数来决定他的配置文件(监听地址、端口、document_root),变量可以在启动容器时进行传递。
#!/bin/sh
cat >/etc/nginx/conf.d/www.conf << EOF
server{
server name ${HOSTNAME};
listen ${IP:-0.0.0.0}:{PORT:-80};
root ${NGX_DOC_ROOT:-/usr/share/nginx/html};
}
EOF exec "$@"
FROM nginx:1.14-alpine
LABEL maintainer="lc <lc.com>"
ENV NGX_DOC_ROOT="/data/web/html/"
ADD index.html ${NGX_DOC_ROOT}
ADD entrypoint.sh /bin/
CMD ["/usr/sbin/nginx" , "-g" , "daemon off;" ]
ENTRYPOINT ["/bin/entrypoint.sh"]
USER
用于指定运行image时的或运行Dockerfile中任何RUN、CMD或ENTRYPOINT指令指定的程序时的用户名或UID,默认情况下,container的运行身份为root用户
Syntax:
USER UID|UseName
需要注意的是,UID可以为任意教字,但实践中必须为 /etc/passwd
中某用户的有效UID,否则,docker run
命令将运行失败
在基于某个镜像启动容器后,只要容器没转向后台(没停止),这个容器就不会停止。在docker引擎在判定容器健康与否并不是主进程能否提供服务,而仅仅判断进程是否运行。因此docker判断机制并不是真正意义上判断主进程的是否健康,需要其他工具来辅助确定。
HEALTHCHECK
HEALTHCHECK指令定义一个command,CMD
为固定关键词,CMD
后指定一个命令,这个命令用于检查容器主进程工作状态健康与否。即使主进程仍在运行,这也可以检测到陷入无限循环且无法处理新连接的Web服务器等情况。
HEALTHCHECK指令有
HEALTHCHECK [OPTIONS] CMD command # 通过在容器内运行命令来检查容器运行状况
HEALTHCHECK NONE # 禁用任何的健康状态检查,包括默认的健康状态检测机制
可以在CMD之前出现的选项:
参数 | 说明- |
---|---|
--interval | 间隔 s秒、m分钟、h小时,default:30s。 |
--timeout | 执行command需要时间,比如curl一个地址,如果超过timeout秒则认为超时是错误的状态,此时每次健康检查的时间是timeout+interval秒。default:30s。 |
--start-period | 在启动容器是,对主进程自我初始化较慢的情况下,default:0s。17.05引入 |
--retries=N | 失败次数,default:3。 |
当指定了健康检测状态命令,检测请求发出时,响应值为如下3种情况:
- 0: 成功,容器健康且随时可用。
- 1: 不健康,容器无法正常工作。
- 2: 预留值,无意义,可以自行定义。
|HEALTHCHECK–start-period=3s CMD wget-0–q http://${IP:-0.0.0.0}:10080/
For example
HEALTHCHECK--interval=5m --timeout=3s \
CMD curl -f http://locdlhost/ || exit 1
SHELL
SHELL指令允许覆盖用于shell命令形式的默认shell。在Linux上的默认shell是 ["/bin/sh","-c"]
, 在Windows上是 ["cmd" , "/S" , "/C"]
。SHELL指令必须以JSON格式写入Dockerfile。
SHELL指令可以多次出现。每个SHELL指令覆盖先前的SHELL指令,并影响所有后续指令。
Syntax:
SHELL ["executable","parameters]
STOHSIGNAL
STOPSIGNAL指令设置将发送到容器的系统调用信号,以退出。此信号可以是与内核的系统调用表中的位置匹配的有效无符号数,例如9,或SIGNAME格式的信号名,例如SIGKILL。
语法:STOPSIGNAL signal
ARG
ARG指令使用 --build-arg varname='value'
标志定义一个变量,用户可以在使用docker build
命令在构建时将其传递给构建器。
此功能使得一个Dockerfile能够适用于较多的不同场景,尤其是应用程序版本变换时。直接传参数就能确定应该基于Dockerfile制作哪个版本。如果用户指定了未在Dockerfile中定义的构建参数,则构建会输出警告。
Syntax:
ARG name = default value
- Dockerfile中可以包括一个或多个ARG指令。
- ARG指令可以选择性地包括默认值:
ARG version = 1.14
ARGuser = mageedu
ONBUILD
用于在Dockerfile中定义一个触发器。Dockerfile用于build映像文件,此映像文件亦可作为base image被另一个Dockerfile用作FROM指令的参数,并以之构建新的映像文件
在后面的这个Dockerfile中的FROM指令在build过程中被执行时,将会“触发”创建其base image的Dockerfile文件中的ONBUILD指令定义的触发器
Syntax:
ONBUILD INSTRUCTION
注意:
- 尽管任何指令都可注册成为触发器指令,但ONBUILD不能自我嵌套,且不会触发FROM和MAINTAINER指令。
- 使用包含ONBUILD指令的Dockerfle构建的镜像应该使用特殊的标签,例如ruby:2.0-onbuild
- 在ONBUILD指令中使用ADD或COPY指令应该格外小心,因为新构建过程的上下文在缺少指定的源文件时会失败。
四、构建php环境镜像
FROM centos:6
MAINTAINER lc
RUN yum install -y httpd php php-gd php-mysql mysql mysql-server
ENV MYSQL_ROOT_PASSWORD 123456
RUN echo "<?php phpinfo()?>" > /var/www/html/index.php
ADD start.sh /start.sh
RUN chmod +x /start.sh
ADD https://cn.wordpress.org/wordpress-4.7.4-zh_CN.tar.gz /var/www/html
COPY wp-config.php /var/www/html/wordpress
VOLUME ["/var/lib/mysql"]
CMD /start.sh
EXPOSE 80 3306
五、构建java环境镜像
FROM centos
MAINTAINER lc
ADD jdk-8u144-linux-x64.tar.gz /usr/local
ENV JAVA_HOME=/usr/local/jdk1.8.0_144
ADD apache-tomcat-8.5.32.tar.gz /usr/local/
RUN mv /usr/local/apache-tomcat-8.5.32 /usr/local/tomcat
WORKDIR /usr/local/tomcat
ENTRYPOINT ["bin/catalina.sh","run"]
EXPOSE 8080
六、构建ssh环境镜像
FROM centos
MAINTAINER zhangsan
ENV PWD 123
RUN yum install openssh openssh-server openssh-clients -y
RUN echo $PWD|passwd --stdin root
RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
CMD ["/usr/sbin/sshd","-D"]
6.1 测试ssh镜像
systemd启动
构建完镜像使用systemctl启动发现没有sshd进程
$ ps
PID TTY TIME CMD
1 pts/0 00:00:00 bash
18 pts/0 00:00:00 ps
$ systemctl start ssh
Failed to get D-Bus connection: Operation not permitted
此问题原因:systemd服务没有启动无法使用systemd启动
Failed to get D-Bus connection: No connection to service manager
故启动时一般使用 CMD ["/usr/sbin/sshd","-D"]
本文发布于Cylon的收藏册,转载请著名原文链接~
链接:https://www.oomkill.com/2018/06/dockerfile/
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」 许可协议进行许可。