You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CDK时,如何等待Helm安装的Operator就绪后再应用清单?

EKS部署ESO与Pinot时CDK提前创建SecretStore导致失败的解决方案

问题场景

使用CDK将External Secrets Operator(ESO)与Apache Pinot部署到EKS集群时,CDK会在ESO完全启动运行前尝试创建SecretStore资源,导致部署失败。手动分两次部署(先部署ESO和Pinot,再部署SecretStore)可正常运行。

相关代码

// install Pinot
const pinot = cluster.addHelmChart('Pinot', {
    chartAsset: new Asset(this, 'PinotChartAsset', { path: path.join(__dirname, '../pinot') }),
    release: 'pinot',
    namespace: 'pinot',
    createNamespace: true
});


// install the External Secrets Operator
const externalSecretsOperator = cluster.addHelmChart('ExternalSecretsOperator', {
    chart: 'external-secrets',
    release: 'external-secrets',
    repository: 'https://charts.external-secrets.io',
    namespace: 'external-secrets',
    createNamespace: true,
    values: {
        installCRDs: true,
        webhook: {
            port: 9443
        }
    }
});


// create a Fargate Profile
const fargateProfile = cluster.addFargateProfile('FargateProfile', {
    fargateProfileName: 'externalsecrets',
    selectors: [{ 'namespace': 'external-secrets' }]
});


// create the Service Account used by the Secret Store
const serviceAccount = cluster.addServiceAccount('ServiceAccount', {
    name: 'eso-service-account',
    namespace: 'external-secrets'
});
serviceAccount.addToPrincipalPolicy(new iam.PolicyStatement({
    effect: iam.Effect.ALLOW,
    actions: [
        'secretsmanager:GetSecretValue',
        'secretsmanager:DescribeSecret'
    ],
    resources: [
        'arn:aws:secretsmanager:us-east-1:<MY-ACCOUNT-ID>:secret:*'
    ]
}))
serviceAccount.node.addDependency(externalSecretsOperator);


// create the Secret Store, an ESO Resource
const secretStoreManifest = getSecretStoreManifest(serviceAccount);
const secretStore = cluster.addManifest('SecretStore', secretStoreManifest);
secretStore.node.addDependency(serviceAccount);
secretStore.node.addDependency(fargateProfile);


// create the External Secret, another ESO resource
const externalSecretManifest = getExternalSecretManifest(secretStoreManifest)
const externalSecret = cluster.addManifest('ExternalSecret', externalSecretManifest)
externalSecret.node.addDependency(secretStore);
externalSecret.node.addDependency(pinot);

部署错误信息

Received response status [FAILED] from custom resource. Message returned: Error: b'Error from server (InternalError): error when creating "/tmp/manifest.yaml": Internal error occurred:
failed calling webhook "validate.clustersecretstore.external-secrets.io": Post "https://external-secrets-webhook.external-secrets.svc:443/validate-external-secrets-io-v1beta1-clustersecretstore?timeout=5s": no endpoints available for service "external-secrets-webhook"
'

解决方案

1. 用Kubernetes Job等待ESO Webhook就绪

创建一个Job,持续检查ESO的webhook服务是否有可用端点,直到就绪后再继续部署SecretStore。

在CDK中添加这个Job的manifest,并让SecretStore依赖该Job:

// 创建等待ESO就绪的Job
const waitForEsoJob = cluster.addManifest('WaitForEsoWebhook', {
  apiVersion: 'batch/v1',
  kind: 'Job',
  metadata: {
    name: 'wait-for-eso-webhook',
    namespace: 'external-secrets'
  },
  spec: {
    template: {
      spec: {
        containers: [
          {
            name: 'wait-for-webhook',
            image: 'bitnami/kubectl:latest',
            command: [
              'sh', '-c',
              'until kubectl get endpoints external-secrets-webhook -n external-secrets | grep -E \'READY.*[1-9]\'; do sleep 5; done'
            ]
          }
        ],
        restartPolicy: 'OnFailure'
      }
    },
    backoffLimit: 10
  }
});

// 让SecretStore依赖这个Job
waitForEsoJob.node.addDependency(externalSecretsOperator);
secretStore.node.addDependency(waitForEsoJob);

2. 拆分CDK栈

将ESO、Pinot和Fargate Profile部署到基础栈,将ServiceAccount、SecretStore和ExternalSecret部署到依赖栈。通过CDK的栈依赖机制,确保基础栈完全部署完成后再部署依赖栈。

示例:

  • 基础栈(EsoPinotStack):包含ESO Helm Chart、Pinot Helm Chart、Fargate Profile
  • 依赖栈(EsoSecretsStack):包含ServiceAccount、SecretStore、ExternalSecret,且依赖EsoPinotStack

3. 自定义CDK等待资源

编写一个Lambda函数,用于检查ESO的Pod和webhook服务状态,直到就绪。将这个Lambda包装成CDK自定义资源,让SecretStore依赖该资源。

核心逻辑示例(Lambda代码):

import boto3
import subprocess
import time

eks_client = boto3.client('eks')

def lambda_handler(event, context):
    cluster_name = event['ClusterName']
    # 获取kubeconfig
    eks_client.update_kubeconfig(name=cluster_name)
    
    # 等待ESO Pod就绪
    while True:
        result = subprocess.run(['kubectl', 'get', 'pods', '-n', 'external-secrets', '-l', 'app.kubernetes.io/name=external-secrets'], capture_output=True, text=True)
        if 'Running' in result.stdout and '1/1' in result.stdout:
            break
        time.sleep(5)
    
    # 等待webhook端点就绪
    while True:
        result = subprocess.run(['kubectl', 'get', 'endpoints', 'external-secrets-webhook', '-n', 'external-secrets'], capture_output=True, text=True)
        if 'READY' in result.stdout and any(c.isdigit() and int(c) > 0 for c in result.stdout.split() if c.isdigit()):
            break
        time.sleep(5)
    
    return {'status': 'ready'}

在CDK中创建自定义资源,并让SecretStore依赖它。


内容的提问来源于stack exchange,提问作者James Kelleher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 04:15:41