DokcerFile 映象定製
更多精彩內容請關注微信公眾號:新猿技術生態圈
定製docker映象的方式有兩種:
手動修改容器內容,匯出新的映象。
基於dockerfile自行編寫指令,基於指令流程建立映象。
Dockerfile簡介
映象是多層儲存,每一層都是在前一層的基礎上進行修改;
容器也是多層儲存,以映象為基礎層,在其基礎上加一層作為容器執行時的儲存層。
剛才說了,建立映象的兩個方法:
手動修改容器內容,然後dokcer commit提交容器為新的映象
通過在dockerfile中定義一系列的命令和引數構建成的指令碼,然後這些命令應用於基礎映象,依次新增層,最終生成一個新的映象。極大的簡化了部署工作。
Dockerfile主要組成部分
基礎映象資訊 FROM centos:7.9 製作映象操作指令 RUN yum install -y nginx 容器啟動時執行指令 CMD ["/bin/bash"]
宿主機直接部署軟體流程與Dockerfile部署軟體流程對比
需求 : 安裝一個mysql,並啟動。
虛擬機器部署形式:
1. 開啟vmware 2. 執行某一個虛擬即,centos7 3. centos7安裝mysql yum install mysql-server 4. 通過指令碼或者命令,啟動mysql即可 部署緩慢,且修改了宿主機的環境,刪除較為麻煩,佔用宿主機的一個3306埠
容器的部署形式:
1. 開始vmware 2. 執行虛擬機器centos7(宿主機) 3. 安裝docker容器軟體 4. 獲取mysql映象即可,docker pull mysql:tag(你無法自由控制,該mysql的基礎映象時什麼發行版本,你獲取的映象,是別人定製好的,你下載使用的預設時Debian發行版,你希望得到一個基於centos7.9的發行版本,執行mysql) 5. 直接執行該映象,通過埠對映,執行mysql 6. 訪問宿主機對的一個對映埠,訪問到容器內的mysql
想自定義映象,就得自己寫指令碼,也就是dockerfile了
Dokcerfile指令
FROM 指定基礎映象
MAINTAINER 指定維護者資訊,可以沒有
RUN 你想讓它幹啥(在命令前面加上RUN即可)
ADD 新增宿主機的檔案到容器內,還多了一個自動解壓的功能
# RUN tar -Zxf /opt/xx.tgz # 報錯!該tgz檔案不存在! !
COPY 作用和ADD是一樣的,都是拷貝宿主機的檔案到容器內, COPY就是僅僅拷貝
WORKDIR 相當於cd命令,設定當前工作目錄
VOLUME 設定目錄對映,掛載主機目錄
EXPOSE 指定對外的埠,在容器內暴露一個埠,埠 EXPORT 80
CMD 指定容器啟動後的要乾的事情
ENTRYPOINT 作用和CMD一樣,都是在指定容器啟動程式以及引數。
# 當指定了ENTRYPOINT之後,CMD指令的語義就有了變化,而是把CMD的內容當作引數傳遞給ENTRYPOINT指令。
ARG 設定環境變數
# ARG只是用於構建映象需要設定的變數,容器執行時就消失了
ENV 和ARG一樣,都是設定環境變數
# 區別在於ENV無論是在映象構建時,還是容器執行,該變數都可以使用
USER 用於改變環境,用於切換使用者
Dokcerfile實踐
需求:通過dockerfile,構建nginx映象,且執行容器後,生成的頁面是"辣辣小姐姐"。
1. 建立Dockerfile,注意檔名,必須是這個
[root@docker01 ~]# mkdir /learn_docker
[root@docker01 ~]# cd /learn_docker/
[root@docker01 learn_docker]# vim Dockerfile
FROM nginx
RUN echo "<meta charset=utf-8>辣辣小姐姐" > /usr/share/nginx/html/index.html
2. 構建Dockerfile
[root@docker01 learn_docker]# docker build .
3. 修改映象名字
[root@docker01 learn_docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 950549357c1f 18 seconds ago 133MB
nginx latest 08b152afcfae 6 days ago 133MB
[root@docker01 learn_docker]# docker tag 950549357c1f my_nginx
4. 執行該映象
docker run -d -p 80:80 my_nginx
5. 檢視宿主機的80埠
http://192.168.15.80/
# 辣辣小姐姐
更多精彩內容請關注微信公眾號:新猿技術生態圈
Dokcerfile相關指令用法
COPY
copy指令從宿主機複製檔案或者目錄到新的一層映象內
如:
copy nana.py /opt
支援多個檔案,以及萬用字元形式的複製,語法要滿足Golang的filepath.Match
copy na* /tmp/cc?.txt /opt
COPY指令能夠保留原始檔的後設資料,訪問時間等等,這點很重要
ADD
特性和COPY基本一致,不過多了些功能
1. 原始檔是一個URL,此時dockcer引擎會下載該連結,放入目標路徑,且許可權自動設為600。若這不是期望結果,還得增加一層RUN指令進行調整
# ADD nana.tgz /home
# RUN xxx修改命令
2. 原始檔是一個URL,且是一個壓縮包,不會自動解壓,也得單獨用RUN指令解壓
3. 原始檔是一個壓縮檔案,且是gzip,bzip,xz,tar情況,ADD指令會自動解壓壓縮該檔案到沒有檔案
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;"]
把宿主機安裝,啟動nginx的理念放入到dockerfile中
1. RUN yum install nginx
2. RUN 配置檔案修改 sed
# RUN systemctl start nginx 容器內的程式必須在前臺執行,容器時啟動不了的
3. 正確的寫法應該時CMD ["nginx","-g","daemon off;"]
ENTRYPOINT
dokcer面試題:
ENTRYPOINT和CMD的區別以及用法! ! !ENTRYPOINT作用和CMD一樣,都是在指定容器啟動程式以及引數。 當指定了ENTRYPOINT之後,CMD指令的語義就有了變化,而是把CMD的內容當作引數傳遞給ENTRYPOINT指令。
ENTRYPOINT和CMD的實際用法
實際用法:
1. 準備一個Dokcerfile
[root@docker01 ~]# cd /learn_docker/
[root@docker01 learn_docker]# > Dockerfile
[root@docker01 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獲取本機的公網ip地址
2. 構建映象
[root@docker01 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. 檢視結果(出現Successfully代表映象構建完成)
Step 4/4 : CMD ["curl","-s","ip.sb"]
---> Running in 295418f71093
Removing intermediate container 295418f71093
---> c920b743282a
Successfully built c920b743282a
4. 檢查映象
[root@docker01 learn_docker]# docker tag c920b743282a centos_curl
[root@docker01 learn_docker]# docker images | grep curl
centos_curl latest c920b743282a 3 minutes ago 471MB
5. 執行映象,生成容器記錄,沒有前臺執行,因此立即掛了
[root@docker01 learn_docker]# docker run centos_curl
139.227.102.189
6. 上述執行正確,但是我想再傳入一個引數,該怎麼辦
# 發現是無法直接傳入引數的,該形式是覆蓋映象中的cmd
# 就好比把docker映象,當作一個環境,去執行後面的命令
[root@docker01 learn_docker]# docker run centos_curl pwd
/
[root@docker01 learn_docker]#
[root@docker01 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. 想要正確的給容器傳入一個引數該怎麼辦
希望容器內能夠正確完整的運作該命令的執行結果
[root@docker01 learn_docker]# curl -s ip.sb -I # 獲取http報頭資訊
HTTP/1.1 200 OK
Date: Wed, 28 Jul 2021 15:16:18 GMT
...
8. 解決辦法
方式一:給容器傳入新的完整的命令,讓後面的命令覆蓋映象中的cmd
# 這是投機取巧的辦法,不合適
[root@docker01 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@docker01 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. 重新構建映象
# 重新構建映象速度特別快,並且我們發現映象的前三個Step的IMAGE ID是一致的,說明前三個的IMAGE ID是直接從快取中拿的。
# 只有Step 4/4的IMAGE ID發生了變化(Dockerfile檔案的第四步是更改過的,是重新構建的映象層),因此更加驗證了我們之前所提到的映象是分層構建的。
[root@docker01 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. 重新執行該映象,看結果,以及傳入新的引數
[root@docker01 learn_docker]# docker tag e9479067148c centos_curl_new
# 此時發現,傳入的CMD指令,當作了ENTRYPOINT的引數
# 其實容器內,執行的完命令是: curl -s ip.sb -I
[root@docker01 learn_docker]# docker run centos_curl_new -I
HTTP/1.1 200 OK
Date: Wed, 28 Jul 2021 15:24:58 GMT
...
ARG和ENV指令
設定環境變數
dockerfile指令碼,shell指令碼
ENV NAME="nana"
ENV AGE=18
ENV MYSQL_VERSION=5.6
後續所有的操作,通過$NAMME就可以直接獲取變數值使用了,維護dockerfile更加方便
ARG和ENV一樣,都是設定環境變數
ENV無論是在映象構建時,還是容器執行,該變數都可以使用
ARG只是用於構建映象需要設定的變數,容器執行時就消失了
VOLUME
容器在執行時,應該保證在儲存層不寫入任何資料,執行在容器內產生的資料,我們推薦是掛載,寫入到宿主機上,進行維護。
# mount /mnt
VOLUME /data
# 將容器內的/data資料夾,在容器執行時,該目錄自動掛載為匿名卷,任何向該目錄中寫入資料的操作,都不會被容器記錄,保證的容器儲存無狀態理念。
# Dockerfile
[root@docker01 ~]# cd /learn_docker/
[root@docker01 learn_docker]# > Dockerfile
[root@docker01 learn_docker]# vim Dockerfile
FROM centos
MAINTAINER nana
VOLUME ["/data1","/data2"]
# 該容器執行的時候,這兩個目錄自動和宿主機的目錄做好對映關係
docker build .
# 執行該映象
docker run 86b4dceba89a
# 檢視生成的容器資訊
[root@docker01 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@docker01 learn_docker]# docker inspect 86b4dceba89a
"Volumes": {
"/data1": {},
"/data2": {}
},
1. 容器資料掛載的方式,通過dockerfile,指定VOLUME目錄
2. 通過docker run -v引數,直接設定需要對映掛載的目錄
EXPOSE
指定容器執行時對外提供的埠服務。
幫助使用該映象的人,快速理解該容器的一個埠業務
docker port 容器
dokcer run -p 宿主機埠:容器埠
docker run -P # 作用是隨機 宿主機埠:容器內埠
WORKDIR
用於在dockerfile中,目錄的切換,更改工作目錄
WORKDIR /opt
USER
用於改變環境,用於切換使用者
USER root
USER nana
使用Dockerfile構建一個網站映象
傳統方式建立一個網站站點
- nginx,修改首頁內容,html網站就跑起來了。web server,提供web服務,提供代理轉發,提供閘道器,限流等等。。。
- web framework。web框架,一般由開發,通過某個開發語言,基於某個web框架,自己去開發一個web站點,python,django框架。
使用Dockerfile建立一個網站站點
- 用python語言,基於flask web框架,開發一個自己的網站,寫一個後端的網站程式碼
- 開發dockerfile,部署該程式碼,生成映象
- 其他人基於該映象,docker run就可以在電腦跑起來你這個網站
使用docker的優勢
比如安裝一個etcd、naco,都是一些比較複雜的軟體。
需要依賴於go語言環境,比如需要依賴於java環境,在自己的機器安裝好對應的開發環境,以及對應的版本,以及各種依賴。。。
tomcat 依賴於jdk環境 當你有了docker, docker pull tomcat # 這些主流的映象都可以直接找到,並且該映象中,就已經打包好了java環境 docker run tomcat xxx ... # 直接可以訪問tomcat了
1. 在宿主機下,準備一個目錄,準備好dockerfile,程式碼檔案
# 寫一個flask的python程式碼
# 建立程式碼檔案
[root@docker01 ~]# cd /learn_docker/
[root@docker01 ~]# vim nana_flask.py
#coding:utf8
from flask import Flask
app=Flask(__name__)
# @app.route(裝飾器),網站的route,指的是url地址後面的檔案路徑
@app.route("/nana")
def nana():
return "From Docker,nana是隻臭豬豬!!!"
if __name__=="__main__":
app.run(host="0.0.0.0",port=8080)
2. 編寫Dockerfile
[root@docker01 learn_docker]# vim Dockerfile
FROM centos:7.8.2003
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo;
RUN curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo;
RUN yum makecache fast;
RUN yum install python3-devel python3-pip -y
RUN pip3 install -i https://pypi.douban.com/simple flask
COPY nana_flask.py /opt
WORKDIR /opt
EXPOSE 8080
CMD ["python3","nana_flask.py"]
3. 構建映象
# --no-cache不是使用之前舊的快取,重新構建映象
[root@docker01 learn_docker]# docker build --no-cache -t "nana_flask" .
...
Successfully built 9e731f439e41
Successfully tagged nana_flask:latest
4. 檢視構建好的映象
[root@docker01 learn_docker]# docker images | head -2
REPOSITORY TAG IMAGE ID CREATED SIZE
nana_flask latest 9e731f439e41 3 minutes ago 649MB
5. 執行映象,生成容器
[root@docker01 learn_docker]# docker run -d --name nana_flask_web01 -p 90:8080 nana_flask
d9f2f83d16bdd0364473d6e4043c433cbd8e3286e87ecbf93fb3fd5e08ac8002
[root@docker01 learn_docker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d9f2f83d16bd nana_flask "python3 nana_flask.…" 2 minutes ago Up 2 minutes 0.0.0.0:90->8080/tcp, :::90->8080/tcp nana_flask_web01
6. 訪問宿主主機,檢視容器內的flask web網站
瀏覽器輸入: http://192.168.15.80:90/nana
# From Docker,nana是隻臭豬豬!!!
如何修改容器內的網站的內容
方法一:修改宿主機的程式碼,以及dockerfile,重新構建映象
[root@docker01 ~]# vim nana_flask.py
...
def nana():
return "From Docker,nana是隻臭豬豬!!!" # 修改return值,重新生成映象
...
方法二:你可以經入到已經執行的容器內,修改程式碼,重啟容器即可
1. 進入容器內部
[root@docker01 learn_docker]# docker exec -it d9f2f83d16bd bash
[root@d9f2f83d16bd opt]# ls
nana_flask.py
2. 修改容器內的程式碼
[root@d9f2f83d16bd opt]# vi nana_flask.py
#coding:utf8
from flask import Flask
app=Flask(__name__)
# @app.route(裝飾器),網站的route,指的是url地址後面的檔案路徑
@app.route("/nana")
def nana():
return "From Docker,nana是隻臭豬豬!!!ABC!!!"
if __name__=="__main__":
app.run(host="0.0.0.0",port=8080)
3. 退出容器並重啟容器
[root@d9f2f83d16bd opt]# exit
exit
[root@docker01 learn_docker]# docker restart d9f2f83d16bd
d9f2f83d16bd
[root@docker01 learn_docker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d9f2f83d16bd nana_flask "python3 nana_flask.…" 4 minutes ago Up About a minute 0.0.0.0:90->8080/tcp, :::90->8080/tcp nana_flask_web01
4. 訪問宿主主機,檢視容器內的flask web網站
瀏覽器輸入: http://192.168.15.80:90/nana
# From Docker,nana是隻臭豬豬!!!ABC!!!
更多精彩內容請關注微信公眾號:新猿技術生態圈
Docker基礎複習
Docker容器檔案系統
容器是docker的一個核心概念,容器使用一個或者一組應用,他的執行狀態如下:
docker利用容器執行應用程式
容器是映象的執行例項,可以被run、start、stop、rm
每個容器都是互相隔離,保證平臺暗轉
容器可以看作是一個簡易版Linux環境(沒有Linux核心,有root許可權、程式、使用者空間、網路)
映象是隻讀的,容器在啟動的時候建立一層可寫層
dokcerfile面向開發,docker image(映象)作為交付標準,docker container(容器)涉及部署和運維,三者合起來完成docker體系。FROM ubuntu:14.04 選擇基礎映象 ADD run.sh 新增檔案映象,這一層映象只有一個內容,就是這個檔案 VOLUME /data 設定儲存目錄,並未新增檔案,只是更新了映象的json檔案,便於啟動時候讀取該層資訊 CMD ["./run.sh"] 更新json檔案,設定程式入口
docker容器管理總結
# 執行映象,且進入容器內
[root@docker01 ~]# docker run -it ubuntu bash
root@7478064e9fff:/#
# 容器執行web程式
# 注意埠使用,數字大一點,建議8000以後開始使用
# --restart=always容器在後臺掛掉後,預設重啟容器
[root@docker01 ~]# docker run --name my_nginx -d --restart=always -p 8000:80 nginx
79d7fcfdc60f2c40e6d92790be6ad6f3bf9db49fda0e46cadb196be6677b4f73
[root@docker01 ~]# docker ps | head -2
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
79d7fcfdc60f nginx "/docker-entrypoint.…" 40 seconds ago Up 39 seconds 0.0.0.0:8000->80/tcp, :::8000->80/tcp my_nginx
瀏覽器訪問:http://192.168.15.80:8000/ ==> 可以訪問到nginx
# 檢視容器內日誌,實時重新整理
docker logs -f
# 檢視執行時,以及掛掉的容器記錄
docker ps 在執行的容器
dokcer ps -a 掛掉以及活著的容器
# 停止啟動
docker start
docker stop
# 進入容器內
docker exec -it 容器id bash
# 刪除容器
docker rm 容器id
docker rm `docker ps -qa`
# 強制殺死並刪除容器
docker rm -f 容器id
# 檢視容器程式資源資訊
docker top 容器id
# 檢視容器內資源
docker stats 容器id
# 檢視容器具體資訊
docker inspect 容器id
# 獲取容器內的ip地址,容器的格式化引數
docker inspect --format '{{ .NetworkSettings.IPAddress }}' 容器id
dokcer run啟動容器的時候,dokcer後臺操作流程是
- 檢查本地是否有該映象,沒有就下載
- 利用映象建立且啟動一個容器
- 分配容器檔案系統,在只讀的映象層掛載讀寫層
- 宿主機的網橋介面會分配一個虛擬介面到容器中
- 容器獲得地址池的ip地址
- 執行使用者指定的程式
- 若程式裡沒有程式在執行,容器執行完畢後立即終止
更多精彩內容請關注微信公眾號:新猿技術生態圈
更多精彩內容請關注微信公眾號:新猿技術生態圈
更多精彩內容請關注微信公眾號:新猿技術生態圈