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種:
- 通過
Dockerhub
提供; - 通過某一個已經執行的容器生成映象(下文講);
- 使用
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
可以使用,RUN
和ENTRYPOINT
也可以使用這三種方式):
- 以
/bin/bash -c
的方法執行命令。比如CMD /bin/bash -c "echo hello world"
; - 執行一個可執行檔案並提供引數,稱為Shell方式。比如
CMD echo "hello world"
; - 可執行檔案連同引數通過一個陣列提供,成為Exec方式,比如
CMD ["echo","hello world"]
;
1. ENTRYPOINT
ENTRYPOINT
與CMD
類似,都是指定容器的啟動引數。不同之處在於:
-
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) 一個例子
4、Registry
Registry
是存放Docker映象
的倉庫,分公有和私有兩種。
(1) DockerHub
DockerHub
是Docker公司
對公眾提供的免費Registry,使用者可以在上面下載各種型別的應用或映象。比如下載一個有Python3環境的映象、可以提供redis儲存服務的伺服器。官網地址
(2) 公司內網
出於對速度或安全的考慮,使用者可以建立自己私有的Registry。公司內網Registry地址
三、Docker管理
除了上面介紹的對容器和映象的基本操作外,還可以使用docker-compose
管理容器。
docker-compose
通過一個docker-compose.yml
配置檔案,完成單個容器的配置(比如映象、埠對映、目錄掛載、環境變數等)、多個相互依賴的容器編排(容器啟動順序)等功能。
這塊內容較多並且也不難,有了上文的基礎,通過下文的參考檔案應該能掌握。
四、實現容器的底層技術
cgroup
和namespace
是實現容器的兩個重要技術。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--從入門到實踐