Author:Cris
1. Docker 基礎知識
1.1 什麼是 Docker ?
這裡引用維基百科
Docker是一個開放原始碼軟體專案,讓應用程式部署在軟體貨櫃下的工作可以自動化進行,藉此在Linux作業系統上,提供一個額外的軟體抽象層,以及作業系統層虛擬化的自動管理機制
依據行業分析公司“451研究”:“Dockers是有能力打包應用程式及其虛擬容器,可以在任何Linux伺服器上執行的依賴性工具,這有助於實現靈活性和便攜性,應用程式在任何地方都可以執行,無論是公有云、私有云、單機等。”
簡單來說,Docker 通過對應用元件的封裝、分發、部署、執行等生命週期的管理,使使用者的APP(可以是一個WEB應用或資料庫應用等等)及其執行環境能夠做到“一次封裝,到處執行”。
1.2 為什麼 Docker 如此流行?
一款產品從開發到上線,從作業系統,到執行環境,再到應用配置。作為開發+運維之間的協作我們需要關心很多東西,這也是很多網際網路公司都不得不面對的問題,特別是各種版本的迭代之後,不同版本環境的相容,對運維人員都是考驗
Docker之所以發展如此迅速,也是因為它對此給出了一個標準化的解決方案。
環境配置如此麻煩,換一臺機器,就要重來一次,費力費時。很多人想到,能不能從根本上解決問題,軟體可以帶環境安裝?也就是說,安裝的時候,把原始環境一模一樣地複製過來。開發人員利用 Docker 可以消除協作編碼時“在我的機器上可正常工作”的問題。
之前在伺服器配置一個應用的執行環境,要安裝各種軟體,隨便拿一個 Java 專案來說,Java/Tomcat/MySQL/JDBC驅動包基本是必不可少的。安裝和配置這些東西有多麻煩就不說了,它還不能跨平臺。假如我們是在 Windows 上安裝的這些環境,到了 Linux 又得重新裝。況且就算不跨作業系統,換另一臺同樣作業系統的伺服器,要移植應用也是非常麻煩的。
傳統上認為,軟體編碼開發/測試結束後,所產出的成果即是程式或是能夠編譯執行的二進位制位元組碼等(java為例)。而為了讓這些程式可以順利執行,開發團隊也得準備完整的部署檔案,讓維運團隊得以部署應用程式,開發需要清楚的告訴運維部署團隊,用的全部配置檔案+所有軟體環境。不過,即便如此,仍然常常發生部署失敗的狀況。
Docker映象的設計,使得Docker得以打破過去「程式即應用」的觀念。透過映象(images)將作業系統核心除外,運作應用程式所需要的系統環境,由下而上打包,達到應用程式跨平臺間的無縫接軌運作。
1.3 Docker 的理念
Docker是基於Go語言實現的雲開源專案。
Docker的主要目標是“Build,Ship and Run Any App,Anywhere”,也就是通過對應用元件的封裝、分發、部署、執行等生命週期的管理,使使用者的APP(可以是一個WEB應用或資料庫應用等等)及其執行環境能夠做到“一次封裝,到處執行”。
Linux 容器技術的出現就解決了這樣一個問題,而 Docker 就是在它的基礎上發展過來的。將應用執行在 Docker 容器上面,而 Docker 容器在任何作業系統上都是一致的,這就實現了跨平臺、跨伺服器
。只需要一次配置好環境,換到別的機子上就可以一鍵部署好,大大簡化了操作(可以參考一下 Java 的一次編譯,處處執行特性)
簡單來說,Docker 的出現解決了執行環境和配置問題軟體容器,方便做持續整合並有助於整體釋出的容器虛擬化技術
1.4 Docker 虛擬化
首先我們簡單瞭解一下 Docker 的實現原理
-
虛擬機器技術
虛擬機器(virtual machine)就是帶環境安裝的一種解決方案。 它可以在一種作業系統裡面執行另一種作業系統,比如在Windows 系統裡面執行Linux 系統。應用程式對此毫無感知,因為虛擬機器看上去跟真實系統一模一樣,而對於底層系統來說,虛擬機器就是一個普通檔案,不需要了就刪掉,對其他部分毫無影響。這類虛擬機器完美的執行了另一套系統,能夠使應用程式,作業系統和硬體三者之間的邏輯不變。
虛擬機器的缺點:
- 資源佔用多
- 冗餘步驟多
- 啟動慢
-
容器虛擬化技術
由於前面虛擬機器存在這些缺點,Linux 發展出了另一種虛擬化技術:Linux 容器(Linux Containers,縮寫為 LXC)。 Linux 容器不是模擬一個完整的作業系統,而是對程式進行隔離。有了容器,就可以將軟體執行所需的所有資源打包到一個隔離的容器中。容器與虛擬機器不同,不需要捆綁一整套作業系統,只需要軟體工作所需的庫資源和設定。系統因此而變得高效輕量並保證部署在任何環境中的軟體都能始終如一地執行。
比較 Docker 和傳統虛擬化方式的不同之處:
- 傳統虛擬機器技術是虛擬出一套硬體後,在其上執行一個完整作業系統,在該系統上再執行所需應用程式;
- 而容器內的應用程式直接執行於宿主的核心,容器內沒有自己的核心,而且也沒有進行硬體虛擬。因此容器要比傳統虛擬機器更為輕便。
- 每個容器之間互相隔離,每個容器有自己的檔案系統 ,容器之間程式不會相互影響,能區分計算資源。
1.5 DevOps
通過 Docker 一次構建,處處執行的特性, DevOps 得到了極大的發展, 關於 DevOps,可以參考知乎的這個問答
或者這個系列的文章
個人理解: DevOps 是一種優化軟體開發和運營部署之間理念,通過自動化的工具協作和溝通來完成軟體的生命週期管理,從而更快、更頻繁地交付更穩定的軟體
1.6 Docker 的優勢
-
更快速的應用交付和部署
傳統的應用開發完成後,需要提供一堆安裝程式和配置說明文件,安裝部署後需根據配置文件進行繁雜的配置才能正常執行。Docker化之後只需要交付少量容器映象檔案,在正式生產環境載入映象並執行即可,應用安裝配置在映象裡已經內建好,大大節省部署配置和測試驗證時間。
-
更便捷的升級和擴縮容
隨著微服務架構和Docker的發展,大量的應用會通過微服務方式架構,應用的開發構建將變成搭樂高積木一樣,每個Docker容器將變成一塊“積木”,應用的升級將變得非常容易。當現有的容器不足以支撐業務處理時,可通過映象執行新的容器進行快速擴容,使應用系統的擴容從原先的天級變成分鐘級甚至秒級。
-
更簡單的系統運維
應用容器化執行後,生產環境執行的應用可與開發、測試環境的應用高度一致,容器會將應用程式相關的環境和狀態完全封裝起來,不會因為底層基礎架構和作業系統的不一致性給應用帶來影響,產生新的BUG。當出現程式異常時,也可以通過測試環境的相同容器進行快速定位和修復。
-
更高效的計算資源利用
Docker是核心級虛擬化,其不像傳統的虛擬化技術一樣需要額外的Hypervisor支援,所以在一臺物理機上可以執行很多個容器例項,可大大提升物理伺服器的CPU和記憶體的利用率。
1.7 當前企業使用 Docker 現狀
-
美團
-
微博
-
蘑菇街
ps: 如果軟體開發人員對自動化運維同樣熟悉,那麼不僅可以大大降低開發和運維之間的扯皮
,還可以提高開發人員的議價能力
1.8 Docker 官網和倉庫
docker官網:www.docker.com
docker中文網站:www.docker-cn.com/
Docker Hub官網: hub.docker.com/
1.9 個人總結
以 Java 為例,以前開發人員只需要將開發好的程式碼交給運維部署即可,但是隨著敏捷開發等開發模式的流行以及越來越高速化的軟體開發-測試-交付-部署等流程,為了減低運維壓力,調和開發人員和運維人員之間的關係,容器虛擬化技術(Docker)的應運而生
以前我們僅僅是是將 Java 程式碼進行交付,現在我們是將開發環境整套進行交付.通過對開發環境(例如 Redis, MySQL 以及各種配置等)和開發程式碼打包,不僅更加快速,便捷,也很容易的對應用部署進行彈性擴容,也大大減少了運維壓力
類似於搬家,為了營造一個和之前一樣的生活環境,的我們還需要將舊家的東西搬運到新家去,假如有一天,你很有錢,可以將舊家所在的整棟樓搬運到新家所在地;或者說你有了超能力,可以將舊家的環境直接複製到新家.那麼比起以前累死累活的搬運東西這種方式,哪個更方便不就是一目瞭然的事情了~~~
2. Docker 安裝
2.1 前提
當前 Docker 基本都裝在 Linux 環境下,以 CentOS 為例,建議 CentOS6.5 以上版本,目前主流 CentOS6.8 和 CentOS7.x 都支援
Cris 的 Linux 環境如下
2.2 Docker 三要素
-
映象(Image)
Docker 映象(Image)就是一個只讀的模板。映象可以用來建立 Docker 容器,一個映象可以建立很多容器。
-
容器(Container)
Docker 利用容器(Container)獨立執行一個或一組應用。容器是用映象建立的執行例項。
它可以被啟動、開始、停止、刪除。每個容器都是相互隔離的、保證安全的平臺。
可以把容器看做是一個簡易版的 Linux 環境(包括root使用者許可權、程式空間、使用者空間和網路空間等)和執行在其中的應用程式。
容器的定義和映象幾乎一模一樣,也是一堆層的統一視角,唯一區別在於容器的最上面那一層是可讀可寫的。
-
倉庫(Repository)
倉庫(Repository)是集中存放映象檔案的場所。
倉庫(Repository)和倉庫註冊伺服器(Registry)是有區別的。倉庫註冊伺服器上往往存放著多個倉庫,每個倉庫中又包含了多個映象,每個映象有不同的標籤(tag)。
倉庫分為公開倉庫(Public)和私有倉庫(Private)兩種形式。 最大的公開倉庫是 Docker Hub(hub.docker.com/), 存放了數量龐大的映象供使用者下載。國內的公開倉庫包括阿里雲 、網易雲等
需要正確的理解倉儲/映象/容器這幾個概念:
Docker 本身是一個容器執行載體或稱之為管理引擎。我們把應用程式和配置依賴打包好形成一個可交付的執行環境,這個打包好的執行環境就是 image映象檔案。只有通過這個映象檔案才能生成容器。image 檔案可以看作是容器的模板。Docker 根據 image 檔案生成容器的例項。同一個 image 檔案,可以生成多個同時執行的容器例項。
image 檔案生成容器例項,稱為映象檔案。
一個容器執行一種服務,當我們需要的時候,就可以通過docker客戶端建立一個對應的執行例項,也就是我們的容器
至於倉儲,就是放了一堆映象的地方,我們可以把映象釋出到倉儲中,需要的時候從倉儲中拉下來就可以了。
Docker 簡易流程圖
2.3 安裝 Docker
以 Cris 的CentOS6.8 為例
-
Docker使用EPEL釋出,RHEL系的OS首先要確保已經持有EPEL倉庫,否則先檢查OS的版本,然後安裝相應的EPEL包。
[cris@hadoop104 ~]$ sudo yum install -y epel-release 複製程式碼
-
然後執行 Docker 安裝命令
當前在 CentOS6.8 版本如果直接執行以下命令,很可能無法安裝 Docker
[cris@hadoop104 ~]$ sudo yum install -y docker-io 複製程式碼
所以需要執行另外的命令
[root@hadoop104 cris]# yum install https://get.docker.com/rpm/1.7.1/centos-6/RPMS/x86_64/docker-engine-1.7.1-1.el6.x86_64.rpm 複製程式碼
-
安裝後的配置檔案:/etc/sysconfig/docker
-
Docker 版本
-
啟動 Docker
ps: 如果要在 CentOS7.x 上安裝 Docker, 請直接參考官網文件即可
2.4 Docker 映象加速
以阿里云為例,首先註冊一個阿里雲賬號,然後進入映象加速頁面
配置本機的 Docker 檔案
[cris@hadoop104 ~]$ sudo vim /etc/sysconfig/docker
複製程式碼
重啟 Docker 服務
[cris@hadoop104 ~]$ sudo service docker restart
停止 docker: [確定]
Starting docker: [確定]
複製程式碼
然後檢測 Docker 映象加速地址是否是我們的阿里雲映象地址
ps: 如果是 CentOS7.x 版本,直接參考上面的阿里雲操作文件
網易雲映象加速這裡直接略過~~~:cowboy_hat_face:
2.5 hello world
直接通過 docker run hello-world
命令,我們可以直接從阿里雲拉取 hello-world 映象並建立容器自動執行(在本地沒有找到 hello-world 的映象時)
docker run 命令執行流程圖
2.6 Docker 和 VM 比較
-
Docker 工作原理
Docker是一個Client-Server結構的系統,Docker守護程式執行在主機上,然後通過Socket連線從客戶端訪問,守護程式從客戶端接受命令並管理執行在主機上的容器。容器,是一個執行時環境,就是我們前面說到的集裝箱。
例如下面 Docker 圖示(一隻鯨魚背上拖著很多個集裝箱, 鯨魚類似於 Docker,一個個的集裝箱就是軟體開發環境中的各種軟體)
以下為 Docker 執行架構圖
-
為什麼 Docker 執行速度遠大於 VM?
(1)Docker有著比虛擬機器更少的抽象層。由於docker不需要Hypervisor實現硬體資源虛擬化,執行在docker容器上的程式直接使用的都是實際物理機的硬體資源。因此在CPU、記憶體利用率上docker將會在效率上有明顯優勢。
(2)Docker利用的是宿主機的核心,而不需要CentOS。因此,當新建一個容器時,docker不需要和虛擬機器一樣重新載入一個作業系統核心。從而避免載入作業系統核心這個比較費時費資源的過程,當新建一個虛擬機器時,虛擬機器軟體需要載入CentOS,整個新建過程是分鐘級別的。而docker由於直接利用宿主機的作業系統,因此新建一個docker容器只需要幾秒鐘。
-
Docker 和 VM 對比圖
- Docker 和 VM 特點對比圖
3. Docker 常用命令
3.1 幫助命令
-
docker version
-
docker info
-
docker --help(-h)
3.2 映象命令
- docker images
列出本地主機上的映象
- REPOSITORY:表示映象的倉庫源
- TAG:映象的標籤
- MAGE ID:映象ID
- CREATED:映象建立時間
- SIZE:映象大小
同一倉庫源可以有多個 TAG,代表這個倉庫源的不同個版本,我們使用 REPOSITORY:TAG 來定義不同的映象。 如果你不指定一個映象的版本標籤,例如你只使用 ubuntu,docker 將預設使用 ubuntu:latest 映象
-
images 命令 的 option 引數
-
-a:列出本地所有的映象(含中間映像層)
-
-q :只顯示映象ID
-
--digests :顯示映象的摘要資訊
-
--no-trunc :顯示完整的映象資訊
-
- docker search 映象名
從 Docker hub 官網搜尋映象
官網地址: hub.docker.com
以 tomcat 為例
和在官網搜尋的結果一模一樣
-
引數說明
-
-s : 列出收藏數不小於指定值的映象
只搜尋點贊數大於30的映象
-
--no-trunc : 顯示完整的映象描述
-
--automated : 只列出 automated build型別的映象
-
-
docker pull 映象名:tag
拉取映象(從前面我們已經設定的阿里雲的映象加速地址)
如果
docker pull 映象名
後面不加引數,預設下載最新版本即 docker pull tomcat 等價於 docker pull tomcat:latest
[cris@hadoop104 ~]$ sudo docker pull tomcat 複製程式碼
-
docker rmi 映象名/映象id
刪除 Docker 映象
ps:
docker rmi 映象名
預設會刪除標籤為 :latest 的映象,如果要刪除指定標籤的映象,在映象名後面指定 tag 即可如果無法刪除,出現如上提示,表示我們的映象正在使用中,可以使用 -f 強制刪除
如果想要刪除多個映象
docker rmi -f 映象名1:tag 映象名2:tag
sudo docker rmi -f hello-world tomcat 複製程式碼
刪除全部映象
sudo docker rmi -f $(docker images -qa) 複製程式碼
結合 git 知識,想想 Docker 是否有 docker pull 和 docker commit 命令?
3.3 容器命令
-
以 CentOS 為例,這裡 Cris 從阿里雲下載一個 CentOS 的映象
-
新建並啟動容器(以 Docker 裡面的 CentOS 映象為例)
docker run [options] image [command] [arg...]
options 這裡常用的有:
--name="容器新名字": 為容器指定一個名稱; -d: 後臺執行容器,並返回容器ID,也即啟動守護式容器; -i:以互動模式執行容器,通常與 -t 同時使用; -t:為容器重新分配一個偽輸入終端,通常與 -i 同時使用; -P: 隨機埠對映; -p: 指定埠對映,有以下四種格式 ip:hostPort:containerPort ip::containerPort hostPort:containerPort containerPort
我們使用 -it 引數來啟動 CentOS 容器
root@ 後面跟著的就是該容器的 id
-
檢視所有執行的容器命令
docker ps [options]
引數說明:
-a :列出當前所有正在執行的容器+歷史上執行過的容器 -l :顯示最近執行的容器。 -n number:顯示最近 number 個建立的容器。 -q :靜默模式,只顯示容器編號。 --no-trunc :不截斷輸出。
-
退出容器
exit: 容器停止並退出
ctrl+p+q: 容器不停止退出
-
啟動已經建立的容器
docker start 容器id/容器名
-
重啟容器
docker restart 容器id/容器名
-
停止容器
docker stop 容器id/容器名
-
強制關閉容器
docker kill 容器id/容器名
-
刪除已停止的容器
docker rm 容器id/容器名
一次性刪除多個已經停止的容器
docker rm -f $(docker ps -qa) 或者 docker ps -a -q | xargs docker rm
-
互動式容器和守護式容器
前面啟動 CentOS 容器使用的 -it 引數就是表示互動式命令,通過終端來保持和容器的互動
如果要啟動守護式容器,那麼需要加上 -d 引數
但是此時查詢正在執行的容器
沒有發現以後臺模式執行的 Docker 容器
發現該容器已經自動退出了
問題:docker ps -a 進行檢視, 會發現容器已經退出 很重要的一點: Docker容器後臺執行,就必須有一個前臺程式. 容器執行的命令如果不是那些一直掛起的命令(比如執行top,tail),是會自動退出的。
這個是docker的機制問題,比如你的web容器,我們以nginx為例,正常情況下,我們配置啟動服務只需要啟動響應的service即可。例如 service nginx start 但是,這樣做,nginx為後臺程式模式執行,就導致docker前臺沒有執行的應用, 這樣的容器後臺啟動後,會立即自殺因為他覺得他沒事可做了. 所以,最佳的解決方案是,將你要執行的程式以前臺程式的形式執行
-
容器日誌
對於後臺執行的容器,可以以下面的方式來啟動
[cris@hadoop104 ~]$ sudo docker run -d --name centos004 centos /bin/sh -c "while true;do echo hello zzyy;sleep 2;done" 複製程式碼
檢視 Docker 容器
即便是後臺啟動,但是因為前臺一直列印日誌,Docker 容器也不會自動關閉
如果此時我們想去檢視 Docker 容器的日誌,可以通過以下命令
docker logs -f -t --tail 容器ID
- -t 是加入時間戳
- -f 跟隨最新的日誌列印
- --tail 數字 顯示最後多少條
-
檢視容器內執行的程式
docker top 容器ID
-
檢視容器內部細節
docker inspect 容器ID
-
進入正在執行的容器並以命令列互動
重新進入正在執行的容器
docker attach 容器ID
還有一種方式是
docker exec -it 容器ID bashShell(功能更加強大,可以直接返回結果到客戶端)
區別在於:
attach 命令直接進入容器啟動命令的終端,不會啟動新的程式
exec 命令是在容器中開啟新的終端,並且可以啟動新的程式
-
從容器內拷貝檔案到主機上
docker cp 容器ID:容器內路徑 目的主機路徑
示例如下
3.4 常用命令總結
attach Attach to a running container # 當前 shell 下 attach 連線指定執行映象
build Build an image from a Dockerfile # 通過 Dockerfile 定製映象
commit Create a new image from a container changes # 提交當前容器為新的映象
cp Copy files/folders from the containers filesystem to the host path #從容器中拷貝指定檔案或者目錄到宿主機中
create Create a new container # 建立一個新的容器,同 run,但不啟動容器
diff Inspect changes on a container's filesystem # 檢視 docker 容器變化
events Get real time events from the server # 從 docker 服務獲取容器實時事件
exec Run a command in an existing container # 在已存在的容器上執行命令
export Stream the contents of a container as a tar archive # 匯出容器的內容流作為一個 tar 歸檔檔案[對應 import ]
history Show the history of an image # 展示一個映象形成歷史
images List images # 列出系統當前映象
import Create a new filesystem image from the contents of a tarball # 從tar包中的內容建立一個新的檔案系統映像[對應export]
info Display system-wide information # 顯示系統相關資訊
inspect Return low-level information on a container # 檢視容器詳細資訊
kill Kill a running container # kill 指定 docker 容器
load Load an image from a tar archive # 從一個 tar 包中載入一個映象[對應 save]
login Register or Login to the docker registry server # 註冊或者登陸一個 docker 源伺服器
logout Log out from a Docker registry server # 從當前 Docker registry 退出
logs Fetch the logs of a container # 輸出當前容器日誌資訊
port Lookup the public-facing port which is NAT-ed to PRIVATE_PORT # 檢視對映埠對應的容器內部源埠
pause Pause all processes within a container # 暫停容器
ps List containers # 列出容器列表
pull Pull an image or a repository from the docker registry server # 從docker映象源伺服器拉取指定映象或者庫映象
push Push an image or a repository to the docker registry server # 推送指定映象或者庫映象至docker源伺服器
restart Restart a running container # 重啟執行的容器
rm Remove one or more containers # 移除一個或者多個容器
rmi Remove one or more images # 移除一個或多個映象[無容器使用該映象才可刪除,否則需刪除相關容器才可繼續或 -f 強制刪除]
run Run a command in a new container # 建立一個新的容器並執行一個命令
save Save an image to a tar archive # 儲存一個映象為一個 tar 包[對應
load]
search Search for an image on the Docker Hub # 在 docker hub 中搜尋映象
start Start a stopped containers # 啟動容器
stop Stop a running containers # 停止容器
tag Tag an image into a repository # 給源中映象打標籤
top Lookup the running processes of a container # 檢視容器中執行的程式資訊
unpause Unpause a paused container # 取消暫停容器
version Show the docker version information # 檢視 docker 版本號
wait Block until a container stops, then print its exit code # 擷取容器停止時的退出狀態值
複製程式碼
4. Docker 映象
映象是一種輕量級、可執行的獨立軟體包,用來打包軟體執行環境和基於執行環境開發,它包含執行某個軟體所需的所有內容,包括程式碼、執行時、庫、環境變數和配置檔案。
而 Docker 映象的底層實現原理是 UnionFS 聯合檔案系統
4.1 UnionFS 聯合檔案系統
UnionFS(聯合檔案系統):Union檔案系統(UnionFS)是一種分層、輕量級並且高效能的檔案系統,它支援對檔案系統的修改作為一次提交來一層層的疊加,同時可以將不同目錄掛載到同一個虛擬檔案系統下(unite several directories into a single virtual filesystem)。Union 檔案系統是 Docker 映象的基礎。映象可以通過分層來進行繼承,基於基礎映象(沒有父映象),可以製作各種具體的應用映象。
類似於花捲這種常見的早餐,檔案系統可以通過一層一層的巢狀,對外暴露統一的"表面層"來供使用者操作
特性:一次同時載入多個檔案系統,但從外面看起來,只能看到一個檔案系統,聯合載入會把各層檔案系統疊加起來,這樣最終的檔案系統會包含所有底層的檔案和目錄
4.2 Docker 映象載入原理
docker的映象實際上由一層一層的檔案系統組成,這種層級的檔案系統UnionFS。
bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引導載入kernel, Linux剛啟動時會載入bootfs檔案系統,在Docker映象的最底層是bootfs。這一層與我們典型的Linux/Unix系統是一樣的,包含boot載入器和核心。當boot載入完成之後整個核心就都在記憶體中了,此時記憶體的使用權已由bootfs轉交給核心,此時系統也會解除安裝bootfs。
rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系統中的 /dev, /proc, /bin, /etc 等標準目錄和檔案。rootfs就是各種不同的作業系統發行版,比如Ubuntu,Centos等等。
平時我們安裝進虛擬機器的CentOS都是好幾個G,為什麼docker這裡才200M??
對於一個精簡的OS,rootfs可以很小,只需要包括最基本的命令、工具和程式庫就可以了,因為底層直接用Host的kernel,自己只需要提供 rootfs 就行了。由此可見對於不同的linux發行版, bootfs基本是一致的, rootfs會有差別, 因此不同的發行版可以公用bootfs。
通過 docker pull 命令再來感受一下映象分層
所以在下載的過程中我們可以看到docker的映象好像是在一層一層的在下載
為什麼 Docker 映象要採用這種分層結構呢?
最大的一個好處就是 - 共享資源
比如:有多個映象都從相同的 base 映象構建而來,那麼宿主機只需在磁碟上儲存一份base映象, 同時記憶體中也只需載入一份 base 映象,就可以為所有容器服務了。而且映象的每一層都可以被共享。
所以,Docker映象都是隻讀的,當容器啟動時,一個新的可寫層被載入到映象的頂部。這一層通常被稱作“容器層”,“容器層”之下的都叫“映象層”。
4.3 Docker 映象 commit 操作
基礎命令
docker commit 用於提交容器副本使之成為一個新的映象
完整格式如下
docker commit -m=“提交的描述資訊” -a=“作者” 容器ID 要建立的目標映象名:[標籤名]
以 Tomcat 為例
- 啟動 Tomcat 容器
- -p 主機埠:docker容器埠
- -P 隨機分配主機埠
- i:互動
- t:終端
- 以互動模式進入到 Docker 中的 Tomcat 中
[cris@hadoop104 ~]$ sudo docker exec -it 8db42f30a60a /bin/bash
root@8db42f30a60a:/usr/local/tomcat#
複製程式碼
我們刪除掉 tomcat 下的 doc 文件
-
也即當前的tomcat執行例項是一個沒有文件內容的容器,以它為模板commit一個沒有doc的tomcat新映象 cris/tomcat
至此,新的沒有 doc 的 Tomcat 映象已經生成好了
-
執行基於新映象的 Tomcat 容器
[cris@hadoop104 ~]$ sudo docker run -it -p 8118:8080 cris/tomcat:1.1 複製程式碼
可以發現是沒有 doc 文件的
ps: 以上都是以前臺方式啟動 Tomcat 容器(不斷列印日誌),如果想要以後臺守護方式啟動,直接加上 -d 引數即可
控制檯也就沒有日誌列印了
5. Docker容器資料卷
5.1 什麼是 Docker 容器資料卷
需求:
- Docker 可以將執行的環境打包形成容器執行,但是我們對 Docker 容器的資料的要求希望是持久化的
- 容器之間希望共享資料
Docker容器產生的資料,如果不通過docker commit生成新的映象,使得資料做為映象的一部分儲存下來, 那麼當容器刪除後,資料自然也就沒有了。
為了能儲存資料在docker中我們使用資料卷。
類似 Redis裡面的rdb和aof檔案或者我們平時使用的行動硬碟
5.2 資料卷的用處
資料卷就是目錄或檔案,存在於一個或多個容器中,由docker掛載到容器,但不屬於聯合檔案系統,因此能夠繞過Union File System提供一些用於持續儲存或共享資料的特性:
資料卷的設計目的就是資料的持久化,完全獨立於容器的生存週期,因此Docker不會在容器刪除時刪除其掛載的資料卷
特點:
- 資料卷可在容器之間共享或重用資料
- 卷中的更改可以直接生效
- 資料卷中的更改不會包含在映象的更新中
- 資料卷的生命週期一直持續到沒有容器使用它為止
5.3 資料卷使用
一. 直接通過命令新增資料卷
docker run -it -v /宿主機絕對路徑目錄:/容器內目錄 映象名
驗證資料卷是否掛載成功
[cris@hadoop104 ~]$ sudo docker inspect 4b02b2727058
複製程式碼
宿主機和容器之間的資料互動
同理, 容器可以對資料進行修改並同步到宿主機
容器停止退出後,主機修改後資料是否同步
通過 exit 命令停止容器並退出終端
然後在宿主機對資料進行修改
[cris@hadoop104 hostDataVolume]$ sudo vim dog.txt
複製程式碼
重新開啟容器
可以發現,即便是容器關閉,宿主機依然可以對資料捲進行資料操作,當容器重新開啟時,資料卷會自動進行同步
如果想要設定許可權,例如容器只能對資料捲進行讀和同步,宿主機可以運算元據卷,那麼只需要新增一個引數即可
docker run -it -v /宿主機絕對路徑目錄:/容器內目錄:ro 映象名
ro
就表示 read-only 許可權(針對容器)
二. DockerFile新增資料卷
DockerFile 簡單來說,就是描述 Docker 映象的描述檔案
流程簡單梳理如下
-
宿主機新建一個 DockerFile
可在Dockerfile中使用VOLUME指令來給映象新增一個或多個資料卷
ps: 出於可移植和分享的考慮,用-v 主機目錄:容器目錄這種方法不能夠直接在Dockerfile中實現。 由於宿主機目錄是依賴於特定宿主機的,並不能夠保證在所有的宿主機上都存在這樣的特定目錄。
-
build 構建映象
-
根據映象執行容器
-
測試資料卷
根據 inspect 命令檢視對應的宿主機資料卷目錄
[cris@hadoop104 ~]$ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES cd98e9b2c94b cris/centos "/bin/sh -c /bin/bas 2 minutes ago Up 2 minutes jovial_goodall [cris@hadoop104 ~]$ sudo docker inspect cd98e9b2c94b 複製程式碼
預設宿主機掛載地址需要通過 inspect 命令檢視
三. 資料卷容器
主要用於容器和容器之間的資料共享
命令: --volumes-from
示例如下:
-
啟動一個父容器
啟動後我們在指定目錄下建立一個檔案
-
新建兩個子容器,繼承自父容器
可以發現成功同步了父容器的資料
同時修改任意一個子容器的資料卷資料,都會同步到其他容器
即便是刪除任意一個容器,資料卷的資料同步不會停止
-
結論
容器之間共享資料的傳遞,資料卷的生命週期一直持續到沒有容器使用它為止
6. DockerFile解析
6.1 什麼是 DockerFile
Dockerfile是用來構建Docker映象的構建檔案,是由一系列命令和引數構成的指令碼。
通常使用 DockerFile 的三個步驟都是:
- 編寫 DockerFile 檔案
- 執行 docker build 編譯命令
- 執行docker run 啟動容器命令
以 CentOS 為例, Docker Hub 上的 CentOS 的 DockerFile 檔案如下
6.2 DockerFile 構建過程解析
DockerFile 基礎知識
以上面的 CentOS DockerFile 檔案為例
- 每條保留字指令(紅色字型)都必須為大寫字母且後面要跟隨至少一個引數
- 指令按照從上到下,順序執行
- #表示註釋
- 每條指令都會建立一個新的映象層,並對映象進行提交
Docker執行Dockerfile的大致流程
- docker從基礎映象執行一個容器
- 執行一條指令並對容器作出修改
- 執行類似docker commit的操作提交一個新的映象層
- docker再基於剛提交的映象執行一個新容器
- 執行dockerfile中的下一條指令直到所有指令都執行完成
總結:
從應用軟體的角度來看,Dockerfile、Docker映象與Docker容器分別代表軟體的三個不同階段,
- Dockerfile是軟體的原材料
- Docker映象是軟體的交付品
- Docker容器則可以認為是軟體的執行態。 Dockerfile面向開發,Docker映象成為交付標準,Docker容器則涉及部署與運維,三者缺一不可,合力充當Docker體系的基石。
Dockerfile,需要定義一個Dockerfile,Dockerfile定義了程式需要的一切東西。Dockerfile涉及的內容包括執行程式碼或者是檔案、環境變數、依賴包、執行時環境、動態連結庫、作業系統的發行版、服務程式和核心程式(當應用程式需要和系統服務和核心程式打交道,這時需要考慮如何設計namespace的許可權控制)等等;
Docker映象,在用Dockerfile定義一個檔案之後,docker build時會產生一個Docker映象,當執行 Docker映象時,會真正開始提供服務;
Docker容器,直接提供服務.
6.3 DockerFile 體系結構(保留字)
-
FROM : 基礎映象,當前新映象是基於哪個映象的
-
MAINTAINER : 映象維護者的姓名和郵箱地址
-
RUN : 容器構建時需要執行的命令
-
EXPOSE : 當前容器對外暴露出的埠
-
WORKDIR : 指定在建立容器後,終端預設登陸的進來工作目錄,一個落腳點
-
ENV : 用來在構建映象過程中設定環境變數
ENV MY_PATH /usr/mytest 這個環境變數可以在後續的任何RUN指令中使用,這就如同在命令前面指定了環境變數字首一樣; 也可以在其它指令中直接使用這些環境變數,
比如:WORKDIR $MY_PATH
-
ADD : 將宿主機目錄下的檔案拷貝進映象且ADD命令會自動處理URL和解壓tar壓縮包
-
COPY : 類似ADD,拷貝檔案和目錄到映象中。 將從構建上下文目錄中 <源路徑> 的檔案/目錄複製到新的一層的映象內的 <目標路徑> 位置
-
VOLUME : 容器資料卷,用於資料儲存和持久化工作
-
CMD : 指定一個容器啟動時要執行的命令
注意: Dockerfile 中可以有多個 CMD 指令,但只有最後一個生效,CMD 會被 docker run 之後的引數替換
-
ENTRYPOINT : 指定一個容器啟動時要執行的命令;ENTRYPOINT 的目的和 CMD 一樣,都是在指定容器啟動程式及引數,但是不會被 docker run 後面的引數替換,而是追加
-
ONBUILD : 當構建一個被繼承的Dockerfile時執行命令,父映象在被子繼承後父映象的onbuild被觸發
總結:
6.4 DockerFile 實戰案例
一. 自定義 CentOS 映象案例
首先,我們需要知道Docker Hub 中 99% 的映象都是通過在 base 映象中安裝和配置需要的軟體構建出來的
而這個 base 映象就是scratch 映象
首先停止所有正在執行的 Docker 容器
然後看看從阿里雲下載的基礎版 CentOS 缺失了哪些功能
現在我們的目標就是通過編寫 DockerFile 為基礎版本的 CentOS 映象加上這些缺失的功能
DockerFile 如下
FROM centos
MAINTAINER cris<cris163@111.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "success--------------ok"
CMD /bin/bash
複製程式碼
開始構建
[cris@hadoop104 dockerFile]$ sudo docker build -f centosDockerFile -t cris/centos:1.2 .
複製程式碼
構建成功,開始執行容器
除此之外,還可以檢視 Docker 映象的修改歷史
二. CMD/ENTRYPOINT 映象案例
CMD 示例:
Dockerfile 中可以有多個 CMD 指令,但只有最後一個生效,CMD 會被 docker run 之後的引數替換
以 Tomcat 為例
原因就在於我們的 ls -l 引數替換掉了原來的啟動引數,如下
相當於在這行引數後面又新增了 CMD ls -l
那麼容器啟動時就會執行最後的 ls -l 命令
如果是 ENTRYPOINT
docker run 之後的引數會被當做引數傳遞給 ENTRYPOINT,之後形成新的命令組合
示例如下
編寫 DockerFile
FROM centos
RUN yum install -y curl
ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]
複製程式碼
然後構建
[cris@hadoop104 dockerFile]$ sudo docker build -f centosDockerFile2 -t cris/ipcentos .
複製程式碼
以新增引數的形式啟動容器
如果我們把上面 DockerFile 檔案中的 ENTRYPOINT 改為 CMD 並重新編譯映象
那麼同樣的命令啟動容器,會出現以下報錯
ONBUILD 示例
類似於觸發器,在映象編譯以及子映象編譯的時候觸發
新建一個 DockerFile , centosDockerFileFather
FROM centos
RUN yum install -y curl
ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]
ONBUILD RUN echo "father is building -------------->"
複製程式碼
進行編譯後,又新建一個子 DockerFile, centosDockerFileSon
FROM cris/ipcentos_father
RUN yum install -y curl
ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]
複製程式碼
cris/ipcentos_father 就是上面編譯完成的父映象
當我們開始編譯子映象時,就會觸發 ONBUILD 操作
三. 自定義 Tomcat9 映象(重要)
在新建目錄,並且新增以下檔案
Dockerfile 內容如下
FROM centos
MAINTAINER cris<cris@1222.com>
#把宿主機當前上下文的c.txt拷貝到容器/usr/local/路徑下
COPY copy.txt /usr/local/cincontainer.txt
#把java與tomcat新增到容器中
ADD jdk-8u172-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.19.tar.gz /usr/local/
#安裝vim編輯器
RUN yum -y install vim
#設定工作訪問時候的WORKDIR路徑,登入落腳點
ENV MYPATH /usr/local
WORKDIR $MYPATH
#配置java與tomcat環境變數
ENV JAVA_HOME /usr/local/jdk1.8.0_172
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.19
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.19
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#容器執行時監聽的埠
EXPOSE 8080
#啟動時執行tomcat
# ENTRYPOINT ["/usr/local/apache-tomcat-9.0.8/bin/startup.sh" ]
# CMD ["/usr/local/apache-tomcat-9.0.8/bin/catalina.sh","run"]
CMD /usr/local/apache-tomcat-9.0.19/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.19/bin/logs/catalina.out
複製程式碼
然後開始編譯
[cris@hadoop104 mytomcat]$ sudo docker build -t cris_tomcat9 .
複製程式碼
如果不加 -f 引數,預設從當前目錄下的 Dockerfile 檔案開始編譯
編譯成功後,直接執行
[cris@hadoop104 mytomcat]$ sudo docker run -d -p 9090:8080 --name cristomcat9 -v /home/cris/dockerFile/mytomcat/test:/usr/local/apache-tomcat-9.0.19/webapps/test -v \
> /home/cris/dockerFile/mytomcat/logs:/usr/local/apache-tomcat-9.0.19/logs --privileged=true cris_tomcat9
複製程式碼
檢視資料卷對應的目錄
[cris@hadoop104 mytomcat]$ sudo docker inspect cristomcat9
複製程式碼
驗證 Tomcat 是否啟動
測試web 工程釋出
我們在宿主機的目錄上新建一個簡單的 web 工程
test.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
-----------welcome------------
<%="i am in docker tomcat self "%>
<br>
<br>
<% System.out.println("=============docker tomcat self");%>
</body>
</html>
複製程式碼
然後是 WEB-INF 目錄下的 web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>test</display-name>
</web-app>
複製程式碼
最後重啟容器
[cris@hadoop104 test]$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e39ccfda5b58 cris_tomcat9 "/bin/sh -c '/usr/lo 18 minutes ago Up 18 minutes 0.0.0.0:9090->8080/tcp cristomcat9
[cris@hadoop104 test]$ sudo docker restart cristomcat9
複製程式碼
測試
我們在宿主機修改 jsp
實時反映到 Docker 容器中的 Tomcat
在檢視對應的日誌
四. 總結
7. 擴充
Docker 安裝常規步驟
- 搜尋映象
- 拉取映象
- 檢視映象
- 啟動映象
- 停止容器
- 移除容器
- 移除映象
7.1 安裝 Tomcat
- docker search tomcat
- docker pull tomcat
- docker image tomcat
- docker run -it -p 8080:8080 tomcat
- -p 主機埠:docker容器埠
- -P 隨機分配埠
- i:互動
- t:終端
7.2 安裝 MySQL
docker pull mysql:5.6
驗證
執行容器
[cris@hadoop104 ~]$ sudo docker run -p 12345:3306 --name mysql -v /home/cris/docker_mysql/conf:/etc/mysql/conf.d -v /home/cris/docker_mysql/logs:/logs -v /home/cris/docker_mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.6
複製程式碼
資料卷已建立
[cris@hadoop104 ~]$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
029d8863fb17 mysql:5.6 "docker-entrypoint.s 7 seconds ago Up 6 seconds 0.0.0.0:12345->3306/tcp mysql
複製程式碼
容器已經成功跑起來了
宿主機測試是否可以連線
資料備份
docker exec myql服務容器ID sh -c ' exec mysqldump --all-databases -uroot -p"123456" ' > /home/cris/docker_mysql/all-databases.sql
複製程式碼
7.3 安裝 Redis
先拉取: docker pull redis:3.2
然後執行以下命令執行容器
[cris@hadoop104 ~]$ sudo docker run -p 6379:6379 -v /home/cris/myredis/data:/data -v /home/cris/myredis/conf/redis.conf:/usr/local/etc/redis/redis.conf -d redis:3.2 redis-server /usr/local/etc/redis/redis.conf --appendonly yes
複製程式碼
如果想要修改 Redis 的配置檔案,可以直接在宿主機上對應目錄修改 Redis 的配置檔案即可,自動對映到Docker 容器中的 Redis
測試 redis-cli 連線
測試持久化檔案生成
7.4 測試本地和阿里雲倉庫的映象釋出和拉取
首先,我們知道了 image 的生成方式有兩種,一種是根據 DockerFile 構建;一種是根據容器 commit 新的 image
示例
首先執行一個 Docker 容器
$ sudo docker run -it cris/centos:1.2
複製程式碼
然後提交一個新的 image
$ sudo docker commit -a cris -m "new centos image by cris with vim and ifconfig features" 3325338e5c43 cris/centos:1.3
複製程式碼
登入阿里雲,進行測試
建立映象倉庫
然後根據指示推送本地 image 到阿里雲的 repository
$ sudo docker login --username=990435014@qq.com registry.cn-hangzhou.aliyuncs.com
$ sudo docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/cris_cool/mycentos:[映象版本號]
$ sudo docker push registry.cn-hangzhou.aliyuncs.com/cris_cool/mycentos:[映象版本號]
複製程式碼
ps: 這裡 Cris 從本機登入阿里雲倉庫的時候一直無法登入,顯示如下錯誤
Error response from daemon: no successful auth challenge for https://registry.cn-hangzhou.aliyuncs.com/v2/ - errors: [token auth attempt for registry https://registry.cn-hangzhou.aliyuncs.com/v2/: https://dockerauth.cn-hangzhou.aliyuncs.com/auth?account=990435014%40qq.com&service=registry.aliyuncs.com%3Acn-hangzhou%3A26842 request failed with status: 401 Unauthorized]
複製程式碼
網上搜尋了後發現登入密碼不對,不是登入阿里雲賬號的密碼,需要重新設定登入 repository 的密碼
然後開始推送
想要拉取也很簡單
[cris@hadoop104 data]$ sudo docker pull registry.cn-hangzhou.aliyuncs.com/cris_cool/mycentos:1.3
複製程式碼
7.5 CentOS 7 下的 Docker 安裝
參考 Docker 官網即可