本系列教程翻译自 Flux7 Docker Tutorial Series,系列共有九篇,本文译自第三篇 Part 3: Automation is the Word Using DockerFile。
该系列全部文章将参考其余学习资料翻译,也会加入本身的学习做为部分注解。若有错误,欢迎指正。html
上篇文章介绍的是 15 个 Docker 基础命令,在手动建立镜像的时候会有用到,例如 pull,commit,push,可是当须要执行的命令不少时,是不太可能逐一执行 Docker 命令进行镜像初始化的,因而就此产生了 Dockerfile。docker
Docker 提供的 Dockerfile 是一个相似 Makefile
的工具,主要用来自动化构建镜像。既然能自动化建立镜像,那么咱们何须去手动建立镜像呢。本文用来说解 Dockerfile 的用法、语法,而且提供一个实例用以更深刻地了解 Dockerfile。shell
注:原文 不太直观,并且不少细节没有讲清楚,所以只取原文中有用的部分,参考其余文章总结出本文。ubuntu
贴一个 Dockerfile 的实例而后开始正文:vim
# Memcached # # VERSION 2.2 # use the ubuntu base image provided by dotCloud FROM ubuntu MAINTAINER Victor Coisne victor.coisne@dotcloud.com # make sure the package repository is up to date RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list RUN apt-get update # install memcached RUN apt-get install -y memcached # Launch memcached when launching the container ENTRYPOINT ["memcached"] # run memcached as the daemon user USER daemon # expose memcached port EXPOSE 11211
Dockerfile 中全部的命令都是如下格式:INSTRUCTION argument
centos
指令(INSTRUCTION)不分大小写,可是推荐大写。session
FROM <image name>
,例如 FROM ubuntu
ssh
全部的 Dockerfile 都用该以 FROM
开头,FROM
命令指明 Dockerfile 所建立的镜像文件以什么镜像为基础,FROM
之后的全部指令都会在 FROM
的基础上进行建立镜像;能够在同一个 Dockerfile 中屡次使用 FROM
命令用于建立多个镜像。ide
MAINTAINER <author name>
用于指定镜像建立者和联系方式。memcached
例如
MAINTAINER Victor Coisne victor.coisne@dotcloud.com
RUN <command>
用于容器内部执行命令。每一个 RUN
命令至关于在原有的镜像基础上添加了一个改动层,原有的镜像不会有变化。
ADD <src> <dst>
用于从将 <src>
文件复制到 <dst>
文件:<src>
是相对被构建的源目录的相对路径,能够是文件或目录的路径,也能够是一个远程的文件 url,<dst>
是容器中的绝对路径。
CMD
命令有三种格式:
CMD ["executable","param1","param2"]
:推荐使用的 exec 形式。CMD ["param1","param2"]
:无可执行程序形式CMD command param1 param2
:shell 形式。CMD
命令用于启动容器时默认执行的命令,CMD
命令能够包含可执行文件,也能够不包含可执行文件:不包含可执行文件的状况下就要用 ENTRYPOINT
指定一个,而后 CMD
命令的参数就会做为ENTRYPOINT
的参数。
一个 Dockerfile 中只能有一个
CMD
,若是有多个,则最后一个生效。CMD
的 shell 形式默认调用/bin/sh -c
执行命令。CMD
命令会被 Docker 命令行传入的参数覆盖:docker run busybox /bin/echo Hello Docker
会把CMD
里的命令覆盖。
ENTRYPOINT
命令的字面意思是进入点,而功能也恰如其意:他可让你的容器表现得像一个可执行程序同样。
ENTRYPOINT
命令也有两种格式:
ENTRYPOINT ["executable", "param1", "param2"]
:推荐使用的 exec 形式ENTRYPOINT command param1 param2
:shell 形式一个 Dockerfile 中只能有一个
ENTRYPOINT
,若是有多个,则最后一个生效。
关于 CMD
和 ENTRYPOINT
的联系请看下面的例子
仅仅使用 ENTRYPOINT
:
FROM ubuntu ENTRYPOINT ls -l
执行 docker run 306cd7e8408b /etc/fstab
和 docker run 306cd7e8408b
结果并不会有什么差异:
命令 # docker run 306cd7e8408b /etc/fstab total 64 drwxr-xr-x 2 root root 4096 Mar 20 05:22 bin drwxr-xr-x 2 root root 4096 Apr 10 2014 boot drwxr-xr-x 5 root root 360 Apr 24 02:52 dev drwxr-xr-x 64 root root 4096 Apr 24 02:52 etc drwxr-xr-x 2 root root 4096 Apr 10 2014 home ……
可是咱们一般使用 ENTRYPOINT
做为容器的入口,使用 CMD
给 ENTRYPOINT
增长默认选项:
FROM ubuntu CMD ["-l"] ENTRYPOINT ["ls"]
而后执行这个容器:
不加参数便会默认有 -l
参数:
命令 # docker run 89dc7e6d0ac1 total 64 drwxr-xr-x 2 root root 4096 Mar 20 05:22 bin drwxr-xr-x 2 root root 4096 Apr 10 2014 boot drwxr-xr-x 5 root root 360 Apr 24 02:47 dev drwxr-xr-x 64 root root 4096 Apr 24 02:47 etc drwxr-xr-x 2 root root 4096 Apr 10 2014 home drwxr-xr-x 12 root root 4096 Mar 20 05:21 lib drwxr-xr-x 2 root root 4096 Mar 20 05:20 lib64 drwxr-xr-x 2 root root 4096 Mar 20 05:19 media drwxr-xr-x 2 root root 4096 Apr 10 2014 mnt drwxr-xr-x 2 root root 4096 Mar 20 05:19 opt dr-xr-xr-x 386 root root 0 Apr 24 02:47 proc drwx------ 2 root root 4096 Mar 20 05:22 root drwxr-xr-x 7 root root 4096 Mar 20 05:21 run drwxr-xr-x 2 root root 4096 Apr 21 22:18 sbin drwxr-xr-x 2 root root 4096 Mar 20 05:19 srv dr-xr-xr-x 13 root root 0 Apr 24 02:47 sys drwxrwxrwt 2 root root 4096 Mar 20 05:22 tmp drwxr-xr-x 11 root root 4096 Apr 21 22:18 usr drwxr-xr-x 12 root root 4096 Apr 21 22:18 var
加了 /etc/fstab
参数便会覆盖原有的 -l
参数:
命令 # docker run 89dc7e6d0ac1 /etc/fstab /etc/fstab
EXPOSE <port> [<port>...]
命令用来指定对外开放的端口。
例如 EXPOSE 80 3306
,开放 80
和 3306
端口。
WORKDIR /path/to/work/dir
配合 RUN
,CMD
,ENTRYPOINT
命令设置当前工做路径。
能够设置屡次,若是是相对路径,则相对前一个 WORKDIR
命令。默认路径为/
。
例如:
FROM ubuntu WORKDIR /etc WORKDIR .. WORKDIR usr WORKDIR lib ENTRYPOINT pwd
docker run ID
获得的结果为:/usr/lib
USER <UID/Username>
为容器内指定 CMD
RUN
ENTRYPOINT
命令运行时的用户名或UID。
VOLUME ['/data']
容许容器访问容器的目录、容许容器之间互相访问目录。VOLUME
仅仅是容许将某一个目录暴露在外面,更多的操做还须要依赖 Docker
命令实现。
更多的内容能够参考 深刻理解 Docker Volume(一)
参考 export
的用法咧:ENV LC_ALL en_US.UTF-8
Dockerfile 的写法已经讲述完毕,这儿有一个示例的 Dockerfile:
#Dockerfile FROM centos6-base #指定centos6系统 MAINTAINER zhou_mfk <zhou_mfk@163.com> #我抄的他的 Dockerfile RUN ssh-keygen -q -N "" -t dsa -f /etc/ssh/ssh_host_dsa_key RUN ssh-keygen -q -N "" -t rsa -f /etc/ssh/ssh_host_rsa_key #建立私钥 RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd #修复SSH登陆,不然登录后的用户会被秒退。 RUN mkdir -p /root/.ssh && chown root.root /root && chmod 700 /root/.ssh #建立root用户的ssh文件夹 EXPOSE 22 #开放端口 RUN echo 'root:redhat' | chpasswd #root用户改密码为redhat RUN yum install -y yum-priorities && rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm && rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6 RUN yum install tar gzip gcc vim wget screen -y #安装epel和安装一些软件 ENV LANG en_US.UTF-8 ENV LC_ALL en_US.UTF-8 #系统环境变量 CMD ["/usr/sbin/sshd", "-D"] #启动sshd #End
全部应用都会有个最佳的方式,Dockerfile 也不例外,下面是咱们总结出的最佳实现方式:
array
形式的 CMD
和 ENTRYPOINT
注:映射端口并不属于 Dockerfile 的工做范围。
下篇文章将会介绍 Docker Registry 和 Workflows。