這篇筆記分成四個(gè)部分:
1. Docker 容器是什么
2. Docker 容器與虛擬機(jī)技術(shù)的對(duì)比
3. Docker 容器的核心概念
4. Docker 容器的安裝
5. Docker 容器的基本操作
一、Docker 容器是什么?
大部分普通的軟件工程師對(duì)“容器”的認(rèn)知,確實(shí)源于 Docker。但 Docker 其實(shí)是源于 LXC(Linux Container)容器技術(shù)。LXC 并不是新技術(shù),是一種操作系統(tǒng)級(jí)的虛擬化技術(shù)。這種技術(shù)能夠?qū)蝹€(gè)操作系統(tǒng)管理的資源劃分到獨(dú)立的分組中,以便能更好的在孤立的組之間平衡資源的使用。同時(shí),由于是基于內(nèi)核級(jí)別的運(yùn)行,因此并不需要模擬特殊的、復(fù)雜的硬件指令,這令容器技術(shù)更輕量,更簡(jiǎn)單。LXC 已經(jīng)被集成了主流的 Linux 內(nèi)核中,已經(jīng)成為 Linux 系統(tǒng)容器技術(shù)事實(shí)上的標(biāo)準(zhǔn)。
Docker 源于LXC,而進(jìn)一步優(yōu)化了 LXC 的使用體驗(yàn)。通過(guò)提供豐富的容器管理工具(如打包、分發(fā)、版本管理、移植等),避免用戶(hù)對(duì)底層進(jìn)行操作,降低了 LXC 的使用門(mén)檻,最終推動(dòng)了容器技術(shù)被廣泛應(yīng)用。

二、Docker 容器與虛擬機(jī)技術(shù)的對(duì)比
提到容器,就避不開(kāi)和傳統(tǒng)虛擬機(jī)技術(shù)進(jìn)行對(duì)比,而且容器本身也是一種虛擬化技術(shù)。因此有必要先對(duì)虛擬化技術(shù)進(jìn)行一定的了解。
虛擬化(Virtualization)是一種資源管理技術(shù),是將計(jì)算機(jī)的各種實(shí)體資源,如處理器、內(nèi)存、存儲(chǔ)、網(wǎng)絡(luò)等,予以抽象和轉(zhuǎn)換后呈現(xiàn)出來(lái),打破實(shí)體間不可切割的障礙,使用戶(hù)可以用到比原本的組態(tài)更好的方式來(lái)應(yīng)用這些資源。
虛擬化的核心是對(duì)資源進(jìn)行抽象,目標(biāo)往往是為了在同一個(gè)主機(jī)上運(yùn)行多個(gè)系統(tǒng)或應(yīng)用,從而提高資源的利用率,降低成本,方便管理。
主流的虛擬化技術(shù)可以分為如下幾個(gè)類(lèi)別:
- 全虛擬化:虛擬機(jī)將模擬出完整的底層硬件環(huán)境,包括特權(quán)指令的執(zhí)行過(guò)程,虛擬化平臺(tái)的技術(shù)難度非常高,但可以做到客戶(hù)操作系統(tǒng)完全不感知和免修改。典型的技術(shù)實(shí)現(xiàn)有 VMWare、VirtualBox、QEMU等。
- 硬件輔助虛擬化:虛擬機(jī)將利用硬件輔助支持(主要是CPU,主流技術(shù)是 Intel-VT 和 AMD-V)特權(quán)指令的執(zhí)行過(guò)程,來(lái)實(shí)現(xiàn)完全的虛擬化,也可以做到客戶(hù)操作系統(tǒng)完全不感知和免修改。典型的技術(shù)實(shí)現(xiàn)有 VMWare、Xen、KVM等。
- 半虛擬化:虛擬機(jī)只模擬出部分硬件環(huán)境,其他則需要操作系統(tǒng)進(jìn)行修改適配。
- 操作系統(tǒng)級(jí)虛擬化:操作系統(tǒng)內(nèi)核通過(guò)創(chuàng)建多個(gè)系統(tǒng)實(shí)例(內(nèi)核+庫(kù))來(lái)隔離不同的應(yīng)用,容器相關(guān)技術(shù)就屬于這個(gè)范疇。
那么,容器和傳統(tǒng)虛擬機(jī)技術(shù)的差異是什么呢?
傳統(tǒng)虛擬機(jī)技術(shù)如 VMware ,VisualBox 需要模擬出完整的服務(wù)器環(huán)境,每臺(tái)虛擬機(jī)都需要擁有自己的操作系統(tǒng),即 GuestOS,同時(shí)還包括必要的庫(kù)文件和應(yīng)用程序。而虛擬機(jī)一旦啟動(dòng),預(yù)分配給它的資源將全部被占用。
而容器技術(shù)則和宿主機(jī)共享硬件資源及操作系統(tǒng)。每個(gè)容器不需要擁有自己的操作系統(tǒng),只需要包含應(yīng)用和依賴(lài)包,與其他容器共享內(nèi)核,但在彼此獨(dú)立的進(jìn)程空間中運(yùn)行。
下面這兩幅圖直觀的反映出兩者的區(qū)別。
第一幅圖:容器引擎部署在裸金屬服務(wù)器上

第二幅圖:容器引擎部署在虛擬機(jī)上

目前,這兩種部署方式在都是廣泛存在的。
通過(guò)使用容器,可以更輕松打包應(yīng)用程序的代碼、配置和依賴(lài)關(guān)系,將其變成容易使用的構(gòu)建塊,從而實(shí)現(xiàn)環(huán)境一致性、運(yùn)營(yíng)效率、開(kāi)發(fā)人員生產(chǎn)力和版本控制等諸多目標(biāo)。容器能幫助應(yīng)用程序快速、可靠、一致地部署,不受部署環(huán)境的影響,遷移更簡(jiǎn)單。同時(shí),容器還賦予對(duì)資源更多的精細(xì)化控制能力,讓基礎(chǔ)設(shè)施效率更高。
比如,基于常見(jiàn)的 LAMP(Linux+Apach+MySQL+PHP)組合運(yùn)維一個(gè)網(wǎng)站,傳統(tǒng)的做法是在虛擬機(jī)或物理機(jī)的操作系統(tǒng)上,單獨(dú)安裝 Apache、MySQL、PHP 以及它們的依賴(lài)環(huán)境,并進(jìn)行復(fù)雜的配置和測(cè)試。這個(gè)過(guò)程可以參見(jiàn)我之前寫(xiě)過(guò)的一篇文章(LAMP開(kāi)發(fā)環(huán)境搭建日志)。經(jīng)歷過(guò),才知道坑有多深(當(dāng)然,在傳統(tǒng)方式下,通過(guò)XAMPP也是另一種簡(jiǎn)化的部署方案)。但通過(guò)容器打包 LAMP 的方案則聰明、輕量的多。后面也會(huì)寫(xiě)一篇實(shí)戰(zhàn)的筆記,更直觀的體驗(yàn)兩種方式的差異。但不管怎樣,自己都不再會(huì)再把時(shí)間花費(fèi)在獨(dú)自安裝各個(gè)組件的事情上了。

所以,容器技術(shù)受到了廣大開(kāi)發(fā)和運(yùn)維人員的喜愛(ài),能夠給大家?guī)?lái)很多實(shí)際的好處:
- 更快速的交付和部署。顯而易見(jiàn),容器更容易構(gòu)建一套標(biāo)準(zhǔn)統(tǒng)一的環(huán)境,研發(fā)和運(yùn)維人員可以使用同相同的環(huán)境來(lái)部署應(yīng)用。所以在 DevOps 領(lǐng)域,容器是明星技術(shù)。
- 更高效的資源利用。容器不需要 GuestOS,這使得資源占用就具備很大優(yōu)勢(shì)了。而且由于容器共享宿主機(jī)(HostOS)的內(nèi)核空間,理論上能夠獲得更高的執(zhí)行效率。
- 更輕松的遷移和擴(kuò)展。Docker 容器幾乎可以在各種基礎(chǔ)設(shè)施平臺(tái)上運(yùn)行,只需要該平臺(tái)上部署了 Docker Engine。比如物理機(jī)、虛擬機(jī)、公有云、私有云、混合云等等。
- 更簡(jiǎn)單的更新管理。這主要是指基于 Dockerfile 的自動(dòng)化部署與軟件管理方式。
Docker 容器作為一種輕量級(jí)的虛擬化技術(shù),和傳統(tǒng)虛擬機(jī)技術(shù)的特性差異如下表所示:
| 特性 | 容器 | 虛擬機(jī) |
|---|---|---|
| 啟動(dòng)速度 | 秒級(jí) | 分鐘級(jí) |
| 存儲(chǔ)占用 | MB級(jí) | GB級(jí) |
| 性能對(duì)比 | 接近原生級(jí)別 | 理論達(dá)不到原生級(jí)別 |
| 系統(tǒng)量級(jí) | 單機(jī)可支持上千個(gè) | 單機(jī)支持幾十個(gè) |
| 安全能力 | 依賴(lài)宿主系統(tǒng)安全能力 | 完全隔離 |
單獨(dú)提一下容器被廣泛詬病的安全問(wèn)題。傳統(tǒng)虛擬機(jī)技術(shù)利用完全模擬或 Intel 的 VT-d 和 VT-x 的 ring-1 硬件隔離技術(shù)將物理資源完全進(jìn)行隔離,不同的虛擬機(jī)即使底層運(yùn)行在同一臺(tái)物理主機(jī)上,彼此之間是完全獨(dú)立的,在技術(shù)上能夠?qū)崿F(xiàn)虛擬機(jī)突破和彼此交互的防護(hù)。而 Docker 利用的只是 Linux 系統(tǒng)自身的進(jìn)程空間隔離機(jī)制實(shí)現(xiàn)容器間的隔離,Docker 租戶(hù)的 root 和宿主機(jī)的 HostOS 的 root 是等同的,也就是說(shuō),Docker 的特權(quán)租戶(hù)可以直接對(duì)宿主機(jī)進(jìn)行無(wú)限制操作,這相對(duì)虛擬機(jī)機(jī)制確實(shí)存在較大的安全隱患。目前,Docker 也引入了相應(yīng)的安全選項(xiàng)和鏡像簽名機(jī)制,較大的改善了容器的安全能力。

三、Docker 容器的核心概念
Docker 有三個(gè)核心概念:
- 鏡像(Image)
- 容器(Container)
- 倉(cāng)庫(kù)(Repository)
理解了這三個(gè)核心概念,對(duì)于理解 Docker 整個(gè)生命周期會(huì)很有幫助。下面是一張被多次引用的圖,清晰的描述了 Docker 的生命周期。

核心概念1:鏡像
Docker 鏡像(Image)和虛擬機(jī)鏡像的概念是一樣的,可以將其理解為一個(gè)面向 Docker 引擎的只讀模板,可用于批量創(chuàng)造可運(yùn)行的容器實(shí)例。Docker 鏡像可以看作是一個(gè)特殊的文件系統(tǒng),除了提供容器運(yùn)行時(shí)所需的程序、庫(kù)、資源、配置等文件外,還包含了一些為運(yùn)行時(shí)準(zhǔn)備的一些配置參數(shù)(如環(huán)境變量、用戶(hù)等)。鏡像不包含任何動(dòng)態(tài)數(shù)據(jù),其內(nèi)容在構(gòu)建之后也不會(huì)被改變。鏡像是創(chuàng)建 Docker 容器的基礎(chǔ),而 Docker 體系能夠提供一套簡(jiǎn)單的機(jī)制創(chuàng)建和更新已有的鏡像,也可以從網(wǎng)上下載一個(gè)制作好的現(xiàn)成的鏡像。
核心概念2:容器
Docker 容器(Container)是一個(gè)運(yùn)行時(shí)的概念,可以理解為一個(gè)簡(jiǎn)易的 Linux 系統(tǒng)環(huán)境(包括 root 用戶(hù)權(quán)限、進(jìn)程空間、網(wǎng)絡(luò)空間等概念)以及運(yùn)行在其中的應(yīng)用程序。每個(gè) Docker 容器本質(zhì)上就是一個(gè) Linux 進(jìn)程,擁有自己的上下文環(huán)境,彼此隔離。Docker 引擎能夠?qū)σ粋€(gè)容器進(jìn)行啟動(dòng)、停止、刪除等操作。
核心概念3:倉(cāng)庫(kù)
Docker 倉(cāng)庫(kù)(Reopsitory)類(lèi)似代碼倉(cāng)庫(kù),是 Docker 體系集中存放鏡像文件的場(chǎng)所。一般情況下,一個(gè)倉(cāng)庫(kù)會(huì)包含同一個(gè)軟件不同版本的鏡像,用“標(biāo)簽”的概念來(lái)標(biāo)記版本 ??梢酝ㄟ^(guò)<倉(cāng)庫(kù)名>:<標(biāo)簽>的格式來(lái)精確定位具體采用哪個(gè)鏡像。如果不指定標(biāo)簽,則采用 latest 作為默認(rèn)標(biāo)簽。
根據(jù)存儲(chǔ)的鏡像公開(kāi)與否,可以分為公開(kāi)倉(cāng)庫(kù)(Public)和私有倉(cāng)庫(kù)(Private),目前最大的公開(kāi)倉(cāng)庫(kù)是 Docker Hub,用戶(hù)可以在自己的本地網(wǎng)絡(luò)中創(chuàng)建私有倉(cāng)庫(kù)。
Docker 利用倉(cāng)庫(kù)管理鏡像的理念類(lèi)似于 Git,默認(rèn)情況下 Docker 會(huì)在中央倉(cāng)庫(kù)(Docker Hub 和 Docker Cloud)尋找鏡像文件。
Docker 基本架構(gòu)
Docker 采用 C/S 架構(gòu)。 Docker Server 負(fù)責(zé)構(gòu)建、運(yùn)行和分發(fā) Docker 鏡像。 Docker Client 和 Docker Server 可以運(yùn)行在同一臺(tái)機(jī)器上,也可以通過(guò) RESTful 或其他網(wǎng)絡(luò)接口進(jìn)行遠(yuǎn)程通信,如下圖所示:

從上圖能夠看到,Docker 體系的核心組件包括如下幾部分:
- Docker Client
- Docker Daemon
- Docker Container
- Docker Image
- Docker Registry
1) Docker Client
Docker Client 提供了命令行界面 (CLI) ,是用戶(hù)與 Docker 進(jìn)行交互的主要窗口。通過(guò) Client 可以構(gòu)建、運(yùn)行和停止容器,還可以與遠(yuǎn)程的 Docker Server 進(jìn)行交互。
andy-zhang@localhost:~$ sudo docker
[sudo] password for andy-zhang:
Usage: docker [OPTIONS] COMMAND
A self-sufficient runtime for containers
Options:
--config string Location of client config files (default "/home/andy-zhang/.docker")
-c, --context string Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and default
context set with "docker context use")
-D, --debug Enable debug mode
-H, --host list Daemon socket(s) to connect to
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
--tls Use TLS; implied by --tlsverify
--tlscacert string Trust certs signed only by this CA (default "/home/andy-zhang/.docker/ca.pem")
--tlscert string Path to TLS certificate file (default "/home/andy-zhang/.docker/cert.pem")
--tlskey string Path to TLS key file (default "/home/andy-zhang/.docker/key.pem")
--tlsverify Use TLS and verify the remote
-v, --version Print version information and quit
Management Commands:
builder Manage builds
config Manage Docker configs
container Manage containers
context Manage contexts
engine Manage the docker engine
image Manage images
network Manage networks
node Manage Swarm nodes
plugin Manage plugins
secret Manage Docker secrets
service Manage services
stack Manage Docker stacks
swarm Manage Swarm
system Manage Docker
trust Manage trust on Docker images
volume Manage volumes
Commands:
attach Attach local standard input, output, and error streams to a running container
build Build an image from a Dockerfile
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes to files or directories on a container's filesystem
events Get real time events from the server
exec Run a command in a running container
export Export a container's filesystem as a tar archive
history Show the history of an image
images List images
import Import the contents from a tarball to create a filesystem image
info Display system-wide information
inspect Return low-level information on Docker objects
kill Kill one or more running containers
load Load an image from a tar archive or STDIN
login Log in to a Docker registry
logout Log out from a Docker registry
logs Fetch the logs of a container
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
ps List containers
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
rmi Remove one or more images
run Run a command in a new container
save Save one or more images to a tar archive (streamed to STDOUT by default)
search Search the Docker Hub for images
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
version Show the Docker version information
wait Block until one or more containers stop, then print their exit codes
2) Docker Daemon
Docker Daemon 是最核心的后臺(tái)服務(wù)進(jìn)程,以 Linux 后臺(tái)服務(wù)的方式運(yùn)行,也稱(chēng)為守護(hù)進(jìn)程。它負(fù)責(zé)響應(yīng)來(lái)自 Docker Client 的請(qǐng)求,內(nèi)部對(duì)請(qǐng)求進(jìn)行路由分發(fā),交給具體的管理模塊進(jìn)行處理。

默認(rèn)情況下,Docker Daemon 只能接收本地 Docker Client 的請(qǐng)求。如果要處理遠(yuǎn)程 Client 的請(qǐng)求,需要在配置文件中打開(kāi) TCP 監(jiān)聽(tīng)
# 編輯 Docker 配置文件
andy-zhang@localhost:~$ vim.tiny /etc/systemd/system/multi-user.target.wants/docker.service
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
# 在 ExecStart后面添加 “-H tcp://0.0.0.0”
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
然后重啟 Docker Daemon 服務(wù)
systemctl daemon-reload
systemctl restart docker.service
通過(guò)以下命令訪(fǎng)問(wèn)遠(yuǎn)程 Docker Server
docker -H 服務(wù)器IP地址 info
3) Docker Container
上文已經(jīng)對(duì)此進(jìn)行了描述,不再贅述:
Docker 容器(Container)是一個(gè)運(yùn)行時(shí)的概念,可以理解為一個(gè)簡(jiǎn)易的 Linux 系統(tǒng)環(huán)境(包括 root 用戶(hù)權(quán)限、進(jìn)程空間、網(wǎng)絡(luò)空間等概念)以及運(yùn)行在其中的應(yīng)用程序。每個(gè) Docker 容器本質(zhì)上就是一個(gè) Linux 進(jìn)程,擁有自己的上下文環(huán)境,彼此隔離。Docker 引擎能夠?qū)σ粋€(gè)容器進(jìn)行啟動(dòng)、停止、刪除等操作。
4) Docker Image
上文已經(jīng)對(duì)此進(jìn)行了描述,不再贅述:
Docker 鏡像(Image)和虛擬機(jī)鏡像的概念是一樣的,可以將其理解為一個(gè)面向 Docker 引擎的只讀模板,可用于批量創(chuàng)造可運(yùn)行的容器實(shí)例。Docker 鏡像可以看作是一個(gè)特殊的文件系統(tǒng),除了提供容器運(yùn)行時(shí)所需的程序、庫(kù)、資源、配置等文件外,還包含了一些為運(yùn)行時(shí)準(zhǔn)備的一些配置參數(shù)(如環(huán)境變量、用戶(hù)等)。鏡像不包含任何動(dòng)態(tài)數(shù)據(jù),其內(nèi)容在構(gòu)建之后也不會(huì)被改變。鏡像是創(chuàng)建 Docker 容器的基礎(chǔ),而 Docker 體系能夠提供一套簡(jiǎn)單的機(jī)制創(chuàng)建和更新已有的鏡像,也可以從網(wǎng)上下載一個(gè)制作好的現(xiàn)成的鏡像。
5) Docker Registry
上文已經(jīng)對(duì)此進(jìn)行了描述,不再贅述:
Docker 倉(cāng)庫(kù)(Reopsitory)類(lèi)似代碼倉(cāng)庫(kù),是 Docker 體系集中存放鏡像文件的場(chǎng)所。一般情況下,一個(gè)倉(cāng)庫(kù)會(huì)包含同一個(gè)軟件不同版本的鏡像,用“標(biāo)簽”的概念來(lái)標(biāo)記版本 ??梢酝ㄟ^(guò)<倉(cāng)庫(kù)名>:<標(biāo)簽>的格式來(lái)精確定位具體采用哪個(gè)鏡像。如果不指定標(biāo)簽,則采用 latest 作為默認(rèn)標(biāo)簽。
根據(jù)存儲(chǔ)的鏡像公開(kāi)與否,可以分為公開(kāi)倉(cāng)庫(kù)(Public)和私有倉(cāng)庫(kù)(Private),目前最大的公開(kāi)倉(cāng)庫(kù)是 Docker Hub,用戶(hù)可以在自己的本地網(wǎng)絡(luò)中創(chuàng)建私有倉(cāng)庫(kù)。
Docker 利用倉(cāng)庫(kù)管理鏡像的理念類(lèi)似于 Git,默認(rèn)情況下 Docker 會(huì)在中央倉(cāng)庫(kù)(Docker Hub 和 Docker Cloud)尋找鏡像文件。
運(yùn)行 docker push、docker pull、docker search 命令時(shí),實(shí)際上是 Docker Client 通過(guò) Docker Daemon 與 Docker Registry 進(jìn)行通信。

關(guān)于 Docker 的架構(gòu)詳解,有必要會(huì)單獨(dú)寫(xiě)一篇學(xué)習(xí)筆記,本篇筆記不再展開(kāi)了。
四、Docker 容器的安裝
Docker 官方文檔是最好的安裝指南:Install Docker on Ubuntu
以 Ubuntu 為例,可以采用兩種方式進(jìn)行安裝:
- Docker Repository(推薦方式)
- Docker Debian Package
方式一:Docker Repository
- 更新
apt列表
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
- 允許 apt 能夠通過(guò) HTTPs 方式使用倉(cāng)庫(kù)
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
- 添加 Dokcer 官方 GPG Key
sudo apt-key fingerprint 0EBFCD88
- 設(shè)置 Docker-CE 穩(wěn)定版的倉(cāng)庫(kù)
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
- 安裝最新版本的 Docker
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
如果想安裝指定版本的 Docker 怎么辦?
# 獲取 Docker 版本列表
apt-cache madison docker-ce
# 安裝指定版本,修改 "<>" 中的版本號(hào)
sudo apt-get install docker-ce=<18.03.1~ce-0~ubuntu>
- 檢查 Docker 版本
sudo docker version
Client: Docker Engine - Community
Version: 19.03.5
API version: 1.40
Go version: go1.12.12
Git commit: 633a0ea838
Built: Wed Nov 13 07:29:52 2019
OS/Arch: linux/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 19.03.5
API version: 1.40 (minimum version 1.12)
Go version: go1.12.12
Git commit: 633a0ea838
Built: Wed Nov 13 07:28:22 2019
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.2.10
GitCommit: b34a5c8af56e510852c35414db4c1f4fa6172339
runc:
Version: 1.0.0-rc8+dev
GitCommit: 3e425f80a8c931f88e6d94a8c831b9d5aa481657
docker-init:
Version: 0.18.0
GitCommit: fec3683
方式二:Docker Debian Package
下載 Docker 壓縮包
下載地址:Ubuntu Docerk 壓縮包地址安裝 Docker
sudo dpkg -i /home/andy/docker/package.deb
五、Docker 容器的基本操作
首先,通過(guò)一個(gè) HelloWord 的例子,對(duì) Docker 體系各組件的協(xié)作流程有個(gè)整體的理解,這對(duì)進(jìn)一步掌握和理解 Docker 的操作方法會(huì)有很好的幫助:

從 hello-world 打印中,官方還給出了如何運(yùn)行一個(gè) Ubuntu 容器的例子,可以認(rèn)為在這個(gè)容器中運(yùn)行的是一個(gè)極簡(jiǎn)的 Ubuntu Linux 系統(tǒng),一個(gè)極為輕量的 GuestOS。

Docker 的操作命令也是非常多的,執(zhí)行 docker --help 能夠看到所有命令接口。這篇筆記只記錄一些關(guān)于鏡像、容器、倉(cāng)庫(kù)的基本操作方法。
andy-zhang@localhost:~$ sudo docker --help
[sudo] password for andy-zhang:
Usage: docker [OPTIONS] COMMAND
A self-sufficient runtime for containers
Options:
--config string Location of client config files (default "/home/andy-zhang/.docker")
-c, --context string Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and default
context set with "docker context use")
-D, --debug Enable debug mode
-H, --host list Daemon socket(s) to connect to
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
--tls Use TLS; implied by --tlsverify
--tlscacert string Trust certs signed only by this CA (default "/home/andy-zhang/.docker/ca.pem")
--tlscert string Path to TLS certificate file (default "/home/andy-zhang/.docker/cert.pem")
--tlskey string Path to TLS key file (default "/home/andy-zhang/.docker/key.pem")
--tlsverify Use TLS and verify the remote
-v, --version Print version information and quit
Management Commands:
builder Manage builds
config Manage Docker configs
container Manage containers
context Manage contexts
engine Manage the docker engine
image Manage images
network Manage networks
node Manage Swarm nodes
plugin Manage plugins
secret Manage Docker secrets
service Manage services
stack Manage Docker stacks
swarm Manage Swarm
system Manage Docker
trust Manage trust on Docker images
volume Manage volumes
Commands:
attach Attach local standard input, output, and error streams to a running container
build Build an image from a Dockerfile
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes to files or directories on a container's filesystem
events Get real time events from the server
exec Run a command in a running container
export Export a container's filesystem as a tar archive
history Show the history of an image
images List images
import Import the contents from a tarball to create a filesystem image
info Display system-wide information
inspect Return low-level information on Docker objects
kill Kill one or more running containers
load Load an image from a tar archive or STDIN
login Log in to a Docker registry
logout Log out from a Docker registry
logs Fetch the logs of a container
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
ps List containers
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
rmi Remove one or more images
run Run a command in a new container
save Save one or more images to a tar archive (streamed to STDOUT by default)
search Search the Docker Hub for images
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
version Show the Docker version information
wait Block until one or more containers stop, then print their exit codes
Run 'docker COMMAND --help' for more information on a command.
鏡像的基本操作:
1)獲取鏡像
【命令】:docker pull NAME[:TAG]
【說(shuō)明】:使用該指令從網(wǎng)絡(luò)上下載指定的鏡像文件。如果不顯示的指定 “TAG”,默認(rèn)選擇 “l(fā)atest” 標(biāo)簽,即對(duì)應(yīng)倉(cāng)庫(kù)中最新版本的鏡像文件。
以獲取 Ubuntu 鏡像為例:
andy-zhang@localhost:~$ sudo docker pull ubuntu:latest
[sudo] password for andy-zhang:
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
5c939e3a4d10: Pull complete
c63719cdbe7a: Pull complete
19a861ea6baf: Pull complete
651c9d2d6c4f: Pull complete
Digest: sha256:8d31dad0c58f552e890d68bbfb735588b6b820a46e459672d96e585871acc110
Status: Downloaded newer image for ubuntu:latest
Docker 倉(cāng)庫(kù)中最新的 Ubuntu 版本為 18.04.3。從下載過(guò)程中能看到一個(gè)小細(xì)節(jié),鏡像是分層的,“5c939e3a4d10” 這樣的數(shù)字代表每一層的ID。分層其實(shí)是 AUFS(Advanced Union File System,聯(lián)合文件系統(tǒng)) 的重要概念,可以實(shí)現(xiàn) Docker 鏡像的增量保存與更新。AUFS 是比較重要的機(jī)制,但這里不再展開(kāi)了。
docker pull 指令默認(rèn)從 Docker 官方的注冊(cè)服務(wù)器(也可以稱(chēng)作鏡像源)中進(jìn)行下載,"docker pull ubuntu:latest" 這條指令等價(jià)于 “docker pull registry.hub.docker.com/ubuntu:latest”,也就是從默認(rèn)的注冊(cè)服務(wù)器“registry.hub.docker.com”中的 “ubuntu” 倉(cāng)庫(kù)中下載標(biāo)簽為 “l(fā)atest” 的鏡像文件。鏡像源可以改變,比如從 DockerPool 社區(qū)的鏡像源 “dl.dockerpol.com” 下載,但需要在命令中進(jìn)行顯示指定。
鏡像下載到本地后,就可以進(jìn)行各種操作了,比如利用該鏡像創(chuàng)建一個(gè) Ubuntu 容器,并在其中運(yùn)行bash應(yīng)用:
andy-zhang@localhost:~$ sudo docker run -i -t ubuntu bash
root@f90e0ca4b855:/# pwd
/
root@f90e0ca4b855:/# whoami
root
root@f90e0ca4b855:/# uname -a
Linux f90e0ca4b855 4.4.0-62-generic #83-Ubuntu SMP Wed Jan 18 14:10:15 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
2)查看鏡像
【命令】:docker images
【說(shuō)明】:使用該指令查詢(xún)本地已經(jīng)擁有的鏡像。
andy-zhang@localhost:~$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest ccc6e87d482b 2 weeks ago 64.2MB
hello-world latest fce289e99eb9 13 months ago 1.84kB
【命令】:docker inspect NAME[:TAG]
【說(shuō)明】:獲取鏡像的詳細(xì)信息,返回 JSON 格式的消息。使用者一般情況下應(yīng)該不太需要查詢(xún)?nèi)绱嗽敿?xì)的信息。
andy-zhang@localhost:~$ sudo docker inspect hello-world:latest
[
{
"Id": "sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e",
"RepoTags": [
"hello-world:latest"
],
"RepoDigests": [
"hello-world@sha256:9572f7cdcee8591948c2963463447a53466950b3fc15a247fcad1917ca215a2f"
],
"Parent": "",
"Comment": "",
"Created": "2019-01-01T01:29:27.650294696Z",
"Container": "8e2caa5a514bb6d8b4f2a2553e9067498d261a0fd83a96aeaaf303943dff6ff9",
"ContainerConfig": {
"Hostname": "8e2caa5a514b",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"/hello\"]"
],
"ArgsEscaped": true,
"Image": "sha256:a6d1aaad8ca65655449a26146699fe9d61240071f6992975be7e720f1cd42440",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"DockerVersion": "18.06.1-ce",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/hello"
],
"ArgsEscaped": true,
"Image": "sha256:a6d1aaad8ca65655449a26146699fe9d61240071f6992975be7e720f1cd42440",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"Architecture": "amd64",
"Os": "linux",
"Size": 1840,
"VirtualSize": 1840,
"GraphDriver": {
"Data": {
"MergedDir": "/var/lib/docker/overlay2/8fcf5abbb31dbe70e7fe9e6cc3d4515b9dfa243adee48efff812bcca9551d488/merged",
"UpperDir": "/var/lib/docker/overlay2/8fcf5abbb31dbe70e7fe9e6cc3d4515b9dfa243adee48efff812bcca9551d488/diff",
"WorkDir": "/var/lib/docker/overlay2/8fcf5abbb31dbe70e7fe9e6cc3d4515b9dfa243adee48efff812bcca9551d488/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:af0b15c8625bb1938f1d7b17081031f649fd14e6b233688eea3c5483994a66a3"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]
3)查找鏡像
【命令】:docker search NAME
【說(shuō)明】:搜索遠(yuǎn)端倉(cāng)庫(kù)中的鏡像,默認(rèn)為 Docker Hub 官方倉(cāng)庫(kù)。而且結(jié)果會(huì)按照星級(jí)進(jìn)行自動(dòng)排序。也可以直接訪(fǎng)問(wèn) Docker Hub 的網(wǎng)址(Docker Hub),更直觀一些。
andy-zhang@localhost:~$ sudo docker search php
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
php While designed for web development, the PHP … 5025 [OK]
phpmyadmin/phpmyadmin A web interface for MySQL and MariaDB. 937 [OK]
adminer Database management in a single PHP file. 339 [OK]
php-zendserver Zend Server - the integrated PHP application… 178 [OK]
webdevops/php-nginx Nginx with PHP-FPM 149 [OK]
webdevops/php-apache-dev PHP with Apache for Development (eg. with xd… 115 [OK]
webdevops/php-apache Apache with PHP-FPM (based on webdevops/php) 96 [OK]
bitnami/php-fpm Bitnami PHP-FPM Docker Image 84 [OK]
phpunit/phpunit PHPUnit is a programmer-oriented testing fra… 74 [OK]
nazarpc/phpmyadmin phpMyAdmin as Docker container, based on off… 60 [OK]
circleci/php CircleCI images for PHP 27
thecodingmachine/php General-purpose ultra-configurable PHP images 26 [OK]
adrianharabula/php7-with-oci8 Latest PHP 7.1 with apache and Oracle oci8 19 [OK]
phpdockerio/php72-fpm PHP 7.2 FPM base container for PHPDocker.io. 19 [OK]
bitnami/phpmyadmin Bitnami Docker Image for phpMyAdmin 16 [OK]
phpdockerio/php7-fpm PHP 7 FPM base container for PHPDocker.io. 14 [OK]
graze/php-alpine Smallish php7 alpine image with some common … 13 [OK]
phpdockerio/php56-fpm PHP 5.6 FPM base container for PHPDocker.io 11 [OK]
appsvc/php Azure App Service php dockerfiles 10 [OK]
phpdockerio/php71-fpm PHP 7.1 FPM base container for PHPDocker.io. 7 [OK]
phpdockerio/php72-cli PHP 7.2 CLI base container for PHPDocker.io. 4 [OK]
phpdockerio/php56-cli PHP 5.6 CLI base container for PHPDocker.io … 1 [OK]
phpdockerio/php71-cli PHP 7.1 CLI base container for PHPDocker.io. 1 [OK]
phpdockerio/php7-cli PHP 7 CLI base container image for PHPDocker… 1 [OK]
isotopab/php Docker PHP 0 [OK]
4)刪除鏡像
【命令】:docker rmi NAME[:TAG]
【說(shuō)明】:刪除指定的鏡像文件,該鏡像所有的 AUFS 層都會(huì)被刪除掉。需要注意的是,如果存在用該鏡像創(chuàng)建的容器時(shí),鏡像文件是無(wú)法被刪除的,雖然可以通過(guò)添加 “-f” 參數(shù)強(qiáng)制刪除,但不推薦這樣干,可能會(huì)因?yàn)橐蕾?lài)關(guān)系導(dǎo)致出現(xiàn)一些莫名其妙的問(wèn)題。詳情參見(jiàn)如下示例中的注釋。
#查詢(xún)本地的鏡像
andy-zhang@localhost:~$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest ccc6e87d482b 2 weeks ago 64.2MB
hello-world latest fce289e99eb9 13 months ago 1.84kB
#刪除hello-world鏡像,但提示沖突,因?yàn)榇嬖谟迷撶R像創(chuàng)建的容器,刪除失敗
andy-zhang@localhost:~$ sudo docker rmi hello-world
Error response from daemon: conflict: unable to remove repository reference "hello-world" (must force) -
container 3dfa00a4e8b7 is using its referenced image fce289e99eb9
#查詢(xún)系統(tǒng)中存在的容器,果然發(fā)現(xiàn)了用hello-world鏡像創(chuàng)建的容器
andy-zhang@localhost:~$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3dfa00a4e8b7 hello-world "/hello" 49 minutes ago Exited (0) 49 minutes ago boring_brattain
#刪除該容器
andy-zhang@localhost:~$ sudo docker rm 3df
3df
#再次查詢(xún),hello-world容器已經(jīng)不存在了
andy-zhang@localhost:~$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
#再次刪除,刪除成功,所有AUFS層都被刪除掉
andy-zhang@localhost:~$ sudo docker rmi hello-world:latest
Untagged: hello-world:latest
Untagged: hello-world@sha256:9572f7cdcee8591948c2963463447a53466950b3fc15a247fcad1917ca215a2f
Deleted: sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e
Deleted: sha256:af0b15c8625bb1938f1d7b17081031f649fd14e6b233688eea3c5483994a66a3
#再次查詢(xún)本地的鏡像,已經(jīng)沒(méi)有hello-world
andy-zhang@localhost:~$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest ccc6e87d482b 2 weeks ago 64.2MB
5)創(chuàng)建鏡像
創(chuàng)建鏡像有三種方式:
- 基于容器創(chuàng)建
- 基于本地模板創(chuàng)建
- 基于 Dockerfile 創(chuàng)建
基于 Dockerfile 的方式非常重要,后面單獨(dú)寫(xiě)篇筆記,這里主要寫(xiě)一些第一種方式,基于容器創(chuàng)建。
【命令】:docker commit BASED_CONTAINER NAME[:TAG]
【說(shuō)明】:基于已有的容器創(chuàng)建一個(gè)新的鏡像。
下面的例子表示基于正在運(yùn)行的一個(gè)容器,對(duì)其進(jìn)行修改后生成一個(gè)新的鏡像。
#查看本地存在的鏡像,只有一個(gè)ubuntu
andy-zhang@localhost:~$ sudo docker images
[sudo] password for andy-zhang:
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest ccc6e87d482b 2 weeks ago 64.2MB
#基于ubuntu鏡像啟動(dòng)一個(gè)容器,ed6ad16ae768就是容器ID
andy-zhang@localhost:~$ sudo docker run -it ubuntu:latest bash
root@ed6ad16ae768:/#
#創(chuàng)建了一個(gè)文件,這時(shí)候該相對(duì)原ubuntu鏡像已經(jīng)發(fā)生了改變
root@ed6ad16ae768:/# cd /home/
root@ed6ad16ae768:/home# touch hello-andy
root@ed6ad16ae768:/home# ll
total 8
drwxr-xr-x 1 root root 4096 Feb 3 07:36 ./
drwxr-xr-x 1 root root 4096 Feb 3 07:36 ../
-rw-r--r-- 1 root root 0 Feb 3 07:36 hello-andy
#退出系統(tǒng),也就是退出容器
root@ed6ad16ae768:/home# exit
exit
#基于ed6ad16ae768容器創(chuàng)建,名字為hello-andy
andy-zhang@localhost:~$ sudo docker commit ed6ad16ae768 hello-andy
sha256:fb6f9a2b58f7b232c24cbdf4746dcfbcf93ed3b0991d81e53f6d6054311af493
#再次查看本地存在的鏡像,多了hello-andy這個(gè)鏡像,該鏡像其實(shí)就是在ubuntu系統(tǒng)中多創(chuàng)建了一個(gè)文件
andy-zhang@localhost:~$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-andy latest fb6f9a2b58f7 12 seconds ago 64.2MB
ubuntu latest ccc6e87d482b 2 weeks ago 64.2MB
#基于hello-andy鏡像啟動(dòng)一個(gè)容器,1f235281f026是該容器ID
andy-zhang@localhost:~$ sudo docker run -it hello-andy:latest bash
root@1f235281f026:/# cd /home/
#能夠看到,該容器是已經(jīng)包含剛剛創(chuàng)建的hello-andy文件
root@1f235281f026:/home# ll
total 8
drwxr-xr-x 1 root root 4096 Feb 3 07:36 ./
drwxr-xr-x 1 root root 4096 Feb 3 07:39 ../
-rw-r--r-- 1 root root 0 Feb 3 07:36 hello-andy
使用這種方法,可以逐步構(gòu)筑一個(gè)可復(fù)用的新鏡像,比如一個(gè) LAMP(Linux+Apache+MySQL+PHP)。
6)導(dǎo)出鏡像
【命令】:docker save -o FILE
【說(shuō)明】:將本地的鏡像導(dǎo)出到本地文件系統(tǒng)中,這樣就可以向傳送普通文件一樣傳送 Docker 鏡像文件,而不必通過(guò) “pull” 指令從鏡像倉(cāng)庫(kù)中獲取。
andy-zhang@localhost:~$ sudo docker save -o hello-world-andy.tar hello-world:latest
andy-zhang@localhost:~$ ll
total 65104
drwxr-xr-x 4 andy-zhang andy-zhang 4096 Feb 3 00:13 ./
drwxr-xr-x 3 root root 4096 Jan 31 07:43 ../
-rw------- 1 andy-zhang andy-zhang 1887 Feb 2 02:19 .bash_history
-rw-r--r-- 1 andy-zhang andy-zhang 220 Jan 31 07:43 .bash_logout
-rw-r--r-- 1 andy-zhang andy-zhang 3771 Jan 31 07:43 .bashrc
drwx------ 2 andy-zhang andy-zhang 4096 Jan 31 15:19 .cache/
-rw------- 1 root root 12800 Feb 3 00:13 hello-world-andy.tar
-rw-r--r-- 1 andy-zhang andy-zhang 655 Jan 31 07:43 .profile
drwxrwxr-x 2 andy-zhang andy-zhang 4096 Jan 31 19:46 software/
7)導(dǎo)入鏡像
【命令】:docker load < FILE
【說(shuō)明】:從本地文件系統(tǒng)導(dǎo)入 Docker 鏡像文件到本地倉(cāng)庫(kù),是導(dǎo)出的逆操作。
#基于存在的ubuntu容器創(chuàng)建一個(gè)新的鏡像ubuntu-hello-andy,前文已經(jīng)描述,不再贅述
andy-zhang@localhost:~$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest ccc6e87d482b 2 weeks ago 64.2MB
hello-world latest fce289e99eb9 13 months ago 1.84kB
andy-zhang@localhost:~$ sudo docker run -it ubuntu:latest bash
root@3e96a231dff7:/# touch /home/hello-andy
root@3e96a231dff7:/# ls /home
hello-andy
root@3e96a231dff7:/# exit
exit
andy-zhang@localhost:~$ sudo docker commit 3e96a231dff7 ubuntu-hello-andy:latest
sha256:0cf13cb05975c7b83b56c4e52ba697f7007ba7d3751b43787bae74d8476d7efc
andy-zhang@localhost:~$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu-hello-andy latest 0cf13cb05975 10 seconds ago 64.2MB
ubuntu latest ccc6e87d482b 2 weeks ago 64.2MB
hello-world latest fce289e99eb9 13 months ago 1.84kB
#將新的ubuntu-hello-world鏡像導(dǎo)出到本地文件系統(tǒng)
andy-zhang@localhost:~$ sudo docker save -o ubuntu-hello-andy.tar ubuntu-hello-andy:latest
andy-zhang@localhost:~$ ll
total 65104
drwxr-xr-x 4 andy-zhang andy-zhang 4096 Feb 3 00:35 ./
drwxr-xr-x 3 root root 4096 Jan 31 07:43 ../
-rw------- 1 root root 66609152 Feb 3 00:35 ubuntu-hello-andy.tar
#為了查看導(dǎo)入效果,先刪除本地鏡像庫(kù)中的ubuntu-hello-world鏡像刪除
andy-zhang@localhost:~$
andy-zhang@localhost:~$ sudo docker rmi ubuntu-hello-andy
Untagged: ubuntu-hello-andy:latest
Deleted: sha256:0cf13cb05975c7b83b56c4e52ba697f7007ba7d3751b43787bae74d8476d7efc
Deleted: sha256:9f9d42f5978c3879d67fb975eb028bfc23e1f880de02ab99929cdb742a400e2c
andy-zhang@localhost:~$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest ccc6e87d482b 2 weeks ago 64.2MB
hello-world latest fce289e99eb9 13 months ago 1.84kB
#從本地文件系統(tǒng)的ubuntu-hello-andy.tar導(dǎo)入到本地鏡像庫(kù)
andy-zhang@localhost:~$ sudo docker load < ubuntu-hello-andy.tar
44e4e13a1f5b: Loading layer [==================================================>] 3.584kB/3.584kB
Loaded image: ubuntu-hello-andy:latest
#導(dǎo)入成功,運(yùn)行成功
andy-zhang@localhost:~$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu-hello-andy latest 0cf13cb05975 2 minutes ago 64.2MB
ubuntu latest ccc6e87d482b 2 weeks ago 64.2MB
hello-world latest fce289e99eb9 13 months ago 1.84kB
andy-zhang@localhost:~$ sudo docker run -it ubuntu-hello-andy bash
root@651596d03b09:/# ls /home/
hello-andy
8)上傳鏡像
【命令】:docker push NAME[:TAG]
【說(shuō)明】:將本地鏡像上傳到 Docker Hub,前提是在 Docker Hub 上注冊(cè)了用戶(hù)。由于注冊(cè)申請(qǐng)還沒(méi)有通過(guò) Docker Hub 的審批,這里就不舉例了。
容器的基本操作:
1)創(chuàng)建&啟動(dòng)容器
Docker 容器非常的輕量,可以隨時(shí)創(chuàng)建或刪除。有兩種方法新建一個(gè)容器d
方法一:
【命令】:docker create NAME[:TAG] + docker start
【說(shuō)明】:執(zhí)行 create 指令創(chuàng)建的容器不會(huì)自動(dòng)運(yùn)行,處于停止?fàn)顟B(tài),需要執(zhí)行 start 指令將其啟動(dòng)起來(lái)。
#查詢(xún)系統(tǒng)中存在哪些容器
andy-zhang@localhost:~$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3e96a231dff7 ubuntu:latest "bash" 3 hours ago Exited (127) 3 hours ago angry_wu
81418356128d hello-world:latest "/hello" 3 hours ago Exited (0) 2 minutes ago stoic_merkle
#利用hello-world鏡像創(chuàng)建一個(gè)新的容器
andy-zhang@localhost:~$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest ccc6e87d482b 2 weeks ago 64.2MB
hello-world latest fce289e99eb9 13 months ago 1.84kB
andy-zhang@localhost:~$ sudo docker create hello-world
a98bb9e79779affb3cb57df091d3a58ef5d9a0924562e8148e7d08fa3af6e639
#再次查詢(xún)系統(tǒng)中存在哪些容器,系統(tǒng)中已經(jīng)存在兩個(gè)基于hello-world鏡像創(chuàng)建的容器
andy-zhang@localhost:~$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a98bb9e79779 hello-world "/hello" 8 seconds ago Created bold_mendel
3e96a231dff7 ubuntu:latest "bash" 3 hours ago Exited (127) 3 hours ago angry_wu
81418356128d hello-world:latest "/hello" 3 hours ago Exited (0) 3 minutes ago stoic_merkle
#用start指令啟動(dòng)新創(chuàng)建的容器
andy-zhang@localhost:~$ sudo docker start -i a98bb9e79779
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
方法二:
【命令】:docker run NAME[:TAG]
【說(shuō)明】:執(zhí)行 run 指令等價(jià)于 start+start,是更常用的一種方式。執(zhí)行 run 指令后,Docker 后臺(tái)引擎的動(dòng)作是:
- 檢查本地是否存在指定的鏡像,如果沒(méi)有就從公有倉(cāng)庫(kù)中下載
- 利用鏡像創(chuàng)建容器
- 基于 AUFS 在只讀的鏡像外層掛在一層讀寫(xiě)層
- 從宿主主機(jī)配置的網(wǎng)橋接口中橋接一個(gè)虛擬接口到容器中
- 從地址池中分配一個(gè) IP 地址給容器
- 執(zhí)行用戶(hù)指定的應(yīng)用程序
- 執(zhí)行完畢后自動(dòng)終止容器運(yùn)行
這里解釋一下上面運(yùn)行 Ubuntu 容器的時(shí)候,為何會(huì)跟著 “-i” 和 “-t” 兩個(gè)參數(shù)。
#run指令不攜帶任何參數(shù)
andy-zhang@localhost:~$ sudo docker run ubuntu:latest
[sudo] password for andy-zhang:
#run指令攜帶-i和-t參數(shù)
andy-zhang@localhost:~$ sudo docker run -i -t ubuntu:latest
root@3dd7d01955af:/# ps
PID TTY TIME CMD
1 pts/0 00:00:00 bash
10 pts/0 00:00:00 ps
-t 選項(xiàng)讓 Docker 分配一個(gè)偽終端(pseudo-tty),并綁定到容器的標(biāo)準(zhǔn)輸入上;-i 選項(xiàng)則讓容器的標(biāo)準(zhǔn)輸入保持打開(kāi)狀態(tài)。對(duì)于 Ubuntu 應(yīng)用,默認(rèn)會(huì)執(zhí)行 bash。那么,如果希望能夠進(jìn)行持續(xù)性的交互,這兩個(gè)參數(shù)就是必要的了。
另外,很多時(shí)候,需要讓 Docker 容器以守護(hù)形式(Daemonized)運(yùn)行(Web服務(wù)器是典型的守護(hù)形式程序),可以增加 -d 選項(xiàng)來(lái)實(shí)現(xiàn)。下面這個(gè)例子,以守護(hù)形式啟動(dòng)一個(gè) Ubuntu 的容器,執(zhí)行 shell 程序,通過(guò) docker logs CONTAINER 指令查看容器后臺(tái)輸出信息。
andy-zhang@localhost:~$ sudo docker run -d ubuntu:latest /bin/sh -c "while true; do echo hello andy; sleep 1; done"
andy-zhang@localhost:~$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f00b81c23380 ubuntu:latest "/bin/sh -c 'while t…" 47 seconds ago Up 45 seconds angry_mclaren
3dd7d01955af ubuntu:latest "/bin/bash" 39 minutes ago Exited (0) 4 minutes ago elastic_brattain
andy-zhang@localhost:~$ sudo docker logs f00b81c23380
hello andy
hello andy
hello andy
hello andy
hello andy
hello andy
2)終止容器
【命令】:docker stop
【說(shuō)明】:終止容器的運(yùn)行有兩種方式,一種方式是執(zhí)行 “stop” 指令方式,首先向容器發(fā)送一個(gè) SIGTERM 信號(hào),等待一段時(shí)間后(默認(rèn)10秒)再向容器發(fā)送一個(gè) SIGKILL 信號(hào)徹底終止容器;另一種方式是自然終止,也就是容器中運(yùn)行的程序執(zhí)行完畢后自行退出,容器會(huì)緊跟著中止運(yùn)行。
下面的示例是終止上面創(chuàng)建的 while 死循環(huán)的容器:
#容器正在運(yùn)行
andy-zhang@localhost:~$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f00b81c23380 ubuntu:latest "/bin/sh -c 'while t…" 10 minutes ago Up 10 minutes angry_mclaren
#執(zhí)行終止指令
andy-zhang@localhost:~$ sudo docker stop f00b81c23380
f00b81c23380
#容器終止,能夠明顯感受到SIGTERM和SIGKILL信號(hào)10s間隔
andy-zhang@localhost:~$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f00b81c23380 ubuntu:latest "/bin/sh -c 'while t…" 11 minutes ago Exited (137) 4 seconds ago angry_mclaren
3)進(jìn)入容器
【命令】:docker exec CONTAINER COMMAND
【說(shuō)明】:采用守護(hù)形式啟動(dòng)容器后,容器進(jìn)入后臺(tái)運(yùn)行,用戶(hù)無(wú)法看到容器中發(fā)生了什么。有的時(shí)候,有必要進(jìn)入容器進(jìn)行一些操作,這時(shí)候可以利用 “exec” 指令,如下示例:
#以守護(hù)形式啟動(dòng)一個(gè)容器
andy-zhang@localhost:~$ sudo docker run -d ubuntu:latest /bin/sh -c "while true; do echo hello andy; sleep 1; done"
andy-zhang@localhost:~$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5390d39f4ee0 ubuntu:latest "/bin/sh -c 'while t…" 53 seconds ago Up 53 seconds nostalgic_babbage
#使用exec指令進(jìn)入正在運(yùn)行的容器中,執(zhí)行各種操作
andy-zhang@localhost:~$ sudo docker exec -i -t 5390d39f4ee0 bash
root@5390d39f4ee0:/# ps -a
PID TTY TIME CMD
146 pts/0 00:00:00 ps
root@5390d39f4ee0:/# ps -ax
PID TTY STAT TIME COMMAND
1 ? Ss 0:00 /bin/sh -c while true; do echo hello andy; sleep 1; done
131 pts/0 Ss 0:00 bash
152 ? S 0:00 sleep 1
153 pts/0 R+ 0:00 ps -ax
4)刪除容器
【命令】:docker rm CONTAINER
【說(shuō)明】:刪除處于終止?fàn)顟B(tài)的容器,如果容器運(yùn)行中,需要先停止,否則會(huì)提示失敗,可以使用 “-f” 選項(xiàng)強(qiáng)制進(jìn)行刪除。
#刪除正在運(yùn)行的容器,提示失敗
andy-zhang@localhost:~$ sudo docker rm 5390d39f4ee0
Error response from daemon: You cannot remove a running container
5390d39f4ee0c41731ec784bb3ed9c41b62b04ac6cfd391e4690eb07e574d4e5. Stop the container before attempting removal or force remove
#強(qiáng)制刪除
andy-zhang@localhost:~$ sudo docker rm -f 5390d39f4ee0
5390d39f4ee0
#刪除成功
andy-zhang@localhost:~$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
別混淆:刪除容器是 “rm” 指令,刪除鏡像是 “rmi” 指令。
倉(cāng)庫(kù)的基本操作:
倉(cāng)庫(kù)(Repository)是集中存放鏡像的地方。但倉(cāng)庫(kù)容易和注冊(cè)服務(wù)器(Registry)相混淆。準(zhǔn)確的說(shuō),注冊(cè)服務(wù)器是存放倉(cāng)庫(kù)的具體服務(wù)器,可以存儲(chǔ)多個(gè)倉(cāng)庫(kù);而每個(gè)倉(cāng)庫(kù)下面可以存放多個(gè)鏡像,用標(biāo)簽(TAG)進(jìn)行區(qū)分。通常情況下,一個(gè)倉(cāng)庫(kù)中存放的都是同一類(lèi)型的鏡像。
也就是說(shuō),精確定位具體的鏡像文件的 “URL” 是:Image = Registry + Repository + Tag。
這三者的關(guān)系可以用下面的圖來(lái)表示:

鏡像資源一般可以分成兩類(lèi),一類(lèi)是官方提供的,由 Docker 公司創(chuàng)建、驗(yàn)證、發(fā)布;另一類(lèi)是第三方組織/個(gè)人提供的。在前面鏡像基本操作的筆記中,提到了 “search” 指令。從該指令的查詢(xún)結(jié)果中能夠看出來(lái),由官方發(fā)布的鏡像,往往用單個(gè)單詞作為名字;而第三方組織或個(gè)人提供的,往往都帶有用戶(hù)名前綴。
如下面的示例所示,官方發(fā)布的鏡像有 “php”、“adminer”、“php-zendserver”,第三方組織的則有 “phpmyadmin/phpmyadmin”、“webdevops/php-ngnix”等。
andy-zhang@localhost:~$ sudo docker search php
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
php While designed for web development, the PHP … 5025 [OK]
phpmyadmin/phpmyadmin A web interface for MySQL and MariaDB. 937 [OK]
adminer Database management in a single PHP file. 339 [OK]
php-zendserver Zend Server - the integrated PHP application… 178 [OK]
webdevops/php-nginx Nginx with PHP-FPM 149 [OK]
webdevops/php-apache-dev PHP with Apache for Development (eg. with xd… 115 [OK]
webdevops/php-apache Apache with PHP-FPM (based on webdevops/php) 96 [OK]
bitnami/php-fpm Bitnami PHP-FPM Docker Image
在當(dāng)前的工作中,主要適用官方提供的倉(cāng)庫(kù)就可以滿(mǎn)足要求,對(duì)于如何創(chuàng)建和適用私有倉(cāng)庫(kù),在這篇筆記中不再涉及,如果工作中有需要時(shí),再進(jìn)行研究了。
以上,就是 Docker 基本的概念與基本的操作方法。敲了很多字,但心情很爽。后面還會(huì)繼續(xù)補(bǔ)充幾篇筆記,涉及 Docker 的數(shù)據(jù)管理、基礎(chǔ)網(wǎng)絡(luò)配置、Dockerfile、經(jīng)典應(yīng)用、Docker 安全等內(nèi)容。
永遠(yuǎn)學(xué)習(xí)。
也向一線(xiàn)抗戰(zhàn)的醫(yī)護(hù)人員致敬。
