本系列教程翻譯自 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。