В Bright Inventions мы часто используем CloudFormation для настройки инфраструктуры, так как это позволяет нам легко версионировать и отслеживать изменения. Первая часть инфраструктуры, которая нам нужна, — это кластер ECS. Кластер — это логическая группа задач/контейнеров, работающих внутри ECS. В частности, поскольку мы будем использовать Тип запуска EC2, кластер также можно рассматривать как группу экземпляров EC2 с установленным агентом ECS.
"ECSMainCluster": {
"Type": "AWS::ECS::Cluster",
"Properties": {
"ClusterName": "app-stack-main"
}
},
"ECSAutoScalingGroup": {
"Type": "AWS::AutoScaling::AutoScalingGroup",
"Properties": {
"VPCZoneIdentifier": [
{ "Ref": "PrivateASubnet" },
{ "Ref": "PrivateBSubnet" }
],
"LaunchConfigurationName": {
"Ref": "ContainerHostInstances"
},
"MinSize": "1",
"MaxSize": "6",
"DesiredCapacity": "1",
"Tags": [
{
"Key": "Name",
"Value": "app-stack-ecs",
"PropagateAtLaunch": true
}
]
},
"CreationPolicy": {
"ResourceSignal": {
"Timeout": "PT5M"
}
},
"UpdatePolicy": {
"AutoScalingReplacingUpdate": {
"WillReplace": "true"
}
}
}
Как вы можете видеть выше, ECSMainCluster
в основном является объявлением. Далее следует группа автоматического масштабирования, которая будет запускать экземпляры EC2 и управлять ими. В VPCZoneIdentifier
перечислены 2 подсети VPC, созданные в отдельных зонах доступности. Это жизненно важно для доступности, так как экземпляры EC2 работают на физически отдельном оборудовании. Для краткости я опустил их конфигурацию в этом посте. Однако, если вам интересна эта тема, переходите в этот пост. Указанный LaunchConfigurationName
с именем ContainerHostInstances
описывает, как должен выглядеть экземпляр EC2.
"ContainerHostInstances": {
"Type": "AWS::AutoScaling::LaunchConfiguration",
"Properties": {
"ImageId": "ami-880d64f1",
"SecurityGroups": [
{ "Ref": "ECSSecurityGroup" }
],
"InstanceType": "t2.medium",
"IamInstanceProfile": { "Ref": "ECSHostEC2InstanceProfile" },
"KeyName": "private-key-pair",
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"",
[
"#!/bin/bash -xe\n",
"echo ECS_CLUSTER=",
{
"Ref": "ECSMainCluster"
},
" >> /etc/ecs/ecs.config\n",
"yum install -y aws-cfn-bootstrap\n",
"/opt/aws/bin/cfn-signal -e $? ",
" --stack ",
{
"Ref": "AWS::StackName"
},
" --resource ECSAutoScalingGroup ",
" --region ",
{
"Ref": "AWS::Region"
},
"\n"
]
]
}
}
}
},
"ECSHostEC2InstanceProfile": {
"Type": "AWS::IAM::InstanceProfile",
"Properties": {
"Path": "/",
"Roles": [
{
"Ref": "ECSHostEC2Role"
}
]
}
},
Первым важным свойством является ImageId
, который использует Amazon ECS-оптимизированный Linux AMI ID. Далее у нас есть группа безопасности, которая добавляет правила для входящего трафика на портах приложений. Затем у нас есть IamInstanceProfile
, который ссылается на профиль экземпляра ECSHostEC2InstanceProfile
, который, в свою очередь, предполагает политику ролей, требуемую агентом ECS для развертывания и настройки контейнеров. Внутри UserData
мы определяем сценарий оболочки, который информирует агент ECS о кластере, в котором он работает. Я опускаю определение ECSHostEC2Role
, так как оно хорошо описано в документации.
С учетом вышеизложенного мы теперь готовы развернуть кластер ECS с помощью шаблона CloudFormation. Однако кластер без контейнеров довольно бессмысленен.
Служба ECS и определение задачи
На жаргоне AWS служба ECS описывает минимальную конфигурацию, необходимую для развертывания и запуска определения задачи. Определение задачи, в свою очередь, описывает, как настроить и запустить набор контейнеров, образующих единый логический компонент.
"EmailSenderService": {
"Type": "AWS::ECS::Service",
"Properties": {
"Cluster": { "Ref": "ECSMainCluster" },
"DesiredCount": 2,
"DeploymentConfiguration": { "MinimumHealthyPercent": 50 },
"Role": { "Ref": "ECSServiceRole" },
"TaskDefinition": { "Ref": "EmailSenderTask" }
}
},
"EmailSenderTask": {
"Type": "AWS::ECS::TaskDefinition",
"Properties": {
"Family": "app-stack-email-sender",
"ContainerDefinitions": [{
"Name": "app-stack-email-sender",
"Essential": "true",
"Image": { "Ref": "EmailSenderTaskDockerImage" },
"LogConfiguration": {
"LogDriver": "awslogs",
"Options": {
"awslogs-group": { "Ref": "EmailSenderLogsGroup" },
"awslogs-region": { "Ref": "AWS::Region" },
"awslogs-stream-prefix": "email-sender",
"awslogs-datetime-format": "%Y-%m-%d %H:%M:%S.%L"
}
},
"PortMappings": [{ "ContainerPort": 8080 }],
"Environment": [{
"Name": "DEPLOY_ENV",
"Value": { "Ref": "DeployEnv" }
}]
}]
}
},
"EmailSenderLogsGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "app-stack-email-sender",
"RetentionInDays": 14
}
}
EmailSenderService
довольно просто понять. EmailSenderTask
определяет один контейнер. В определении задачи app-stack-email-sender
указано, что Image
— это ссылка на параметр, передаваемый в шаблон CloudFormation при создании или обновлении стека. Его значение должно быть именем образа Docker, который может быть извлечен агентом ECS. Репозиторий может быть как публичным, так и приватным. При размещении собственного частного репозитория образов Docker необходимо убедиться, что агент ECS имеет правильные учетные данные. К счастью, существует Elastic Container Registry, который предлагает частные репозитории, которые автоматически настраиваются при использовании ECS, если политика ECSHostEC2Role
разрешает действия, связанные с ECR.
Далее у нас есть LogConfiguration
, который отправляет журналы контейнеров в группу журналов EmailSenderLogsGroup
CloudWatch, чтобы мы могли проверять их через консоль AWS. В PortMappings
перечислены порты, открытые работающим контейнером. Обратите внимание, что мы не определили порт хоста, и он будет назначен автоматически. Это важно при запуске нескольких экземпляров одного и того же контейнера. Чуть подробнее опишу в следующем посте. И последнее, но не менее важное: в разделе Environment
перечислены переменные среды, которые передаются экземплярам контейнера при запуске. Здесь мы ссылаемся на параметр стека DeployEnv
, который позволяет нам информировать приложение, работающее внутри контейнера, о текущей среде развертывания, например. постановка против производства.
Как вы можете видеть выше, требуется несколько шагов, чтобы использовать CloudFormation для развертывания контейнера в ECS. Это правда, что он требует большей настройки, чем Elastic Beanstalk. Однако он позволяет лучше использовать инстансы EC2 и использовать единый подход к развертыванию и настройке независимо от технологии приложений, используемых внутри контейнера. Более того, это больше рассчитано на будущее, так как с небольшими настройками можно будет переключиться в Fargate Launch Mode. Использование этого режима освобождает нас от бремени задач управления кластером EC2 ECS. Для развертывания дополнительных сервисов и задач потребуются отдельные определения ресурсов CloudFormation. Однако с помощью cloudform легко сохранить шаблон CloudFormation СУХИМ.
Пётр Мионсковски,поклонник TDD, стремящийся узнать что-то новое
Личный блог Электронная почта Twitter Github Stackoverflow
Эта статья кросспостирована с личным блогом автора.