生成鏡像的方法:
A . 從container生成
方法1.? # docker commit? <container>? ? ? ? ? ? 這是把container的變更,提交給新image
方法2.? # docker export <container>? >? tarball? ?
? ? ?# cat tarball | docker import - <image>? ? ?同1
B. 從image生成
方法1.? # docker save -o tarball? registry/reposiry/image? ? ? ? ? ? ? ? 這是從registry的db到本地FS文件
? ? modify the tarball
? ? docker load -i tarball? ? ? ? ? ? ? ? ? ? ? ? ? ?這是從本地FS文件裝在鏡像,到本地image的db
C. 從Dockerfile生成
1.? 和A,B比,優點: 可追蹤image的定義,可升級image中軟件版本、幾乎不消耗存儲、通過閱讀Dockerfile代替docker inspect來檢視鏡像/container的內容
2. 命令: docker build -t <image_name>? ?[-f Dockerfile] <構建目錄>? [options]? ??
? ? ? ? 不指定-f選項時,在當前目錄下自動搜索Dockerfile。 指定-f選項時,需要是構建目錄的相對路徑,且位于構建目錄的子目錄內
3. 原理:?
????????docker build命令是傳令官;
? ??????構建目錄(一般是當前目錄 . )下所有內容是build鏡像的素材, 由docker build傳給docker daemon,存在/var/lib/docker下------
? ? ? ? ? ? ? ? 如果要排除一些文件、目錄不傳給docker daemon,就把它們列入構建目錄下的.dockerignore文件
? ? ? ? Dockerfile里每一行是docker daemon執行的指令;
????????docker damon是真正執行build鏡像的工人。
????????這些被執行的命令是在build 鏡像是執行的
? ? ? ? 每執行一個Dockerfile的命令,生成一個中間鏡像,和數據緩存;下次再docker build時,會重用最后一條沒有改變過的指令的中間層容器,來節省時間------
? ? ? ? ? ? ? ? 如果要不留中間層容器:docker build --force-rm=true
????????????????如果要從頭build不使用緩存和中間層:docker build --no-cache=true
4. 鏡像的定制基于哪些素材:
????????a. 基礎鏡像 -- 由FROM命令指定,本地有優先用本地的,沒有就去registry拉取;強制拉取的選項是 --pull=true
? ? ? ? ? ? FROM? ? ? ? 永遠的底格指令
? ? ? ? b. 文件素材 -- 須位于構建目錄之下
? ? ? ? ? ? ADD / COPY? ? 不會使用docker build生成的臨時層,而是檢索docker build傳給docker daemon的“文件系統”。
? ? ? ? ? ? ? ? ADD? ?<相對Dockerfile的目錄路徑>? ? <去往容器的文件的絕對路徑>
? ? ? ? c. 通信接口 -- 端口
? ? ? ? ? ? EXPOSE? ? ? ? 暴露容器內端口。這個端口可以用于容器連接,或者影射給主機的socket,映射關系可以由docker port察看,宿主機docker-proxy監聽宿主機的映射端口(netstat -tupln)。
? ? ? ? ? ? ? ? ? ? 映射給主機指定的socket地址: docker run -p? <主機ip:主機端口>:<被暴露的容器端口>。 主機IP默認是0.0.0.0
? ? ? ? ? ? ? ? ? ? 映射給主機隨機的隨機的端口:? docker run -P? ??<被暴露的容器端口>
? ? ? ? ? ? ? ? ? ? 容器連接
? ? ? ? d. 修改基礎鏡像
? ? ? ? ? ? RUN????????比如創建文件、安裝軟件
? ? ? ? e. 修改后續的build鏡像的環境變量
? ? ? ? ? ? ENV? <key>=<value>? ? ? ? 可以在docker run? 時由選項-e <key>=<value>?覆蓋
? ? ? ? f. 自定義鍵值,作為鏡像的標簽
? ? ? ? ? ? LABEL??<key>=<value>? ? ? ? 可以一行定義多個,用空格分開,這樣避免多個容器層被創建。
? ? ? ? ? ? ? ? ? ? LABEL的key的定義沒有限制,但推薦使用開發者可控域名的反向順序的DNS格式:比如: LABEL net.linuxtoys.mylabel=xxx
? ? ? ? ? ? ? ? ? ? 容器的LABEL可以用docker inspect檢視,也可以用docker ps -a --filter “label=<key>=<value>”來篩選容器
????????????????????也可以用docker images --filter “label=<key>=<value>”來篩選鏡像
? ? ? ? g. 景象啟動時的默認命令
????????????ENTRYPOINT? ? ? ? 默認的運行命令,可以在docker run? 時由選項--entrypoint="xxx" 覆蓋
????????????CMD? ? ? ? ????????????????默認的ENTRYPOINT的運行參數,可以在docker run時 由 最后的參數覆蓋
基于Dockerfile設計容器的原則
1. 一個容器只干一件事
容器連接或K8S編排,實現共享服務
2. 讓構建目錄盡可能小,否則用.dockerignore文件排除不想包含的文件
目的是減少傳遞構建目錄給docker daemon的時間,也節省/var/lib/docker的空間
3. 高效合理地組織Dockerfile的RUN命令
一行生成一個中間層。
所以,多命令在一行,可以節省空間。但是其中任何命令失敗了,下次build還得全部build這一行,浪費時間。
其實合理組織RUN命令,是Docker鏡像合理分層的手段。Docker鏡像是一種特殊的FS:Union FS,是一系列中間層疊加在基礎鏡像(也是之前疊加產物)上的結果。docker pull 拉取的,實際是本地已有鏡像之上的疊加層。所以Dockerfile的RUN命令,不僅影響開發,也影響拉取使用的效率。
4. ENTRYPOINT命令最先去做清理工作,比如刪除上次kill/stop時僵死的進程.pid文件
5. 最佳實踐
https://docs.docker.com/engine/reference/builder/????????????????
https://docs.docker.com/develop/develop-images/dockerfile_best-practices/?
容器開發和運行環境的種類
1. 運行在VirtualBox、KVM上的虛擬機鏡像Vagrant,它已經配置好了Docker、K8S等容器開發運行需要的軟件(CDK3.9 )
https://developers.redhat.com/products/cdk/download?
https://access.redhat.com/downloads/content/293/ver=3.9/rhel---7/3.9/x86_64/product-software?
https://access.redhat.com/documentation/en-us/red_hat_container_development_kit/3.9/?
2. 運行于Openshift之上 (K8S的包裝)
1) 開發者專用的上游項目--容器內的Openshift-- Openshift Origin。 搭建
step1.? install redhat7
step2. install docker、kubernetes、etcd
step3. 配置K8S集群
step4. 禁用SELinux
step5. 信任docker registry
step6. 啟動docker服務
step7. 拉取、運行Opeshift/origin容器
step8. 打開后臺運行的Origin容器的Bash Shell
Step9. 純Openshift操作,建立項目、app(也就是容器鏡像)、pods(啟動容器)
2)Ansible搭建的Openshift (NNIT ENET用的),即K8S集群
3)基于AWS、GCE的Openshift