八、【Docker筆記】使用Dockerfile創建鏡像

  • 2020 年 4 月 12 日
  • 筆記

在前面我們講解了基於已有的鏡像容器創建和基於本地模板導入兩種方式來創建鏡像,在這裡我們就來說說第三種創建鏡像的方式。Dockerfile是一個文本格式的配置文件,我們可以通過Dockerfile快速創建自定義的鏡像。

一、基本結構

Dockerfile是由多行命令語句組成的,並且在文件中支援以 # 開始的注釋行。我們一般將Dockerfile文件分為四部分:基礎鏡像資訊、維護者資訊、鏡像操作指令和容器啟動時執行指令。其中,第一行(不包含注釋行)必須指定基於的基礎鏡像,例如:FROM ubuntu。之後可以是維護者資訊,如:MAINTAINER gongziqi [email protected]。再往後可以是鏡像的操作指令,如:

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

最後可以是容器啟動時執行指令,如:CMD /usr/sbin/nginx。

# 0. 在ubuntu鏡像的基礎上,安裝inotify-tools/nginx/apache2/openssh-server等,創建新的Nginx鏡像  	# Nginx  	# VERSION 1.0  	FROM ubuntu  	MAINTAINER gongziqi [email protected]  	RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server    # 1. 在ubuntu鏡像基礎上,安裝firefox/vnc。啟動後,用戶可通過5900埠通過vnc方式使用firefox  	# FireFox over VNC  	# VERSION 1.0  	FROM ubuntu  	RUN apt-get update && apt-get install -y x11vnc xvfb firefox  	RUN mkdir ./.vnc  	RUN x11vnc -storepasswd 123456 ~/.vnc/passwd  	RUN bash -c 'echo "firefox" >> /.bashrc'  	EXPOSE 5900  	CMD ["x11vnc","-forever","usepw","-create"]  

二、指令

1、FROM

語法為:FROM 或 FROM :。若在同一個Dockerfile中創建多個鏡像,可以使用多個FROM即每個鏡像一個。

2、MAINTAINER

語法:MAINTAINER ,用來指定維護者資訊。

3、RUN

語法:RUN 或 RUN ["executable","param1","param2"]。第一個將在shell終端中運行命令,即 /bin/bash -c;第二個則使用 exec 執行。每條RUN指令將在當前鏡像基礎上執行指定指令,並提交為新的鏡像。若命令行太長可以使用 來換行書寫。

4、CMD

支援三種方式:

  • CMD ["executable", "param1", "param2"],使用 exec執行,推薦方式。

  • CMD command param1 param2,在 /bin/sh 中執行,提供給需要交互的應用。

  • CMD ["param1","param2"],提供給 ENTRYPOINT的默認參數。

    指定啟動容器時執行的命令,每個Dockerfile只能由一條 CMD命令。若指定多條,則只有最後一條有效。若在啟動容器時,指定了運行的命令,則CMD命令將會被覆蓋。

5、EXPOSE

語法:EXPOSE [ ...],如:EXPOSE 22 80 8443,即告訴Docker伺服器容器暴露的埠,這些埠可供互聯使用。此時在容器啟動中,可使用 -P 來隨機指定一個埠,也可使用 -p 來指定具體的埠映射。

6、ENV

語法:ENV 。指定一個環境變數,會被後面的RUN指令使用,並在容器運行時保持。如:

ENV PG_MAJOR 9.3  ENV PG_VERSION 9.3.4  RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && ...  ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH  

7、ADD

語法:ADD 。將複製指定的src到容器中的desc。其中,src 可以是Dockerfile所在目錄的一個相對路徑(文件/目錄);也可為一個URL;還可為一個tar文件。

8、COPY

語法:COPY 。複製本地主機的src(Dockerfile所在目錄的相對路徑)到容器中的desc。當目標路徑不存在時,將自動創建。當使用本地目錄為源目錄時,推薦使用COPY,不推薦ADD。

9、ENTRYPOINT

語法:ENTRYPOINT ["executable","param1","param2"] 或 ENTRYPOINT command param1 param2(shell中執行)。配置容器啟動後執行的命令,並且不可被docker run 提供的參數覆蓋。每個Dockerfile只能有一個ENTRYPOINT,當指定多個時,只有最後一個有效。

10、VOLUME

語法:VOLUME ["/data"]。創建一個可以從本地主機或其他容器掛載的掛載點,一般用來存放資料庫和需要保持的數據等。

11、USER

語法:USER daemon。指定運行容器時的用戶名或UID,後續的RUN指令也會使用指定用戶。當服務不需要管理員許可權時,可通過該命令指定運行用戶,並且可以在之前創建所需要的用戶。如:RUN groupadd -r postgres && useradd -r -g postgres postgres。若此時需要臨時獲取管理員許可權,則可使用gosu,不推薦使用sudo。

12、WORKDIR

語法:WORKDIR /path/to/workdir。為後續的 RUN、CMD、ENTRYPOINT指令配置工作目錄。可使用多個WORKDIR,若後面的WORKDIR指定的是相對路徑,則是基於前一個WORKDIR指定的路徑。如:

WORKDIR /a  WORKDIR b  WORKDIR c  RUN pwd  # 結果為:/a/b/c  

13、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指令後添加了以上的兩條指令。在使用ONBUILD指令的鏡像,我們推薦在標籤中註明,如:ruby:1.9-onbuild。

三、創建鏡像

在編寫完Dockerfile之後,可以通過 Docker build 命令來創建鏡像。語法為:docker build [選項] 路徑,即讀取指定路徑下的Dockerfile,並將該路徑下所有內容發送給Docker服務端,由服務端來創建鏡像。因此我們建議放置Dockerfile的目錄為空目錄。若為非空目錄,希望忽略路徑下的某些目錄或文件,可通過 .dockerignore文件來配置。

# 指定Dockerfile路徑所在路徑為 /tmp/docker_builder/,希望生成鏡像標籤為 build_repo/first_image, # 在標籤命名時需要注意,所有字母必須為小寫  $ sudo docker build -t build_repo/first_image /tmp/docker_builder/  

四、一個實例

根據以上資訊,我們來自己創建一個Nginx鏡像。

# 0. 創建Dockerfile所在目錄  $ sudo mkdir /opt/tmp_dockerbuilder    # 1. 創建Dockerfile文件並編寫內容  $ sudo vim Dockerfile  	# Nginx  	# VERSION 1.0  	FROM ubuntu  	MAINTAINER gongziqi [email protected]  	RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server    # 2. 查看當前本地鏡像  $ sudo docker images  REPOSITORY                   TAG                 IMAGE ID            CREATED             SIZE    # 3. build Dockerfile文件,創建鏡像  $ sudo docker build -t nginx/mynginx /opt/tmp_dockerbuilder/Dockerfile  Sending build context to Docker daemon  2.048kB  Step 1/3 : FROM ubuntu   ---> 4e5021d210f6  Step 2/3 : MAINTAINER gongziqi [email protected]   ---> Running in 8dc5269da475  Removing intermediate container 8dc5269da475   ---> e27af3f3a447  Step 3/3 : RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server   ---> Running in 2ec0f5b9fc81   ........   ........   ........  Successfully built d27de6c7896d  Successfully tagged nginx/mynginx:latest    # 4. 再次查看本地鏡像  $ sudo docker images  REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE  nginx/mynginx        latest              d27de6c7896d        6 minutes ago       275MB    # 5. 以當前創建的鏡像運行容器  $ sudo docker run -ti d27de6c7896d /bin/bash  root@a505965d1b84:/#    # 6. 查看當前的容器中是否有我們剛才需要安裝的相關軟體  root@a505965d1b84:/# find / -name apache2  /etc/cron.daily/apache2  /etc/init.d/apache2  /etc/logrotate.d/apache2  /etc/apache2  /etc/ufw/applications.d/apache2  find: '/proc/1/map_files': Operation not permitted  find: '/proc/12/map_files': Operation not permitted  /usr/lib/apache2  /usr/sbin/apache2  /usr/share/bug/apache2  /usr/share/doc/apache2  /usr/share/lintian/overrides/apache2  /usr/share/apache2  /var/cache/apache2  /var/lib/apache2  /var/log/apache2    # 7. 查看ubuntu鏡像運行的容器中是否有apache2  $ sudo docker run -tid ubuntu /bin/bash  $ sudo docker exec -ti 6df8ff14f57f /bin/bash  root@6df8ff14f57f:/# find / -name apache2  find: '/proc/1/map_files': Operation not permitted  find: '/proc/10/map_files': Operation not permitted  find: '/proc/19/map_files': Operation not permitted  root@6df8ff14f57f:/#    # 說明:我們會發現剛才的配置的 apache2 軟體已被安裝,而基於的 ubuntu鏡像本身是沒有apache2的  

image-20200412143000638

Tags: