Docker從入門到入土

一: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     可以獲取所有的信息

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章