

# Criar recursos do Amazon ECS usando o AWS CDK
<a name="tutorial-ecs-web-server-cdk"></a>

O AWS Cloud Development Kit (AWS CDK) é um framework de infraestrutura como código (IAC) que pode ser usado para definir a infraestrutura da nuvem AWS usando uma linguagem de programação completa. Para definir sua própria infraestrutura de nuvem, primeiro é necessário criar uma aplicação (em uma das linguagens aceitas pelo CDK) que contenha uma ou mais pilhas. Em seguida, sintetize-a em um modelo do CloudFormation e implante seus recursos na Conta da AWS. Siga as etapas descritas neste tópico para implantar um servidor Web em contêiner com o Amazon Elastic Container Service (Amazon ECS) e o AWS CDK no Fargate. 

A AWS Construct Library, incluída no CDK, fornece módulos que podem ser usados para modelar os recursos fornecidos por cada serviço da Serviços da AWS. Para serviços populares, a biblioteca fornece construções selecionadas com padrões inteligentes e práticas recomendadas. Um desses módulos, especificamente o `[aws-ecs-patterns](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecs_patterns-readme.html)`, fornece abstrações de alto nível que permitem definir o serviço em contêineres e todos os recursos de suporte necessários em algumas linhas de código.

Este tópico usa a construção [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecs_patterns.ApplicationLoadBalancedFargateService.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecs_patterns.ApplicationLoadBalancedFargateService.html). A construção implanta um serviço do Amazon ECS no Fargate por trás de um Application Load Balancer. O módulo `aws-ecs-patterns` também inclui construções que usam um network load balancer e são executadas no Amazon EC2.

Antes de iniciar esta tarefa, configure o ambiente de desenvolvimento do AWS CDK e instale o AWS CDK executando o comando a seguir. Para obter instruções sobre como configurar o ambiente de desenvolvimento do AWS CDK, consulte [Conceitos básicos do AWS CDK: pré-requisitos](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_prerequisites).

```
npm install -g aws-cdk
```

**nota**  
Essas instruções pressupõem que você está usando o AWS CDK v2. 

**Topics**
+ [Etapa 1: configurar o projeto do AWS CDK](#ecs-web-server-cdk-step-1)
+ [Etapa 2: usar o AWS CDK para definir um servidor Web em contêiner no Fargate](#ecs-web-server-cdk-step-2)
+ [Etapa 3: testar o serviço da Web](#ecs-web-server-cdk-step-3)
+ [Etapa 4: limpar](#ecs-web-server-cdk-step-4)
+ [Próximas etapas](#ecs-web-server-cdk-next-steps)

## Etapa 1: configurar o projeto do AWS CDK
<a name="ecs-web-server-cdk-step-1"></a>

Crie um diretório para a nova aplicação do AWS CDK e inicialize o projeto.

------
#### [ TypeScript ]

```
mkdir hello-ecs
cd hello-ecs
cdk init --language typescript
```

------
#### [ JavaScript ]

```
mkdir hello-ecs
cd hello-ecs
cdk init --language javascript
```

------
#### [ Python ]

```
mkdir hello-ecs
cd hello-ecs
cdk init --language python
```

Iniciado o projeto, ative o ambiente virtual do projeto e instale as dependências de linha de base do AWS CDK.

```
source .venv/bin/activate
python -m pip install -r requirements.txt
```

------
#### [ Java ]

```
mkdir hello-ecs
cd hello-ecs
cdk init --language java
```

Importe esse projeto do Maven para seu Java IDE. Por exemplo, no Eclipse, use **File** (Arquivo) > **Import** (Importar) > **Maven** > **Existing Maven Projects** (Projetos do Maven existentes).

------
#### [ C\$1 ]

```
mkdir hello-ecs
cd hello-ecs
cdk init --language csharp
```

------
#### [ Go ]

```
mkdir hello-ecs
cd hello-ecs
cdk init --language go
```

------

**nota**  
O modelo de aplicação do AWS CDK usa o nome do diretório do projeto para gerar nomes para arquivos e classes de origem. Neste exemplo, o diretório se chama `hello-ecs`. Se você escolher outro nome de diretório de projeto, sua aplicação não corresponderá a estas instruções.

O AWS CDK v2 inclui construções estáveis para todos os Serviços da AWS em um único pacote chamado `aws-cdk-lib`. Esse pacote é instalado como uma dependência quando o projeto é inicializado. Quando determinadas linguagens de programação são usadas, o pacote é instalado quando o projeto é compilado pela primeira vez. Este tópico descreve como usar construção de padrões do Amazon ECS que fornece abstrações de alto nível para trabalhar com o Amazon ECS. Esse módulo depende de construções do Amazon ECS e de outras construções para provisionar os recursos necessários para sua aplicação do Amazon ECS.

Os nomes usados para importar essas bibliotecas para a aplicação do CDK podem diferir ligeiramente dependendo da linguagem de programação utilizada. Para referência, estes são os nomes usados em cada linguagem de programação aceita pelo CDK.

------
#### [ TypeScript ]

```
aws-cdk-lib/aws-ecs
aws-cdk-lib/aws-ecs-patterns
```

------
#### [ JavaScript ]

```
aws-cdk-lib/aws-ecs
aws-cdk-lib/aws-ecs-patterns
```

------
#### [ Python ]

```
aws_cdk.aws_ecs
aws_cdk.aws_ecs_patterns
```

------
#### [ Java ]

```
software.amazon.awscdk.services.ecs
software.amazon.awscdk.services.ecs.patterns
```

------
#### [ C\$1 ]

```
Amazon.CDK.AWS.ECS
Amazon.CDK.AWS.ECS.Patterns
```

------
#### [ Go ]

```
github.com/aws/aws-cdk-go/awscdk/v2/awsecs
github.com/aws/aws-cdk-go/awscdk/v2/awsecspatterns
```

------

## Etapa 2: usar o AWS CDK para definir um servidor Web em contêiner no Fargate
<a name="ecs-web-server-cdk-step-2"></a>

Use a imagem do contêiner [https://gallery.ecr.aws/ecs-sample-image/amazon-ecs-sample](https://gallery.ecr.aws/ecs-sample-image/amazon-ecs-sample). Essa imagem contém uma aplicação da Web em PHP que é executada no Ngingx.

No projeto AWS CDK criado por você, edite o arquivo que contém a definição de pilha de modo que ele se pareça com um dos exemplos a seguir.

**nota**  
Uma pilha é uma unidade de implantação. Todos os recursos devem estar em uma pilha, e todos os recursos que estão em uma pilha são implantados ao mesmo tempo. Se a implantação de um recurso falhar, todos os demais recursos já implantados serão revertidos. Uma aplicação do AWS CDK pode conter várias pilhas, e os recursos de uma pilha podem se referir aos recursos de outra pilha.

------
#### [ TypeScript ]

Atualize `lib/hello-ecs-stack.ts` de modo que ele seja semelhante ao seguinte.

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ecsp from 'aws-cdk-lib/aws-ecs-patterns';

export class HelloEcsStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    new ecsp.ApplicationLoadBalancedFargateService(this, 'MyWebServer', {
      taskImageOptions: {
        image: ecs.ContainerImage.fromRegistry('public.ecr.aws/ecs-sample-image/amazon-ecs-sample:latest'),
      },
      publicLoadBalancer: true
    });
  }
}
```

------
#### [ JavaScript ]

Atualize `lib/hello-ecs-stack.js` de modo que ele seja semelhante ao seguinte.

```
const cdk = require('aws-cdk-lib');
const { Construct } = require('constructs');
const ecs = require('aws-cdk-lib/aws-ecs');
const ecsp = require('aws-cdk-lib/aws-ecs-patterns');

class HelloEcsStack extends cdk.Stack {
  constructor(scope = Construct, id = string, props = cdk.StackProps) {
    super(scope, id, props);

    new ecsp.ApplicationLoadBalancedFargateService(this, 'MyWebServer', {
      taskImageOptions: {
        image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
      },
      publicLoadBalancer: true
    });
  }
}

module.exports = { HelloEcsStack }
```

------
#### [ Python ]

Atualize `hello-ecs/hello_ecs_stack.py` de modo que ele seja semelhante ao seguinte.

```
import aws_cdk as cdk
from constructs import Construct

import aws_cdk.aws_ecs as ecs
import aws_cdk.aws_ecs_patterns as ecsp

class HelloEcsStack(cdk.Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        ecsp.ApplicationLoadBalancedFargateService(self, "MyWebServer",
            task_image_options=ecsp.ApplicationLoadBalancedTaskImageOptions(
                image=ecs.ContainerImage.from_registry("amazon/amazon-ecs-sample")),
            public_load_balancer=True
        )
```

------
#### [ Java ]

Atualize `src/main/java/com.myorg/HelloEcsStack.java` de modo que ele seja semelhante ao seguinte.

```
package com.myorg;

import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;

import software.amazon.awscdk.services.ecs.ContainerImage;
import software.amazon.awscdk.services.ecs.patterns.ApplicationLoadBalancedFargateService;
import software.amazon.awscdk.services.ecs.patterns.ApplicationLoadBalancedTaskImageOptions;

public class HelloEcsStack extends Stack {
    public HelloEcsStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public HelloEcsStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        ApplicationLoadBalancedFargateService.Builder.create(this, "MyWebServer")
        	.taskImageOptions(ApplicationLoadBalancedTaskImageOptions.builder()
        			.image(ContainerImage.fromRegistry("amazon/amazon-ecs-sample"))
        			.build())
        	.publicLoadBalancer(true)
        	.build();        
    }
}
```

------
#### [ C\$1 ]

Atualize `src/HelloEcs/HelloEcsStack.cs` de modo que ele seja semelhante ao seguinte.

```
using Amazon.CDK;
using Constructs;
using Amazon.CDK.AWS.ECS;
using Amazon.CDK.AWS.ECS.Patterns;
namespace HelloEcs
{
    public class HelloEcsStack : Stack
    {
        internal HelloEcsStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            new ApplicationLoadBalancedFargateService(this, "MyWebServer",
                new ApplicationLoadBalancedFargateServiceProps
                {
                    TaskImageOptions = new ApplicationLoadBalancedTaskImageOptions
                    {
                        Image = ContainerImage.FromRegistry("amazon/amazon-ecs-sample")
                    },
                    PublicLoadBalancer = true
                });
        }
    }
}
```

------
#### [ Go ]

Atualize `hello-ecs.go` de modo que ele seja semelhante ao seguinte.

```
package main

import (
	"github.com/aws/aws-cdk-go/awscdk/v2"
	// "github.com/aws/aws-cdk-go/awscdk/v2/awssqs"
	"github.com/aws/aws-cdk-go/awscdk/v2/awsecs"
	"github.com/aws/aws-cdk-go/awscdk/v2/awsecspatterns"
	"github.com/aws/constructs-go/constructs/v10"
	"github.com/aws/jsii-runtime-go"
)

type HelloEcsStackProps struct {
	awscdk.StackProps
}

func NewHelloEcsStack(scope constructs.Construct, id string, props *HelloEcsStackProps) awscdk.Stack {
	var sprops awscdk.StackProps
	if props != nil {
		sprops = props.StackProps
	}
	stack := awscdk.NewStack(scope, &id, &sprops)

	// The code that defines your stack goes here

	// example resource
	// queue := awssqs.NewQueue(stack, jsii.String("HelloEcsQueue"), &awssqs.QueueProps{
	// 	VisibilityTimeout: awscdk.Duration_Seconds(jsii.Number(300)),
	// })
	res := awsecspatterns.NewApplicationLoadBalancedFargateService(stack, jsii.String("MyWebServer"),
		&awsecspatterns.ApplicationLoadBalancedFargateServiceProps{
			TaskImageOptions: &awsecspatterns.ApplicationLoadBalancedTaskImageOptions{
				Image: awsecs.ContainerImage_FromRegistry(jsii.String("amazon/amazon-ecs-sample"), &awsecs.RepositoryImageProps{}),
			},
		},
	)
	awscdk.NewCfnOutput(stack, jsii.String("LoadBalancerDNS"), &awscdk.CfnOutputProps{Value: res.LoadBalancer().LoadBalancerDnsName()})

	return stack
}

func main() {
	defer jsii.Close()

	app := awscdk.NewApp(nil)

	NewHelloEcsStack(app, "HelloEcsStack", &HelloEcsStackProps{
		awscdk.StackProps{
			Env: env(),
		},
	})

	app.Synth(nil)
}

// env determines the AWS environment (account+region) in which our stack is to
// be deployed. For more information see: https://docs.aws.amazon.com/cdk/latest/guide/environments.html
func env() *awscdk.Environment {
	// If unspecified, this stack will be "environment-agnostic".
	// Account/Region-dependent features and context lookups will not work, but a
	// single synthesized template can be deployed anywhere.
	//---------------------------------------------------------------------------
	return nil

	// Uncomment if you know exactly what account and region you want to deploy
	// the stack to. This is the recommendation for production stacks.
	//---------------------------------------------------------------------------
	// return &awscdk.Environment{
	//  Account: jsii.String("123456789012"),
	//  Region:  jsii.String("us-east-1"),
	// }

	// Uncomment to specialize this stack for the AWS Account and Region that are
	// implied by the current CLI configuration. This is recommended for dev
	// stacks.
	//---------------------------------------------------------------------------
	// return &awscdk.Environment{
	//  Account: jsii.String(os.Getenv("CDK_DEFAULT_ACCOUNT")),
	//  Region:  jsii.String(os.Getenv("CDK_DEFAULT_REGION")),
	// }
}
```

------

O snippet curto anterior inclui o seguinte:
+ O nome lógico do serviço: `MyWebServer`.
+ A imagem do contêiner que foi obtida na Galeria Pública do Amazon ECR: `amazon/amazon-ecs-sample`.
+ Outras informações relevantes, como o fato de que o balanceador de carga tem um endereço público e é acessível via Internet.

 O AWS CDK criará todos os recursos necessários para implantar o servidor Web, incluindo os seguintes recursos. Esses recursos foram omitidos neste exemplo.
+ Cluster do Amazon ECS 
+ Instâncias do Amazon VPC e do Amazon EC2 
+  Auto Scaling group (Grupo do Auto Scaling)
+  Application Load Balancer 
+  Perfis e políticas do IAM 

 Alguns recursos provisionados automaticamente serão compartilhados por todos os serviços do Amazon ECS definidos na pilha.

Salve o arquivo de origem e, em seguida, execute o comando `cdk synth` no diretório principal da aplicação. O AWS CDK executa a aplicação e sintetiza um modelo do CloudFormation baseado nela. Em seguida, exibe o modelo. O modelo é um arquivo YAML com aproximadamente 600 linhas. O início do arquivo é mostrado aqui. Seu modelo pode ser diferente deste exemplo.

```
Resources:
  MyWebServerLB3B5FD3AB:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      LoadBalancerAttributes:
        - Key: deletion_protection.enabled
          Value: "false"
      Scheme: internet-facing
      SecurityGroups:
        - Fn::GetAtt:
            - MyWebServerLBSecurityGroup01B285AA
            - GroupId
      Subnets:
        - Ref: EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1Subnet3C273B99
        - Ref: EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2Subnet95FF715A
      Type: application
    DependsOn:
      - EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1DefaultRouteFF4E2178
      - EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2DefaultRouteB1375520
    Metadata:
      aws:cdk:path: HelloEcsStack/MyWebServer/LB/Resource
  MyWebServerLBSecurityGroup01B285AA:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Automatically created Security Group for ELB HelloEcsStackMyWebServerLB06757F57
      SecurityGroupIngress:
        - CidrIp: 0.0.0.0/0
          Description: Allow from anyone on port 80
          FromPort: 80
          IpProtocol: tcp
          ToPort: 80
      VpcId:
        Ref: EcsDefaultClusterMnL3mNNYNVpc7788A521
    Metadata:
      aws:cdk:path: HelloEcsStack/MyWebServer/LB/SecurityGroup/Resource
# and so on for another few hundred lines
```

Para implantar o serviço na Conta da AWS, execute `cdk deploy` no diretório principal da aplicação. Você será avisado para aprovar as políticas do IAM que geradas pelo AWS CDK.

A implantação demora vários minutos, período durante o qual o AWS CDK cria diversos recursos. As últimas linhas da saída da implantação incluem o nome de host público do balanceador de carga e o URL do novo servidor Web. Eles são os seguintes:

```
Outputs:
HelloEcsStack.MyWebServerLoadBalancerDNSXXXXXXX = Hello-MyWeb-ZZZZZZZZZZZZZ-ZZZZZZZZZZ.us-west-2.elb.amazonaws.com
HelloEcsStack.MyWebServerServiceURLYYYYYYYY = http://Hello-MyWeb-ZZZZZZZZZZZZZ-ZZZZZZZZZZ.us-west-2.elb.amazonaws.com
```

## Etapa 3: testar o serviço da Web
<a name="ecs-web-server-cdk-step-3"></a>

Copie o URL da saída da implantação e cole no navegador da Web. A mensagem de boas-vindas a seguir do servidor Web é exibida.

![\[Captura de tela da aplicação de exemplo do Amazon ECS. A saída indica "Amazon ECS”.\]](http://docs.aws.amazon.com/pt_br/AmazonECS/latest/developerguide/images/simple-php-app-congrats.png)


## Etapa 4: limpar
<a name="ecs-web-server-cdk-step-4"></a>

Após terminar com o servidor Web, encerre o serviço usando o CDK ao executar o comando `cdk destroy` no diretório principal da aplicação. Isso evita incorrer em cobranças não intencionais no futuro.

## Próximas etapas
<a name="ecs-web-server-cdk-next-steps"></a>

Para saber mais sobre como desenvolver a infraestrutura da AWS usando o AWS CDK, consulte o [Guia do desenvolvedor do AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/).

Para obter informações sobre como criar aplicações do AWS CDK em sua linguagem preferida, consulte:

------
#### [ TypeScript ]

[Trabalhar com o AWS CDK no TypeScript](https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-typescript.html)

------
#### [ JavaScript ]

[Trabalhar com o AWS CDK no JavaScript](https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-javascript.html)

------
#### [ Python ]

[Trabalhar com o AWS CDK no Python](https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-python.html)

------
#### [ Java ]

[Trabalhar com o AWS CDK no Java](https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-java.html)

------
#### [ C\$1 ]

[Trabalhar com o AWS CDK em C\$1](https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-csharp.html)

------
#### [ Go ]

[Working with the AWS CDK in Go](https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-go.html)

------

Para obter mais informações sobre os módulos da AWS Construct Library usados neste tópico, consulte as visões gerais da Referência da API do AWS CDK a seguir.
+ [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecs-readme.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecs-readme.html)
+  [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecs_patterns-readme.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecs_patterns-readme.html)