В продолжение/дополнение постов Prometheus: AWS EC2 service discovery и AWS: настройка VPC peering — пример настройки VPC peering в шаблонах стеков CloudFormation.
Идея следующая:
- создадим стек monitor — он будет имитировать стек мониторинга
- создадим стек application — он будет имитировать стек приложения
- application должен будет запросить пиринг с VPC из стека monitor, что бы Prometheus в стеке monitor смог использовать service discovery
ec2_sd_configs
в стеке application
Документация — тут>>> и тут>>>.
Что бы сделать запрос на создание peering connection — надо найти VPC ID из стека monitor.
Для этого — добавим в Outputs
шаблона monitor вывод VPC ID, а потом используем Fn::ImportValue
в шаблоне application, что бы выполнить запрос на пиринг.
Используем существующий шаблон vpc_ec2_stack.json
, копируем его:
[simterm]
$ cp ~/Work/RTFM/Github/setevoy-aws-templates/vpc_ec2_stack.json vpc_monitor_stack.json $ cp ~/Work/RTFM/Github/setevoy-aws-templates/vpc_ec2_stack.json vpc_application_stack.json
[/simterm]
Получившиеся в результате шаблоны доступны в Github:
- стек monitor —
vpc_peering_accepter.json
- стек application —
vpc_peering_requester.json
Не забываем поменять блоки адресов для VPC в обоих шаблонах, что они не пересекались, иначе получим ошибку «VpcPeeringConnection failed to stabilize. State: [failed]» и «Failed due to incorrect VPC-ID, Account ID, or overlapping CIDR range«.
Например для стека monitor:
... "VPCCIDRBlock": { "Description": "VPC CidrBlock", "Type": "String", "Default": "10.0.0.0/16" }, "PublicSubnetCIDR": { "Description": "Public Subnet CIDR", "Type": "String", "Default": "10.0.1.0/24" }, ...
И для стека application:
... "VPCCIDRBlock": { "Description": "VPC CidrBlock", "Type": "String", "Default": "10.1.0.0/16" }, "PublicSubnetCIDR": { "Description": "Public Subnet CIDR", "Type": "String", "Default": "10.1.0.0/24" }, ...
Запрос на создание пиринга будет выполняться из стека application к стеку monitor.
Стек monitor будет «статичным», т.е. — он «уже есть» (сначала будет разворачиваться мониторинг, а потом к нему — добавляться стеки с приложениями), и его параметры известы, поэтому их мы будем передавать в создаваемые стеки приложений через параметры в шаблоне monitor.
Параметры же создаваемых стеков (application в данном случае) — неизвестны, поэтому их мы будем экспортировать в Outputs
новых стеков, а потом эти значения использовать в Fn::ImportValue
для стека monitor.
Перед тем, как начать — небольшая заметка по импортам и экспортам данных: при первой попытке создания стеков — у меня получилось залочить два стека так, что ни изменить, ни удалить их нельзя было. Проблема заключалась в том, что стек monitor экспортировал в Outputs
свой VPC ID и свою подсеть, которые импортировались в стеке application. А стек application, в свою очередь, экспортировал свою подсеть и VpcPeeringConnectionId
, которая импортировались в стеке monitor для создания маршрута. В результате — получилась взаминая связь между стеками, которая не позволяла удалить один из стеков, т.к. его данные использовались в другом. Подробнее про ограничения см. в документации Fn::ImportValue
.
Содержание
AWS::EC2::VPCPeeringConnection
В шаблоне стека application добавляем параметр MonitorVPCID
:
... "MonitorVPCID": { "Description": "Monitoring VPC ID to be used to request peering connection", "Type": "String", "Default": "vpc-00d98968" }, ...
Добавляем ресурс AWS::EC2::VPCPeeringConnection
:
... "VPCPeeringConnection": { "Type": "AWS::EC2::VPCPeeringConnection", "Properties": { "VpcId": { "Ref": "VPC" }, "PeerVpcId": { "Ref": "MonitorVPCID" } } }, ...
Стек monitor уже создан.
Создаём стек appliсation:
[simterm]
$ aws --profile btrm-mon cloudformation create-stack --stack-name application --template-body file://vpc_application_stack.json --disable-rollback
[/simterm]
Проверяем статус пиринга:
[simterm]
$ aws --profile btrm-mon ec2 describe-vpc-peering-connections --filters Name=vpc-peering-connection-id,Values=pcx-a8427bc1 --query '[VpcPeeringConnections[*].Status.Message]' --output text Active
[/simterm]
Т.к. обе VPC принадлежат одному пользователю — то запрос на пиринг принимается автоматически.
В панели управления:
Теперь надо обновить таблицы маршрутизации обоих стеков.
AWS::EC2::Route
Для этого потребуется:
- в стек monitor добавить параметр с именем стека application
- в стек monitor добавить ресурс
AWS::EC2::Route
, который будет:- с помощью
Fn::ImportValue
получать значение дляDestinationCidrBlock
из стека application — его параметрPublicSubnetCIDR
- с помощью
Fn::ImportValue
получатьVpcPeeringConnectionId
из стека application — его ресурсVPCPeeringConnection
- с помощью
- в стек application добавить параметр с CIDR подсети (или всей VPC) стека monitor
- в стек application добавить в
Outputs
экспорт егоPublicSubnetCIDR
, что бы его мог использовать стек monitor - в стек application добавить в
Outputs
экспорт егоVpcPeeringConnectionId
- в стек application добавить ещё один ресурс
AWS::EC2::Route
, который будет:- использоват параметр
DestinationCidrBlock
, в котором указывается сеть стека monitor — егоPublicSubnetCIDR
- использовать
VpcPeeringConnectionId
из стекаmonitor
— его ресурсVPCPeeringConnection
- использоват параметр
Route стека application
Сначала обновляем стек application — добавляем параметр с подсетью стека monitor:
... "MonitorPublicSubnet": { "Description": "Stack Name to be used to add routes", "Type": "String", "Default": "10.0.1.0/24" }, ...
И добавляем новый роут:
... "PeeringRouteToMonitorStackSubnet": { "Type": "AWS::EC2::Route", "Properties": { "RouteTableId": { "Ref": "PublicRouteTable" }, "DestinationCidrBlock": { "Ref": "MonitorPublicSubnet" }, "VpcPeeringConnectionId": { "Ref": "VPCPeeringConnection" } } }, ...
Обновляем его Outputs
, добавляем экспорт значений для импорта в стеке monitor — PublicSubnetCIDR
и VPCPeeringConnectionID
:
... "PublicSubnetCIDR" : { "Description" : "Own Subnet CIDR to be used in the monitor's stack route", "Value" : {"Ref" : "PublicSubnetCIDR"}, "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-PublicSubnetCIDR" } } }, "VPCPeeringConnectionID" : { "Description" : "VPD ID to a Peering connection with", "Value" : {"Ref" : "VPCPeeringConnection"}, "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-VPCPeeringConnectionID" } } } ...
Обновляем стек:
[simterm]
$ aws --profile btrm-mon cloudformation update-stack --stack-name application --template-body file://vpc_application_stack.json
[/simterm]
Проверяем Outputs
:
Проверяем маршруты:
Route стека monitor
Обновляем шаблон для стека monitor.
Добавляем параметр с именем стека, который будет подключаться (при доабвлении новых стеков с новыми приложениями — просто добавим новые параметры в стек monitor с их именами и новые ресурсы роутов):
... "ApplicationRouteStackName": { "Description": "Stack Name to be used to add routes", "Type": "String", "Default": "application" }, ...
Далее — ресурс AWS::EC2::Route
будет аналогичен ресурсу стека application, но тут можем использовать cross-stack ссылки на Outputs
стека application:
... "PeeringRouteToApplicationSubnet": { "Type": "AWS::EC2::Route", "Properties": { "RouteTableId": { "Ref": "PublicRouteTable" }, "DestinationCidrBlock": { "Fn::ImportValue": {"Fn::Sub" : "${ApplicationRouteStackName}-PublicSubnetCIDR"} }, "VpcPeeringConnectionId": { "Fn::ImportValue": {"Fn::Sub" : "${ApplicationRouteStackName}-VPCPeeringConnectionID"} } } }, ...
Тут через Fn::ImportValue
мы получаем значения PublicSubnetCIDR
и VPCPeeringConnectionID
из Outputs
стека application.
Обновляем стек monitor:
[simterm]
$ aws --profile btrm-mon cloudformation update-stack --stack-name monitor --template-body file://vpc_monitor_stack.json
[/simterm]
Проверяем его маршруты:
Пробуем пинг с EC2 в стеке monitor к EC2 в стеке application, используя приватный IP:
[simterm]
$ ssh [email protected] -i setevoy-testing-ohio.pem 'ip a s eth0 | grep -w inet; ping -c 1 10.1.0.141' The authenticity of host '18.217.222.6 (18.217.222.6)' can't be established. ECDSA key fingerprint is SHA256:0L83Mz5D2DFGBrIzov7E7YLWwOvgZNCMycLLkgp7x20. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '18.217.222.6' (ECDSA) to the list of known hosts. inet 10.0.1.221/24 brd 10.0.1.255 scope global eth0 PING 10.1.0.141 (10.1.0.141) 56(84) bytes of data. 64 bytes from 10.1.0.141: icmp_seq=1 ttl=64 time=0.477 ms --- 10.1.0.141 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.477/0.477/0.477/0.000 ms
[/simterm]
И обратно — с EC2 в стеке application к EC2 в стеке monitor:
[simterm]
$ ssh [email protected] -i setevoy-testing-ohio.pem 'ip a s eth0 | grep -w inet; ping -c 1 10.0.1.221' The authenticity of host '18.219.246.166 (18.219.246.166)' can't be established. ECDSA key fingerprint is SHA256:Gnz/KbfZ1hw2p6eKuo4WuVFSstzkBRMgTFmNhD9c6uU. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '18.219.246.166' (ECDSA) to the list of known hosts. inet 10.1.0.141/24 brd 10.1.0.255 scope global eth0 PING 10.0.1.221 (10.0.1.221) 56(84) bytes of data. 64 bytes from 10.0.1.221: icmp_seq=1 ttl=64 time=0.408 ms --- 10.0.1.221 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.408/0.408/0.408/0.000 ms
[/simterm]
Готово.