一:Docker簡介
Docker使用Google公司推出的Go語言進行開發實現,基於Linux內核cgroup,namespace,對進程技術進行封裝與隔離,屬於操作系統層面的虛擬化技術。由於隔離的進程獨立於宿主和其他的隔離的進程,因此也稱其爲容器
Docker在容器的基礎上,進行了進一步的封裝,從文件系統、網絡互連到進程隔離等等,極大的簡化了容器的創建和維護
傳統虛擬機技術是虛擬出一套硬件後,在其上運行一個完整的操作系統,在該系統上再運行所需用的應用進程;而容器內的應用進行直接運行於宿主的內核,容器內沒有自己的內核,而且也沒有進行硬件虛擬
Docker容器與傳統虛擬機對比總結
特性 | 容器 | 虛擬機 |
---|---|---|
啓動 | 秒級 | 分鐘級 |
硬盤使用 | 一般爲 MB |
一般爲 GB |
性能 | 接近原生 | 弱於 |
系統支持量 | 單機支持上千個容器 | 一般幾十個 |
二:基本概念
2.1 鏡像(Image)
操作系統分爲內核和用戶空間。對於Linux而言,內核啓動後,會掛載root文件系統爲其提供用戶空間支持
Docker鏡像(Image),就相當於是一個root文件系統。比如官方鏡像 ubuntu:18.04就包含了完整的一套ubuntu:18.04最小系統的root文件系統
Docker鏡像是一個特殊的文件系統,除了提供容器運行時所需的程序、庫、資源、配置等文件外,還包含了一些爲運行時準備的一些配置參數(如匿名卷、環境變量、用戶等)
鏡像不包含任何動態數據,其內容在構建之後也不會被改變
因爲鏡像包含操作系統完整的root文件
2.2 容器(Container)
鏡像(Image)和容器(Container)的關係,就像是面向對象程序設計中的類和實例一樣,鏡像是靜態的定義,容器是鏡像運行時的實體。容器可以被創建、啓動、停止、刪除、暫停等
容器的實質是進程,但與直接在宿主執行的進程不同,容器進程運行於屬於自己的命名空間。因此容器可以擁有自己的 root 文件系統、自己的網絡配置、自己的進程空間,甚至自己的用戶ID空間。容器內的進程是運行在一個隔離的環境裏,使用起來就像是在一個獨立於宿主的系統下操作一樣。該特性使得容器封裝的應用比直接在宿主機運行更安全
鏡像使用的是分層存儲,容器也是如此。每一個容器運行時,是以鏡像爲基礎層,在其上創建一個當前容器的存儲曾,可以稱這個爲容器運行時讀寫而準備的存儲層爲 容器存儲層
容器存儲層的生命週期和容器一樣,容器消亡時,容器存儲層也隨之消亡。因此,任何保存於容器存儲層的信息都會隨容器刪除而丟失
按照Docker最佳實踐的要求,容器不應該向其存儲層內寫入任何數據,容器存儲層要保持無狀態化。所有的文件寫入操作,都應該使用數據卷(Volume)、或者綁定宿主目錄,在這些位置的讀寫會跳過容器存儲層,直接對宿主(或網絡存儲)發生讀寫,其性能和穩定性會更高
數據卷的生存週期獨立於容器,容器消亡,數據卷不會消亡。因此,使用數據卷後,容器刪除或者重新運行之後,數據不會丟失
2.3 倉庫(Repository)
Docker Registry(Docker 註冊服務器)
註冊服務器是管理倉庫的具體服務器,每個服務器上有多個倉庫,每個倉庫下面由多個鏡像
對於倉庫地址
docker.io/ubuntu 來說, docker.io 是註冊服務器地址, ubuntu 是倉庫名
鏡像構建完成之後,可以很容易的在當前宿主機上運行,但是,如果需要其在其他服務器上使用這個鏡像,需要一個集中的存儲、分發鏡像的服務,Docker Registry就是這樣的服務
一個Docker Registry中可以包含多個倉庫(Repository);每個倉庫可以包含多個標籤(Tag);每個標籤對應一個鏡像
通常,一個倉庫會包含同一個軟件不同版本的鏡像,而標籤就常用於對應該軟件的各個版本。可以通過 <倉庫名>:<標籤>的格式來指定具體是 這個軟件哪個版本的鏡像。如果不給出標籤,將以 latest 作爲默認標籤
以Ubuntu爲例,Ubuntu是倉庫的名字,其內包含不同的版本標籤,如,16.04,18.04。可以通過Ubuntu:16.04 或者 Ubuntu:18.04 來具體指定所需哪個版本的鏡像。如果忽略了標籤,比如Ubuntu,將視爲 Ubuntu:latest
倉庫名經常以兩段路徑的格式出現,比如 jwilder / nginx-proxy ,前者往往意味着Docker Registry多用戶環境下的用戶名,後者往往是對應的軟件名。但這並非絕對,取決於所使用的具體Docker Registry 的軟件或服務
Docker Registry 公開服務
Docker Regitsry 公開服務是開放給用戶使用、允許用戶管理鏡像的Registry服務。一般這類公開服務允許用戶免費上傳、下載公開的鏡像,並可以能提供收費服務供用戶管理私有鏡像
最常使用的Registry公開服務是官方的 Docker Hub,這也是默認的Registry,並擁有大量的高質量的官方鏡像。除此之外,還有CoreOS的Quay.io,CoreOS相關的鏡像存儲在這裏;Google的 Google Container Registry,Kubernetes 的鏡像
使用的就是這個服務。
由於某些原因,在國內訪問這些服務可能會比較緩慢。國內的一些雲服務商提供了針對Docker Hub 的鏡像服務(Registry Mirror),這些服務被稱爲加速器。常見的有阿里雲加速器、DaoCloud 加速器等。使用加速器會直接從國內的地址下載Docker Hub的鏡像,比直接從Docker Hub下載速度會提高很多
國內也有一些雲服務商提供類似於 Docker Hub 的公開服務。比如 網易雲鏡像服務、DaoCloud 鏡像市場、阿里雲鏡像庫 等
私有 Docker Registry
除了使用公開服務外,用戶還可以在本地搭建私有 Docker Registry。Docker官方提供了Docker Registry鏡像,可以直接使用作爲私有Registry服務
開源的Docker Registry鏡像只提供了Docker Registry API的服務端實現,足以支持docker命令,不影響使用。但不包含圖形界面,以及鏡像維護、用戶管理、訪問控制等高級功能。在官方的商業化版本 Docker Trusted Registry 提供了這些高級功能
除了官方的Docker Registry外,還有第三方軟件實現了Docker Registry API,甚至提供了用戶界面以及一些高級功能。比如Harbor 和 Sonatype Nexus
三:使用Docker鏡像
Docker運行容器前需要本地存在對應的鏡像,如果本地不存在該鏡像,Docker會從鏡像倉庫下載該鏡像
docker pull ubuntu:18.04 從Docker鏡像倉庫獲取鏡像 (若未指明地址,從Docker Hub中獲取鏡像)
docker image ls 列出已經下載下來的鏡像
docker image rm ** 刪除本地的鏡像
使用Dockerfile 定製鏡像
鏡像的定製 實際上就是定製每一層所添加的配置、文件。如果可以把每一層修改、安裝、構建、操作的命令都寫入一個腳本,用這個腳本來構建、定製鏡像,那麼之前提及到的無法重複的問題、鏡像構建透明性的問題、體積的問題都會解決,這個腳本就是Dockerfile
Dockerfile是一個文本文件,其內包含了一條條的指令(Instruction),每一條指令構建一層,因此每一條指令的內容,就是描述該層應當如何構建
四:操作Docker容器
簡單來說,容器是獨立運行的一個或一組應用,以及它們的運行態環境。虛擬機可以理解爲模擬運行的一整套操作系統(提供了運行態環境和其他系統環境)和跑在上面的應用
4.1 啓動
啓動容器有兩種方式,一種是基於鏡像新建一個容器並啓動,另外一個是將在終止狀態(stopped)的容器重新啓動
因爲Docker的容器實在太輕量級了,很多時候用戶都是隨時刪除和新創建容器
4.1.1 新建並啓動
所需要的命令主要是 docker run ,例如下面的命令輸出一個“Hello world”,之後終止容器
docker run ubuntu:18.04 /bin/echo 'Hello world'
Hello world
這跟在本地直接執行 /bin/echo 'hello world' 幾乎感覺不出任何區別
下面的命令則啓動一個bash終端,允許用戶進行交互
docker run -t -i ubuntu:18.04 /bin/bash
root@af8bae53bdd3:/#
其中, -t 選項是讓Docker分配一個僞終端(pseudo-tty)並綁定到容器的標準輸入上
-i 則讓容器的標準輸入保持打開
在交互模式下,用戶可以通過所創建的終端來輸入命令,例如
root@af8bae53bdd3:/# pwd
/
root@af8bae53bdd3:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin
srv sys tmp usr var
當利用 docker run 來創建容器時,Docker在後臺運行的標準操作包括
- 檢查本地是否存在指定的鏡像,不存在就從公有倉庫下載
- 利用鏡像創建並啓動一個容器
- 分配一個文件系統,並在只讀的鏡像層外面掛載一層可讀寫層
- 從宿主主機配置的網橋接口中橋接一個虛擬接口到容器中去
- 從地址池配置一個 ip 地址給容器
- 執行用戶指定的應用程序
- 執行完畢後容器被終止
4.1.2 啓動已終止容器
可以利用 docker container start 命令,直接將一個已經終止的容器啓動運行
容器的核心爲所指向的應用程序,所需要的資源都是應用程序運行所必須的。除此之外,並沒有其他的資源。可以在僞終端中利用 ps 或 top 來查看進行信息
root@ba267838cc1b:/# ps
PID TTY TIME CMD
1 ? 00:00:00 bash
11 ? 00:00:00 ps
可見,容器中僅僅運行了指定的bash應用,使得docker對資源的利用率極高,實現了輕量級虛擬化
4.2 守護態運行
更多的時候,需要讓docker在後臺運行而不是直接把執行命令的結果輸出在當前宿主機下,此時,可以通過 -d 參數實現
如果不使用 -d 參數運行容器
$ docker run ubuntu:18.04 /bin/sh -c "while true; do echo hello
world; sleep 1; done"
hello world
hello world
hello world
hello world
容器會把輸出的結果(STDOUT)打印到宿主機上面
如果使用了 -d 參數運行容器
docker run -d ubuntu:18.04 /bin/sh -c "while true; do echo hel
lo world; sleep 1; done"
77b2dc01fe0f3f1265df143181e7b9af5e05279a884f4776ee75350ea9d8017a
此時容器會在後臺運行,並不會把輸出結果(STDOUT)打印到宿主機上面(輸出結果可以用 docker logs 查看)
注:容器是否會長久運行,是和 docker run指定的命令有關,和 -d 參數無關
使用-d 參數啓動後會返回一個唯一的 id,也可以通過 docker container ls 命令來查看容器信息
docker container ls
CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS NAMES
77b2dc01fe0f ubuntu:18.04 /bin/sh -c 'while tr 2 minutes ago
Up 1 minute agitated_wright
要獲取容器的輸出信息,可以通過docker container logs 命令
docker container logs [container ID or NAMES]
hello world
hello world
hello world
. . .
4.3 終止
可以使用 docker container stop 來終止一個運行中的容器
此外,當docker容器中指定的應用終結時,容器也自動終止
對於只啓動了一個終端的容器,用戶通過 exit 命令或者 ctrl d 來退出終端時,所創建的容器立刻終止
終止狀態的容器可以用 docker container ls -a 命令查看到,例如
docker container ls -a
CONTAINER ID IMAGE COMMAND
CREATED STATUS PORTS
NAMES
ba267838cc1b ubuntu:18.04 "/bin/bash"
30 minutes ago Exited (0) About a minute ago
trusting_newton
98e5efa7d997 training/webapp:latest "python app.py"
About an hour ago Exited (0) 34 minutes ago
backstabbing_pike
處於終止狀態的容器,可以通過 docker container start 命令來重新啓動
docker container restart 命令可以將一個運行狀態的容器終止,然後再重新啓動
4.4 進入容器
在使用 -d 參數時,容器啓動後會進入後臺
某些時候需要進入容器進行操作,使用 docker exec
docker exec 後邊可以跟多個參數,主要說明 -i -t
只用 -i 參數時,由於沒有分配僞終端,界面沒有熟悉的Linux 命令提示符,但命令執行結果仍然可以返回
當 -i -t 參數一起使用時,可以看到熟悉的Linux命令提示符
docker run -dit ubuntu
69d137adef7a8a689cbcb059e94da5489d3cddd240ff675c640c8d96e84fe1f6
docker container ls
CONTAINER ID IMAGE COMMAND CREA
TED STATUS PORTS NAMES
69d137adef7a ubuntu:latest "/bin/bash" 18 s
econds ago Up 17 seconds zealous_
swirles
docker exec -i 69d1 bash
ls
bin
boot
dev
...
docker exec -it 69d1 bash
root@69d137adef7a:/#
如果從這個stdin中exit,不會導致容器的停止
更多的參數說明可以使用 docker exec --help 查看
4.5 導出和導入
4.5.1 導出容器
如果要導出本地某個容器,可以使用docker export 命令
docker container ls -a
CONTAINER ID IMAGE COMMAND CREA
TED STATUS PORTS NA
MES
7691a814370e ubuntu:18.04 "/bin/bash" 36 h
ours ago Exited (0) 21 hours ago te
st
docker export 7691a814370e > ubuntu.tar
這樣導出容器到本地文件 Ubuntu.tar
4.5.2 導入容器快照
可以使用docker import 從容器快照文件中再導入爲鏡像,例如
cat ubuntu.tar | docker import - test/ubuntu:v1.0
docker image ls
REPOSITORY TAG IMAGE ID CREA
TED VIRTUAL SIZE
test/ubuntu v1.0 9d37a6082e97 Abou
t a minute ago 171.3 MB
4.6 刪除
4.6.1 刪除容器
可以使用 docker container rm 來刪除一個處於終止狀態的容器 ,例如
docker container rm trusting_newton
trusting_newton
如果要刪除一個運行中的容器,可以添加 -f 參數。docker 會發送sigkill 信號給容器
4.6.2 清理所有處於終止狀態的容器
用docker container ls -a 命令可以查看已經創建的包括終止狀態的容器
如果數量太多要一個個刪除會很麻煩,用下面的命令可以清理掉所有處於終止狀態的容器
docker container prune
五:使用網絡
Docker允許通過外部訪問容器或容器互連的方式來提供網絡服務
5.1 外部訪問容器
容器中可以運行一些網絡應用,要讓外部也可以訪問這些應用,可以通過 -P 或 -p 參數來指定端口映射
當使用 -P 標記時,docker會隨機映射一個 49000-49900 的端口到內部容器開放的網絡端口
使用 docker container ls 可以看到,本地主機的49155 被映射到了容器的5000 端口。此時訪問主機的49155端口即可訪問容器內web應用提供的界面
docker run -d -P training/webapp python app.py
docker container ls -l
CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS NAMES
bc533791f3f5 training/webapp:latest python app.py 5 seconds ag
o Up 2 seconds 0.0.0.0:49155->5000/tcp nostalgic_morse
同樣的,可以通過 docker logs 命令來查看應用的信息
docker logs -f nostalgic_morse
* Running on http://0.0.0.0:5000/
-p 則可以指定要映射的端口,並且,在一個指定端口上只可以綁定一個容器。支持的格式有
ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort
使用 hostPort:containerPort 格式本地的 5000 端口映射到容器的 5000 端口,可以執行
docker run -d -p 5000:5000 training/webapp python app.py
此時默認會綁定本地所有接口上的所有地址
可以使用 ip:hostPort:containerPort 格式指定映射使用一個特定地址,比如localhost 地址 127.0.0.1
docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py
使用 ip::containerPort 綁定 localhost 的任意端口到容器的 5000 端口,本地主機會自動分配一個端口。
docker run -d -p 127.0.0.1::5000 training/webapp python app.py
使用 docker port 來查看當前映射的端口配置,也可以查看到綁定的地址
docker port nostalgic_morse 5000
127.0.0.1:49155.
容器有自己的內部網絡和IP地址
docker inspect 可以獲取所有的信息