Terraform то чудово, але поки що вирішили перші кластера AWS EKS створювати за допомогою AWS CDK, бо по-преше – він вже є на проекті, по-друге – самому цікаво спробувати новий інструмент.
Тож сьогодні розглянемо що з цього вийшло, та як створювався кластер і необхідні ресурси.
Про перше знайомство з СDK писав тут – AWS: CDK – знайомство та приклади на Python.
Забігаючи наперед – особисто я, дуже м’яко кажучи, не в захваті від CDK:
- ніякого тобі KISS – Keep It Simple Stupid, ніякого тобі “явне краще неявного”
- місцями незрозуміла документація з приклами на TypeScript навіть в репозиторії PyPi
- купа окремих бібліотек та модулів, іноді геморой з їхніми імпортами
- загальна перенавантаженість коду CDK/Python – Terraform з його HCL або Pulumi з Python виглядає набагато простішим для розуміння загальної картини інфрастуктури, котора цим кодом описана
- перенавантаженість самого CloudFormation стеку, створенного за допомогою CDK – купа IAM-ролей, якісь Lambda-функції і таке інше – коли воно зламається, то доведеться дуже довго шукати де і що саме “пішло не так”
- питати Google на тему “AWS CDK Python create something” – майже марна справа, бо результатів або не буде взагалі, але будуть на TypeScript
Хоча пост планувався в стилі “як зробити”, але в результаті вийшло “Як вистрілити собі в ногу, запроваджуючи на проекті AWS CDK”.
Зміст
AWS CDK vs Terraform
Знову-таки, хоча сам пост не про це, але кілька слів після роботи з CDK та його порівняння з Terraform.
Time To Create: AWS CDK vs Terraform
Перше, що хочеться прям на початку показати – це швидкість роботи AWS CDK vs Terraform:
Тест, звісно, достаточно штучний, але дуже гарно показав різницю в роботі.
Я спецільно не створював NAT Gateways, бо їхнє створення займає більше хвилини просто на запуск самих NAT-інстансів, тоді як на створення VPC/Subnets/etc час не витрачається, тож бачимо саме швидкість роботи CDK/CloudFormation versus Terraform.
Пізніше ще заміряв створення VPC+EKS з CDK та Terraform:
CDK
- create: 18m54.643s
- destroy: 26m4.509s
Terraform:
- create: 12m56.801s
- destroy: 5m32.329s
AWS CDK workflow
Та й в цілому процес роботи CDK виглядає занадто ускладненим:
- пишемо код на Python
- який траснлюється до бекенду CDK на NodeJS
- генерує CloudFormation Template та ChangeSets
- CDK для своєї роботи створює пачку Lambda-функцій
- і тільки потім створюються ресурси
Плюс в самому CloudFormation стеку для EKS створюється ціла купа AIM ролей та Lambda-функцій з неясним та неявним призначенням.
AWS CDK та нові “фічі” AWS
Ще з насправді досить очікуваного – CDK не має всіх нових “плюшок” AWS. Я с цим зіткнувся ще кілька років тому, коли потрібно було у CloudFormation створити cross-region VPC Peering, а CloudFormation це не підтримував, хоча у Terraform це вже було реалізовано.
Аналогічно виявилось і зараз: остання версія CDK (2.84.0) не має підтримки EKS 1.27, реліз якої відбувся майже місць тому, 24-го травня – Amazon EKS now supports Kubernetes version 1.27. А ось Terraform її вже підтримує – AWS EKS Terraform module.
Але таке. Окей, най буде, як то кажуть.
Давайте пробувати.
Початок роботи: спитаємо ChatGPT
Щоб мати якусь точку для старту – спитав ChatGPT. В цілому, ідею від подав, хоча з застарілими імпортами та деякими атрибутами, які довелось переписувати:
Поїхали.
Python virtualevn
Створюємо Python virtualevn:
[simterm]
$ python -m venv .venv $ ls -l .venv/ total 16 drwxr-xr-x 2 setevoy setevoy 4096 Jun 20 11:18 bin drwxr-xr-x 3 setevoy setevoy 4096 Jun 20 11:18 include drwxr-xr-x 3 setevoy setevoy 4096 Jun 20 11:18 lib lrwxrwxrwx 1 setevoy setevoy 3 Jun 20 11:18 lib64 -> lib -rw-r--r-- 1 setevoy setevoy 176 Jun 20 11:18 pyvenv.cfg
[/simterm]
Активуємо його:
[simterm]
$ . .venv/bin/activate (.venv)
[/simterm]
Тепер можемо створювати новий application.
AWS CDK Init
Створюємо шаблон нашого стеку з Python:
[simterm]
$ cdk init app --language python ... ✅ All done!
[/simterm]
Отримуємо таку структуру файлів та каталогів:
[simterm]
$ tree .
.
├── README.md
├── app.py
├── atlas_eks
│ ├── __init__.py
│ └── atlas_eks_stack.py
├── cdk.json
├── requirements-dev.txt
├── requirements.txt
├── source.bat
└── tests
├── __init__.py
└── unit
├── __init__.py
└── test_atlas_eks_stack.py
4 directories, 11 files
[/simterm]
Встановлюємо залежності:
[simterm]
$ pip install -r requirements.txt Collecting aws-cdk-lib==2.83.1 Using cached aws_cdk_lib-2.83.1-py3-none-any.whl (41.5 MB) ...
[/simterm]
Перевіряємо, що все працює:
[simterm]
$ cdk list AtlasEksStack
[/simterm]
Зміст app.py зараз маємо такий:
Та у atlas_eks/atlas_eks_stack.py маємо шаблон для створення стеку:
from aws_cdk import (
# Duration,
Stack,
# aws_sqs as sqs,
)
from constructs import Construct
class AtlasEksStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# The code that defines your stack goes here
# example resource
# queue = sqs.Queue(
# self, "AtlasEksQueue",
# visibility_timeout=Duration.seconds(300),
# )
Додамо змінні оточення до app.py – аккаунт та регіон, та оновлюємо виклик AtlasEksStack():
...
AWS_ACCOUNT = os.environ["AWS_ACCOUNT"]
AWS_REGION = os.environ["AWS_REGION"]
app = cdk.App()
AtlasEksStack(app, "AtlasEksStack",
env=cdk.Environment(account=AWS_ACCOUNT, region=AWS_REGION),
)
...
Задаємо змінні в консолі:
[simterm]
$ export AWS_ACCOUNT=492***148 $ export AWS_REGION=us-east-1
[/simterm]
Перевіряємо ще раз з cdk list.
Створення EKS кластеру
Повертаємось до ChatGPT, що він там далі рекомендує:
Нам тут цікаві тільки імпорти (з якими він не вгадав), та сам ресурс cluster = eks.Cluster(), якому він пропонує версію 1.21, бо сам ChatGPT, як ми знаємо, має базу до 2021 року.
CDK: AttributeError: type object ‘KubernetesVersion’ has no attribute ‘V1_27’
Щодо AWS CDK та версії EKS, писав про це на початку – виглядала помилка так:
AttributeError: type object ‘KubernetesVersion’ has no attribute ‘V1_27’
Окей – давайте поки 1.26, там подивимось, як з цим жити.
Обновлюємо файл atlas_eks_stack.py, використовуємо eks.KubernetesVersion.V1_26:
from aws_cdk import (
aws_eks as eks,
Stack
)
from constructs import Construct
class AtlasEksStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
cluster = eks.Cluster(
self, 'EKS-Cluster',
cluster_name='my-eks-cluster',
version=eks.KubernetesVersion.V1_26,
)
Перевіряємо з cdk synth:
[simterm]
$ cdk synth
[Warning at /AtlasEksStack/EKS-Cluster] You created a cluster with Kubernetes Version 1.26 without specifying the kubectlLayer property. This may cause failures as the kubectl version provided with aws-cdk-lib is 1.20, which is only guaranteed to be compatible with Kubernetes versions 1.19-1.21. Please provide a kubectlLayer from @aws-cdk/lambda-layer-kubectl-v26.
Resources:
EKSClusterDefaultVpc01B29049:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsHostnames: true
EnableDnsSupport: true
InstanceTenancy: default
Tags:
- Key: Name
Value: AtlasEksStack/EKS-Cluster/DefaultVpc
Metadata:
aws:cdk:path: AtlasEksStack/EKS-Cluster/DefaultVpc/Resource
...
[/simterm]
CDK сам тсворить VPC та subnets і все інше для мережі, та IAM ролі. Це, в принципі, зручно, хоча там є свої питання.
Ми далі будемо створювати власну VPC.
Warning: You created a cluster with Kubernetes Version 1.26 without specifying the kubectlLayer property
На початку cdk synth каже щось про kubectlLayer:
[Warning at /AtlasEksStack/EKS-Cluster] You created a cluster with Kubernetes Version 1.26 without specifying the kubectlLayer property. This may cause failures as the kubectl version provided with aws-cdk-lib is 1.20, which is only guaranteed to be compatible with Kubernetes versions 1.19-1.21. Please provide a kubectlLayer from @aws-cdk/lambda-layer-kubectl-v26.
З імені можно припустити, що CDK створить Lambda-функцію, в якій буде викликати kubectl для виконання якихось задач в самоу Kubernetes.
В документації KubectlLayer сказано, що “An AWS Lambda layer that includes kubectl and helm.”
Дуже дякую – все відразу стало зрозуміло. Де воно використовується, для чого?
Ну, ок… Давайте спробуємо позбутися цього варнінгу.
Знову спитаємо ChatGP:
Пробуємо встановити aws-lambda-layer-kubectl-v26:
[simterm]
$ pip install aws-cdk.aws-lambda-layer-kubectl-v26 ERROR: Could not find a version that satisfies the requirement aws-cdk.aws-lambda-layer-kubectl-v26 (from versions: none) ERROR: No matching distribution found for aws-cdk.aws-lambda-layer-kubectl-v26
[/simterm]
Da f*****ck!
Ну, добре… Пам’ятаємо, що ChatGP “старенький” – може, ліба якось інакше називається?
PyPI no longer supports ‘pip search’
Пробуємо pip search – спочатку перевіримо, що search в PiP взагалі є, бо давно ним не користувався:
[simterm]
$ pip search --help Usage: pip search [options] <query> Description: Search for PyPI packages whose name or summary contains <query>. Search Options: -i, --index <url> Base URL of Python Package Index (default https://pypi.org/pypi) ...
[/simterm]
Окей – шукаємо:
[simterm]
$ pip search aws-lambda-layer-kubectl ERROR: XMLRPC request failed [code: -32500] RuntimeError: PyPI no longer supports 'pip search' (or XML-RPC search). Please use https://pypi.org/search (via a browser) instead. See https://warehouse.pypa.io/api-reference/xml-rpc.html#deprecated-methods for more information.
[/simterm]
WHAAAAT?!?
Тобто, просто з консолі з PiP знайти пакет неможливо? Це як так? Трохи “розрив шаблону”.
Окей – поки лишимо, як є, хоча далі з цим знову зустрінемось, і таки доведеться фіксити.
Змінні в CDK Stack
Що тепер хочеться, це додати змінну для Environment – Dev/Stage/Prod, і потім використовати її в іменах ресурсів та тегах.
Додамо до app.py змінну $EKS_STAGE, а до створення AtlasEksStack() – передаємо її другим агрументом, щоб використати як ім’я стеку, і додаємо параметр stage, що потім використовувати всередені класу:
...
EKS_STAGE = os.environ["EKS_ENV"]
app = cdk.App()
AtlasEksStack(app, "f'eks-{EKS_STAGE}-1-26'",
env=cdk.Environment(account=AWS_ACCOUNT, region=AWS_REGION),
stage=EKS_STAGE
)
...
Далі у файлі atlas_eks_stack.py описуємо параметр stage: str, і використовуємо його при створенні eks.Cluster() у параметрі cluster_name:
...
def __init__(self, scope: Construct, construct_id: str, stage: str, **kwargs)
...
cluster = eks.Cluster(
self, 'EKS-Cluster',
cluster_name=f'eks-{stage}-1-26-cluster',
version=eks.KubernetesVersion.V1_26,
)
Задаємо змінну оточення в терміналі:
[simterm]
$ export EKS_ENV=dev
[/simterm]
З cdk list перевіримо, що ім’я стеку змінилось і має $EKS_ENV:
[simterm]
$ cdk list eks-dev-1-26
[/simterm]
Та з sdk synth перевіримо, що ім’я кластеру теж змінилось:
[simterm]
$ cdk synth
...
Type: Custom::AWSCDK-EKS-Cluster
Properties:
ServiceToken:
Fn::GetAtt:
- awscdkawseksClusterResourceProviderNestedStackawscdkawseksClusterResourceProviderNestedStackResource9827C454
- Outputs.AtlasEksStackawscdkawseksClusterResourceProviderframeworkonEvent588F9666Arn
Config:
name: eks-dev-1-26-cluster
...
[/simterm]
Добре – кластер є, тепер створимо для нього VPC.
Створення VPC та Subnets
Кастомну VPC хочеться, бо по-дефолту CDK створить по Subnet-у у кожній AvailabilityZone, тобто три мережі, плюс до кожної буде свій NAT Gateway. Але по-перше – мені більше подобається самому контролювати розбивку мережі, по-друге – кожен NAT Gateway коштує грошей, а нам поки що fault-tolerance аж на три AvailabilityZone не потрібен, краще зекономити трохи грошей.
Документація по CDK VPC – aws_cdk.aws_ec2.Vpc.
Типи Subnet тут – SubnetType.
Тут як на мене ще один не найкращий нюанс CDK: так, це зручно, що він має багато викорорівневих ресурсів, коли тобі достатньо просто вказати subnet_type=ec2.SubnetType.PUBLIC, а CDK сам створить все необхідне, але особисто мені декларативний підхід Terraform та його HCL виглядає привабливішим, бо навіть якщо використовувати модуль VPC, а не описувати все вручну – набагато простіше зайти в код того модулю і подивитись, що він має “під капотом”, ніж копатись у бібліотеці CDK. Але це чисто особисте “Я так бачу“.
Крім того, в документації не сказано, що PRIVATE_WITH_NAT вже deprecated, побачив це тільки коли перевіряв створення ресурсів:
[simterm]
$ cdk synth [WARNING] aws-cdk-lib.aws_ec2.VpcProps#cidr is deprecated. Use ipAddresses instead This API will be removed in the next major release. [WARNING] aws-cdk-lib.aws_ec2.SubnetType#PRIVATE_WITH_NAT is deprecated. use `PRIVATE_WITH_EGRESS` This API will be removed in the next major release. [WARNING] aws-cdk-lib.aws_ec2.SubnetType#PRIVATE_WITH_NAT is deprecated. use `PRIVATE_WITH_EGRESS` This API will be removed in the next major release. ...
[/simterm]
Окей.
Додаємо availability_zones, в яких хочемо створювати subnets, і описуємо subnet_configuration.
В subnet_configuration описуємо subnet group – одну Public, та одну Private – CDK створить subnet кожного типу в кожній Availability Zone.
На майбутнє – відразу створимо S3 Endpoint, бо в кластері планується Grafana Loki, яка буде ходити в S3 бакети.
До ресурсу eks.Cluster() додаємо параметр vpc.
Весь файл тепер виглядає так:
from aws_cdk import (
aws_eks as eks,
aws_ec2 as ec2,
Stack
)
from constructs import Construct
class AtlasEksStack(Stack):
def __init__(self, scope: Construct, construct_id: str, stage: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
availability_zones = ['us-east-1a', 'us-east-1b']
# Create a new VPC
vpc = ec2.Vpc(self, 'Vpc',
ip_addresses=ec2.IpAddresses.cidr("10.0.0.0/16"),
vpc_name=f'eks-{stage}-1-26-vpc',
enable_dns_hostnames=True,
enable_dns_support=True,
availability_zones=availability_zones,
subnet_configuration=[
ec2.SubnetConfiguration(
name=f'eks-{stage}-1-26-subnet-public',
subnet_type=ec2.SubnetType.PUBLIC,
cidr_mask=24
),
ec2.SubnetConfiguration(
name=f'eks-{stage}-1-26-subnet-private',
subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS,
cidr_mask=24
)
]
)
# Add an S3 VPC endpoint
vpc.add_gateway_endpoint('S3Endpoint',
service=ec2.GatewayVpcEndpointAwsService.S3)
cluster = eks.Cluster(
self, 'EKS-Cluster',
cluster_name=f'eks-{stage}-1-26-cluster',
version=eks.KubernetesVersion.V1_26,
vpc=vpc
)
Деплоємо, перевіряємо:
[simterm]
$ cdk deploy eks-dev-1-26 ... eks-dev-1-26: deploying... [1/1] eks-dev-1-26: creating CloudFormation changeset... ... ✨ Total time: 1243.08s
[/simterm]
1243.08s секунд – 20 хвилин. Окей…
Додавання Stack Tags
Що ще хочеться – це додати власні теги до всіх ресурсів, які буде створювати CDK в цьому стеку.
В app.py використовуємо cdk.Tags, якому передаємо об’єкт AtlasEksStack():
...
app = cdk.App()
eks_stack = AtlasEksStack(app, f'eks-{EKS_STAGE}-1-26',
env=cdk.Environment(account=AWS_ACCOUNT, region=AWS_REGION),
stage=EKS_STAGE
)
cdk.Tags.of(eks_stack).add("environment", EKS_STAGE)
cdk.Tags.of(eks_stack).add("component", "EKS")
app.synth()
Деплоїмо (Total time: 182.67s просто на додавання тегів на ресурси), та перевіряємо теги:
Все є.
Створення NodeGroup
Взагалі скоріш за все будемо використовувати Karpenter замість “класичного” Cluster Autoscaler, бо про Karpenter чув багато гарних відгуків і хочеться його спробувати у ділі, і тоді ноди треба буде переробити, але поки що створимо звичайну Managed NodeGroup за допомогою add_nodegroup_capacity().
До файлу atlas_eks_stack.py додаємо cluster.add_nodegroup_capacity() з Amazon Linux AMI :
...
# Create the EC2 node group
nodegroup = cluster.add_nodegroup_capacity(
'Nodegroup',
instance_types=[ec2.InstanceType('t3.medium')],
desired_size=1,
min_size=1,
max_size=3,
ami_type=eks.NodegroupAmiType.AL2_X86_64
)
Необхідні IAM-ролі CDK має створити сам – подивимось.
У ресурсі eks.Cluster() вказуємо default_capacity=0, щоб СDK не створював власну дефолтну групу:
...
cluster = eks.Cluster(
self, 'EKS-Cluster',
cluster_name=f'eks-{stage}-1-26-cluster',
version=eks.KubernetesVersion.V1_26,
vpc=vpc,
default_capacity=0
)
...
Error: b’configmap/aws-auth configured\nerror: error retrieving RESTMappings to prune: invalid resource batch/v1beta1, Kind=CronJob, Namespaced=true: no matches for kind “CronJob” in version “batch/v1beta1″\n’
Зараз стек вже задеплоєно, запускаємо cdk deploy, щоб оновити – і…
[simterm]
eks-dev-1-26: creating CloudFormation changeset... 1:26:35 PM | UPDATE_FAILED | Custom::AWSCDK-EKS-KubernetesResource | EKSClusterAwsAuthmanifest5D430CCD Received response status [FAILED] from custom resource. Message returned: Error: b'configmap/aws-auth configured\nerror: error retrieving RESTMappings to prune: invalid resource batch/v1beta1, Kind=CronJob, Namespaced=true: no matches for kind "CronJob" in version "bat ch/v1beta1"\n'
[/simterm]
Шта? Якого біса?
aws-auth ConfigMap, Kind=CronJob? Звідки це?
Тобто, мабуть, CDK намагається оновити aws-auth ConfigMap, щоб додати NodeGroup AIM роль, але… Але – що?
Судячи з Гуглу, проблема як раз пов’язана з kubectlLayer, про яку писав вище – aws-eks: cdk should validate cluster version and kubectl layer version.
При чьому проявляється це тільки під час оновлення стеку. Якщо створювати його заново – то все працює. Але тут варто згадати про швидкість роботи CDK/CloudFormation, бо видалення і створення займає хвилин 30-40.
KubectlV26Layer
Ну, все ж довелося фіксити цю проблему.
Добре… Шукаємо просто в браузері – aws-cdk.lambda-layer-kubectl-v26. Є така ліба. Але навіть у PyPi репозиторії приклади на TypeScript – щиро дякую:
Це взагалі проблема при роботі з AWS CDK на Python – дуже багато прикладів все одно на TS.
Окей, ладно – лібу знайшли, вона називається aws-cdk.lambda-layer-kubectl-v26, встановлюємо:
[simterm]
$ pip install aws-cdk.lambda-layer-kubectl-v26
[/simterm]
Додаємо до requirements.txt:
[simterm]
$ pip freeze | grep -i lambda-layer-kubectl >> requirements.txt
[/simterm]
Додаємо у файл atlas_eks_stack.py:
...
from aws_cdk.lambda_layer_kubectl_v26 import KubectlV26Layer
...
# to fix warning "You created a cluster with Kubernetes Version 1.26 without specifying the kubectlLayer property"
kubectl_layer = KubectlV26Layer(self, 'KubectlV26Layer')
...
cluster = eks.Cluster(
self, 'EKS-Cluster',
cluster_name=f'eks-{stage}-1-26-cluster',
version=eks.KubernetesVersion.V1_26,
vpc=vpc,
default_capacity=0,
kubectl_layer=kubectl_layer
)
...
Повторюємо деплой для апдейту вже існуючого стеку, і…
CloudFormation UPDATE_ROLLBACK_FAILED
І маємо іншу помилку, бо після “Error: b’configmap/aws-auth configured\nerror” стек лишився у статусі UPDATE_ROLLBACK_FAILED:
[simterm]
... eks-dev-1-26: deploying... [1/1] eks-dev-1-26: creating CloudFormation changeset... ❌ eks-dev-1-26 failed: Error [ValidationError]: Stack:arn:aws:cloudformation:us-east-1:492***148:stack/eks-dev-1-26/9c7daa50-10f4-11ee-b64a-0a9b7e76090b is in UPDATE_ROLLBACK_FAILED state and can not be updated. ...
[/simterm]
Тут варіант або просто видалити стек і створити заново (вбити ще хвилин 30-40 свого часу), або погуглилити та знайти How can I get my CloudFormation stack to update if it’s stuck in the UPDATE_ROLLBACK_FAILED state.
Спробуємо ContinueUpdateRollback:
Але нє – все-одно стек поломаний:
Тож видаляємо, і йдемо на Фейсбук дивитись котиків, поки воно буде перестворюватись.
Cannot replace cluster “since it has an explicit physical name
На цьому місці ще ловив “Cannot replace cluster “eks-dev-1-26-cluster” since it has an explicit physical name.“, виглядало це так:
[simterm]
... 2:30:45 PM | UPDATE_FAILED | Custom::AWSCDK-EKS-Cluster | EKSCluster676AE7D7 Received response status [FAILED] from custom resource. Message returned: Cannot replace cluster "eks-dev-1-26-cluster" since it has an explicit physical name. Either rename the cluster or remove the "name" configuration ...
[/simterm]
Але на цей раз не зарепродьюсилось, хоча треба мати на увазі, бо точно вилізе ще колись.
Добре, отже тепер вже маємо VPC, EKS Cluster та NodeGroup – час подумати про IAM.
IAM Role та aws-auth ConfigMap
Що треба зробити наступним – це створити IAM-роль, яку можна буде assume для отримання доступу до кластеру.
Поки що без всяких RBAC та юзер-груп – просто роль, щоб потім виконати aws eks update-kubeconfig.
Використовуємо aws_cdk.aws_iam.Role() і aws_cdk.aws_eks.AwsAuth():
from aws_cdk import (
...
aws_iam as iam,
...
)
...
# Create an IAM Role to be assumed by admins
masters_role = iam.Role(
self,
'EksMastersRole',
assumed_by=iam.AccountRootPrincipal()
)
# Attach an IAM Policy to that Role so users can access the Cluster
masters_role_policy = iam.PolicyStatement(
actions=['eks:DescribeCluster'],
resources=['*'], # Adjust the resource ARN if needed
)
masters_role.add_to_policy(masters_role_policy)
cluster.aws_auth.add_masters_role(masters_role)
# Add the user to the cluster's admins
admin_user = iam.User.from_user_arn(self, "AdminUser", user_arn="arn:aws:iam::492***148:user/arseny")
cluster.aws_auth.add_user_mapping(admin_user, groups=["system:masters"])
masters_role – роль, яку можна буде assume будь-ким з AWS-аккаунту, а admin_user – мій IAM юзер для “прямого” доступу до кластеру.
CfnOutput
Outputs CloudFormation-стеку. Наскільки пам’ятаю, може використовуватись для cross-stack передачі values, але нам більше треба для отримання ARN-у masters_role:
from aws_cdk import (
...
Stack, CfnOutput
)
...
# Output the EKS cluster name
CfnOutput(
self,
'ClusterNameOutput',
value=cluster.cluster_name,
)
# Output the EKS master role ARN
CfnOutput(
self,
'ClusterMasterRoleOutput',
value=masters_role.role_arn
)
Деплоїмо:
[simterm]
... Outputs: eks-dev-1-26.ClusterMasterRoleOutput = arn:aws:iam::492***148:role/eks-dev-1-26-EksMastersRoleD1AE213C-1ANPWK8HZM1W5 eks-dev-1-26.ClusterNameOutput = eks-dev-1-26-cluster
[/simterm]
Налаштування kubectl з AWS CLI
Ну й врешті-решт, після всіх страждань – спробуємо отримати доступ до кластеру.
Спочатку через master_role – оновлюємо ~/.aws/config:
[profile work] region = us-east-1 output = json [profile work-eks] role_arn = arn:aws:iam::492***148:role/eks-dev-1-26-EksMastersRoleD1AE213C-1ANPWK8HZM1W5 source_profile = work
У [profile work-eks] виконуємо IAM Role Assume – використовуємо нашу master_role, використовуючи ACCESS/SECRET ключи профайлу [work].
Створюємо kube-config:
[simterm]
$ aws --profile work-eks eks update-kubeconfig --region us-east-1 --name eks-dev-1-26-cluster --alias eks-dev-1-26 Added new context eks-dev-1-26 to /home/setevoy/.kube/config
[/simterm]
І перевіряємо доступ:
[simterm]
$ kubectl get node NAME STATUS ROLES AGE VERSION ip-10-0-2-60.ec2.internal Ready <none> 19h v1.26.4-eks-0a21954
[/simterm]
Аналогічно, якщо використовувати персональний AIM-аккаунт, тобто user_arn="arn:aws:iam::492***148:user/arseny":
[simterm]
$ aws --profile work eks update-kubeconfig --region us-east-1 --name eks-dev-1-26-cluster --alias eks-dev-1-26-personal
[/simterm]
“Вона працює” (с)
По результату можу сказати одне – особисто я не готовий брати відповідальність за роботу такого стеку у production.
Можливо, якщо з CDK попрацювати ще, і знати основні його підводні камені, та згадати всі “особливості” CloudFormation – то з ними можна жити. Але поки що – ні, взагалі не хочеться.








