Docker的鏡像和容器

我們在理解 docker 之前,首先我們得先區(qū)分清楚兩個(gè)概念,容器虛擬機(jī)。

可能很多讀者朋友都用過虛擬機(jī),而對容器這個(gè)概念比較的陌生。

我們用的傳統(tǒng)虛擬機(jī)如 VMware , VisualBox 之類的需要模擬整臺(tái)機(jī)器包括硬件,每臺(tái)虛擬機(jī)都需要有自己的操作系統(tǒng),虛擬機(jī)一旦被開啟,預(yù)分配給它的資源將全部被占用。每一臺(tái)虛擬機(jī)包括應(yīng)用,必要的二進(jìn)制和庫,以及一個(gè)完整的用戶操作系統(tǒng)。

而容器技術(shù)是和我們的宿主機(jī)共享硬件資源及操作系統(tǒng),可以實(shí)現(xiàn)資源的動(dòng)態(tài)分配。容器包含應(yīng)用和其所有的依賴包,但是與其他容器共享內(nèi)核。容器在宿主機(jī)操作系統(tǒng)中,在用戶空間以分離的進(jìn)程運(yùn)行。

容器技術(shù)是實(shí)現(xiàn)操作系統(tǒng)虛擬化的一種途徑,可以讓您在資源受到隔離的進(jìn)程中運(yùn)行應(yīng)用程序及其依賴關(guān)系。通過使用容器,我們可以輕松打包應(yīng)用程序的代碼、配置和依賴關(guān)系,將其變成容易使用的構(gòu)建塊,從而實(shí)現(xiàn)環(huán)境一致性、運(yùn)營效率、開發(fā)人員生產(chǎn)力和版本控制等諸多目標(biāo)。容器可以幫助保證應(yīng)用程序快速、可靠、一致地部署,其間不受部署環(huán)境的影響。容器還賦予我們對資源更多的精細(xì)化控制能力,讓我們的基礎(chǔ)設(shè)施效率更高。通過下面這幅圖我們可以很直觀的反映出這兩者的區(qū)別所在。

image

Docker 屬于 Linux 容器的一種封裝,提供簡單易用的容器使用接口。它是目前最流行的 Linux 容器解決方案。

Linux 容器是 Linux 發(fā)展出了另一種虛擬化技術(shù),簡單來講, Linux 容器不是模擬一個(gè)完整的操作系統(tǒng),而是對進(jìn)程進(jìn)行隔離,相當(dāng)于是在正常進(jìn)程的外面套了一個(gè)保護(hù)層。對于容器里面的進(jìn)程來說,它接觸到的各種資源都是虛擬的,從而實(shí)現(xiàn)與底層系統(tǒng)的隔離。

Docker 將應(yīng)用程序與該程序的依賴,打包在一個(gè)文件里面。運(yùn)行這個(gè)文件,就會(huì)生成一個(gè)虛擬容器。程序在這個(gè)虛擬容器里運(yùn)行,就好像在真實(shí)的物理機(jī)上運(yùn)行一樣。有了 Docker ,就不用擔(dān)心環(huán)境問題。

總體來說, Docker 的接口相當(dāng)簡單,用戶可以方便地創(chuàng)建和使用容器,把自己的應(yīng)用放入容器。容器還可以進(jìn)行版本管理、復(fù)制、分享、修改,就像管理普通的代碼一樣。

Docker的優(yōu)勢

Docker相比于傳統(tǒng)虛擬化方式具有更多的優(yōu)勢:

  • docker 啟動(dòng)快速屬于秒級別。虛擬機(jī)通常需要幾分鐘去啟動(dòng)
  • docker 需要的資源更少, docker 在操作系統(tǒng)級別進(jìn)行虛擬化, docker 容器和內(nèi)核交互,幾乎沒有性能損耗,性能優(yōu)于通過 Hypervisor 層與內(nèi)核層的虛擬化
  • docker 更輕量, docker 的架構(gòu)可以共用一個(gè)內(nèi)核與共享應(yīng)用程序庫,所占內(nèi)存極小。同樣的硬件環(huán)境, Docker 運(yùn)行的鏡像數(shù)遠(yuǎn)多于虛擬機(jī)數(shù)量,對系統(tǒng)的利用率非常高
  • 與虛擬機(jī)相比, docker 隔離性更弱, docker 屬于進(jìn)程之間的隔離,虛擬機(jī)可實(shí)現(xiàn)系統(tǒng)級別隔離
  • 安全性: docker 的安全性也更弱。 Docker 的租戶 root 和宿主機(jī) root 等同,一旦容器內(nèi)的用戶從普通用戶權(quán)限提升為root權(quán)限,它就直接具備了宿主機(jī)的root權(quán)限,進(jìn)而可進(jìn)行無限制的操作。虛擬機(jī)租戶 root 權(quán)限和宿主機(jī)的 root 虛擬機(jī)權(quán)限是分離的,并且虛擬機(jī)利用如 IntelVT-dVT-xring-1 硬件隔離技術(shù),這種隔離技術(shù)可以防止虛擬機(jī)突破和彼此交互,而容器至今還沒有任何形式的硬件隔離,這使得容器容易受到攻擊
  • 可管理性: docker 的集中化管理工具還不算成熟。各種虛擬化技術(shù)都有成熟的管理工具,例如 VMware vCenter 提供完備的虛擬機(jī)管理能力
  • 高可用和可恢復(fù)性: docker 對業(yè)務(wù)的高可用支持是通過快速重新部署實(shí)現(xiàn)的。虛擬化具備負(fù)載均衡,高可用,容錯(cuò),遷移和數(shù)據(jù)保護(hù)等經(jīng)過生產(chǎn)實(shí)踐檢驗(yàn)的成熟保障機(jī)制, VMware 可承諾虛擬機(jī) 99.999% 高可用,保證業(yè)務(wù)連續(xù)性
  • 快速創(chuàng)建、刪除:虛擬化創(chuàng)建是分鐘級別的, Docker 容器創(chuàng)建是秒級別的, Docker 的快速迭代性,決定了無論是開發(fā)、測試、部署都可以節(jié)約大量時(shí)間
  • 交付、部署:虛擬機(jī)可以通過鏡像實(shí)現(xiàn)環(huán)境交付的一致性,但鏡像分發(fā)無法體系化。 DockerDockerfile 中記錄了容器構(gòu)建過程,可在集群中實(shí)現(xiàn)快速分發(fā)和快速部署

我們可以從下面這張表格很清楚地看到容器相比于傳統(tǒng)虛擬機(jī)的特性的優(yōu)勢所在:

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

Docker的三個(gè)基本概念

image.png

從上圖我們可以看到,Docker 中包括三個(gè)基本的概念:

  • Image(鏡像)
  • Container(容器)
  • Repository(倉庫)
    鏡像是 Docker 運(yùn)行容器的前提,倉庫是存放鏡像的場所,可見鏡像更是 Docker 的核心。

Image (鏡像)

那么鏡像到底是什么呢?

Docker 鏡像可以看作是一個(gè)特殊的文件系統(tǒng),除了提供容器運(yùn)行時(shí)所需的程序、庫、資源、配置等文件外,還包含了一些為運(yùn)行時(shí)準(zhǔn)備的一些配置參數(shù)(如匿名卷、環(huán)境變量、用戶等)。鏡像不包含任何動(dòng)態(tài)數(shù)據(jù),其內(nèi)容在構(gòu)建之后也不會(huì)被改變。

鏡像(Image)就是一堆只讀層(read-only layer)的統(tǒng)一視角,也許這個(gè)定義有些難以理解,下面的這張圖能夠幫助讀者理解鏡像的定義。

image

從左邊我們看到了多個(gè)只讀層,它們重疊在一起。除了最下面一層,其它層都會(huì)有一個(gè)指針指向下一層。這些層是Docker 內(nèi)部的實(shí)現(xiàn)細(xì)節(jié),并且能夠在主機(jī)的文件系統(tǒng)上訪問到。統(tǒng)一文件系統(tǒng) (union file system) 技術(shù)能夠?qū)⒉煌膶诱铣梢粋€(gè)文件系統(tǒng),為這些層提供了一個(gè)統(tǒng)一的視角,這樣就隱藏了多層的存在,在用戶的角度看來,只存在一個(gè)文件系統(tǒng)。我們可以在圖片的右邊看到這個(gè)視角的形式。

Container (容器)

容器 (container) 的定義和鏡像 (image) 幾乎一模一樣,也是一堆層的統(tǒng)一視角,唯一區(qū)別在于容器的最上面那一層是可讀可寫的。

image

由于容器的定義并沒有提及是否要運(yùn)行容器,所以實(shí)際上,容器 = 鏡像 + 讀寫層。

Repository (倉庫)

Docker 倉庫是集中存放鏡像文件的場所。鏡像構(gòu)建完成后,可以很容易的在當(dāng)前宿主上運(yùn)行,但是, 如果需要在其它服務(wù)器上使用這個(gè)鏡像,我們就需要一個(gè)集中的存儲(chǔ)、分發(fā)鏡像的服務(wù),Docker Registry (倉庫注冊服務(wù)器)就是這樣的服務(wù)。有時(shí)候會(huì)把倉庫 (Repository) 和倉庫注冊服務(wù)器 (Registry) 混為一談,并不嚴(yán)格區(qū)分。Docker 倉庫的概念跟 Git 類似,注冊服務(wù)器可以理解為 GitHub 這樣的托管服務(wù)。實(shí)際上,一個(gè) Docker Registry 中可以包含多個(gè)倉庫 (Repository) ,每個(gè)倉庫可以包含多個(gè)標(biāo)簽 (Tag),每個(gè)標(biāo)簽對應(yīng)著一個(gè)鏡像。所以說,鏡像倉庫是 Docker 用來集中存放鏡像文件的地方類似于我們之前常用的代碼倉庫。

通常,一個(gè)倉庫會(huì)包含同一個(gè)軟件不同版本的鏡像,而標(biāo)簽就常用于對應(yīng)該軟件的各個(gè)版本 。我們可以通過<倉庫名>:<標(biāo)簽>的格式來指定具體是這個(gè)軟件哪個(gè)版本的鏡像。如果不給出標(biāo)簽,將以 latest 作為默認(rèn)標(biāo)簽.。

倉庫又可以分為兩種形式:

  • public(公有倉庫)
  • private(私有倉庫)

Docker Registry 公有倉庫是開放給用戶使用、允許用戶管理鏡像的 Registry 服務(wù)。一般這類公開服務(wù)允許用戶免費(fèi)上傳、下載公開的鏡像,并可能提供收費(fèi)服務(wù)供用戶管理私有鏡像。

除了使用公開服務(wù)外,用戶還可以在本地搭建私有 Docker Registry 。Docker 官方提供了 Docker Registry鏡像,可以直接使用做為私有 Registry 服務(wù)。當(dāng)用戶創(chuàng)建了自己的鏡像之后就可以使用 push 命令將它上傳到公有或者私有倉庫,這樣下次在另外一臺(tái)機(jī)器上使用這個(gè)鏡像時(shí)候,只需要從倉庫上 pull 下來就可以了。

我們主要把 Docker 的一些常見概念如 Image , Container , Repository 做了詳細(xì)的闡述,也從傳統(tǒng)虛擬化方式的角度闡述了 docker 的優(yōu)勢,我們從下圖可以直觀地看到 Docker 的架構(gòu):

framework

Docker 使用 C/S 結(jié)構(gòu),即客戶端/服務(wù)器體系結(jié)構(gòu)。 Docker 客戶端與 Docker 服務(wù)器進(jìn)行交互,Docker服務(wù)端負(fù)責(zé)構(gòu)建、運(yùn)行和分發(fā) Docker 鏡像。 Docker 客戶端和服務(wù)端可以運(yùn)行在一臺(tái)機(jī)器上,也可以通過 RESTful 、 stock 或網(wǎng)絡(luò)接口與遠(yuǎn)程 Docker 服務(wù)端進(jìn)行通信。

docker-framework

這張圖展示了 Docker 客戶端、服務(wù)端和 Docker 倉庫(即 Docker HubDocker Cloud ),默認(rèn)情況下Docker 會(huì)在 Docker 中央倉庫尋找鏡像文件,這種利用倉庫管理鏡像的設(shè)計(jì)理念類似于 Git ,當(dāng)然這個(gè)倉庫是可以通過修改配置來指定的,甚至我們可以創(chuàng)建我們自己的私有倉庫。

Docker的安裝

Centos7上安裝docker

Docker Platform

  • Docker提供了一個(gè)開發(fā)、打包、運(yùn)行app的平臺(tái)
  • Docker把a(bǔ)pp和底層infrastructure隔離開來


    image.png

Docker Engine

Docker Engine是一個(gè)C/S架構(gòu)的應(yīng)用程序,主要包含下面幾個(gè)組件;

  • 常駐后臺(tái)進(jìn)程Dockerd
  • 一個(gè)用來和Dockerd交互的REST API Server
  • 命令行CLI接口,通過和REST API進(jìn)行交互


    image.png

Docker架構(gòu)

image.png

Docker 的核心組件包括:

  • Docker Client
  • Docker daemon
  • Docker Image
  • Docker Registry
  • Docker Container

Docker Damon
Docker Damon來監(jiān)聽Docker API的請求和管理Docker對象,比如鏡像、容器、網(wǎng)絡(luò)和Volume。

Docker Client
docker client是我們和Docker進(jìn)行交互的最主要的方式方法,比如可以通過docker run來運(yùn)行一個(gè)容器,然后我們的這個(gè)client會(huì)把命令發(fā)送給上面的Docker。

Docker Registry
Docker Registry 用來存儲(chǔ)Docker鏡像的倉庫,Docker Hub是Docker官方提供的一個(gè)公共倉庫,而且Docker默認(rèn)也是從Docker Hub上查找鏡像的,當(dāng)然你也可以很方便的運(yùn)行一個(gè)私有倉庫,當(dāng)我們使用docker pull或者docker run命令時(shí),就會(huì)從我們配置的Docker鏡像倉庫中去拉取鏡像,使用docker push命令時(shí),會(huì)將我們構(gòu)建的鏡像推送到對應(yīng)的鏡像倉庫中。

Images 鏡像
鏡像是一個(gè)制度模板,帶有Docker容器的說明。一般來說的,鏡像會(huì)基于另外的一些基礎(chǔ)鏡像上面安裝一個(gè)Nginx服務(wù)器,這樣就可以構(gòu)建一個(gè)屬于我們自己的鏡像了。

Containers 容器
容器是一個(gè)鏡像的可運(yùn)行的實(shí)例,可以使用Docker REST API或者CLI來操作容器,容器的實(shí)質(zhì)是進(jìn)程,但與直接在宿主執(zhí)行的實(shí)例進(jìn)程不同,容器進(jìn)程屬于自己的獨(dú)立的命名空間。因此容器可以擁有自己的root文件系統(tǒng)、自己的網(wǎng)絡(luò)配置、自己的進(jìn)程空間、甚至自己的用戶ID。容器內(nèi)的經(jīng)常是運(yùn)行在一個(gè)隔離的環(huán)境里,使用起來,就好像在一個(gè)獨(dú)立于宿主的系統(tǒng)下操作一樣。這種特性使得容器封裝的應(yīng)用比直接在宿主運(yùn)行更加安全。

Docker底層的技術(shù)支持

Namespaces:做隔離pid、net、ipc、mnt、uts
Control groups:做資源限制
Union file systems:Container和image的分層

Docker Image概述

  • 文件和meta data的集合(root filesystem)
  • 分層的,并且每一層都可以添加、改變和刪除文件,成為一個(gè)新的image
  • 不同的image可以共享相同的layer
  • Image本身是read-only的


Docker技術(shù)里最為基礎(chǔ)的兩大概念:鏡像和容器。

鏡像的獲取方式:

  • 從registry拉取
  • 從Dockerfile構(gòu)建

搜索鏡像

docker search <image> # 在docker index中搜索image
    --automated=false 僅顯示自動(dòng)創(chuàng)建的鏡像
    --no-trunc=false 輸出信息不截?cái)囡@示
    -s 0 指定僅顯示評價(jià)為指定星級的鏡像

下載鏡像

docker pull <image> # 從docker registry server 中下拉image
還可通過指定標(biāo)簽下載某鏡像
    docker pull [:TAG]
    docker pull centos:7

查看鏡像/刪除

docker images: # 列出images
docker images -a # 列出所有的images(包含歷史)
docker ps -a #列出本機(jī)所有容器
docker rmi <image ID>: # 刪除一個(gè)或多個(gè)image

存出和載入鏡像

    存出本地鏡像文件為.tar
    docker save -o ubuntu_14.04.tar ubuntu:14.04
    導(dǎo)入鏡像到本地鏡像庫
    docker load --input ubuntu_14.04.tar或者
    docker load < ubuntu_14.04.tar

上傳鏡像

    用戶在dockerhub網(wǎng)站注冊后,即可上傳自制的鏡像。
    docker push NAME[:TAG]

Container容器

  • 通過Image創(chuàng)建(copy)
  • 在Image layer之上建立一個(gè)container layer(可讀寫)
  • 類比Java面向?qū)ο螅侯惡蛯?shí)例
  • Image負(fù)責(zé)app的存儲(chǔ)和分發(fā),Container負(fù)責(zé)運(yùn)行app


    image.png

創(chuàng)建(使用鏡像創(chuàng)建容器):

    首先得查看鏡像的REPOSITORY和TAG
docker run -i -t REPOSITORY:TAG (等價(jià)于先執(zhí)行docker create 再執(zhí)行docker start 命令)
其中-t選項(xiàng)讓docker分配一個(gè)偽終端并綁定到容器的標(biāo)準(zhǔn)輸入上, -i則讓容器的標(biāo)準(zhǔn)輸入保持打開。若要在后臺(tái)以守護(hù)態(tài)(daemonized)形式運(yùn)行,可加參數(shù)-d

在執(zhí)行docker run來創(chuàng)建并啟動(dòng)容器時(shí),后臺(tái)運(yùn)行的標(biāo)準(zhǔn)包括:

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

進(jìn)入容器:

docker attach [container_id] #連接一個(gè)正在運(yùn)行的container實(shí)例(即實(shí)例須為start狀態(tài),可以多個(gè) 窗口同時(shí)attach 一個(gè)container實(shí)例),但當(dāng)某個(gè)窗口因命令阻塞時(shí),其它窗口也無法執(zhí)行了。

exec可直接在容器內(nèi)運(yùn)行的命令。docker exec -ti [container_id] /bin/bash

刪除容器:

docker rm <container...> #:刪除一個(gè)或多個(gè)container
docker rm `docker ps -a -q` #:刪除所有的container
docker ps -a -q | xargs docker rm #:同上, 刪除所有的container

docker -rm
    -f 強(qiáng)制中止并運(yùn)行的容器
    -l 刪除容器的連接,但保留容器
    -v 刪除容器掛載的數(shù)據(jù)卷

修改容器:

docker commit <container> [repo:tag] # 將一個(gè)container固化為一個(gè)新的image,后面的repo:tag可選。

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

    導(dǎo)出到一個(gè)文件,不管是否處于運(yùn)行狀態(tài)。
    docker export CONTAINER > test.tar

    導(dǎo)入為鏡像:
cat test.tar | docker import - centos:latest

Dockerfile語法梳理及最佳實(shí)踐

一、 FROM

Syntax:

FROM  <image>[:<tag> | @<digest>] [AS <name>]
  • FROM指定一個(gè)基礎(chǔ)鏡像,且必須為Dockerfile文件開篇的每個(gè)非注釋行,至于image則可以是任何合理存在的image鏡像

  • FROM可以在一個(gè)Dockerfile中出現(xiàn)多次,以便于創(chuàng)建混合的images。如果沒有指定tag,latest將會(huì)被指定為要使用的基礎(chǔ)鏡像版本。

  • AS name,可以給新的構(gòu)建階段賦予名稱。該名稱可用于后續(xù)FROM 和 COPY --from=<name | index>說明可以引用此階段中構(gòu)建的鏡像

image.png
  • 為了安全,盡量使用官方的image作為base image

二、LABEL

為鏡像生成元數(shù)據(jù)標(biāo)簽信息
Syntax:

LABEL <KEY>=<VALUE> \
    <KEY>="XXXX"

多個(gè)標(biāo)簽寫成一行,避免在鏡像中額外增加layer


image.png

三、MAINTAINER

作者信息,寫在FROM后
Syntax:

MAINTAINER "auth <email>"

四、COPY

當(dāng)復(fù)制一個(gè)目錄時(shí),并不會(huì)復(fù)制目錄本身,而是會(huì)遞歸復(fù)制其下子目錄 至目標(biāo)目錄下


image.png

Syntax:

COPY data /data/

文件復(fù)制準(zhǔn)則

  • <src>必須是build上下言文中的路徑,不能是其父目錄中的文件
  • 如果<src>是目錄,則其內(nèi)部文件或子目錄會(huì)被遞歸復(fù)制,但<src>目錄自身不會(huì)被復(fù)制
  • 如果指定了多個(gè)<src>,或在<src>中使用了通配符,則<dest>必須是一個(gè)目錄,且必須以/結(jié)尾
  • 如果<dest>事先不存在,它將會(huì)被自動(dòng)創(chuàng)建,這包括其父目錄路徑。

五、ADD

ADD指令類似于COPY指令,ADD支持使用TAR文件和URL路徑


image.png

Syntax:

ADD <src>...<dest>
ADD ["<src>",..."<dest>"]

操作準(zhǔn)則:

  • 如果<src>為URL且<dest>不以/結(jié)尾,則<src>指定的文件將被下載并直接被創(chuàng)建為<dest>;如果<dest>以/結(jié)尾,則文件名URL指定的文件將被直接下載并保存為<dest>/<filename>
  • 如果<src>是一個(gè)本地文件系統(tǒng)上的壓縮格式的tar文件,它將被展開為一個(gè)目錄,其行為類似于"tar -x"命令;然而,通過URL獲取到的tar文件將不會(huì)自動(dòng)展開。
  • 如果<src>有多個(gè),或其間接或直接使用了通配符,則<dest>必須是一個(gè)以/結(jié)尾的目錄路徑;如果<dest>不以/結(jié)尾,則其被視作一個(gè)普通文件,<src>內(nèi)容將被直接寫入到<dest>
  • 為了讓鏡像盡量小,最好不要使用 ADD 指令從遠(yuǎn)程 URL 獲取包,而是使用 curl 和 wget。這樣你可以在文件提取完之后刪掉不再需要的文件來避免在鏡像中額外添加一層。
    示例:
    額外操作:
ADD http://example.com/1.tar.gz /apps/
RUN tar xf /apps/1.tar.gz -C /apps/ && \
    /bin/sh -c /apps/***.sh
     
簡單操作:
RUN mkdir -p /iyunwen/server/ && \
        curl -SL http://example.com/1.tar.gz \
        | tar -xzC /iyunwen/server/ && \
        /bin/sh -c /apps/***.sh

注意:

大部分情況下,COPY由于ADD
ADD除了COPY外還有額外解壓縮功能
添加遠(yuǎn)程文件 / 目錄,請使用curl或者wget

六、WORKDIR

用于為Dockerfile中所有RUN、CMD、ENTRYPOINT、COPY和ADD指令設(shè)定工作目錄


image.png

注意:

  • 用WORKDIR,不要用RUN cd
  • 盡量使用絕對目錄
    Syntax:
WORKDIR <dirpath>

在Dockerfile文件中,WORKDIR指令可以出現(xiàn)多次,其路徑也可以為相對路徑,不過,其是相對此前一個(gè)WORKDIR指令指定的路徑
另外,WORKDIR也可調(diào)用由ENV指定定義的變量

ex:

    WORKDIR /var/log
    WORKDIR $STATEPATH

七、RUN

接受命令作為參數(shù)并用于創(chuàng)建鏡像,在之前的commit層上形成新的層。


image.png

注意:

  • 為了美觀,復(fù)雜的RUN請用反斜線換行
  • 避免無用分層,合并多條命令成一行

Syntax:

RUN \<command\>(如同執(zhí)行shell命令 /bin/sh -c)
RUN ["executable","param1","param2"]
  • RUN 指令將在當(dāng)前image中執(zhí)行任意合法命令并提交執(zhí)行結(jié)果。命令執(zhí)行提交后,就會(huì)自動(dòng)執(zhí)行Dockerfile中的下一個(gè)指令。
  • 分層RUN指令和生成提交符合Docker的核心概念,其中提交很輕量,可以從image將用于Dockerfile中的下一步。
  • exec形式使得可以避免shell字符串變化,以及使用不包含指定的shell可執(zhí)行文件的基本image來運(yùn)行RUN命令。
  • 在shell形式中,可以使用\(反斜杠)將單個(gè)RUN指令繼續(xù)到下一行。例如:
RUN yum install -y \ openssl \ pcre-devel \ zlib
  • 第二種語法格式中的參數(shù)是一個(gè)JSON格式的數(shù)組,其中<executable>為要運(yùn)行的命令,后面的<paramN>為傳遞給命令的選項(xiàng)或?qū)?shù);然而,此種格式指定的命令不會(huì)以"/bin/sh -c"來發(fā)起,因此常見的shell操作如變量替換以及通配符(?,*等)替換將不會(huì)進(jìn)行;不過,如果要運(yùn)行的命令依賴于此shell特性的話,可以將其替換為類似下面的格式。
RUN ["/bin/bash","-c","<executable>","<param1>"]

RUN 指令的緩存在下一次構(gòu)建期間不會(huì)自動(dòng)失效。用于諸如:yum repolist 之類的指令的緩存將在下一次構(gòu)建期間被重用??梢酝ㄟ^--no-cache 參數(shù)來使RUN指令的緩存無效,例如: docker build --no-cache

管理命令
某些RUN 命令依賴于使用管道字符( | )將管道輸出到另一個(gè)命令功能

RUN wget -O - http://www.baidu.com/index.html | wc -l > /app/html/baidu.html

Docker使用 /bin/sh -c 解釋執(zhí)行這些命令,解釋器只評估管道中最后一個(gè)操作的退出代碼以確定成功。在上面的例子中,只要wc -l 命令成功,即使wget 命令失敗,該構(gòu)建步驟也會(huì)成功并生成新的鏡像。

由于管道中任何階段的錯(cuò)誤而導(dǎo)致命令失敗,請預(yù)先 set -o pipefail && 確保意外錯(cuò)誤可防止構(gòu)建無意中成功。例如:
set -o pipefail : 表示在管道連接的命令序列中,只要有任何一個(gè)命令返回非0值,則整個(gè)管道返回非0值,即使最后一個(gè)命令返回0.

RUN set -o pipefail && wget -O - http://www.baidu.com/index.html | wc -l > /app/html/baidu.html

注意:

并非所有的shell都支持 -o pipefail 選項(xiàng)。在這種情況下(例如 dash shell,這是基于Debian的映像上的默認(rèn)shell),請考慮使用exec形式RUN來明確選擇一個(gè)支持該pipefail選項(xiàng)的shell。如:

RUN ["/bin/bash","-c","set -o pipefail && wget -O - http://www.baidu.com/index.html | wc -l > /app/html/baidu.html"]

八、CMD

類似于RUN指令,CMD指令也可用于運(yùn)行任何命令或應(yīng)用程序,不過,二者的運(yùn)行時(shí)間點(diǎn)不同

  • RUN 指令運(yùn)行于映像文件構(gòu)建過程中,而CMD指令運(yùn)行于基于Dockerfile構(gòu)建出的新鏡像文件啟動(dòng)一個(gè)容器時(shí)。
  • CMD指令的首要目的在于為啟動(dòng)的容器指定默認(rèn)要運(yùn)行的程序,且其運(yùn)行結(jié)束后,容器也將終止;不過,CMD指定的命令其可以被docker run的命令行選項(xiàng)所覆蓋
  • 在Dockerfile中可以存在多個(gè)CMD指令,但僅最后一個(gè)生效
    Syntax:
CMD <command>   //支持命令展開,但是不支持傳遞信號 
CMD ["<executable>","<param1>","<param2>"]  //相當(dāng)于容器的第一個(gè)命令,可以接受信號
CMD ["param1","param2"]
前兩種語法格式的意義同RUN
第三種則用于為ENTRYPOINT指令提供默認(rèn)參數(shù)

CMD會(huì)在啟動(dòng)容器的時(shí)候執(zhí)行,build時(shí)不執(zhí)行,而RUN只是在構(gòu)建鏡像的時(shí)候執(zhí)行,后續(xù)鏡像構(gòu)建完成之后,啟動(dòng)容器就與RUN無關(guān)了。這個(gè)命令就相當(dāng)于在/etc/rc.d/rc.local中寫命令

九、ENTRYPOINT

類似CMD指令的功能,用于為容器指定默認(rèn)運(yùn)行程序,從而使得容器像是一具單獨(dú)的可執(zhí)行程序
與CMD不同的是,由ENTRYPOINT啟動(dòng)的程序不會(huì)被docker run命令行指定的參數(shù)所覆蓋,而且,這些命令行參數(shù)會(huì)被當(dāng)作參數(shù)傳遞給ENTRYPOINT指定的程序。不過,docker run 命令的--entrypoint 選項(xiàng)的參數(shù)可覆蓋ENTRYPOINT指令指定的程序

Syntax:

ENTRYPOINT <command>    //這種方式能接受shell命令行展開
ENTRYPOINT ["<executable>","param1"]  //展開不了,但能接收到信號

docker run命令傳入的命令參數(shù)會(huì)覆蓋CMD指令的內(nèi)容并且附加到ENTRYPOINT命令最后做為其參數(shù)使用。Dockerfile文件中也可以存在多個(gè)ENTRYPOINT指令,但僅有最后一個(gè)會(huì)生效

image.png

十、EXPOSE

用來指定端口,使容器內(nèi)的應(yīng)用可以通過端口和外界交互。
Syntax:

EXPOSE <port> [<port>...]

告訴Docker服務(wù)端容器對外映射的本地端口,需要在docker run 的時(shí)候使用-p 或者 -P 選項(xiàng)生效。

EXPOSE 80/tcp

十一、ENV

ENV指令可以用于docker容器設(shè)置環(huán)境變量

Syntax:

ENV <key> <value>
ENV <key>=<value> ...

指定一個(gè)環(huán)境變量,會(huì)被后續(xù)RUN指令使用,并在容器運(yùn)行時(shí)保留。
ENV設(shè)置的環(huán)境變量,可以使用 docker inspect 命令來查看。同時(shí)還可以使用 docker run --env <key>=<value>來修改環(huán)境變量
盡量使用ENV增加可維護(hù)性


image.png

十二、USER

用于指定運(yùn)行image時(shí)的或運(yùn)行Dockerfile中任何RUN、CMD或ENTRYPOINT指令指定的程序時(shí)的用戶名或UID
默認(rèn)情況下,container的運(yùn)行身份為root用戶
Syntax:

USER <UID>|<UserName> 

需要注意的是,<UID>可以為任意數(shù)字,但實(shí)踐中其必須為/etc/passwd中某用戶的有效UID,否則,docker run命令將運(yùn)行失敗

十三、ONBUILD

用于在Dockerfile中定義一個(gè)觸發(fā)器
Dockerfile用于build映像文件,此映像文件亦可作為base image被另一個(gè)Dockerfile用作FROM指令的參數(shù),并以之構(gòu)建新的映像文件
在后的這個(gè)Dockerfile中的FROM指令在build過程中被執(zhí)行時(shí),將會(huì)“觸發(fā)”創(chuàng)建其base image的Dockerfile文件中的ONBUILD指令定義的觸發(fā)器

Syntax:

ONBUILD <INSTRUCTION>

注意:
盡管任何指令都可注冊成為觸發(fā)器指令,但ONBUILD不能自我嵌套,且不會(huì)觸發(fā)FROM和MAINTAINER指令
使用包含ONBUILD指令的Dockerfile構(gòu)建的鏡像應(yīng)該使用特殊的標(biāo)簽,例如ruby:2.0-onbuild
在ONBUILD指令中使用ADD或COPY指令應(yīng)該格外小心,因?yàn)樾聵?gòu)建過程和上下文在缺少指定的源文件時(shí)會(huì)失敗。

十四、HEALTHCHECK

Docker 1.12版本后引入的判斷容器狀態(tài)是否正常

Syntax:

HEALTHCHECK [OPTION] CMD <command>  //設(shè)置檢查容器健康狀況的命令 
HEALTHCHECK NONE   //如果基礎(chǔ)鏡像有健康檢查指令,使用這行可屏蔽掉其健康檢查指令

在沒HEALTHCHECK指令前,Docker只能通過容器內(nèi)主進(jìn)程是否退出來判斷容器是否狀態(tài)異常。很多情況下這沒問題,但是如果程序進(jìn)入死鎖狀態(tài),或者死循環(huán)狀態(tài),應(yīng)用進(jìn)程并不退出,但是該容器已經(jīng)無法提供服務(wù)了。雖然后端的程序可以通過前端的檢測工具來檢查狀態(tài)信息。但是最前端的服務(wù)就需要本身的檢測機(jī)制加上監(jiān)控,就可以做到出現(xiàn)問題解決問題。

當(dāng)在一個(gè)鏡像指定了 HEALTHCHECK 指令后,用其啟動(dòng)容器,初始狀態(tài)會(huì)為 starting,在 HEALTHCHECK 指令檢查成功后變?yōu)?healthy,如果連續(xù)一定次數(shù)失敗,則會(huì)變?yōu)?unhealthy。

HEALTHCHECK支持下列選項(xiàng):

  • --interval=<間隔> : 兩次健康檢查間隔,默認(rèn)30秒
  • --timeout=<時(shí)長> : 健康檢查命令運(yùn)行超時(shí)時(shí)間,如果超過這個(gè)時(shí)間,本次健康檢查就被視為失敗,默認(rèn)為30秒
  • --retries=<次數(shù)> :當(dāng)連續(xù)失敗指定次數(shù)后,則將容器狀態(tài)視為unhealthy,默認(rèn)3次。

和CMD、ENTRYPOINT一樣,HEALTHCHECK只可以出現(xiàn)一次,如果寫了多個(gè),只有最后一個(gè)生效。CMD 后面的命令也分為shell和exec格式。命令的返回值決定了該次檢查的成功與否: 0表示成功;1表示失敗;2保留。

ex:

HEALTHCHECK --interval=5s --timeout=3s \
  CMD curl -fs http://localhost/ || exit 1

命令收集:

容器生命周期管理 — docker [run|start|stop|restart|kill|rm|pause|unpause]
容器操作運(yùn)維 — docker [ps|inspect|top|attach|exec|events|logs|wait|export|import|port]
容器rootfs命令 — docker [commit|cp|diff]
鏡像倉庫 — docker [login|pull|push|search]
本地鏡像管理 — docker [images|rmi|tag|build|history|save|import]
其他命令 — docker [info|version]

查看docker信息:

$ docker version
# 或者
$ docker info</pre>

Docker 需要用戶具有 sudo 權(quán)限,為了避免每次命令都輸入sudo,可以把用戶加入 Docker 用戶組(官方文檔

$ sudo usermod -aG docker $USER

服務(wù)啟動(dòng),重啟,狀態(tài)

[hongdada@localhost home]$ systemctl stop docker.service

[hongdada@localhost home]$ systemctl restart docker.service

[hongdada@localhost home]$ systemctl status docker.service</pre>

images相關(guān)命令:

以鏡像centos為例

登錄倉庫 docker login
查找鏡像docker search centos
下載鏡像docker pull centos
上傳鏡像docker push centos
刪除鏡像docker rmi centos  說明:如果有多個(gè)tag,則指定tag只會(huì)刪除tag,而不會(huì)刪除鏡像本身。
查看鏡像docker images
查看具體某一個(gè)鏡像的詳細(xì)信息:docker inspect  centos
更改tag: docker tag  docker.io/centos  21yunwei:latest
創(chuàng)建鏡像docker commit  容器ID 鏡像名稱   注:創(chuàng)建鏡像有三種方式,基于容器創(chuàng)建,基于本地模板創(chuàng)建,基于dockerfile創(chuàng)建
保存鏡像docker save -o testcentos.tar 21yunwei:latest
載入鏡像docker  load < tesetcentos.tar
# 列出本機(jī)的所有 image 文件。
$ docker image ls

# 刪除 image 文件
$ docker image rm [imageName]

# 搜索鏡像
$ docker search mysql (輸出信息包括鏡像名字、描述、星級、是否為官方創(chuàng)建、是否自動(dòng)創(chuàng)建)

# image 文件從倉庫抓取到本地。
$ docker image pull library/hello-world

# 運(yùn)行image文件
$ docker container run hello-world

container相關(guān)命令:

列出本機(jī)正在運(yùn)行的容器:docker container ls
列出本機(jī)所有容器,包括終止運(yùn)行的容器:docker container ls --all
創(chuàng)建容器docker create -ti image  容器ID:cid
啟動(dòng)容器docker start  cid
運(yùn)行容器docker run -dit cid 等同于docker create+docker start
停止容器服務(wù) docker container kill cid
關(guān)閉容器docker stop  cid
重啟容器docker restart  cid
刪除容器docker rm cid    #注意數(shù)據(jù)卷
刪除所有容器docker rm `docker ps -a -q`  docker kill `docker ps -q`

阻塞對容器的其他調(diào)用方法,直到容器停止后退出 docker wait  cid
查看容器docker ps 或者docker ps -a
列出容器ID docker ps -q (docker ps  -q  -a)
容器文件拷貝 docker  cp cid:路徑 宿主機(jī)路徑或docker  cp 宿主機(jī)路徑你 cid:路徑
查看容器進(jìn)程docker top cid
查看容器日志docker logs cid
查看容器變化 docker diff  cid
進(jìn)入容器docker exec -ti cid /bin/bash或者 docker attach cid(不推薦,終端顯示相同,顯示不安全且容易卡?。?查看容器詳細(xì)信息 docker inspect cid 包括配置信息,名稱,命令、網(wǎng)路配置以及很多有用數(shù)據(jù)
查看容器端口 docker port  cid

導(dǎo)出容器docker export 3ad>21yunwei.tar
導(dǎo)入容器cat 21yunwei.tar | docker import -test/centos:latest

參考:
https://www.cnblogs.com/dance-walter/p/9581508.html

https://www.cnblogs.com/edisonchou/p/dockerfile_inside_introduction.html

https://www.cnblogs.com/hongdada/p/8906967.html

https://baijiahao.baidu.com/s?id=1641433332828402192&wfr=spider&for=pc

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

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

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