1. 程式人生 > 程式設計 >Docker容器從入門到入門

Docker容器從入門到入門

一、概述

1、容器為解決什麼問題

現在的軟體系統已經非常複雜。一方面包含多種服務,這些服務有自己所依賴的庫和軟體包;另一方面存在多種部署環境。這就產生了一個問題:如何讓每種服務能夠在所有的部署環境中順利執行?

容器的設計理念由碼頭上的集裝箱而來,通過集裝箱的標準化相互隔離實現軟體系統依賴的打包與執行隔離。

2、Docker是什麼

Docker現在幾乎是容器的代名詞,它同時也是Docker公司的名字。不過我們通常所說的Docker指的是容器或者容器技術

使用Docker之前,需要安裝它。以CentOS為例:

# yum install docker-ce
# systemctl start docker
複製程式碼

之後便可以使用docker命令操作容器或映象了(容器與映象下文會講到)。

3、容器優點

  • 一致的執行環境:Docker的映象提供了除核心外完整的執行時環境,確保了應用執行環境一致性;
  • 極其輕量:只打包了必要的Bin/Lib,容器不是模擬一個完整的作業系統,而是對程式進行隔離,是程式級別的
  • 秒級部署:根據映象的不同,容器的部署大概在毫秒與秒之間(比虛擬機器器強很多);
  • 易於移植:一次構建,隨處部署;
  • 彈性伸縮:Kubernetes、Swam、Mesos這類開源、方便、好使的容器管理平臺有著非常強大的彈性管理能力。

4、容器的主要應用場景

  • 持續整合和持續部署(CI/CD): 通過Docker
    完成持續整合管道自動化和應用部署;
  • 微服務

二、Docker中的概念及使用

1、映象(Image)

Docker映象是Docker容器執行的基礎,沒有Docker映象,就沒有Docker容器。映象與容器就像是面向物件程式設計中的例項一樣,映象是靜態的定義,容器是映象執行時的實體

映象是一個特殊的檔案系統,除了提供容器執行時所需的程式資源配置等檔案外,還包含了一些為執行時準備的一些配置引數(如匿名卷、環境變數、使用者等)。 映象不包含任何動態資料,其內容在構建之後也不會被改變

(1) 映象的獲取方式通常有3種:

  1. 通過Dockerhub提供;
  2. 通過某一個已經執行的容器生成映象(下文講);
  3. 使用Dockerfile生成(下文講);

上面是使用pull子命令從DockerHub下載centos:latest映象,其中centos是映象名,latest是標籤名。使用docker images命令已經可以看到剛下載的centos映象了。

(2) 映象常用操作

從倉庫拉取映象: # docker pull <image_id> 有時候可能需要先登入docker login <registry_host>

從容器生成映象: # docker commit <container_id> <image_name>

刪除映象: # docker rmi [-f] <image_id | image_name>

轉移映象: # docker save <image_id | image_name> a_file_name.tar 儲存映象到檔案 # docker load a_file_name.tar 載入映象檔案到本地映象庫

2、容器(Container)

容器是映象執行時的實體。容器可以被建立、啟動、停止、刪除、暫停等。 容器的實質是程式,但與直接在宿主執行的程式不同,容器程式執行於屬於自己的獨立的名稱空間。

(1) 啟動容器

Docker啟動容器的命令格式:Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...],現在使用我們下載的centos映象啟動一個容器:

上圖使用run命令啟動一個容器(注意容器啟動前後的whoami輸出以及終端提示符的變化)。

  • -ti 會進入容器的終端(使用ctrl-p+ctrl-q方式返回宿主機);
  • -name test 容器名以test命令,不指定會隨機去一個字串;
  • centos:latest 啟動容器使用的映象名;
  • /bin/bash 容器啟動後的執行命令;

除了這裡的幾個啟動引數外,啟動容器還經常使用以下OPTIONS

  • --privileged=true 進入容器後,使用真正的root許可權;
  • --net host 表示在容器內與主機共享網路卡,host是安裝Docker時在主機上建立的三個網路之一;
  • --volume host_dir:container_dir 把容器內的container_dir掛載到宿主機的host_dir目錄;
  • --env 環境變數名=value 設定容器內的環境變數;
  • --cpu-shares n 設定容器佔用CPU的權重n,這個權重是相對的,第一個容器是10,第二個是20,那第二個容器佔用的CPU就是第一個的2倍;
  • -p host_port:container_port/udp 宿主機與容器的埠對映,預設是tcp,如果是udp需要/udp

(2) 容器基本操作

啟動容器# docker run [OPTIONS] <image_name | image_id> [COMMAND] [ARG...]

檢視容器資訊: 使用inspect子命令檢視容器/映象的元資料。包括id啟動命令網路連線方式埠對映等資訊。

進入容器# docker exec -it <container_name | container_id>

停止容器# docker stop/kill <container_name | container_id>

刪除容器# docker rm [-f] <container_name | container_id>

3、Dockerfile

雖然DockerHub提供了眾多Linux映象,但如果需要定製,DockerHub還是不能滿足的。這個時候就需要基於DockerHub提供的映象做一些擴充套件。

Dockerfile

(1) 常用關鍵字

  • FROM 使用一個基礎映象構建;
  • RUN 執行一個shell命令,通常用來安裝工具;
  • ENV 設定容器內的環境變數;
  • COPY 拷貝宿主機檔案到映象內;
  • ADD 拷貝宿主機檔案到映象內,並解壓;
  • WORKDIR 設定容器啟動時的工作目錄,預設會cd到該目錄,如果目錄不存在會自動建立;

(2) 兩個特殊的關鍵字

1. CMD

CMD指令允許使用者指定容器啟動的預設執行的命令。此命令會在容器啟動且docker run沒有指定其他命令時執行。

  • 如果docker run指定了其他啟動命令,CMD指定的預設命令將被忽略;否則預設執行CMD指定的命令;
  • 如果Dockerfile中有多個CMD指令,只有最後一個CMD有效;

CMD的三種格式(不只是CMD可以使用,RUNENTRYPOINT也可以使用這三種方式):

  1. /bin/bash -c的方法執行命令。比如CMD /bin/bash -c "echo hello world"
  2. 執行一個可執行檔案並提供引數,稱為Shell方式。比如CMD echo "hello world"
  3. 可執行檔案連同引數通過一個陣列提供,成為Exec方式,比如CMD ["echo","hello world"]

1. ENTRYPOINT ENTRYPOINTCMD類似,都是指定容器的啟動引數。不同之處在於:

  • ENTRYPOINT一定會執行,不會被忽略;
  • CMD指令允許使用者指定容器啟動的預設執行的命令。此命令會在容器啟動且docker run沒有指定其他命令時執行;

ENTRYPOINT使用exec方式時,還可以通過使用CMD的exec方式提供額外的引數,此時CMD的引數列表僅包含引數、不再有可執行檔案。比如:

  • 下面的Dockerfile片段,ENTRYPOINT ["echo","hello"] CMD ["world"],會輸出hello world;
  • 若啟動上面的Dockerfile建立的映象,啟動命令為docker run -it [image] cvte,會輸出hello cvte

(3) 構建映象

# docker build -t tag_name path_to_Dockerfile
複製程式碼

Tips: Dockerfile所在目錄除了需要拷貝到映象中的檔案外,不要有其他無關檔案或資料夾,即保證Dockerfile所在目錄乾淨。否則構建時可能會出現長時間拷貝導致失敗;

(4) 一個例子

Dockerfile倉庫

4、Registry

Registry是存放Docker映象的倉庫,分公有和私有兩種。

(1) DockerHub

DockerHubDocker公司對公眾提供的免費Registry,使用者可以在上面下載各種型別的應用或映象。比如下載一個有Python3環境的映象、可以提供redis儲存服務的伺服器。官網地址

(2) 公司內網

出於對速度或安全的考慮,使用者可以建立自己私有的Registry。公司內網Registry地址

三、Docker管理

除了上面介紹的對容器和映象的基本操作外,還可以使用docker-compose管理容器。

docker-compose通過一個docker-compose.yml配置檔案,完成單個容器的配置(比如映象、埠對映、目錄掛載、環境變數等)、多個相互依賴的容器編排(容器啟動順序)等功能。

這塊內容較多並且也不難,有了上文的基礎,通過下文的參考檔案應該能掌握。

四、實現容器的底層技術

cgroupnamespace是實現容器的兩個重要技術。cgroup實現資源限額namespace實現資源隔離

1、cgroup

  • 對容器的資源限制,比如--cpu-shares、-m實際就是在配置cgroup;
  • 在/sys/fs/cgroup/cpu/docker目錄中,會為每個容器建立一個cgroup目錄,以容器長ID命名,裡面的若干檔案就是與CPU相關的cgroup配置。比如cpu.shares儲存的就是--cpu-shares的配置;
  • 同理,/sys/fs/cgroup/memory/docker儲存的就是容器記憶體的cgroup配置;

2、namespace

namespace相對cgroup要難一些。Linux使用了6中namespace,分別對應6種資源:Mount、UTS、IPC、PID、Network、User。

  • Mount namespace: 讓容器看山去擁有整個檔案系統,可以在容器內執行mount,這些操作只會在容器內生效;
  • UTS namespace:讓容器擁有自己的hostname。預設情況下,容器的hostname是它的短ID,也可以使用-h或--hostname指定。
  • IPC namespace:讓容器擁有自己的IPC來實現程式間通訊,不會與主機的IPC混合在一起;
  • PID namespace:容器在宿主機上以進城的形式存在;所有容器進城都掛載dockerd程式下,同時也可以看到容易內只屬於該容器的子程式;
  • Network namespace:讓容器擁有自己獨立的網路卡、IP、路由等資源;
  • User namespace:讓容器能夠管理自己的使用者,host不能看到容器中建立的使用者。

參考檔案: Docker--從入門到實踐