ALIYUN::CS::ClusterApplication

ALIYUN::CS::ClusterApplication类型用于容器应用部署。

语法

{
  "Type": "ALIYUN::CS::ClusterApplication",
  "Properties": {
    "YamlContent": String,
    "ClusterId": String,
    "DefaultNamespace": String,
    "RolePolicy": String,
    "Stage": String,
    "WaitUntil": List,
    "ValidationMode": String,
    "CreationMode": String,
    "DefaultNamespaceDeletion": Boolean
  }
}

属性

属性名称

类型

必须

允许更新

描述

约束

ClusterId

String

集群ID。

YamlContent

String

部署应用的YAML模板内容。

DefaultNamespace

String

应用程序的默认命名空间。

RolePolicy

String

角色策略。

在部署应用程序之前,请检查与当前用户角色关联的策略。

取值:

  • EnsureAdminRoleAndBinding(默认值):自动创建一个名为ros:application-admin:${user-id}\的角色,具有管理员权限,并将其绑定到当前用户。

  • None:不执行任何操作。 

Stage

String

运行阶段。 

取值:

  • All(默认值):所有阶段,包括创建、更新和删除。 

  • Delete:删除阶段。这意味着只有在该资源的删除阶段才会将YAML应用到集群。 

ValidationMode

String

验证模式。

取值:

  • Basic:基本验证,例如验证集群是否存在。

  • Strict:除了基本验证外,还验证WaitUntil的合法性。 

WaitUntil

List

开始创建或更新后,等待直到满足所有条件。 

更多信息,请参见WaitUntil属性

CreationMode

String

创建模式。

取值:

  • Normal:创建新资源,如果资源已存在则报错。

  • Apply:类似于 kubectl apply 的行为,若资源不存在则创建,若存在则更新。在删除阶段,ROS 会删除新创建的应用程序,但不会删除已更新的现有应用程序。

DefaultNamespaceDeletion

Boolean

是否删除由 DefaultNamespace 指定的命名空间。

如果 DefaultNamespace 属于 ('default', 'kube-node-lease', 'kube-public', 'kube-system', 'arms-prom'),无论 DefaultNamespaceDeletion 是否为 true,这些命名空间都不会被删除。

WaitUntil语法

"WaitUntil": [
  {
   "ApiVersion": String,
   "FirstMatch": Boolean,
   "Timeout": Integer,
   "JsonPath": String,
   "Namespace": String,
   "Stage": String,
   "Name": String,
   "ValueType": String,
   "Kind": String,
   "Value": String,
   "Operator": String
  }
]

WaitUntil属性

属性名称

类型

必须

允许更新

描述

约束

ApiVersion

String

API版本。

Kind

String

要查询的Kubernetes资源类型。

Name

String

要查询的Kubernetes资源名称。

Operator

String

将值与JsonPath表达式的结果进行比较的操作符。 

FirstMatch

Boolean

只返回JsonPath过滤结果中的第一个匹配结果。 

取值:

  • true

  • false(默认值)

JsonPath

String

Json路径表达式来过滤输出。

Namespace

String

资源所在的kubernetes的命名空间。

默认值为DefaultNamespace。 

Stage

String

在什么阶段等待。  

取值:

  • Create/Update(默认值):创建和更新阶段。

  • Delete:删除阶段。 

Timeout

Integer

等待满足条件的超时时间。

单位为秒。

Value

String

要与JsonPath表达式的结果进行比较的值。 

ValueType

String

值的类型。

默认值为String。

返回值

Fn::GetAtt

  • ClusterId:集群ID。

  • WaitUntilData:WaitUntil中每个JsonPath的值列表。 

示例

场景 1 :为容器部署应用

ROSTemplateFormatVersion: '2015-09-01'
Parameters:
  ClusterId:
    Type: String
    Description: The ID of the kubernetes cluster.
    AssociationProperty: ALIYUN::CS::Cluster::ClusterId
Resources:
  ClusterApplication:
    Type: ALIYUN::CS::ClusterApplication
    Properties:
      YamlContent: |-
        apiVersion: storage.k8s.io/v1
        kind: StorageClass
        metadata:
          name: test-ut-storage
          annotations:
            storageclass.beta.kubernetes.io/is-default-class: "true"
            storageclass.kubernetes.io/is-default-class: "true"
        mountOptions:
        - nolock,tcp,noresvport
        - vers=3
        parameters:
          server:  1.1.1.1
          driver: flexvolume
        provisioner: alicloud/nas
        reclaimPolicy: Delete

        ---

        apiVersion: v1
        kind: ConfigMap
        metadata:
          name: test-ut-configmap
        data:
          k1: v1
          k2: v2
      ClusterId:
        Ref: ClusterId
Outputs:
  ClusterId:
    Description: The ID of the cluster.
    Value:
      Fn::GetAtt:
        - ClusterApplication
        - ClusterId
{
  "ROSTemplateFormatVersion": "2015-09-01",
  "Parameters": {
    "ClusterId": {
      "Type": "String",
      "AssociationProperty":"ALIYUN::CS::Cluster::ClusterId",
      "Description": "The ID of the kubernetes cluster."
    }
  },
  "Resources": {
    "ClusterApplication": {
      "Type": "ALIYUN::CS::ClusterApplication",
      "Properties": {
        "YamlContent": "apiVersion: storage.k8s.io/v1\nkind: StorageClass\nmetadata:\n  name: test-ut-storage\n  annotations:\n    storageclass.beta.kubernetes.io/is-default-class: \"true\"\n    storageclass.kubernetes.io/is-default-class: \"true\"\nmountOptions:\n- nolock,tcp,noresvport\n- vers=3\nparameters:\n  server:  1.1.1.1\n  driver: flexvolume\nprovisioner: alicloud/nas\nreclaimPolicy: Delete\n\n---\n\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: test-ut-configmap\ndata:\n  k1: v1\n  k2: v2",
        "ClusterId": {
          "Ref": "ClusterId"
        }
      }
    }
  },
  "Outputs": {
    "ClusterId": {
      "Description": "The ID of the cluster.",
      "Value": {
        "Fn::GetAtt": [
          "ClusterApplication",
          "ClusterId"
        ]
      }
    }
  }
}

场景 2 :创建托管Kubernetes集,并为容器部署应用

ROSTemplateFormatVersion: '2015-09-01'
Description:
  zh-cn: 创建托管Kubernetes集群,配置VPC、节点池、HPA及日志服务,实现容器应用的自动伸缩与监控。
  en: Create a managed Kubernetes cluster, configure Virtual Private Cloud (VPC),
    node pools, Horizontal Pod Autoscaler (HPA), and logging services to enable automatic
    scaling and monitoring of containerized applications.
Parameters:
  CommonName:
    Type: String
    Default:  k8s-hpa-cluster
  SlsProjectName:
    Type: String
    Label:
      en: Name of sls project
      zh-cn: 日志项目的名称
    Description:
      en: The name contains 3 to 36 characters. It must start and end with a lowercase letter or number. The value can contain lowercase letters, digits, and hyphens (-).
      zh-cn: 长度为3~36个字符。必须以小写英文字母或数字开头和结尾。可包含小写英文字母、数字和短划线(-)。
    AssociationProperty: AutoCompleteInput
    AssociationPropertyMetadata:
      Length: 5
      Prefix: k8s-hpa-sls-project-
      CharacterClasses:
        - Class: lowercase
          min: 1
  ManagedKubernetesClusterName:
    Type: String
    Label:
      en: Managed Kubernetes Cluster Name
      zh-cn: ACK托管版集群名称
    AssociationProperty: AutoCompleteInput
    AssociationPropertyMetadata:
      Length: 5
      Prefix: k8s-hpa-cluster-
      CharacterClasses:
        - Class: lowercase
          min: 1
  ZoneId1:
    Type: String
    AssociationProperty: 'ALIYUN::ECS::Instance::ZoneId'
    AssociationPropertyMetadata:
      ExclusiveTo:
        - ZoneId2
    Label:
      en: Availability Zone
      zh-cn: 可用区1
  ZoneId2:
    Type: String
    AssociationProperty: 'ALIYUN::ECS::Instance::ZoneId'
    AssociationPropertyMetadata:
      ExclusiveTo:
        - ZoneId1
    Label:
      en: Availability Zone
      zh-cn: 可用区2
  InstanceType:
    Type: CommaDelimitedList
    AssociationProperty: 'ALIYUN::ECS::Instance::InstanceType'
    AssociationPropertyMetadata:
      InstanceChargeType: PostPaid
      SystemDiskCategory: cloud_essd
      CreateACKClusterParams:
        NetworkPlugin: terway-eniip
    Label:
      en: Instance Type
      zh-cn: 实例规格
  InstancePassword:
    NoEcho: true
    Type: String
    Description:
      en: >-
        Server login password, Length 8-30, must contain three(Capital letters,
        lowercase letters, numbers, ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ Special
        symbol in)
      zh-cn: >-
        服务器登录密码,长度8-30,必须包含三项(大写字母、小写字母、数字、 ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/
        中的特殊符号)
    Label:
      en: Instance Password
      zh-cn: 实例密码
    ConstraintDescription:
      en: >-
        Length 8-30, must contain three(Capital letters, lowercase letters,
        numbers, ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ Special symbol in)
      zh-cn: '长度8-30,必须包含三项(大写字母、小写字母、数字、 ()`~!@#$%^&*_-+=|{}[]:;''<>,.?/ 中的特殊符号)'
    AssociationProperty: 'ALIYUN::ECS::Instance::Password'
    Default: null
Resources:
  Vpc:
    Type: 'ALIYUN::ECS::VPC'
    Properties:
      CidrBlock: 10.0.0.0/8
      VpcName:
        Fn::Sub: ${CommonName}-vpc
  VSwitch1:
    Type: 'ALIYUN::ECS::VSwitch'
    Properties:
      VpcId:
        Ref: Vpc
      CidrBlock: 10.0.0.0/24
      ZoneId:
        Ref: ZoneId1
      VSwitchName:
        Fn::Sub: ${CommonName}-vsw
  VSwitch2:
    Type: 'ALIYUN::ECS::VSwitch'
    Properties:
      VpcId:
        Ref: Vpc
      CidrBlock: 10.0.1.0/24
      ZoneId:
        Ref: ZoneId2
      VSwitchName:
        Fn::Sub: ${CommonName}-vsw
  SecurityGroup:
    Type: 'ALIYUN::ECS::SecurityGroup'
    Properties:
      VpcId:
        Ref: Vpc
      SecurityGroupName:
        Fn::Sub: ${CommonName}-sg
      SecurityGroupIngress:
        - PortRange: 443/443
          SourceCidrIp: 0.0.0.0/0
          IpProtocol: tcp
        - PortRange: 80/80
          SourceCidrIp: 0.0.0.0/0
          IpProtocol: tcp
  SlsProject:
    Type: 'ALIYUN::SLS::Project'
    Properties:
      Name:
        Ref: SlsProjectName
  AliyunCSManagedAutoScalerRole:
    Type: 'ALIYUN::RAM::Role'
    Properties:
      RoleName: AliyunCSManagedAutoScalerRole
      Description: CS使用此角色来访问您在其他云产品中的资源。
      AssumeRolePolicyDocument:
        Version: '1'
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service:
                - cs.aliyuncs.com
      MaxSessionDuration: 3600
      IgnoreExisting: true
      DeletionForce: true
      PolicyAttachments:
        System:
          - AliyunCSManagedAutoScalerRolePolicy
  AckCluster:
    Type: 'ALIYUN::CS::ManagedKubernetesCluster'
    DependsOn: AliyunCSManagedAutoScalerRole
    Properties:
      VpcId:
        Ref: Vpc
      VSwitchIds:
        - Ref: VSwitch1
        - Ref: VSwitch2
      PodVswitchIds:
        - Ref: VSwitch1
        - Ref: VSwitch1
      Name:
        Ref: ManagedKubernetesClusterName
      KubernetesVersion: 1.31.1-aliyun.1
      ServiceCidr: 192.168.0.0/16
      ClusterSpec: ack.pro.small
      LoadBalancerSpec: slb.s2.small
      IsEnterpriseSecurityGroup: true
      SnatEntry: true
      NumOfNodes: 0
      EndpointPublicAccess: true
      Platform: AliyunLinux
      Addons:
        - Name: ack-node-local-dns
        - Name: terway-eniip
          Config: '{"IPVlan":"false","NetworkPolicy":"false","ENITrunking":"false"}'
        - Name: csi-plugin
        - Name: csi-provisioner
        - Name: storage-operator
          Config: '{"CnfsOssEnable":"false","CnfsNasEnable":"false"}'
        - Name: nginx-ingress-controller
          Disabled: true
        - Name: logtail-ds
          Config: '{"IngressDashboardEnabled":"true"}'
        - Name: alb-ingress-controller
          Version: ""
          Config:
            Fn::Sub: >-
              {"albIngress":{"AddressType":"Internet","ZoneMappings":{"${ZoneId1}":["${VSwitch1}"],
              "${ZoneId2}":["${VSwitch2}"]},"CreateDefaultALBConfig":true}}
        - Name: ack-helm-manager
        - Name: arms-prometheus
      ProxyMode: ipvs
      DeleteOptions:
        - ResourceType: ALB
          DeleteMode: delete
        - ResourceType: SLB
          DeleteMode: delete
        - ResourceType: SLS_Data
          DeleteMode: delete
        - ResourceType: SLS_ControlPlane
          DeleteMode: delete
        - ResourceType: PrivateZone
          DeleteMode: delete
  NodePools:
    Type: 'ALIYUN::CS::ClusterNodePool'
    Properties:
      ClusterId:
        Ref: AckCluster
      NodePoolInfo:
          Name: k8s-hpa-cluster-nodepool
      ScalingGroup:
        VSwitchIds:
          - Ref: VSwitch1
          - Ref: VSwitch2
        ZoneIds:
          - Ref: ZoneId1
          - Ref: ZoneId2
        SystemDiskCategory: cloud_essd
        SystemDiskPerformanceLevel: PL0
        SystemDiskSize: 40
        InstanceTypes:
          Ref: InstanceType
        LoginPassword:
          Ref: InstancePassword
        Platform: AliyunLinux
        ImageId: aliyun_3_9_x64_20G_alibase_20231219.vhd
      KubernetesConfig:
        Runtime: containerd
        RuntimeVersion: 1.6.28
      AutoScaling:
        Enable: true
        MinInstances: 2
        MaxInstances: 10
  Sleep:
    Type: 'ALIYUN::ROS::Sleep'
    DependsOn: NodePools
    Properties:
      CreateDuration: 300
  AckMetricsAdapter:
    Type: 'ALIYUN::CS::ClusterHelmApplication'
    DependsOn: Sleep
    Properties:
      Namespace: kube-system
      ChartUrl: 'https://aliacs-app-catalog.oss-cn-hangzhou.aliyuncs.com/charts-incubator/ack-alibaba-cloud-metrics-adapter-1.3.3.tgz'
      ClusterId:
        Ref: AckCluster
      Name: ack-alibaba-cloud-metrics-adapter
      ChartValues:
        AlibabaCloudMetricsAdapter:
          commonLabels: ''
          replicas: 1
          resources:
            metricsAdapterDeployment:
              resources:
                limits:
                  cpu: 0.5
                  memory: 1Gi
                requests:
                  cpu: 100m
                  memory: 200Mi
            configReloader:
              resources:
                limits:
                  cpu: 20m
                  memory: 30Mi
                requests:
                  cpu: 20m
                  memory: 30Mi
          listenPort: 443
          costWeights:
            cpu: '1.0'
            memory: '0.0'
          image:
            repository: registry-cn-hangzhou-vpc.ack.aliyuncs.com/acs/alibaba-cloud-metrics-adapter-amd64
            tag: v0.2.7-f1ee5c3-aliyun
            pullPolicy: Always
          nameOverride: ''
          fullnameOverride: ''
          service:
            type: ClusterIP
          serviceAccountName: ack-alibaba-cloud-metrics-adapter
          annotations: { }
          nodeSelector: { }
          tolerations: [ ]
          env:
            - AccessKeyId: ''
            - AccessKeySecret: ''
            - Region: ''
          affinity: { }
          prometheus:
            enabled: true
            url: { }
            metricsRelistInterval: 1m
            logLevel: 5
            adapter:
              rules:
                default: false
                custom:
                  - seriesQuery: container_memory_working_set_bytes{namespace!="",pod!=""}
                    resources:
                      overrides:
                        namespace:
                          resource: namespace
                        pod:
                          resource: pod
                    name:
                      matches: ^(.*)_bytes
                      as: ${1}_bytes_per_second
                    metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>)
                  - seriesQuery: container_cpu_usage_seconds_total{namespace!="",pod!=""}
                    resources:
                      overrides:
                        namespace:
                          resource: namespace
                        pod:
                          resource: pod
                    name:
                      matches: ^(.*)_seconds_total
                      as: ${1}_core_per_second
                    metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>)
        ConfigReloader:
          image:
            repository: registry-vpc.cn-hangzhou.aliyuncs.com/acs/configmap-reload
            tag: v0.0.1
  InstallBackendApp:
    Type: 'ALIYUN::CS::ClusterApplication'
    DependsOn: AckMetricsAdapter
    Properties:
      ClusterId:
        Ref: AckCluster
      YamlContent:
        Fn::Sub: |-
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: coffee
          spec:
            replicas: 2
            selector:
              matchLabels:
                app: coffee
            template:
              metadata:
                labels:
                  app: coffee
              spec:
                containers:
                - name: coffee
                  image: registry.${ALIYUN::Region}.aliyuncs.com/acs-sample/nginxdemos:latest
                  ports:
                  - containerPort: 80
                  resources:
                    limits:
                      cpu: 500m
                      memory: 1Gi
                    requests:
                      cpu: 500m
                      memory: 512Mi
          ---
          apiVersion: v1
          kind: Service
          metadata:
            name: coffee-svc
          spec:
            ports:
            - port: 80
              targetPort: 80
              protocol: TCP
            selector:
              app: coffee
            type: NodePort
          ---
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: tea
          spec:
            replicas: 2
            selector:
              matchLabels:
                app: tea
            template:
              metadata:
                labels:
                  app: tea
              spec:
                containers:
                - name: tea
                  image: registry.${ALIYUN::Region}.aliyuncs.com/acs-sample/nginxdemos:latest
                  ports:
                  - containerPort: 80
                  resources:
                    limits:
                      cpu: 500m
                      memory: 1Gi
                    requests:
                      cpu: 500m
                      memory: 512Mi
          ---
          apiVersion: v1
          kind: Service
          metadata:
            name: tea-svc
          spec:
            ports:
            - port: 80
              targetPort: 80
              protocol: TCP
            selector:
              app: tea
            type: NodePort
  AlbConfig:
    Type: 'ALIYUN::CS::ClusterApplication'
    DependsOn: InstallBackendApp
    Properties:
      ClusterId:
        Ref: AckCluster
      YamlContent:
        Fn::Sub: |-
          apiVersion: alibabacloud.com/v1
          kind: AlbConfig
          metadata:
            name: k8s-hpa-alb-config
          spec:
            config:
              name: k8s-hpa-alb
              addressType: Internet
              zoneMappings:
              - vSwitchId: ${VSwitch1}
              - vSwitchId: ${VSwitch2}
              accessLogConfig:
                logProject: ${SlsProject}
                logStore: "alb_k8s_hpa_sls_logstore"
            listeners:
              - port: 80
                protocol: HTTP
  IngressClass:
    Type: 'ALIYUN::CS::ClusterApplication'
    DependsOn: AlbConfig
    Properties:
      ClusterId:
        Ref: AckCluster
      YamlContent:
        Fn::Sub: |-
          apiVersion: networking.k8s.io/v1
          kind: IngressClass
          metadata:
            name: k8s-hpa-alb-ingress-class
          spec:
            controller: ingress.k8s.alibabacloud/alb
            parameters:
              apiGroup: alibabacloud.com
              kind: AlbConfig
              name: k8s-hpa-alb-config
  Ingress:
    Type: 'ALIYUN::CS::ClusterApplication'
    DependsOn: IngressClass
    Properties:
      ClusterId:
        Ref: AckCluster
      YamlContent:
        Fn::Sub: |-
          apiVersion: networking.k8s.io/v1
          kind: Ingress
          metadata:
            name: k8s-hpa-alb-ingress
          spec:
            ingressClassName: k8s-hpa-alb-ingress-class
            rules:
             - http:
                paths:
                - path: /tea
                  pathType: ImplementationSpecific
                  backend:
                    service:
                      name: tea-svc
                      port:
                        number: 80
                - path: /coffee
                  pathType: ImplementationSpecific
                  backend:
                    service:
                      name: coffee-svc
                      port: 
                        number: 80
  Hpa:
    Type: 'ALIYUN::CS::ClusterApplication'
    DependsOn: WaitAlbIngress
    Properties:
      ClusterId:
        Ref: AckCluster
      YamlContent:
        Fn::Sub: |-
          apiVersion: autoscaling/v2
          kind: HorizontalPodAutoscaler
          metadata:
            name: k8s-alb-tea-hpa
          spec:
            scaleTargetRef:
              apiVersion: apps/v1
              kind: Deployment
              name: tea
            minReplicas: 2
            maxReplicas: 10
            metrics:
              - type: External
                external:
                  metric:
                    name: sls_alb_ingress_qps
                    selector:
                      matchLabels:
                        sls.project: ${SlsProject}
                        sls.logstore: "alb_k8s_hpa_sls_logstore" 
                        sls.ingress.route: "default-tea-svc-80"
                  target:
                    type: AverageValue
                    averageValue: 2
              - resource:
                  name: cpu
                  target:
                    averageUtilization: 80
                    type: Utilization
                type: Resource
              - resource:
                  name: memory
                  target:
                    averageUtilization: 80
                    type: Utilization
                type: Resource
  WaitAlbIngress:
    Type: 'ALIYUN::ROS::Sleep'
    DependsOn: Ingress
    Properties:
      CreateDuration: 120
  IngressInfo:
    Type: 'DATASOURCE::CS::ClusterApplicationResources'
    DependsOn: WaitAlbIngress
    Properties:
      ClusterId:
        Ref: AckCluster
      Kind: Ingress
      Namespace: default
      JsonPath: $.items.[0].status.loadBalancer.ingress.[0].hostname
      FirstMatch: true
Outputs:
  TeaUrl:
    Description:
      zh-cn: tea服务访问地址。
      en: The addresses of tea service.
    Value:
      'Fn::Sub': http://${IngressInfo}/tea
  CoffeeUrl:
    Description:
      zh-cn: coffee服务访问地址。
      en: The addresses of coffee service.
    Value:
      'Fn::Sub': http://${IngressInfo}/coffee
Metadata:
  'ALIYUN::ROS::Interface':
    ParameterGroups:
      - Parameters:
          - SlsProjectName
          - ManagedKubernetesClusterName
          - ZoneId1
          - ZoneId2
          - InstanceType
          - InstancePassword
    TemplateTags:
      - acs:technical-solution:micro:通过HPA实现容器应用的水平弹性伸缩-tech_solu_125
    Hidden:
      - CommonName
{
  "ROSTemplateFormatVersion": "2015-09-01",
  "Description": {
    "zh-cn": "创建托管Kubernetes集群,配置VPC、节点池、HPA及日志服务,实现容器应用的自动伸缩与监控。",
    "en": "Create a managed Kubernetes cluster, configure Virtual Private Cloud (VPC), node pools, Horizontal Pod Autoscaler (HPA), and logging services to enable automatic scaling and monitoring of containerized applications."
  },
  "Parameters": {
    "CommonName": {
      "Type": "String",
      "Default": "k8s-hpa-cluster"
    },
    "SlsProjectName": {
      "Type": "String",
      "Label": {
        "en": "Name of sls project",
        "zh-cn": "日志项目的名称"
      },
      "Description": {
        "en": "The name contains 3 to 36 characters. It must start and end with a lowercase letter or number. The value can contain lowercase letters, digits, and hyphens (-).",
        "zh-cn": "长度为3~36个字符。必须以小写英文字母或数字开头和结尾。可包含小写英文字母、数字和短划线(-)。"
      },
      "AssociationProperty": "AutoCompleteInput",
      "AssociationPropertyMetadata": {
        "Length": 5,
        "Prefix": "k8s-hpa-sls-project-",
        "CharacterClasses": [
          {
            "Class": "lowercase",
            "min": 1
          }
        ]
      }
    },
    "ManagedKubernetesClusterName": {
      "Type": "String",
      "Label": {
        "en": "Managed Kubernetes Cluster Name",
        "zh-cn": "ACK托管版集群名称"
      },
      "AssociationProperty": "AutoCompleteInput",
      "AssociationPropertyMetadata": {
        "Length": 5,
        "Prefix": "k8s-hpa-cluster-",
        "CharacterClasses": [
          {
            "Class": "lowercase",
            "min": 1
          }
        ]
      }
    },
    "ZoneId1": {
      "Type": "String",
      "AssociationProperty": "ALIYUN::ECS::Instance::ZoneId",
      "AssociationPropertyMetadata": {
        "ExclusiveTo": [
          "ZoneId2"
        ]
      },
      "Label": {
        "en": "Availability Zone",
        "zh-cn": "可用区1"
      }
    },
    "ZoneId2": {
      "Type": "String",
      "AssociationProperty": "ALIYUN::ECS::Instance::ZoneId",
      "AssociationPropertyMetadata": {
        "ExclusiveTo": [
          "ZoneId1"
        ]
      },
      "Label": {
        "en": "Availability Zone",
        "zh-cn": "可用区2"
      }
    },
    "InstanceType": {
      "Type": "CommaDelimitedList",
      "AssociationProperty": "ALIYUN::ECS::Instance::InstanceType",
      "AssociationPropertyMetadata": {
        "InstanceChargeType": "PostPaid",
        "SystemDiskCategory": "cloud_essd",
        "CreateACKClusterParams": {
          "NetworkPlugin": "terway-eniip"
        }
      },
      "Label": {
        "en": "Instance Type",
        "zh-cn": "实例规格"
      }
    },
    "InstancePassword": {
      "NoEcho": true,
      "Type": "String",
      "Description": {
        "en": "Server login password, Length 8-30, must contain three(Capital letters, lowercase letters, numbers, ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ Special symbol in)",
        "zh-cn": "服务器登录密码,长度8-30,必须包含三项(大写字母、小写字母、数字、 ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ 中的特殊符号)"
      },
      "Label": {
        "en": "Instance Password",
        "zh-cn": "实例密码"
      },
      "ConstraintDescription": {
        "en": "Length 8-30, must contain three(Capital letters, lowercase letters, numbers, ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ Special symbol in)",
        "zh-cn": "长度8-30,必须包含三项(大写字母、小写字母、数字、 ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ 中的特殊符号)"
      },
      "AssociationProperty": "ALIYUN::ECS::Instance::Password",
      "Default": null
    }
  },
  "Resources": {
    "Vpc": {
      "Type": "ALIYUN::ECS::VPC",
      "Properties": {
        "CidrBlock": "10.0.0.0/8",
        "VpcName": {
          "Fn::Sub": "${CommonName}-vpc"
        }
      }
    },
    "VSwitch1": {
      "Type": "ALIYUN::ECS::VSwitch",
      "Properties": {
        "VpcId": {
          "Ref": "Vpc"
        },
        "CidrBlock": "10.0.0.0/24",
        "ZoneId": {
          "Ref": "ZoneId1"
        },
        "VSwitchName": {
          "Fn::Sub": "${CommonName}-vsw"
        }
      }
    },
    "VSwitch2": {
      "Type": "ALIYUN::ECS::VSwitch",
      "Properties": {
        "VpcId": {
          "Ref": "Vpc"
        },
        "CidrBlock": "10.0.1.0/24",
        "ZoneId": {
          "Ref": "ZoneId2"
        },
        "VSwitchName": {
          "Fn::Sub": "${CommonName}-vsw"
        }
      }
    },
    "SecurityGroup": {
      "Type": "ALIYUN::ECS::SecurityGroup",
      "Properties": {
        "VpcId": {
          "Ref": "Vpc"
        },
        "SecurityGroupName": {
          "Fn::Sub": "${CommonName}-sg"
        },
        "SecurityGroupIngress": [
          {
            "PortRange": "443/443",
            "SourceCidrIp": "0.0.0.0/0",
            "IpProtocol": "tcp"
          },
          {
            "PortRange": "80/80",
            "SourceCidrIp": "0.0.0.0/0",
            "IpProtocol": "tcp"
          }
        ]
      }
    },
    "SlsProject": {
      "Type": "ALIYUN::SLS::Project",
      "Properties": {
        "Name": {
          "Ref": "SlsProjectName"
        }
      }
    },
    "AliyunCSManagedAutoScalerRole": {
      "Type": "ALIYUN::RAM::Role",
      "Properties": {
        "RoleName": "AliyunCSManagedAutoScalerRole",
        "Description": "CS使用此角色来访问您在其他云产品中的资源。",
        "AssumeRolePolicyDocument": {
          "Version": "1",
          "Statement": [
            {
              "Action": "sts:AssumeRole",
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "cs.aliyuncs.com"
                ]
              }
            }
          ]
        },
        "MaxSessionDuration": 3600,
        "IgnoreExisting": true,
        "DeletionForce": true,
        "PolicyAttachments": {
          "System": [
            "AliyunCSManagedAutoScalerRolePolicy"
          ]
        }
      }
    },
    "AckCluster": {
      "Type": "ALIYUN::CS::ManagedKubernetesCluster",
      "DependsOn": "AliyunCSManagedAutoScalerRole",
      "Properties": {
        "VpcId": {
          "Ref": "Vpc"
        },
        "VSwitchIds": [
          {
            "Ref": "VSwitch1"
          },
          {
            "Ref": "VSwitch2"
          }
        ],
        "PodVswitchIds": [
          {
            "Ref": "VSwitch1"
          },
          {
            "Ref": "VSwitch1"
          }
        ],
        "Name": {
          "Ref": "ManagedKubernetesClusterName"
        },
        "KubernetesVersion": "1.31.1-aliyun.1",
        "ServiceCidr": "192.168.0.0/16",
        "ClusterSpec": "ack.pro.small",
        "LoadBalancerSpec": "slb.s2.small",
        "IsEnterpriseSecurityGroup": true,
        "SnatEntry": true,
        "NumOfNodes": 0,
        "EndpointPublicAccess": true,
        "Platform": "AliyunLinux",
        "Addons": [
          {
            "Name": "ack-node-local-dns"
          },
          {
            "Name": "terway-eniip",
            "Config": "{\"IPVlan\":\"false\",\"NetworkPolicy\":\"false\",\"ENITrunking\":\"false\"}"
          },
          {
            "Name": "csi-plugin"
          },
          {
            "Name": "csi-provisioner"
          },
          {
            "Name": "storage-operator",
            "Config": "{\"CnfsOssEnable\":\"false\",\"CnfsNasEnable\":\"false\"}"
          },
          {
            "Name": "nginx-ingress-controller",
            "Disabled": true
          },
          {
            "Name": "logtail-ds",
            "Config": "{\"IngressDashboardEnabled\":\"true\"}"
          },
          {
            "Name": "alb-ingress-controller",
            "Version": "",
            "Config": {
              "Fn::Sub": "{\"albIngress\":{\"AddressType\":\"Internet\",\"ZoneMappings\":{\"${ZoneId1}\":[\"${VSwitch1}\"], \"${ZoneId2}\":[\"${VSwitch2}\"]},\"CreateDefaultALBConfig\":true}}"
            }
          },
          {
            "Name": "ack-helm-manager"
          },
          {
            "Name": "arms-prometheus"
          }
        ],
        "ProxyMode": "ipvs",
        "DeleteOptions": [
          {
            "ResourceType": "ALB",
            "DeleteMode": "delete"
          },
          {
            "ResourceType": "SLB",
            "DeleteMode": "delete"
          },
          {
            "ResourceType": "SLS_Data",
            "DeleteMode": "delete"
          },
          {
            "ResourceType": "SLS_ControlPlane",
            "DeleteMode": "delete"
          },
          {
            "ResourceType": "PrivateZone",
            "DeleteMode": "delete"
          }
        ]
      }
    },
    "NodePools": {
      "Type": "ALIYUN::CS::ClusterNodePool",
      "Properties": {
        "ClusterId": {
          "Ref": "AckCluster"
        },
        "NodePoolInfo": {
          "Name": "k8s-hpa-cluster-nodepool"
        },
        "ScalingGroup": {
          "VSwitchIds": [
            {
              "Ref": "VSwitch1"
            },
            {
              "Ref": "VSwitch2"
            }
          ],
          "ZoneIds": [
            {
              "Ref": "ZoneId1"
            },
            {
              "Ref": "ZoneId2"
            }
          ],
          "SystemDiskCategory": "cloud_essd",
          "SystemDiskPerformanceLevel": "PL0",
          "SystemDiskSize": 40,
          "InstanceTypes": {
            "Ref": "InstanceType"
          },
          "LoginPassword": {
            "Ref": "InstancePassword"
          },
          "Platform": "AliyunLinux",
          "ImageId": "aliyun_3_9_x64_20G_alibase_20231219.vhd"
        },
        "KubernetesConfig": {
          "Runtime": "containerd",
          "RuntimeVersion": "1.6.28"
        },
        "AutoScaling": {
          "Enable": true,
          "MinInstances": 2,
          "MaxInstances": 10
        }
      }
    },
    "Sleep": {
      "Type": "ALIYUN::ROS::Sleep",
      "DependsOn": "NodePools",
      "Properties": {
        "CreateDuration": 300
      }
    },
    "AckMetricsAdapter": {
      "Type": "ALIYUN::CS::ClusterHelmApplication",
      "DependsOn": "Sleep",
      "Properties": {
        "Namespace": "kube-system",
        "ChartUrl": "https://aliacs-app-catalog.oss-cn-hangzhou.aliyuncs.com/charts-incubator/ack-alibaba-cloud-metrics-adapter-1.3.3.tgz",
        "ClusterId": {
          "Ref": "AckCluster"
        },
        "Name": "ack-alibaba-cloud-metrics-adapter",
        "ChartValues": {
          "AlibabaCloudMetricsAdapter": {
            "commonLabels": "",
            "replicas": 1,
            "resources": {
              "metricsAdapterDeployment": {
                "resources": {
                  "limits": {
                    "cpu": 0.5,
                    "memory": "1Gi"
                  },
                  "requests": {
                    "cpu": "100m",
                    "memory": "200Mi"
                  }
                }
              },
              "configReloader": {
                "resources": {
                  "limits": {
                    "cpu": "20m",
                    "memory": "30Mi"
                  },
                  "requests": {
                    "cpu": "20m",
                    "memory": "30Mi"
                  }
                }
              }
            },
            "listenPort": 443,
            "costWeights": {
              "cpu": "1.0",
              "memory": "0.0"
            },
            "image": {
              "repository": "registry-cn-hangzhou-vpc.ack.aliyuncs.com/acs/alibaba-cloud-metrics-adapter-amd64",
              "tag": "v0.2.7-f1ee5c3-aliyun",
              "pullPolicy": "Always"
            },
            "nameOverride": "",
            "fullnameOverride": "",
            "service": {
              "type": "ClusterIP"
            },
            "serviceAccountName": "ack-alibaba-cloud-metrics-adapter",
            "annotations": {},
            "nodeSelector": {},
            "tolerations": [],
            "env": [
              {
                "AccessKeyId": ""
              },
              {
                "AccessKeySecret": ""
              },
              {
                "Region": ""
              }
            ],
            "affinity": {},
            "prometheus": {
              "enabled": true,
              "url": {},
              "metricsRelistInterval": "1m",
              "logLevel": 5,
              "adapter": {
                "rules": {
                  "default": false,
                  "custom": [
                    {
                      "seriesQuery": "container_memory_working_set_bytes{namespace!=\"\",pod!=\"\"}",
                      "resources": {
                        "overrides": {
                          "namespace": {
                            "resource": "namespace"
                          },
                          "pod": {
                            "resource": "pod"
                          }
                        }
                      },
                      "name": {
                        "matches": "^(.*)_bytes",
                        "as": "${1}_bytes_per_second"
                      },
                      "metricsQuery": "sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>)"
                    },
                    {
                      "seriesQuery": "container_cpu_usage_seconds_total{namespace!=\"\",pod!=\"\"}",
                      "resources": {
                        "overrides": {
                          "namespace": {
                            "resource": "namespace"
                          },
                          "pod": {
                            "resource": "pod"
                          }
                        }
                      },
                      "name": {
                        "matches": "^(.*)_seconds_total",
                        "as": "${1}_core_per_second"
                      },
                      "metricsQuery": "sum(rate(<<.Series>>{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>)"
                    }
                  ]
                }
              }
            }
          },
          "ConfigReloader": {
            "image": {
              "repository": "registry-vpc.cn-hangzhou.aliyuncs.com/acs/configmap-reload",
              "tag": "v0.0.1"
            }
          }
        }
      }
    },
    "InstallBackendApp": {
      "Type": "ALIYUN::CS::ClusterApplication",
      "DependsOn": "AckMetricsAdapter",
      "Properties": {
        "ClusterId": {
          "Ref": "AckCluster"
        },
        "YamlContent": {
          "Fn::Sub": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: coffee\nspec:\n  replicas: 2\n  selector:\n    matchLabels:\n      app: coffee\n  template:\n    metadata:\n      labels:\n        app: coffee\n    spec:\n      containers:\n      - name: coffee\n        image: registry.${ALIYUN::Region}.aliyuncs.com/acs-sample/nginxdemos:latest\n        ports:\n        - containerPort: 80\n        resources:\n          limits:\n            cpu: 500m\n            memory: 1Gi\n          requests:\n            cpu: 500m\n            memory: 512Mi\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: coffee-svc\nspec:\n  ports:\n  - port: 80\n    targetPort: 80\n    protocol: TCP\n  selector:\n    app: coffee\n  type: NodePort\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: tea\nspec:\n  replicas: 2\n  selector:\n    matchLabels:\n      app: tea\n  template:\n    metadata:\n      labels:\n        app: tea\n    spec:\n      containers:\n      - name: tea\n        image: registry.${ALIYUN::Region}.aliyuncs.com/acs-sample/nginxdemos:latest\n        ports:\n        - containerPort: 80\n        resources:\n          limits:\n            cpu: 500m\n            memory: 1Gi\n          requests:\n            cpu: 500m\n            memory: 512Mi\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: tea-svc\nspec:\n  ports:\n  - port: 80\n    targetPort: 80\n    protocol: TCP\n  selector:\n    app: tea\n  type: NodePort"
        }
      }
    },
    "AlbConfig": {
      "Type": "ALIYUN::CS::ClusterApplication",
      "DependsOn": "InstallBackendApp",
      "Properties": {
        "ClusterId": {
          "Ref": "AckCluster"
        },
        "YamlContent": {
          "Fn::Sub": "apiVersion: alibabacloud.com/v1\nkind: AlbConfig\nmetadata:\n  name: k8s-hpa-alb-config\nspec:\n  config:\n    name: k8s-hpa-alb\n    addressType: Internet\n    zoneMappings:\n    - vSwitchId: ${VSwitch1}\n    - vSwitchId: ${VSwitch2}\n    accessLogConfig:\n      logProject: ${SlsProject}\n      logStore: \"alb_k8s_hpa_sls_logstore\"\n  listeners:\n    - port: 80\n      protocol: HTTP"
        }
      }
    },
    "IngressClass": {
      "Type": "ALIYUN::CS::ClusterApplication",
      "DependsOn": "AlbConfig",
      "Properties": {
        "ClusterId": {
          "Ref": "AckCluster"
        },
        "YamlContent": {
          "Fn::Sub": "apiVersion: networking.k8s.io/v1\nkind: IngressClass\nmetadata:\n  name: k8s-hpa-alb-ingress-class\nspec:\n  controller: ingress.k8s.alibabacloud/alb\n  parameters:\n    apiGroup: alibabacloud.com\n    kind: AlbConfig\n    name: k8s-hpa-alb-config"
        }
      }
    },
    "Ingress": {
      "Type": "ALIYUN::CS::ClusterApplication",
      "DependsOn": "IngressClass",
      "Properties": {
        "ClusterId": {
          "Ref": "AckCluster"
        },
        "YamlContent": {
          "Fn::Sub": "apiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n  name: k8s-hpa-alb-ingress\nspec:\n  ingressClassName: k8s-hpa-alb-ingress-class\n  rules:\n   - http:\n      paths:\n      - path: /tea\n        pathType: ImplementationSpecific\n        backend:\n          service:\n            name: tea-svc\n            port:\n              number: 80\n      - path: /coffee\n        pathType: ImplementationSpecific\n        backend:\n          service:\n            name: coffee-svc\n            port: \n              number: 80"
        }
      }
    },
    "Hpa": {
      "Type": "ALIYUN::CS::ClusterApplication",
      "DependsOn": "WaitAlbIngress",
      "Properties": {
        "ClusterId": {
          "Ref": "AckCluster"
        },
        "YamlContent": {
          "Fn::Sub": "apiVersion: autoscaling/v2\nkind: HorizontalPodAutoscaler\nmetadata:\n  name: k8s-alb-tea-hpa\nspec:\n  scaleTargetRef:\n    apiVersion: apps/v1\n    kind: Deployment\n    name: tea\n  minReplicas: 2\n  maxReplicas: 10\n  metrics:\n    - type: External\n      external:\n        metric:\n          name: sls_alb_ingress_qps\n          selector:\n            matchLabels:\n              sls.project: ${SlsProject}\n              sls.logstore: \"alb_k8s_hpa_sls_logstore\" \n              sls.ingress.route: \"default-tea-svc-80\"\n        target:\n          type: AverageValue\n          averageValue: 2\n    - resource:\n        name: cpu\n        target:\n          averageUtilization: 80\n          type: Utilization\n      type: Resource\n    - resource:\n        name: memory\n        target:\n          averageUtilization: 80\n          type: Utilization\n      type: Resource"
        }
      }
    },
    "WaitAlbIngress": {
      "Type": "ALIYUN::ROS::Sleep",
      "DependsOn": "Ingress",
      "Properties": {
        "CreateDuration": 120
      }
    },
    "IngressInfo": {
      "Type": "DATASOURCE::CS::ClusterApplicationResources",
      "DependsOn": "WaitAlbIngress",
      "Properties": {
        "ClusterId": {
          "Ref": "AckCluster"
        },
        "Kind": "Ingress",
        "Namespace": "default",
        "JsonPath": "$.items.[0].status.loadBalancer.ingress.[0].hostname",
        "FirstMatch": true
      }
    }
  },
  "Outputs": {
    "TeaUrl": {
      "Description": {
        "zh-cn": "tea服务访问地址。",
        "en": "The addresses of tea service."
      },
      "Value": {
        "Fn::Sub": "http://${IngressInfo}/tea"
      }
    },
    "CoffeeUrl": {
      "Description": {
        "zh-cn": "coffee服务访问地址。",
        "en": "The addresses of coffee service."
      },
      "Value": {
        "Fn::Sub": "http://${IngressInfo}/coffee"
      }
    }
  },
  "Metadata": {
    "ALIYUN::ROS::Interface": {
      "ParameterGroups": [
        {
          "Parameters": [
            "SlsProjectName",
            "ManagedKubernetesClusterName",
            "ZoneId1",
            "ZoneId2",
            "InstanceType",
            "InstancePassword"
          ]
        }
      ],
      "TemplateTags": [
        "acs:technical-solution:micro:通过HPA实现容器应用的水平弹性伸缩-tech_solu_125"
      ],
      "Hidden": [
        "CommonName"
      ]
    }
  }
}