ECS(EC2启动类型)Docker容器获取实例元数据报错如何解决?
问题原因
该JSON解析报错本质是请求实例元数据服务(IMDS)后返回的响应为空或非JSON格式,触发的直接原因通常有三类:
- 最常见的是EC2实例启用了IMDSv2且配置的响应跳数限制为1:Docker默认bridge网络模式下,容器访问宿主机IMDS服务需要经过1次网络转发,跳数刚好超出限制,IMDS会直接丢弃请求返回空响应,直接调用
x.json()就会抛出解析失败异常。同集群其他容器正常大概率是因为那些容器使用了host网络模式,不需要经过网络转发,跳数不会超出限制。 - 其次可能是出问题的容器缺少访问IMDS的权限:比如容器对应的ECS任务定义中配置了禁用元数据访问的参数,或者容器内部/宿主机的iptables规则拦截了到
169.254.169.254的请求。 - 代码本身缺少响应合法性校验:没有判断响应状态码是否为200就直接解析JSON,只要响应不符合JSON格式就会触发报错。
修复方案
可以根据实际场景选择对应方案:
- 调整EC2实例的IMDSv2跳数限制,执行命令
aws ec2 modify-instance-metadata-options --instance-id <你的实例ID> --http-put-response-hop-limit 2 --http-endpoint enabled,将跳数调整为2适配bridge网络的容器访问。 - 修改ECS任务定义,将出问题的容器网络模式改为host模式,和正常运行的容器配置保持一致。
- 优化代码兼容IMDSv2同时增加响应校验,参考实现如下:
import requests import logging def get_aws_account_id(): try: # 先获取IMDSv2的访问token token_url = 'http://169.254.169.254/latest/api/token' token_headers = {'X-aws-ec2-metadata-token-ttl-seconds': '21600'} token = requests.put(token_url, headers=token_headers, timeout=10).text # 携带token请求IAM元数据 url = 'http://169.254.169.254/latest/meta-data/iam/info/' headers = {'X-aws-ec2-metadata-token': token} x = requests.get(url, headers=headers, timeout=10) # 先校验状态码再解析JSON if x.status_code == 200: data = x.json() return data['InstanceProfileArn'].split(':')[4] else: logging.error(f"请求元数据失败,状态码:{x.status_code},响应内容:{x.text}") return None except Exception as e: logging.error(f"exception ==> {e}") return None
内容的提问来源于stack exchange,提问作者ca9163d9
相关产品推荐
相关产品推荐

