Dokcer使用DokcerFile定制鏡像
定制docker鏡像的方式有兩種:
- 手動修改容器內(nèi)容喧伞,導(dǎo)出新的鏡像西饵。
- 基于dockerfile自行編寫指令插掂,基于指令流程創(chuàng)建鏡像问潭。
Dockerfile簡介
鏡像是多層存儲找蜜,每一層都是在前一層的基礎(chǔ)上進(jìn)行修改饼暑;
容器也是多層存儲,以鏡像為基礎(chǔ)層洗做,在其基礎(chǔ)上加一層作為容器運(yùn)行時的存儲層弓叛。
剛才說了,創(chuàng)建鏡像的兩個方法:
手動修改容器內(nèi)容诚纸,然后dokcer commit提交容器為新的鏡像
通過在dockerfile中定義一系列的命令和參數(shù)構(gòu)建成的腳本撰筷,然后這些命令應(yīng)用于基礎(chǔ)鏡像,依次添加層畦徘,最終生成一個新的鏡像毕籽。極大的簡化了部署工作。
Dockerfile主要組成部分
基礎(chǔ)鏡像信息 FROM centos:7.9
制作鏡像操作指令 RUN yum install -y nginx
容器啟動時執(zhí)行指令 CMD ["/bin/bash"]
宿主機(jī)直接部署軟件流程與Dockerfile部署軟件流程對比
需求 : 安裝一個mysql旧烧,并啟動影钉。
虛擬機(jī)部署形式:
1. 開啟vmware
2. 運(yùn)行某一個虛擬即,centos7
3. centos7安裝mysql yum install mysql-server
4. 通過腳本或者命令掘剪,啟動mysql即可
部署緩慢平委,且修改了宿主機(jī)的環(huán)境,刪除較為麻煩夺谁,占用宿主機(jī)的一個3306端口
容器的部署形式:
1. 開始vmware
2. 運(yùn)行虛擬機(jī)centos7(宿主機(jī))
3. 安裝docker容器軟件
4. 獲取mysql鏡像即可廉赔,docker pull mysql:tag(你無法自由控制,該mysql的基礎(chǔ)鏡像時什么發(fā)行版本匾鸥,你獲取的鏡像蜡塌,是別人定制好的,你下載使用的默認(rèn)時Debian發(fā)行版勿负,你希望得到一個基于centos7.9的發(fā)行版本馏艾,運(yùn)行mysql)
5. 直接運(yùn)行該鏡像,通過端口映射,運(yùn)行mysql
6. 訪問宿主機(jī)對的一個映射端口琅摩,訪問到容器內(nèi)的mysql
想自定義鏡像铁孵,就得自己寫腳本,也就是dockerfile了
Dokcerfile指令
FROM 指定基礎(chǔ)鏡像
MAINTAINER 指定維護(hù)者信息,可以沒有
RUN 你想讓它干啥(在命令前面加上RUN即可)
ADD 添加宿主機(jī)的文件到容器內(nèi),還多了一個自動解壓的功能
# RUN tar -Zxf /opt/xx.tgz # 報(bào)錯!該tgz文件不存在! !
COPY 作用和ADD是一樣的,都是拷貝宿主機(jī)的文件到容器內(nèi), COPY就是僅僅拷貝
WORKDIR 相當(dāng)于cd命令,設(shè)置當(dāng)前工作目錄
VOLUME 設(shè)置目錄映射,掛載主機(jī)目錄
EXPOSE 指定對外的端口,在容器內(nèi)暴露一個端口,端口 EXPORT 80
CMD 指定容器啟動后的要干的事情
ENTRYPOINT 作用和CMD一樣房资,都是在指定容器啟動程序以及參數(shù)蜕劝。
# 當(dāng)指定了ENTRYPOINT之后,CMD指令的語義就有了變化轰异,而是把CMD的內(nèi)容當(dāng)作參數(shù)傳遞給ENTRYPOINT指令岖沛。
ARG 設(shè)置環(huán)境變量
# ARG只是用于構(gòu)建鏡像需要設(shè)置的變量,容器運(yùn)行時就消失了
ENV 和ARG一樣搭独,都是設(shè)置環(huán)境變量
# 區(qū)別在于ENV無論是在鏡像構(gòu)建時婴削,還是容器運(yùn)行,該變量都可以使用
USER 用于改變環(huán)境戳稽,用于切換用戶
ONBUILD 用于設(shè)置鏡像觸發(fā)器
Dokcerfile實(shí)踐
需求:通過dockerfile馆蠕,構(gòu)建nginx鏡像,且運(yùn)行容器后惊奇,生成的頁面是"Docker mhg"互躬。
1. 創(chuàng)建Dockerfile,注意文件名,必須是這個
mkdir /root/learn_docker
cd /root/learn_docker
vim Dockerfile
FROM nginx
RUN echo "<meta charset=utf-8>Docker mhg" > /usr/share/nginx/html/index.html
2. 構(gòu)建Dockerfile
docker build .
3. 修改鏡像名字
docker images
[root@qzcsbj-harbor learn_docker]# docker tag 531f41ec3c5a my_nginx
4. 運(yùn)行該鏡像
docker run -d -p 9080:80 my_nginx
5. 查看宿主機(jī)的9080端口
http://192.168.117.160:9080/
Dokcerfile相關(guān)指令用法
COPY
copy指令從宿主機(jī)復(fù)制文件或者目錄到新的一層鏡像內(nèi)
如:
copy nana.py /opt
支持多個文件,以及通配符形式的復(fù)制颂郎,語法要滿足Golang的filepath.Match
copy na* /tmp/cc?.txt /opt
COPY指令能夠保留源文件的元數(shù)據(jù)吼渡,訪問時間等等,這點(diǎn)很重要
ADD
特性和COPY基本一致乓序,不過多了些功能
1. 源文件是一個URL寺酪,此時dockcer引擎會下載該鏈接,放入目標(biāo)路徑替劈,且權(quán)限自動設(shè)為600寄雀。若這不是期望結(jié)果,還得增加一層RUN指令進(jìn)行調(diào)整
# ADD nana.tgz /home
# RUN xxx修改命令
2. 源文件是一個URL陨献,且是一個壓縮包盒犹,不會自動解壓,也得單獨(dú)用RUN指令解壓
3. 源文件是一個壓縮文件眨业,且是gzip急膀,bzip,xz龄捡,tar情況卓嫂,ADD指令會自動解壓壓縮該文件到?jīng)]有文件
CMD
用法,注意是雙引號
# CMD在容器內(nèi)運(yùn)行某個命令,啟動程序
# 該鏡像在運(yùn)行容器實(shí)例的時候,執(zhí)行的具體參數(shù)是什么
CMD["參數(shù)1","參數(shù)2"]
在指定了entrypoint指令后,用CMD指定具體的參數(shù)
dokcer不是虛擬機(jī)聘殖,容器就是一個進(jìn)程晨雳,既然是進(jìn)程行瑞,那么程序在啟動的時候需要指定些運(yùn)行參數(shù),這就是CMD指令作用
例如centos鏡像默認(rèn)的CMD是/bin/bash悍募,直接docker run -it centos會直接進(jìn)入bash解釋器蘑辑。
也可以啟動容器時候洋机,指定參數(shù): docker run -it centos cat /etc/os-release
CMD ["/bin/bash"]
# 該容器運(yùn)行時坠宴,執(zhí)行的命令
# 等同于命令行的直接操作:docker run -it centos cat /etc/os-release
CMD ["cat","/etc/os-release"]
容器內(nèi)運(yùn)行程序
這里要注意的是,docker不是虛擬機(jī)的概念绷旗,虛擬機(jī)的程序運(yùn)行喜鼓,基本上都是在后臺運(yùn)行,利用systemctl運(yùn)行衔肢,但是容器內(nèi)沒有后臺進(jìn)程的概念庄岖,必須在前臺運(yùn)行。
容器就是為了主進(jìn)程而存在的角骤,主進(jìn)程如果退出了隅忿,容器也就失去意義,自動退出邦尊。
例如一個經(jīng)典的問題:
# 這樣的寫法是錯誤的背桐,容器會立即退出
CMD systemctl start nginx
因?yàn)閟ystemctl start nginx是以守護(hù)進(jìn)程(默認(rèn)在后臺運(yùn)行)的形式啟動nginx,且CMD命令會轉(zhuǎn)化為
CMD ["sh","-c","systemctl start nginx" ]
這樣的命令主進(jìn)程是sh解釋器,執(zhí)行完畢后立即結(jié)束了,因此容器也就退出了蝉揍。
# 相當(dāng)于nginx -g daemon off
因此正確的做法應(yīng)該是 CMD ["nginx","-g","daemon off;"]
把宿主機(jī)安裝链峭,啟動nginx的理念放入到dockerfile中
1. RUN yum install nginx
2. RUN 配置文件修改 sed
# RUN systemctl start nginx 容器內(nèi)的程序必須在前臺運(yùn)行,容器時啟動不了的
3. 正確的寫法應(yīng)該時CMD ["nginx","-g","daemon off;"]
ENTRYPOINT
dokcer面試題:
ENTRYPOINT和CMD的區(qū)別以及用法! ! !
CMD:指定這個容器啟動的時候要運(yùn)行的命令又沾,只有最后一個會生效弊仪,可被替代
ENTRYPOINT:指定這個容器啟動的時候要運(yùn)行的命令,可以追加命令
ENTRYPOINT作用和CMD一樣杖刷,都是在指定容器啟動程序以及參數(shù)励饵。
當(dāng)指定了ENTRYPOINT之后,CMD指令的語義就有了變化滑燃,而是把CMD的內(nèi)容當(dāng)作參數(shù)傳遞給ENTRYPOINT指令役听。
ENTRYPOINT和CMD的實(shí)際用法
實(shí)際用法:
1. 準(zhǔn)備一個Dokcerfile
[root@qzcsbj-harbor ~]# cd /learn_docker/
[root@qzcsbj-harbor learn_docker]# > Dockerfile
[root@qzcsbj-harbor learn_docker]# vim Dockerfile
FROM centos:7.8.2003
RUN rpm --rebuilddb && yum install epel-release -y
RUN rpm --rebuilddb && yum install curl -y
CMD ["curl","-s","ip.sb"]
# 用法如下
dokcer run my_centos curl -s ip.sb # curl -s ip.sb獲取本機(jī)的公網(wǎng)ip地址
2. 構(gòu)建鏡像
[root@qzcsbj-harbor learn_docker]# docker build .
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos:7.8.2003
---> afb6fca791e0
Step 2/4 : RUN rpm --rebuilddb && yum install epel-release -y
---> Using cache
---> 81b4e83fb0a5
Step 3/4 : RUN rpm --rebuilddb && yum install curl -y
---> Using cache
---> bd0074c78b6c
Step 4/4 : CMD ["curl","-s","ip.sb"]
---> Running in 295418f71093
Removing intermediate container 295418f71093
---> c920b743282a
Successfully built c920b743282a
3. 查看結(jié)果(出現(xiàn)Successfully代表鏡像構(gòu)建完成)
Step 4/4 : CMD ["curl","-s","ip.sb"]
---> Running in 295418f71093
Removing intermediate container 295418f71093
---> c920b743282a
Successfully built c920b743282a
4. 檢查鏡像
[root@qzcsbj-harbor learn_docker]# docker tag c920b743282a centos_curl
[root@qzcsbj-harbor learn_docker]# docker images | grep curl
centos_curl latest c920b743282a 3 minutes ago 471MB
5. 運(yùn)行鏡像,生成容器記錄,沒有前臺運(yùn)行,因此立即掛了
[root@qzcsbj-harbor learn_docker]# docker run centos_curl
139.227.102.189
6. 上述運(yùn)行正確,但是我想再傳入一個參數(shù),該怎么辦
# 發(fā)現(xiàn)是無法直接傳入?yún)?shù)的不瓶,該形式是覆蓋鏡像中的cmd
# 就好比把docker鏡像禾嫉,當(dāng)作一個環(huán)境,去執(zhí)行后面的命令
[root@qzcsbj-harbor learn_docker]# docker run centos_curl pwd
/
[root@qzcsbj-harbor learn_docker]#
[root@qzcsbj-harbor learn_docker]# docker run centos_curl -I
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-I": executable file not found in $PATH: unknown.
7. 想要正確的給容器傳入一個參數(shù)該怎么辦
希望容器內(nèi)能夠正確完整的運(yùn)作該命令的執(zhí)行結(jié)果
[root@qzcsbj-harbor learn_docker]# curl -s ip.sb -I # 獲取http報(bào)頭信息
HTTP/1.1 200 OK
Date: Wed, 28 Jul 2021 15:16:18 GMT
...
8. 解決辦法
方式一:給容器傳入新的完整的命令,讓后面的命令覆蓋鏡像中的cmd
# 這是投機(jī)取巧的辦法,不合適
[root@qzcsbj-harbor learn_docker]# docker run centos_curl curl -s ip.sb -I
HTTP/1.1 200 OK
Date: Wed, 28 Jul 2021 15:18:05 GMT
Content-Type: text/plain
9. 正確的解決辦法
[root@qzcsbj-harbor learn_docker]# vim Dockerfile
FROM centos:7.8.2003
RUN rpm --rebuilddb && yum install epel-release -y
RUN rpm --rebuilddb && yum install curl -y
ENTRYPOINT ["curl","-s","ip.sb"]
10. 重新構(gòu)建鏡像
# 重新構(gòu)建鏡像速度特別快,并且我們發(fā)現(xiàn)鏡像的前三個Step的IMAGE ID是一致的,說明前三個的IMAGE ID是直接從緩存中拿的蚊丐。
# 只有Step 4/4的IMAGE ID發(fā)生了變化(Dockerfile文件的第四步是更改過的熙参,是重新構(gòu)建的鏡像層),因此更加驗(yàn)證了我們之前所提到的鏡像是分層構(gòu)建的。
[root@qzcsbj-harbor learn_docker]# docker build .
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos:7.8.2003
---> afb6fca791e0
Step 2/4 : RUN rpm --rebuilddb && yum install epel-release -y
---> Using cache
---> 81b4e83fb0a5
Step 3/4 : RUN rpm --rebuilddb && yum install curl -y
---> Using cache
---> bd0074c78b6c
Step 4/4 : ENTRYPOINT ["curl","-s","ip.sb"]
---> Running in df106e04d533
Removing intermediate container df106e04d533
---> e9479067148c
Successfully built e9479067148c
11. 重新運(yùn)行該鏡像麦备,看結(jié)果孽椰,以及傳入新的參數(shù)
[root@qzcsbj-harbor learn_docker]# docker tag e9479067148c centos_curl_new
# 此時發(fā)現(xiàn)昭娩,傳入的CMD指令,當(dāng)作了ENTRYPOINT的參數(shù)
# 其實(shí)容器內(nèi)黍匾,執(zhí)行的完命令是: curl -s ip.sb -I
[root@qzcsbj-harbor learn_docker]# docker run centos_curl_new -I
HTTP/1.1 200 OK
Date: Wed, 28 Jul 2021 15:24:58 GMT
...
ARG和ENV指令
設(shè)置環(huán)境變量
dockerfile腳本栏渺,shell腳本
ENV NAME="nana"
ENV AGE=18
ENV MYSQL_VERSION=5.6
后續(xù)所有的操作,通過$NAMME就可以直接獲取變量值使用了锐涯,維護(hù)dockerfile更加方便
ARG和ENV一樣磕诊,都是設(shè)置環(huán)境變量
ENV無論是在鏡像構(gòu)建時,還是容器運(yùn)行纹腌,該變量都可以使用
ARG只是用于構(gòu)建鏡像需要設(shè)置的變量霎终,容器運(yùn)行時就消失了
VOLUME
容器在運(yùn)行時,應(yīng)該保證在存儲層不寫入任何數(shù)據(jù)升薯,運(yùn)行在容器內(nèi)產(chǎn)生的數(shù)據(jù)莱褒,我們推薦是掛載,寫入到宿主機(jī)上涎劈,進(jìn)行維護(hù)广凸。
# mount /mnt
VOLUME /data
# 將容器內(nèi)的/data文件夾,在容器運(yùn)行時蛛枚,該目錄自動掛載為匿名卷谅海,任何向該目錄中寫入數(shù)據(jù)的操作,都不會被容器記錄坤候,保證的容器存儲無狀態(tài)理念胁赢。
# Dockerfile
[root@qzcsbj-harbor ~]# cd /learn_docker/
[root@qzcsbj-harbor learn_docker]# > Dockerfile
[root@qzcsbj-harbor learn_docker]# vim Dockerfile
FROM centos
MAINTAINER nana
VOLUME ["/data1","/data2"]
# 該容器運(yùn)行的時候,這兩個目錄自動和宿主機(jī)的目錄做好映射關(guān)系
docker build .
# 運(yùn)行該鏡像
docker run 86b4dceba89a
# 查看生成的容器信息
[root@qzcsbj-harbor nana]# 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@qzcsbj-harbor learn_docker]# docker inspect 86b4dceba89a
"Volumes": {
"/data1": {},
"/data2": {}
},
1. 容器數(shù)據(jù)掛載的方式白筹,通過dockerfile智末,指定VOLUME目錄
2. 通過docker run -v參數(shù),直接設(shè)置需要映射掛載的目錄
EXPOSE
指定容器運(yùn)行時對外提供的端口服務(wù)徒河。
幫助使用該鏡像的人系馆,快速理解該容器的一個端口業(yè)務(wù)
docker port 容器
dokcer run -p 宿主機(jī)端口:容器端口
docker run -P # 作用是隨機(jī) 宿主機(jī)端口:容器內(nèi)端口
WORKDIR
用于在dockerfile中,目錄的切換顽照,更改工作目錄
WORKDIR /opt
USER
用于改變環(huán)境由蘑,用于切換用戶
USER root
USER nana
ONBUILD
用于設(shè)置鏡像觸發(fā)器,從當(dāng)前鏡像創(chuàng)建子鏡像代兵,會觸發(fā)ONBUILD的執(zhí)行
注意:ONBUILD指令不會繼承
# 創(chuàng)建一個Dockerfile,寫入觸發(fā)器
[root@qzcsbj-harbor ~]# mdkir /docker
[root@qzcsbj-harbor ~]# vim /docker/Dockerfile
FROM centos:7
RUN yum -y install curl
ENTRYPOINT ["curl","-s","https://www.cip.cc/"]
ONBUILD RUN echo "==images onbuild=="
# 構(gòu)建鏡像(觸發(fā)器并沒有執(zhí)行)
[root@qzcsbj-harbor ~]# cd /docker/
[root@qzcsbj-harbor docker]# docker build . -t "nana_ip"
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos:7
7: Pulling from library/centos
2d473b07cdd5: Pull complete
Digest: sha256:0f4ec88e21daf75124b8a9e5ca03c37a5e937e0e108a255d890492430789b60e
Status: Downloaded newer image for centos:7
---> 8652b9f0cb4c
...
我們基于構(gòu)建完成的鏡像(nana_ip),創(chuàng)建一個新的Dockerfile
[root@qzcsbj-harbor docker]# cd
[root@qzcsbj-harbor ~]# vim Dockerfile
FROM nana_ip
RUN yum -y install curl
ENTRYPOINT ["curl","-s","https://www.cip.cc/"]
# 構(gòu)建子鏡像,觸發(fā)器執(zhí)行成功
[root@qzcsbj-harbor ~]# docker build . -t "nana_ip02"
Sending build context to Docker daemon 17.92kB
Step 1/3 : FROM nana_ip
# Executing 1 build trigger
---> Running in 70833b9adb69
==images onbuild==
Removing intermediate container 70833b9adb69
---> fce1318ec153
...