什麼是 Dockerfile 呢?
Dockerfile 是一個文本文檔,其中包含用戶能夠在命令行上調用以組裝映像的全部命令。Docker 能夠經過閱讀該文件中的指令來自動構建映像。(相似於 Linux 上的 bash 腳本,Docker 經過該腳本構建鏡像)html
$ mkdir mynginx $ cd mynginx $ touch Dockerfile //首字母必須大寫
Dockerfile 文件內容以下nginx
FROM nginx RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
這個 Dockerfile 很簡單,一共就兩行。涉及到了兩條指令,FROM 和 RUN。程序員
功能:指定基礎鏡像redis
所謂定製鏡像,那必定是以一個鏡像爲基礎,在其上進行定製。就像咱們以前運行了一個 nginx 鏡像的容器,再進行修改同樣,基礎鏡像是必須指定的。而 FROM 就是指定 基礎鏡像,所以一個 Dockerfile 中 FROM 是必備的指令,而且必須是第一條指令。
通常使用中咱們經過 Docker Hub 來查找相關鏡像。以下圖所示,紅標中標識的爲官方鏡像
docker
除了選擇現有鏡像爲基礎鏡像外,Docker 還存在一個特殊的鏡像,名爲 scratch(該鏡像不能經過 docker pull 命令直接拉取)。這個鏡像是虛擬的概念,並不實際存在,它表示一個空白的鏡像。shell
由於本人只對 PHP 較爲熟悉,沒有使用過 go,這個也不是很瞭解,就先跳過了json
功能:執行命令bash
用來執行命令行命令的
實際使用下有兩種格式app
RUN <命令>
RUN ["可執行文件", "參數1", "參數2"]
Dockerfile 中每個指令都會創建一層,RUN 也不例外。每個 RUN 執行結束後,都會 commit 這一層的修改,構成新的鏡像。因此在使用中盡力減小指令。ui
FROM debian:stretch RUN apt-get update RUN apt-get install -y gcc libc6-dev make wget RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" RUN mkdir -p /usr/src/redis RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 RUN make -C /usr/src/redis RUN make -C /usr/src/redis install
上面的這種寫法,建立了 7 層鏡像。這是徹底沒有意義的,並且不少運行時不須要的東西,都被裝進了鏡像裏,好比編譯環境、更新的軟件包等等。結果就是產生很是臃腫、很是多層的鏡像,不只僅增長了構建部署的時間,也很容易出錯。咱們在之後的使用應該避免。正確的寫法以下所示:
FROM debian:stretch RUN buildDeps='gcc libc6-dev make wget' \ && apt-get update \ && apt-get install -y $buildDeps \ && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.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
在上一個 Dockerfile 中全部的命令只有一個目的,就是編譯、安裝 redis 可執行文件。所以沒有必要創建不少層,這只是一層的事情。所以,這裏咱們僅僅使用一個 RUN 指令,並使用 && 將各個所需命令串聯起來。將以前的 7 層,簡化爲了 1 層。
在撰寫 Dockerfile 的時候,要常常提醒本身,這並非在寫 Shell 腳本,而是在定義每一層該如何構建。
命裏格式: docker build [選項] <上下文路徑/URL/->
$ docker build -t mynginx:v1 . Sending build context to Docker daemon 2.048kB Step 1/2 : FROM nginx ---> 08393e824c32 Step 2/2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html ---> Running in 1d7edd724b5f Removing intermediate container 1d7edd724b5f ---> e29ba82c8e43 Successfully built e29ba82c8e43 Successfully tagged mynginx:v1 // 查看剛剛建立的鏡像 $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE mynginx v1 e29ba82c8e43 3 minutes ago 132MB
格式:
COPY [--chown=<user>:<group>] <源路徑> <目標路徑>
(經常使用)COPY [--chown=<user>:<group>] ["<源路徑1>", "<目標路徑>"]
構建上下文目錄中 <源路徑> 的文件/目錄複製到新的一層的鏡像內的 <目標路徑> 位置。
COPY package.json /usr/src/app/
加上 --chown=<user>:<group> 選項來改變文件的所屬用戶及所屬組
COPY --chown=55:mygroup files* /mydir/ COPY --chown=bin files* /mydir/ COPY --chown=1 files* /mydir/ COPY --chown=10:11 files* /mydir/
和 COPY 的格式和性質基本一致。可是在 COPY 基礎上增長了一些功能。
在 Docker 官方的 Dockerfile 最佳實踐文檔 中要求,儘量的使用 COPY,由於 COPY 的語義很明確,就是複製文件而已,而 ADD 則包含了更復雜的功能,其行爲也不必定很清晰。最適合使用 ADD 的場合,就是所說起的須要自動解壓縮的場合。
Docker 不是虛擬機,容器就是進程。既然是進程,那麼在啓動容器的時候,須要指定所運行的程序及參數。CMD 指令就是用於指定默認的容器主進程的啓動命令的。
格式:
用於設置環境變量,不管是後面的其它指令,如 RUN,仍是運行時的應用,均可以直接使用這裏定義的環境變量。
格式:
<key> <value>
<key1>=<value1> <key2>=<value2>...
格式:
ARG <參數名>[=<默認值>]
與 ENV 指令同樣,都是設置環境變量。所不一樣的是,ARG 所設置的構建環境的環境變量,在未來容器運行時是不會存在這些環境變量的。
Dockerfile 中的 ARG 指令是定義參數名稱,以及定義其默認值。該默認值能夠在構建命令 docker build 中用 --build-arg <參數名>=<值>
來覆蓋。
格式:
VOLUME ["<路徑1>", "<路徑2>"...]
VOLUME <路徑>
示例:
容器中的 /data 目錄自動掛載到匿名卷中
VOLUME /data
該指令能夠在運行時被覆蓋
docker run -d -v mydata:/data xxxx
格式:
EXPOSE <端口1> [<端口2>...]
聲明運行時容器提供服務端口,這只是一個聲明,在運行時並不會由於這個聲明就會開啓這個端口的服務。
寫入這樣的聲明有兩個好處,一個是幫助鏡像使用者理解這個鏡像服務的守護端口,以方便配置映射;另外一個用處則是在運行時使用隨機端口映射時,也就是 docker run -P 時,會自動隨機映射 EXPOSE 的端口。
格式:
使用 WORKDIR 指令能夠來指定工做目錄(或者稱爲當前目錄),之後各層的當前目錄就被改成指定的目錄,如該目錄不存在,WORKDIR 會幫你創建目錄。
RUN cd /app RUN echo "hello" > world.txt
使用上面的內容構建鏡像後會發現根本找不到 /app/world.txt
文件。緣由其實很簡單,在 Shell 中,連續兩行是同一個進程執行環境,所以前一個命令修改的內存狀態,會直接影響後一個命令;而在 Dockerfile 中,這兩行 RUN 命令的執行環境根本不一樣,是兩個徹底不一樣的容器。這就是對 Dockerfile 構建分層存儲的概念不瞭解所致使的錯誤。
所以若是須要改變之後各層的工做目錄的位置,那麼應該使用 WORKDIR 指令。
格式:
USER <用戶名>[:<用戶組>]
USER 指令和 WORKDIR 類似,都是改變環境狀態並影響之後的層。WORKDIR 是改變工做目錄,USER 則是改變以後層的執行 RUN, CMD 以及 ENTRYPOINT 這類命令的身份。固然,和 WORKDIR 同樣,USER 只是幫助你切換到指定用戶而已,這個用戶必須是事先創建好的,不然沒法切換。
其餘指令參考官方文檔