聊聊Docker中容器的創建與啟停問題

1. 鏡像和容器

看待鏡像和容器的一種方式是將它們類比成程序與進程。一個進程可以視為一個被執行的應用程序,同樣,一個Docker容器可以視為一個運行中的Docker鏡像。

標題Docker鏡像與容器

如果大傢熟悉面向對象原理,看待鏡像和容器的另一種方法是將鏡像看作類而將容器看作對象。對象是類的具體實例,同樣,容器是鏡像的實例。用戶可以從單個鏡像創建多個容器,就像對象一樣,它們之間全都是相互隔離的。不論用戶在對象內修改瞭什麼,都不會影響類的定義——它們從根本上就是不同的東西。

2. 新建並啟動容器

首先,我們會查看Docker是否能正常工作,然後學習基本的Docker的工作流:創建並管理容器。我們將瀏覽容器的典型生命周期:從創建、管理到停止,直到最終刪除。 第一步,查看docker程序是否存在,功能是否正常:

[root@localhost ~]# sudo docker info
Containers: 1
Images: 8
Storage Driver: aufs
    Root Dir: /var/lib/docker/aufs
    Backing Filesystem: extfs
    Dirs: 10
Execution Driver: native-0.2
Kernel Version: 3.13.0-43-generic
Operating System: Ubuntu 14.04.2 LTS
CPUs: 1
Total Memory: 994 MiB
Name: riemanna
ID: DOIT:XN5S:WNYP:WP7Q:BEUP:EBBL:KGIX:GO3V:NDR7:YW6E:VFXT:FXHM WARNING: No swap limit support

在這裡我們調用瞭docker可執行程序的info命令,該命令會返回所有容器和鏡像(鏡像即是Docker用來構建容器的“構建塊”)的數量、Docker使用的執行驅動和存儲驅動(execution and storage driver),以及Docker的基本配置。

Docker是基於客戶端-服務器構架的。它有一個docker程序,既能作為客戶端,也可以作為服務器端。作為客戶端時,docker程序向Docker守護進程發送請求(如請求返回守護進程自身的信息),然後再對返回的請求結果進行處理。

現在,讓我們嘗試啟動第一個Docker容器。我們可以使用docker run命令創建容器。 docker run命令提供瞭Docker容器的創建到啟動的功能:

[root@localhost ~]# sudo docker run -i -t ubuntu /bin/bash
Unable to find image 'ubuntu' locally
ubuntu:latest: The image you are pulling has been verified 511136ea3c5a: Pull complete
d497ad3926c8: Pull complete
ccb62158e970: Pull complete
e791be0477f2: Pull complete
3680052c0f5c: Pull complete
22093c35d77b: Pull complete
5506de2b643b: Pull complete
Status: Downloaded newer image for ubuntu:latest
root@fcd78e1a3569:/#

官方文檔列出瞭完整的Docker命令列表,也可以使用docker help獲取這些命令。此外,還可以使用Docker的man頁(即執行man docker-run)。

[root@localhost ~]# sudo docker run -i -t ubuntu /bin/bash

上述命令中:

上述命令中:

        -t  選項讓Docker分配一個偽終端(pseudo-tty)並綁定到容器的標準輸入上,
        -i  則讓容器的標準輸入保持打開。
利用docker run來創建並啟動容器時,Docker在後臺運行的標準操作包括:
        ·檢查本地是否存在指定的鏡像,不存在就從公有倉庫下載;
        ·利用鏡像創建一個容器,並啟動該容器;
        ·分配一個文件系統給容器,並在隻讀的鏡像層外面掛載一層可讀寫層;
        ·從宿主主機配置的網橋接口中橋接一個虛擬接口到容器中;
        ·從網橋的地址池配置一個IP地址給容器;
        ·執行用戶指定的應用程序;
        ·執行完畢後容器被自動終止。

官方文檔上列出瞭docker run命令的所有標志,此外還可以用命令docker help run查看這些標志。或者,也可以用Docker的man頁(也就是執行man docker-run命令)。

接下來,我們告訴Docker基於什麼鏡像來創建容器,示例中使用的是ubuntu鏡像。ubuntu鏡像是一個常備鏡像,也可以稱為“基礎”(base)鏡像,它由Docker公司提供,保存在Docker HubRegistry上。可以以ubuntu基礎鏡像(以及類似的fedora、debian、centos等鏡像)為基礎,在選擇的操作系統上構建自己的鏡像。到目前為止,我們基於此基礎鏡像啟動瞭一個容器,並且沒有對容器增加任何東西。

首先Docker會檢查本地是否存在ubuntu鏡像,如果本地還沒有該鏡像的話,那麼Docker就會連接官方維護的Docker Hub Registry,查看Docker Hub中是否有該鏡像。Docker一旦找到該鏡像,就會下載該鏡像並將其保存到本地宿主機中。 隨後,Docker在文件系統內部用這個鏡像創建瞭一個新容器。該容器擁有自己的網絡、IP地址,以及一個用來和宿主機進行通信的橋接網絡接口。最後,我們告訴Docker在新容器中要運行什麼命令,在本例中我們在容器中運行/bin/bash命令啟動瞭一個Bash shell。 當容器創建完畢之後,Docker就會執行容器中的/bin/bash命令,這時就可以看到容器內的shell瞭,如下:

root@f7cbdac22a02:/#

3. 使用第一個容器

現在,我們已經以root用戶登錄到瞭新容器中,容器的ID f7cbdac22a02,乍看起來有些令人迷惑的字符串`。這是一個完整的Ubuntu系統,可以用它來做任何事情。下面就來研究一下這個容器。首先,我們可以獲取該容器的主機名,如下:

root@f7cbdac22a02:/# hostname 
f7cbdac22a02

可以看到,容器的主機名就是該容器的ID。再來看看/etc/hosts文件內容:

root@f7cbdac22a02:/# cat /etc/hosts
172.17.0.4 f7cbdac22a02
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

Docker已在hosts文件中為該容器的IP地址添加瞭一條主機配置項。 再來看看容器的網絡配置情況,如下:

root@f7cbdac22a02:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 1500 qdisc noqueue state
    UNKNOWN group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
899: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast
    state UP group default qlen 1000
link/ether 16:50:3a:b6:f2:cc brd ff:ff:ff:ff:ff:ff
inet 172.17.0.4/16 scope global eth0
inet6 fe80::1450:3aff:feb6:f2cc/64 scope link valid_lft forever preferred_lft forever

可以看到,這裡有lo的環回接口,還有IP為172.17.0.4的標準 eth0網絡接口,和普通宿主機是完全一樣的。我們還可以查看容器中運行的進程,如下:

root@f7cbdac22a02:/# ps -aux
USER PID %CPU %MEM    VSZ RSS TTY    STAT START TIME COMMAND
root    1 0.0 0.0    18156 1936 ?    Ss    May30 0:00 /bin/bash 
root    21 0.0 0.0   15568 1100 ?    R+    02:38 0:00 ps -aux

接下來嘗試安裝一個軟件包:

root@f7cbdac22a02:/# apt-get update && apt-get install vim

通過上述命令,就在容器中安裝瞭Vim編輯器軟件。 用戶可以繼續在容器中做任何自己想做的事情。當所有工作都結束時,輸入exit,就可以返回到Ubuntu宿主機的命令行提示符瞭。 但是,容器現在已經停止運行瞭!隻有在指定的/bin/bash命令處於運行狀態的時候,我們的容器也才會相應地處於運行狀態。一旦退出容器,/bin/bash命令也就結束瞭,這時容器也隨之停止瞭運行。

但容器仍然是存在的,可以用docker ps -a命令查看當前系統中容器的列表,如下:

CONTAINER ID IMAGE     COMMAND    CREATED  STATUS PORTS NAMES
1cd57c2cdf7f ubuntu:14.04 "/bin/bash" A minute Exited
    gray_cat

默認情況下,當執行docker ps命令時,隻能看到正在運行的容器。如果指定-a標志的話,那麼docker ps命令會列出所有容器,包括正在運行的和已經停止的。 註意:也可以為docker ps命令指定-l標志,列出最後一個運行的容器,無論其正在運行還是已經停止。也可以通過–format標志,進一步控制顯示哪些信息,以及如何顯示這些信息

從該命令的輸出結果中我們可以看到關於這個容器的很多有用信息:ID、用於創建該容器的鏡像、容器最後執行的命令、創建時間以及容器的退出狀態(在上面的例子中,退出狀態是0,因為容器是通過正常的exit命令退出的)。我們還可以看到,每個容器都有一個名稱。 有3種方式可以唯一指代容器:短UUID(如f7cbdac22a02)、長UUID(如f7cbdac22a02e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778)或者名稱(如gray_cat)。

4. 容器命名

Docker會為我們創建的每一個容器自動生成一個隨機的名稱。例如,上面我們剛剛創建的容器就被命名為gray_cat。如果想為容器指定一個名稱,而不是使用自動生成的名稱,則可以用–name標志來實現,如下:

[root@localhost ~]# sudo docker run --name bob_the_container -i -t ubuntu /bin/bash 
root@aa3f365f0f4e:/# exit

上述命令將會創建一個名為bob_the_container的容器。一個合法的容器名稱隻能包含以下字符:小寫字母a~z、大寫字母A~Z、數字 0~9、下劃線、圓點、橫線(如果用正則表達式來表示這些符號,就是[a-zA-Z0-9_.-])

在很多Docker命令中,都可以用容器的名稱來替代容器ID,後面我們將會看到。容器名稱有助於分辨容器,當構建容器和應用程序之間的邏輯連接時,容器的名稱也有助於從邏輯上理解連接關系。具體的名稱(如web、db)比容器ID和隨機容器名好記多瞭。我推薦大傢都使用容器名稱,以更加方便地管理容器。 容器的命名必須是唯一的。如果試圖創建兩個名稱相同的容器,則命令將會失敗。如果要使用的容器名稱已經存在,可以先用docker rm命令刪除已有的同名容器後,再來創建新的容器。

5.重啟容器

容器已經停止瞭,我們可以用下面的命令重新啟動一個已經停止的容器,如下:

[root@localhost ~]# sudo docker start bob_the_container

除瞭容器名稱,也可以用容器ID來指定容器,

[root@localhost ~]# sudo docker start aa3f365f0f4e

也可以使用docker restart命令來重新啟動一個容器。 這時運行不帶-a標志的docker ps命令,就應該看到我們的容器已經開始運行瞭。 類似地,Docker也提供瞭docker create命令來創建一個容器,但是並不運行它。這讓我們可以在自己的容器工作流中對其進行精準化的控制。

6. 附著到容器上

Docker容器重新啟動的時候,會沿用docker run命令時指定的參數來運行,因此我們的容器重新啟動後會運行一個交互式會話shell。此外,也可以用docker attach命令,重新附著到該容器的會話上,如下:

[root@localhost ~]# sudo docker attach bob_the_container

也可以使用容器ID,重新附著到容器的會話上,如下:

[root@localhost ~]# sudo docker attach aa3f365f0f4e

現在,又重新回到瞭容器的Bash提示符,如下:

root@aa3f365f0f4e:/_#_

可能需要按下回車鍵才能進入該會話。 如果退出容器的shell,容器會再次停止運行。

容器是直接提供應用服務的組件,也是Docker實現快速啟停和高效服務性能的基礎。 在生產環境中,因為容器自身的輕量級特性,推薦大傢使用容器時在一組容器前引入HA(High Availability,高可靠性)機制。例如使用HAProxy工具來代理容器訪問,這樣在容器出現故障時,可以快速切換到功能正常的容器。此外,建議通過指定合適的容器重啟策略,來自動重啟退出的容器。

到此這篇關於Docker中容器的創建與啟停的文章就介紹到這瞭,更多相關docker容器創建內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: