1. 程式人生 > >根據Dockerfile構建鏡像

根據Dockerfile構建鏡像

hpa 需求 creat 其中 upa sshd服務 系統 port 必須

根據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
#技術分享圖片還可以指定需要映射到宿主機器上的某個端口號
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工作目錄
技術分享圖片
編輯run.sh腳本
[root@docker01 sshd_dockerfile]# cat run.sh
#!/bin/sh
/usr/sbin/httpd -D DFOREGROUND
/usr/sbin/sshd -D
在主機上生成ssh秘鑰對,並創建authorized_keys文件
技術分享圖片
[root@docker01 sshd_dockerfile]# cat /root/.ssh/id_rsa.pub >
/root/sshd_dockerfile/authorized_keys
[root@docker01 sshd_dockerfile]# ls
authorized_keys Dockerfile run.sh
2、編寫Dockerfile文件,內容如下:
[root@docker01 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
[root@docker01 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、可以查看到生成的鏡像文件:
技術分享圖片
啟動容器,並做映射端口
技術分享圖片
使用admin用戶登錄
技術分享圖片
訪問容器的網站服務:
技術分享圖片

根據Dockerfile構建鏡像