使用Dockerfile定製本身的docker鏡像

咱們都知道,在Linux系統下能夠經過shell腳原本自動安裝部署應用,這樣不但免去了手動操做的麻煩,並且還能夠經過一些自動化工具來實現批量安裝部署。那麼docker是否也能夠經過腳本的方式定製鏡像呢?固然能夠,那就是Dockerfile,咱們能夠把建立應用鏡像的操做都寫入一個Dockerfile文件裏,而後經過docker build命令來構建自已的鏡像,這個過程相似shell腳本的功能。
docker環境的安裝部署能夠參考個人另外一篇博文《Centos 7部署docker環境、基本命令使用及簡單實戰》,http://www.javashuo.com/article/p-hqpgquik-bu.html 本文的全部操做都是基於這個環境執行的。
在使用dockerfile以前,咱們先來看一個簡單的例子:
實例1:查看本機公網IP地址html

docker pull ubuntu
mkdir -p dockerfile/myip

建立Dockerfile文件
vim dockerfile/myip/Dockerfilenginx

FROM ubuntu:latest   #基於ubuntu:latest鏡像來構建新的鏡像
MAINTAINER xuad   #描述鏡像的做者信息
ARG APT=apt-get   #臨時變量,只有在執行docker build命令構建容器時有效
RUN $APT update \   #構建容器時執行的命令
&& $APT install -y curl \
&& rm -rf /var/lib/apt/lists/*
CMD [ "curl", "-s", "http://ip.cn" ]   #運行容器時執行的命令

構建鏡像c++

cd dockerfile/myip/
docker build -t myip .

使用Dockerfile定製本身的docker鏡像
運行這個鏡像
docker run myip
使用Dockerfile定製本身的docker鏡像redis

經過以上實例咱們能夠了解到使用Dockerfile來構建鏡像的整個流程:
一、編寫dockerfile文件;
二、經過docker build來建立新的鏡像;
三、經過docker run來建立並運行新的容器。

build命令

Usage:  docker build [OPTIONS] PATH | URL | -
OPTIONS:
-t, --tag list  #指定構建的鏡像名稱和標記名稱
-f, --file string #指定Dockerfiile文件路徑

示例:
一、docker build . #不指定鏡像名稱的話,將會默認以<none>做爲鏡像名稱和標記名稱
二、docker build -t myip:v1 . #鏡像名稱爲nginx,標記名稱爲v1
三、docker build -t myip:v1 -f /path/Dockerfile /path #指定dockerfile文件路徑
注:在構建鏡像時,Docker daemon會首先將Dockerfile所在的目錄構建成一個context(上下文),而後經過Dockerfile裏的COPY或者ADD語句將context裏的文件複製到指定的鏡像目錄裏。因此須要複製到鏡像裏的文件,不管是腳本、安裝包仍是配置文件,都須要跟Dockerfile文件放在同一個目錄下。
當咱們執行docker build命令後,返回的第一條信息即是在構建上下文。
Sending build context to Docker daemon 2.048kBdocker

Dockerfile指令詳解

一、FROM指令
語法格式:shell

FROM <image>   #<tag>是可選項,沒有指定<tag>的話,表示使用latest
FROM <image>:<tag>

說明:基於哪一個鏡像來構建新的鏡像,FROM指令必須是dockerfile文件的第一行。
例如:FROM ubuntu:latest
二、MAINTAINER指令
語法格式:
MAINTAINER [做者信息]
說明:這個指令用於聲明做者,用於將image的製做者相關的信息寫入到image中。
例如:MAINTAINER xuad或者MAINTAINER xuad.com
三、ENV指令
語法格式:npm

ENV <key> <value>   #設置一個環境變量
ENV <key1>=<value1> <key2>=<value2>...   #設置多個環境變量

說明:定義環境變量,永久變量,容器運行後仍然有效,即容器內的永久變量。
例如:ENV pashname /usr/local/nginx或者ENV pashname=/usr/local/nginx VERSION=1.0
四、ARG指令
語法格式:json

ARG <參數名>   #不設置默認值的話,須要使用--build-arg來設置參數的值
ARG <參數名>[=<默認值>]   #設置參數的默認值

說明:定義參數,即臨時變量,只限於構建鏡像時使用,容器運行後是不會存在的。
例如:ARG APT=apt-get
注:在構建命令docker build中用--build-arg <參數名>=<值> 能夠覆蓋此參數的值。
例如:docker build --build-arg APT=yum -t myip:v1 .
五、RUN指令
語法格式:ubuntu

RUN <command>
RUN ["executable", "param1", "param2" ...]

說明:構建鏡像時運行的shell命令
例如:RUN yum install httpd或者RUN ["yum", "install", "httpd"]
Dockerfile中每個指令都會創建一層,RUN也不例外。多少個RUN就構建了多少層鏡像,多個RUN會產生很是臃腫、多層的鏡像,不只僅增長了構建部署的時間,還容易出錯。咱們在寫Dockerfile的時候,要儘可能避免使用多個RUN,儘可能將須要執行的命令都寫在一個RUN裏。多條命令可以使用\來換行,換行的命令前面加上&&,最後還須要將不須要的文件及目錄刪除,好比安裝包、臨時目錄等,減小容器的大小。
注:Union FS是有最大層數限制的,好比AUFS,曾經是最大不得超過42層,如今是不得超過127層。
如下是安裝redis的一個例子:vim

FROM debian:jessie
RUN buildDeps='gcc libc6-dev make' \
    && apt-get update \
    && apt-get install -y $buildDeps \
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \
    && mkdir -p /usr/src/redis \
    && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
    && make -C /usr/src/redis \
    && make -C /usr/src/redis install \
    && rm -rf /var/lib/apt/lists/* \
    && rm redis.tar.gz \
    && rm -r /usr/src/redis \
    && apt-get purge -y --auto-remove $buildDeps

經過上面的命令咱們能夠看到後面添加的清理命令,刪除了下載的安裝包及解壓出來的文件,刪除了apt緩存文件,還卸載了編譯安裝所須要用到的軟件。鏡像是多層存儲,每一層的東西都不會在下一層被刪除,會一直跟隨着鏡像。所以在構建鏡像時,必定要確保每一層只添加真正須要添加的東西,任何無關的東西都應該清理掉。
六、WORKDIR指令
語法格式:

WORKDIR <工做目錄路徑>

說明:指定工做目錄,之後各層指令的當前目錄就是此目錄。
例如:WORKDIR /usr/local/nginx
注:若是目錄不存在,WORKDIR會自動建立這個目錄。
七、COPY指令
語法格式:

COPY <源路徑>... <目標路徑>
COPY ["<源路徑1>",... "<目標路徑>"]

說明:將上下文目錄中的文件或目錄複製到鏡像內指定的目錄下。
例如:COPY nginx.conf /usr/local/nginx/conf/或者COPY ["nginx.conf","/usr/local/nginx/conf/"]
注:源路徑能夠是多個,甚至可使用通配符;目標路徑能夠是容器內的絕對路徑,也能夠是相對於WORKDIR指定的工做目錄的相對路徑。
八、ADD指令
語法格式:

ADD <源路徑>... <目標路徑>
ADD ["<源路徑1>",... "<目標路徑>"]

說明:更高級的複製指令,與COPY不一樣的是,針對壓縮包會自動解壓處理。
例如:html.tar.gz /var/www/html或者ADD https://xuad.com/html.tar.gz /var/www/html
注:源路徑是一個壓縮文件的話,將會解壓到容器的目標路徑下;源路徑是一個URL的話,會下載或者解壓到容器的目標路徑下。
九、VOLUME指令
語法格式:

VOLUME <路徑>
VOLUME ["<路徑1>", "<路徑2>"...]

說明:將本地卷掛載到容器中
例如:VOLUME /data
注:容器使用的是AUFS,這種文件系統不能持久化數據,當容器關閉後,全部的更改都會丟失。當數據須要持久化時使用VOLUME指令,向掛載目錄裏寫入的任何信息都不會寫進容器存儲層,從而保證了容器存儲層的無變化。
十、EXPOSE指令
語法格式:

EXPOSE <端口1> [<端口2>...]

說明:聲明容器運行時提供的服務端口
例如:EXPOSE 80 443
注:docker run命令可以使用-p <宿主端口>:<容器端口>將聲明的端口映射到本地指定的端口。
十一、USER指令
語法格式:

USER <用戶名>
USER <UID>

說明:指定運行的用戶,之後各層的RUN、CMD或者ENTRYPOINT等指令都會以這個用戶身份執行。
十二、CMD指令
語法格式:

CMD <命令>
CMD ["可執行文件", "參數1", "參數2"...]

說明:容器運行時執行的shell命令,CMD指令通常應爲Dockerfile文件的最後一行。
例如:CMD echo $HOME或者CMD [ "sh", "-c", "echo $HOME" ]
舉個例子,啓動nginx服務不能使用CMD systemctl start nginx,而應該使用CMD ["nginx", "-g", "daemon off;"]。由於docker會將CMD systemctl start nginx命令理解爲CMD ["sh", "-c", "systemctl start nginx"],主進程其實是sh,當systemctl start nginx命令執行完後,sh做爲主進程退出了,天然容器也會退出。這就是爲何使用CMD systemctl start nginx指令,容器運行不起來的緣由。正確的做法是將nginx之前臺形式運行,即CMD ["nginx", "-g", "daemon off;"]。
1三、ENTRYPOINT指令
語法格式:

ENTRYPOINT <命令>
ENTRYPOINT ["可執行文件", "參數1", "參數2"...]

說明:容器運行時執行的shell命令,通常應爲Dockerfile文件的最後一行。
例如:ENTRYPOINT ["nginx", "-g", "daemon off;"]
注:與CMD不一樣的是,當指定了ENTRYPOINT後,CMD再也不是直接運行命令,而是將CMD的內容做爲參數傳給ENTRYPOINT指令。
例如在Dockerfile文件中同時寫了ENTRYPOINT和CMD,而CMD指令不是一個完整的命令,而是一個參數,以下:

ENTRYPOINT ["nginx", "-g"]
CMD ["daemon off;"]

此時CMD的內容會做爲參數傳遞給ENTRYPOINT,至關於ENTRYPOINT ["nginx", "-g", "daemon off;"]。
若是CMD是一個完整的命令,以下:

ENTRYPOINT ["nginx", "-g", "daemon off;"]
CMD echo $HOME

那麼ENTRYPOINT和CMD指令會互相覆蓋,誰在最後誰生效。即ENTRYPOINT ["nginx", "-g", "daemon off;"]不會執行,執行的是CMD echo $HOME。
經過docker run命令給ENTRYPOINT傳遞參數,例如上面查看本機公網IP地址的例子,若是咱們想查看HTTP頭信息,那curl命令須要加上-i參數,運行docker run myip -i時會報下圖錯誤。
使用Dockerfile定製本身的docker鏡像
將Dockerfile文件中CMD指令替換爲ENTRYPOINT,即ENTRYPOINT [ "curl", "-s", "http://ip.cn" ],而後再從新構建鏡像。

docker rmi -f myip:latest
docker build -t myip .
docker run myip -i

使用Dockerfile定製本身的docker鏡像
此時HTTP頭信息成功打印出來了。
1四、HEALTHCHECK指令
語法格式:

HEALTHCHECK [選項] CMD <命令>
HEALTHCHECK NONE   #若是基礎鏡像有健康檢查指令,使用這行能夠取消健康檢查指令

說明:容器健康狀態檢查指令
例如:HEALTHCHECK --interval=5s --timeout=3s CMD curl -fs http://localhost/ || exit 1

HEALTHCHECK的選項有:
--interval=<間隔>:兩次健康檢查的間隔時間,默認爲30秒
--timeout=<時長>:每次檢查的超時時間,超過這個時間,本次檢查就視爲失敗,默認30秒
--retries=<次數>:指定健康檢查的次數,默認3次,若是指定次數都失敗後,則容器的健康狀態爲unhealthy(不健康)

CMD命令的返回值決定了本次健康檢查是否成功,命令的返回值以下:
0: success - 成功 1: unhealthy - 失敗 2: reserved - 保留
若是鏡像添加了健康狀態檢查,容器運行後,在STATUS下會顯示健康狀態。
1五、ONBUILD指令
語法格式:

ONBUILD <其它指令>

說明:指定以當前鏡像爲基礎鏡像構建的下一級鏡像運行的命令
例如:ONBUILD COPY ./package.json /app或者ONBUILD RUN [ "npm", "install" ]
注:在當前鏡像構建時不會執行,只有以當前鏡像爲基礎鏡像,去構建下一級鏡像的時候纔會被執行。

Dockerfile實例

實例2:經過Dockerfile部署nginx容器
nginx版本是1.14.0,使用源碼編譯安裝
(1)Dockerfile文件所在目錄結構
使用Dockerfile定製本身的docker鏡像
(2)Dockerfile文件內容

FROM centos:7
MAINTAINER https://blog.51cto.com/andyxu
ENV TIME_ZOME Asia/Shanghai
ARG NV="nginx-1.14.0"

COPY nginx.conf /data/nginx/conf/
ADD $NV.tar.gz /tmp
RUN yum -y install gcc gcc-c++ make openssl-devel pcre-devel \
        && mkdir -p /data \
        && cd /tmp/$NV \
        && ./configure --prefix=/data/nginx \
        && make -j 2 \
        && make install \
        && echo "${TIME_ZOME}" > /etc/timezone \
        && ln -sf /usr/share/zoneinfo/${TIME_ZOME} /etc/localtime \
        && rm -rf /tmp/nginx* \
        && yum clean all \
        && yum -y remove gcc gcc-c++ make

WORKDIR /data/nginx/
EXPOSE 80
CMD ["./sbin/nginx","-g","daemon off;"]

(3)準備好nginx配置文件
nginx配置文件的內容我就不貼上來了,請自行準備好修改後的nginx配置文件。
(4)構建nginx鏡像

cd dockerfile/nginx/
docker build -t nginx:1.14.0 .

此時會先下載centos鏡像,而後再構建新鏡像,時間會比較久,可喝杯茶耐心等待
使用Dockerfile定製本身的docker鏡像
(5)建立並運行nginx容器
運行nginx鏡像的腳本內容以下:

#!/bin/bash
docker run --name nginx --restart=always -p 8080:80 \
    -v /data/docker/nginx/html:/data/nginx/html \
    -v /data/docker/nginx/logs:/data/nginx/logs \
    -d nginx:1.14.0

查看nginx容器是否成功啓動
使用Dockerfile定製本身的docker鏡像
(6)測試
建立一個index.html文件來作測試

echo "Welcome to nginx" > /data/docker/nginx/html/index.html

經過瀏覽器訪問http://192.168.2.227:8080/
使用Dockerfile定製本身的docker鏡像

相關文章
相關標籤/搜索