簡介
Dockerfile是由一系列命令和參數構成的腳本,這些命令應用於操作系統(centos或者Ubuntu)基礎鏡像並最終創建的一個新鏡像
在沒有Dockerfile之前用手工的方式,修改配置文件,或者添加,刪除文件目錄的方式,來構建一種新鏡像;這種手工方式麻煩,容易出錯,而且不能復用;
如果有Dockerfile,用腳本方式來構建自動化,可復用的,高效率的創建鏡像方式
再軟件系統開發生命周期中,采用Dockerfile來構建鏡像;
1、對於開發人員:可以為開發團隊提供一個完全一致的開發環境;
2、對於測試人員:可以直接拿開發時所構建的鏡像或者通過Dockerfile文件構建一個新的鏡像開始工作;
3、對於運維人員:在部署時,可以實現應用的無縫移植。
DockerFile常用指令
指令 | 含義 |
---|---|
FROM image_name:tag | 定義了使用哪個基礎鏡像啟動構建流程 |
MAINTAINER user_info | 聲明鏡像維護者信息 |
LABEL key value | 鏡像描述元信息(可以寫多條) |
ENV key value | 設置環境變量(可以寫多條) |
RUN command | 構建鏡像時需要運行的命令(可以寫多條) |
WORKDIR path_dir | 設置終端默認登錄進來的工作目錄 |
EXPOSE port | 當前容器對外暴露出的端口 |
ADD source_dir/file dest_dir/file | 將宿主機的文件復制到容器內,如果是一個壓縮文件,將會在復制后自動解壓 |
COPY source_dir/file dest_dir/file | 和ADD相似,但是如果有壓縮文件是不能解壓 |
VOLUME | 創建一個可以從本地主機或其他容器掛載的掛載點,一般用來存放數據庫和需要保持的數據等 |
CMD | 指定容器啟動時要運行的命令,假如有多個CMD,最后一個生效 |
ENTRYPOINT | 指定容器啟動時要運行的命令 |
ONBUILD | 當構建一個被繼承的Dockerfile時運行的命令,父鏡像在被子鏡像繼承后父鏡像的onbuild被觸發。可以把ONBUID理解為一個觸發器。 |
構建鏡像命令
docker build 命令用於使用 Dockerfile 創建鏡像。
語法
docker build [OPTIONS] PATH | URL | -
OPTIONS說明:
- --build-arg=[] :設置鏡像創建時的變量;
- --cpu-shares :設置 cpu 使用權重;
- --cpu-period :限制 CPU CFS周期;
- --cpu-quota :限制 CPU CFS配額;
- --cpuset-cpus :指定使用的CPU id;
- --cpuset-mems :指定使用的內存 id;
- --disable-content-trust :忽略校驗,默認開啟;
- -f :指定要使用的Dockerfile路徑;
- --force-rm :設置鏡像過程中刪除中間容器;
- --isolation :使用容器隔離技術;
- --label=[] :設置鏡像使用的元數據;
- -m :設置內存最大值;
- --memory-swap :設置Swap的最大值為內存+swap,"-1"表示不限swap;
- --no-cache :創建鏡像的過程不使用緩存;
- --pull :嘗試去更新鏡像的新版本;
- --quiet, -q :安靜模式,成功后只輸出鏡像 ID;
- --rm :設置鏡像成功后刪除中間容器;
- --shm-size :設置/dev/shm的大小,默認值是64M;
- --ulimit :Ulimit配置。
- --squash :將 Dockerfile 中所有的操作壓縮為一層。
- --tag, -t: 鏡像的名字及標簽,通常 name:tag 或者 name 格式;可以在一次構建中為一個鏡像設置多個標簽。
- --network: 默認 default。在構建期間設置RUN指令的網絡模式
[選看]docker build 命令后點的意思 . 號的意思
我們在使用 docker build 命令去構建鏡像時,往往會看到命令最后會有一個 . 號。
那么這里的 . 號代表什么意思呢?
在我們學習對 . 號的理解有所偏差,以為是用來指定 Dockerfile 文件所在的位置的,但其實 -f 參數才是用來指定 Dockerfile 的路徑的,那么 . 號究竟是用來做什么的呢?
Docker 在運行時分為 Docker引擎(服務端守護進程) 以及 客戶端工具,我們日常使用各種 docker 命令,其實就是在使用客戶端工具與 Docker 引擎 進行交互。
那么當我們使用 docker build 命令來構建鏡像時,這個構建過程其實是在 Docker引擎 中完成的,而不是在本機環境。
那么如果在 Dockerfile 中使用了一些 COPY 等指令來操作文件,如何讓 Docker引擎 獲取到這些文件呢?
這里就有了一個 鏡像構建上下文 的概念,當構建的時候,由用戶指定構建鏡像的上下文路徑,而 docker build 會將這個路徑下所有的文件都打包上傳給 Docker 引擎,引擎內將這些內容展開后,就能獲取到所有指定上下文中的文件了。
比如說 dockerfile 中的 COPY ./package.json /project,其實拷貝的並不是本機目錄下的 package.json 文件,而是 docker引擎 中展開的構建上下文中的文件,所以如果拷貝的文件超出了構建上下文的范圍,Docker引擎 是找不到那些文件的。
所以 docker build 最后的 . 號,其實是在指定鏡像構建過程中的上下文環境的目錄。
關於基礎鏡像
我們看到dockerFile 都會有一句FROM xxx
,這句話的意思就是基於那個基礎鏡像創建,那問題來了,最開始沒有鏡像怎么構建呢?
官方提供了兩種方式
-
使用tar創建一個完整的鏡像(一般用於系統打包構建鏡像)
-
從頭開始創建簡單的鏡像(FROM scratch 類似於對象的基類)
參考:https://docs.docker.com/develop/develop-images/baseimages/
這里我們只使用第二種方式
DockerFile構建最簡單自定義鏡像,輸入hello docker images
需求:
構建最簡單的鏡像,輸出hello docker images
參考:
https://github.com/docker-library/hello-world/
生成輸出hello docker images的可執行c文件
安裝環境
安裝:gcc glibc glibc-static
yum install -y gcc glibc glibc-static
編寫hello.c文件
文件內容
#include<stdio.h>
int main()
{
printf("hello docker images\n");
}
編譯生成可執行文件
gcc -static hello.c -o hello
測試輸出
./hello
編寫DockerFile腳本
vi myHello
文件內容
#從最小鏡像 scratch 構建,scratch類似於基類
#意思是不依賴任何base鏡像
FROM scratch
#添加文件到根目錄
ADD hello /
#執行根目錄的hello命令
CMD ["/hello"]
保存退出
構建鏡像
#注意鏡像名稱必須小寫
#注意最后有個點
docker build -f myHello -t makalo/myhello:1.0 .
構建完成
使用自定義鏡像啟動容器測試
docker run makalo/myhello:1.0
執行結果
但是這種是比較麻煩的,一般我們基於鏡像庫里面創建好的鏡像構建自定義鏡像更方便
例:DockerFile構建自定義centos鏡像
需求:
基於centos構建並安裝net-tools和vim兩個工具
編寫DockerFile腳本
Dokcerfile 是一個普通的文本文件,文件名一般叫 Dockerfile
也可以不用
這里我們創建 myCentosDockerFile
文件不用加任何后綴,寫入下面內容
#基於centos鏡像創建
FROM centos
#聲明鏡像維護者信息
MAINTAINER makalo<makalochen@foxmail.com>
#鏡像描述元信息 多個元信息 用 | 隔開 太長需要換行的話則使用\符號,不需要換行用|
LABEL name="makalo CentOS Image"|build-date="20210106"
#設置環境變量
ENV WORKPATH /home/
#設置終端默認登錄進來的工作目錄並引用上面設置的環境變量
WORKDIR $WORKPATH
#構建鏡像時需要運行的命令 安裝兩個工具
RUN yum -y install net-tools
RUN yum -y install vim
#當前容器對外暴露出的端口
EXPOSE 80
#指定容器啟動時要運行的命令
CMD /bin/bash
構建鏡像
例:
#使用當前目錄下的myCentosDockerFile文件構建一個鏡像
#鏡像名為makalo/mycentos,tag為1.1 注意最后有個點
docker build -f myCentosDockerFile -t makalo/mycentos:1.1 .
構建完成
使用自定義鏡像啟動容器測試
docker run -it makalo/mycentos:1.1
如圖工具已經裝上
DockerFile通過VOLUME實現容器卷
說明:前面用啟動命令 -v 宿主機目錄:容器卷目錄 來實現容器卷目錄掛載
但是由於定義Dockerfile的時候,並不能保證在所有的宿主機上都有這樣的特定目錄,
所以在Dockerfile定義中,只能指定容器卷目錄,宿主機目錄不能自定義
命令
VOLUME['/home/v1','/home/v2']
編寫dockkerFile
FROM centos
VOLUME ["/home/v1","/home/v2"]
CMD /bin/bash
構建鏡像
docker build -f myVolumeDockerFile -t makalo/mytest:1.1 .
使用鏡像創建容器測試
docker run -it makalo/mytest:1.1
測試
容器內的文件夾
正常
然后我們通過 docker inspect 容器ID 來查看下默認生成的容器卷對應的宿主機目錄
或者直接過濾顯示的
docker inspect -f "{{ .Mounts }}" 容器id1 容器id2
例:
docker inspect -f "{{ .Mounts }}" 7092b859d9c5
下圖圈起來的就是容器卷在宿主機的位置
我們創建一個文件
查看容器
完成同步,沒問題
個人認為,要實現容器卷,還是通過 -v 啟動命令,用dockerfile方式,比較操蛋,宿主機目錄不能自定義
DockerFile中CMD, ENTRYPOINT 的區別和聯系
-
CMD, ENTRYPOINT都是容器啟動的時候,執行執行命令
-
都支持exec和shell方式;
-
一般用法,是單獨一個CMD,或者先ENTRYPOINT,后CMD結合使用
-
假如有多個CMD,啟動的時候帶命令參數,會覆蓋前面的CMD命令,最后一個命令生效,
所以我們平時用CMD的時候,有一種情況的就是單獨一個CMD命令即可,啟動命令也不帶參數;
單獨CMD方式(tomcat 官方dockerFile)
先看下tomcat的官方鏡像的dockerfile;
由於CMD命令假如有多個,會被覆蓋 ,只有最后一個執行;所以我們測試啟動
docker run -it -p 8080:8080 tomcat
像這種啟動不帶參數 是沒毛病的,tomcat可以正常啟動;
但是我們如果加上參數 比如 /bin/bash 或者 ls -l
那就會覆蓋dockerfile中的CMD ["catalina.sh","run"],tomcat就不執行
如:
docker run -it -p 8080:8080 tomcat ls -l
CMD和ENTRYPOINT結合使用(redis 官方dockerFile)
我們再看下redis官方dockerfile
這種就是第二種常見用法,先搞個ENTRYPOINT 執行下執行命令,然后后面跟CMD來拼接具體的執行參數;
最終執行的 是
docker-entrypoint.sh redis-server
經過上面兩個例子,相信大伙對CMD, ENTRYPOINT 有一定的了解;
我們再看看詳細語法
CMD語法
CMD ["executable","param1","param2"] (exec form, this is the preferred form)
CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
CMD command param1 param2 (shell form)
第一種用法:運行一個可執行的文件並提供參數。
第二種用法:為ENTRYPOINT指定參數。
第三種用法(shell form):是以”/bin/sh -c”的方法執行的命令。
ENTRYPOINT 語法
ENTRYPOINT [“executable”, “param1”, “param2”] (exec 格式, 推薦)
ENTRYPOINT command param1 param2 (shell 格式)
我們一般開發 官方都建議用 exec格式;好使
下面通過一些簡單例子,來具體看下CMD, ENTRYPOINT 的實際用法
案例
單獨CMD
第一個dockerfile
FROM centos
CMD echo "abc"
#CMD ["/bin/echo", "defg"]
我們可以運行測試,看看結果,以及把第二個CMD去掉 看看結果;
以及 運行命令后面跟運行參數 看看結果;能明白CMD多個的話 只有最后一個生效;
構建鏡像參考
docker build -f test1 -t makalo/test1:1.0 .
啟動容器運行結果
多個CMD
CMD和ENTRYPOINT結合
第二個dockerfile
FROM centos
ENTRYPOINT ["ls"]
CMD ["-l"]
這個dockerfile 我們用 ENTRYPOINT 執行一個ls命令 然后CMD 追加參數
相當於這個CMD是默認的一個參數 假如需要更換參數 啟動的時候 ,我們直接替換即可
構建鏡像參考
docker build -f test2 -t makalo/test2:1.0 .
運行結果
默認參數
帶參數(會替換原來的默認)
DockerFile之ONBUILD的使用
簡介
ONBUILD:當構建一個被繼承的Dockerfile時運行的命令,父鏡像在被子鏡像繼承后父鏡像的onbuild被觸發。可以把ONBUID理解為一個觸發器
格式:
ONBUILD <其它指令>
ONBUILD 是一個特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而這些指令,
在當前鏡像構建時並不會被執行。只有當以當前鏡像為基礎鏡像,去構建下一級鏡像的時候才會被執行。
啥意思呢?
案例
看個小例子
1.新建base文件,寫入下面內容
FROM centos
#子鏡像會執行此命令
ONBUILD RUN yum -y install net-tools
CMD /bin/bash
2.新建child文件,寫入下面內容
FROM base
3.構建兩個鏡像
先構建父鏡像
docker build -f base -t base .
構建子鏡像
docker build -f child -t child .
4.運行容器測試
docker run -it child
子鏡像運行了父鏡像ONBUILD 內容,已經安裝了net-tools