源自摘抄,留個記錄,防止再次被禁,不明白公開的純技術文檔也能享受這種待遇。
安裝
使用自動腳本安裝
# wget -qO- https://get.docker.com/ | sh
or
$ sudo curl -sSL https://get.docker.com/ | sh
國內方式,可以通過 --mirror
選項使用國內源進行安裝:
$ curl -fsSL get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh --mirror Aliyun
# $ sudo sh get-docker.sh --mirror AzureChinaCloud
啟動 Docker
$ sudo systemctl enable docker
$ sudo systemctl start docker
If you want to avoid typing sudo whenever you run the docker command, add your username to the docker group:
$ sudo groupadd docker
$ sudo usermod -aG docker ${USER}
Ubuntu
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update
apt-cache policy docker-ce
sudo apt-get install -y docker-ce
Docker should now be installed, the daemon started, and the process enabled to start on boot. Check that it's running:
$ sudo systemctl status docker
國內方式
$ curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
$ echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
測試 Docker 是否安裝正確
$ docker run --rm hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
b8dfde127a29: Pull complete
Digest: sha256:308866a43596e83578c7dfa15e27a73011bdd402185a84c5cd7f32a88b501a24
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
...
使用鏡像
Docker 運行容器前需要本地存在對應的鏡像,如果本地不存在該鏡像,Docker 會從鏡像倉庫下載該鏡像。
獲取鏡像
從 Docker 鏡像倉庫獲取鏡像的命令是 docker pull
。其命令格式為:
$ docker pull [選項] [Docker Registry 地址[:端口號]/]倉庫名[:標簽]
具體的選項可以通過 docker pull --help
命令看到,這里我們說一下鏡像名稱的格式。
- Docker 鏡像倉庫地址:地址的格式一般是
<域名/IP>[:端口號]
。默認地址是 Docker Hub(docker.io
)。 - 倉庫名:如之前所說,這里的倉庫名是兩段式名稱,即
<用戶名>/<軟件名>
。對于 Docker Hub,如果不給出用戶名,則默認為library
,也就是官方鏡像。
比如:
$ docker pull ubuntu:18.04
18.04: Pulling from library/ubuntu
92dc2a97ff99: Pull complete
be13a9d27eb8: Pull complete
c8299583700a: Pull complete
Digest: sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9c4361e321b26
Status: Downloaded newer image for ubuntu:18.04
docker.io/library/ubuntu:18.04
上面的命令中沒有給出 Docker 鏡像倉庫地址,因此將會從 Docker Hub (docker.io
)獲取鏡像。而鏡像名稱是 ubuntu:18.04
,因此將會獲取官方鏡像 library/ubuntu
倉庫中標簽為 18.04
的鏡像。docker pull
命令的輸出結果最后一行給出了鏡像的完整名稱,即: docker.io/library/ubuntu:18.04
。
列出鏡像
要想列出已經下載下來的鏡像,可以使用 docker image ls
命令。
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
redis latest 5f515359c7f8 5 days ago 183 MB
nginx latest 05a60462f8ba 5 days ago 181 MB
mongo 3.2 fe9198c04d62 5 days ago 342 MB
<none> <none> 00285df0df87 5 days ago 342 MB
ubuntu 18.04 329ed837d508 3 days ago 63.3MB
ubuntu bionic 329ed837d508 3 days ago 63.3MB
列表包含了 倉庫名
、標簽
、鏡像 ID
、創建時間
以及 所占用的空間
。
其中倉庫名、標簽在之前的基礎概念章節已經介紹過了。鏡像 ID 則是鏡像的唯一標識,一個鏡像可以對應多個 標簽。因此,在上面的例子中,我們可以看到 ubuntu:18.04
和 ubuntu:bionic
擁有相同的 ID,因為它們對應的是同一個鏡像。
鏡像體積
docker image ls
列表中的鏡像體積總和并非是所有鏡像實際硬盤消耗。由于 Docker 鏡像是多層存儲結構,并且可以繼承、復用,因此不同鏡像可能會因為使用相同的基礎鏡像,從而擁有共同的層。由于 Docker 使用 Union FS,相同的層只需要保存一份即可,因此實際鏡像硬盤占用空間很可能要比這個列表鏡像大小的總和要小的多。
你可以通過 docker system df
命令來便捷的查看鏡像、容器、數據卷所占用的空間。
$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 24 0 1.992GB 1.992GB (100%)
Containers 1 0 62.82MB 62.82MB (100%)
Local Volumes 9 0 652.2MB 652.2MB (100%)
Build Cache 0B 0B
虛懸鏡像
上面的鏡像列表中,還可以看到一個特殊的鏡像,這個鏡像既沒有倉庫名,也沒有標簽,均為 <none>
。:
<none> <none> 00285df0df87 5 days ago 342 MB
這個鏡像原本是有鏡像名和標簽的,原來為 mongo:3.2
,隨著官方鏡像維護,發布了新版本后,重新 docker pull mongo:3.2
時,mongo:3.2
這個鏡像名被轉移到了新下載的鏡像身上,而舊的鏡像上的這個名稱則被取消,從而成為了 <none>
。除了 docker pull
可能導致這種情況,docker build
也同樣可以導致這種現象。由于新舊鏡像同名,舊鏡像名稱被取消,從而出現倉庫名、標簽均為 <none>
的鏡像。這類無標簽鏡像也被稱為 虛懸鏡像(dangling image) ,可以用下面的命令專門顯示這類鏡像:
$ docker image ls -f dangling=true
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 00285df0df87 5 days ago 342 MB
一般來說,虛懸鏡像已經失去了存在的價值,是可以隨意刪除的,可以用下面的命令刪除。
$ docker image prune
刪除本地鏡像
如果要刪除本地的鏡像,可以使用 docker image rm
命令,其格式為:
$ docker image rm [選項] <鏡像1> [<鏡像2> ...]
用 ID、鏡像名、摘要刪除鏡像
其中,<鏡像>
可以是 鏡像短 ID
、鏡像長 ID
、鏡像名
或者 鏡像摘要
。
## 鏡像短 ID
$ docker image rm 501
## 鏡像名
$ docker image rm centos
## 摘要
$ docker image ls --digests
REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
node slim sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228 6e0c4c8e3913 3 weeks ago 214 MB
$ docker image rm node@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228
Untagged: node@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228
用 docker image ls 命令來配合
像其它可以承接多個實體的命令一樣,可以使用 docker image ls -q
來配合使用 docker image rm
,這樣可以成批的刪除希望刪除的鏡像。
比如,我們需要刪除所有倉庫名為 redis
的鏡像:
$ docker image rm $(docker image ls -q redis)
或者刪除所有在 mongo:3.2
之前的鏡像:
$ docker image rm $(docker image ls -q -f before=mongo:3.2)
使用 Dockerfile 定制鏡像
Dockerfile 內容
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
FROM 指定基礎鏡像
所謂定制鏡像,那一定是以一個鏡像為基礎,在其上進行定制。就像我們之前運行了一個 nginx
鏡像的容器,再進行修改一樣,基礎鏡像是必須指定的。而 FROM
就是指定 基礎鏡像,因此一個 Dockerfile
中 FROM
是必備的指令,并且必須是第一條指令。
除了選擇現有鏡像為基礎鏡像外,Docker 還存在一個特殊的鏡像,名為 scratch
。這個鏡像是虛擬的概念,并不實際存在,它表示一個空白的鏡像。
FROM scratch
...
如果你以 scratch
為基礎鏡像的話,意味著你不以任何鏡像為基礎,接下來所寫的指令將作為鏡像第一層開始存在。
不以任何系統為基礎,直接將可執行文件復制進鏡像的做法并不罕見,對于 Linux 下靜態編譯的程序來說,并不需要有操作系統提供運行時支持,所需的一切庫都已經在可執行文件里了,因此直接 FROM scratch
會讓鏡像體積更加小巧。使用 Go 語言 開發的應用很多會使用這種方式來制作鏡像,這也是有人認為 Go 是特別適合容器微服務架構的語言的原因之一。
RUN 執行命令
RUN
指令是用來執行命令行命令的。由于命令行的強大能力,RUN
指令在定制鏡像時是最常用的指令之一。其格式有兩種:
-
shell 格式:
RUN <命令>
,就像直接在命令行中輸入的命令一樣。剛才寫的 Dockerfile 中的RUN
指令就是這種格式。
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
-
exec 格式:
RUN ["可執行文件", "參數1", "參數2"]
,這更像是函數調用中的格式。
構建鏡像
在 Dockerfile
文件所在目錄執行:
$ docker build -t nginx:v3 .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM nginx
---> e43d811ce2f4
Step 2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
---> Running in 9cdc27646c7b
---> 44aa4490ce2c
Removing intermediate container 9cdc27646c7b
Successfully built 44aa4490ce2c
這里我們使用了 docker build
命令進行鏡像構建。其格式為:
docker build [選項] <上下文路徑/URL/->
指定了最終鏡像的名稱 -t nginx:v3
鏡像構建上下文(Context)
如果注意,會看到 docker build
命令最后有一個 .
。.
表示當前目錄,而 Dockerfile
就在當前目錄,因此不少初學者以為這個路徑是在指定 Dockerfile
所在路徑,這么理解其實是不準確的。
首先我們要理解 docker build
的工作原理。Docker 在運行時分為 Docker 引擎(也就是服務端守護進程)和客戶端工具。Docker 的引擎提供了一組 REST API,被稱為 Docker Remote API,而如 docker
命令這樣的客戶端工具,則是通過這組 API 與 Docker 引擎交互,從而完成各種功能。因此,雖然表面上我們好像是在本機執行各種 docker
功能,但實際上,一切都是使用的遠程調用形式在服務端(Docker 引擎)完成。也因為這種 C/S 設計,讓我們操作遠程服務器的 Docker 引擎變得輕而易舉。
當我們進行鏡像構建的時候,并非所有定制都會通過 RUN
指令完成,經常會需要將一些本地文件復制進鏡像,比如通過 COPY
指令、ADD
指令等。而 docker build
命令構建鏡像,其實并非在本地構建,而是在服務端,也就是 Docker 引擎中構建的。那么在這種客戶端/服務端的架構中,如何才能讓服務端獲得本地文件呢?
這就引入了上下文的概念。當構建的時候,用戶會指定構建鏡像上下文的路徑,docker build
命令得知這個路徑后,會將路徑下的所有內容打包,然后上傳給 Docker 引擎。這樣 Docker 引擎收到這個上下文包后,展開就會獲得構建鏡像所需的一切文件。
如果在 Dockerfile
中這么寫:
COPY ./package.json /app/
這并不是要復制執行 docker build
命令所在的目錄下的 package.json
,也不是復制 Dockerfile
所在目錄下的 package.json
,而是復制 上下文(context) 目錄下的 package.json
。
因此,COPY
這類指令中的源文件的路徑都是相對路徑。這也是初學者經常會問的為什么 COPY ../package.json /app
或者 COPY /opt/xxxx /app
無法工作的原因,因為這些路徑已經超出了上下文的范圍,Docker 引擎無法獲得這些位置的文件。如果真的需要那些文件,應該將它們復制到上下文目錄中去。
現在就可以理解剛才的命令 docker build -t nginx:v3 .
中的這個 .
,實際上是在指定上下文的目錄,docker build
命令會將該目錄下的內容打包交給 Docker 引擎以幫助構建鏡像。
如果觀察 docker build
輸出,我們其實已經看到了這個發送上下文的過程:
$ docker build -t nginx:v3 .
Sending build context to Docker daemon 2.048 kB
...
客戶端命令(docker)
客戶端命令選項
-
--config=""
:指定客戶端配置文件,默認為~/.docker
; -
-D=true|false
:是否使用 debug 模式。默認不開啟; -
-H, --host=[]
:指定命令對應 Docker 守護進程的監聽接口,可以為 unix 套接字unix:///path/to/socket
,文件句柄fd://socketfd
或 tcp 套接字tcp://[host[:port]]
,默認為unix:///var/run/docker.sock
; -
-l, --log-level="debug|info|warn|error|fatal"
:指定日志輸出級別; -
--tls=true|false
:是否對 Docker 守護進程啟用 TLS 安全機制,默認為否; -
--tlscacert=/.docker/ca.pem
:TLS CA 簽名的可信證書文件路徑; -
--tlscert=/.docker/cert.pem
:TLS 可信證書文件路徑; -
--tlscert=/.docker/key.pem
:TLS 密鑰文件路徑; -
--tlsverify=true|false
:啟用 TLS 校驗,默認為否。
客戶端命令
可以通過 docker COMMAND --help
來查看這些命令的具體用法。
-
attach
:依附到一個正在運行的容器中; -
build
:從一個 Dockerfile 創建一個鏡像; -
commit
:從一個容器的修改中創建一個新的鏡像; -
cp
:在容器和本地宿主系統之間復制文件中; -
create
:創建一個新容器,但并不運行它; -
diff
:檢查一個容器內文件系統的修改,包括修改和增加; -
events
:從服務端獲取實時的事件; -
exec
:在運行的容器內執行命令; -
export
:導出容器內容為一個tar
包; -
history
:顯示一個鏡像的歷史信息; -
images
:列出存在的鏡像; -
import
:導入一個文件(典型為tar
包)路徑或目錄來創建一個本地鏡像; -
info
:顯示一些相關的系統信息; -
inspect
:顯示一個容器的具體配置信息; -
kill
:關閉一個運行中的容器 (包括進程和所有相關資源); -
load
:從一個 tar 包中加載一個鏡像; -
login
:注冊或登錄到一個 Docker 的倉庫服務器; -
logout
:從 Docker 的倉庫服務器登出; -
logs
:獲取容器的 log 信息; -
network
:管理 Docker 的網絡,包括查看、創建、刪除、掛載、卸載等; -
node
:管理 swarm 集群中的節點,包括查看、更新、刪除、提升/取消管理節點等; -
pause
:暫停一個容器中的所有進程; -
port
:查找一個 nat 到一個私有網口的公共口; -
ps
:列出主機上的容器; -
pull
:從一個Docker的倉庫服務器下拉一個鏡像或倉庫; -
push
:將一個鏡像或者倉庫推送到一個 Docker 的注冊服務器; -
rename
:重命名一個容器; -
restart
:重啟一個運行中的容器; -
rm
:刪除給定的若干個容器; -
rmi
:刪除給定的若干個鏡像; -
run
:創建一個新容器,并在其中運行給定命令; -
save
:保存一個鏡像為 tar 包文件; -
search
:在 Docker index 中搜索一個鏡像; -
service
:管理 Docker 所啟動的應用服務,包括創建、更新、刪除等; -
start
:啟動一個容器; -
stats
:輸出(一個或多個)容器的資源使用統計信息; -
stop
:終止一個運行中的容器; -
swarm
:管理 Docker swarm 集群,包括創建、加入、退出、更新等; -
tag
:為一個鏡像打標簽; -
top
:查看一個容器中的正在運行的進程信息; -
unpause
:將一個容器內所有的進程從暫停狀態中恢復; -
update
:更新指定的若干容器的配置信息; -
version
:輸出 Docker 的版本信息; -
volume
:管理 Docker volume,包括查看、創建、刪除等; -
wait
:阻塞直到一個容器終止,然后輸出它的退出符。