1 概述
Dockerfile基于DSL(Domain Specific Language)语法的指令来构建镜像,利用Dockerfile构建镜像具备可重复性和幂等性,比利用docker commit的方式更具优势。
2 指令介绍
每个Dockerfile指令必须大写
(1)FROM:指定基础镜像,FROM是必备的指令,并且必须是第一条指令。
1 |
FROM centos |
(2)RUN:用来执行命令,有shell格式和exec格式两种方式来执行命令。
1 2 |
<span class="hljs-keyword">RUN</span> shell命令 RUN ["可执行文件", "参数1", "参数2"] |
每执行一个命令就会构建一层镜像,为避免不必要的commit,建议使用&&将命令连接起来。为了增加可读性,利用#进行注释,利用\进行换行,并增加相应缩进。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
FROM debian:jessie RUN buildDeps='gcc libc6-dev make' \ && apt-get update \ && apt-get install -y $buildDeps \ && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \ && mkdir -p /usr/src/redis \ && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \ && make -C /usr/src/redis \ && make -C /usr/src/redis install \ && rm -rf /var/lib/apt/lists/* \ && rm redis.tar.gz \ && rm -r /usr/src/redis \ && apt-get purge -y --auto-remove $buildDeps |
注意这里的清理操作,执行rm清理不必要的临时文件,–auto-remove清理临时变量,避免镜像臃肿。
(3)COPY:文件的复制,可用于将一些本地文件复制进镜像。
格式:
COPY <源路径>… <目标路径>
COPY [“<源路径1>”,… “<目标路径>”]
1 2 3 |
<span class="hljs-keyword">COPY</span> <span class="bash">package.json /usr/src/app/</span> COPY hom* /mydir/ COPY hom?.txt /mydir/ |
<目标路径> 可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 WORKDIR 指令来指定)。
注意:COPY 指令会保留源文件的rwx等权限、变更时间等信息。
(4)ADD:同COPY,但源文件路径可以是URL,Docker 引擎会先下载,然后再拷贝到目标路径中。通常情况下如果需要对文件进行解压并变更权限,建议直接使用docker run命令,再拷贝进去,实际中推荐COPY指令,仅在需要自动解压缩的场合使用 ADD。
(5)CMD:用于指定默认的容器主进程的启动命令。
格式同RUN相似:
shell 格式:CMD <命令>
exec 格式:CMD [“可执行文件”, “参数1”, “参数2″…]
参数列表格式:CMD [“参数1”, “参数2″…]。在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数。
注意:Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样用 upstart/systemd 去启动后台服务,容器内没有后台服务的概念。
以下方式是错误的,
1 2 |
<span class="hljs-keyword">CMD</span> <span class="bash">service httpd start CMD systemctl start httpd</span> |
正确做法是直接执行可执行文件来启动服务。
1 |
CMD ["/run-httpd.sh"] |
(6)ENTRYPOINT:同CMD一样,可以指定容器启动程序及参数,使用ENTRYPOINT 替代,可以直接在docker run 镜像名称后跟参数
1 2 3 4 5 |
<span class="hljs-keyword">FROM</span> ubuntu:<span class="hljs-number">16.04</span> RUN apt-get update \ && apt-get install -y curl \ && rm -rf /var/lib/apt/lists/* <span class="hljs-keyword">ENTRYPOINT</span> <span class="bash">[ <span class="hljs-string">"curl"</span>, <span class="hljs-string">"-s"</span>, <span class="hljs-string">"http://ip.cn"</span> ]</span> |
使用 docker build -t myip . 来构建镜像后,为了查询公网IP,可以执行:
1 |
$ docker run myip |
Dockerfile中使用ENTRYPOINT 还可以直接在后面跟curl的参数
1 |
$ docker run myip -i |
(7)ENV:设置环境变量
格式:ENV <key1>=<value1> <key2>=<value2>..
利用ENV设置环境变量后,其他指令可以利用“$变量”的方式进行调用,这一点同shell。
(8)ARG:构建参数
ARG同ENV一样也是设置环境变量,但ARG是在Bulid的时候,通过–build-arg传入参数的,例如:
1 2 3 4 5 6 |
From resin/rpi-raspbian ARG NODE_VER ADD ./${NODE_VER:-node-v5.9.1-linux-armv7l} / RUN ln -s /${NODE_VER} /node ENV PATH=/node/bin:$PATH CMD ["node"] |
构建时动态传入参数:
1 |
docker build --build-arg NODE_VER=node-v5.9.0-linux-armv7l . |
格式:
- ${variable:-word} :如果variable动态传值,则以variable设定的文字为主,如未设定,则变量为word字符串。
- ${variable:+word} 代表,如果variable动态传值,则以variable设定的文字为主,如未设定,则变量为空(好BT的约定)。
(9)VOLUME:定义匿名卷
容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中,VOLUME会定义某些目录为匿名卷,如果用户在运行时未指定挂载,镜像中应用想该目录写入的数据也不会向存储层写入大量数据。从而保证了容器存储层的无状态化。
1 |
VOLUME /var/lib/mysql/ |
当然也可以在运行时可以覆盖这个挂载设置,如:
1 |
docker run -d -v mydata:/var/lib/mysql/ xxxx |
在示例中,使用了 mydata 这个命名卷挂载到了 /var/lib/mysql/这个位置,替代了 Dockerfile 中定义的匿名卷的挂载配置。
(10)EXPOSE:声明端口
EXPOSE声明运行时容器提供服务端口,仅仅是帮助镜像使用者查看该镜像守护服务所使用的端口。
区分:不同运行时使用 -p <宿主端口>:<容器端口>,EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射
(11)WORKDIR:指定工作目录
WORKDIR指定工作目录,以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。
(12)USER:指定当前用户
同WORKDIR,执行RUN、CMD等命令的指定用户。
注意:对于需要Root权限,建议采用gosu替代执行su或sudo,例如:
1 2 3 4 5 6 7 8 |
# 建立 redis 用户,并使用 gosu 换另一个用户执行命令 RUN groupadd -r redis && useradd -r -g redis redis # 下载 gosu RUN wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.7/gosu-amd64" \ && chmod +x /usr/local/bin/gosu \ && gosu nobody true # 设置 CMD,并以另外的用户执行 CMD [ "exec", "gosu", "redis", "redis-server" ] |
(13)HEALTHCHECK:健康检查
HEALTHCHECK 指令是告诉 Docker 应该如何进行判断容器的状态是否正常,格式如下:
- HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
- HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
详细请参考:https://yeasy.gitbooks.io/docker_practice/content/image/dockerfile/healthcheck.html
1 2 3 4 |
FROM nginx RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* HEALTHCHECK --interval=5s --timeout=3s \ CMD curl -fs http://localhost/ || exit 1 |
(14)ONBUILD:为其他镜像引用做准备
ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。
Dockerfile 中的其它指令都是为了定制当前镜像而准备的,唯有 ONBUILD 是为了帮助别人定制自己而准备的。
1 2 3 4 5 6 7 |
FROM node:slim RUN mkdir /app WORKDIR /app ONBUILD COPY ./package.json /app ONBUILD RUN [ "npm", "install" ] ONBUILD COPY . /app/ CMD [ "npm", "start" ] |
其他项目构建引用上个镜像:
1 |
FROM my-node |
(15)构建镜像
在 Dockerfile 文件所在目录执行:
1 |
docker build [选项] <上下文路径/URL/-> |
3 构建示例
以neutron镜像构建的Dockerfile为例:
下载源码:
1 2 3 4 5 6 7 8 9 10 11 |
# git clone https://github.com/anguslees/kube-openstack.git # cd kube-openstack/docker/neutron/ # ll total 28 -rw-r--r-- 1 root root 2434 Oct 21 23:30 Dockerfile -rw-r--r-- 1 root root 292 Oct 21 23:30 l3_agent_compute.ini.in -rw-r--r-- 1 root root 352 Oct 21 23:30 l3_agent_network.ini.in -rw-r--r-- 1 root root 554 Oct 21 23:30 metadata_agent.ini.in -rw-r--r-- 1 root root 496 Oct 21 23:30 ml2_conf.ini.in -rw-r--r-- 1 root root 1836 Oct 21 23:30 neutron.conf.in -rwxr-xr-x 1 root root 486 Oct 21 23:30 _wrap.sh |
Dockerfile内容如下:
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
FROM ubuntu:vivid MAINTAINER Angus Lees <gus@inodes.org> ENV \ PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin \ PREFIX=/home/install \ ETC_IN=/home/install/etc \ ETC=/home/user/etc \ BRANCH=stable/liberty # Run pip install as one (non-root) user, and run resulting binaries # as another. RUN \ apt-get -q update && apt-get -qy upgrade && \ adduser --disabled-login --gecos 'Unprivileged runtime user' user && \ adduser --disabled-login --gecos 'Unprivileged install user' install && \ apt-get -qy --no-install-recommends install \ sudo virtualenv python-dev python-pip git build-essential # System depdendencies needed to build python modules, followed by runtime deps. # # Note! # rootwrap.conf controls sudo/rootwrap access and in a secure setup needs to # be installed from a trusted source to a location writeable only by # root. In the interests of easy testing of git HEAD, that is not # what we're doing here. # RUN apt-get -qy --no-install-recommends install \ libxslt-dev libxml2-dev zlib1g-dev libyaml-dev libffi-dev libssl-dev \ iproute dnsmasq-utils dnsmasq-base iputils-arping ipset && \ mkdir -p /etc/neutron /var/lib/neutron /var/lock/neutron && \ chown user:user /var/lib/neutron /var/lock/neutron && \ ln -s $ETC/neutron/rootwrap.conf /etc/neutron/rootwrap.conf && \ ln -s $ETC/neutron/rootwrap.d /etc/neutron/rootwrap.d && \ echo "user ALL = (root) NOPASSWD: $PREFIX/venv/bin/neutron-rootwrap /etc/neutron/rootwrap.conf *" > /etc/sudoers.d/rootwrap # _wrap.sh sets up environment and copies templated configs from $ETC_IN -> $ETC COPY _wrap.sh /usr/local/bin/ ENTRYPOINT ["/usr/local/bin/_wrap.sh"] CMD ["/bin/bash"] # Note neutron git repo has files in both etc/ and etc/neutron USER install RUN \ set -x && \ cd $PREFIX && \ git clone --depth 1 --single-branch --branch $BRANCH https://github.com/openstack/neutron.git git-fetch && \ cd git-fetch && \ virtualenv --system-site-packages $PREFIX/venv && \ $PREFIX/venv/bin/pip install --upgrade pip && \ $PREFIX/venv/bin/pip install --compile . PyMySQL && \ mkdir -p $ETC_IN/neutron && \ cp -r etc/* $ETC_IN/neutron/ && \ mv $ETC_IN/neutron/neutron/* $ETC_IN/neutron/ && \ rmdir $ETC_IN/neutron/neutron && \ . $PREFIX/venv/bin/activate && neutron-server --help >/dev/null COPY neutron.conf.in l3_agent_network.ini.in l3_agent_compute.ini.in metadata_agent.ini.in ml2_conf.ini.in /etc/neutron/ USER user WORKDIR / EXPOSE 9696 9697 4789 |
第1行:FROM ubuntu:vivid,基于ubuntu:vivid镜像构建
第2行:MAINTAINER Angus Lees <gus@inodes.org>,维护者标签信息
第4~9行:ENV设置环境变量,可供后续操作使用
第13~18行:RUN,创建user&install用户,执行更新,并安装软件包
第28~35行:RUN,依赖包的安装,创建neutron相关目录并修改目录权限,创建软连接,并向文件中追加内容
第38行:COPY,拷贝脚本_wrap.sh到镜像的 /usr/local/bin/路径下
第39行:ENTRYPOINT,设置镜像入口点,运行时执行脚本/usr/local/bin/_wrap.sh
第40行:CMD,设置容器的启动时执行/bin/bash
第43行:USER,切换命令执行用户为install
第44~56行:RUN,下载neutron源码,利用pip执行安装,并测试neutron命令
第58行:COPY,复制neutron所需的配置文件到/etc/neutron/目录中
第60行:USER,切换用户为user
第61行:WORKDIR,指定工作目录为镜像根目录
第62行:EXPOSE,声明neutron所需的三个端口
构建镜像:
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 |
# docker build --no-cache -t neutron-test . Sending build context to Docker daemon 12.29 kB Step 1 : FROM ubuntu:utopic ---> a8a2ba3ce1a3 Step 2 : MAINTAINER Angus Lees <gus@inodes.org> ---> Running in 0d33655f5d81 ---> 524a5427b413 Removing intermediate container 0d33655f5d81 Step 3 : ENV PATH /usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin PREFIX /home/install ETC_IN /home/install/etc ETC /home/user/etc ---> Running in 5bea9f89b451 ---> 6cbc22e2557f Removing intermediate container 5bea9f89b451 Step 4 : RUN apt-get -q update && apt-get -qy upgrade && adduser --disabled-login --gecos 'Unprivileged runtime user' user && adduser --disabled-login --gecos 'Unprivileged install user' install && apt-get -qy --no-install-recommends install sudo virtualenv python-dev python-pip git build-essential ---> Running in 26db541bcd07 Ign http://archive.ubuntu.com utopic InRelease Ign http://archive.ubuntu.com utopic-updates InRelease Ign http://archive.ubuntu.com utopic-security InRelease Ign http://archive.ubuntu.com utopic Release.gpg Ign http://archive.ubuntu.com utopic-updates Release.gpg Ign http://archive.ubuntu.com utopic-security Release.gpg Ign http://archive.ubuntu.com utopic Release Ign http://archive.ubuntu.com utopic-updates Release Ign http://archive.ubuntu.com utopic-security Release Ign http://archive.ubuntu.com utopic/main amd64 Packages/DiffIndex Ign http://archive.ubuntu.com utopic/restricted amd64 Packages/DiffIndex Err http://archive.ubuntu.com utopic/main Sources 404 Not Found [IP: 91.189.91.26 80] …… |
4 参考文档
《第一本Docker书》
https://yeasy.gitbooks.io/docker_practice/content/image/build.html
https://peihsinsu.gitbooks.io/docker-note-book/content/dockerfile-env-vs-arg.html
code
more code
~~~~