Dockerfile、Docker-Compose基本命令與介紹

1、Dockerfile基本命名

指令 說明 備註
FROM 指定所建立鏡像的基礎鏡像 第一條指令必須爲 FROM 指令。格式爲 FROM <image>FROM <image>:<tag>
MAINTAINER 指定維護者信息 格式爲 MAINTAINER <name>
RUN RUN 指令一般用於安裝應用和軟件包。 在鏡像中要執行的命令,格式爲 RUN <command>RUN ["executable", "param1", "param2"]。前者默認將在 shell 終端中運行命令,即 /bin/bash -c ;後者則使用 exec 執行。指定使用其它終端能夠經過第二種方式實現,例如 RUN [「/bin/bash」, 「-c」,」echo hello」] 。每條RUN指令將在當前鏡像的基礎上執行指定命令,並提交爲新的鏡像。當命令較長時可使用換行。例如:RUN apt-get update \&& apt-get install -ylibsnappy-dev zliblg-dev libbz2-dev \&& rm -rf /var/cache/apt
CMD 指定啓動容器時默認執行的命令 支持三種格式:1. CMD["executable","param1","param2"] 使用 exec 執行,推薦方式;2. CMD command param1 param2/bin/bash 中執行,提供給須要交互的應用;3. CMD ["param1","param2"] 提供給 ENTRYPOINT 的默認參數;
LABEL 指定生成鏡像的元數據標籤信息
EXPOSE 聲明鏡像內服務所監聽的端口 指定容器要打開的端口
ENV 指定環境變量 格式爲 ENV <key> <value> 。 指定一個環境變量,會被後續 RUN 指令使用,並在容器運行時保持。
ADD 賦值指定的路徑下的內容到容器中的路徑下,能夠爲URL;若是爲tar文件,會自動解壓到路徑下 至關於 COPY,可是比 COPY 功能更強大
COPY 賦值本地主機的路徑下的內容到容器中的路徑下;通常狀況下推薦使用COPY而不是ADD 複製本地主機的 (爲 Dockerfile 所在目錄的相對路徑)到容器中的。用法同ADD,惟一的不一樣是不能指定遠程文件 URLS。
VOLUME 建立數據掛載點 掛載目錄,格式爲VOLUME ["/data"]
USER 指定運行容器時的用戶名或UID
WORKDIR 配置工做目錄 指定當前工做目錄,至關於 cd
ARG 指定鏡像內使用的參數(例如版本號信息等)
ONBUILD 配置當前所建立的鏡像做爲其餘鏡像的基礎鏡像時,所執行的建立操做的命令
STOPSIGNAL 容器退出的信號
HEALTHCHECK 如何進行健康檢查
CMD、ENTRYPOINT 容器啓動時執行指令 配置容器啓動後執行的命令,而且不可被 docker run 提供的參數覆蓋,而CMD是能夠被覆蓋的。若是須要覆蓋,則可使用docker run --entrypoint選項。每一個 Dockerfile 中只能有一個ENTRYPOINT,當指定多個時,只有最後一個生效。
RUN 有兩種使用方式:
  • RUN
  • RUN "executable", "param1", "param2"

每條RUN指令將在當前鏡像基礎上執行指定命令,並提交爲新的鏡像,後續的RUN都在以前RUN提交後的鏡像爲基礎,鏡像是分層的,能夠經過一個鏡像的任何一個歷史提交點來建立,相似源碼的 版本控制 。php

exec 方式會被解析爲一個 JSON 數組,因此必須使用雙引號而不是單引號。exec 方式不會調用一個命令 shell,因此也就不會繼承相應的變量,如:html

RUN [ "echo", "$HOME" ]

這種方式是不會達到輸出 HOME 變量的,正確的方式應該是這樣的python

RUN [ "sh", "-c", "echo", "$HOME" ]

RUN產生的緩存在下一次構建的時候是不會失效的,會被重用,可使用--no-cache選項,即docker build --no-cache,如此便不會緩存。
注意:apt-get updateapt-get install 被放在一個 RUN 指令中執行,這樣可以保證每次安裝的是最新的包。若是 apt-get install 在單獨的 RUN 中執行,則會使用 apt-get update 建立的鏡像層,而這一層多是好久之前緩存的。mysql

CMD有三種使用方式:
CMD  "executable","param1","param2"
CMD  "param1","param2"
CMD command param1 param2 (shell form)

CMD指定在 Dockerfile 中只能使用一次,若是有多個,則只有最後一個會生效。nginx

CMD的目的是爲了在啓動容器時提供一個默認的命令執行選項。若是用戶啓動容器時指定了運行的命令,則會覆蓋掉CMD指定的命令。c++

CMD會在啓動容器的時候執行,build 時不執行,而RUN只是在構建鏡像的時候執行,後續鏡像構建完成以後,啓動容器就與RUN無關了,這個初學者容易弄混這個概念,這裏簡單註解一下。

Docker學習筆記:Dockerfileweb

2、Dockerfile 基本結構

    通常的,Dockerfile 分爲四部分:基礎鏡像信息、維護者信息、鏡像操做指令和容器啓動時執行指令。’#’ 爲 Dockerfile 中的註釋。先看下面一個小例子:redis

# This my first nginx Dockerfile
# Version 1.0

# Base images 基礎鏡像
FROM centos

#MAINTAINER 維護者信息
MAINTAINER tianfeiyu 

#ENV 設置環境變量
ENV PATH /usr/local/nginx/sbin:$PATH

#ADD  文件放在當前目錄下,拷過去會自動解壓
ADD nginx-1.8.0.tar.gz /usr/local/  
ADD epel-release-latest-7.noarch.rpm /usr/local/  

#RUN 執行如下命令 
RUN rpm -ivh /usr/local/epel-release-latest-7.noarch.rpm
RUN yum install -y wget lftp gcc gcc-c++ make openssl-devel pcre-devel pcre && yum clean all
RUN useradd -s /sbin/nologin -M www

#WORKDIR 至關於cd
WORKDIR /usr/local/nginx-1.8.0 

RUN ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-pcre && make && make install

RUN echo "daemon off;" >> /etc/nginx.conf

#EXPOSE 映射端口
EXPOSE 80

#CMD 運行如下命令
CMD ["nginx"]

3、構建鏡像

3.1 編寫Dockerfile文件

vim Dockerfilesql

FROM alpine:latest
MAINTAINER troy
CMD echo "Hello Workd!"

3.2 構建鏡像

docker build -t hello_world .

3.3 運行鏡像

docker run hello_world

clipboard.png

記:

1.表示當前用戶使用的shell是/bin/bash,所謂的shell你能夠理解爲操做系統和人之間交互的平臺。例如windows系統的桌面環境就是一個shell。
bin目錄中基本上都是可執行的命令。docker

啓動容器並啓動bash(交互方式):

$docker run -i -t <image_name/continar_id> /bin/bash

2.保存對容器的修改(commit) 當你對某一個容器作了修改以後(經過在容器中運行某一個命令),能夠把對容器的修改保存下來,這樣下次能夠從保存後的最新狀態運行該容器。

$docker commit ID new_image_name

固然若是在保存成新鏡像的時候想添加新的 dockerfile命令,好比,啓動進入新的目錄。

docker commit -c "WORKDIR /usr/bin" 07c5f9ed32b0 test-images

固然你也能夠在舊鏡像的基礎上寫一個新的dockerfile,用dockerfile生成新的鏡像。
Note: image至關於類,container至關於實例,不過能夠動態給實例安裝新軟件,而後把這個container用commit命令固化成一個image。

Dockerfile文件的每條指令生成鏡像的一層(注:一個鏡像不能超過127層)。Dockerfile中的指令被一條條地執行。每一步都建立一個新的容器,在容器中執行指令並提交修改。當全部指令執行完畢後,返回最終的鏡像id。

前臺運行:
CMD 指令就是用於指定默認的容器主進程的啓動命令的。提到 CMD 就不得不提容器中應用在前臺執行和後臺執行的問題。這是初學者常出現的一個混淆。
Docker 不是虛擬機,容器中的應用都應該之前臺執行,而不是像虛擬機、物理機裏面那樣,用 upstart/systemd 去啓動後臺服務,容器內沒有後臺服務的概念。
一些初學者將 CMD 寫爲:

CMD service nginx start

而後發現容器執行後就當即退出了。甚至在容器內去使用 systemctl 命令結果卻發現根本執行不了。這就是由於沒有搞明白前臺、後臺的概念,沒有區分容器和虛擬機的差別,依舊在以傳統虛擬機的角度去理解容器。
對於容器而言,其啓動程序就是容器應用進程,容器就是爲了主進程而存在的,主進程退出,容器就失去了存在的意義,從而退出,其它輔助進程不是它須要關心的東西。
而使用 service nginx start 命令,則是但願 upstart 來之後臺守護進程形式啓動 nginx 服務。而剛纔說了 CMD service nginx start 會被理解爲

CMD [ "sh", "-c", "service nginx start"],

所以主進程其實是 sh。那麼當 service nginx start 命令結束後,sh 也就結束了,sh 做爲主進程退出了,天然就會令容器退出。
正確的作法是直接執行 nginx 可執行文件,而且要求之前臺形式運行。好比:

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

ENTRYPOINT [ "/usr/sbin/nginx", "-g", "daemon off;" ]

爲何要這麼作呢?由於Docker容器僅在它的1號進程(PID爲1)運行時,會保持運行。若是1號進程退出了,Docker容器也就退出了。

Shell 和 Exec 格式

咱們可用兩種方式指定 RUN、CMD 和 ENTRYPOINT 要運行的命令:Shell 格式和 Exec 格式,兩者在使用上有細微的區別。
Shell 格式

<instruction> <command>

例如:

RUN apt-get install python3  

CMD echo "Hello world"  

ENTRYPOINT echo "Hello world"

當指令執行時,shell 格式底層會調用 /bin/sh -c <command> 。
例以下面的 Dockerfile 片斷:

ENV name Cloud Man  

ENTRYPOINT echo "Hello, $name"

執行 docker run <image> 將輸出:

Hello, Cloud Man

注意環境變量 name 已經被值 Cloud Man 替換。

下面來看 Exec 格式。

Exec 格式

<instruction> ["executable", "param1", "param2", ...]

例如:

RUN ["apt-get", "install", "python3"]  

CMD ["/bin/echo", "Hello world"]  

ENTRYPOINT ["/bin/echo", "Hello world"]

當指令執行時,會直接調用 <command>,不會被 shell 解析。
例以下面的 Dockerfile 片斷:

ENV name Cloud Man  

ENTRYPOINT ["/bin/echo", "Hello, $name"]

運行容器將輸出:

Hello, $name

注意環境變量「name」沒有被替換。
若是但願使用環境變量,照以下修改

ENV name Cloud Man  

ENTRYPOINT ["/bin/sh", "-c", "echo Hello, $name"]

運行容器將輸出:

Hello, Cloud Man

CMD 和 ENTRYPOINT 推薦使用 Exec 格式,由於指令可讀性更強,更容易理解。RUN 則兩種格式均可以。

4、Docker-Compose

    一句話:docker-compose 是用來作docker 的多容器控制,是一個用來把 docker 自動化的東西。有了 docker-compose 你能夠把全部繁複的 docker 操做全都一條命令,自動化的完成。

4.1 經常使用命令

docker-compose up -d nginx                     構建建啓動nignx容器

docker-compose exec nginx bash            登陸到nginx容器中

docker-compose down                              刪除全部nginx容器,鏡像

docker-compose ps                                   顯示全部容器

docker-compose restart nginx                   從新啓動nginx容器

docker-compose run --no-deps --rm php-fpm php -v  在php-fpm中不啓動關聯容器,並容器執行php -v 執行完成後刪除容器

docker-compose build nginx                     構建鏡像 。        

docker-compose build --no-cache nginx   不帶緩存的構建。

docker-compose logs  nginx                     查看nginx的日誌 

docker-compose logs -f nginx                   查看nginx的實時日誌



docker-compose config  -q                        驗證(docker-compose.yml)文件配置,當配置正確時,不輸出任何內容,當文件配置錯誤,輸出錯誤信息。 

docker-compose events --json nginx       以json的形式輸出nginx的docker日誌

docker-compose pause nginx                 暫停nignx容器

docker-compose unpause nginx             恢復ningx容器

docker-compose rm nginx                       刪除容器(刪除前必須關閉容器)

docker-compose stop nginx                    中止nignx容器

docker-compose start nginx                    啓動nignx容器

4.2 docker-compose.yml

depends_on

在使用 Compose 時,最大的好處就是少打啓動命令,可是通常項目容器啓動的順序是有要求的,若是直接從上到下啓動容器,必然會由於容器依賴問題而啓動失敗。
例如在沒啓動數據庫容器的時候啓動了應用容器,這時候應用容器會由於找不到數據庫而退出,爲了不這種狀況咱們須要加入一個標籤,就是 depends_on,這個標籤解決了容器的依賴、啓動前後的問題。
例以下面容器會先啓動 redis 和 db 兩個服務,最後才啓動 web 服務:

version: '2'
services:
  web:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: postgres

注意的是,默認狀況下使用 docker-compose up web 這樣的方式啓動 web 服務時,也會啓動 redis 和 db 兩個服務,由於在配置文件中定義了依賴關係。

links

還記得上面的depends_on吧,那個標籤解決的是啓動順序問題,這個標籤解決的是容器鏈接問題,與Docker client的--link同樣效果,會鏈接到其它服務中的容器。
格式以下:

links:
 - db
 - db:database
 - redis

使用的別名將會自動在服務容器中的/etc/hosts裏建立。例如:

172.12.2.186  db
172.12.2.186  database
172.12.2.187  redis

相應的環境變量也將被建立。

volumes

掛載一個目錄或者一個已存在的數據卷容器,能夠直接使用 [HOST:CONTAINER] 這樣的格式,或者使用 [HOST:CONTAINER:ro] 這樣的格式,後者對於容器來講,數據卷是隻讀的,這樣能夠有效保護宿主機的文件系統。
Compose的數據卷指定路徑能夠是相對路徑,使用 . 或者 .. 來指定相對目錄。
數據卷的格式能夠是下面多種形式:

volumes:
  // 只是指定一個路徑,Docker 會自動在建立一個數據卷(這個路徑是容器內部的)。
  - /var/lib/mysql

  // 使用絕對路徑掛載數據卷
  - /opt/data:/var/lib/mysql

  // 以 Compose 配置文件爲中心的相對路徑做爲數據卷掛載到容器。
  - ./cache:/tmp/cache

  // 使用用戶的相對路徑(~/ 表示的目錄是 /home/<用戶目錄>/ 或者 /root/)。
  - ~/configs:/etc/configs/:ro

  // 已經存在的命名的數據卷。
  - datavolume:/var/lib/mysql

若是你不使用宿主機的路徑,你能夠指定一個volume_driver。

volume_driver: mydriver

volumes_from

從其它容器或者服務掛載數據卷,可選的參數是 :ro或者 :rw,前者表示容器只讀,後者表示容器對數據卷是可讀可寫的。默認狀況下是可讀可寫的。

volumes_from:
  - service_name
  - service_name:ro
  - container:container_name
  - container:container_name:rw

參考文檔:1. docker與dockerfile教程
2. Docker系列教程22-docker-compose.yml經常使用命令
3. Shell 和 Exec 格式

相關文章
相關標籤/搜索