1. 程式人生 > 其它 >4--Docker之Dockerfile映象定製

4--Docker之Dockerfile映象定製

目錄

一、Dockerfile 映象定製的使用

建立docker映象的方式有兩種:

  1. 手動修改容器內容,然後docker commit提交容器為新的映象。
  2. 通過在dockerfile中定義一系列的命令和引數構成的指令碼,然後這些命令應用於基礎映象,以此新增層,最終生成一個新的映象。極大的簡化了部署工作。

dockerfile是用來構建docker映象的檔案==>相當於一個指令碼,通過dockerfile指令,來構建軟體依賴,檔案依賴,儲存,等等

構建步驟:

  • 編寫一個dockerfile檔案
  • docker build 構 建成一個映象
  • docker run 執行映象
  • docker push 釋出映象(DockerHub、阿里雲映象倉庫)

1.什麼是Dockerfile?

Dockerfile由一行行命令語句組成,並且支援以#開頭的註釋行,一般而言,Dockerfile主體內容分為四部分:基礎映象資訊,維護者資訊,映象操作指令和容器啟動時執行命令。
Dockerfile以從上而下的順序執行Dockerfile的指令。為了指定基本映像,第一條指令必須是FROM,一個宣告以#字元開頭則被視為註釋,可以在docker檔案中使用RUN,CMD,FROM,EXPOSE,ENV等指令。

注意事項

由於dockerfile中每一個指令都會建立一層,每一個 RUN 的行為,會新建立一層,在其上執行這些命令,執行結束後,commit 這一層的修改,構成新的映象。映象是多層儲存,每一層的東西並不會在下一層被刪除,會一直跟隨著映象。因此映象構建時,一定要確保每一層只新增真正需要新增的東西,任何無關的東西都應該清理掉。(安裝包、快取等)

Dockerfile 支援 Shell 類的行尾新增 \ 的命令換行方式,以及行首 # 進行註釋的格式。良好的格式,比如換行、縮排、註釋等,會讓維護、排障更為容易,這是一個比較好的習慣。

2.基礎知識

每個保留關鍵字(指令)都必須是大寫字母
執行從上到下順序執行
用#表示註釋
每一個指令都會建立提交一個新的映象 層,並提交!

dockerfile是面向開發的,我們以後要釋出專案,做映象,就需要編寫dockerfile檔案,這個檔案十分簡單!
docker映象逐漸成為了企業交付的標準,必須掌握 !

步驟:開發、部署、運維,缺一不可!

dockerfile:構建檔案,定義了一切步驟,相當於原始碼
dockerimages:通過dockerfile構建生成的映象,最終釋出和執行的產品
docker容器:容器就是映象執行起來提供服務的

3.dockerfile指令說明

# 1.FROM        #基礎映象,一切從這裡構建 
# 2.USER        #指定容器執行程式的使用者身份,預設是 root使用者
# 3.MAINTAINER  #映象是誰寫的,姓名+郵箱 maintainer 
# 4.RUN         #映象構建的時候需要執行的命令
# 5.ADD         #更高階的複製檔案,新增宿主機的檔案到容器內,還多了一個自動解壓的功能
# 6.WORKDIR     #映象的工作目錄
# 7.VOLUME      #掛載的目錄
# 8.EXPOSE      #暴露埠配置
# 9.CMD         #指定容器啟動的時候要執行的命令,只有最後一個會生效,可被替代
# 10.ENTRYPOINT  #入口點,指定容器啟動的時候要執行的命令,可以追加命令
# 11.ONBUILD    #當構建一個被繼承dockerfile,這個時候就會執行這個指令,觸發指令
# 12.COPY       #類似ADD,拷貝宿主機的檔案到容器內,僅僅是拷貝
# 13.ENV        #構建的時候設定環境變數

COPY

copy指令從宿主機複製檔案或者目錄到新的一層映象內
如:
copy dockerfile.txt /opt

支援多個檔案,以及萬用字元形式的複製,語法要滿足Golang的filepath.Match
copy docker* /tmp/cc?.txt /opt

COPY指令能夠保留原始檔的元資料,如許可權,訪問時間等等,這點很重要

ADD

特性和COPY基本一致,不過多了些功能
1. 原始檔是一個URL,此時dockcer引擎會下載該連結,放入目標路徑,且許可權自動設為600。若這不是期望結果,還得增加一層RUN指令進行調整
# ADD dockerfile.gz /home
# RUN xxx修改命令  
2. 原始檔是一個URL,且是一個壓縮包,不會自動解壓,也得單獨用RUN指令解壓
3. 原始檔是一個壓縮檔案,且是gzip,bzip,xz,tar情況,ADD指令會自動解壓壓縮該檔案到沒有檔案

Dockerfile官方更為推薦使用copy,ADD包含了更多複製的功能,切ADD會使構建快取失效,導致映象構建緩慢

ADD和COPY的區別

#ADD : 將檔案新增至映象內
	1、支援自動解壓(tar)
	2、ADD支援遠端下載內容到容器內(不支援自動解壓)

#COPY:將檔案複製到映象內
	1、不支援自動解壓
	2、不支援網路下載內容

CMD

用法,注意是雙引號
# CMD在容器內執行某個命令,啟動程式
# 該映象在執行容器例項的時候,執行的具體引數是什麼

CMD["引數1","引數2"]
在指定了entrypoint指令後,用CMD指定具體的引數

dokcer不是虛擬機器,容器就是一個程序,既然是程序,那麼程式在啟動的時候需要指定些執行引數,這就是CMD指令作用

例如centos映象預設的CMD是/bin/bash,直接docker run -it centos會直接進入bash直譯器。
也可以啟動容器時候,指定引數: docker run -it centos cat /etc/os-release

CMD ["/bin/bash"]

# 該容器執行時,執行的命令
# 等同於命令列的直接操作:docker run -it centos cat /etc/os-release
CMD ["cat","/etc/os-release"]

容器內執行程式

這裡要注意的是,docker不是虛擬機器的概念,虛擬機器的程式執行,基本上都是在後臺執行,利用systemctl執行,但是容器內沒有後臺程序的概念,必須在前臺執行
容器就是為了主程序而存在的,主程序如果退出了,容器也就失去意義,自動退出。

例如一個經典的問題:
# 這樣的寫法是錯誤的,容器會立即退出
CMD systemctl start nginx

因為systemctl start nginx是以守護程序(預設在後臺執行)的形式啟動nginx,且CMD命令會轉化為
CMD ["sh","-c","systemctl start nginx" ]

這樣的命令主程序是sh直譯器,執行完畢後立即結束了,因此容器也就退出了。

# 相當於nginx -g daemon off
因此正確的做法應該是 CMD ["nginx","-g","daemon off;"]

dokcer面試題:
ENTRYPOINT和CMD的區別以及用法! ! !

ENTRYPOINT作用和CMD一樣,都是在指定容器啟動程式以及引數。

當指定了ENTRYPOINT之後,CMD指令的語義就有了變化,而是把CMD的內容當作引數傳遞給ENTRYPOINT指令。

CMD和ENIRYPOINT的區別

CMD #指定容器啟動的時候要執行的命令,只有最後一個會 生效,可被替代

ENTRYPOINT #指定容器啟動的時候要執行的命令,可以追加命令

#1.測試CMD
[root@docker dockerfile]# vim dockerfile-cmd-test  #編寫dockerfile檔案
FROM centos
CMD ["ls","-a"]
[root@docker dockerfile]# docker build -f dockerfile-cmd-test  -t cmdtest .  #構建映象
[root@docker dockerfile]# docker run c851cfaf4de4  #執行構建的映象  (ls -a命令生效)
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc

#2.想追加一個命令l【ls -al】
[root@docker dockerfile]# docker run c851cfaf4de4 -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:370: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.

注:CMD用-l替換了 ["ls","-a"],然而-l不是命令所以報錯

#如果想執行命令要接完整命令
[root@docker dockerfile]# docker run c851cfaf4de4 ls -al
total 0
drwxr-xr-x   1 root root   6 Mar 20 10:02 .
drwxr-xr-x   1 root root   6 Mar 20 10:02 ..
-rwxr-xr-x   1 root root   0 Mar 20 10:02 .dockerenv
lrwxrwxrwx   1 root root   7 Nov  3 15:22 bin -> usr/bin
drwxr-xr-x   5 root root 340 Mar 20 10:02 dev
drwxr-xr-x   1 root root  66 Mar 20 10:02 etc
drwxr-xr-x   2 root root   6 Nov  3 15:22 home
#1.測試ENTRYPOINT
[root@docker dockerfile]# vim dockerfile-ENTRYPOINT-test   #編寫dockerfile檔案
FROM centos
ENTRYPOINT ["ls","-a"]
[root@docker dockerfile]# docker build -f dockerfile-ENTRYPOINT-test  -t entrypointtest .   #構建映象
[root@docker dockerfile]# docker run fd149b7d1690   #執行映象
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found

#2.想追加一個命令-l  【ls -al】
[root@docker dockerfile]# docker run fd149b7d1690 -l
total 0
drwxr-xr-x   1 root root   6 Mar 20 10:07 .
drwxr-xr-x   1 root root   6 Mar 20 10:07 ..
-rwxr-xr-x   1 root root   0 Mar 20 10:07 .dockerenv
lrwxrwxrwx   1 root root   7 Nov  3 15:22 bin -> usr/bin
drwxr-xr-x   5 root root 340 Mar 20 10:07 dev

ARG和ENV指令

  • 設定環境變數
dockerfile指令碼,shell指令碼

ENV NAME="cdan"
ENV AGE=28
ENV MYSQL_VERSION=5.6

後續所有的操作,通過$NAME就可以直接獲取變數值使用了,維護dockerfile更加方便

ARG和ENV一樣,都是設定環境變數
ENV無論是在映象構建時,還是容器執行,該變數都可以使用
ARG只是用於構建映象需要設定的變數,容器執行時就消失了

VOLUME

  • 容器在執行時,應該保證在儲存層不寫入任何資料,執行在容器內產生的資料,我們推薦是掛載,寫入到宿主機上,進行維護。
VOLUME /data   #== mount /mnt 
# 將容器內的/data資料夾,在容器執行時,該目錄自動掛載為匿名卷,任何向該目錄中寫入資料的操作,都不會被容器記錄,保證的容器儲存無狀態理念。

# Dockerfile
[root@docker01 ~]# cd /docker/
[root@docker01 docker]# vim Dockerfile 
FROM centos
MAINTAINER cdan
VOLUME ["/data1","/data2"]

# 該容器執行的時候,這兩個目錄自動和宿主機的目錄做好對映關係
docker build .

# 執行該映象
docker run 86b4dceba89a

# 檢視生成的容器資訊
[root@docker01 ~]# docker ps -a | head -2
CONTAINER ID   IMAGE             COMMAND                  CREATED         STATUS                     PORTS     NAMES
84014622b3a4   86b4dceba89a      "/bin/bash"              2 minutes ago   Exited (0) 2 minutes ago             sharp_noether

# dokcer inspect命令檢視
[root@docker01 docker]# docker inspect 86b4dceba89a
            "Volumes": {
                "/data1": {},
                "/data2": {}
            },

1. 容器資料掛載的方式,通過dockerfile,指定VOLUME目錄
2. 通過docker run -v引數,直接設定需要對映掛載的目錄

4.通過Dockerfile生成映象

#1.建立一個Dockerfile檔案,名字必須是Dockerfile(檔案中的內容指令大寫)
[root@docker ~]# cd /home
[root@docker home]# vim dockerfile
FROM centos
VOLUME ["volume01","volume02" ]   #匿名掛載
CMD echo "-----end-----"
CMD /bin/bash              
[root@docker home]# docker build -f dockerfile -t test/centos:v1 .   #構建映象
Sending build context to Docker daemon  190.8MB
Step 1/4 : FROM centos
 ---> 300e315adb2f
Step 2/4 : VOLUME ["volume01","volume02"]
 ---> Running in f0c041664f2f
Removing intermediate container f0c041664f2f
 ---> 736d765bc692
Step 3/4 : CMD echo "-----end-----"
 ---> Running in 718ddf9ab2fd
Removing intermediate container 718ddf9ab2fd
 ---> d7a675f0e939
Step 4/4 : CMD /bin/bash
 ---> Running in 585894ec73cd
Removing intermediate container 585894ec73cd
 ---> 3850e269b94a
Successfully built 3850e269b94a
Successfully tagged test/centos:v1
[root@docker home]# docker images  #檢視構建映象
REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
test/centos   v1        3850e269b94a   51 seconds ago   209MB
#2.啟動自己生成的容器
[root@docker home]# docker run -it 3850e269b94a /bin/bash
[root@383339684d3c /]# 
[root@383339684d3c /]# ls -l   #檢視目錄
total 0
lrwxrwxrwx   1 root root   7 Nov  3 15:22 bin -> usr/bin
drwxr-xr-x   5 root root 360 Mar 20 07:09 dev
drwxr-xr-x   1 root root  66 Mar 20 07:09 etc
drwxr-xr-x   2 root root   6 Nov  3 15:22 home
lrwxrwxrwx   1 root root   7 Nov  3 15:22 lib -> usr/lib
lrwxrwxrwx   1 root root   9 Nov  3 15:22 lib64 -> usr/lib64
drwx------   2 root root   6 Dec  4 17:37 lost+found
drwxr-xr-x   2 root root   6 Nov  3 15:22 media
drwxr-xr-x   2 root root   6 Nov  3 15:22 mnt
drwxr-xr-x   2 root root   6 Nov  3 15:22 opt
dr-xr-xr-x 113 root root   0 Mar 20 07:09 proc
dr-xr-x---   2 root root 162 Dec  4 17:37 root
drwxr-xr-x  11 root root 163 Dec  4 17:37 run
lrwxrwxrwx   1 root root   8 Nov  3 15:22 sbin -> usr/sbin
drwxr-xr-x   2 root root   6 Nov  3 15:22 srv
dr-xr-xr-x  13 root root   0 Mar 20 07:09 sys
drwxrwxrwt   7 root root 145 Dec  4 17:37 tmp
drwxr-xr-x  12 root root 144 Dec  4 17:37 usr
drwxr-xr-x  20 root root 262 Dec  4 17:37 var
drwxr-xr-x   2 root root   6 Mar 20 07:09 volume01  #自己掛載的目錄(生成映象自動掛載的資料卷目錄)
drwxr-xr-x   2 root root   6 Mar 20 07:09 volume02  #自己掛載的目錄(生成映象自動掛載的資料卷目錄)
注:這個卷一定和外部有一個同步目錄
#3.在容器內掛載目錄下建立測試檔案
[root@383339684d3c /]# cd volume01
[root@383339684d3c volume01]# touch 1.txt
[root@383339684d3c volume01]# ls
1.txt
#4.檢視容器的具體資訊
[root@docker ~]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS       
383339684d3c   3850e269b94a   "/bin/bash"              4 minutes ago   Up 4 minutes
[root@docker ~]# docker inspect 383339684d3c
   "Mounts": [
            {
                "Type": "volume",
                "Name": "34bbc194a4ba7b7cdc424ba768f89d6437f6be9004ef91e89a205288cfa
                "Source": "/var/lib/docker/volumes/34bbc194a4ba7b7cdc424ba768f89d643 #對應容器外目錄路徑
                "Destination": "volume01",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            },
            {
                "Type": "volume",
                "Name": "b4f2a3ca38131f0bc8fe55398a9759266f171e02fd8f3ad7813a6889712
                "Source": "/var/lib/docker/volumes/b4f2a3ca38131f0bc8fe55398a9759266  #對應容器外目錄路徑
                "Destination": "volume02",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
#5.去容器外看一下建立的測試檔案是否同步
[root@docker ~]# cd /var/lib/docker/volumes/34bbc194a4ba7b7cdc424ba768f89d6437f6be9004ef91e89a205288cfa3aeba/_data
[root@docker _data]# ls
1.txt

5.實戰測試(構建自己的centos)

#1.編寫dockerfile檔案
mkdir Dockerfile
[root@docker dockerfile]# vim Dockerfile
FROM centos
MAINTAINER dan<[email protected]>

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum install -y vim 
RUN yum install -y net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "----end----"
CMD /bin/bash

#2.通過檔案構建映象
[root@docker dockerfile]# docker build -f Dockerfile -t mycentos:v1 .
Sending build context to Docker daemon  2.048kB 
Step 1/10 : FROM centos
 ---> 300e315adb2f
Step 2/10 : MAINTAINER fxs<[email protected]>
 ---> Running in e52e12575926
Removing intermediate container e52e12575926
 ---> 4e870718528a
Step 3/10 : ENV MYPATH /usr/local
 ---> Running in d82fa4ed482b
Removing intermediate container d82fa4ed482b
 ---> c82eb3e4a162
Step 4/10 : WORKDIR $MYPATH
 ---> Running in 6f0249f46ab3
Removing intermediate container 6f0249f46ab3
 ---> 109dee8d18e9
Step 5/10 : RUN yum install -y vim
 ---> Running in 5560189ef2bf
CentOS Linux 8 - AppStream                      1.2 MB/s | 6.3 MB     00:05    
CentOS Linux 8 - BaseOS                         935 kB/s | 2.3 MB     00:02    
CentOS Linux 8 - Extras                         7.6 kB/s | 9.2 kB     00:01

#3.檢視自己建立的映象
[root@docker dockerfile]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
mycentos      v1        3f33768da126   2 minutes ago   291MB

#4.執行自己構建的映象
[root@docker dockerfile]# docker run -it mycentos:v1
[root@f9e4e57fdbeb local]# pwd   #自動進入工作目錄
/usr/local
[root@f9e4e57fdbeb local]# ifconfig   #自己增加的命令可以使用
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 8  bytes 648 (648.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0