Docker 學(xué)習(xí)筆記(一):基礎(chǔ)概念與基本操

這篇筆記分成四個(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是什么

二、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ù)器上

容器引擎部署在裸金屬服務(wù)器上

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

容器引擎部署在虛擬機(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è)組件的事情上了。

曾經(jīng)掉過(guò)的坑

所以,容器技術(shù)受到了廣大開(kāi)發(fā)和運(yùn)維人員的喜愛(ài),能夠給大家?guī)?lái)很多實(shí)際的好處:

  1. 更快速的交付和部署。顯而易見(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ù)。
  2. 更高效的資源利用。容器不需要 GuestOS,這使得資源占用就具備很大優(yōu)勢(shì)了。而且由于容器共享宿主機(jī)(HostOS)的內(nèi)核空間,理論上能夠獲得更高的執(zhí)行效率。
  3. 更輕松的遷移和擴(kuò)展。Docker 容器幾乎可以在各種基礎(chǔ)設(shè)施平臺(tái)上運(yùn)行,只需要該平臺(tái)上部署了 Docker Engine。比如物理機(jī)、虛擬機(jī)、公有云、私有云、混合云等等。
  4. 更簡(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 vs Virtual Machine

三、Docker 容器的核心概念

Docker 有三個(gè)核心概念:

  1. 鏡像(Image)
  2. 容器(Container)
  3. 倉(cāng)庫(kù)(Repository)

理解了這三個(gè)核心概念,對(duì)于理解 Docker 整個(gè)生命周期會(huì)很有幫助。下面是一張被多次引用的圖,清晰的描述了 Docker 的生命周期。

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基本架構(gòu)

從上圖能夠看到,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)行處理。

Docker Daemon邏輯架構(gòu)

默認(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)行通信。

Docker Client-Daemon-Registry 的關(guān)系

關(guān)于 Docker 的架構(gòu)詳解,有必要會(huì)單獨(dú)寫(xiě)一篇學(xué)習(xí)筆記,本篇筆記不再展開(kāi)了。

四、Docker 容器的安裝

Docker 官方文檔是最好的安裝指南:Install Docker on Ubuntu

以 Ubuntu 為例,可以采用兩種方式進(jìn)行安裝:

  1. Docker Repository(推薦方式)
  2. Docker Debian Package
方式一:Docker Repository
  1. 更新 apt 列表
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common
  1. 允許 apt 能夠通過(guò) HTTPs 方式使用倉(cāng)庫(kù)
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
  1. 添加 Dokcer 官方 GPG Key
sudo apt-key fingerprint 0EBFCD88
  1. 設(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"
  1. 安裝最新版本的 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>
  1. 檢查 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
  1. 下載 Docker 壓縮包
    下載地址:Ubuntu Docerk 壓縮包地址

  2. 安裝 Docker

sudo dpkg -i /home/andy/docker/package.deb

五、Docker 容器的基本操作

首先,通過(guò)一個(gè) HelloWord 的例子,對(duì) Docker 體系各組件的協(xié)作流程有個(gè)整體的理解,這對(duì)進(jìn)一步掌握和理解 Docker 的操作方法會(huì)有很好的幫助:

Docker Hello-World

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

Docker Ubuntu

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)表示:

Registry-Repository-Tag

鏡像資源一般可以分成兩類(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ù)人員致敬。

Docker
?著作權(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)容

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