天天看點

使用 Dockerfile 建構鏡像

Dockerfile的指令是忽略大小寫的,建議使用大寫,使用 # 作為注釋,每一行隻支援一條指令,每條指令可以攜帶多個參數。

Dockerfile的指令根據作用可以分為兩種,建構指令和設定指令。建構指令用于建構image,其指定的操作不會在運作image的容器上執行;設定指令用于設定image的屬性,其指定的操作将在運作image的容器中執行

建構指令,必須指定且需要在Dockerfile其他指令的前面。後續的指令都依賴于該指令指定的image。FROM指令指定的基礎image可以是官方遠端倉庫中的,也可以位于本地倉庫。

該指令有兩種格式:

FROM <image>  

指定基礎image為該image的最後修改的版本。或者:

FROM <image>:<tag>  

指定基礎image為該image的一個tag版本

(2)MAINTAINER(用來指定鏡像建立者資訊)

建構指令,用于将image的制作者相關的資訊寫入到image中。當我們對該image執行docker inspect指令時,輸出中有相應的字段記錄該資訊。

格式:

MAINTAINER <name>  

建構指令,RUN可以運作任何被基礎image支援的指令。如基礎image選擇了ubuntu,那麼軟體管理部分隻能使用ubuntu的指令。

RUN <command> (the command is run in a shell - `/bin/sh -c`)  

RUN ["executable", "param1", "param2" ... ]  (exec form)  

設定指令,用于container啟動時指定的操作。該操作可以是執行自定義腳本,也可以是執行系統指令。該指令隻能在檔案中存在一次,如果有多個,則隻執行最後一條。

該指令有三種格式:

CMD ["executable","param1","param2"] (like an exec, this is the preferred form)  

CMD command param1 param2 (as a shell)  

當Dockerfile指定了ENTRYPOINT,那麼使用下面的格式:

CMD ["param1","param2"] (as default parameters to ENTRYPOINT)  

ENTRYPOINT指定的是一個可執行的腳本或者程式的路徑,該指定的腳本或者程式将會以param1和param2作為參數執行。是以如果CMD指令使用上面的形式,那麼Dockerfile中必須要有配套的ENTRYPOINT。

設定指令,指定容器啟動時執行的指令,可以多次設定,但是隻有最後一個有效。

兩種格式:

ENTRYPOINT ["executable", "param1", "param2"] (like an exec, the preferred form)  

ENTRYPOINT command param1 param2 (as a shell)  

該指令的使用分為兩種情況,一種是獨自使用,另一種和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"]  

設定指令,設定啟動容器的使用者,預設是root使用者。

# 指定memcached的運作使用者  

ENTRYPOINT ["memcached"]  

USER daemon  

或  

ENTRYPOINT ["memcached", "-u", "daemon"]  

設定指令,該指令會将容器中的端口映射成主控端器中的某個端口。當你需要通路容器的時候,可以不是用容器的IP位址而是使用主控端器的IP位址和映射後的端口。要完成整個操作需要兩個步驟,首先在Dockerfile使用EXPOSE設定需要映射的容器端口,然後在運作容器的時候指定-p選項加上EXPOSE設定的端口,這樣EXPOSE設定的端口号會被随機映射成主控端器中的一個端口号。也可以指定需要映射到主控端器的那個端口,這時要確定主控端器上的端口号沒有被使用。EXPOSE指令可以一次設定多個端口号,相應的運作容器的時候,可以配套的多次使用-p選項。

格式:

EXPOSE <port> [<port>...]  

# 映射一個端口  

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來檢視該端口号在主控端器上的映射端口。

建構指令,在image中設定一個環境變量。

ENV <key> <value>  

設定了後,後續的RUN指令都可以使用,container啟動後,可以通過docker inspect檢視這個環境變量,也可以通過在docker run --env key=value時設定或修改環境變量。

假如你安裝了JAVA程式,需要設定JAVA_HOME,那麼可以在Dockerfile中這樣寫:

ENV JAVA_HOME /path/to/java/dirent

建構指令,所有拷貝到container中的檔案和檔案夾權限為0755,uid和gid為0;如果是一個目錄,那麼會将該目錄下的所有檔案添加到container中,不包括目錄;如果檔案是可識别的壓縮格式,則docker會幫忙解壓縮(注意壓縮格式);如果<src>是檔案且<dest>中不使用斜杠結束,則會将<dest>視為檔案,<src>的内容會寫入<dest>;如果<src>是檔案且<dest>中使用斜杠結束,則會<src>檔案拷貝到<dest>目錄下。

ADD <src> <dest>  

<src> 是相對被建構的源目錄的相對路徑,可以是檔案或目錄的路徑,也可以是一個遠端的檔案url;

<dest> 是container中的絕對路徑

設定指令,使容器中的一個目錄具有持久化存儲資料的功能,該目錄可以被容器本身使用,也可以共享給其他容器使用。我們知道容器使用的是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的名字。

設定指令,可以多次切換(相當于cd指令),對RUN,CMD,ENTRYPOINT生效。

WORKDIR /path/to/workdir  

# 在 /p1/p2 下執行 vim a.txt  

WORKDIR /p1 WORKDIR p2 RUN vim a.txt  

ONBUILD <Dockerfile關鍵字>  

ONBUILD 指定的指令在建構鏡像時并不執行,而是在它的子鏡像中執行。

Dockerfile檔案

# cd /app/zpy/docker/

# vim Dockerfile

# VERSION 0.0.1

FROM registry.cn-hangzhou.aliyuncs.com/acs-sample/centos

# 簽名

MAINTAINER Jo

# 更新源,安裝ssh server

RUN yum -y update

RUN yum clean all

RUN yum list

RUN yum install -y openssh-server

RUN mkdir -p /var/run/sshd

# 設定root ssh遠端登入密碼為123456

RUN echo "1qaz@WSX?" | passwd --stdin root

# 安裝vim,wget,curl,java,tomcat等必備軟體

RUN yum install -y vim wget curl

RUN mkdir -p /app/zpy

RUN mkdir -p /app/zpy/3rd

RUN cd /tmp

RUN wget http://10.0.70.243/jdk-8u51-linux-x64.tar.gz 

RUN wget http://10.0.70.243/apache-tomcat-6.0.41.tar.gz

RUN tar zxvf jdk-8u51-linux-x64.tar.gz -C /app/zpy/ 

RUN tar zxvf apache-tomcat-6.0.41.tar.gz -C /app/zpy/

RUN mv /app/zpy/apache-tomcat-6.0.41 /app/zpy/tomcat_its

RUN echo "JAVA_HOME=/app/zpy/jdk1.8.0_51" >> /etc/profile

RUN echo "JAVA_BIN=/app/zpy/jdk1.8.0_51/bin" >> /etc/profile

RUN echo "PATH=$PATH:$JAVA_BIN" >> /etc/profile

RUN echo "CLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar" >> /etc/profile

RUN echo "export MAVEN_HOME JENKINS_HOME JAVA_HOME JAVA_BIN PATH CLASSPATH" >> /etc/profile

RUN source /etc/profile

ENV JAVA_HOME /app/zpy/jdk1.8.0_51

ENV JAVA_BIN /app/zpy/jdk1.8.0_51/bin

# 容器需要開放SSH 22端口

EXPOSE 22

# 容器需要開放Tomcat 8080端口

EXPOSE 8080

# 設定Tomcat初始化運作,SSH終端伺服器作為背景運作

ENTRYPOINT sh /app/zpy/tomcat_its/bin/startup.sh && tail -f /app/zpy/tomcat_its/logs/catalina.out

+++++++++++++++++++++++++++++++++++++++++++++

需要注意:

ENTRYPOINT,表示鏡像在初始化時需要執行的指令,不可被重寫覆寫,需謹記

CMD,表示鏡像運作預設參數,可被重寫覆寫

ENTRYPOINT/CMD都隻能在檔案中存在一次,并且最後一個生效 多個存在,隻有最後一個生效,其它無效!

需要初始化運作多個指令,彼此之間可以使用 && 隔開,但最後一個須要為無限運作的指令,需切記!

ENTRYPOINT/CMD,一般兩者可以配合使用,比如:

在Docker daemon模式下,無論你是使用ENTRYPOINT,還是CMD,最後的指令,一定要是目前程序需要一直運作的,才能夠防容器退出。

以下無效方式:

這樣有效:

這樣也有效:

腳本寫好了,需要轉換成鏡像:

# docker build -t centos/javaweb .

-t: 為建構的鏡像制定一個标簽,便于記憶/索引等

. : 指定Dockerfile檔案在目前目錄下

# docker images

REPOSITORY                                            TAG                 IMAGE ID            CREATED             VIRTUAL SIZE

centos/javaweb                                        latest              f1ee20338304        About an hour ago   1.246 GB

啟動鏡像

# docker run -d -p 58081:8080 f1ee20338304

# docker ps

可檢視到程序

本文轉自 周新宇1991 51CTO部落格,原文連結:http://blog.51cto.com/zhouxinyu1991/1875892,如需轉載請自行聯系原作者