使用 Port forwarding 開放服務
今天將會使用 Docker 啟動 HTTP server,並讓瀏覽器能看得到 HTTP server 所提供的 hello world。
常見的 HTTP server 主要有兩種:Nginx 與 Apache,今天會以 Apache HTTP server(以下簡稱 Apache)為例。
Container 管理小技巧
首先,先使用 docker run
跑 Apache container。
# Apache 的 image 名稱叫 httpd |
Apache 執行時,會停在前景等待收 request。若要中止它,可以按 Ctrl + C
快捷鍵強制中離。從訊息可以觀察到,Ctrl + C
跟 docker stop
一樣是發出 SIGTERM
信號給 process。狀態已經停止了,但 container 還存在,如果不需要的話得手動移除。
通常練習或測試的 container 都不需要保留,每次手動移除也很麻煩,這時可以使用參數 --rm
,範例如下:
# 加帶 --rm 參數 |
--rm
選項的功能是,當 container 的狀態變成 Exited
時,會自動把這個 container 移除,在練習或測試的時候非常方便。
背景執行
前景執行 Apache 的時候,按下昨天提到的 Ctrl + P
與 Ctrl + Q
,會發現一點用都沒有。但像今天是啟動 HTTP server,通常會希望它是背景執行,這時可以使用另一個參數 -d
,範例如下:
# 執行完會馬上回到 host 上 |
執行完 docker run
會回 CONTAINER ID
並回到原本的命令提示字元。這時再觀察 docker ps
會看到對應的 container 是運作中的狀態。
在 Hello Docker 說明 docker rm
的時候有提到,container 的狀態不是 Up
才能移除。除了先使用 docker stop
再使用 docker rm
外,也可以使用 docker rm
的 -f
參數強制移除 container:
# 執行完會馬上回到 host 上 |
加 --rm
選項可以讓它結束後自動移除,但得先用 docker stop
停止 container 才會觸發移除,那倒不如使用 docker rm -f
指令還比較直接一點。
雖然 Docker 並沒有特別禁止,但建議不要同時啟用 --rm
和 -d
這兩個選項;另外還有一個原因是,在 Docker v1.13.0 版以前,是不能同時啟用 --rm
與 -d
的,詳細可參考 Docker issue。
存取服務
我們先把 container 都移除,然後背景執行一個 Apache container。
# 背景啟動 Apache |
docker ps
裡面有個欄位是 PORTS
,上面寫著 80/tcp
,看起來很像是可以透過本地的 80 port 來存取 HTTP server。但實際上用 curl 會回應連線被拒絕,這代表從 host 連到 container 的方法有問題。
說明解法前,大家可以先試看看下面的指令:run 3 個 Apache container:
docker run -d httpd |
docker ps
可以觀察到,所有 port 都是 80/tcp
,但奇妙的是,全部 container 都沒有遇到 port 衝突!?從這個實驗結果可以了解 container 具有隔離特性,也就是每個 container 都是獨立的個體,它們各自有屬於自己的 80 port 可以用,因此才不會相衝。
今天的目標是要從外界存取 container,因此要做點手腳才行--正是標題提到的 port forwarding。Docker 使用 -p
選項設定 port forwarding,範例如下:
# 加上 -p 參數 |
-p
後面參數 8080:80
的意思代表:當連線到 host 的 8080 port 會轉接到 container 的 80 port。以上面的指令為例,只要輸入 http://localhost:8080/
即可接到 container 所啟動的 HTTP 服務。
下面是簡單示意圖:
Container 啟動完後,8080 是被綁定在 host 上的。只要有另一個服務綁 8080 在 host 上的話,就會出現錯誤訊息 port is already allocated.
:
docker run -d -p 8080:80 httpd |
指令補充說明
docker run
補充說明其他參數:
--rm
當 container 主程序一結束時,立刻移除 container-d|--detach
背景執行 container-p|--publish
把 container 的 port 公開到 host 上,格式為[[[IP:]HOST_PORT:]CONTAINER_PORT]
給完整格式的話,會把IP:HOST_PORT
綁定到CONTAINER_PORT
;如果沒給 IP,則 IP 會代 0.0.0.0;如果連 HOST_PORT 也沒給,則會使用 0.0.0.0 加上隨機選一個 port,如0.0.0.0:32768
。
docker rm
補充說明其他參數:
-f|--force
如果是執行中的 container,會強制移除(使用 SIGKILL)
今日自我回顧
Container 具備了隔離機制,因此有辦法把它當作「輕量的 VM 」使用。
今天說明的 port forwarding,可以應用在任何有開 port 提供服務的 server,如:MySQL、Redis、Memcached 等,有興趣可以參考官網範例自行試試。
- 了解 container 隔離的特性
- 練習使用
docker run
的--rm
參數與-p
參數 - 練習透過 port forwarding 存取 container 提供的 HTTP server 或其他 server