Docker容器技術之映象管理基礎(三)
上一篇文章連結:Docker容器技術基礎用法(二)
目錄
映象的匯入docker load和匯出docker save
一、回顧
上篇文章的最後我們講了docker的容器的狀態轉換和相關各種常用命令
1.1docker容器的狀態
docker容器會處於一下狀態中的某一種:
- created:處於建立
狀態的容器- running:處於執行狀態的容器
- paused:處於暫停狀態的容器
- stopped:處於停止狀態的容器
- deleted:不能算是一種狀態了。因為一個容器已刪除,我們就無法檢視他的狀態了。
1.2docker容器管理時常用的命令
關於docker attach命令:一個docker容器處於stop以後為了能夠使得其在啟動以後再關聯到它的終端上,那麼我們使用了docker start命令,那麼attach就是如果我們對一個處於執行狀態的有終端的容器處於剝離了,那麼我們也可以給他重新連上去就用attach
docker attach :
連線到正在執行中的容器。語法
docker attach [OPTIONS] CONTAINER
要attach上去的容器必須正在執行,可以同時連線上同一個container來共享螢幕(與screen命令的attach類似)。
官方文件中說attach後可以通過CTRL-C來detach,但實際上經過我的測試,如果container當前在執行bash,CTRL-C自然是當前行的輸入,沒有退出;如果container當前正在前臺執行程序,如輸出nginx的access.log日誌,CTRL-C不僅會導致退出容器,而且還stop了。這不是我們想要的,detach的意思按理應該是脫離容器終端,但容器依然執行。好在attach是可以帶上--sig-proxy=false來確保CTRL-D或CTRL-C不會關閉容器。
1.3docker的架構形式
如果我們只考慮單機之上所執行的容器的話,那麼docker的整體架構形式是
docker容器所能執行的主機叫Docker Host,所謂Docker Host就是執行的docker Daemon守護程序的主機,也成Docker Server端
接收客戶端請求是通過http或https協議與客戶端互動,客戶端可以是遠端主機的docker客戶端,此前我們用的docker create,docker run等等命令都是客戶端命令,而後Docker Daemon接收到建立或啟動容器的命令後,將在本地建立或啟動容器,注意:在一個docker Host之上可以啟動多個容器,所以此處我們可能執行的是分別屬於執行各種各樣不同程式的容器,而容器的啟動是要基於映象來實現,如果映象本地沒有,那麼docker Daemon會自動連到Docker Registry上,(Docker Registry是統稱,docker Hub是其最知名的,是預設的Registry)而後從中獲取映象以後,儲存在本地,一個能夠專門儲存住這種所謂的映象的儲存空間中(這個空間要求是特殊而且是專用的檔案系統,比如我們安裝的docker是1.18的版本那麼他使用的是overlay2這種儲存驅動),映象本身是隻讀的,而且映象在映象Registry上放的時候倉庫名通常就是應用程式名,而倉庫內可以放多個映象,而且這些映象通常是屬於同一個應用程式的不同版本,我們用標籤來識別這些映象。docker這個單詞是碼頭工人的意思。
以前我們去安裝部署應用程式的時候:應該都是散裝的。以後我們應用程式在部署的時候是靠映象,映象在理解的時候可以是應用程式的集裝箱。因此叫docker碼頭工人,他來負責裝卸集裝箱的。
所以docker映象是啟動docker容器非常重要的元件。接下來我們就瞭解一下docker映象是由什麼構建的!
二、About Docker Images
2.1 關於docker映象的作用及架構剖析
我們之前啟動過busybox容器。
可以看到藍色的完整意義上的根檔案系統。容器啟動就是靠映象實現,如果我們建立一個容器後,沒有做任何修改,那麼我們看到的內容應該是底層映象所提供的內容,所以映象含有啟動容器所需要的檔案系統及其內容。因此主要作用就在於建立並啟動docker容器的。
docker映象採用分層構建機制,這種分層大體分為兩部分:最底層為bootfs(引導檔案系統)和真正讓使用者拿來構建使用者空間並執行程序的容器的我們成為rootfs。
2.2 docker映象的層結構剖析
Apache映象就是執行httpd的映象,在底層有一個純淨的最小化的Debian,centos或者是suse系統。在上層我們添加了一個編輯器emac相當於vim一樣,當然你也可以新增vim,除此之外新增一個httpd。每新增一個軟體就是一個獨立的層次。上圖是三層,最底下的bootfs層在容器啟動時,一旦被引導完了就會被解除安裝並移除的(這裡的移除並不是刪除檔案,而是從記憶體中移除),因此真正的使用者空間執行的只有add Apache,add emacs,Debian這三層,而這三層的層級關係是:最底層的被稱為Base Image(通常用來構建一個系統的基本組成,就是上面我們看到的bin,sbin,usr等這樣的目錄,但是他是最小化的,沒有你所依賴的應用程式,如果我們要用到某個額外的應用工具的話,需要在上面執行安裝操作)。比如我們要最小化安裝一個centos,接下來我們要用vim,那麼就執行yum install vim就完了。但是對於我們的映象來講,底層的映象本來就是個最小安裝的映象,他是不會動的,你去額外安裝一個vim,他會在這個系統之上新生成一個層次。這個層次可以理解為vim層,只包含vim。如果我們再yum install nginx就又生成一個nginx層。這就是三層。隨後我們要啟動nginx需要啟動,要把這三個層都啟動起來,首先先啟動最底層,掛載最底層。在最底層的基礎之上掛載第二層然後在掛載第三層,他們是疊加在一起掛載的。所以我們稱為聯合掛載。而後者三層都是隻讀的。容器啟動完成以後,如果某一個程序需要建立一些臨時檔案之類的,他應該放在tmp目錄下對吧?事實上tmp所在的底層 基礎映象是不允許編輯的,如果我們要想進行編輯或者是支援編輯的,只能是最上層就是圖中寫著writable container的。這一層才是容器自有的,底下那層都是可供多個基於一個映象啟動的容器所共享的層次。
因此對一個容器來講,他的所有寫操作,僅能夠在最上面這個writable層次上來實現。而且如果刪除了容器,這個writable也會被刪除的。docker rm或者docker container rm來刪除docker容器,當我們刪除容器以後,這個容器自有的可寫層一定會被刪除的。
2.3 docker的檔案系統
docker映象的這種分層構建和聯合掛載依賴於專有檔案系統的支撐才能實現,而早起用到的專有檔案系統叫做Aufs
- Aufs
因為這個Aufs程式碼很爛,幾萬行,這個作者每次寫完都去申請加入核心中,但是一直被拒絕,後來一氣之下就不在申請了。所以Aufs一直都不是核心中自有的檔案系統,想用需要自己去向核心打補丁並且編譯使用它, 很遺憾的是centos是紅帽發行的,一般不會幹這種出格的事,因為他是是以保守穩定著稱的。因此在centos系列的系統上,想使用Aufs這種聯合掛載檔案系統是不可能的。而Ubuntu是略微激進點的,Ubuntu Server是很早一批就把Aufs打包進核心當中去的。隨著他的發行版直接提供補丁過的核心。因此早起我們要使用docker沒有很好的選擇,要使用UbuntuServer。
Aufs的競爭產品叫overlayfs,overlay的中文意思是疊加,從3.18版本已經被合併到Linux核心
但是問題是早期centos不支援Aufs和overlayfs時候怎麼辦呢?所以除了Aufs外還支援btrfs,devicemapper(簡稱是dm,是紅帽牽頭來維護一個核心模組)和vfs檔案系統等。
LVM2用的一定是dm,包括他的多路徑功能用的都是dm模組。因此docker支援dm,那麼紅帽就應該在他的系統上推動使用dm來作為解決方案。所以在早些時候centos7使用的就是dm,但是現在我們新版的docker能夠啟用overlay2。有人做過overlay2和dm的測試,dm在使用聯合掛載方面效能很差,因為他使用了叫超重的方式來實現, 而且非常不穩定。
- Devicemapper
dm我們就不詳細介紹了。那麼我們需要知道有這麼個東西就行
同時映象要實現分層構建聯合掛載就需要支援overlay2
overlay2是一種抽象的二級檔案系統,他需要建構於本地檔案系統之上。後端:xfs。前段:overlay2
2.4 Docker Registry
2.4.1 Registry的概述
Registry如果沒有特別的指定,通常就是指docker Hub,如果要指向別的Registry,我們必須在映象的訪問路徑當中給明伺服器地址,如果沒給伺服器地址,只是指明瞭Tag,那麼這個映象一定是Docker Hub上的映象。
後面我們將介紹一個非常著名的開源的docker Registry是由vmware提供的叫harbor
2.4.2 Registry分類
- Sponsor Registry:捐助者
- Mirror Registry:例如docker cn加速,阿里雲的docker加速器,也可以稱為映象Registry
- Vendor Registry:服務商的Registry,比如紅帽的Registry,但是並不需開放使用,一般提供給買了紅帽作業系統服務的。
- Private Registry:自建Registry,好處是不消耗網際網路頻寬。而且Docker Hub上的很多映象我們都用不了。因為要修改一些配置檔案,當然不僅僅是為了改配置檔案。後面再說吧。
2.4.3 Registry 的組成部分
2.4.4 Docker Registry中的映象來源
如上圖所示,不同的環境中的映象裡面的配置還是不同的。所以我們還有不同配置的同一個映象,如果配置資訊通過製作映象的方式來做,將會非常頭疼
因此現在有一個術語:“雲原生”。比如我們要寫C程式要針對C環境進行開發。雲原生就是面向雲環境去執行一個程式,而調雲系統本身既有的功能而開發應用程式。他就是為雲端計算環境而生的。
因此我們把那些單機程式託管到容器雲上去執行,會有很多的問題和不便,最大的不便就是改配置檔案很麻煩。
那些雲原生開發的程式,會使得對雲端計算這麼一個應用程式怎麼配置更方便,用那種配置介面提供所謂的配置邏輯。
而容器本來就加了一層外殼,我們操作裡面的資料是不方便的。所以後來人們就想:向容器啟動時,傳環境變數來傳資訊。而後你的配置檔案應該是容器啟動時,從環境變數中載入,自動注入到配置檔案中,而生成的。這是早起常用的解決方案。也就是說我們通過環境變數來配置容器的啟動。
但是nginx表示我們很少能接收到環境變數後自動的將她注入到配置檔案中。所以nginx不是雲原生。
而云原生都是通過向環境變數獲取資料來配置檔案的。而不是自己非要修改配置檔案引數來配置的。
多數情況下我們做映象應該基於被人已存在的一個應用的基礎映象來實現的,我們把其成為base image
而這個基礎映象從何而來呢?一般是docker Hub工作人員製作的。
2.4.5 docker Hub
在docker Hub之上如果你登陸後在裡面會發現下圖所示的幾個標籤
這幾個紅色標籤分別表示了他們的不同功能:
- Image Repositories:映象倉庫
- Automated Builds:自動構建,dockerfile是構建映象的檔案,後面重點講
- Webhooks:是自動構建功能的一種特性,特徵。和上面是有關聯性的
- Organizations:組織。可以建立一個工作組,大家協同工作
- GitHub and Bitbucket Integration:可以於GitHub 和Bitbucket進行整合
2.4.6 Registry的拉取
拉取映象使用docker pull命令
docker pull <registry>[:<port>]/[<namespace>/]<name>:<tag>
其中registry、port、namespace可省略
registry:是一個倉庫的web地址,如果不使用預設的docker hub倉庫,需要指明倉庫地址
port:是倉庫web地址的埠號,預設使用443
namespace:代表是哪個使用者的倉庫,如果映象是頂級倉庫,namespace就是可省略的,namespace分為三類
name:倉庫的名字,和tag一起標識了一個唯一的映象
tag:映象的標籤,沒有就代表是一個映象的最新版
其中,nginx為頂層倉庫,jwilder/nginx-proxy為使用者的倉庫
例如:
docker pull nginx:1.14 # 沒有指倉庫地址預設從docker hub上下載nginx1.14版本到本地 docker pull quay.io/coreos/flannel:v0.10.0-amd64 # 從quay上拉取鏡
世界上除了docker Hub還有很多可用的倉庫伺服器,比如著名的quay.io這個站點,這是由QuayOS所維護的第三方的映象倉庫,非常著名!!!!
然後我們搜尋flannel
這是非常重要的,將來可能在k8s上要用到的映象
但是他不是預設的映象倉庫,我們要下載必須要指定這種格式的命令,如下圖紅色框內所示的命令。
其中的quay.io是伺服器地址,埠沒指定預設就是443,因為是通過https協議來獲取的
coreos指的是:使用者名稱,就是所謂名稱空間中的名字,不是頂層倉庫
flannel指的是倉庫名,如果不加Tag預設就是latest,檢視標籤請看下圖所示。
報錯說沒找到lastet,所以我們要加上Tag的。
下載好的映象即帶伺服器地址又帶名稱空間還有倉庫自己的名稱,除非來自docker Hub我們不需要標註,否則預設都被docker識別為docker Hub之上。
2.5 映象相關的操作
2.5.1映象製作的兩種方式
docker映象的製作有兩種方式:
- 用Dockerfile我們自己使用一個命令叫docker build命令,這是專門做映象的
- 基於容器來做:比如某個容器我們已經啟動並處於運行當中,我們使用docker commit命令,會把容器最上面的可寫層單獨建立成一個映象層
- 在Docker Hub上有一個automated builds(其實還是基於dockerfile來實現的
2.5.2 基於容器製作映象
先啟動一個容器並在容器中做好你打算做的修改,比如我們啟動一個簡單centos,在centos之上使用yum install 安裝nginx,而後把安裝生成nginx檔案的這生成的writable可寫層單獨做成映象使用docker commit命令來做就行了。
案例:把busybox加上一個html目錄並建立一個index的網頁,把這個結果做成映象
1.先啟動busybox容器
2.建立html目錄並在這個目錄下建立一個網頁
加入下面的內容
3.下面我們要儲存我們所做的改變,說以不要關閉容器,讓容器處於執行狀態,因為一關閉下次在啟動就沒有了。
使用docker commit 命令製作映象
CONTAINER:基於哪個容器做映象
[REPOSITORY[:TAG]]:做完這個映象屬於哪個倉庫並擁有什麼標籤,這個是可以省略的,如果省略就表示做出來的映象是本地的裸映象不屬於任何倉庫也沒有任何標籤
當我們使用docker commit命令的時候 應用程式還在執行還在不斷的生成新檔案很有可能儲存下來得檔案是一半的,所以為了避免這種情況,可以使用-p選項讓其暫停(做映象的過程儘可能的讓容器暫停下來)
4.檢視結果
可以看出他的IMAGE ID跟上上圖中的sha256是其開頭的部分
給映象打標籤:
5.為了方便管理我們還是給其加上標籤
使用docker tag命令,是標籤管理命令可以給哪個映象打上哪個標籤,這個標籤可以是他所屬的倉庫名和標籤名,如果是引用的映象,他本身已經有標籤了,我們可以在其基礎上再打一個標籤。一個映象是可以有多個標籤的。如果這個映象一個標籤都沒有,那麼我們只能使用ID來引用他
假設我們github上有個mageedu,我們期待把它上傳到github上的mageedu下的叫做httpd的倉庫中,打個標籤叫v0.1-1
我們還可以給他在打個標籤
其ID實一模一樣的
刪除一個標籤,如果還有其他標籤的時候,這個映象是不會被真刪的,只是刪除了一個引用
其實我們在做映象的時候可以同時打標籤的。
這次我們重新做個映象
之前我們講過映象定義了基於此映象啟動容器時預設要執行的程式
其中的cmd表示基於此映象啟動容器預設要執行的什麼命令
所以上面就表明了為什麼要執行shell的原因
我們在看一下nginx的預設命令
表示讓nginx執行在前臺
我們之前解釋過,因為這個容器只執行單個程式,所以這個程式必須要執行在前臺,否則一啟動就到後臺去,那麼就認為這個程式就結束了。容器也就自動轉為停止狀態了。
如果我們期望在建立映象時,改變原來映象中的預設執行命令:
下面我們來看一下我們自己做的映象:
所以說我們改變的東西都還在,但是現在沒有改變預設要執行的命令
改變容器啟動時候預設要執行的命令:
假如我們不想讓容器啟動的時候執行shell,而是預設執行httpd
httpd有一個對應的選項 -f 表示執行在前臺,-h則指明他的網頁檔案的根目錄,不指定就是當前目錄
我們需要修改的只是docker commit的時候額外加一項 -c 意思就是修改原有基礎映象要執行的命令也稱Dockerfile指令
我們這裡簡單一點,只是修改裡面的CMD。所以方法很簡單,還可以加上作者-a
注意CMD一定要大寫的。加上我們要給的指令,我們這裡給他一個列表用 [ 括起來的列表
這裡我們先看一下httpd在哪
-f 表示執行在前臺
-h 則指明他的網頁檔案的根目錄
-p表示製作時先讓容器處於暫停狀態
而後我們要基於b1來做
做完以後映象直接取名叫mageedu/httpd:v0.2
下面我們基於v0.2啟動一個容器看一下效果:
可以看到沒有什麼資訊,因為它不是互動式介面,因為預設的shell被我們改成httpd了
此時我們換個終端
可以看到地址,然後我們使用curl直接訪問這個地址
到這裡我們就完成了基於busybox做一個預設就執行很微型的web伺服器的映象就這麼完成了!
把製作好的映象推到docker Hub中:
我們做好了,想共享給別人用我們可以放到我們的倉庫上,比如docker Hub,當然要確保有docker Hub的賬號
我們要確保我們有一個剛打了標籤的叫httpd的倉庫,這裡我們新建一個倉庫
如果是私有,那麼只有我們登陸之後自己才能訪問,這裡我們選擇public
到此倉庫就建立完成了。我們要把映象推到這裡來
注意:本地的標籤一定要跟遠端倉庫的名稱一定要保持一致,才能推上來
推映象我們使用docker pull命令
我們要指定標籤,如果不指定標籤也可以使用該命令的-a,把該映象的所有標籤都推上來
但是在推之前有可能讓你進行登陸,不登入對著倉庫沒有訪問許可權
所以我們使用docker login這個命令
所以我們先登陸docker Hub,如果是別的伺服器要指定server
返回Login Succeeded表示登陸成功
下面我們開始推送映象到docker Hub(注意如果你不是推送到docker Hub,必須!要跟上伺服器地址,下面還有個案例是講阿里雲的docker倉庫)
這樣就推送成功了
下面是筆記的截圖部分:
建議國內大家使用阿里雲的docker Hub比較快
注意重啟docker才會生效
把製作好的映象推到aliyun Hub中:
之前我們使用的docker CN的加速器,現在我們把阿里雲的配置進去
登陸阿里雲是一個賬號,但是倉庫的字首(即名稱空間)是可以自己定義的
上圖表示映象從哪來,來自於我們的本地倉庫。
選擇其他的話就表示要基於這些程式碼倉庫的dockerfile自動觸發自動構建的。
上圖不是我們的操作步驟
然後我們點選“管理”
我們要pull的時候選擇下圖的標籤字首來使用:
注意我們的阿里雲賬號的密碼不是我們使用aliyun映象倉庫的密碼,需要獨立設定的。這裡不多說
現在我們開始推送映象到aliyun,注意標籤字首要跟對方提供給我們的倉庫名稱和對應的倉庫訪問路徑一致才行
到這裡就推送ok了。出現下圖即為成功!!!
可以掃面一下看看有沒有問題,因為前一段時間有人想docke Hub上傳了很多映象,裡面有挖礦程式碼,所以很多人使用它們的映象後被人拿去挖礦了。所以不要隨意下不熟悉使用者上傳的映象,要使用官方的。
映象的匯入docker load和匯出docker save
假設我們有兩個伺服器node01和node02
假設02想用剛才自己做的映象怎麼辦?
第一我們把這個映象推到一個公共的位置,第二node02使用docker pull拖下來就能用了
但是這樣還是很麻煩,假設我們是測試用的。我在01上做完,我想在02上跑一下
這裡還有個更簡單的辦法,我們可以在已有映象元件的基礎上把映象打包,打包成一個壓縮檔案,到另外一個主機上再把它裝了就行了。
docker save命令叫儲存打包檔案
docker load命令 可以從打包檔案給他直接裝入
而且一次打包出來可以打包多個檔案
下面開始打包
-o 表示輸出到何處
在當前路徑下就有剛打包好的檔案了。咱們可以通過SCP或者其他的檔案共享方式到node02主機上就ok了
因為沒有docker所以我們按照下圖快速安裝一個docker
這時候我們去node02,快速安裝一下docker
先在node02上建好docker配置檔案目錄
再把配置檔案發給node02
然後我們在node02執行下面命令啟動docker服務
下面我們使用docker load命令
-i 指明從哪個檔案進行load
這是屬於映象分發的另外一種方式:直接使用save打包。用檔案共享的方式共享過去,讓別人執行load。
但是這種方式有個缺陷,當我們使用docker run的時候,如果沒有映象還是要到伺服器上去進行下載,因此像這種方式我們必須要先準備好本地映象
否則他在使用docker pull的時候,一定還是到映象應該本身所屬的位置去執行pull操作的。
下一篇文章連結:docker容器技術之虛擬化網路概述(四)