01/引言
对于实施多云或混合云策略的企业来说,kOps 是一个理想的 Kubernetes 集群管理工具。它通过统一的配置文件(YAML 或 JSON)实现跨多个云环境(如 AWS、GCP、Azure)或本地数据中心的集群管理。
kOps 提供了丰富的自定义选项,包括控制面节点和工作节点的操作系统、网络插件(如 Calico、Cilium)、存储解决方案等,满足企业在复杂场景下的灵活部署需求。
对于希望进一步优化 Kubernetes 资源效率的企业,开源的 Kubernetes 集群自动扩展工具 Karpenter 则是一个强大的选择。
Karpenter 能根据 Pod 的资源需求动态配置节点,支持多种实例类型,并可以智能调度 AWS Spot 实例,大幅降低运行成本。其无节点池的设计,使得资源调度更加灵活,特别适合需要高弹性和高性价比的场景。
然而,kOps 与 Karpenter 的官方集成已停止更新,仅支持较旧的版本。这意味着在最新版本的 kOps 上,用户需要通过手动配置的方式实现与 Karpenter 的集成。
为了解决这一问题,本文将介绍如何在 kOps 部署的 AWS Kubernetes 集群上部署 Karpenter,通过具体步骤和技术细节,帮助用户在现有架构中实现动态扩展能力,同时最大化利用 Karpenter 的优势,提升集群的弹性与资源利用效率。
为什么选择 kOps
kOps 是一个开源项目,可以创建、销毁、升级和维护一个高可用的生产级 Kubernetes 集群。该项目的开发者将其描述为“为集群打造的 Kubectl”。
目前,kOps 主要用于部署 AWS 和 GCE Kubernetes 集群,对 Azure 的支持处于 alpha 阶段。以下是这款工具的主要特性:
- 自动配置高可用 Kubernetes 集群
- 支持集群滚动更新
- 在命令行中自动补齐命令
- 生成 Terraform 配置
- 以状态同步模型为基础,实现 dry-runs 和自动幂等性(idempotency)
- 创建实例组以支持异构集群
相较其他产品 ,kOps更灵活。通过采用 kOps,企业可以获得 K8s 集群配置的较大控制权,并且能够自定义 K8s 环境以满足特定需求。还能根据自己的偏好配置云环境,并可以完全访问 master 节点以进行微调和故障排除。
此外,对于小型或临时集群,kOps 往往比其他选择更具成本效益。 作为一种开源和免费的解决方案,企业只需支付底层基础设施的费用。
为什么选择 Karpenter
Karpenter 是当前业界最流行的开源 Kubernetes 集群自动扩展工具之一,最初由 AWS 开源,目前已捐献给 CNCF。当前,Karpenter 支持 AWS、Azure及阿里云,针对 GKE 的支持正在紧锣密鼓地开发中。
与传统的自动扩缩不同,Karpenter 能够动态地在实时环境中为集群工作负载提供所需的计算资源。它通过观察未调度 pod 的资源请求总量,智能决策并启动精准匹配需求的新节点。
Karpenter 项目地址:
https://github.com/kubernetes-sigs/karpenter
02/前期准备
- 具有 IAM 权限的 AWS 账户, 以创建 EC2 Instance.
- 安装并配置 AWS CLI.
- 安装 Kubernetes CLI (kubectl)
- 安装 Helm(Kubernetes 的包管理工具)
- 安装 kOps
03/通过 kOps 创建集群
配置集群
在创建集群前,您需要配置集群所在的 Region,以及集群的名称。为了简化部署流程,我们会创建基于 Gossip DNS 的集群。
https://kops.sigs.k8s.io/gossip/
如果您希望使用自己的域名创建集群,您可以参阅下文:
https://kops.sigs.k8s.io/getting_started/aws/#configure-dns- export DEPLOY_REGION="us-west-1"
- export CLUSTER_NAME="demo1"
- export DEPLOY_ZONE="us-west-1a"
- export NAME=${CLUSTER_NAME}.k8s.loca
复制代码 创建 kOps IAM User
为了在 AWS 中创建集群,我们将使用 AWS CLI 为 kOps 创建一个专用的 IAM 用户 kops。- aws iam create-group --group-name kops
- aws iam attach-group-policy --policy-arn arn:aws:iam::aws:policy/AmazonEC2FullAccess --group-name kops
- aws iam attach-group-policy --policy-arn arn:aws:iam::aws:policy/AmazonRoute53FullAccess --group-name kops
- aws iam attach-group-policy --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess --group-name kops
- aws iam attach-group-policy --policy-arn arn:aws:iam::aws:policy/IAMFullAccess --group-name kops
- aws iam attach-group-policy --policy-arn arn:aws:iam::aws:policy/AmazonVPCFullAccess --group-name kops
- aws iam attach-group-policy --policy-arn arn:aws:iam::aws:policy/AmazonSQSFullAccess --group-name kops
- aws iam attach-group-policy --policy-arn arn:aws:iam::aws:policy/AmazonEventBridgeFullAccess --group-name kops
- aws iam create-user --user-name kops
- aws iam add-user-to-group --user-name kops --group-name kops
- aws iam create-access-key --user-name kops
复制代码 导出 AWS AccessKey/SecretKey
我们需要使用 AccessKey 和 SecretKey,需要将其导出。为了简化部署,本教程中没有切换用户,您可以手动通过 aws configure 切换到 kops 用户。- export AWS_ACCESS_KEY_ID=$(aws configure get aws_access_key_id)
- export AWS_SECRET_ACCESS_KEY=$(aws configure get aws_secret_access_key)
复制代码 创建集群状态存储 Bucket
为了保存集群的状态信息以及描述集群的配置信息,我们需要创建一个专用的 S3 存储桶供 kOps 使用。这个存储桶将成为保存集群配置的唯一可信来源。- export KOPS_STATE_STORE_NAME=kops-state-store-${CLUSTER_NAME}
- export KOPS_OIDC_STORE_NAME=kops-oidc-store-${CLUSTER_NAME}
- export KOPS_STATE_STORE=s3://${KOPS_STATE_STORE_NAME}
- aws s3api create-bucket \
- --bucket ${KOPS_STATE_STORE_NAME} \
- --region ${DEPLOY_REGION} \
- --create-bucket-configuration LocationConstraint=${DEPLOY_REGION}
- aws s3api create-bucket \
- --bucket ${KOPS_OIDC_STORE_NAME} \
- --region ${DEPLOY_REGION} \
- --create-bucket-configuration LocationConstraint=${DEPLOY_REGION} \
- --object-ownership BucketOwnerPreferred
- aws s3api put-public-access-block \
- --bucket ${KOPS_OIDC_STORE_NAME} \
- --public-access-block-configuration BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false
- aws s3api put-bucket-acl \
- --bucket ${KOPS_OIDC_STORE_NAME} \
- --acl public-read
复制代码 创建集群
以下是创建集群的命令。我们将使用最基本的示例,以下命令将生成集群配置,但不会开始构建它。- kops create cluster \
- --name=${NAME} \
- --cloud=aws \
- --node-count=1 \
- --control-plane-count=1 \
- --zones=${DEPLOY_ZONE} \
- --discovery-store=s3://${KOPS_OIDC_STORE_NAME}/${NAME}/discovery
复制代码
现在我们进入实际构建集群的最后一步,这需要一段时间。完成后,您将需要等待更长时间,直到启动的实例完成下载 Kubernetes 组件并达到“就绪”状态。- kops update cluster --name ${NAME} --yes --admin
- kops export kubeconfig
- # 等待集群状态 Ready
- kops validate cluster --wait 10m --name ${NAME}
复制代码
04/部署 Karpenter
准备必要的内容
我们需要这些环境变量来部署 Karpenter 和创建 NodePool/NodeClass。
通过 AWS CLI 获取 OIDC Provider 的信息、Issuer 地址和 AWS 账户 ID,确保后续部署正常进行。- export OIDC_PROVIDER_ID=$(aws iam list-open-id-connect-providers \
- --query "OpenIDConnectProviderList[?contains(Arn, '${NAME}')].Arn" \
- --output text | awk -F'/' '{print $NF}')
- export OIDC_ISSUER=${KOPS_OIDC_STORE_NAME}.s3.${DEPLOY_REGION}.amazonaws.com/${NAME}/discovery/${NAME}
- export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' \
- --output text)
- export AWS_INSTANCE_PROFILE_NAME=nodes.${NAME}
- export KARPENTER_ROLE_NAME=karpenter.kube-system.sa.${NAME}
- export CLUSTER_ENDPOINT=$(kubectl config view -o jsonpath="{.clusters[?(@.name=='${NAME}')].cluster.server}")
- # 储存后续需要的临时文件
- export TMP_DIR=$(mktemp -d)
复制代码 创建 Karpenter IAM Role
我们需要为 Karpenter 创建和配置专用的 IAM Role 和 Policy,允许 Karpenter 通过 OIDC 身份验证该角色,并为该角色添加必要的权限,使其能够动态创建、管理和删除AWS资源(如EC2实例),以满足 Kubernetes 工作负载的需求。- aws iam create-role \
- --role-name ${KARPENTER_ROLE_NAME} \
- --assume-role-policy-document "{
- "Version": "2012-10-17",
- "Statement": [
- {
- "Effect": "Allow",
- "Principal": {
- "Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/oidc.eks.${DEPLOY_REGION}.amazonaws.com/id/${OIDC_PROVIDER_ID}"
- },
- "Action": "sts:AssumeRoleWithWebIdentity",
- "Condition": {
- "StringEquals": {
- "oidc.eks.${DEPLOY_REGION}.amazonaws.com/id/${OIDC_PROVIDER_ID}:sub": "system:serviceaccount:kube-system:karpenter"
- }
- }
- }
- ]
- }"
- aws iam create-role \
- --role-name ${KARPENTER_ROLE_NAME} \
- --assume-role-policy-document "{
- "Version": "2012-10-17",
- "Statement": [
- {
- "Effect": "Allow",
- "Principal": {
- "Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${KOPS_OIDC_STORE_NAME}.s3.us-west-1.amazonaws.com/${NAME}/discovery/${NAME}"
- },
- "Action": "sts:AssumeRoleWithWebIdentity",
- "Condition": {
- "StringEquals": {
- "${OIDC_ISSUER}:sub": "system:serviceaccount:kube-system:karpenter"
- }
- }
- }
- ]
- }"
- aws iam put-role-policy \
- --role-name ${KARPENTER_ROLE_NAME} \
- --policy-name InlineKarpenterPolicy \
- --policy-document '{
- "Version": "2012-10-17",
- "Statement": [
- {
- "Effect": "Allow",
- "Action": [
- "ec2:CreateFleet",
- "ec2:CreateTags",
- "ec2:DescribeAvailabilityZones",
- "ec2:DescribeImages",
- "ec2:DescribeInstanceTypeOfferings",
- "ec2:DescribeInstanceTypes",
- "ec2:DescribeInstances",
- "ec2:DescribeLaunchTemplates",
- "ec2:DescribeSecurityGroups",
- "ec2:DescribeSpotPriceHistory",
- "ec2:DescribeSubnets",
- "ec2:RunInstances",
- "ec2:TerminateInstances",
- "iam:PassRole",
- "pricing:GetProducts",
- "ssm:GetParameter",
- "ec2:CreateLaunchTemplate",
- "ec2:DeleteLaunchTemplate",
- "sts:AssumeRoleWithWebIdentity"
- ],
- "Resource": "*"
- }
- ]
- }'
复制代码 部署 Karpenter
首先,我们需要配置一些额外的内容从而限制 Karpenter 仅在控制面运行,并且绑定和传入我们之前配置的内容,如 clusterEndpoint / clusterName 以及最重要的 IAM Role。
[code]cat |