docker快速學(xué)習(xí)筆記

[TOC]

1. Docker 簡(jiǎn)介

1.1 為什么使用Docker

為什么要使用 Docker?

作為一種新興的虛擬化方式,Docker 跟傳統(tǒng)的虛擬化方式相比具有眾多的優(yōu)勢(shì)。

首先,Docker 容器的啟動(dòng)可以在秒級(jí)實(shí)現(xiàn),這相比傳統(tǒng)的虛擬機(jī)方式要快得多。 其次,Docker 對(duì)系統(tǒng)資源的利用率很高,一臺(tái)主機(jī)上可以同時(shí)運(yùn)行數(shù)千個(gè) Docker 容器。

容器除了運(yùn)行其中應(yīng)用外,基本不消耗額外的系統(tǒng)資源,使得應(yīng)用的性能很高,同時(shí)系統(tǒng)的開(kāi)銷盡量小。傳統(tǒng)虛擬機(jī)方式運(yùn)行 10 個(gè)不同的應(yīng)用就要起 10 個(gè)虛擬機(jī),而Docker 只需要啟動(dòng) 10 個(gè)隔離的應(yīng)用即可。

具體說(shuō)來(lái),Docker 在如下幾個(gè)方面具有較大的優(yōu)勢(shì)。

更快速的交付和部署

對(duì)開(kāi)發(fā)和運(yùn)維(devop)人員來(lái)說(shuō),最希望的就是一次創(chuàng)建或配置,可以在任意地方正常運(yùn)行。

開(kāi)發(fā)者可以使用一個(gè)標(biāo)準(zhǔn)的鏡像來(lái)構(gòu)建一套開(kāi)發(fā)容器,開(kāi)發(fā)完成之后,運(yùn)維人員可以直接使用這個(gè)容器來(lái)部署代碼。 Docker 可以快速創(chuàng)建容器,快速迭代應(yīng)用程序,并讓整個(gè)過(guò)程全程可見(jiàn),使團(tuán)隊(duì)中的其他成員更容易理解應(yīng)用程序是如何創(chuàng)建和工作的。 Docker 容器很輕很快!容器的啟動(dòng)時(shí)間是秒級(jí)的,大量地節(jié)約開(kāi)發(fā)、測(cè)試、部署的時(shí)間。

更高效的虛擬化

Docker 容器的運(yùn)行不需要額外的 hypervisor 支持,它是內(nèi)核級(jí)的虛擬化,因此可以實(shí)現(xiàn)更高的性能和效率。

更輕松的遷移和擴(kuò)展

Docker 容器幾乎可以在任意的平臺(tái)上運(yùn)行,包括物理機(jī)、虛擬機(jī)、公有云、私有云、個(gè)人電腦、服務(wù)器等。 這種兼容性可以讓用戶把一個(gè)應(yīng)用程序從一個(gè)平臺(tái)直接遷移到另外一個(gè)。

更簡(jiǎn)單的管理

使用 Docker,只需要小小的修改,就可以替代以往大量的更新工作。所有的修改都以增量的方式被分發(fā)和更新,從而實(shí)現(xiàn)自動(dòng)化并且高效的管理。

對(duì)比傳統(tǒng)虛擬機(jī)總結(jié)

特性 容器 虛擬機(jī)
啟動(dòng) 秒級(jí) 分鐘級(jí)
硬盤使用 一般為 MB 一般為 GB
性能 接近原生 弱于
系統(tǒng)支持量 單機(jī)支持上千個(gè)容器 一般幾十個(gè)

2. 基本概念

Docker 包括三個(gè)基本概念

  • 鏡像(Image)
  • 容器(Container)
  • 倉(cāng)庫(kù)(Repository)

理解了這三個(gè)概念,就理解了 Docker 的整個(gè)生命周期。

2.1 Docker 鏡像

Docker 鏡像就是一個(gè)只讀的模板。

例如:一個(gè)鏡像可以包含一個(gè)完整的 ubuntu 操作系統(tǒng)環(huán)境,里面僅安裝了 Apache 或用戶需要的其它應(yīng)用程序。

鏡像可以用來(lái)創(chuàng)建 Docker 容器。

Docker 提供了一個(gè)很簡(jiǎn)單的機(jī)制來(lái)創(chuàng)建鏡像或者更新現(xiàn)有的鏡像,用戶甚至可以直接從其他人那里下載一個(gè)已經(jīng)做好的鏡像來(lái)直接使用。

2.2 Docker 容器

Docker 利用容器來(lái)運(yùn)行應(yīng)用。

容器是從鏡像創(chuàng)建的運(yùn)行實(shí)例。它可以被啟動(dòng)、開(kāi)始、停止、刪除。每個(gè)容器都是相互隔離的、保證安全的平臺(tái)。

可以把容器看做是一個(gè)簡(jiǎn)易版的 Linux 環(huán)境(包括root用戶權(quán)限、進(jìn)程空間、用戶空間和網(wǎng)絡(luò)空間等)和運(yùn)行在其中的應(yīng)用程序。

*注:鏡像是只讀的,容器在啟動(dòng)的時(shí)候創(chuàng)建一層可寫(xiě)層作為最上層。

2.3 Docker 倉(cāng)庫(kù)

倉(cāng)庫(kù)是集中存放鏡像文件的場(chǎng)所。有時(shí)候會(huì)把倉(cāng)庫(kù)和倉(cāng)庫(kù)注冊(cè)服務(wù)器(Registry)混為一談,并不嚴(yán)格區(qū)分。實(shí)際上,倉(cāng)庫(kù)注冊(cè)服務(wù)器上往往存放著多個(gè)倉(cāng)庫(kù),每個(gè)倉(cāng)庫(kù) 中又包含了多個(gè)鏡像,每個(gè)鏡像有不同的標(biāo)簽(tag)。

倉(cāng)庫(kù)分為公開(kāi)倉(cāng)庫(kù)(Public)和私有倉(cāng)庫(kù)(Private)兩種形式。

最大的公開(kāi)倉(cāng)庫(kù)是 Docker Hub,存放了數(shù)量龐大的鏡像供用戶下載。 國(guó)內(nèi)的公開(kāi)倉(cāng)庫(kù)包括Docker Pool 等,可以提供大陸用戶更穩(wěn)定快速的訪問(wèn)。

當(dāng)然,用戶也可以在本地網(wǎng)絡(luò)內(nèi)創(chuàng)建一個(gè)私有倉(cāng)庫(kù)。

當(dāng)用戶創(chuàng)建了自己的鏡像之后就可以使用 push 命令將它上傳到公有或者私有倉(cāng)庫(kù),這樣下次在另外一臺(tái)機(jī)器上使用這個(gè)鏡像時(shí)候,只需要從倉(cāng)庫(kù)上 pull 下來(lái)就可以了。

*注:Docker 倉(cāng)庫(kù)的概念跟 Git 類似,注冊(cè)服務(wù)器可以理解為 GitHub 這樣的托管服務(wù)

3. 安裝

3.1 Ubuntu 系列安裝 Docker

通過(guò)系統(tǒng)自帶包安裝

Ubuntu 14.04 版本系統(tǒng)中已經(jīng)自帶了 Docker 包,可以直接安裝。

$ sudo apt-get update
$ sudo apt-get install -y docker.io
$ sudo ln -sf /usr/bin/docker.io /usr/local/bin/docker
$ sudo sed -i '$acomplete -F _docker docker' /etc/bash_completion.d/docker.io

如果使用操作系統(tǒng)自帶包安裝 Docker,目前安裝的版本是比較舊的 0.9.1。 要安裝更新的版本,可以通過(guò)使用 Docker 源的方式。
通過(guò)Docker源安裝最新版本

要安裝最新的 Docker 版本,首先需要安裝 apt-transport-https 支持,之后通過(guò)添加源來(lái)安裝。

$ sudo apt-get install apt-transport-https
$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
$ sudo bash -c "echo deb https://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list"
$ sudo apt-get update
$ sudo apt-get install lxc-docker

14.04 之前版本

如果是較低版本的 Ubuntu 系統(tǒng),需要先更新內(nèi)核。

$ sudo apt-get update
$ sudo apt-get install linux-image-generic-lts-raring linux-headers-generic-lts-raring
$ sudo reboot

然后重復(fù)上面的步驟即可。

安裝之后啟動(dòng) Docker 服務(wù)。

$ sudo service docker start

4. Docker 鏡像

在之前的介紹中,我們知道鏡像是 Docker 的三大組件之一。

Docker 運(yùn)行容器前需要本地存在對(duì)應(yīng)的鏡像,如果鏡像不存在本地,Docker 會(huì)從鏡像倉(cāng)庫(kù)下載(默認(rèn)是 Docker Hub 公共注冊(cè)服務(wù)器中的倉(cāng)庫(kù))。

本章將介紹更多關(guān)于鏡像的內(nèi)容,包括:

  • 從倉(cāng)庫(kù)獲取鏡像;
  • 管理本地主機(jī)上的鏡像;
  • 介紹鏡像實(shí)現(xiàn)的基本原理。

4.1 獲取鏡像

可以使用 docker pull 命令來(lái)從倉(cāng)庫(kù)獲取所需要的鏡像。

下面的例子將從 Docker Hub 倉(cāng)庫(kù)下載一個(gè) Ubuntu 12.04 操作系統(tǒng)的鏡像。

$ sudo docker pull ubuntu:12.04
Pulling repository ubuntu
ab8e2728644c: Pulling dependent layers
511136ea3c5a: Download complete
5f0ffaa9455e: Download complete
a300658979be: Download complete
904483ae0c30: Download complete
ffdaafd1ca50: Download complete
d047ae21eeaf: Download complete

下載過(guò)程中,會(huì)輸出獲取鏡像的每一層信息。

該命令實(shí)際上相當(dāng)于 $ sudo docker pull registry.hub.docker.com/ubuntu:12.04 命令,即從注冊(cè)服務(wù)器 registry.hub.docker.com 中的 ubuntu 倉(cāng)庫(kù)來(lái)下載標(biāo)記為 12.04 的鏡像。

有時(shí)候官方倉(cāng)庫(kù)注冊(cè)服務(wù)器下載較慢,可以從其他倉(cāng)庫(kù)下載。 從其它倉(cāng)庫(kù)下載時(shí)需要指定完整的倉(cāng)庫(kù)注冊(cè)服務(wù)器地址。例如

$ sudo docker pull dl.dockerpool.com:5000/ubuntu:12.04
Pulling dl.dockerpool.com:5000/ubuntu
ab8e2728644c: Pulling dependent layers
511136ea3c5a: Download complete
5f0ffaa9455e: Download complete
a300658979be: Download complete
904483ae0c30: Download complete
ffdaafd1ca50: Download complete
d047ae21eeaf: Download complete

完成后,即可隨時(shí)使用該鏡像了,例如創(chuàng)建一個(gè)容器,讓其中運(yùn)行 bash 應(yīng)用。

$ sudo docker run -t -i ubuntu:12.04 /bin/bash
root@fe7fc4bd8fc9:/#

4.2 列出本地鏡像

使用 docker images 顯示本地已有的鏡像。

$ sudo docker images
REPOSITORY       TAG      IMAGE ID      CREATED      VIRTUAL SIZE
ubuntu           12.04    74fe38d11401  4 weeks ago  209.6 MB
ubuntu           precise  74fe38d11401  4 weeks ago  209.6 MB
ubuntu           14.04    99ec81b80c55  4 weeks ago  266 MB
ubuntu           latest   99ec81b80c55  4 weeks ago  266 MB
ubuntu           trusty   99ec81b80c55  4 weeks ago  266 MB
...

在列出信息中,可以看到幾個(gè)字段信息

    來(lái)自于哪個(gè)倉(cāng)庫(kù),比如 ubuntu
    鏡像的標(biāo)記,比如 14.04
    它的 ID 號(hào)(唯一)
    創(chuàng)建時(shí)間
    鏡像大小

其中鏡像的 ID 唯一標(biāo)識(shí)了鏡像,注意到 ubuntu:14.04 和 ubuntu:trusty 具有相同的鏡像 ID,說(shuō)明它們實(shí)際上是同一鏡像。

TAG 信息用來(lái)標(biāo)記來(lái)自同一個(gè)倉(cāng)庫(kù)的不同鏡像。例如 ubuntu 倉(cāng)庫(kù)中有多個(gè)鏡像,通過(guò) TAG 信息來(lái)區(qū)分發(fā)行版本,例如 10.04、12.04、12.10、13.04、14.04 等。例如下面的命令指定使用鏡像 ubuntu:14.04 來(lái)啟動(dòng)一個(gè)容器。

$ sudo docker run -t -i ubuntu:14.04 /bin/bash

如果不指定具體的標(biāo)記,則默認(rèn)使用 latest 標(biāo)記信息。

4.3 創(chuàng)建鏡像

創(chuàng)建鏡像有很多方法,用戶可以從 Docker Hub 獲取已有鏡像并更新,也可以利用本地文件系統(tǒng)創(chuàng)建一個(gè)。
修改已有鏡像

先使用下載的鏡像啟動(dòng)容器。

$ sudo docker run -t -i training/sinatra /bin/bash
root@0b2616b0e5a8:/#

注意:記住容器的 ID,稍后還會(huì)用到。

在容器中添加 json 和 gem 兩個(gè)應(yīng)用。

root@0b2616b0e5a8:/# gem install json

當(dāng)結(jié)束后,我們使用 exit 來(lái)退出,現(xiàn)在我們的容器已經(jīng)被我們改變了,使用 docker commit 命令來(lái)提交更新后的副本。

$ sudo docker commit -m "Added json gem" -a "Docker Newbee" 0b2616b0e5a8 ouruser/sinatra:v2
4f177bd27a9ff0f6dc2a830403925b5360bfe0b93d476f7fc3231110e7f71b1c

其中,
-m 來(lái)指定提交的說(shuō)明信息,跟我們使用的版本控制工具一樣;
-a 可以指定更新的用戶信息;之后是用來(lái)創(chuàng)建鏡像的容器的 ID;
最后指定目標(biāo)鏡像的倉(cāng)庫(kù)名和 tag 信息。創(chuàng)建成功后會(huì)返回這個(gè)鏡像的 ID 信息。

使用 docker images 來(lái)查看新創(chuàng)建的鏡像。

$ sudo docker images
REPOSITORY          TAG     IMAGE ID       CREATED       VIRTUAL SIZE
training/sinatra    latest  5bc342fa0b91   10 hours ago  446.7 MB
ouruser/sinatra     v2      3c59e02ddd1a   10 hours ago  446.7 MB
ouruser/sinatra     latest  5db5f8471261   10 hours ago  446.7 MB

之后,可以使用新的鏡像來(lái)啟動(dòng)容器

$ sudo docker run -t -i ouruser/sinatra:v2 /bin/bash
root@78e82f680994:/#

利用 Dockerfile 來(lái)創(chuàng)建鏡像

使用 docker commit 來(lái)擴(kuò)展一個(gè)鏡像比較簡(jiǎn)單,但是不方便在一個(gè)團(tuán)隊(duì)中分享。我們可以使用 docker build 來(lái)創(chuàng)建一個(gè)新的鏡像。為此,首先需要?jiǎng)?chuàng)建一個(gè) Dockerfile,包含一些如何創(chuàng)建鏡像的指令。

新建一個(gè)目錄和一個(gè) Dockerfile

$ mkdir sinatra
$ cd sinatra
$ touch Dockerfile

Dockerfile 中每一條指令都創(chuàng)建鏡像的一層,例如:

# This is a comment
FROM ubuntu:14.04
MAINTAINER Docker Newbee 
RUN apt-get -qq update
RUN apt-get -qqy install ruby ruby-dev
RUN gem install sinatra

Dockerfile 基本的語(yǔ)法是

    使用#來(lái)注釋
    FROM 指令告訴 Docker 使用哪個(gè)鏡像作為基礎(chǔ)
    接著是維護(hù)者的信息
    RUN開(kāi)頭的指令會(huì)在創(chuàng)建中運(yùn)行,比如安裝一個(gè)軟件包,在這里使用 apt-get 來(lái)安裝了一些軟件

編寫(xiě)完成 Dockerfile 后可以使用 docker build 來(lái)生成鏡像。

$ sudo docker build -t="ouruser/sinatra:v2" .
Uploading context  2.56 kB
Uploading context
Step 0 : FROM ubuntu:14.04
 ---> 99ec81b80c55
Step 1 : MAINTAINER Newbee 
 ---> Running in 7c5664a8a0c1
 ---> 2fa8ca4e2a13
Removing intermediate container 7c5664a8a0c1
Step 2 : RUN apt-get -qq update
 ---> Running in b07cc3fb4256
 ---> 50d21070ec0c
Removing intermediate container b07cc3fb4256
Step 3 : RUN apt-get -qqy install ruby ruby-dev
 ---> Running in a5b038dd127e
Selecting previously unselected package libasan0:amd64.
(Reading database ... 11518 files and directories currently installed.)
Preparing to unpack .../libasan0_4.8.2-19ubuntu1_amd64.deb ...
Setting up ruby (1:1.9.3.4) ...
Setting up ruby1.9.1 (1.9.3.484-2ubuntu1) ...
Processing triggers for libc-bin (2.19-0ubuntu6) ...
 ---> 2acb20f17878
Removing intermediate container a5b038dd127e
Step 4 : RUN gem install sinatra
 ---> Running in 5e9d0065c1f7
. . .
Successfully installed rack-protection-1.5.3
Successfully installed sinatra-1.4.5
4 gems installed
 ---> 324104cde6ad
Removing intermediate container 5e9d0065c1f7
Successfully built 324104cde6ad

其中 -t 標(biāo)記來(lái)添加 tag,指定新的鏡像的用戶信息。 “.” 是 Dockerfile 所在的路徑(當(dāng)前目錄),也可以替換為一個(gè)具體的 Dockerfile 的路徑。

可以看到 build 進(jìn)程在執(zhí)行操作。它要做的第一件事情就是上傳這個(gè) Dockerfile 內(nèi)容,因?yàn)樗械牟僮鞫家罁?jù) Dockerfile 來(lái)進(jìn)行。 然后,Dockfile 中的指令被一條一條的執(zhí)行。每一步都創(chuàng)建了一個(gè)新的容器,在容器中執(zhí)行指令并提交修改(就跟之前介紹過(guò)的 docker commit 一樣)。當(dāng)所有的指令都執(zhí)行完畢之后,返回了最終的鏡像 id。所有的中間步驟所產(chǎn)生的容器都被刪除和清理了。

*注意一個(gè)鏡像不能超過(guò) 127 層

此外,還可以利用 ADD 命令復(fù)制本地文件到鏡像;用 EXPOSE 命令來(lái)向外部開(kāi)放端口;用 CMD 命令來(lái)描述容器啟動(dòng)后運(yùn)行的程序等。例如

# put my local web site in myApp folder to /var/www
ADD myApp /var/www
# expose httpd port
EXPOSE 80
# the command to run
CMD ["/usr/sbin/apachectl", "-D", "FOREGROUND"]

現(xiàn)在可以利用新創(chuàng)建的鏡像來(lái)啟動(dòng)一個(gè)容器。

$ sudo docker run -t -i ouruser/sinatra:v2 /bin/bash
root@8196968dac35:/#

還可以用 docker tag 命令來(lái)修改鏡像的標(biāo)簽。

$ sudo docker tag 5db5f8471261 ouruser/sinatra:devel
$ sudo docker images ouruser/sinatra
REPOSITORY          TAG     IMAGE ID      CREATED        VIRTUAL SIZE
ouruser/sinatra     latest  5db5f8471261  11 hours ago   446.7 MB
ouruser/sinatra     devel   5db5f8471261  11 hours ago   446.7 MB
ouruser/sinatra     v2      5db5f8471261  11 hours ago   446.7 MB

*注:更多用法,請(qǐng)參考 Dockerfile 章節(jié)。
從本地文件系統(tǒng)導(dǎo)入

要從本地文件系統(tǒng)導(dǎo)入一個(gè)鏡像,可以使用 openvz(容器虛擬化的先鋒技術(shù))的模板來(lái)創(chuàng)建: openvz 的模板下載地址為 templates 。

比如,先下載了一個(gè) ubuntu-14.04 的鏡像,之后使用以下命令導(dǎo)入:

sudo cat ubuntu-14.04-x86_64-minimal.tar.gz  |docker import - ubuntu:14.04

然后查看新導(dǎo)入的鏡像。

docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu              14.04               05ac7c0b9383        17 seconds ago      215.5 MB

上傳鏡像

用戶可以通過(guò) docker push 命令,把自己創(chuàng)建的鏡像上傳到倉(cāng)庫(kù)中來(lái)共享。例如,用戶在 Docker Hub 上完成注冊(cè)后,可以推送自己的鏡像到倉(cāng)庫(kù)中。

$ sudo docker push ouruser/sinatra
The push refers to a repository [ouruser/sinatra] (len: 1)
Sending image list
Pushing repository ouruser/sinatra (3 tags)

4.4 存出和載入鏡像

存出鏡像

如果要導(dǎo)出鏡像到本地文件,可以使用 docker save 命令。

$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu              14.04               c4ff7513909d        5 weeks ago         225.4 MB
...
$sudo docker save -o ubuntu_14.04.tar ubuntu:14.04

載入鏡像

可以使用 docker load 從導(dǎo)出的本地文件中再導(dǎo)入到本地鏡像庫(kù),例如

$ sudo docker load --input ubuntu_14.04.tar

$ sudo docker load < ubuntu_14.04.tar

這將導(dǎo)入鏡像以及其相關(guān)的元數(shù)據(jù)信息(包括標(biāo)簽等)。

4.5 移除本地鏡像

如果要移除本地的鏡像,可以使用 docker rmi 命令。注意 docker rm 命令是移除容器。

$ sudo docker rmi training/sinatra
Untagged: training/sinatra:latest
Deleted: 5bc342fa0b91cabf65246837015197eecfa24b2213ed6a51a8974ae250fedd8d
Deleted: ed0fffdcdae5eb2c3a55549857a8be7fc8bc4241fb19ad714364cbfd7a56b22f
Deleted: 5c58979d73ae448df5af1d8142436d81116187a7633082650549c52c3a2418f0

*注意:在刪除鏡像之前要先用 docker rm 刪掉依賴于這個(gè)鏡像的所有容器。

docker rm $(docker ps -a -q) 刪除所有容器

docker rmi $(docker images | awk '/^<none>/ {print $3}') 刪除tag為NONE的鏡像

docker rmi $(docker images | awk '{print $3}') 刪除所有鏡像

5. 容器

容器是 Docker 又一核心概念。

簡(jiǎn)單的說(shuō),容器是獨(dú)立運(yùn)行的一個(gè)或一組應(yīng)用,以及它們的運(yùn)行態(tài)環(huán)境。對(duì)應(yīng)的,虛擬機(jī)可以理解為模擬運(yùn)行的一整套操作系統(tǒng)(提供了運(yùn)行態(tài)環(huán)境和其他系統(tǒng)環(huán)境)和跑在上面 的應(yīng)用。

本章將具體介紹如何來(lái)管理一個(gè)容器,包括創(chuàng)建、啟動(dòng)和停止等

5.1 啟動(dòng)容器

新建并啟動(dòng)

所需要的命令主要為 docker run。

例如,下面的命令輸出一個(gè) “Hello World”,之后終止容器。

$ sudo docker run ubuntu:14.04 /bin/echo 'Hello world'
Hello world

下面的命令則啟動(dòng)一個(gè) bash 終端,允許用戶進(jìn)行交互。

$ sudo docker run -t -i ubuntu:14.04 /bin/bash
root@af8bae53bdd3:/#

其中,-t 選項(xiàng)讓Docker分配一個(gè)偽終端(pseudo-tty)并綁定到容器的標(biāo)準(zhǔn)輸入上, -i 則讓容器的標(biāo)準(zhǔn)輸入保持打開(kāi)。

當(dāng)利用 docker run 來(lái)創(chuàng)建容器時(shí),Docker 在后臺(tái)運(yùn)行的標(biāo)準(zhǔn)操作包括:

  • 檢查本地是否存在指定的鏡像,不存在就從公有倉(cāng)庫(kù)下載
  • 利用鏡像創(chuàng)建并啟動(dòng)一個(gè)容器
  • 分配一個(gè)文件系統(tǒng),并在只讀的鏡像層外面掛載一層可讀寫(xiě)層
  • 從宿主主機(jī)配置的網(wǎng)橋接口中橋接一個(gè)虛擬接口到容器中去
  • 從地址池配置一個(gè) ip 地址給容器
  • 執(zhí)行用戶指定的應(yīng)用程序
  • 執(zhí)行完畢后容器被終止

5.2 守護(hù)態(tài)運(yùn)行

更多的時(shí)候,需要讓 Docker 容器在后臺(tái)以守護(hù)態(tài)(Daemonized)形式運(yùn)行。此時(shí),可以通過(guò)添加 -d 參數(shù)來(lái)實(shí)現(xiàn)。

例如下面的命令會(huì)在后臺(tái)運(yùn)行容器。

$ sudo docker run -d ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
1e5535038e285177d5214659a068137486f96ee5c2e85a4ac52dc83f2ebe4147

容器啟動(dòng)后會(huì)返回一個(gè)唯一的 id,也可以通過(guò) docker ps 命令來(lái)查看容器信息。

$ sudo docker ps
CONTAINER ID  IMAGE         COMMAND               CREATED        STATUS       PORTS NAMES
1e5535038e28  ubuntu:14.04  /bin/sh -c 'while tr  2 minutes ago  Up 1 minute        insane_babbage

要獲取容器的輸出信息,可以通過(guò) docker logs 命令。

$ sudo docker logs insane_babbage
hello world
hello world
hello world
. . .

5.3 終止容器

可以使用 docker stop 來(lái)終止一個(gè)運(yùn)行中的容器。

此外,當(dāng)Docker容器中指定的應(yīng)用終結(jié)時(shí),容器也自動(dòng)終止。 例如對(duì)于上一章節(jié)中只啟動(dòng)了一個(gè)終端的容器,用戶通過(guò) exit 命令或 Ctrl+d 來(lái)退出終端時(shí),所創(chuàng)建的容器立刻終止。

終止?fàn)顟B(tài)的容器可以用 docker ps -a 命令看到。例如

sudo docker ps -a
CONTAINER ID        IMAGE                    COMMAND                CREATED             STATUS                          PORTS               NAMES
ba267838cc1b        ubuntu:14.04             "/bin/bash"            30 minutes ago      Exited (0) About a minute ago                       trusting_newton
98e5efa7d997        training/webapp:latest   "python app.py"        About an hour ago   Exited (0) 34 minutes ago                           backstabbing_pike

處于終止?fàn)顟B(tài)的容器,可以通過(guò) docker start 命令來(lái)重新啟動(dòng)。

此外,docker restart 命令會(huì)將一個(gè)運(yùn)行態(tài)的容器終止,然后再重新啟動(dòng)它。

5.4 進(jìn)入容器


在使用 -d 參數(shù)時(shí),容器啟動(dòng)后會(huì)進(jìn)入后臺(tái)。 某些時(shí)候需要進(jìn)入容器進(jìn)行操作,有很多種方法,包括使用 docker attach 命令或 nsenter 工具等。
attach 命令

docker attach 是Docker自帶的命令。下面示例如何使用該命令。

$ sudo docker run -idt ubuntu
243c32535da7d142fb0e6df616a3c3ada0b8ab417937c853a9e1c251f499f550
$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
243c32535da7        ubuntu:latest       "/bin/bash"         18 seconds ago      Up 17 seconds                           nostalgic_hypatia
$sudo docker attach nostalgic_hypatia
root@243c32535da7:/#

但是使用 attach 命令有時(shí)候并不方便。當(dāng)多個(gè)窗口同時(shí) attach 到同一個(gè)容器的時(shí)候,所有窗口都會(huì)同步顯示。當(dāng)某個(gè)窗口因命令阻塞時(shí),其他窗口也無(wú)法執(zhí)行操作了。
nsenter 命令
安裝

nsenter 工具在 util-linux 包2.23版本后包含。 如果系統(tǒng)中 util-linux 包沒(méi)有該命令,可以按照下面的方法從源碼安裝。

$ cd /tmp; curl https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz | tar -zxf-; cd util-linux-2.24;
$ ./configure --without-ncurses
$ make nsenter && sudo cp nsenter /usr/local/bin

使用

nsenter 可以訪問(wèn)另一個(gè)進(jìn)程的名字空間。nsenter 要正常工作需要有 root 權(quán)限。 很不幸,Ubuntu 14.04 仍然使用的是 util-linux 2.20。安裝最新版本的 util-linux(2.24)版,請(qǐng)按照以下步驟:

$ wget https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz; tar xzvf util-linux-2.24.tar.gz
$ cd util-linux-2.24
$ ./configure --without-ncurses && make nsenter
$ sudo cp nsenter /usr/local/bin

為了連接到容器,你還需要找到容器的第一個(gè)進(jìn)程的 PID,可以通過(guò)下面的命令獲取。

PID=$(docker inspect --format "{ { .State.Pid } }" )

通過(guò)這個(gè) PID,就可以連接到這個(gè)容器:

$ nsenter --target $PID --mount --uts --ipc --net --pid

下面給出一個(gè)完整的例子。

$ sudo docker run -idt ubuntu
243c32535da7d142fb0e6df616a3c3ada0b8ab417937c853a9e1c251f499f550
$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
243c32535da7        ubuntu:latest       "/bin/bash"         18 seconds ago      Up 17 seconds                           nostalgic_hypatia
$ PID=$(docker-pid 243c32535da7)
10981
$ sudo nsenter --target 10981 --mount --uts --ipc --net --pid
root@243c32535da7:/#

更簡(jiǎn)單的,建議大家下載 .bashrc_docker,并將內(nèi)容放到 .bashrc 中。

$ wget -P ~ https://github.com/yeasy/docker_practice/raw/master/_local/.bashrc_docker;
$ echo "[ -f ~/.bashrc_docker ] && . ~/.bashrc_docker" >> ~/.bashrc; source ~/.bashrc

這個(gè)文件中定義了很多方便使用 Docker 的命令,例如 docker-pid 可以獲取某個(gè)容器的 PID;而 docker-enter 可以進(jìn)入容器或直接在容器內(nèi)執(zhí)行命令。

$ echo $(docker-pid )
$ docker-enter  ls


5.5 導(dǎo)出和導(dǎo)入容器


導(dǎo)出容器

如果要導(dǎo)出本地某個(gè)容器,可以使用 docker export 命令。

$ sudo docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                    PORTS               NAMES
7691a814370e        ubuntu:14.04        "/bin/bash"         36 hours ago        Exited (0) 21 hours ago                       test
$ sudo docker export 7691a814370e > ubuntu.tar

這樣將導(dǎo)出容器快照到本地文件。
導(dǎo)入容器快照

可以使用 docker import 從容器快照文件中再導(dǎo)入為鏡像,例如

$ cat ubuntu.tar | sudo docker import - test/ubuntu:v1.0
$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              VIRTUAL SIZE
test/ubuntu         v1.0                9d37a6082e97        About a minute ago   171.3 MB

此外,也可以通過(guò)指定 URL 或者某個(gè)目錄來(lái)導(dǎo)入,例如

$sudo docker import http://example.com/exampleimage.tgz example/imagerepo

*注:用戶既可以使用 docker load 來(lái)導(dǎo)入鏡像存儲(chǔ)文件到本地鏡像庫(kù),也可以使用 docker import 來(lái)導(dǎo)入一個(gè)容器快照到本地鏡像庫(kù)。這兩者的區(qū)別在于容器快照文件將丟棄所有的歷史記錄和元數(shù)據(jù)信息(即僅保存容器當(dāng)時(shí)的快照狀態(tài)),而鏡像存儲(chǔ)文件將保存完整記錄,體積也要大。此外,從容器快照文件導(dǎo)入時(shí)可以重新指定標(biāo)簽等元數(shù)據(jù)信息。

5.6 刪除容器

可以使用 docker rm 來(lái)刪除一個(gè)處于終止?fàn)顟B(tài)的容器。 例如

$sudo docker rm  trusting_newton
trusting_newton

如果要?jiǎng)h除一個(gè)運(yùn)行中的容器,可以添加 -f 參數(shù)。Docker 會(huì)發(fā)送 SIGKILL 信號(hào)給容器。

6. 倉(cāng)庫(kù)

倉(cāng)庫(kù)(Repository)是集中存放鏡像的地方。

一個(gè)容易混淆的概念是注冊(cè)服務(wù)器(Registry)。實(shí)際上注冊(cè)服務(wù)器是管理倉(cāng)庫(kù)的具體服務(wù)器,每個(gè)服務(wù)器上可以有多個(gè)倉(cāng)庫(kù),而每個(gè)倉(cāng)庫(kù)下面有多個(gè)鏡像。從這方面來(lái) 說(shuō),倉(cāng)庫(kù)可以被認(rèn)為是一個(gè)具體的項(xiàng)目或目錄。例如對(duì)于倉(cāng)庫(kù)地址 dl.dockerpool.com/ubuntu 來(lái)說(shuō),dl.dockerpool.com 是注冊(cè)服務(wù)器地址,ubuntu 是倉(cāng)庫(kù)名。

大部分時(shí)候,并不需要嚴(yán)格區(qū)分這兩者的概念。

6.1

Docker Hub

目前 Docker 官方維護(hù)了一個(gè)公共倉(cāng)庫(kù) Docker Hub,其中已經(jīng)包括了超過(guò) 15,000 的鏡像。大部分需求,都可以通過(guò)在 Docker Hub 中直接下載鏡像來(lái)實(shí)現(xiàn)。
登錄

可以通過(guò)執(zhí)行 docker login 命令來(lái)輸入用戶名、密碼和郵箱來(lái)完成注冊(cè)和登錄。 注冊(cè)成功后,本地用戶目錄的 .dockercfg 中將保存用戶的認(rèn)證信息。
基本操作

用戶無(wú)需登錄即可通過(guò) docker search 命令來(lái)查找官方倉(cāng)庫(kù)中的鏡像,并利用 docker pull 命令來(lái)將它下載到本地。

例如以 centos 為關(guān)鍵詞進(jìn)行搜索:

$ sudo docker search centos
NAME                                            DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
centos                                          The official build of CentOS.                   465       [OK]
tianon/centos                                   CentOS 5 and 6, created using rinse instea...   28
blalor/centos                                   Bare-bones base CentOS 6.5 image                6                    [OK]
saltstack/centos-6-minimal                                                                      6                    [OK]
tutum/centos-6.4                                DEPRECATED. Use tutum/centos:6.4 instead. ...   5                    [OK]
...

可以看到返回了很多包含關(guān)鍵字的鏡像,其中包括鏡像名字、描述、星級(jí)(表示該鏡像的受歡迎程度)、是否官方創(chuàng)建、是否自動(dòng)創(chuàng)建。 官方的鏡像說(shuō)明是官方項(xiàng)目組創(chuàng)建和維護(hù)的,automated 資源允許用戶驗(yàn)證鏡像的來(lái)源和內(nèi)容。

根據(jù)是否是官方提供,可將鏡像資源分為兩類。 一種是類似 centos 這樣的基礎(chǔ)鏡像,被稱為基礎(chǔ)或根鏡像。這些基礎(chǔ)鏡像是由 Docker 公司創(chuàng)建、驗(yàn)證、支持、提供。這樣的鏡像往往使用單個(gè)單詞作為名字。 還有一種類型,比如 tianon/centos 鏡像,它是由 Docker 的用戶創(chuàng)建并維護(hù)的,往往帶有用戶名稱前綴。可以通過(guò)前綴 user_name/ 來(lái)指定使用某個(gè)用戶提供的鏡像,比如 tianon 用戶。

另外,在查找的時(shí)候通過(guò) -s N 參數(shù)可以指定僅顯示評(píng)價(jià)為 N 星以上的鏡像。

下載官方 centos 鏡像到本地。

$ sudo docker pull centos
Pulling repository centos
0b443ba03958: Download complete
539c0211cd76: Download complete
511136ea3c5a: Download complete
7064731afe90: Download complete

用戶也可以在登錄后通過(guò) docker push 命令來(lái)將鏡像推送到 Docker Hub。
自動(dòng)創(chuàng)建

自動(dòng)創(chuàng)建(Automated Builds)功能對(duì)于需要經(jīng)常升級(jí)鏡像內(nèi)程序來(lái)說(shuō),十分方便。 有時(shí)候,用戶創(chuàng)建了鏡像,安裝了某個(gè)軟件,如果軟件發(fā)布新版本則需要手動(dòng)更新鏡像。。

而自動(dòng)創(chuàng)建允許用戶通過(guò) Docker Hub 指定跟蹤一個(gè)目標(biāo)網(wǎng)站(目前支持 GitHub 或BitBucket)上的項(xiàng)目,一旦項(xiàng)目發(fā)生新的提交,則自動(dòng)執(zhí)行創(chuàng)建。

要配置自動(dòng)創(chuàng)建,包括如下的步驟:

    創(chuàng)建并登錄 Docker Hub,以及目標(biāo)網(wǎng)站;
    在目標(biāo)網(wǎng)站中連接帳戶到 Docker Hub;
    在 Docker Hub 中 配置一個(gè)自動(dòng)創(chuàng)建;
    選取一個(gè)目標(biāo)網(wǎng)站中的項(xiàng)目(需要含 Dockerfile)和分支;
    指定 Dockerfile 的位置,并提交創(chuàng)建。

之后,可以 在Docker Hub 的 自動(dòng)創(chuàng)建頁(yè)面 中跟蹤每次創(chuàng)建的狀態(tài)。

6.2 私有倉(cāng)庫(kù)


有時(shí)候使用 Docker Hub 這樣的公共倉(cāng)庫(kù)可能不方便,用戶可以創(chuàng)建一個(gè)本地倉(cāng)庫(kù)供私人使用。

本節(jié)介紹如何使用本地倉(cāng)庫(kù)。

docker-registry 是官方提供的工具,可以用于構(gòu)建私有的鏡像倉(cāng)庫(kù)。
安裝運(yùn)行 docker-registry
容器運(yùn)行

在安裝了 Docker 后,可以通過(guò)獲取官方 registry 鏡像來(lái)運(yùn)行。

$ sudo docker run -d -p 5000:5000 registry

這將使用官方的 registry 鏡像來(lái)啟動(dòng)本地的私有倉(cāng)庫(kù)。 用戶可以通過(guò)指定參數(shù)來(lái)配置私有倉(cāng)庫(kù)位置,例如配置鏡像存儲(chǔ)到 Amazon S3 服務(wù)。

$ sudo docker run \
         -e SETTINGS_FLAVOR=s3 \
         -e AWS_BUCKET=acme-docker \
         -e STORAGE_PATH=/registry \
         -e AWS_KEY=AKIAHSHB43HS3J92MXZ \
         -e AWS_SECRET=xdDowwlK7TJajV1Y7EoOZrmuPEJlHYcNP2k4j49T \
         -e SEARCH_BACKEND=sqlalchemy \
         -p 5000:5000 \
         registry
`

此外,還可以指定本地路徑(如 /home/user/registry-conf )下的配置文件。

$ sudo docker run -d -p 5000:5000 -v /home/user/registry-conf:/registry-conf -e DOCKER_REGISTRY_CONFIG=/registry-conf/config.yml registry

默認(rèn)情況下,倉(cāng)庫(kù)會(huì)被創(chuàng)建在容器的 /tmp/registry 下??梢酝ㄟ^(guò) -v 參數(shù)來(lái)將鏡像文件存放在本地的指定路徑。 例如下面的例子將上傳的鏡像放到 /opt/data/registry 目錄。

$ sudo docker run -d -p 5000:5000 -v /opt/data/registry:/tmp/registry registry

本地安裝

對(duì)于 Ubuntu 或 CentOS 等發(fā)行版,可以直接通過(guò)源安裝。

    Ubuntu

    $ sudo apt-get install -y build-essential python-dev libevent-dev python-pip liblzma-dev

    $ sudo pip install docker-registry

    CentOS

    $ sudo yum install -y python-devel libevent-devel python-pip gcc xz-devel

    $ sudo python-pip install docker-registry

也可以從 docker-registry 項(xiàng)目下載源碼進(jìn)行安裝。

$ sudo apt-get install build-essential python-dev libevent-dev python-pip libssl-dev liblzma-dev libffi-dev
$ git clone https://github.com/docker/docker-registry.git
$ cd docker-registry
$ sudo python setup.py install

然后修改配置文件,主要修改 dev 模板段的 storage_path 到本地的存儲(chǔ)倉(cāng)庫(kù)的路徑。

$ cp config/config_sample.yml config/config.yml

之后啟動(dòng) Web 服務(wù)。

$ sudo gunicorn -c contrib/gunicorn.py docker_registry.wsgi:application

或者

$ sudo gunicorn --access-logfile - --error-logfile - -k gevent -b 0.0.0.0:5000 -w 4 --max-requests 100 docker_registry.wsgi:application

此時(shí)使用 curl 訪問(wèn)本地的 5000 端口,看到輸出 docker-registry 的版本信息說(shuō)明運(yùn)行成功。

*注:config/config_sample.yml 文件是示例配置文件。
在私有倉(cāng)庫(kù)上傳、下載、搜索鏡像

創(chuàng)建好私有倉(cāng)庫(kù)之后,就可以使用 docker tag 來(lái)標(biāo)記一個(gè)鏡像,然后推送它到倉(cāng)庫(kù),別的機(jī)器上就可以下載下來(lái)了。例如私有倉(cāng)庫(kù)地址為 192.168.7.26:5000。

先在本機(jī)查看已有的鏡像。

$ sudo docker images
REPOSITORY                        TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu                            latest              ba5877dc9bec        6 weeks ago         192.7 MB
ubuntu                            14.04               ba5877dc9bec        6 weeks ago         192.7 MB

使用docker tag 將 ba58 這個(gè)鏡像標(biāo)記為 192.168.7.26:5000/test(格式為 docker tag IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG])。

$ sudo docker tag ba58 192.168.7.26:5000/test
root ~ # docker images
REPOSITORY                        TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu                            14.04               ba5877dc9bec        6 weeks ago         192.7 MB
ubuntu                            latest              ba5877dc9bec        6 weeks ago         192.7 MB
192.168.7.26:5000/test            latest              ba5877dc9bec        6 weeks ago         192.7 MB

使用 docker push 上傳標(biāo)記的鏡像。

$ sudo docker push 192.168.7.26:5000/test
The push refers to a repository [192.168.7.26:5000/test] (len: 1)
Sending image list
Pushing repository 192.168.7.26:5000/test (1 tags)
Image 511136ea3c5a already pushed, skipping
Image 9bad880da3d2 already pushed, skipping
Image 25f11f5fb0cb already pushed, skipping
Image ebc34468f71d already pushed, skipping
Image 2318d26665ef already pushed, skipping
Image ba5877dc9bec already pushed, skipping
Pushing tag for rev [ba5877dc9bec] on {http://192.168.7.26:5000/v1/repositories/test/tags/latest}

用 curl 查看倉(cāng)庫(kù)中的鏡像。

$ curl http://192.168.7.26:5000/v1/search
{"num_results": 7, "query": "", "results": [{"description": "", "name": "library/miaxis_j2ee"}, {"description": "", "name": "library/tomcat"}, {"description": "", "name": "library/ubuntu"}, {"description": "", "name": "library/ubuntu_office"}, {"description": "", "name": "library/desktop_ubu"}, {"description": "", "name": "dockerfile/ubuntu"}, {"description": "", "name": "library/test"}]}

這里可以看到 {"description": "", "name": "library/test"},表明鏡像已經(jīng)被成功上傳了。

現(xiàn)在可以到另外一臺(tái)機(jī)器去下載這個(gè)鏡像。

$ sudo docker pull 192.168.7.26:5000/test
Pulling repository 192.168.7.26:5000/test
ba5877dc9bec: Download complete
511136ea3c5a: Download complete
9bad880da3d2: Download complete
25f11f5fb0cb: Download complete
ebc34468f71d: Download complete
2318d26665ef: Download complete
$ sudo docker images
REPOSITORY                         TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
192.168.7.26:5000/test             latest              ba5877dc9bec        6 weeks ago         192.7 MB

可以使用 這個(gè)腳本 批量上傳本地的鏡像到注冊(cè)服務(wù)器中,默認(rèn)是本地注冊(cè)服務(wù)器 127.0.0.1:5000。例如:

$ wget https://github.com/yeasy/docker_practice/raw/master/_local/push_images.sh; sudo chmod a+x push_images.sh
$ ./push_images.sh ubuntu:latest centos:centos7
The registry server is 127.0.0.1
Uploading ubuntu:latest...
The push refers to a repository [127.0.0.1:5000/ubuntu] (len: 1)
Sending image list
Pushing repository 127.0.0.1:5000/ubuntu (1 tags)
Image 511136ea3c5a already pushed, skipping
Image bfb8b5a2ad34 already pushed, skipping
Image c1f3bdbd8355 already pushed, skipping
Image 897578f527ae already pushed, skipping
Image 9387bcc9826e already pushed, skipping
Image 809ed259f845 already pushed, skipping
Image 96864a7d2df3 already pushed, skipping
Pushing tag for rev [96864a7d2df3] on {http://127.0.0.1:5000/v1/repositories/ubuntu/tags/latest}
Untagged: 127.0.0.1:5000/ubuntu:latest
Done
Uploading centos:centos7...
The push refers to a repository [127.0.0.1:5000/centos] (len: 1)
Sending image list
Pushing repository 127.0.0.1:5000/centos (1 tags)
Image 511136ea3c5a already pushed, skipping
34e94e67e63a: Image successfully pushed
70214e5d0a90: Image successfully pushed
Pushing tag for rev [70214e5d0a90] on {http://127.0.0.1:5000/v1/repositories/centos/tags/centos7}
Untagged: 127.0.0.1:5000/centos:centos7
Done


6.3 倉(cāng)庫(kù)配置文件


Docker 的 Registry 利用配置文件提供了一些倉(cāng)庫(kù)的模板(flavor),用戶可以直接使用它們來(lái)進(jìn)行開(kāi)發(fā)或生產(chǎn)部署。
模板

在 config_sample.yml 文件中,可以看到一些現(xiàn)成的模板段:

    common:基礎(chǔ)配置
    local:存儲(chǔ)數(shù)據(jù)到本地文件系統(tǒng)
    s3:存儲(chǔ)數(shù)據(jù)到 AWS S3 中
    dev:使用 local 模板的基本配置
    test:?jiǎn)卧獪y(cè)試使用
    prod:生產(chǎn)環(huán)境配置(基本上跟s3配置類似)
    gcs:存儲(chǔ)數(shù)據(jù)到 Google 的云存儲(chǔ)
    swift:存儲(chǔ)數(shù)據(jù)到 OpenStack Swift 服務(wù)
    glance:存儲(chǔ)數(shù)據(jù)到 OpenStack Glance 服務(wù),本地文件系統(tǒng)為后備
    glance-swift:存儲(chǔ)數(shù)據(jù)到 OpenStack Glance 服務(wù),Swift 為后備
    elliptics:存儲(chǔ)數(shù)據(jù)到 Elliptics key/value 存儲(chǔ)

用戶也可以添加自定義的模版段。

默認(rèn)情況下使用的模板是 dev,要使用某個(gè)模板作為默認(rèn)值,可以添加 SETTINGS_FLAVOR 到環(huán)境變量中,例如

export SETTINGS_FLAVOR=dev

另外,配置文件中支持從環(huán)境變量中加載值,語(yǔ)法格式為 _env:VARIABLENAME[:DEFAULT]。
示例配置

common:
    loglevel: info
    search_backend: "_env:SEARCH_BACKEND:"
    sqlalchemy_index_database:
        "_env:SQLALCHEMY_INDEX_DATABASE:sqlite:////tmp/docker-registry.db"

prod:
    loglevel: warn
    storage: s3
    s3_access_key: _env:AWS_S3_ACCESS_KEY
    s3_secret_key: _env:AWS_S3_SECRET_KEY
    s3_bucket: _env:AWS_S3_BUCKET
    boto_bucket: _env:AWS_S3_BUCKET
    storage_path: /srv/docker
    smtp_host: localhost
    from_addr: docker@myself.com
    to_addr: my@myself.com

dev:
    loglevel: debug
    storage: local
    storage_path: /home/myself/docker

test:
    storage: local
    storage_path: /tmp/tmpdockertmp

選項(xiàng)

7. Docker 數(shù)據(jù)管理

這一章介紹如何在 Docker 內(nèi)部以及容器之間管理數(shù)據(jù),在容器中管理數(shù)據(jù)主要有兩種方式:

數(shù)據(jù)卷(Data volumes)
數(shù)據(jù)卷容器(Data volume containers)

7.1 數(shù)據(jù)卷

數(shù)據(jù)卷是一個(gè)可供一個(gè)或多個(gè)容器使用的特殊目錄,它繞過(guò) UFS,可以提供很多有用的特性:

    數(shù)據(jù)卷可以在容器之間共享和重用
    對(duì)數(shù)據(jù)卷的修改會(huì)立馬生效
    對(duì)數(shù)據(jù)卷的更新,不會(huì)影響鏡像
    卷會(huì)一直存在,直到?jīng)]有容器使用

*數(shù)據(jù)卷的使用,類似于 Linux 下對(duì)目錄或文件進(jìn)行 mount。
創(chuàng)建一個(gè)數(shù)據(jù)卷

在用 docker run 命令的時(shí)候,使用 -v 標(biāo)記來(lái)創(chuàng)建一個(gè)數(shù)據(jù)卷并掛載到容器里。在一次 run 中多次使用可以掛載多個(gè)數(shù)據(jù)卷。

下面創(chuàng)建一個(gè) web 容器,并加載一個(gè)數(shù)據(jù)卷到容器的 /webapp 目錄。

$ sudo docker run -d -P --name web -v /webapp training/webapp python app.py

*注意:也可以在 Dockerfile 中使用 VOLUME 來(lái)添加一個(gè)或者多個(gè)新的卷到由該鏡像創(chuàng)建的任意容器。
掛載一個(gè)主機(jī)目錄作為數(shù)據(jù)卷

使用 -v 標(biāo)記也可以指定掛載一個(gè)本地主機(jī)的目錄到容器中去。

$ sudo docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py

上面的命令加載主機(jī)的 /src/webapp 目錄到容器的 /opt/webapp 目錄。這個(gè)功能在進(jìn)行測(cè)試的時(shí)候十分方便,比如用戶可以放置一些程序到本地目錄中,來(lái)查看容器是否正常工作。本地目錄的路徑必須是絕對(duì)路徑,如果目錄不存在 Docker 會(huì)自動(dòng)為你創(chuàng)建它。

*注意:Dockerfile 中不支持這種用法,這是因?yàn)?Dockerfile 是為了移植和分享用的。然而,不同操作系統(tǒng)的路徑格式不一樣,所以目前還不能支持。

Docker 掛載數(shù)據(jù)卷的默認(rèn)權(quán)限是讀寫(xiě),用戶也可以通過(guò) :ro 指定為只讀。

$ sudo docker run -d -P --name web -v /src/webapp:/opt/webapp:ro
training/webapp python app.py

加了 :ro 之后,就掛載為只讀了。
掛載一個(gè)本地主機(jī)文件作為數(shù)據(jù)卷

-v 標(biāo)記也可以從主機(jī)掛載單個(gè)文件到容器中

$ sudo docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash

這樣就可以記錄在容器輸入過(guò)的命令了。

*注意:如果直接掛載一個(gè)文件,很多文件編輯工具,包括 vi 或者 sed --in-place,可能會(huì)造成文件 inode 的改變,從 Docker 1.1 .0起,這會(huì)導(dǎo)致報(bào)錯(cuò)誤信息。所以最簡(jiǎn)單的辦法就直接掛載文件的父目錄。

7.2 數(shù)據(jù)卷容器

如果你有一些持續(xù)更新的數(shù)據(jù)需要在容器之間共享,最好創(chuàng)建數(shù)據(jù)卷容器。

數(shù)據(jù)卷容器,其實(shí)就是一個(gè)正常的容器,專門用來(lái)提供數(shù)據(jù)卷供其它容器掛載的。

首先,創(chuàng)建一個(gè)命名的數(shù)據(jù)卷容器 dbdata:

$ sudo docker run -d -v /dbdata --name dbdata training/postgres echo Data-only container for postgres

然后,在其他容器中使用 --volumes-from 來(lái)掛載 dbdata 容器中的數(shù)據(jù)卷。

$ sudo docker run -d --volumes-from dbdata --name db1 training/postgres
$ sudo docker run -d --volumes-from dbdata --name db2 training/postgres

還可以使用多個(gè) --volumes-from 參數(shù)來(lái)從多個(gè)容器掛載多個(gè)數(shù)據(jù)卷。 也可以從其他已經(jīng)掛載了數(shù)據(jù)卷的容器來(lái)掛載數(shù)據(jù)卷。

$ sudo docker run -d --name db3 --volumes-from db1 training/postgres

*注意:使用 --volumes-from 參數(shù)所掛載數(shù)據(jù)卷的容器自己并不需要保持在運(yùn)行狀態(tài)。

如果刪除了掛載的容器(包括 dbdata、db1 和 db2),數(shù)據(jù)卷并不會(huì)被自動(dòng)刪除。如果要?jiǎng)h除一個(gè)數(shù)據(jù)卷,必須在刪除最后一個(gè)還掛載著它的容器時(shí)使用 docker rm -v 命令來(lái)指定同時(shí)刪除關(guān)聯(lián)的容器。 這可以讓用戶在容器之間升級(jí)和移動(dòng)數(shù)據(jù)卷。具體的操作將在下一節(jié)中進(jìn)行講解。

7.3 利用數(shù)據(jù)卷容器來(lái)備份、恢復(fù)、遷移數(shù)據(jù)卷


可以利用數(shù)據(jù)卷對(duì)其中的數(shù)據(jù)進(jìn)行進(jìn)行備份、恢復(fù)和遷移。
備份

首先使用 --volumes-from 標(biāo)記來(lái)創(chuàng)建一個(gè)加載 dbdata 容器卷的容器,并從本地主機(jī)掛載當(dāng)前到容器的 /backup 目錄。命令如下:

$ sudo docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata

容器啟動(dòng)后,使用了 tar 命令來(lái)將 dbdata 卷備份為本地的 /backup/backup.tar。
恢復(fù)

如果要恢復(fù)數(shù)據(jù)到一個(gè)容器,首先創(chuàng)建一個(gè)帶有數(shù)據(jù)卷的容器 dbdata2。

$ sudo docker run -v /dbdata --name dbdata2 ubuntu /bin/bash

然后創(chuàng)建另一個(gè)容器,掛載 dbdata2 的容器,并使用 untar 解壓備份文件到掛載的容器卷中。

$ sudo docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf
/backup/backup.tar


8. 使用網(wǎng)絡(luò)

8.1 外部訪問(wèn)容器


容器中可以運(yùn)行一些網(wǎng)絡(luò)應(yīng)用,要讓外部也可以訪問(wèn)這些應(yīng)用,可以通過(guò) -P 或 -p 參數(shù)來(lái)指定端口映射。

當(dāng)使用 -P 標(biāo)記時(shí),Docker 會(huì)隨機(jī)映射一個(gè) 49000~49900 的端口到內(nèi)部容器開(kāi)放的網(wǎng)絡(luò)端口。

使用 docker ps 可以看到,本地主機(jī)的 49155 被映射到了容器的 5000 端口。此時(shí)訪問(wèn)本機(jī)的 49155 端口即可訪問(wèn)容器內(nèi) web 應(yīng)用提供的界面。

$ sudo docker run -d -P training/webapp python app.py
$ sudo docker ps -l
CONTAINER ID  IMAGE                   COMMAND       CREATED        STATUS        PORTS                    NAMES
bc533791f3f5  training/webapp:latest  python app.py 5 seconds ago  Up 2 seconds  0.0.0.0:49155->5000/tcp  nostalgic_morse

同樣的,可以通過(guò) docker logs 命令來(lái)查看應(yīng)用的信息。

$ sudo docker logs -f nostalgic_morse
* Running on http://0.0.0.0:5000/
10.0.2.2 - - [23/May/2014 20:16:31] "GET / HTTP/1.1" 200 -
10.0.2.2 - - [23/May/2014 20:16:31] "GET /favicon.ico HTTP/1.1" 404 -

-p(小寫(xiě)的)則可以指定要映射的端口,并且,在一個(gè)指定端口上只可以綁定一個(gè)容器。支持的格式有 ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort。
映射所有接口地址

使用 hostPort:containerPort 格式本地的 5000 端口映射到容器的 5000 端口,可以執(zhí)行

$ sudo docker run -d -p 5000:5000 training/webapp python app.py

此時(shí)默認(rèn)會(huì)綁定本地所有接口上的所有地址。
映射到指定地址的指定端口

可以使用 ip:hostPort:containerPort 格式指定映射使用一個(gè)特定地址,比如 localhost 地址 127.0.0.1

$ sudo docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py

映射到指定地址的任意端口

使用 ip::containerPort 綁定 localhost 的任意端口到容器的 5000 端口,本地主機(jī)會(huì)自動(dòng)分配一個(gè)端口。

$ sudo docker run -d -p 127.0.0.1::5000 training/webapp python app.py

還可以使用 udp 標(biāo)記來(lái)指定 udp 端口

$ sudo docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py

查看映射端口配置

使用 docker port 來(lái)查看當(dāng)前映射的端口配置,也可以查看到綁定的地址

$ docker port nostalgic_morse 5000
127.0.0.1:49155.

注意:

    容器有自己的內(nèi)部網(wǎng)絡(luò)和 ip 地址(使用 docker inspect 可以獲取所有的變量,Docker 還可以有一個(gè)可變的網(wǎng)絡(luò)配置。)
    -p 標(biāo)記可以多次使用來(lái)綁定多個(gè)端口

例如

$ sudo docker run -d -p 5000:5000  -p 3000:80 training/webapp python app.py


8.2 容器互聯(lián)

容器的連接(linking)系統(tǒng)是除了端口映射外,另一種跟容器中應(yīng)用交互的方式。

該系統(tǒng)會(huì)在源和接收容器之間創(chuàng)建一個(gè)隧道,接收容器可以看到源容器指定的信息。
自定義容器命名

連接系統(tǒng)依據(jù)容器的名稱來(lái)執(zhí)行。因此,首先需要自定義一個(gè)好記的容器命名。

雖然當(dāng)創(chuàng)建容器的時(shí)候,系統(tǒng)默認(rèn)會(huì)分配一個(gè)名字。自定義命名容器有2個(gè)好處:

    自定義的命名,比較好記,比如一個(gè)web應(yīng)用容器我們可以給它起名叫web
    當(dāng)要連接其他容器時(shí)候,可以作為一個(gè)有用的參考點(diǎn),比如連接web容器到db容器

使用 --name 標(biāo)記可以為容器自定義命名。

$ sudo docker run -d -P --name web training/webapp python app.py

使用 docker ps 來(lái)驗(yàn)證設(shè)定的命名。

$ sudo docker ps -l
CONTAINER ID  IMAGE                  COMMAND        CREATED       STATUS       PORTS                    NAMES
aed84ee21bde  training/webapp:latest python app.py  12 hours ago  Up 2 seconds 0.0.0.0:49154->5000/tcp  web

也可以使用 docker inspect 來(lái)查看容器的名字

$ sudo docker inspect -f "{ { .Name } }" aed84ee21bde
/web

注意:容器的名稱是唯一的。如果已經(jīng)命名了一個(gè)叫 web 的容器,當(dāng)你要再次使用 web 這個(gè)名稱的時(shí)候,需要先用docker rm 來(lái)刪除之前創(chuàng)建的同名容器。

在執(zhí)行 docker run 的時(shí)候如果添加 --rm 標(biāo)記,則容器在終止后會(huì)立刻刪除。注意,--rm 和 -d 參數(shù)不能同時(shí)使用。
容器互聯(lián)

使用 --link 參數(shù)可以讓容器之間安全的進(jìn)行交互。

下面先創(chuàng)建一個(gè)新的數(shù)據(jù)庫(kù)容器。

$ sudo docker run -d --name db training/postgres

刪除之前創(chuàng)建的 web 容器

$ docker rm -f web

然后創(chuàng)建一個(gè)新的 web 容器,并將它連接到 db 容器

$ sudo docker run -d -P --name web --link db:db training/webapp python app.py

此時(shí),db 容器和 web 容器建立互聯(lián)關(guān)系。

--link 參數(shù)的格式為 --link name:alias,其中 name 是要鏈接的容器的名稱,alias 是這個(gè)連接的別名。

使用 docker ps 來(lái)查看容器的連接

$ docker ps
CONTAINER ID  IMAGE                     COMMAND               CREATED             STATUS             PORTS                    NAMES
349169744e49  training/postgres:latest  su postgres -c '/usr  About a minute ago  Up About a minute  5432/tcp                 db, web/db
aed84ee21bde  training/webapp:latest    python app.py         16 hours ago        Up 2 minutes       0.0.0.0:49154->5000/tcp  web

可以看到自定義命名的容器,db 和 web,db 容器的 names 列有 db 也有 web/db。這表示 web 容器鏈接到 db 容器,web 容器將被允許訪問(wèn) db 容器的信息。

Docker 在兩個(gè)互聯(lián)的容器之間創(chuàng)建了一個(gè)安全隧道,而且不用映射它們的端口到宿主主機(jī)上。在啟動(dòng) db 容器的時(shí)候并沒(méi)有使用 -p 和 -P 標(biāo)記,從而避免了暴露數(shù)據(jù)庫(kù)端口到外部網(wǎng)絡(luò)上。

Docker 通過(guò) 2 種方式為容器公開(kāi)連接信息:

    環(huán)境變量
    更新 /etc/hosts 文件

使用 env 命令來(lái)查看 web 容器的環(huán)境變量

$ sudo docker run --rm --name web2 --link db:db training/webapp env
. . .
DB_NAME=/web2/db
DB_PORT=tcp://172.17.0.5:5432
DB_PORT_5000_TCP=tcp://172.17.0.5:5432
DB_PORT_5000_TCP_PROTO=tcp
DB_PORT_5000_TCP_PORT=5432
DB_PORT_5000_TCP_ADDR=172.17.0.5
. . .

其中 DB_ 開(kāi)頭的環(huán)境變量是供 web 容器連接 db 容器使用,前綴采用大寫(xiě)的連接別名。

除了環(huán)境變量,Docker 還添加 host 信息到父容器的 /etc/hosts 的文件。下面是父容器 web 的 hosts 文件

$ sudo docker run -t -i --rm --link db:db training/webapp /bin/bash
root@aed84ee21bde:/opt/webapp# cat /etc/hosts
172.17.0.7  aed84ee21bde
. . .
172.17.0.5  db

這里有 2 個(gè) hosts,第一個(gè)是 web 容器,web 容器用 id 作為他的主機(jī)名,第二個(gè)是 db 容器的 ip 和主機(jī)名。 可以在 web 容器中安裝 ping 命令來(lái)測(cè)試跟db容器的連通。

root@aed84ee21bde:/opt/webapp# apt-get install -yqq inetutils-ping
root@aed84ee21bde:/opt/webapp# ping db
PING db (172.17.0.5): 48 data bytes
56 bytes from 172.17.0.5: icmp_seq=0 ttl=64 time=0.267 ms
56 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.250 ms
56 bytes from 172.17.0.5: icmp_seq=2 ttl=64 time=0.256 ms

用 ping 來(lái)測(cè)試db容器,它會(huì)解析成 172.17.0.5。 *注意:官方的 ubuntu 鏡像默認(rèn)沒(méi)有安裝 ping,需要自行安裝。

用戶可以鏈接多個(gè)父容器到子容器,比如可以鏈接多個(gè) web 到 db 容器上。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Docker 學(xué)習(xí)目標(biāo): 掌握Docker基礎(chǔ)知識(shí),能夠理解Docker鏡像與容器的概念 完成Docker安裝與啟...
    執(zhí)筆夢(mèng)一場(chǎng)閱讀 3,517評(píng)論 2 10
  • 特別說(shuō)明: 本人平時(shí)混跡于 B 站,不咋回復(fù)這里的評(píng)論,有問(wèn)題可以到 B 站視頻評(píng)論區(qū)留言找我視頻地址: http...
    擼帝閱讀 1,006評(píng)論 1 3
  • 一、Docker 簡(jiǎn)介 Docker 兩個(gè)主要部件:Docker: 開(kāi)源的容器虛擬化平臺(tái)Docker Hub: 用...
    R_X閱讀 4,511評(píng)論 0 27
  • 心情不好,元旦第一天,本來(lái)前一天積累下來(lái)的好心情,此刻早就已經(jīng)煙消云散。我不知道說(shuō)什么,我有點(diǎn)兒難過(guò),從來(lái)不知...
    拾安叁閱讀 296評(píng)論 0 1
  • 葉落悲秋寂無(wú)遼。心上秋,一轉(zhuǎn)三番幾多愁,愁字不見(jiàn)頭。葉落蕭條,風(fēng)怒嚎。 問(wèn)秋幾時(shí)重回頭?心上頭,腦上愁。
    夢(mèng)想家的二余閱讀 679評(píng)論 0 0

友情鏈接更多精彩內(nèi)容