亚马逊AWS官方博客

中国区通过CDK安装EKS Helm Chart 常见错误及解决方案

1. 简介

本文介绍了如何解决在中国区通过CDK内置方法安装EKS Helm Chart失败的问题。经过总结,安装失败主要是由于AWS中国区网络问题无法访问到相应的Repository,具体分为以下两种情况:

  • Helm Chart Repository无法访问
  • Helm Chart 所依赖的特定Image无法访问

本文会对这两种情况具体给出几种解决方案,需要注意的是本文所采用的CDK版本为2.27.0,在不同版本下具体操作步骤会有些许区别

1. 1 关于 Helm Chart

Helm 是一款当下流行的基于Kubernetes的应用包管理工具。开发者按照Helm Chart的格式,将应用所需的资源文件包装起来,通过模版化的方式将一些可变字段暴露给用户,最后将封装好的应用包,也就是Helm Chart,集中存放在统一的仓库中供用户浏览下载。用户只需要一行简单的命令就可以完成应用的安装、卸载与升级。对于安装之后状态,也可以通过 helm list 或者是原生的 kubectl 进行查询。

1. 2 CDK安装Helm Chart原理

AWS CDK提供了内置方法给EKS Cluster安装Helm Chart,aws_cdk.aws_eks.Cluster.add_helm_chart。实现方法是通过部署一个预定义好的Lambda函数,通过 helm upgrade 命令以及用户输入的参数,安装指定Helm Chart。但是如果Helm Chart的配置中包含特定域名的Repository则会安装失败,例如gcr.io。

2. Helm Chart Repository 无法访问解决方案

这里以通过CDK安装“aws-efs-csi-driver”Helm Chart为例,以下代码在Global Region测试通过

awsefscsi_chart = eks_cluster.add_helm_chart(
    "aws-efs-csi-driver",
    chart="aws-efs-csi-driver",
    version="2.2.5",
    release="awsefscsidriver",
    repository="https://kubernetes-sigs.github.io/aws-efs-csi-driver/",
    namespace="xxx",
    values={
    },
)

在中国区运行 cdk deploy 出现以下报错信息,可以确认为无法访问Helm Chart的应用包

下午6:21:22 | CREATE_FAILED        | Custom::AWSCDK-EKS-HelmChart          | clusterchartawsefscsidriverFB9E01B8
Received response status [FAILED] from custom resource. Message returned: Error: b'Release "awsefscsidriver" does not exist. Installing it now.\nE
rror: failed to download "https://github.com/kubernetes-sigs/aws-efs-csi-driver/releases/download/helm-chart-aws-efs-csi-driver-2.2.5/aws-efs-csi-driver-2.2.5.tgz" at version "2.2.5" (hint: running helm repo update may help)\n'

2. 1 下载Helm Chart到本地,通过CDK内置方式上传

可以通过浏览器访问指定Repository,或者通过 helm pull 命令,下载相应Helm Chart到本地,将.tgz文件解压缩或者打包成.zip文件。需要注意通过VPN访问外网,或者通过Global Region的Cloud9来进行操作,这里不做赘述。

在CDK中import Helm Chart目录为Asset,然后在 add_helm_chart 中添加 chart_asset 参数,并且注释掉chart,version,repository参数,即可正常安装本地Helm Chart,同样以“aws-efs-csi-driver”为例

import aws_cdk.aws_s3_assets as s3_assets

chart_asset = s3_assets.Asset(
    self, 
    "aws-efs-csi-driver",
    path='./aws-efs-csi-driver/'
)
efscsi_chart = eks_cluster.add_helm_chart(
    "aws-efs-csi-driver",
    #chart="aws-efs-csi-driver",
    #version="2.2.5",
    release="awsefscsidriver",
    #repository="https://kubernetes-sigs.github.io/aws-efs-csi-driver/",
    chart_asset=chart_asset,
    namespace="xxx",
    values={
   },
)

2. 2 手动Pull & Push Helm Chart到中国区ECR

首先本地安装Helm 3.5.4,需注意CDK 2.27.0自带的Helm版本为3.5.4,因此本地不能用超过3.7版本的 helm push 否则安装会失败。通过以下命令安装指定版本的Helm

curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/getchmod +x get_helm.sh
./get_helm.sh -v v3.5.4

按照2. 1中的方法下载Helm Chart到本地,再通过以下命令push到ECR

aws ecr create-repository --repository-name <chart_name>

aws ecr get-login-password \
    --region cn-north-1 | helm registry login \
    --username AWS \
    --password-stdin <account_id>.dkr.ecr.cn-north-1.amazonaws.com.cn

helm chart save <chart_name>.tgz <account_id>.dkr.ecr.cn-north-1.amazonaws.com.cn/<chart_name>:<version>
helm chart push <account_id>.dkr.ecr.cn-north-1.amazonaws.com.cn/<chart_name>:<version> 

查看push结果,注意”imageManifestMediaType”和”artifactMediaType”两个字段。

aws ecr describe-images —repository-name <chart_name>

{
    "imageDetails": [
        {
            "registryId": "",
            "repositoryName": <chart_name>,
            "imageDigest": "",
            "imageTags": [
                <version>
            ],
            "imageSizeInBytes": ,
            "imagePushedAt": "",
            "imageManifestMediaType": "application/vnd.oci.image.manifest.v1+json",
            "artifactMediaType": "application/vnd.cncf.helm.config.v1+json"
        }
    ]
}

若Helm版本高于3.7,则可以通过官方文档所写步骤push Helm Chart到ECR
https://docs.aws.amazon.com/zh_cn/AmazonECR/latest/userguide/push-oci-artifact.html

成功push到ECR之后,CDK中add_helm_chart方法,将repository参数替换为ECR Image URI。

awsefscsi_chart = eks_cluster.add_helm_chart(
    "aws-efs-csi-driver",
    chart="aws-efs-csi-driver",
    version="2.2.5",
    release="awsefscsidriver",
    repository="<account_id>.dkr.ecr.cn-north-1.amazonaws.com.cn/aws-efs-csi-driver",
    namespace="xxx",
    values={
    },
)

由于cdk 2.27.0版本不支持中国区ECR地址解析,还需要手动修改Lambda代码才能正常跑通,新版本可能会做相应适配,即可省去这个步骤。

具体操作为先执行 cdk synth
找到以下路径文件 cdk.out/asset.<random string>/helm/__init__.py
并将其中的“amazonaws.com”替换为“amazonaws.com.cn“,再执行 cdk deploy 即可。

2. 3 手动Pull & Push Helm Chart到Global Public ECR

操作同2. 2类似,语法稍有修改

aws ecr-public create-repository --repository-name <chart_name>
aws ecr-public get-login-password \
     --region us-east-1 | helm registry login \
     --username AWS \
     --password-stdin public.ecr.aws
     
helm chart save <chart_name>.tgz public.ecr.aws/<random_string>/<chart_name>:<version>
helm chart push public.ecr.aws/<random_string>/<chart_name>:<version>

且cdk代码也需要做相应修改

执行 cdk synth
找到以下路径文件cdk.out/asset.<random string>/helm/__init__.py

line 111: cmnd = ['HELM_EXPERIMENTAL_OCI=1', 'helm', 'pull', repository, '—version', version, '—untar']
line 126: output = subprocess.check_output(cmnd, stderr=subprocess.STDOUT, cwd=tmpdir, env=env, shell=True)

2. 4 总结

由于CDK代码对中国区适配不佳,方法2. 2与2. 3略显复杂,建议采用2. 1作为解决方案,但2. 1的弊端在于无法对Helm Chart做版本管理,未来可根据CDK的更新内容采用不同解决方案。

3. Helm Chart 所依赖的特定Image无法访问解决方案

这里以通过CDK安装“jupyter-hub” Helm Chart为例,以下代码在Global Region测试通过

jupyterhub_chart = eks_cluster.add_helm_chart(
    "jupyterhub-chart",
    chart="jupyterhub",
    version="1.2.0",
    release="jupyterhub",
    repository="https://jupyterhub.github.io/helm-chart",
    create_namespace=True,
    namespace="jupyter-hub",
    values=k8s_values,
)

在中国区运行 cdk deploy 出现以下报错信息,可以确认为无法访问Helm Chart所依赖的Image

下午9:59:34 | CREATE_FAILED        | Custom::AWSCDK-EKS-HelmChart          | addftestjupyrerhub...erhubchart8C4E93E9
Received response status [FAILED] from custom resource. Message returned: Error: b'Release "jupyterhub" does not exist. Installing it now.\nError:
failed pre-install: timed out waiting for the condition\n'

本地连接EKS Cluster

aws sts assume-role —role-arn arn:aws-cn:iam::<account-id>:role/<eks-cluster-master-role> —role-session-name aws-auth-ops | jq -r ‘.Credentials | "export AWS_ACCESS_KEY_ID=\(.AccessKeyId)\nexport AWS_SECRET_ACCESS_KEY=\(.SecretAccessKey)\nexport AWS_SESSION_TOKEN=\(.SessionToken)\n"'

export AWS_ACCESS_KEY_ID=<access-key>
export AWS_SECRET_ACCESS_KEY=<secret-key>
export AWS_SESSION_TOKEN=<session-token>

aws eks update-kubeconfig --name <eks-cluster-name>

运行以下指令查看EKS log,定位具体是哪个Image执行pull的时候失败

kubectl -n jupyter-hub get events --sort-by='{.lastTimestamp}'

可以找到报错信息如下

60m         Warning   Failed             pod/hook-image-puller-qxcpj    Failed to pull image "k8s.gcr.io/pause:3.5": rpc error: code = Unknown desc = Error response from daemon: Get "https://k8s.gcr.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)

可以采取手动的方式,或者根据这篇博客提供的方法,将相应Image批量上传到中国区ECR
https://aws.amazon.com/cn/blogs/china/convenient-and-safe-use-of-overseas-public-container-images-in-aws-china/
并根据Helm Chart values的schema将Image地址做替换

具体操作为,在Helm Chart目录下values.yaml文件中,找到下载失败的Image位置,本文案例中为”k8s.gcr.io/pause:3.5

prePuller:            
  pause:           
  image:
    name: k8s.gcr.io/pause
    tag: "3.5"

在CDK的add_helm_chart中根据values的schema添加values参数,替换掉相应Image地址,即可正常执行 cdk deploy

chart = eks_cluster.add_helm_chart(
    "jupyterhub-chart",
    chart="jupyterhub",
    version="1.2.0",
    release="jupyterhub",
    repository="https://jupyterhub.github.io/helm-chart",
    create_namespace=True,
    namespace="jupyter-hub",
     values={
        "prePuller": {
            "pause": {
                "image": {
                    "name": "<account-id>.dkr.ecr.cn-north-1.amazonaws.com.cn/pause"
                }
            }
        },
    },
)

4. 总结

目前CDK对于在中国区安装EKS Helm Chart支持尚不完善,通过本文,你可以了解一些解决方案,来实现通过CDK部署相应Helm Chart。

参考资料:

CDK Python Document – https://docs.aws.amazon.com/cdk/api/v1/python/

Helm Command Document – https://helm.sh/docs/helm/

在 AWS 中国区方便安全的使用海外公开容器镜像 – https://aws.amazon.com/cn/blogs/china/convenient-and-safe-use-of-overseas-public-container-images-in-aws-china/

Push Helm Chart to ECR – https://docs.aws.amazon.com/zh_cn/AmazonECR/latest/userguide/push-oci-artifact.html

本篇作者

熊远

AWS专业服务团队大数据工程师。在企业数据仓库、大数据解决方案架构、数据湖以及机器学习算法开发拥有扎实经验,深度参与过零售快消、医疗器械、能源工业等行业的 数据平台建设与机器学习应用搭建。

王帅

AWS专业服务团队Devops顾问。提倡融合文化,实践和工具的Devops理念,致力于帮助客户使组织能够以更高的速度和可靠性交付产品并获得业务价值。擅长平台规划,迁移和工具链设计。对新鲜事物充满热情