編寫 DockerFile
本節內容簡介
在前面的實驗中我們多次用到的 Dockerfile,在本實驗里我們將通過完成一個實例來學習Dockerfile的編寫。
本節中,我們需要依次完成下面幾項任務:
- Dockerfile 基本框架
- Dockerfile 編寫常用命令
- 從 Dockerfile 構建鏡像
本次實驗的需求是完成一個Dockerfile,通過該Dockerfile創建一個Web應用,該web應用為apache托管的一個靜態頁面網站,換句話說,我們寫一個Dockerfile,用來創建一個實驗樓公司的網站應用,就是http://www.simplecloud.cn這個站點。這個站點是純靜態的頁面,我們也可以直接下載得到。

一、實驗准備
1、創建 Dockerfile 文件
首先,需要創建一個目錄來存放 Dockerfile 文件,目錄名稱可以任意,在目錄里創建Dockerfile文件:
cd /home/shiyanlou mkdir shiyanloutest cd shiyanloutest touch Dockerfile

使用vim/gedit編輯Dockerfile文件,根據我們的需求輸入內容。
二、Dockerfile 基本框架
Dockerfile一般包含下面幾個部分:
- 基礎鏡像:以哪個鏡像作為基礎進行制作,用法是
FROM 基礎鏡像名稱 - 維護者信息:需要寫下該Dockerfile編寫人的姓名或郵箱,用法是
MANITAINER 名字/郵箱 - 鏡像操作命令:對基礎鏡像要進行的改造命令,比如安裝新的軟件,進行哪些特殊配置等,常見的是
RUN 命令 - 容器啟動命令:當基於該鏡像的容器啟動時需要執行哪些命令,常見的是
CMD 命令或ENTRYPOINT
在本節實驗中,我們依次先把這四項信息填入文檔。Dockerfile中的#標志后面為注釋,可以不用寫,另外實驗樓的環境不支持中文輸入,比較可惜。
依次輸入下面的基本框架內容:
# Version 0.1 # 基礎鏡像 FROM ubuntu:latest # 維護者信息 MAINTAINER shiyanlou@shiyanlou.com # 鏡像操作命令 RUN apt-get -yqq update && apt-get install -yqq apache2 && apt-get clean # 容器啟動命令 CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
上面的Dockerfile非常簡單,創建了一個apache的鏡像。包含了最基本的四項信息。
其中FROM指定基礎鏡像,如果鏡像名稱中沒有制定TAG,默認為latest。RUN命令默認使用/bin/sh Shell執行,默認為root權限。如果命令過長需要換行,需要在行末尾加\。CMD命令也是默認在/bin/sh中執行,並且默認只能有一條,如果是多條CMD命令則只有最后一條執行。用戶也可以在docker run命令創建容器時指定新的CMD命令來覆蓋Dockerfile里的CMD。
這個Dockerfile已經可以使用docker build創建新鏡像了,先構建一個版本shiyanloutest:0.1:
cd /home/shiyanlou/shiyanloutest docker build -t shiyanloutest:0.1 .
構建需要安裝apache2,會花幾分鍾,最后查看新創建的鏡像:

使用該鏡像創建容器web1,將容器中的端口80映射到本地80端口:

使用實驗環境桌面上的firefox瀏覽器打開localhost進行測試,查看是否apache已運行:

三、Dockerfile 編寫常用命令
在上述基本的架構下,我們根據需求可以增加新的內容到Dockerfile中。后續的擴展操作都需要放置在Dockerfile的鏡像操作部分。其中部分命令在本實驗中並不會用到,但需要有所了解。
1、指定容器運行的用戶
該用戶將作為后續的RUN命令執行的用戶。這個命令本實驗不需要,但在一些需要指定用戶來運行的應用部署時非常關鍵,比如提供hadoop服務的容器通常會使用hadoop用戶來啟動服務。
命令使用方式,例如使用shiyanlou用戶來執行后續命令:
USER shiyanlou
2、指定后續命令的執行目錄
由於我們需要運行的是一個靜態網站,將啟動后的工作目錄切換到/var/www/html目錄:
WORKDIR /var/www/html
3、對外連接端口號
由於內部服務會啟動Web服務,我們需要把對應的80端口暴露出來,可以提供給容器間互聯使用,可以使用EXPOSE命令。
在鏡像操作部分增加下面一句:
EXPOSE 80
4、設置容器主機名
ENV命令能夠對容器內的環境變量進行設置,我們使用該命令設置由該鏡像創建的容器的主機名為shiyanloutest,向Dockerfile中增加下面一句:
ENV HOSTNAME shiyanloutest
5、向鏡像中增加文件
向鏡像中添加文件有兩種命令:COPY 和ADD。
COPY simplecloudsite /var/www/html
ADD 命令支持添加本地的tar壓縮包到容器中指定目錄,壓縮包會被自動解壓為目錄,也可以自動下載URL並拷貝到鏡像,例如:
ADD html.tar /var/www ADD http://www.shiyanlou.com/html.tar /var/www
根據實驗需求,我們把需要的一個網站放到鏡像里,需要把一個tar包添加到apache的/var/www目錄下,因此選擇使用 ADD命令:
ADD html.tar /var/www
四、CMD 與 ENTRYPOINT
ENTRYPOINT 容器啟動后執行的命令,讓容器執行表現的像一個可執行程序一樣,與CMD的區別是不可以被docker run覆蓋,會把docker run后面的參數當作傳遞給ENTRYPOINT指令的參數。Dockerfile中只能指定一個ENTRYPOINT,如果指定了很多,只有最后一個有效。docker run命令的-entrypoint參數可以把指定的參數繼續傳遞給ENTRYPOINT。
在本實驗中兩種方式都可以選擇。
五、掛載數據卷
將apache訪問的日志數據存儲到宿主機可以訪問的數據卷中:
VOLUME ["/var/log/apche2"]
六、設置容器內的環境變量
使用ENV設置一些apache啟動的環境變量:
ENV APACHE_RUN_USER www-data ENV APACHE_RUN_GROUP www-data ENV APACHE_LOG_DIR /var/log/apche2 ENV APACHE_PID_FILE /var/run/apache2.pid ENV APACHE_RUN_DIR /var/run/apache2 ENV APACHE_LOCK_DIR /var/lock/apche2
七、使用 Supervisord
CMD如果只有一個命令,那如果我們需要運行多個服務怎么辦呢?最好的辦法是分別在不同的容器中運行,通過link進行連接,比如先前實驗中用到的web,app,db容器。如果一定要在一個容器中運行多個服務可以考慮用Supervisord來進行進程管理,方式就是將多個啟動命令放入到一個啟動腳本中。
首先安裝Supervisord,添加下面內容到Dockerfile:
RUN apt-get install -yqq supervisor RUN mkdir -p /var/log/supervisor
拷貝配置文件到指定的目錄:
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
其中supervisord.conf文件需要放在/home/shiyanlou/shiyanloutest下,文件內容如下:
[supervisord] nodaemon=true [program:apache2] command=/bin/bash -c "source /etc/apache2/envvars && exec /usr/sbin/apache2ctl -D FOREGROUND"
如果有多個服務需要啟動可以在文件后繼續添加[program:xxx],比如如果有ssh服務,可以增加[program:ssh]。
修改CMD命令,啟動Supervisord:
CMD ["/usr/bin/supervisord"]
八、從 Dockerfile 創建鏡像
將上述內容完成后放入到/home/shiyanlou/shiyanloutest/Dockerfile文件中,最終得到的Dockerfile文件如下:
# Version 0.2 # 基礎鏡像 FROM ubuntu:latest # 維護者信息 MAINTAINER shiyanlou@shiyanlou.com # 鏡像操作命令 RUN apt-get -yqq update && apt-get install -yqq apache2 && apt-get clean RUN apt-get install -yqq supervisor RUN mkdir -p /var/log/supervisor VOLUME ["/var/log/apche2"] ADD html.tar /var/www COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf WORKDIR /var/www/html ENV HOSTNAME shiyanloutest ENV APACHE_RUN_USER www-data ENV APACHE_RUN_GROUP www-data ENV APACHE_LOG_DIR /var/log/apche2 ENV APACHE_PID_FILE /var/run/apache2.pid ENV APACHE_RUN_DIR /var/run/apache2 ENV APACHE_LOCK_DIR /var/lock/apche2 EXPOSE 80 # 容器啟動命令 CMD ["/usr/bin/supervisord"]
同時在/home/shiyanlou/shiyanloutest目錄下,添加supervisord.conf文件:
[supervisord] nodaemon=true [program:apache2] command=/bin/bash -c "source /etc/apache2/envvars && exec /usr/sbin/apache2ctl -D FOREGROUND"
並下載靜態頁面文件壓縮包:
cd /home/shiyanlou/shiyanloutest wget http://labfile.oss.aliyuncs.com/courses/498/html.tar
將http://simplecloud.cn網站的頁面tar包下載到/home/shiyanlou/shiyanloutest目錄:
docker build 執行創建,-t參數指定鏡像名稱:
docker build -t shiyanloutest:0.2 /home/shiyanlou/shiyanloutest/

docker images 查看創建的新鏡像已經出現在了鏡像列表中:

docker inspect shiyanloutest:0.2 查看該鏡像的詳細信息:

由該鏡像創建新的容器web2,並映射本地的80端口到容器的80端口:
docker run -d -p 80:80 --name web2 shiyanloutest:0.2
最后打開桌面上的firefox瀏覽器,輸入本地地址訪問127.0.0.1,看到我們克隆的琛石科技的網站:

總結
- Dockerfile 基本框架
- Dockerfile 編寫常用命令
- 從 Dockerfile 構建鏡像
請務必保證自己能夠動手完成整個實驗,只看文字很簡單,真正操作的時候會遇到各種各樣的問題,解決問題的過程才是收獲的過程。
