Translate

понеділок, 11 травня 2020 р.

Pulumi. Part II: AWS Subnets and Fargate

Минулого разу  ми торкнулись причин появи нового IaС продукту Pulumi та спробували розібратись із базовими принципами його роботи на прикладі створення простого AWS S3 buсket-у. Наразі ж спробуємо описати на Python-інтерфейсі Pulumi власний VPC із підмережами та ECS Fargate кластер, тобто значно ближчий до реального життя випадок. Також побачимо як користуватись S3-бекендом для збереження стейтів (checkpoints в термінології Pulumi), та що робити із відсутністю lock-ів на паралельний запуск того ж коду. У кінці спробуємо поговорити про нинішній стан речей та перспективи Pulumi. Всі описані нижче приклади можна буде знайти у наступному github-проекті https://github.com/ipeacocks/pulumi-aws-example

Отже для подальших дій необхідні:

1. CUSTOM VPC/SUBNETS IN FEW AZs

Якою має бути мережа, котру буде не дуже соромно лишати для prod-цілей? Має бути як мінімум декілька публічний підмереж у різних зонах доступності регіону (AZ, availability zone), декілька приватних та стільки ж NAT-шлюзів для з'єднання приватних підмереж із зовнішнім світом. NAT-шлюзи зобов'язані мати постійні IP-адреси (EIP) і лежати в публічних підмережах аналогічних зон доступності. Трафік публічних підмереж має прямувати на Internet-gateway, а приватних - на відповідний NAT-гейтвей своєї ж зони доступності. Спробуємо це реалізувати.

Експортуємо значення Programmatic Access:

$ export AWS_ACCESS_KEY_ID=AKIA1234563J76A
$ export AWS_SECRET_ACCESS_KEY=/xLmpmdp1V3abcdefghklmnopabcdefg2nKRDKO
$ export AWS_REGION=us-east-1

Створимо S3-bucket для стейтів Pulumi:

$ aws s3api create-bucket \
      --bucket pulumi-states-zeezpha \
      --region us-east-1

$ aws s3api put-bucket-versioning \
      --bucket pulumi-states-zeezpha \
      --versioning-configuration Status=Enabled

Назва бакету має бути унікальною, тому необхідно обрати якусь власну назву.

Укажемо для Pulumi, що ми збираємось зберігати стейти в створеному вище бакеті S3:

$ pulumi login s3://pulumi-states-zeezpha

Окрім AWS S3 Pulumi підтримує також Azure Blob, Google Cloud та локальне збереження.

Скористуємось шаблоном aws-python для створення файлів необхідних для Pulumi:

$ mkdir pulumi-infra-az
$ cd pulumi-infra-az

$ pulumi new aws-python
This command will walk you through creating a new Pulumi project.

Enter a value or leave blank to accept the (default), and press <ENTER>.
Press ^C at any time to quit.

project name: (pulumi-infra-az)
project description: (A minimal AWS Python Pulumi program) 
Created project 'pulumi-infra-az'

stack name: (dev) pulumi-infra-az_dev
Enter your passphrase to protect config/secrets: 
Re-enter your passphrase to confirm: 
Created stack 'pulumi-infra-az_dev'

Enter your passphrase to unlock config/secrets
    (set PULUMI_CONFIG_PASSPHRASE to remember): 
aws:region: The AWS region to deploy into: (us-east-1) 
Saved config

Your new project is ready to go! 
...

У разі використання стореджів для зберігання стейтів відмінних від app.pulumi.com Pulumi вимагає введення додаткового паролю (PULUMI_CONFIG_PASSPHRASE) для шифрування всіх змінних, що будуть помічені як секрети.

Список всіх доступних та активний стек можна побачити, виконавши наступну команду:

$ pulumi stack ls
NAME                  LAST UPDATE     RESOURCE COUNT
pulumi-infra-az_dev*  22 minutes ago  27

Для створення нового стеку зовсім не обов'язково користуватись pulumi new командою, з чим чудово допомагає init:

$ pulumi stack init

Повернемось до роботи та створимо Python venv та встановимо всі необхідні залежності після його активації:

$ python3 -m venv venv
$ source venv/bin/activate
$ pip3 install -r requirements.txt

Дещо відредагуємо автоматично створені файли метаданих:

$ vim Pulumi.yaml
name: pulumi-infra-az
description: AWS Infrastructure to run instances with Pulumi
runtime: python

В Pulumi.yaml додаткових даних не має бути. Відредагуємо файл стеку Pulumi.pulumi-infra-az_dev.yaml:

$ vim Pulumi.pulumi-infra-az_dev.yaml

Де:
  • encryptionsalt - закриптований пароль, що було введено на етапі створення стеку з pulumi new.
  • aws:region - AWS-регіон, обов'язковий параметр.
  • private_subnet_cidrs - перелік публічних підмереж
  • public_subnet_cidrs - приватні підмережі
  • vpc_cidr - AWS VPC CIDR
  • zones_amount - кількість зон доступності

Для прикладу винесемо окремо функцію отримання переліку доступних AZ:

$ vim utils.py

І найцікавіше - файл опису інфраструктури:

$ vim __main__.py


Отже, в лістингу відбувається наступне:

  1. із config.require_object() ми вичитали множину публічних та приватних мереж із налаштувань стеку (файл Pulumi.pulumi-infra-az_dev.yaml)
  2. створили VPC, internet gateway, таблицю роутів public_rt для майбутніх публічних мереж. Вони створені до for циклу, адже не залежать від майбутніх мереж
  3. for циклом обходимо масив zip(zones, private_subnet_cidrs, public_subnet_cidrs) і створюємо 3 публічні та 3 приватні мережі, 3 NAT-гейтвея в кожній публічній мережі і ці ж гейтвеї описані в таблиці роутингу трафіку для кожної приватної мережі.
  4. в кінці робимо export змінних задля використання їх надалі

Це все, запускаємо код:

$ pulumi up   
Enter your passphrase to unlock config/secrets
    (set PULUMI_CONFIG_PASSPHRASE to remember):
Previewing update (pulumi-infra-az_dev):
     Type                              Name                                 Plan     
 +   pulumi:pulumi:Stack               pulumi-infra-az-pulumi-infra-az_dev  create   
 +   ├─ aws:ec2:Eip                    pulumi-eip-us-east-1a                create   
 +   ├─ aws:ec2:Vpc                    pulumi-vpc                           create   
 +   ├─ aws:ec2:Eip                    pulumi-eip-us-east-1b                create   
 +   ├─ aws:ec2:Eip                    pulumi-eip-us-east-1c                create   
 +   ├─ aws:ec2:InternetGateway        pulumi-igw                           create   
 +   ├─ aws:ec2:Subnet                 pulumi-public-subnet-us-east-1a      create   
 +   ├─ aws:ec2:Subnet                 pulumi-private-subnet-us-east-1a     create   
 +   ├─ aws:ec2:Subnet                 pulumi-public-subnet-us-east-1b      create   
 +   ├─ aws:ec2:Subnet                 pulumi-private-subnet-us-east-1b     create   
 +   ├─ aws:ec2:Subnet                 pulumi-private-subnet-us-east-1c     create   
 +   ├─ aws:ec2:Subnet                 pulumi-public-subnet-us-east-1c      create   
 +   ├─ aws:ec2:RouteTable             pulumi-public-rt                     create   
 +   ├─ aws:ec2:NatGateway             pulumi-natgw-us-east-1a              create   
 +   ├─ aws:ec2:NatGateway             pulumi-natgw-us-east-1c              create   
 +   ├─ aws:ec2:NatGateway             pulumi-natgw-us-east-1b              create   
 +   ├─ aws:ec2:RouteTableAssociation  pulumi-public-rta-us-east-1a         create   
 +   ├─ aws:ec2:RouteTableAssociation  pulumi-public-rta-us-east-1b         create   
 +   ├─ aws:ec2:RouteTableAssociation  pulumi-public-rta-us-east-1c         create   
 +   ├─ aws:ec2:RouteTable             pulumi-private-rt-us-east-1a         create   
 +   ├─ aws:ec2:RouteTable             pulumi-private-rt-us-east-1c         create   
 +   ├─ aws:ec2:RouteTable             pulumi-private-rt-us-east-1b         create   
 +   ├─ aws:ec2:RouteTableAssociation  pulumi-private-rta-us-east-1a        create   
 +   ├─ aws:ec2:RouteTableAssociation  pulumi-private-rta-us-east-1c        create   
 +   └─ aws:ec2:RouteTableAssociation  pulumi-private-rta-us-east-1b        create   

Resources:
    + 25 to create

Do you want to perform this update? yes
Updating (pulumi-infra-az_dev):
     Type                              Name                                 Status   
 +   pulumi:pulumi:Stack               pulumi-infra-az-pulumi-infra-az_dev  created   
 +   ├─ aws:ec2:Eip                    pulumi-eip-us-east-1a                created   
...   
 +   ├─ aws:ec2:RouteTable             pulumi-private-rt-us-east-1a         created   
 +   └─ aws:ec2:RouteTableAssociation  pulumi-private-rta-us-east-1a        created   

Outputs:
    pulumi-az-amount         : 3
    pulumi-private-subnet-ids: [
        [0]: "subnet-0247a0dc1c4908be5"
        [1]: "subnet-0f6782bc1ba956151"
        [2]: "subnet-07486fe231764e33a"
    ]
    pulumi-public-subnet-ids : [
        [0]: "subnet-04e7996f3136725ff"
        [1]: "subnet-07d007de94f1c83e4"
        [2]: "subnet-04d494b32373b9f2a"
    ]
    pulumi-vpc-id            : "vpc-007606812e1b879d3"

Resources:
    + 25 created

Duration: 3m6s

Permalink: https://pulumi-states-zeezpha.s3.amazonaws.com/.pulumi/stacks/pulumi-infra-az_dev.json?...7addac8bdc5cc4d9861


Переглянути експортовані дані можна в будь-який час за допомогою команди output:

$ pulumi stack output
Current stack outputs (4):
    OUTPUT                     VALUE
    pulumi-az-amount           3
    pulumi-private-subnet-ids  ["subnet-0247a0dc1c4908be5","subnet-0f6782bc1ba956151","subnet-07486fe231764e33a"]
    pulumi-public-subnet-ids   ["subnet-04e7996f3136725ff","subnet-07d007de94f1c83e4","subnet-04d494b32373b9f2a"]
    pulumi-vpc-id              vpc-007606812e1b879d3



2. AWS ECS FARGATE CLUSTER

Тепер створимо ECS Fargate кластер та сервіс, що буде працювати із nginx докер-образом. У якості мережі оберемо створену вище. Сервіс буде доступний через ALB балансувальник, що лежатиме в публічній мережі.

Код розмістимо в іншій окремій директорії і його буде обслуговувати новий стек. Не буду зайвий раз коментувати ті ж самі дії:

$ mkdir pulumi-ecs-fargate
$ cd pulumi-ecs-fargate

$ pulumi new aws-python
This command will walk you through creating a new Pulumi project.

Enter a value or leave blank to accept the (default), and press <ENTER>.
Press ^C at any time to quit.

project name: (pulumi-ecs-fargate)
project description: (A minimal AWS Python Pulumi program)
Created project 'pulumi-ecs-fargate'

stack name: (dev) pulumi-ecs-fargate_dev
Enter your passphrase to protect config/secrets:
Re-enter your passphrase to confirm:
Created stack 'pulumi-ecs-fargate_dev'

Enter your passphrase to unlock config/secrets
    (set PULUMI_CONFIG_PASSPHRASE to remember):
aws:region: The AWS region to deploy into: (us-east-1)
Saved config

Your new project is ready to go!
...

Активуємо python venv:

$ python3 -m venv venv
$ source venv/bin/activate
$ pip3 install -r requirements.txt

Редагуємо вміст щойно створеної директорії:

$ vim Pulumi.pulumi-ecs-fargate_dev.yaml

encryptionsalt, як і в попередньому випадку, буде мати індивідуальне значення у залежності від обраного паролю. А у якості регіону обираємо вже традиційний us-east-1.

Метадані проекту:

$ vim Pulumi.yaml

Та основний файл проекту - __main__.py:

$ vim __main__.py


Отже цього разу ми вичитуємо вихідні змінні попереднього стеку StackReference(f"pulumi-infra-az_dev"), вони потрібні будуть дещо пізніше. Далі ми описуємо security-групу для балансувальника, сам балансувальник, target-групу для нього, listener-а, котрий буде підключений до того ж балансувальника, task execution роль і зрештою task_definition та сам сервіс. Щодо логіки створення ECS Fargate кластеру можна проконсультуватись із офіційною документацією. Тобто той самий декларативний підхід, що ми бачили в тому ж Terraform.

Запускаємо створення кластера:

$ pulumi up
Enter your passphrase to unlock config/secrets
    (set PULUMI_CONFIG_PASSPHRASE to remember): 
Previewing update (pulumi-ecs-fargate_dev):
     Type                             Name                                       Plan       
 +   pulumi:pulumi:Stack              pulumi-ecs-fargate-pulumi-ecs-fargate_dev  create
 +   ├─ aws:iam:Role                  pulumi-app-te-role                         create
 +   ├─ aws:ecs:Cluster               pulumi-app-cluster                         create
 +   ├─ aws:ec2:SecurityGroup         pulumi-app-sg                              create
 +   ├─ aws:lb:TargetGroup            pulumi-app-tg                              create
 +   ├─ aws:iam:RolePolicyAttachment  pulumi-app-te-policy-attach                create
 +   ├─ aws:ecs:TaskDefinition        pulumi-app-task-def                        create
 +   ├─ aws:lb:LoadBalancer           pulumi-app-alb                             create
 +   ├─ aws:lb:Listener               pulumi-app-listener                        create
 +   └─ aws:ecs:Service               pulumi-app-svc                             create

Resources:
    + 10 to create

Do you want to perform this update? yes
Updating (pulumi-ecs-fargate_dev):
     Type                             Name                                       Status      
 +   pulumi:pulumi:Stack              pulumi-ecs-fargate-pulumi-ecs-fargate_dev  created
 +   ├─ aws:iam:Role                  pulumi-app-te-role                         created
...   
 +   └─ aws:ecs:Service               pulumi-app-svc                             created

Outputs:
    url: "pulumi-app-alb-f80aa12-414577325.us-east-1.elb.amazonaws.com"

Resources:
    + 10 created

Duration: 3m49s

Permalink: https://pulumi-states-zeezpha.s3.amazonaws.com/.pulumi/stacks/pulumi-ecs-fargate_dev.json?X-Amz-Algorithm=AWS4-HMAC-SHA256...4b0ba0813247c1

Чудово, перевіримо роботу додатка, перейшовши за посиланням в Outputs:


Приклад із Fargate майже повністю скопійований звідси https://github.com/pulumi/examples/tree/master/aws-py-fargate. А тут можна побачити значно більше прикладів в т.ч. на інших мовах програмування.


3. WHAT'S NEXT?

Наразі логічне питання, що з цим робити? Чи варто мігрувати із інших IaC систем на Pulumi? Звісно все залежить від вдоволеності теперішніми продуктами та цілей. Загалом Pulumi демонструє якісну і передбачувану роботу, але, як на мене, думати про міграцію ще зарано в силу наступних обставин:
  • надто молодий продукт, перша публічна версія була лише 2018 року
  • замало документації. Знайти непогані приклади використання Pulumi можна тільки на GitHub, скориставшись його ж пошуком. Якщо вони і є, то не обов'язково на бажаній для вас мові. Найкраща ситуація для JavaScript/TypeScript.
  • lock-и (тобто заборона запустити одночасно той самий код) присутні лише в платному тарифному плані Pulumi із власним бекендом. Хоч це можливо і не велика проблема, адже є чудові бібліотеки, які легко реалізують подібний функціонал. І варто не забувати, що в Terraform локи зі сторонніми бекендами з'явились далеко не одразу.
  • cкладно уявити, як буде виглядати коректний опис та організація комплексної інфраструктури. Це ж саме досі стосується і Terraform-у. Я прийшов до висновку, що ліпше за все працює логічна схема розміщення коду ресурсів: директорія із назвою сервіс А в котрій знаходяться всі ресурси сервісу А (балансувальники, таргет групи, сервіси, домени і т.п.)
  • якщо в команді відсутні домовленості як має виглядати код, гнучкість Pulumi може зіграти злий жарт. На HCL явно менше способів написати дуже погано
  • описувати інфраструктуру на Python може бути складніше, ніж робота із DSL мовами. Але вивчення мови програмування загального вжитку - дуже корисна річ навіть у недалекій перспективі.
Але разом з цим це досить цікаво і виглядає багатообіцяюче! З Pulumi навіть можна читати стейти Terraform чи дані подібних систем і вже дані з них використовувати для нових сервісів. Тобто зовсім не обов'язково все руйнувати і будувати заново. Можливо вивчення Pulumi сьогодні спростить ваше життя завтра.


Посилання:
https://github.com/retgits/pulumi-blogs/tree/part2-blog
https://github.com/pulumi/examples/blob/master/README.md#python
https://github.com/CliffJumper/pulumi-py-tf2-infra
https://github.com/CliffJumper/pulumi-py-tf2-server
https://github.com/pulumi/pulumi-awsx/tree/master/python/pulumi_aws_infra
https://www.pulumi.com/docs/intro/vs/terraform/
https://www.pulumi.com/docs/intro/concepts/stack/
https://www.pulumi.com/docs/intro/concepts/programming-model/#stack-outputs
https://www.pulumi.com/docs/intro/concepts/programming-model/#aliases
https://medium.com/it-dead-inside/deploy-aws-fargate-clusters-with-pulumi-e06637e6821d
https://medium.com/@kscloud/how-to-program-infrastructure-with-pulumi-part-1-a47d5edb913f
https://www.slideshare.net/JonasHecht1/infrastructureascode-with-pulumi-better-than-all-the-others-like-ansible
https://www.thehumblelab.com/iac-vsphere-pulumi/
https://hashnode.com/post/why-i-switched-from-terraform-to-pulumi-python-ck3d8cico00sjo8s1i2j2c94m
https://www.geekwire.com/2018/meet-pulumi-seattle-grown-cloud-startup-wants-development-platform-multicloud-era/
https://www.infoq.com/podcasts/infrastructure-code-multi-cloud/
https://thenewstack.io/pulumi-uses-real-programming-languages-to-enforce-cloud-best-practices/

Немає коментарів:

Опублікувати коментар