情境
通常在使用 EC2 的建議上都是希望將機器掛上 IAM Role 的權限,在機器上面執行相關 AWS 資源時就可以透過該角色的權限來執行,避免將 Access Toke 、Secret Key 寫到程式中去跑。
但如果將程式包到 Container 裡面去執行時卻發現,Linux Container 可以吃到 Host 的 IAM Role 權限,而 Windows Container 卻不行,為何 ?
原因
原來 AWS 之所以能夠讓機器能知道執行權限為何是否過一個叫 Metadata Service 的服務來達成
1 | $ curl 169.254.169.254 |
當在 EC2 上執行該指令應該能看到基本的回應
連線到 http://169.254.169.254/latest/meta-data/
也可以看到一些對應的 Metadata 設定,而這個 Metadata Service IP 很巧的在 Azure 上也一模一樣 XD
所以要能夠透過 IAM Role 的權限來執行 AWS 相關資源,169.254.169.254 就勢必要能通,接著將 Windows Container Run起來並執行相同指令會發現得到 Timeout 的回應
Windows Container 預設是走 NAT 的網路模式,如果你在 Host 與 Windows Container 內列出 Routing Table IPv4 的資料會發現,169.254.169.254 Gateway 是走同一條
1 | $ route print -4 |
這也是導致 Container 內得不到回應的原因
1 | $ ipconfig /all |
應該透過 NAT Router default gateway 才出的去
解法
先看看預設 Container 用的網路是如何設定的
1 | $ docker network ls |
1 | $ docker network inspect nat |
可以看到紅框處並沒有指定 Default Gateway,所以每次執行 Container 時都是動態分配 Subnet 與 Default Gateway,這樣讓我們設定上會有困難
自建一組網路給 Container 使用
可以透過 Docker network create 來預先建立一組規範好的網路,並讓 Container 起起來的時候指定吃這組設定
1 | $ docker network create --driver nat --gateway 172.17.0.1 --subnet 172.17.0.0/20 mynetwork |
1 | $ docker run -it --rm --network mynetwork mycontainer:latest |
檢視 Container 起來後網路設定狀況,可以看到 Default Gateway 已經被定下來了
接著執行
1 | $ route -p add 169.254.169.254 172.17.0.1 |
至於 route add 怎麼在 Container 起起來時自動執行那就是另一個課題了,這邊不討論
Docker compose 動態建網路給 Container 使用
第二種方法是透過 Docker compose 執行時動態建立一組網路來使用,方法大同小異,只是透過 Docker Compose 來設定而已
1 | version: '2.1' |
結語
最近跟著架構師還有一群很厲害的同事做新的專案,發現自己對於 Infra 與網路的知識真的相當不足,所以在Docker 一些設定與建置上常常卡的亂七八糟,也趁著這個機會把以前一堆已經還老師的知識又惡補了一翻,希望能越來越順利