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 – то з ними можна жити. Але поки що – ні, взагалі не хочеться.