1. 程式人生 > >根據Dockerfile構建映象

根據Dockerfile構建映象

根據Dockerfile構建出一個映象
Dockfile是一種被Docker程式解釋的指令碼,Dockerfile由一條一條的指令組成,每條
指令對應Linux下面的一條命令。Docker程式將這些Dockerfile指令翻譯真正的Linux命
令。Dockerfile有自己書寫格式和支援的命令,Docker程式解決這些命令間的依賴關係,
類似於Makefile。Docker程式將讀取Dockerfile,根據指令生成定製的image。相比
image這種黑盒子,Dockerfile這種顯而易見的指令碼更容易被使用者接受,它明確的表明
image是怎麼產生的。有了Dockerfile,當我們需要定製自己額外的需求時,只需在
Dockerfile上新增或者修改指令,重新生成image即可,省去了敲命令的麻煩。
Dockerfile由一行行命令語句組成,並且支援以# 開頭的註釋行。
Dockerfile的指令是忽略大小寫的,建議使用大寫,每一行只支援一條指令,每條指令
可以攜帶多個引數。
Dockerfile的指令根據作用可以分為兩種:構建指令和設定指令。
構建指令用於構建image,其指定的操作不會在執行image的容器上執行;
設定指令用於設定image的屬性,其指定的操作將在執行image的容器中執行。
一般的,Dockerfile分為四部分:基礎映象資訊、維護者資訊、映象操作指令和容器啟動時
執行指令。
下面是一個例子:
#This dockerfile uses the ubuntu image
#VERSION 2 - EDITION 1
#Author: docker_user
#Command format: Instruction [arguments / command] ..
#Base image to use, this must be set as the first line
#第一行必須指明基於的基礎映象
FROM ubuntu
#Maintainer: docker_user<docker_user at email.com> (@docker_user)
#維護該映象的使用者資訊
MAINTAINER docker_user

[email protected]
#Commands to update the image
#映象操作命令
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >>
/etc/apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
#開啟80埠
EXPOSE 80
#Commands when creating a new container
#啟動容器時執行的命令
CMD /usr/sbin/nginx
在編寫dockerfile時,有嚴格的格式要遵循:
其中,一開始必須使用FROM指令指明所基於的映象名稱,接下來使用MAINTAINER指
令說明維護者資訊。後面則是映象操作指令,例如RUN指令,RUN 指令將對映象執行跟隨
的命令。每執行一條RUN 指令,都會給基礎映象新增新的一層並提交。最後是CMD指令,
來指定執行容器時的操作命令。
dockerfile指令
指令的一般格式為INSTRUCTION arguments,指令包括FROM 、MAINTAINER 、RUN
等。
(1)FROM(指定基礎image)
構建指令,必須指定且需要在Dockerfile其他指令的前面。後續的指令都依賴於該指令指定
的image。FROM指令指定的基礎image可以是官方遠端倉庫中的,也可以位於本地倉庫。
該指令有兩種格式:
FROM <image>
指定基礎image為該image的最後修改的版本。
或者:
FROM <image>:<tag>
指定基礎image為該image的一個tag版本。
(2)MAINTAINER(用來指定映象建立者資訊)
構建指令,用於將image的製作者相關的資訊寫入到image中。當我們對該image執行
docker inspect命令時,輸出中有相應的欄位記錄該資訊。
格式:
MAINTAINER <name>
(3)RUN(安裝軟體用)
構建指令,RUN可以執行任何被基礎image支援的命令。如基礎image選擇了ubuntu,那
麼軟體管理部分只能使用ubuntu的命令。
該指令有兩種格式:
RUN <command> (the command is run in a shell - /bin/sh -c
)
RUN ["executable", "param1", "param2" ... ] (exec form)
前者將在 shell 終端中執行命令,即/bin/sh -c ;後者則使用exec 執行。
指定使用其它終端可以通過第二種方式實現,例如 RUN ["/bin/bash", "-c", "echo hello"]

每條RUN指令將在當前映象基礎上執行指定命令,並提交為新的映象。當命令較長時可以
使用“\”來換行。
(4)CMD(設定container啟動時執行的操作)
該指令有三種格式:
設定指令,用於container啟動時指定的操作。該操作可以是執行自定義指令碼,也可以是執
行系統命令。
CMD ["executable","param1","param2"] 使用exec 執行,推薦方式;
CMD command param1 param2 在/bin/sh中執行,提供給需要互動的應用;
當Dockerfile指定了ENTRYPOINT,那麼使用下面的格式:
CMD ["param1","param2"] 提供給ENTRYPOINT 的預設引數;
ENTRYPOINT指定的是一個可執行的指令碼或者程式的路徑,該指定的指令碼或者程式將會
param1和param2作為引數執行。所以如果CMD指令使用上面的形式,那麼Dockerfile中
必須要有配套的ENTRYPOINT。
指定啟動容器時執行的命令,每個Dockerfile只能有一條CMD 命令。如果指定了多條命
令,只有最後一條會被執行。如果使用者啟動容器時候指定了執行的命令,則會覆蓋掉CMD
指定的命令。
5)ENTRYPOINT(設定container啟動時執行的操作)
設定指令,指定容器啟動時執行的命令,可以多次設定,但是隻有最後一個有效。
兩種格式:
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2 (shell中執行)。
配置容器啟動後執行的命令,並且不可被docker run提供的引數覆蓋。
每個Dockerfile 中只能有一個ENTRYPOINT,當指定多個時,只有最後一個起效。
該指令的使用分為兩種情況,一種是獨自使用,另一種和CMD指令配合使用。
當獨自使用時,如果你還使用了CMD命令且CMD是一個完整的可執行的命令,那麼CMD
指令和ENTRYPOINT會互相覆蓋只有最後一個CMD或者ENTRYPOINT有效。
例如: CMD指令將不會被執行,只有ENTRYPOINT指令被執行
CMD echo “Hello, World!”
ENTRYPOINT ls -l
另一種用法和CMD指令配合使用來指定ENTRYPOINT的預設引數,這時CMD指令不是一
個完整的可執行命令,僅僅是引數部分;ENTRYPOINT指令只能使用JSON方式指定執行命
令,而不能指定引數。
例如:
FROM ubuntu
CMD ["-l"]
ENTRYPOINT ["/usr/bin/ls"]
(6)USER(設定container容器的使用者,預設是root使用者)
格式為:
USER daemon
指定執行容器時的使用者名稱或UID,後續的RUN 也會使用指定使用者。
當服務不需要管理員許可權時,可以通過該命令指定執行使用者。並且可以在之前建立所需要的
使用者,例
如: RUN groupadd -r postgres&&useradd -r -g postgres postgres

例如: 指定memcached的執行使用者
ENTRYPOINT ["memcached"]
USER daemon
或 EN
TRYPOINT ["memcached", "-u", "daemon"]
(7)EXPOSE(指定容器需要對映到宿主機器的埠)
格式為:
EXPOSE <port> [<port>...]
設定指令,該指令會將容器中的埠對映成宿主機器中的某個埠。當你需要訪問容器的時
候,可以不是用容器的IP地址而是使用宿主機器的IP地址和對映後的埠。
要完成整個操作需要兩個步驟,首先在Dockerfile使用EXPOSE設定需要對映的容器埠,
然後在執行容器的時候指定-p選項加上EXPOSE設定的埠,這樣EXPOSE設定的埠號會
被隨機對映成宿主機器中的一個埠號。也可以指定需要對映到宿主機器的哪個埠,這時
要確保宿主機器上的埠號沒有被使用。EXPOSE指令可以一次設定多個埠號,相應的運
行容器的時候,可以配套的多次使用-p選項。
例如: 對映一個埠
EXPOSE port1
#相應的執行容器使用的命令
docker run -p port1 image
例如: 對映多個埠
EXPOSE port1 port2 port3
#相應的執行容器使用的命令
docker run -p port1 -p port2 -p port3 image
#根據Dockerfile構建映象還可以指定需要對映到宿主機器上的某個埠號
docker run -p host_port1:port1 -p host_port2:port2 -p host_port3:port3 image
埠對映是docker比較重要的一個功能,原因在於我們每次執行容器的時候容器的IP地址
不能指定而是在橋接網絡卡的地址範圍內隨機生成的。宿主機器的IP地址是固定的,我們可以
將容器的埠的對映到宿主機器上的一個埠,免去每次訪問容器中的某個服務時都要檢視
容器的IP的地址。對於一個執行的容器,可以使用docker port加上容器中需要對映的埠
和容器的ID來檢視該埠號在宿主機器上的對映埠。
(8)ENV(用於設定環境變數)
構建指令,指定一個環境變數,會被後續RUN指令使用,並在容器執行時保持。
格式:
ENV <key> <value>
設定了後,後續的RUN命令都可以使用,container啟動後,可以通過docker inspect檢視
這個環境變數,也可以通過在docker run --env key=value時設定或修改環境變數。
假如你安裝了JAVA程式,需要設定JAVA_HOME,那麼可以在Dockerfile中這樣寫:
ENV JAVA_HOME /path/to/java/dirent
再例如:
ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC
/usr/src/postgress
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
(9)ADD(將原始檔複製到container的目標檔案)
構建指令,所有拷貝到container中的檔案和資料夾許可權為0755,uid和gid為0;
原始檔要與Dockerfile位於相同目錄中;
1、如果源路徑是個檔案,且目標路徑是以 / 結尾, 則docker會把目標路徑當作一個目
錄,會把原始檔拷貝到該目錄下。如果目標路徑不存在,則會自動建立目標路徑。
2、如果源路徑是個檔案,且目標路徑是不是以 / 結尾,則docker會把目標路徑當作一個文
件。
如果目標路徑不存在,會以目標路徑為名建立一個檔案,內容同源檔案;
如果目標檔案是個存在的檔案,會用原始檔覆蓋它,當然只是內容覆蓋,檔名還是目標文
件名。
如果目標檔案實際是個存在的目錄,則會原始檔拷貝到該目錄下。 注意,這種情況下,最
好顯示的以 / 結尾,以避免混淆。
3、如果源路徑是個目錄,且目標路徑不存在,則docker會自動以目標路徑建立一個目錄,
把源路徑目錄下的檔案拷貝進來。如果目標路徑是個已經存在的目錄,則docker會把源路
徑目錄下的檔案拷貝到該目錄下。
4、如果原始檔是個歸檔檔案(壓縮檔案),則docker會自動幫解壓。
格式:
ADD <src> <dest>
該命令將複製指定的<src>到容器中的<dest>。
其中<src>可以是Dockerfile所在目錄的一個相對路徑;也可以是一個 URL;還可以是一個
tar 檔案(自動解壓為目錄)
<dest>是container中的絕對路徑
例如:
#test
FROM ubuntu
MAINTAINER hello
ADD test1.txt test1.txt
ADD test1.txt test1.txt.bak
ADD test1.txt /mydir/
ADD data1 data1
ADD data2 data2
ADD zip.tar /myzip
(10)COPY
格式為 COPY <src><dest>
複製本地主機的<src>(為Dockerfile所在目錄的相對路徑)到容器中的<dest>。
原始檔/目錄要與Dockerfile在相同的目錄中
COPY指令和ADD指令功能和使用方式類似。只是COPY指令不會做自動解壓工作。
(11)VOLUME(指定掛載點)
設定指令,使容器中的一個目錄具有持久化儲存資料的功能,該目錄可以被容器本身使用,
也可以共享給其他容器使用。我們知道容器使用的是AUFS,這種檔案系統不能持久化數
據,當容器關閉後,所有的更改都會丟失。當容器中的應用有持久化資料的需求時可以在
Dockerfile中使用該指令。
格式:
VOLUME ["<mountpoint>"]
例如:FROM base
VOLUME ["/tmp/data"]
執行通過該Dockerfile生成image的容器,/tmp/data目錄中的資料在容器關閉後,裡面的
資料還存在。例如另一個容器也有持久化資料的需求,且想使用上面容器共享的/tmp/data
目錄,那麼可以執行下面的命令啟動一個容器:
docker run -t -i -rm -volumes-from container1 image2 bash
container1為第一個容器的ID,image2為第二個容器執行image的名字。
(12)WORKDIR(切換目錄)
設定指令,可以多次切換(相當於cd命令),對RUN,CMD,ENTRYPOINT生效。為後續的
RUN、CMD、ENTRYPOINT 指令配置工作目錄。
格式:
WORKDIR /path/to/workdir
例如: 在 /p1/p2 下執行 vim a.txt
WORKDIR /p1
WORKDIR p2
RUN vim a.txt
可以使用多個WORKDIR指令,後續命令如果引數是相對路徑,則會基於之前命令指定的路
徑。
例如
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
則最終路徑為/a/b/c。
(13)ONBUILD(在子映象中執行)
ONBUILD <Dockerfile關鍵字>
ONBUILD 指定的命令在構建映象時並不執行,而是在它的子映象中執行。
格式為:
ONBUILD [INSTRUCTION] 。
配置當所建立的映象作為其它新建立映象的基礎映象時,所執行的操作指令。
例如,Dockerfile使用如下的內容建立了映象image-A 。
[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]
如果基於 image-A 建立新的映象時,新的Dockerfile中使用FROM image-A 指定基礎鏡
像時,會自動執行ONBUILD 指令內容。
等價於在後面添加了兩條指令。
FROM image-A
#Automatically run the following
ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src
使用ONBUILD指令的映象,推薦在標籤中註明,例如ruby:1.9-onbuild。
編寫完成Dockerfile之後,可以通過docker build 命令來建立映象。
基本的格式為docker build [選項] 路徑,該命令將讀取指定路徑下的Dockerfile,並將該
路徑下所有內容傳送給Docker 服務端,由服務端來建立映象。因此一般建議放置
Dockerfile的目錄為空目錄。
要指定映象的標籤資訊,可以通過-t選項,例如
$ sudo docker build –t myrepo /myapp/tmp/test1/
docker應用案例:使用dockerfile建立sshd映象模板並提供http訪問應用
1) 建立一個sshd_dockerfile工作目錄
根據Dockerfile構建映象
編輯run.sh指令碼
[[email protected] sshd_dockerfile]# cat run.sh
#!/bin/sh
/usr/sbin/httpd -D DFOREGROUND
/usr/sbin/sshd -D
在主機上生成ssh祕鑰對,並建立authorized_keys檔案
根據Dockerfile構建映象
[[email protected] sshd_dockerfile]# cat /root/.ssh/id_rsa.pub >
/root/sshd_dockerfile/authorized_keys
[[email protected] sshd_dockerfile]# ls
authorized_keys Dockerfile run.sh
2、編寫Dockerfile檔案,內容如下:
[[email protected] sshd_dockerfile]# cat /root/sshd_dockerfile/Dockerfile
FROM centos:latest
MAINTAINER from [email protected]
RUN yum install -y -q httpd openssh-server sudo net-tools
RUN useradd admin
RUN echo "admin:admin" | chpasswd
RUN echo "admin ALL=(ALL) ALL" >> /etc/sudoers
RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
RUN ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key
RUN ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key
RUN mkdir -p /var/run/sshd
RUN mkdir -p /home/admin/.ssh
RUN sed -ri 's/#ServerName www.example.com:80/ServerName www.cloud.com/g'
/etc/httpd/conf/httpd.conf
ADD authorized_keys /home/admin/.ssh/authorized_keys
ADD run.sh /run.sh
RUN chmod 775 /run.sh
EXPOSE 22 80
CMD ["/run.sh"]
以上選項的含義解釋:
FROM centos:latest 選擇一個已有的os映象作為基礎
MAINTAINER 映象的作者
RUN yum install -y -q httpd openssh-server sudo 安裝httpd、openssh-server、

sudo和net-tools軟體包
新增測試使用者admin,密碼admin,並且將此使用者新增到sudoers裡
RUN useradd admin
RUN echo "admin:admin" | chpasswd
RUN echo "admin ALL=(ALL) ALL" >> /etc/sudoers
下面這兩句比較特殊,在centos6上必須要有,否則創建出來的容器sshd不能登入
RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
注意:centos7上下面4句必須要有,否則創建出來的容器sshd不能登入
RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
RUN ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key
RUN ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key
將公鑰資訊上傳到遠端連線使用者的宿主目錄的.ssh下
ADD authorized_keys /home/admin/.ssh/authorized_keys
啟動sshd服務並且暴露22埠
RUN mkdir /var/run/sshd
EXPOSE 22 80
CMD ["/run.sh"] 執行指令碼, 也可以寫成這種方式CMD ["/usr/sbin/sshd", "-D"]
3、在sshd_dockerfile目錄下,使用docker build命令來建立映象,注意:在最後還有一
個”.”,表示使用當前目錄中的dockerfile
[[email protected] sshd_dockerfile]# docker build --no-cache -t "centos:httpv1" .
Sending build context to Docker daemon 4.608kB
Step 1/18 : FROM centos:latest
---> 3fa822599e10
Step 2/18 : MAINTAINER from [email protected]
---> 0d8eeedbef89
Removing intermediate container 661854eafd44
Step 14/18 : ADD authorized_keys /home/admin/.ssh/authorized_keys
....................
4、可以檢視到生成的映象檔案:
根據Dockerfile構建映象
啟動容器,並做對映埠
根據Dockerfile構建映象
使用admin使用者登入
根據Dockerfile構建映象
訪問容器的網站服務:
根據Dockerfile構建映象