前幾天有個朋友詢問他們的 Amazon EKS Pod 在存取 IMDS (EC2 Instance Metadata Service) 時非常的慢,有時要 4s 甚至跑到 timeout 根本就是無法使用的情況,稍微記錄一下處理過程。
IMDS 能夠提供 Amazon EC2 所有環境的基礎訊息,例如:Instance-Id、AMI、Region 等等狀態。對於需要處理一些系統狀態時非常好用,不過 IMDS 的位置是基於 APIPA (Automatic Private IP Addressing) 的 169.254.169.254 位置,所以通常不太會遇到效能上的問題,小弟在聽到這個狀況時也是瞬間一頭霧水
首先先釐清異常情境的一些資訊:
curl http://169.254.169.254
在 Worker node 內訪問速度正常- 異常情境在 Pod 內使用 boto3 V2 以上版本訪問 IMDSv2
由此可以得知問題僅發生在 Pod-level 以及 IMDSv2 版本上,然後找了一下有關 IMDS 文件,最後在「Amazon EKS now supports EC2 Instance Metadata Service v2」找到了端倪:
By default, the response to PUT requests has a response hop limit (time to live) of 1 at the IP protocol level. However, this limit is incompatible with containerized applications on Kubernetes that run in a separate network namespace from the instance.
Now, newly launched and any updated EKS managed node groups will be configured with a metadata token response hop limit set to 2.
這段內容關鍵的提到在使用 IMDSv2 時必須用 PUT
拿到 token
,基於網路安全性將 network hop 限制在 1 hop 避免 token
外流,但是在 Kubernetes 的網路設計中 Pod
要訪問 IMDSv2 需要經過多個虛擬網卡轉譯至少需要 hop 2 以上才能到達,所以 hop 上限至少也要 2 以上,這個在 Amazon EKS Managed node group 預設就是採用 hop 2,但是對於 Self-managed node 除非是用 eksctl 就要自己設定 hop 2。
如何設定 hop limit?
預設情況下所有的 EC2 instance 應該都是 hop 1,可以透過 awscli 查詢:
$ aws ec2 describe-instances --instance-id i-0c48d5aac6576a19f | grep HttpPutResponseHopLimit
"HttpPutResponseHopLimit": 1,
已經存在並且在運行的 EC2 Worker node 可以用 awscli 修改:
$ aws ec2 modify-instance-metadata-options \
--instance-id i-0c48d5aac6576a19f \
--http-tokens required \
--http-endpoint enabled \
--http-put-response-hop-limit 2
但是多數情況下我們會用 Auto Scaling Group 來建立 Self-managed node,hop limit 可以在 Launch template 內找到設定 Metadata response hot limit
參數:
ASG 套用新版本後,再次從 Pod 訪問 IMDSv2 就恢復啦!
從上述來看,問題出在於 IMDSv2 對於 network hop 的限制,如果不是從 Host (e.g. Amazon EC2) 直接 1 hop 就到達就需要調整,這篇文章發生於 Amazon EKS 所以同理在 Docker Container、Amazon ECS Task 也都會遇到相同的狀況。