1. 程式人生 > 實用技巧 >Docker基礎知識及入門

Docker基礎知識及入門

什麼是Docker?


Docker是由dotcloud公司使用golang語言進行開發的,基於Linux核心的 cgroupnamespace,以及OverlayFS類的Union FS等技術,對程序進行封裝隔離,屬於作業系統層面的虛擬化技術。由於隔離的程序獨立於宿主和其它的隔離的程序,因此也稱其為容器。

下面的圖片比較了 Docker 和傳統虛擬化方式的不同之處:

傳統虛擬化

Docker

傳統虛擬機器技術是虛擬出一套硬體後,在其上執行一個完整作業系統,在該系統上再執行所需應用程序;而容器內的應用程序直接運行於宿主的核心,容器內沒有自己的核心,而且也沒有進行硬體虛擬。因此容器要比傳統虛擬機器更為輕便。


為什麼要使用Docker

更高效地利用系統資源

由於容器不需要進行硬體虛擬以及執行完整作業系統等額外開銷,Docker對系統資源的利用率更高。無論是應用執行速度、記憶體損耗或者檔案儲存速度,都要比傳統虛擬機器技術更高效。因此,相比虛擬機器技術,一個相同配置的主機,往往可以執行更多數量的應用。


更快速的啟動時間

傳統虛擬機器在啟動的時候是需要啟動一個完整的作業系統,所以使用傳統虛擬化技術啟動一個服務需要數分鐘,而Docker容器應用是直接將服務的應用程式啟動在宿主機的核心上,無需啟動完整的作業系統,因此可以做到秒級、甚至毫秒級的啟動時間。大大的節約了開發、測試、部署的時間。


一致的執行環境

開發過程中一個常見的問題是環境一致性問題。由於開發環境、測試環境、生產環境不一致,導致有些bug並未在開發過程中被發現。而Docker的映象提供了除核心以外的完整的執行時環境,確保了應用執行環境一致性,不需要做任何配置就能在任意Linux伺服器上執行,即Build Once, Run Anywhere。從而不會再出現「這段程式碼在我機器上沒問題啊」這類問題。


更輕鬆的遷移與彈性伸縮

由於Docker映象封裝了除作業系統核心外的完整的檔案系統,所以Docker應用在進行遷移的時候只需要在新的伺服器上將映象拉取下來或者使用Dockerfile重新Build,然後run一下就遷移完成了,完全不用擔心執行環境的變化導致應用無法正常執行的情況。


更輕鬆的擴充套件與維護

Docker使用的分層儲存以及映象的技術,使得應用重複部分的複用更為容易,也使得應用的維護更新更加簡單,基於基礎映象進一步擴充套件映象也變得非常簡單。


與傳統虛擬技術對比總結

特性 容器 虛擬機器
啟動速度 秒級 分鐘級
磁碟使用 MB級 GB級
單機執行數量 支援上千個容器 最多跑幾十個虛擬機器

Docker基礎概念

映象(Image)

我們都知道,作業系統分為核心和使用者空間。對於Linux而言,核心啟動後,會掛載 root檔案系統為其提供使用者空間支援。而 Docker映象(Image),就相當於是一個 root檔案系統。比如官方映象 ubuntu:18.04 就包含了完整的一套 Ubuntu 18.04 最小系統的 root 檔案系統。

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


容器(Container)

容器(Container)映象(Image)的關係,就像是面向物件程式設計中的例項一樣,映象是靜態的定義,容器是映象執行時的實體。容器可以被建立、啟動、停止、刪除、暫停等。

容器的實質是程序,但與直接在宿主執行的程序不同,容器程序運行於屬於自己的獨立的 名稱空間。因此容器可以擁有自己的root檔案系統、自己的網路配置、自己的程序空間,甚至自己的使用者ID空間。容器內的程序是執行在一個隔離的環境裡,使用起來,就好像是在一個獨立於宿主的系統下操作一樣。這種特性使得容器封裝的應用比直接在宿主執行更加安全。


倉庫(Registry)

Docker Registry提供的是儲存Docker映象的服務,便於將映象可以在任意支援Docker引擎的伺服器上“例項化”為容器提供服務。

通常一個Registry可以包含多個倉庫,每個倉庫裡又可以包含多個映象,每個映象之間使用tag(標籤)進行區分,如果映象沒有標籤則以預設latest作為該映象的標籤,相同標籤的映象會被新映象覆蓋。

以ubuntu映象為例,ubuntu是倉庫的名字,其內包含有不同的版本標籤,如,16.04, 18.04。我們可以通過ubuntu:16.04,或者ubuntu:18.04來具體指定所需哪個版本的映象。如果忽略了標籤,比如ubuntu,那將視為ubuntu:latest

Docker基礎命令

01. 使用映象

獲取映象

docker pull [選項] [Docker Registry 地址[:埠號]/]倉庫名[:標籤]

具體的選項可以通過 docker pull --help 命令看到,這裡我們說一下映象名稱的格式。

  • Docker 映象倉庫地址:地址的格式一般是<域名/IP>[:埠號]。預設地址是Docker Hub(docker.io)
  • 倉庫名:如之前所說,這裡的倉庫名是兩段式名稱,即 <使用者名稱>/<軟體名>。對於 Docker Hub,如果不給出使用者名稱,則預設為 library,也就是官方映象。

例如:

docker pull ubuntu:15.10

列出映象

docker image ls

刪除映象

docker image rm <映象id>
docker images rm <映象名>:<映象tag>

# 例如:
docker images rm 5c64
docker images rm alpine:latest

02. 執行容器

使用docker run命令啟動一個ubuntu的容器並在其中輸出 Hello World文字,執行完畢後,容器會自動退出。

docker run --name=hello ubuntu:15.10 /bin/echo "Hello, World"

引數解析:

run: y與docker組合啟動一個新容器;
--name: 容器的名稱;
ubuntu:15.10:啟動容器使用的映象;
/bin/echo:在容器中執行的命令。

03. 執行互動式容器

使用命令列執行以下命令,此命令將啟動一個ubuntu容器並在其中執行bash互動命令列介面,你可以嘗試執行pwd,ls,ps等命令檢視容器內環境,就如同遠端操作一臺伺服器一樣。

docker run -i -t ubuntu:latest /bin/bash
root@cd07977c1a22:/#

-i: 以互動模式執行容器,通常與 -t 同時使用;
-t: 為容器重新分配一個偽輸入終端,通常與 -i 同時使用;

第二行表示已經進入了一個ubuntu系統的容器中,可以執行命令。

04. 在容器中執行持續任務並管理容器生命週期

後臺啟動容器

使用以下命令建立一個以程序方式執行的容器

docker run --name=ubuntu -it -d ubuntu:15.10 /bin/bash

引數解析:

-d: 後臺執行容器,並返回容器ID;
/bin/bash: 執行的命令,必須是可以一直掛起的命令,如死迴圈。

docker run --name=test -d ubuntu:15.10 sh -c "while true; do echo hello world; sleep 1; done"

Docker容器後臺執行,就必須有一個前臺程序,容器執行的命令如果不是那些一直掛起的命令(比如執行top,tail),就是會自動退出的

檢視容器列表

使用docker ps命令檢視當前宿主機上執行的容器:

# 檢視正在執行的容器
docker ps
# 檢視所有容器
docker ps -a

檢視容器日誌

使用docker logs命令檢視容器日誌

# 檢視容器日誌
docker logs <containerid>
# 實時檢視容器日誌
docker logs -f <containerid>

連線容器

連線容器有兩種方法,attachexec -it:

# 使用attach
docker attach <containerid>

# 使用exec -it
docker exec -it <containerid> /bin/<bash|sh>

注意事項:

使用attach連線是使用現有終端,ctrl+d退出後容器也跟著退出,需要使用ctrl+p+q;
使用exec -it是使用偽終端,ctrl+d退出後容器會繼續執行。

停止及刪除容器

停止執行中的容器

docker stop e8c6

刪除容器

# 刪除已經停止的容器
docker rm e8c6
# 刪除正在執行的容器
docker rm -f e86c

刪除所有停止的容器

docker container prune

容器重啟

啟動已經停止的容器

docker start e8c6

重啟正在執行的容器

docker restart e8c6

05. 容器埠對映

將容器中服務埠對映到宿主機:

# 指定宿主機埠對映
docker run --name=nginx -d -p 80:80 nginx:1.17.0
# 隨機宿主機埠對映
docker run --name=nginx -d -P nginx:1.17.0

-p:將容器目錄對映至宿主機,<宿主機埠>:<容器埠>
-P: 將容器中暴露的埠對映到宿主機上的隨機埠,防止埠衝突。

06. 容器與宿主機檔案傳輸

目錄掛載

# 預設許可權為讀寫
docker run --name=nginx -d -v /data:/data nginx:latest
# 配置許可權為只讀
docker run --name=nginx -d -v /data:/data:ro nginx:latest

檔案cp

使用docker cp命令傳輸檔案

# 將宿主機檔案copy至容器
docker cp test.txt nginx:/mnt/

# 將容器檔案copy至宿主機
docker cp nginx:/mnt/test.txt /mnt/

07. docker for mac中容器訪問宿主機服務

docker在mac上啟動後,在宿主機上沒有docker-0網橋,所以無法通過訪問宿主機ip或者docker-0網橋ip訪問宿主機服務。
docker for mac提供了一個宿主機的域名host.docker.internal,所以mac上訪問宿主機業務時的格式為host.docker.internal:port,如settings.py中mysql的配置:

MYSQL_HOST = 'host.docker.internal'
MYSQL_PORT = '3306'

nginx容器反向代理宿主機後端服務時的配置:

proxy_pass http://host.docker.internal:8899;