docker-每天5分鍾玩轉Docker容器技術


---

DOCKER鏡像
    1、鏡像的內部結構
        1.1 hello-world 最小的鏡像
            docker pull hello-world 從Docker Hub下載
            docker images查看鏡像信息
            docker run hello-world 運行
        1.2 base鏡像(FROM scratch)
        1.3 鏡像為什么這么小(底層直接使用Host的kernel)
        1.4 為什么鏡像可以運行在不同的linux發行版 (kernel一樣)
        1.5 鏡像的分層結構
        1.6 可寫的容器層
    2、構建鏡像
        2.1 docker commit
            1、運行容器,docker run -it ubuntu 
            2、做修改
            3、將容器保存為新的鏡像 docker commit 容器名字 鏡像名字
        2.2 Dockerfile(docker build -t ubuntu-with-vi-dockerfile .)
            查看鏡像分層結構 docker history ubuntu-with-vi-dockerfile
    3、鏡像的緩存特性
        Docker 會緩存已有鏡像的鏡像層,構建新鏡像時,如果某鏡像層已經存在,就直接使用,無需重新創建。
        如果我們希望在構建鏡像時不使用緩存,可以在 docker build 命令中加上  --no-cache  參數。 
    4、調試Dockerfile
        如果下一個鏡像有問題,根據上一個鏡像來拍錯
    5、Dockerfile常用指令
        FROM COPY ADD RUN CMD ENTRYPOINT
    6、分發鏡像
        實際上鏡像的名字由兩部分組成:【image name】= 【repository】 + 【tag】
        鏡像名稱由repository和tag兩部分組成,而repository的完整格式為:[registry-host]:[port]/[username]/xxx,只有Docker Hub上的鏡像可以省略registry-host:[host]
        如果執行docker build時沒有指定tag,默認為latest,相當於docker build -t ubuntu-with-vi : latest
            myimage:1 始終指向 1 這個分支中最新的鏡像。
            myimage:1.9 始終指向 1.9.x 中最新的鏡像。
            myimage:latest 始終指向所有版本中最新的鏡像。
        在Docker Host中登錄:docker login -u 賬號
        單獨查看具體鏡像:docker images hello-world 
        重命名:docker tag myimage-v1.9.1 myimage:1
        上傳一份:docker push dongye95/hello-world:test1
    7、命令
        images:顯示鏡像列表
        history:顯示鏡像構建歷史
        commit:從容器創建新鏡像
        build:從Dockerfile構建鏡像
        tag:給鏡像打tag
        pull:從registry下載鏡像
        push:將鏡像上傳到registry
        rmi:刪除Docker host中的鏡像
            1、只能刪除host上的鏡像,不會刪除registry的鏡像
            2、一個鏡像對應多個tag,只有當最后一個tag被刪除時,鏡像才被真正刪除
        search:搜索Docker Hub中的鏡像
            1、搜索Docker Hub中的鏡像
            2、docker search httpd       

Docker容器
    1、運行容器
        docker ps [-a]
        docker container ls [-a]
        1.1 讓容器長期運行
            docker run -d ubuntu /bin/bash -c "while true;do sleep 1;done"
        1.2 容器的container id和name
            容器啟動時有一個“長ID”,docker ps時container id字段會顯示“長ID”的前12位。
            docker run --name "my_http_server" -d httpd
            也可以通過rename重命名
        1.3 兩種進入容器的方法
            docker attach <container>    退出:Ctrl+p,然后Ctrl +q 
            docker exec -it <container> bash|sh
            只查看日志的話可以用logs,docker logs -f <container>  -f類似於tail -f 能夠持續輸出
    2、容器命令
        docker stop <container>        實際上向容器進程發送一個SIGTERM
        docker start <container>       會保留容器的第一次啟動時的所有參數
        docker kill <container>          快速結束容器,實際上是發送SIGKILL
        
        自動重啟
        docker run -d --restart=always httpd
        --restart=always 表示不管何種方式退出都重啟----包括正常退出
        --restart=on-failure:3,意識是如果啟動進程退出代碼非0,則重啟機器,最多3次
        
        docker pause <container>
        docker unpause <container>
        
        docker rm <container>
        
        批量刪除所有已經退出的容器:
        docker rm -v $(docker ps -aq -f status=exited)
        
        docker create <container>,只創建一個容器,處於created狀態,未start

 

---

安裝

安裝:

  1、Docker要求CentOS系統的內核版本高於 3.10 ,通過 uname -r 命令查看你當前的內核版本是否支持安賬docker

  2、更新yum包:sudo yum update

  3、安裝需要的軟件包,yum-util 提供yum-config-manager功能,另外兩個是devicemapper驅動依賴的

    sudo yum install -y yum-utils device-mapper-persistent-data lvm2

  4、設置yum源:sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

     

  5、可以查看所有倉庫中所有docker版本,並選擇特定版本安裝:yum list docker-ce --showduplicates | sort -r

    

  6、安裝docker:sudo yum install docker-ce-17.12.0.ce

  7、啟動、設置開啟開機啟動

    sudo systemctl start docker

    sudo systemctl enable docker

  8、驗證安裝是否成功(有client和service兩部分表示docker安裝啟動都成功了):docker version

    

  9、查看docker啟動狀態:systemctl status docker(如下圖即啟動成功)   


卸載:

  1、查詢docker安裝過的包:

    yum list installed | grep docker

       

  2、刪除安裝包:

   yum remove docker-ce.x86_64 ddocker-ce-cli.x86_64 -y

  3、刪除鏡像/容器等

    rm -rf /var/lib/docker

目前只能安裝到18版本的,安裝完后執行下面命令更新到版本19

yum install docker-ce -y

docker-compose的安裝1.24.1 https://github.com/docker/compose/releases curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose docker-compose version

linux環境下安裝docker-machine

wget https://github.com/docker/machine/releases/download/v0.16.2/docker-machine-Linux-x86_64

chmod +x docker-machine-Linux-x86_64

最后移動二進制文件到/usr/local/bin/目錄下

sudo cp docker-machine-Linux-x86_64 /usr/local/bin/docker-machine docker-machine -v


一、容器生態系統

1.1 容器核心技術

1.1.1 容器規范

保證容器的可移植性和互操作性:使不同組織不同廠商開發的容器能夠在不同的runtime上運行。

  目前有兩個規范:runtime spec 和 image format spec

1.1.2 容器runtime

容器真正運行的地方,為容器提供運行環境。

  三種主流:lxc、runc、rkt。runc官方欽定

1.1.3 容器管理工具

  lxd對應lxc、docker engine(常說的Docker)對應runc、rkt對應rkt cli。docker engine 官方欽定

1.1.4 容器定義工具

允許用戶定義容器的內容和屬性,這樣容器就能夠被保存、共享和重建。

  1. docker image是Docker容器的模板,runtime依據docker image創建容器
  2. dockerfile是包含若干命令的文本文件,可以通過這些命令創建出docker image
  3. ACI與docker image類似,只不過是有CoreOS開發的rkt容器的image格式。

1.1.5 Registry

統一存放image的倉庫

  1. 私有Registry。
  2. Docker Hub(https://hub.docker.com)是Docker為公眾提供的托管倉庫,上面有很多現成的image
  3. Quay.io(https://quay.io)另一個公共托管倉庫。

1.1.6 容器OS

專門運行容器的操作系統。

  coreos、atomic、Ubuntu core等

1.2 容器平台技術

容器核心技術使得容器能夠在單個host上運行,而容器平台技術能夠讓容器作為集群在分布式環境中運行

1.2.1 容器編排引擎

  基於容器的應用一般會采用微服務架構。在這種架構下,應用被划分為不同的組件,並以服務的形式運行在各自的容器中,通過 API 對外提供服務。為了保證應用的高可用,每個組件都可能會運行多個相同的容器。這些容器會組成集群,集群中的容器會根據業務需要被動態地創建、遷移和銷毀。

  這樣一個基於微服務架構的應用系統實際上是一個動態的可伸縮的系統。----容器編排引擎用來管理容器集群。

  所謂編排(orchestration),通常包括容器管理、調度、集群定義和服務發現等。通過容器編排引擎,容器被有機的組合成微服務應用,實現業務需求。

  1. docker swarm --- Docker 開發
  2. kubernetes 是 Google 領導開發的開源容器編排引擎,同時支持 Docker 和 CoreOS 容器。
  3. mesos 是一個通用的集群資源調度平台,mesos 與 marathon 一起提供容器編排引擎功能。

1.2.2 容器管理平台

通用的平台:通常支持多種編排引擎,為用戶提供更方便的功能。

  Rancher 和 ContainerShip

1.2.3 基於容器的PaaS

  基於容器的 PaaS 為微服務應用開發人員和公司提供了開發、部署和管理應用的平台,使用戶不必關心底層基礎設施而專注於應用的開發。

  Deis、Flynn 和 Dokku。

1.3 容器支持技術

1.3.1 容器網絡

管理容器與容器,容器與其他實體之間的連通性和隔離性。

  docker network 是 Docker 原生的網絡解決方案。

  第三方開源解決方案: flannel、weave 和 calico

1.3.2 服務發現

一種讓 client 能夠知道如何訪問容器提供的服務的機制。

  動態變化是微服務應用的一大特點。

  當負載增加時,集群會自動創建新的容器;負載減小,多余的容器會被銷毀。容器也會根據 host 的資源使用情況在不同 host 中遷移,容器的 IP 和端口也會隨之發生變化。

  etcd、consul 和 zookeeper 是服務發現的典型解決方案。

1.3.3 監控

  docker ps/top/stats 是 Docker 原生的命令行監控工具。除了命令行,Docker 也提供了 stats API,用戶可以通過 HTTP 請求獲取容器的狀態信息。

  sysdig、cAdvisor/Heapster 和 Weave Scope 是其他開源的容器監控方案。

1.3.4 數據管理

  保證持久化數據也能夠動態遷移,是 Flocker 這類數據管理工具提供的能力。

1.3.5 日志管理

  docker logs 是 Docker 原生的日志工具。

  而 logspout 對日志提供了路由功能,它可以收集不同容器的日志並轉發給其他工具進行后處理。

1.3.6 安全性

  OpenSCAP 能夠對容器鏡像進行掃描,發現潛在的漏洞。

1.4 初步搭建

1.4.1 安裝

  省略……待補充

1.4.2 運行

docker run -d -p 80:80 httpd
-p: 端口映射,格式為:主機(宿主)端口:容器端口

  自動從Docker Hub下載httpd鏡像。鏡像中已經安裝好了 Apache HTTP Server。

  啟動 httpd ,並將容器的80端口映射到 host  的 80 端口。

 

二、容器技術

2.1 what----什么是容器

容器是一種輕量級、可移植、自包含軟件打包技術,使應用程序可以在幾乎任何地方以相同的方式運行。Container=集裝箱,翻譯成容器。

容器和虛擬機的區別:

  1. 容器:1.應用程序本身 2.依賴:比如應用程序需要的庫或其他軟件
  2. 虛擬機:為了運行應用,除了部署應用本身及其依賴,還得安裝整個操作系統
  3. 另外,啟動容器不需要啟動整個操作系統,所以容器部署和啟動速度更快,開銷更小,也更容易遷移。

2.2 why----為什么需要容器

  1. 容器使軟件具備了超強的可移植能力。
  2. 以前幾乎所有的應用都采用三層架構(Presentation/Application/Data),系統部署到有限的幾台物理服務器上(Web Server/Application Server/Database Server)。而今天,開發人員通常使用多種服務(比如 MQ,Cache,DB)構建和組裝應用,而且應用很可能會部署到不同的環境,比如虛擬服務器,私有雲和公有雲。
  3. docker類似於集裝箱,不管是香蕉還是榴蓮,都放進集裝箱里,不會相互影響。Container=集裝箱,翻譯成容器

容器優勢

  1. 對於開發人員 - Build Once, Run Anywhere 。容器環境與所在的 Host 環境是隔離的
  2. 對於運維人員 - Configure Once, Run Anything 

2.3 how----容器是如何工作的

2.3.1 docker架構

  1. Docker客戶端:Client
  2. Docker服務器:Docker daemon
  3. Docker鏡像:Image
  4. Registry
  5. Docker容器:Container

  Docker 采用的是 Client/Server 架構。客戶端向服務器發送請求,服務器負責構建、運行和分發容器。客戶端和服務器可以運行在同一個 Host 上,客戶端也可以通過 socket 或 REST API 與遠程的服務器通信

2.3.2 Docker客戶端

  最常用的 Docker 客戶端是 docker 命令。通過 docker 我們可以方便地在 Host 上構建和運行容器。

2.3.3 Docker 服務器

  Docker daemon 是服務器組件,以 Linux 后台服務的方式運行。

  默認配置下,Docker daemon 只能響應來自本地 Host 的客戶端請求。如果要允許遠程客戶端請求,需要在配置文件中打開 TCP 監聽,步驟如下:
    1、編輯配置文件  /etc/systemd/system/multi-user.target.wants/docker.service ,在環境變量  ExecStart  后面添加  -H tcp://0.0.0.0 ,允許來自任意 IP 的客戶端連接。
    2、重啟Docker daemon

systemctl daemon-reload
systemctl restart docker.service

  假如服務器ip為192.168.56.102,客戶端在命令行里加 -H參數,即可與遠程服務器通信

docker -H 192.168.56.102 info

2.3.4 Docker鏡像

  可將 Docker 鏡像看着只讀模板,通過它可以創建 Docker 容器。

  鏡像有多種生成方法:

    1.可以從無到有開始創建鏡像
    2. 也可以下載並使用別人創建好的現成的鏡像
    3. 還可以在現有鏡像上創建新的鏡像
    4.我們可以將鏡像的內容和創建步驟描述在一個文本文件中,這個文件被稱作 Dockerfile,通過執行  docker build <docker-file>  命令可以構建出 Docker 鏡像

 

2.3.5 Docker容器

  Docker 容器就是 Docker 鏡像的運行實例。

  用戶可以通過 CLI(docker)或是 API 啟動、停止、移動或刪除容器。

  可以這么認為,對於應用軟件,鏡像是軟件生命周期的構建和打包階段,而容器則是啟動和運行階段。 

2.3.6 Registry

  docker pull 命令可以從 Registry 下載鏡像。
  docker run 命令則是先下載鏡像(如果本地沒有),然后再啟動容器。

  查看倉庫內的鏡像

curl http://your-server-ip:5000/v2/_catalog

三、Docker鏡像

3.1 鏡像的內部結構

3.1.1 hello-world 最小的鏡像

docker pull hello-world從Docker Hub下載
docker images查看鏡像信息
docker run hello-world運行

hello-world 的 Dockerfile

FROM scratch此鏡像是從白手起家,從 0 開始構建
COPY hello /將文件“hello”復制到鏡像的根目錄。
CMD ["/hello"]

3.1.2 base 鏡像

centos的鏡像-標准的base鏡像

FROM scratch
ADD centos-7-docker.tar.xz /
CMD ["/bin/bash"]

所謂的 base 鏡像

  1、不依賴其他鏡像,從 scratch 構建。

  2、其他鏡像可以之為基礎進行擴展。

3.1.3 鏡像為什么這么小?(一個centos只有200M)

linux操作系統由內核空間用戶空間組成

內核空間是kernel,linux剛啟動的時候回加載bootfs文件系統,之后bootfs會被卸載掉

用戶空間是rootfs,包含熟悉的/dev、/bin目錄等

對於base鏡像來說,底層直接用 Host 的 kernel,自己只需要提供 rootfs 就行

 

 

3.1.4 為什么鏡像可以運行在不同的 linux 發行版本上

不同Linux發行版的區別主要就是roots,Linux kernel差別不大。

base鏡像只是在用戶控件與發行版一致,kernel版本與發行版是不同的。比如centos使用3.x.x的kernel,但是Docker Host是4.x.x的話,容器的kernel版本與Host一致。

容器只能使用 Host 的 kernel,並且不能修改。所以如果容器對kernel版本有要求,則不建議用容器,虛擬機更合適。

3.1.5 鏡像的分層結構

Docker Hub 中 99% 的鏡像都是通過在 base 鏡像中安裝和配置需要的軟件構建出來的。

新鏡像是從 base 鏡像一層一層疊加生成的。每安裝一個軟件,就在現有鏡像的基礎上增加一層。

最大的一個好處就是 - 共享資源

  1、有多個鏡像都從相同的 base 鏡像構建而來,那么 Docker Host 只需在磁盤上保存一份 base 鏡像
  2、同時內存中也只需加載一份 base 鏡像,就可以為所有容器服務了。

如果多個容器共享一份基礎鏡像,當某個容器修改了基礎鏡像的內容,比如 /etc 下的文件,其他容器下的/etc不會被修改

3.1.6 可寫的容器層

 

 

  • 當容器啟動時,一個新的可寫層被加載到鏡像的頂部。
  • 這一層通常被稱作“容器層”,“容器層”之下的都叫“鏡像層”。 
  • 所有對容器的改動 - 無論添加、刪除、還是修改文件都只會發生在容器層中。 
  • 只有容器層是可寫的,容器層下面的所有鏡像層都是只讀的。 

對於增刪改查:

  1. 添加文件:在容器中創建文件時,新文件被添加到容器層中。
  2. 讀取文件:在容器中讀取某個文件時,Docker 會從上往下依次在各鏡像層中查找此文件。一旦找到,立即將其復制到容器層,然后打開並讀入內存。 
  3. 修改文件:在容器中修改已存在的文件時,Docker 會從上往下依次在各鏡像層中查找此文件。一旦找到,立即將其復制到容器層,然后修改之。 只有當需要修改時才復制一份數據,這種特性被稱作 Copy-on-Write
  4. 刪除文件:在容器中刪除文件時,Docker 也是從上往下依次在鏡像層中查找此文件。找到后,會在容器層中記錄下此刪除操作。 

容器層記錄對鏡像的修改,所有鏡像層都是只讀的,不會被容器修改,所以鏡像可以被多個容器共享

3.2 構建鏡像

3.2.1 docker commit

1、運行容器

docker run -it ubuntu         -it參數的作用是以交互模式進入容器,並打開終端

2、修改容器

apt-get install -y vim

3、將容器保存為新的鏡像

查看當前運行的容器:docker ps,發現自動分配了silly_goldberg名字
docker commit silly_goldberg ubuntu-with-vi

這種方式不建議使用,原因如下:

  1. 手工,容易出錯,效率低
  2. 使用者只能拿到一個鏡像,不知道這個鏡像這么創建的,無法對鏡像進行審計,存在安全隱患

當然,cockerfile底層也是docker commit一層層構建的

3.2.2 Dockerfile

  Dockerfile就是普通文件,可用touch創建。
  如果 /root 下有如下Dockerfile文件

FROM ubuntu
RUN apt-get upadte && apt-get install -y vim

  如果運行的話

root@ubuntu:~# pwd/root   
root@ubuntu:~# ls          ②    
Dockerfile    
root@ubuntu:~# docker build -t ubuntu-with-vi-dockerfile .            
Sending build context to Docker daemon 32.26 kB               
Step 1 : FROM ubuntu           ---> f753707788c5    
Step 2 : RUN apt-get update && apt-get install -y vim           ---> Running in 9f4d4166f7e3                 
......    
Setting up vim (2:7.4.1689-3ubuntu1.1) ...    
 ---> 35ca89798937                
Removing intermediate container 9f4d4166f7e3              
Successfully built 35ca89798937               
root@ubuntu:~#    

  各步驟詳細解釋


假設Dockerfile存在當前目錄
docker build -t ubuntu-with-vi-dockerfile .  (會從 . 即當前目錄查找dockerfile文件,並重命名為ubuntu-with-vi-dockerfile)
也可以通過 -f 參數指定 Dockerfile 的位置


從這步開始就是鏡像真正的構建過程。 首先 Docker 將 build context 中的所有文件發送給 Docker daemon。build context 為鏡像構建提供所需要的文件或目錄。
Dockerfile 中的 ADD、COPY 等命令可以將 build context 中的文件添加到鏡像。此例中,build context 為當前目錄 /root,該目錄下的所有文件和子目錄都會被發送給 Docker daemon。 
所以,使用 build context 就得小心了,不要將多余文件放到 build context,特別不要把 /、/usr 作為 build context,否則構建過程會相當緩慢甚至失敗。


執行FROM
將 ubuntu 作為 base 鏡像。
ubuntu 鏡像 ID 為 f753707788c5


執行 RUN,安裝 vim


啟動 ID 為 9f4d4166f7e3 的臨時容器,在容器中通過 apt-get 安裝 vim


安裝成功后,將容器保存為鏡像,其 ID 為 35ca89798937
這一步底層使用的是類似 docker commit 的命令 


刪除臨時容器 9f4d4166f7e3


鏡像構建成功。 
通過 docker images 查看鏡像信息。 
鏡像 ID 為 35ca89798937,與構建時的輸出一致

我們要特別注意指令 RUN 的執行過程 ⑦、⑧、⑨。Docker 會在啟動的臨時容器中執行操作,並通過 commit 保存為新的鏡像。 

  查看鏡像分層結構:

docker history ubuntu-with-vi-dockerfile

3.3 鏡像的緩存特性

  Docker 會緩存已有鏡像的鏡像層,構建新鏡像時,如果某鏡像層已經存在,就直接使用,無需重新創建。

  Dockerfile:

FROM ubuntu
RUN apt-get upadte && apt-get install -y vim
COPY testfile /

執行過程

root@ubuntu:~# ls           ① 
Dockerfile  testfile 
root@ubuntu:~# 
root@ubuntu:~# docker build -t ubuntu-with-vi-dockerfile-2 . 
Sending build context to Docker daemon 32.77 kB 
Step 1 : FROM ubuntu 
 ---> f753707788c5 
Step 2 : RUN apt-get update && apt-get install -y vim 
 ---> Using cache          
 ---> 35ca89798937 
Step 3 : COPY testfile /---> 8d02784a78f4 
Removing intermediate container bf2b4040f4e9 
Successfully built 8d02784a78f4 

   重點在這里:之前已經運行過相同的 RUN 指令,這次直接使用緩存中的鏡像層 35ca89798937。 

  如果我們希望在構建鏡像時不使用緩存,可以在 docker build 命令中加上  --no-cache  參數。 

 

  Dockerfile 中每一個指令都會創建一個鏡像層,上層是依賴於下層的。無論什么時候,只要某一層發生變化,其上面所有層的緩存都會失效。 也就是說,如果我們改變 Dockerfile 指令的執行順序,或者修改或添加指令,都會使緩存失效。 

3.4 調試Dockerfile

1.從 base 鏡像運行一個容器。
2.執行一條指令,對容器做修改。
3.執行類似 docker commit 的操作,生成一個新的鏡像層。
4.Docker 再基於剛剛提交的鏡像運行一個新容器。
5.重復 2-4 步,直到 Dockerfile 中的所有指令執行完畢。

  如果下一個指令有問題,可以通過運行上一條指令的鏡像來調試

3.5 Dockerfile 常用指令

FROM 
 : 指定 base 鏡像

MAINTAINER 
    : 設置鏡像的作者,可以是任意字符串

COPY : 將文件從 build context 復制到鏡像。

COPY 支持兩種形式 
    : 1. COPY src dest 
      2. COPY ["src", "dest"] 
      注意:src 只能指定 build context 中的文件或目錄。

ADD
 : 與 COPY 類似,從 build context 復制文件到鏡像。不同的是,如果 src 是歸檔文件(tar, zip, tgz, xz 等),文件會被自動解壓到 dest

ENV
    : 設置環境變量,環境變量可被后面的指令使用
... 
ENV MY_VERSION 1.3 
RUN apt-get install -y mypackage=$MY_VERSION 
...

EXPOSE
    : 指定容器中的進程會監聽某個端口,Docker 可以將該端口暴露出來

VOLUME
    : 將文件或目錄聲明為 volume

WORKDIR
    :為后面的 RUN, CMD, ENTRYPOINT, ADD 或 COPY 指令設置鏡像中的當前工作目錄

RUN
 :在容器中運行指定的命令

CMD
    : 容器啟動時運行指定的命令。
    Dockerfile 中可以有多個 CMD 指令,但只有最后一個生效。CMD 可以被 docker run 之后的參數替換

ENTRYPOINT
    : 設置容器啟動時運行的命令。
    Dockerfile 中可以有多個 ENTRYPOINT 指令,但只有最后一個生效。CMD 或 docker run 之后的參數會被當做參數傳遞給 ENTRYPOINT

3.5.1 RUN、CMD、ENTRYPOINT的區別

Shell + Exec

Shell格式
    RUN apt-get install python3

Exec格式
    RUN ["apt-get","install","python3"]

指令執行時,shell格式底層會調用 /bin/sh -c [command]
    ENV name Cloud Man ENTRYPOINT echo "Hello,$name"
    執行docker run [image]將輸出:
    Hello,Cloud Man

指令執行時,Exec會直接調用 [command],不會被shell解析
    ENV name Cloud Man ENTRYPOINT ["/bin/echo","Hello,$name"]
    執行docker run [image]將輸出:
    Hello,$name
如果希望使用環境變量,做如下修改:
    ENV name Cloud Man ENTRYPOINT ["/bin/sh","-c","echo Hello,$name"]
    將會輸出
    Hello,Cloud Man

RUN

RUN 指令通常用於安裝應用和軟件包。 
RUN 在當前鏡像的頂部執行命令,並通過創建新的鏡像層RUN apt-get update && apt-get install -y \bzr\cvs\git\mercurial\subversion 

一定要這么寫,不能如下寫法
RUN apt-get update
RUN apt-get install -y \bzr\cvs\git\mercurial\subversion 
因為在第二步會創建鏡像層,或者調用鏡像層,由於鏡像緩存,不能保證是最新的

CMD

CMD 指令允許用戶指定容器的默認執行的命令。 
此命令會在容器啟動且 docker run 沒有指定其他命令時運行。 
    1、如果 docker run 指定了其他命令,CMD 指定的默認命令將被忽略。 
    2、如果 Dockerfile 中有多個 CMD 指令,只有最后一個 CMD 有效。

三種格式
    1、Exec格式(推薦):CMD ["executable","paam1","parama2"]
    2、CMD ["param1","parama2"] 為ENTRYPOINT提供額外的參數,此時ENTRYPOINT必須使用Exec格式
    3、Shell格式:CMD command param1 param2

Docker片段:CMD echo "Hello World" ,運行容器 docker run -it [image],輸出:
Hello World

Docker片段:CMD echo "Hello World" ,運行容器 docker run -it [image] /bin/bash,此時:
CMD命令被忽略,bash將被執行

ENTRYPOINT

  可讓容器以應用程序或者服務的形式運行。跟CMD不同的是,不會被忽略

ENTRYPOINT ["/bin/echo","Hello"] CMD ["world"]
運行容器 docker run -it [image]
Hello World
運行容器 docker run -it [image] CloudMan
Hello CloudMan

ENTRYPOINT echo "Hello" 的shell格式不會忽略任何CMD或docker run提供的參數

最佳實踐

最佳實踐 
    1、使用 RUN 指令安裝應用和軟件包,構建鏡像。 
    2、如果 Docker 鏡像的用途是運行應用程序或服務,比如運行一個 MySQL,應該優先使用 Exec 格式的 ENTRYPOINT 指令。CMD 可為 ENTRYPOINT 提供額外的默認參數,同時可利用 docker run 命令行替換默認參數。 
    3、如果想為容器設置默認的啟動命令,可使用 CMD 指令。用戶可在 docker run 命令行中替換此默認命令。

3.6 分發鏡像

三種方式:

  1. 用相同的Dockerfile在其他host構建鏡像
  2. 將鏡像上傳到公共Registry(比如Docker Hub),Host直接下載使用
  3. 搭建私有的Registry供本地Host使用
docker build -t ubuntu-with-vi . ---就是鏡像的名字

查看鏡像 docker images 可以看到鏡像的tag

實際上鏡像的名字由兩部分組成:
【image name】= 【repository】 : 【tag】
如果執行docker build時沒有指定tag,默認為latest,相當於docker build -t ubuntu-with-vi : latest

假設我們現在發布了一個鏡像 myimage,版本為 v1.9.1。那么我們可以給鏡像打上四個 tag:1.9.11.91 和 latest:
    docker tag myimage-v1.9.1 myimage:1   (原來的myimage-v1.9.1:latest,新增一個myimage:1)
    docker tag myimage-v1.9.1 myimage:1.9
    docker tag myimage-v1.9.1 myimage:1.9.1
    docker tag myimage-v1.9.1 myimage:latest
過了一段時間,我們發布了 v1.9.2。這時可以打上 1.9.2 的 tag,並將 1 和1.9 和 latest 從 v1.9.1 移到 v1.9.2:
    docker tag myimage-v1.9.2 myimage:1
    docker tag myimage-v1.9.2 myimage:1.9
    docker tag myimage-v1.9.2 myimage:1.9.2
    docker tag myimage-v1.9.2 myimage:latest
之后,v2.0.0 發布了。這時可以打上 2.0.02.02 的 tag,並將 latest 移到 v2.0.0。

    docker tag myimage-v2.0.0 myimage:2
    docker tag myimage-v2.0.0 myimage:2.0
    docker tag myimage-v2.0.0 myimage:2.0.0
    docker tag myimage-v2.0.0 myimage:latest

這種 tag 方案使鏡像的版本很直觀,用戶在選擇非常靈活:
 myimage:1 始終指向 1 這個分支中最新的鏡像。
    myimage:1.9 始終指向 1.9.x 中最新的鏡像。 myimage:latest 始終指向所有版本中最新的鏡像。
如果想使用特定版本,可以選擇 myimage:1.9.1、myimage:1.9.2 或 myimage:2.0.0

3.7 Registry

3.7.1 公共Registry

公共Docker Hub:
    1、先在Docker Hub中創建賬號
    2、在Docker Host中登錄:docker login -u 賬號
    3、Docker Hub為了區分不同用戶的同名鏡像,鏡像的registry中要包含用戶名:[username]/xxx.tag。通過docker tag重命名鏡像:docker tag hello-world dongye95/hello-world:test1
    4、比如要上傳一份:docker push dongye95/hello-world:test1
    5、查看:docker images dongye95/hello-world

3.7.2 本地Registry

本地Registry:Registry本身也是一個鏡像
    Docker已經將Registry開源,Docker Hub上也有官方的鏡像registry
    1、docker pull registry(可以直接run,會自動去pull)
    2、docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:latest
        -d:后台啟動容器
        -p:將容器的5000端口映射到Host的5000端口。5000是registry服務端口。前一個5000是本機端口,后一個是容器端口
        -v:將容器 /var/lib/registry目錄映射到 Host的 /muregistry,用於存放鏡像數據
    3、重命名鏡像,使之與registry匹配
    docker tag dongye95/hello-world:test1 主機Host:5000/dongye95/hello-world:test1
    鏡像名稱由repository和tag兩部分組成,而repository的完整格式為:[registry-host]:[port]/[username]/xxx,只有Docker Hub上的鏡像可以省略 registry-host:[host]
    4、可以docker push 上傳鏡像了
    docker push 主機Host:5000/dongye/hello-world:test1

3.8 命令

images:顯示鏡像列表
history:顯示鏡像構建歷史
commit:從容器創建新鏡像
build:從Dockerfile構建鏡像
tag:給鏡像打tag
pull:從registry下載鏡像
push:將鏡像上傳到registry
rmi:刪除Docker host中的鏡像
    1、只能刪除host上的鏡像,不會刪除registry的鏡像
    2、一個鏡像對應多個tag,只有當最后一個tag被刪除時,鏡像才被真正刪除
search:搜索Docker Hub中的鏡像
    1、搜索Docker Hub中的鏡像
    2、docker search httpd

四、容器

4.1 運行容器

三種方式指定容器啟動時執行命令
    1、CMD指令
    2、ENTRYPOINT指令
    3、在docker run命令中指定
    docker run ubuntu pwd
    返回目錄

查看Docker host中當前運行的容器

docker ps [-a]
docker container ls [-a]
[-a]包括已經exited的容器

4.1.1 讓容器長期運行

docker run ubuntu /bin/bash -c "while true;do sleep 1;done"
這種方法會占用一個終端

不占用終端,后台執行
docker run -d ubuntu /bin/bash -c "while true;do sleep 1;done"

4.1.2 容器的container id和name

容器啟動時有一個“長ID”,docker ps時container id字段會顯示“長ID”的前12位。NAMES字段顯示容器的名字,在啟動容器的時候可以通過 --name參數顯式的為容器命名,不命名則自動分配
docker run --name "my_http_server" -d httpd

對於容器的操作,需要通過“長ID”、“短ID”或者“名稱”

docker run --name "mysql_http_server" -d -p 80:80 httpd
也可以通過rename重命名

4.1.3 兩種進入容器的方法

docker attach <container>
退出:Ctrl+p,然后Ctrl +q 

docker exec -it <container> bash
    1、-it以交互模式打開 pseudo-TTY,執行bash,打開一個bash終端
    2、進入到容器內,容器的hostname就是其“短ID”
    3、可以想在linux里一樣操作
    4、exit退出

docker exec -it <container> bash|sh

只查看日志的話可以用logs
docker logs -f <container>  -f類似於tail -f 能夠持續輸出

4.2 容器相關命令

docker stop <container>        實際上向容器進程發送一個SIGTERM
docker start <container>       會保留容器的第一次啟動時的所有參數
docker kill <container>          快速結束容器,實際上是發送SIGKILL

自動重啟
docker run -d --restart=always httpd
--restart=always 表示不管何種方式退出都重啟----包括正常退出
--restart=on-failure:3,意識是如果啟動進程退出代碼非0,則重啟機器,最多3次

docker pause <container>
docker unpause <container>

docker rm <container> 批量刪除所有已經退出的容器:
docker rm -v $(docker ps -aq -f status=exited)

docker create <container>,只創建一個容器,處於created狀態,未start

4.3 資源限制

4.3.1 內存

與操作系統類似,容器可使用的內存包括兩部分:物理內存和swap

-m或者--memory:設置內存的使用限額
--memory-swap:設置內存+swap的使用限額

docker run -it -m 200M --memory-swap=300M ubuntu
如果只有 -m 沒有 --memory-swap,這后者默認為前者的兩倍

使用progrium/stress鏡像來測試,該鏡像可用於對容器執行壓力測試
docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
--vm 1:啟動1個內存工作線程
--vm-bytes 280M:每個線程分配280M內存

4.3.2 CPU限額

-c 或者 --cpu-shares,設定權重,不設定的話默認值為1024
docker run --name "container_A" -c 1024 ubuntu
docker run --name "container_B" -c 512 ubuntu
當爭搶CPU時,則A能搶到B的兩倍。不爭搶都是正常跑滿

docker run --name container_A -it -c 1024 progrium/stress --cpu 1
docker run --name container_B -it -c 1024 progrium/stress --cpu 1
--cpu 1 用來設置工作線程數量,只有1個cpu的話,1個工作線程就能將CPU壓滿
此時,A分得66的cpu資源,B只有33。如果關掉A,則全部分給B。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM