Docker 提供多種網路模式,影響容器的網路行為。可以讓容器與 Docker 主機共用網路,或完全隔離。none 網路不提供任何網路介面,bridge 網路則為單一主機上的預設網路,透過 docker0 介面路由。自訂網路允許建立隔離的網路環境,而 Docker Swarm 的 Overlay 網路則可建立跨主機網路。服務暴露可透過 -p 選項發布容器埠,方便外部存取。除錯網路問題時,可使用 netstat、telnet、strace 等工具。設定 DNS 可透過 –dns 選項指定伺服器,或使用 dnsmasq 覆寫 DNS 條目。容器內傳送郵件可使用主機郵件服務或安裝 ssmtp。

VII. 連線埠繫結 - 透過連線埠繫結匯出服務

在 Docker 和網路相關的應用中,容器執行的網路模式有多種,這些模式對於容器的網路行為有著重要的影響。你可以選擇讓容器與 Docker 主機共用相同的網路,或者完全隔離容器的網路。這種行為取決於所使用的網路驅動程式。

使用 Docker 時,你可以定義自己的使用者自定義網路。這些網路可以在單一主機上建立,也可以跨越多個主機(Docker Swarm)。預設情況下,Docker 會建立幾個網路:

Docker 網路型別

  1. none 網路:此網路不會為容器新增任何網路介面,這意味著容器內的程式無法使用任何網路功能。容器無法連線到網際網路,也無法將服務暴露給其他容器。

    # docker run --rm -it --network=none alpine:3.5 ip addr
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
        valid_lft forever preferred_lft forever
        inet6 ::1/128 scope host 
        valid_lft forever preferred_lft forever
    

    如上所示,只有「lo」(迴路/本地端)介面可在容器中使用。這種網路模式適用於執行不可信任的程式碼,或者你知道某些 CLI 應用程式不應該具有網際網路存取許可權的情況。

  2. bridge 網路:這是你在單一主機上執行 Docker 容器時的預設網路。此網路透過 Docker 主機上的 docker0 介面進行路由。

    如果你在預設網路上執行多個容器,它們無法透過 DNS 互相看到對方,但如果你知道其他容器的 IP,就可以 ping/連線到它們。

    # docker run -itd --name sh1 alpine:3.5 sh
    # docker run -itd --name sh2 alpine:3.5 sh
    # docker run --rm -it alpine:3.5 ping sh1
    ping: bad address 'sh1'
    

    但是,你可以 ping/連線到相同網路上的其他容器(如果知道其 IP)。

    # docker exec -it sh1 ip addr | grep global
    inet 172.17.0.3/16 scope global eth0
    # docker exec -it sh2 ip addr | grep global
    inet 172.17.0.4/16 scope global eth0
    # docker exec -it sh2 ping 172.17.0.3
    PING 172.17.0.3 (172.17.0.3): 56 data bytes
    64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.167 ms
    64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.111 ms
    ^C
    

    從這些容器中可以自由存取網際網路,因此你可以擷取網際網路上的套件、取用公開的 API 服務或連線到相同私有區域網路中的其他主機。

內容解密:

  • Docker 網路型別包括 none 和 bridge 等。
  • none 網路使容器完全隔離於網路,而 bridge 網路則允許容器間的通訊(透過 IP 位址)並可存取網際網路。
  • 正確選擇網路模式對於確保容器的安全性和功能性至關重要。

Docker Swarm 與服務擴充套件

Docker Swarm 是 Docker 的叢集管理工具,允許你將多個 Docker 主機組成一個虛擬的 Docker 主機。在上述範例中,我們使用 Docker Swarm 建立了一個具有多個副本的 sonyflake 服務,並對其進行了效能測試。

# docker service create \
--replicas 5 \
--network party-swarm \
--update-parallelism 5 \
--name sonyflake \
-p 80:80 titpetric/sonyflake

內容解密:

  • 使用 Docker Swarm 可以輕鬆地擴充套件服務。
  • --replicas 引數用於指定服務的副本數量。
  • --network 引數指定服務所使用的網路。
  • -p 引數進行主機與容器的連線埠對應。

自定義網路與服務暴露:深入解析 Docker 網路架構

Docker 的網路功能是其重要的組成部分,允許容器之間進行通訊以及與外部網路互動。本文將探討 Docker 的自定義網路、跨主機網路以及主機網路模式,提供技術深度與實務經驗的分析。

自定義橋接網路

自定義橋接網路允許使用者建立多個隔離的網路環境,讓容器可以在特定的網路中進行通訊。建立自定義橋接網路的指令如下:

docker network create -d bridge --subnet 172.25.0.0/24 party

此指令建立了一個名為 party 的橋接網路,使用 172.25.0.0/24 子網。這種網路與預設的橋接網路不同,連線到此網路的容器可以透過 Docker 內部的 DNS 服務互相解析對方的名稱。

內容解密:

  • docker network create:建立新的 Docker 網路。
  • -d bridge:指定網路驅動程式為橋接模式。
  • --subnet 172.25.0.0/24:指定子網範圍。
  • party:自定義網路的名稱。

建立兩個容器並測試它們之間的連通性:

docker run -itd --name sh1 --network party alpine:3.5 sh
docker run -itd --name sh2 --network party alpine:3.5 sh
docker exec -it sh2 ping sh1

內容解密:

  • docker run -itd --name sh1 --network party alpine:3.5 sh:以分離模式執行一個名為 sh1 的容器,並連線到 party 網路。
  • docker exec -it sh2 ping sh1:在 sh2 容器中執行 ping 命令測試與 sh1 的連通性。

跨主機網路

在 Docker Swarm 模式下,可以使用 Overlay 網路驅動程式建立跨主機的網路。這種網路允許不同主機上的容器進行通訊。

建立 Overlay 網路的指令如下:

docker network create \
  --driver overlay \
  --subnet 10.0.0.0/20 \
  --attachable \
  party-swarm

內容解密:

  • --driver overlay:指定使用 Overlay 網路驅動程式。
  • --subnet 10.0.0.0/20:指定較大的子網範圍以支援更多的容器。
  • --attachable:允許非 Swarm 服務的容器連線到此網路。

在不同主機上執行容器並測試它們之間的連通性:

ssh swarm2 docker run -itd --name sh1 --network party-swarm alpine:3.5 sh
ssh swarm3 docker run -itd --name sh2 --network party-swarm alpine:3.5 sh
docker run -it --rm --network party-swarm alpine:3.5 nslookup sh1

內容解密:

  • ssh swarm2 docker run ...:在遠端主機 swarm2 上執行容器。
  • docker run -it --rm --network party-swarm alpine:3.5 nslookup sh1:在當前主機上執行容器並解析 sh1 的名稱。

主機網路模式

主機網路模式讓容器分享主機的網路堆疊,提供完全的網路存取許可權。這對於需要高度網路存取許可權的應用(如 VPN 使用者端或網路監控工具)非常有用。

執行容器時使用 --net=host 選項即可啟用主機網路模式:

docker run --net=host my-vpn-client

內容解密:

  • --net=host:啟用主機網路模式,讓容器分享主機的網路堆疊。

透過埠繫結(Port Binding)匯出服務

暴露服務埠

執行服務的建議方式是將容器附加到自訂的橋接網路(bridge network)或疊加網路(overlay network),取決於您是使用 Docker 還是 Swarm 服務來呼叫容器。無論採用哪種方式,都可以透過 -p 選項公開個別埠。

檢視第四章的 Redis 範例,您會注意到沒有公開任何埠。Redis 是一個私有的服務,執行在我們的內部網路上,這意味著同一個網路上的其他容器可以存取它,而無需 Docker 設定代理。

當您明確想要發布服務埠時,只有一個選項:

使用 -p 選項發布容器埠

格式如下:

ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort | containerPort

hostPortcontainerPort 都可以指定為埠範圍。當為兩者指定範圍時,容器埠範圍內的埠數量必須與主機埠範圍內的埠數量相匹配,例如:

-p 1234-1236:1234-1236/tcp

當僅指定 hostPort 的範圍時,containerPort 不能是範圍。在這種情況下,容器埠會被發布到指定的 hostPort 範圍內的某個埠,例如:

-p 1234-1236:1234/tcp

假設您的應用程式監聽埠 3000,但您想暴露埠 80,您可以傳遞 -p 80:3000。這使得執行不完全符合 12FA 規範的應用程式變得更加容易,您無法透過環境變數設定其埠。

除錯 Docker 網路連線

除錯網路連線問題時,通常會檢查幾個方面。在 Debian 中,有一個名為 net-tools 的套件,提供了 netstat 工具。使用它,可以輕鬆檢查給定的服務是否正在監聽某個埠。例如,要了解您的 Docker 應用程式正在繫結哪些內部服務埠,可以執行:

docker exec -it apt-cacher netstat -pan

輸出範例:

Active Internet connections (servers and established)
Proto Local Address           Foreign Address         State       PID/Program name
tcp   127.0.0.11:37391        0.0.0.0:*               LISTEN      -
tcp   0.0.0.0:3142            0.0.0.0:*               LISTEN      7/apt-cacher-ng
tcp6  :::3142                 :::*                    LISTEN      7/apt-cacher-ng
udp   127.0.0.11:32837        0.0.0.0:*                           -

您可以選擇附加 | grep LISTEN 以僅檢視正在監聽傳入連線的埠。這裡,我們有一個 apt-cacher-ng 的例項,它正在 IPv4 和 IPv6 上監聽埠 3142。

Linux 中可用的網路除錯工具

Linux 中有多種工具可用於除錯網路連線和程式執行。至少應該對以下工具有所瞭解:

  • telnetnetcat:開啟到 IP/主機和埠的原始連線(TCP)
  • curlwget:向端點發出 HTTP 請求
  • netcatss:列出開啟的連線、列出監聽的通訊端
  • lsof:列出正在執行的程式開啟的檔案
  • strace:列印您執行的程式的系統呼叫軌跡

尤其是 strace,在除錯網路連線問題時可能非常有用。曾經遇到過連線到在 Docker 中執行的資料函式庫例項需要幾秒鐘的時間。使用了 telnet 後,發現連線到 MySQL 的時間延遲是由於 DNS 解析問題引起的。使用 strace 後,發現了 /etc/resolv.conf 中的 search mtk.lan 選項導致了延遲。重新啟動 Docker 守護程式後,問題得以解決。

使用 Plantuml 圖表呈現網路架構

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title 使用 Plantuml 圖表呈現網路架構

rectangle "監聽埠 3000" as node1
rectangle "暴露埠 80" as node2
rectangle "反向代理" as node3

node1 --> node2
node2 --> node3

@enduml

此圖示呈現了應用程式、容器和主機之間的關係,以及如何透過暴露埠和反向代理來處理外部請求。

詳細說明

透過使用 -p 選項,可以將容器的埠對映到主機的埠,使得外部可以存取容器內的服務。在除錯網路連線問題時,可以使用多種 Linux 工具,如 netstattelnetstrace 等。這些工具可以幫助您瞭解容器的網路組態、檢查服務是否正在監聽特定的埠、以及除錯網路延遲等問題。

自訂DNS與郵件傳送在Docker中的應用

在Docker容器中,有時需要自訂DNS伺服器或傳送郵件。本文將介紹如何在Docker中使用自訂DNS以及如何設定郵件傳送。

使用自訂DNS

Docker提供了--dns選項,允許使用者指定容器使用的DNS伺服器。例如:

docker run -it --rm=true --dns 8.8.8.8 alpine:3.5 ping www.google.com

內容解密:

  1. docker run:啟動一個新的Docker容器。
  2. -it:分配一個偽TTY,並保持STDIN開啟,允許與容器互動。
  3. --rm=true:當容器離開時自動刪除容器。
  4. --dns 8.8.8.8:指定容器使用Google的公共DNS伺服器(8.8.8.8)。
  5. alpine:3.5:使用Alpine Linux 3.5作為容器基礎映像。
  6. ping www.google.com:在容器內執行ping命令測試網路連線。

此外,還可以使用janeczku/go-dnsmasq來執行一個開發用的DNS伺服器,並覆寫某些公共DNS條目。例如:

#!/bin/bash
NAME="dnsmasq"
DOCKERFILE="janeczku/go-dnsmasq:latest"
PARENT=$(dirname $(dirname $(realpath -s $0)))
docker rm -f $NAME
docker run --restart=always -d -h $NAME --name $NAME -p 53:53/udp -p 53:53 -v $PARENT/conf:/conf $DOCKERFILE -f /conf/hosts --verbose -n 8.8.8.8,8.8.4.4

內容解密:

  1. docker rm -f $NAME:強制刪除名為$NAME的容器。
  2. docker run:啟動一個新的容器。
  3. --restart=always:設定容器總是重啟。
  4. -d:以分離模式執行容器。
  5. -h $NAME:設定容器的主機名。
  6. --name $NAME:命名容器。
  7. -p 53:53/udp -p 53:53:將主機的53埠(TCP和UDP)對映到容器的53埠,用於DNS服務。
  8. -v $PARENT/conf:/conf:掛載主機的組態目錄到容器的/conf目錄。
  9. $DOCKERFILE:使用指定的Docker映像。
  10. -f /conf/hosts --verbose -n 8.8.8.8,8.8.4.4:指定dnsmasq的組態檔案和上游DNS伺服器。

傳送郵件

在Docker容器中傳送郵件有多種方法。最簡單的方法是使用主機上的郵件服務,或在容器中安裝ssmtp

使用主機上的郵件服務

可以透過--add-host選項將主機的郵件服務對映到容器內。例如:

--add-host docker:172.25.0.1 --add-host mail:172.25.0.1 --add-host $(uname -n):172.25.0.1

內容解密:

  1. --add-host:在容器的/etc/hosts檔案中新增主機名到IP的對映。
  2. docker:172.25.0.1mail:172.25.0.1$(uname -n):172.25.0.1:將指定的主機名對映到IP 172.25.0.1

在容器中安裝ssmtp

在根據Alpine的容器中,可以透過以下命令安裝ssmtp

apk --update add ssmtp

內容解密:

  1. apk:Alpine的包管理工具。
  2. --update:更新包索引。
  3. add ssmtp:安裝ssmtp包。

安裝後,可以透過環境變陣列態ssmtp

cat << EOF > /etc/ssmtp/ssmtp.conf
mailhub=$SSMTP_SERVER:$SSMTP_PORT
AuthUser=$SSMTP_USER
AuthPass=$SSMTP_PASS
UseSTARTTLS=$SSMTP_TLS
hostname=$SSMTP_HOSTNAME
FromLineOverride=YES
EOF

內容解密:

  1. cat << EOF > /etc/ssmtp/ssmtp.conf:建立或覆寫/etc/ssmtp/ssmtp.conf檔案。
  2. 各個組態項指定了SMTP伺服器的地址、埠、驗證資訊、TLS使用等。

對於實際的郵件投遞,可以使用公共或私有的郵件服務,如Google Mail SMTP、Sendgrid、Mailchimp或Amazon SES。也可以使用Sendy等工具簡化郵件傳送過程。