2.2 一探究竟容器內部
在這個小節,我們將進入容器內部一探究竟。
在以前,連線進入一個雲端或是隔離環境內,我們常常使用 ssh 的方式來建立安全的通道,但在 Docker 的世界裡不需要這麼做,就可以輕鬆連線到容器內部。
透過指令進入容器內部
透過下方的指令,終端機將會進入另一個終端機:
$ docker container run --interactive --tty nginx bash
root@d33940b87e66:/#
終端機理論上會呈現一個可以輸入的模式,所以我們可以輸入一些基本的 Linux 指令來驗證一下:
root@d33940b87e66:/# ls
bin boot dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
離開容器內部
目前的我們還待在容器的內部,只要輸入 exit
就能夠輕鬆的離開容器內部,並且回到本機的終端機輸入行。
root@d33940b87e66:/# exit
exit
$
進入運作中的容器
上一個示範是在啟動容器時進入,但現實中大部分的應用程式都是一直在執行中的狀態,所以隨時都有進入容器的可能。
首先讓 nginx 容器在背景執行:
$ docker container run --detach --publish 80:80 nginx
64d52ea0e08797aade7f86701b60ed903373f53713d6f7eca62...
利用 docker container list
確定 nginx 容器在背景執行:
$ docker container list
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
64d52ea0... nginx "/doc.. 31 se.. Up 2.. 0.0.0.0:80->80/tcp hungry..
加入 exec
這個新的指令,對正在運作中的容器下指令,都需要加入 exec 的指令才能執行,我們進入後一樣用了 ls 這個 Linux 指令來查看容器中的檔案,並且輸入 exit 退出容器。
$ docker container exec --interactive --tty 64d52 bash
root@64d52ea0e087:/# ls
bin boot dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@64d52ea0e087:/# exit
exit
新的參數代表什麼?
首先是 --interactive
,我們透過閱讀 Docker 官方文件得到下面的答案:
Keep STDIN open even if not attached
直接翻譯就是保持輸入模式,但可以理解成和容器之間保持互動的狀況,要如何驗證呢?
我們故意不輸入 --interactive
的參數,看看會發生什麼事情。
$ docker container run --tty nginx bash
在你還沒輸入任何 Linux 指令前,看起來應該是很正常,那我們試著來輸入指令吧!
root@d33940b87e66:/# ls
# 接著他就完全停住了
要離開的話,直接關掉終端機就可以了,用上述的例子證明了如果不加入 --interactive
這個參數,即使我們能夠輸入指令,也沒辦法和容器互動。
接著是 --tty
這個參數,透過閱讀 Docker 官方文件得到的答案是:
Allocate a pseudo-TTY
直接翻譯就是分配一個虛擬的 TTY,而這個 TTY 代表甚麼呢?
這就是一個有歷史淵源的故事了,在上古時代,當時的電腦非常的昂貴,所以一台電腦要分配給多個用戶進行操作,而多個用戶自然就需要多台打字機對著電腦進行輸入。
而 tty 正是英文 Teletypewriter 的縮寫,但其實在現代,終端機和打字機的界線已經模糊不清,可以想像,終端機就是 tty,反之亦然。
具有實驗精神的我們,也可以透過故意不使用 --tty
的參數來看看會發生什麼事情?
$ docker container run --interactive nginx bash
# 這邊看起來雖然像是不能動,但還是能夠輸入指令
ls
bin
boot
dev
docker-entrypoint.d
docker-entrypoint.sh
輸入 exit
也可以正常離開,但很明顯的感受到這根本不像是一個正常的終端機,回傳的資訊也都會自動的換行,根本沒辦法好好瀏覽,所以有沒有一個正常的終端機視窗也是很重要的。
exec 又代表什麼呢?
為什麼只要是對正在運作中的容器下指令,都需要加入 exec
才能執行呢?
exec
是一個允許在運行中的 Docker 容器內執行任何指令的指令,這邊聽起來很饒口,白話文就是它可以把指令傳遞到運行中的容器內並要求容器執行指令。
讓我們用下方的例子來快速地了解一下。
首先我們讓 nginx 容器在背景執行:
$ docker container run --detach --publish 80:80 nginx
a276f434ce5900b664ccfe99f74d957539681412f07f8802821e8de938a42e0b
這時候我們若是要列出容器內的所有檔案會怎麼做呢?根據剛剛學到的指令,您可能會用下面的方式,先進入到容器內,並且輸入 ls 指令來列出所有的檔案。
$ docker container exec --interactive --tty a276 bash
root@a276f434ce59:/# ls
bin boot dev docker-entrypoint.d docker-entrypoint.sh ...
root@a276f434ce59:/# exit
exit
但根據 exec
這個指令的定義,可以把指令傳遞到運行中的容器內並要求容器執行指令,所以我們其實可以這樣做:
$ docker container exec a276 ls
bin
boot
dev
docker-entrypoint.d
docker-entrypoint.sh
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
如同定義一樣,我們要求 nginx 指令執行 ls 這段指令,並且回傳結果。
後面的 bash 是什麼?
在我們練習進入容器內部時,應該會有一個疑惑,就是為什麼要在 nginx 映像檔的後方加上一個 bash 指令呢?
首先我們利用 Docker 提供的 --help
方法來看看,後面到底能夠接受什麼樣的參數呢?
$ docker container run --help
Usage: docker container run [OPTIONS] IMAGE [COMMAND] [ARG...]
Run a command in a new container
....
可以看到 IMAGE 的後方還可以接受 COMMAND 的參數,而這個 COMMAND 就是容器啟動時會執行的指令。
那為什麼之前又不需要呢?是因為映像檔在建置的時候都會給予一個 CMD 參數來當作容器啟動時的指令,若沒有輸入額外的 COMMAND 去取代,就會使用映像檔預設的啟動指令。
而 nginx 這個映像檔預設的啟動指令就是 nginx -g daemon off
,也就是啟動 nginx 的意思。
在上面的範例中,我們就是利用了 bash
這個指令來取代掉 nginx -g daemon off
啟動指令,變成容器在啟動時執行 bash 這個命令處理器。