Creación de recursos de Amazon ECS con comandos de la AWS CLI para AWS CloudFormation
Otra forma de utilizar Amazon ECS con AWS CloudFormation es a través de la AWS CLI. Puede usar comandos para crear sus pilas de AWS CloudFormation para los componentes de Amazon ECS, como definiciones de tareas, clústeres y servicios, e implementarlos. El siguiente tutorial muestra cómo puede utilizar la AWS CLI para crear recursos de Amazon ECS con una plantilla de AWS CloudFormation.
Requisitos previos
-
Se han completado los pasos que se indican en Configuración para utilizar Amazon ECS.
-
Su usuario de IAM dispone de los permisos requeridos que se especifican en la política de IAM AmazonECS_FullAccess de ejemplo.
Paso 1: creación de una pila
Para crear una pila con la AWS CLI guardada en un archivo llamado ecs-tutorial-template.yaml
, ejecute el siguiente comando.
cat << 'EOF' > ecs-tutorial-template.yaml AWSTemplateFormatVersion: '2010-09-09' Description: '[AWSDocs] ECS: load-balanced-web-application' Parameters: VpcCidr: Type: String Default: '10.0.0.0/16' Description: CIDR block for the VPC ContainerImage: Type: String Default: 'public.ecr.aws/ecs-sample-image/amazon-ecs-sample:latest' Description: Container image to use in task definition PublicSubnet1Cidr: Type: String Default: '10.0.1.0/24' Description: CIDR block for public subnet 1 PublicSubnet2Cidr: Type: String Default: '10.0.2.0/24' Description: CIDR block for public subnet 2 PrivateSubnet1Cidr: Type: String Default: '10.0.3.0/24' Description: CIDR block for private subnet 1 PrivateSubnet2Cidr: Type: String Default: '10.0.4.0/24' Description: CIDR block for private subnet 2 ServiceName: Type: String Default: 'tutorial-app' Description: Name of the ECS service ContainerPort: Type: Number Default: 80 Description: Port on which the container listens DesiredCount: Type: Number Default: 2 Description: Desired number of tasks MinCapacity: Type: Number Default: 1 Description: Minimum number of tasks for auto scaling MaxCapacity: Type: Number Default: 10 Description: Maximum number of tasks for auto scaling Resources: # VPC and Networking VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCidr EnableDnsHostnames: true EnableDnsSupport: true Tags: - Key: Name Value: !Sub '${AWS::StackName}-vpc' # Internet Gateway InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Sub '${AWS::StackName}-igw' InternetGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: !Ref InternetGateway VpcId: !Ref VPC # Public Subnets for ALB PublicSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [0, !GetAZs ''] CidrBlock: !Ref PublicSubnet1Cidr MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub '${AWS::StackName}-public-subnet-1' PublicSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [1, !GetAZs ''] CidrBlock: !Ref PublicSubnet2Cidr MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub '${AWS::StackName}-public-subnet-2' # Private Subnets for ECS Tasks PrivateSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [0, !GetAZs ''] CidrBlock: !Ref PrivateSubnet1Cidr Tags: - Key: Name Value: !Sub '${AWS::StackName}-private-subnet-1' PrivateSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [1, !GetAZs ''] CidrBlock: !Ref PrivateSubnet2Cidr Tags: - Key: Name Value: !Sub '${AWS::StackName}-private-subnet-2' # NAT Gateways for private subnet internet access NatGateway1EIP: Type: AWS::EC2::EIP DependsOn: InternetGatewayAttachment Properties: Domain: vpc Tags: - Key: Name Value: !Sub '${AWS::StackName}-nat-eip-1' NatGateway2EIP: Type: AWS::EC2::EIP DependsOn: InternetGatewayAttachment Properties: Domain: vpc Tags: - Key: Name Value: !Sub '${AWS::StackName}-nat-eip-2' NatGateway1: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGateway1EIP.AllocationId SubnetId: !Ref PublicSubnet1 Tags: - Key: Name Value: !Sub '${AWS::StackName}-nat-1' NatGateway2: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGateway2EIP.AllocationId SubnetId: !Ref PublicSubnet2 Tags: - Key: Name Value: !Sub '${AWS::StackName}-nat-2' # Route Tables PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub '${AWS::StackName}-public-routes' DefaultPublicRoute: Type: AWS::EC2::Route DependsOn: InternetGatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway PublicSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnet1 PublicSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnet2 PrivateRouteTable1: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub '${AWS::StackName}-private-routes-1' DefaultPrivateRoute1: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTable1 DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway1 PrivateSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateRouteTable1 SubnetId: !Ref PrivateSubnet1 PrivateRouteTable2: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub '${AWS::StackName}-private-routes-2' DefaultPrivateRoute2: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTable2 DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway2 PrivateSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateRouteTable2 SubnetId: !Ref PrivateSubnet2 # Security Groups ALBSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupName: !Sub '${AWS::StackName}-alb-sg' GroupDescription: Security group for Application Load Balancer VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 Description: Allow HTTP traffic from internet SecurityGroupEgress: - IpProtocol: -1 CidrIp: 0.0.0.0/0 Description: Allow all outbound traffic Tags: - Key: Name Value: !Sub '${AWS::StackName}-alb-sg' ECSSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupName: !Sub '${AWS::StackName}-ecs-sg' GroupDescription: Security group for ECS tasks VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: !Ref ContainerPort ToPort: !Ref ContainerPort SourceSecurityGroupId: !Ref ALBSecurityGroup Description: Allow traffic from ALB SecurityGroupEgress: - IpProtocol: -1 CidrIp: 0.0.0.0/0 Description: Allow all outbound traffic Tags: - Key: Name Value: !Sub '${AWS::StackName}-ecs-sg' # Application Load Balancer ApplicationLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: !Sub '${AWS::StackName}-alb' Scheme: internet-facing Type: application Subnets: - !Ref PublicSubnet1 - !Ref PublicSubnet2 SecurityGroups: - !Ref ALBSecurityGroup Tags: - Key: Name Value: !Sub '${AWS::StackName}-alb' ALBTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: !Sub '${AWS::StackName}-tg' Port: !Ref ContainerPort Protocol: HTTP VpcId: !Ref VPC TargetType: ip HealthCheckIntervalSeconds: 30 HealthCheckPath: / HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 UnhealthyThresholdCount: 5 Tags: - Key: Name Value: !Sub '${AWS::StackName}-tg' ALBListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref ALBTargetGroup LoadBalancerArn: !Ref ApplicationLoadBalancer Port: 80 Protocol: HTTP # ECS Cluster ECSCluster: Type: AWS::ECS::Cluster Properties: ClusterName: !Sub '${AWS::StackName}-cluster' CapacityProviders: - FARGATE - FARGATE_SPOT DefaultCapacityProviderStrategy: - CapacityProvider: FARGATE Weight: 1 - CapacityProvider: FARGATE_SPOT Weight: 4 ClusterSettings: - Name: containerInsights Value: enabled Tags: - Key: Name Value: !Sub '${AWS::StackName}-cluster' # IAM Roles ECSTaskExecutionRole: Type: AWS::IAM::Role Properties: RoleName: !Sub '${AWS::StackName}-task-execution-role' AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: ecs-tasks.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy Tags: - Key: Name Value: !Sub '${AWS::StackName}-task-execution-role' ECSTaskRole: Type: AWS::IAM::Role Properties: RoleName: !Sub '${AWS::StackName}-task-role' AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: ecs-tasks.amazonaws.com Action: sts:AssumeRole Tags: - Key: Name Value: !Sub '${AWS::StackName}-task-role' # CloudWatch Log Group LogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub '/ecs/${AWS::StackName}' RetentionInDays: 7 # ECS Task Definition TaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: !Sub '${AWS::StackName}-task' Cpu: '256' Memory: '512' NetworkMode: awsvpc RequiresCompatibilities: - FARGATE ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn TaskRoleArn: !GetAtt ECSTaskRole.Arn ContainerDefinitions: - Name: !Ref ServiceName Image: !Ref ContainerImage PortMappings: - ContainerPort: !Ref ContainerPort Protocol: tcp Essential: true LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: ecs HealthCheck: Command: - CMD-SHELL - curl -f http://localhost/ || exit 1 Interval: 30 Timeout: 5 Retries: 3 StartPeriod: 60 Tags: - Key: Name Value: !Sub '${AWS::StackName}-task' # ECS Service ECSService: Type: AWS::ECS::Service DependsOn: ALBListener Properties: ServiceName: !Sub '${AWS::StackName}-service' Cluster: !Ref ECSCluster TaskDefinition: !Ref TaskDefinition DesiredCount: !Ref DesiredCount LaunchType: FARGATE PlatformVersion: LATEST NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - !Ref ECSSecurityGroup Subnets: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 LoadBalancers: - ContainerName: !Ref ServiceName ContainerPort: !Ref ContainerPort TargetGroupArn: !Ref ALBTargetGroup DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 50 DeploymentCircuitBreaker: Enable: true Rollback: true EnableExecuteCommand: true # For debugging Tags: - Key: Name Value: !Sub '${AWS::StackName}-service' # Auto Scaling Target ServiceScalingTarget: Type: AWS::ApplicationAutoScaling::ScalableTarget Properties: MaxCapacity: !Ref MaxCapacity MinCapacity: !Ref MinCapacity ResourceId: !Sub 'service/${ECSCluster}/${ECSService.Name}' RoleARN: !Sub 'arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService' ScalableDimension: ecs:service:DesiredCount ServiceNamespace: ecs # Auto Scaling Policy - CPU Utilization ServiceScalingPolicy: Type: AWS::ApplicationAutoScaling::ScalingPolicy Properties: PolicyName: !Sub '${AWS::StackName}-cpu-scaling-policy' PolicyType: TargetTrackingScaling ScalingTargetId: !Ref ServiceScalingTarget TargetTrackingScalingPolicyConfiguration: PredefinedMetricSpecification: PredefinedMetricType: ECSServiceAverageCPUUtilization TargetValue: 70.0 ScaleOutCooldown: 300 ScaleInCooldown: 300 Outputs: VPCId: Description: VPC ID Value: !Ref VPC Export: Name: !Sub '${AWS::StackName}-VPC-ID' LoadBalancerURL: Description: URL of the Application Load Balancer Value: !Sub 'http://${ApplicationLoadBalancer.DNSName}' Export: Name: !Sub '${AWS::StackName}-ALB-URL' ECSClusterName: Description: Name of the ECS Cluster Value: !Ref ECSCluster Export: Name: !Sub '${AWS::StackName}-ECS-Cluster' ECSServiceName: Description: Name of the ECS Service Value: !GetAtt ECSService.Name Export: Name: !Sub '${AWS::StackName}-ECS-Service' PrivateSubnet1: Description: Private Subnet 1 ID Value: !Ref PrivateSubnet1 Export: Name: !Sub '${AWS::StackName}-Private-Subnet-1' PrivateSubnet2: Description: Private Subnet 2 ID Value: !Ref PrivateSubnet2 Export: Name: !Sub '${AWS::StackName}-Private-Subnet-2' EOF
La plantilla utilizada en este tutorial crea un servicio de Amazon ECS con dos tareas que se ejecutan en Fargate. Cada una de las tareas ejecuta una aplicación de Amazon ECS de ejemplo. La plantilla también crea un equilibrador de carga de aplicación que distribuye el tráfico de la aplicación y una política de escalado automático de la aplicación que escala la aplicación en función del uso de la CPU. La plantilla también crea los recursos de red necesarios para implementar la aplicación, los recursos de registro para los registros de contenedores y un rol de IAM de ejecución de tareas de Amazon ECS. Para obtener más información sobre el rol de ejecución de tareas, consulte Rol de IAM de ejecución de tareas de Amazon ECS. Para obtener más información sobre el escalado automático, consulte Escalado automático de su servicio de Amazon ECS.
Tras crear un archivo de plantilla, utilice el siguiente comando para crear una pila. El indicador --capabilities
es obligatorio para crear un rol de ejecución de tareas de Amazon ECS tal y como se especifica en la plantilla. También puede especificar el indicador --parameters
para personalizar los parámetros de la plantilla.
aws cloudformation create-stack \ --stack-name
ecs-tutorial-stack
\ --template-body file://ecs-tutorial-template.yaml
\ --regionaws-region
\ --capabilities CAPABILITY_NAMED_IAM
Después de ejecutar el comando create-stack
, puede usar describe-stacks
para comprobar el estado de la creación de la pila.
aws cloudformation describe-stacks \ --stack-name
ecs-tutorial-stack
\ --regionaws-region
Paso 2: Verificación de la creación de recursos de Amazon ECS
Para asegurarse de que los recursos de Amazon ECS se creen correctamente, siga estos pasos.
-
Ejecute el siguiente comando para que se muestren todas las definiciones de tarea en una Región de AWS.
aws ecs list-task-definitions
El comando devuelve una lista de nombres de recurso de Amazon (ARN) de definiciones de tareas. El ARN de la definición de tarea que creó con la plantilla se mostrará en el siguiente formato.
{ "taskDefinitionArns": [ ..... "arn:aws:ecs:
aws-region
:111122223333
:task-definition/ecs-tutorial-stack-task:1", ..... ] } -
Ejecute el siguiente comando para que se enumeren todos los clústeres en una Región de AWS.
aws ecs list-clusters
El comando devuelve una lista de ARN de clústeres. El ARN del clúster que creó con la plantilla se mostrará en el siguiente formato.
{ "clusterArns": [ ..... "arn:aws:ecs:
aws-region
:111122223333
:cluster/ecs-tutorial-stack-cluster", ..... ] } -
Ejecute el siguiente comando para enumerar todos los servicios que se ejecutan en el clúster
ecs-tutorial-stack-cluster
.aws ecs list-services \ --cluster
ecs-tutorial-stack-cluster
El comando devuelve una lista de ARN de servicios. El ARN del servicio que creó con la plantilla se mostrará en el siguiente formato.
{ "serviceArns": [ "arn:aws:ecs:
aws-region
:111122223333
:service/ecs-tutorial-stack-cluster/ecs-tutorial-stack-service" ] }
También puede obtener el nombre de DNS del equilibrador de carga de aplicación que se creó y usarlo para verificar la creación de los recursos. Para obtener el nombre de DNS, ejecute el siguiente comando:
Ejecute el siguiente comando para recuperar los resultados de la pila creada.
aws cloudformation describe-stacks \ --stack-name
ecs-tutorial-stack
\ --regionaws-region
\ --query 'Stacks[0].Outputs[?OutputKey==`LoadBalancerURL`].OutputValue' \ --output text
Salida:
http://ecs-tutorial-stack-alb-0123456789
.aws-region
.elb.amazonaws.com
Pegue el nombre de DNS en un navegador web para ver una página web que muestre un ejemplo de la aplicación de Amazon ECS.
Paso 3: Limpieza
Para limpiar los recursos que ha creado, ejecute el siguiente comando.
aws cloudformation delete-stack \ --stack-name
ecs-stack
El comando delete-stack
inicia la eliminación de la pila AWS CloudFormation que se creó en este tutorial y, por tanto, elimina todos los recursos de la pila. Para verificar la eliminación, puede repetir el procedimiento en Paso 2: Verificación de la creación de recursos de Amazon ECS. La lista de ARN de los resultados ya no incluirá una definición de tarea denominada ecs-tutorial-stack-task
ni un clúster denominado ecs-tutorial-stack-cluster
. La llamada list-services
fallará.