

# Amazon ECS에 관한 자습서
<a name="ecs-tutorials"></a>

다음 자습서는 Amazon ECS 사용 시 일반적인 태스크를 수행하는 방법을 설명합니다.

다음 자습서 중 하나를 사용하여 Amazon ECS를 시작하는 방법에 대해 자세히 알아볼 수 있습니다.


| 자습서 개요 | 자세히 알아보기 | 
| --- | --- | 
|  Fargate에서 Amazon ECS를 시작합니다.  |  [Fargate에 대한 Amazon ECS Linux 태스크를 생성하는 방법에 대해 알아보기](getting-started-fargate.md)  | 
|  Fargate에서 Windows 컨테이너를 시작합니다.  |  [Fargate에 대한 Amazon ECS Windows 태스크를 생성하는 방법에 대해 알아보기](Windows_fargate-getting_started.md)  | 
|  EC2에 대한 Windows 컨테이너를 시작합니다.  |  [EC2에 대한 Amazon ECS Windows 태스크를 생성하는 방법에 대해 알아보기](getting-started-ecs-ec2-v2.md)  | 

다음 자습서 중 하나를 사용하여 AWS CLI를 통해 Amazon ECS에 작업을 배포할 수 있습니다.


| 자습서 개요 | 자세히 알아보기 | 
| --- | --- | 
|  Fargate에 대한 Linux 태스크를 생성합니다.  |  [AWS CLI를 사용하여 Fargate에 대한 Amazon ECS Linux 태스크 생성](ECS_AWSCLI_Fargate.md)  | 
|  Fargate에 대한 Windows 태스크를 생성합니다.  |  [AWS CLI를 사용하여 Fargate에 대한 Amazon ECS Windows 태스크 생성](ECS_AWSCLI_Fargate_windows.md)  | 
|  EC2에 대한 Linux 태스크를 생성합니다.  |  [AWS CLI를 사용하여 EC2에 대한 Amazon ECS 태스크 생성](ECS_AWSCLI_EC2.md)  | 

다음 자습서 중 하나를 사용하여 모니터링 및 로깅에 대해 자세히 알아볼 수 있습니다.


| 자습서 개요 | 자세히 알아보기 | 
| --- | --- | 
|  Amazon ECS 작업 이벤트를 수신 대기하고 이를 CloudWatch Logs 로그 스트림에 기록하는 간단한 Lambda 함수를 설정합니다.  |  [CloudWatch Events 이벤트를 수신 대기하도록 Amazon ECS 구성](ecs_cwet.md)  | 
|  필수 컨테이너 중 하나가 종료되어 작업 실행이 중지된 작업 이벤트만 캡처하는 Amazon EventBridge 이벤트 규칙을 구성합니다.  |  [Amazon ECS 작업 중지 이벤트에 대한 Amazon Simple Notification Service 알림 보내기](ecs_cwet2.md)  | 
|  원래 하나의 컨텍스트에 속하지만 여러 레코드 또는 여러 로그 줄로 분할된 로그 메시지를 연결합니다.  |  [여러 줄 또는 스택 추적 Amazon ECS 로그 메시지 연결](firelens-concatanate-multiline.md)  | 
|  Amazon ECS에서 실행 중인 Windows 인스턴스에 Fluent Bit 컨테이너를 배포하여 중앙 집중식 로깅을 위해 Windows 작업에서 생성된 로그를 Amazon CloudWatch로 스트리밍합니다.  |  [Amazon ECS Windows 컨테이너에서 Fluent Bit 배포](tutorial-deploy-fluentbit-on-windows.md)  | 

다음 자습서 중 하나를 사용하여 Amazon ECS의 그룹 관리형 서비스 계정과 함께 Active Directory 인증을 사용하는 방법에 대해 자세히 알아볼 수 있습니다.


| 자습서 개요 | 자세히 알아보기 | 
| --- | --- | 
|  EC2의 Linux 컨테이너에서 그룹 관리형 서비스 계정을 사용합니다.  |  [Amazon ECS에서 EC2 Linux 컨테이너에 대해 gMSA 사용](linux-gmsa.md)  | 
|  EC2의 Windows 컨테이너에서 그룹 관리형 서비스 계정을 사용합니다.  |  [Amazon ECS의 EC2 Windows 컨테이너에 대해 gMSA를 사용하는 방법 알아보기](windows-gmsa.md)  | 
|  Fargate의 Linux 컨테이너에서 그룹 관리형 서비스 계정을 사용합니다.  |  [Fargate의 Linux 컨테이너에서 gMSA 사용](fargate-linux-gmsa.md)  | 
|  도메인이 없는 그룹 관리형 서비스 계정으로 Active Directory에 액세스할 수 있도록 자격 증명을 포함하는 Windows 컨테이너를 실행하는 작업을 생성합니다.  |  [AWS CLI를 사용하여 도메인이 없는 gMSA로 Amazon ECS Windows 컨테이너 사용](tutorial-gmsa-windows.md)  | 

# AWS CLI를 사용하여 Fargate에 대한 Amazon ECS Linux 태스크 생성
<a name="ECS_AWSCLI_Fargate"></a>

다음 단계는 AWS CLI를 사용하여 Amazon ECS에서 클러스터를 설정하고, 태스크 정의를 등록하고, Linux 태스크를 실행하고, 기타 일반적인 시나리오를 수행하는 데 도움이 됩니다. AWS CLI의 최신 버전을 사용합니다. 최신 버전으로 업그레이드하는 방법에 대한 자세한 내용은 [AWS CLI 최신 버전의 설치 또는 업데이트](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)를 참조하세요.

**참고**  
듀얼 스택 서비스 엔드포인트를 사용하면 AWS CLI, SDK 및 Amazon ECS API에서 IPv4 및 IPv6 모두를 통해 Amazon ECS와 상호 작용할 수 있습니다. 자세한 내용은 [Amazon ECS 듀얼 스택 엔드포인트 사용](dual-stack-endpoint.md) 섹션을 참조하세요.

**Topics**
+ [사전 조건](#ECS_AWSCLI_Fargate_prereq)
+ [1단계: 클러스터 생성](#ECS_AWSCLI_Fargate_create_cluster)
+ [2단계: Linux 태스크 정의 등록](#ECS_AWSCLI_Fargate_register_task_definition)
+ [3단계: 작업 정의 나열](#ECS_AWSCLI_Fargate_list_task_definitions)
+ [4단계: 서비스 생성](#ECS_AWSCLI_Fargate_create_service)
+ [5단계: 서비스 나열](#ECS_AWSCLI_Fargate_list_services)
+ [6단계: 실행 서비스 설명](#ECS_AWSCLI_Fargate_describe_service)
+ [7단계: 테스트](#ECS_AWSCLI_Fargate_test)
+ [8단계: 정리](#ECS_AWSCLI_Fargate_clean_up)

## 사전 조건
<a name="ECS_AWSCLI_Fargate_prereq"></a>

이 자습서에서는 다음 사전 조건이 충족되었다고 가정합니다.
+ 최신 버전의 AWS CLI가 설치 및 구성됩니다. AWS CLI 설치 또는 업그레이드에 대한 자세한 내용은 [AWS CLI 최신 버전 설치 또는 업데이트](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)를 참고하세요.
+ [Amazon ECS 사용 설정](get-set-up-for-amazon-ecs.md)의 단계가 완료되었습니다.
+ IAM 사용자는 [AmazonECS\$1FullAccess](security-iam-awsmanpol.md#security-iam-awsmanpol-AmazonECS_FullAccess) IAM 정책 예제에 지정된 필수 권한을 가집니다.
+ 사용할 VPC 및 보안 그룹이 생성되었습니다. 이 자습서에서는 Amazon ECR Public에서 호스팅되는 컨테이너 이미지를 사용하므로 태스크에서 인터넷에 액세스할 수 있어야 합니다. 작업에 인터넷 경로를 제공하려면 다음 옵션 중 하나를 사용합니다.
  + 탄력적 IP 주소가 있는 NAT 게이트웨이와 함께 프라이빗 서브넷을 사용합니다.
  + 퍼블릭 서브넷을 사용하고 퍼블릭 IP 주소를 작업에 할당합니다.

  자세한 내용은 [Virtual Private Cloud 생성](get-set-up-for-amazon-ecs.md#create-a-vpc) 섹션을 참조하세요.

  보안 그룹 및 규칙에 대한 자세한 내용은 *Amazon Virtual Private Cloud 사용 설명서*의 [VPC에 대한 기본 보안 그룹](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#DefaultSecurityGroup)과 [규칙 예](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#security-group-rule-examples)를 참조하세요.
+  프라이빗 서브넷을 사용하여 이 자습서를 따르면 Amazon ECS Exec을 사용하여 컨테이너와 직접 상호 작용하고 배포를 테스트할 수 있습니다. ECS Exec을 사용하려면 작업 IAM 역할을 생성해야 합니다. 태스크 IAM 역할 및 기타 사전 조건에 대한 자세한 내용은 [Amazon ECS Exec을 사용하여 Amazon ECS 컨테이너 모니터링](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-exec.html)을 참조하세요.
+ (선택 사항) AWS CloudShell은 고객에게 자체 EC2 인스턴스를 생성할 필요 없이 명령줄을 제공하는 도구입니다. 자세한 내용은 *AWS CloudShell 사용 설명서*의 [AWS CloudShell이란?](https://docs.aws.amazon.com/cloudshell/latest/userguide/welcome.html)을 참조하세요.

## 1단계: 클러스터 생성
<a name="ECS_AWSCLI_Fargate_create_cluster"></a>

계정에는 기본적으로 `default` 클러스터가 할당됩니다.

**참고**  
제공된 `default` 클러스터를 사용하는 이점은 후속 명령에서 `--cluster cluster_name` 옵션을 지정할 필요가 없다는 것입니다. 기본 클러스터가 아닌 자체 클러스터를 생성하는 경우, 해당 클러스터에 사용할 각 명령에 `--cluster cluster_name`을 지정해야 합니다.

다음 명령을 사용하여 고유한 이름의 자체 클러스터를 생성합니다.

```
aws ecs create-cluster --cluster-name fargate-cluster
```

출력:

```
{
    "cluster": {
        "status": "ACTIVE", 
        "defaultCapacityProviderStrategy": [], 
        "statistics": [], 
        "capacityProviders": [], 
        "tags": [], 
        "clusterName": "fargate-cluster", 
        "settings": [
            {
                "name": "containerInsights", 
                "value": "disabled"
            }
        ], 
        "registeredContainerInstancesCount": 0, 
        "pendingTasksCount": 0, 
        "runningTasksCount": 0, 
        "activeServicesCount": 0, 
        "clusterArn": "arn:aws:ecs:region:aws_account_id:cluster/fargate-cluster"
    }
}
```

## 2단계: Linux 태스크 정의 등록
<a name="ECS_AWSCLI_Fargate_register_task_definition"></a>

ECS 클러스터에서 작업을 실행하려면 먼저 작업 정의를 등록해야 합니다. 태스크 정의는 그룹화된 컨테이너의 목록입니다. 다음 예제는 Docker Hub에서 호스팅되는 httpd 컨테이너 이미지를 사용하여 PHP 웹 앱을 생성하는 간단한 작업 정의입니다. 사용 가능한 태스크 정의 파라미터에 대한 자세한 정보는 [Amazon ECS 작업 정의](task_definitions.md) 섹션을 참조하세요. 이 자습서에서 `taskRoleArn`는 프라이빗 서브넷에 작업을 배포하고 배포를 테스트하려는 경우에만 필요합니다. `taskRoleArn`을 [사전 조건](#ECS_AWSCLI_Fargate_prereq)에 설명한 대로 ECS Exec을 사용하기 위해 생성한 IAM 작업 역할로 바꿉니다.

```
 {
        "family": "sample-fargate",
        "networkMode": "awsvpc",
        "taskRoleArn": "arn:aws:iam::aws_account_id:role/execCommandRole", 
        "containerDefinitions": [
            {
                "name": "fargate-app",
                "image": "public.ecr.aws/docker/library/httpd:latest",
                "portMappings": [
                    {
                        "containerPort": 80,
                        "hostPort": 80,
                        "protocol": "tcp"
                    }
                ],
                "essential": true,
                "entryPoint": [
                    "sh",
                    "-c"
                ],
                "command": [
                    "/bin/sh -c \"echo '<html> <head> <title>Amazon ECS Sample App</title> <style>body {margin-top: 40px; background-color: #333;} </style> </head><body> <div style=color:white;text-align:center> <h1>Amazon ECS Sample App</h1> <h2>Congratulations!</h2> <p>Your application is now running on a container in Amazon ECS.</p> </div></body></html>' >  /usr/local/apache2/htdocs/index.html && httpd-foreground\""
                ]
            }
        ],
        "requiresCompatibilities": [
            "FARGATE"
        ],
        "cpu": "256",
        "memory": "512"
}
```

작업 정의 JSON을 파일로 저장하고 `--cli-input-json file://path_to_file.json` 옵션을 사용하여 전달합니다.

컨테이너 정의에 JSON 파일을 사용하려면

```
aws ecs register-task-definition --cli-input-json file://$HOME/tasks/fargate-task.json
```

**register-task-definition** 명령은 등록을 완료한 후 작업 정의의 설명을 반환합니다.

## 3단계: 작업 정의 나열
<a name="ECS_AWSCLI_Fargate_list_task_definitions"></a>

언제라도 **list-task-definitions** 명령을 사용하여 계정의 작업 정의를 나열할 수 있습니다. 이 명령은 **run-task** 또는 **start-task**를 호출할 때 함께 사용할 수 있는 `family` 및 `revision` 값을 출력합니다.

```
aws ecs list-task-definitions
```

출력:

```
{
    "taskDefinitionArns": [
        "arn:aws:ecs:region:aws_account_id:task-definition/sample-fargate:1"
    ]
}
```

## 4단계: 서비스 생성
<a name="ECS_AWSCLI_Fargate_create_service"></a>

계정에 대한 작업을 등록한 후 클러스터에서 등록된 작업에 대해 서비스를 생성할 수 있습니다. 이 예제에서는 클러스터에서 실행 중인 `sample-fargate:1` 작업 정의 인스턴스 하나를 사용하여 서비스를 생성합니다. 이 작업에는 인터넷 경로가 필요하므로 이 작업을 수행할 수 있는 두 가지 방법이 있습니다. 한 가지 방법은 퍼블릭 서브넷에서 탄력적 IP 주소가 있는 NAT 게이트웨이로 구성된 프라이빗 서브넷을 사용하는 것입니다. 또 다른 방법은 퍼블릭 서브넷을 사용하고 작업에 퍼블릭 IP 주소를 할당하는 것입니다. 아래 두 가지 예를 모두 제공합니다.

프라이빗 서브넷을 사용하는 예. Amazon ECS Exec을 사용하려면 이 ` enable-execute-command ` 옵션이 필요합니다.

```
aws ecs create-service --cluster fargate-cluster --service-name fargate-service --task-definition sample-fargate:1 --desired-count 1 --launch-type "FARGATE" --network-configuration "awsvpcConfiguration={subnets=[subnet-abcd1234],securityGroups=[sg-abcd1234]}" --enable-execute-command
```

퍼블릭 서브넷을 사용하는 예.

```
aws ecs create-service --cluster fargate-cluster --service-name fargate-service --task-definition sample-fargate:1 --desired-count 1 --launch-type "FARGATE" --network-configuration "awsvpcConfiguration={subnets=[subnet-abcd1234],securityGroups=[sg-abcd1234],assignPublicIp=ENABLED}"
```

**create-service** 명령은 등록을 완료한 후 작업 정의의 설명을 반환합니다.

## 5단계: 서비스 나열
<a name="ECS_AWSCLI_Fargate_list_services"></a>

클러스터의 서비스를 나열합니다. 이전 섹션에서 생성한 서비스가 보일 것입니다. 이 명령에서 반환된 서비스 이름 또는 전체 ARN을 기록해 두었다가 나중에 서비스를 설명하는 데 사용할 수 있습니다.

```
aws ecs list-services --cluster fargate-cluster
```

출력:

```
{
    "serviceArns": [
        "arn:aws:ecs:region:aws_account_id:service/fargate-cluster/fargate-service"
    ]
}
```

## 6단계: 실행 서비스 설명
<a name="ECS_AWSCLI_Fargate_describe_service"></a>

앞서 검색한 서비스 이름으로 서비스를 설명하여 작업에 관한 정보를 더 많이 가져옵니다.

```
aws ecs describe-services --cluster fargate-cluster --services fargate-service
```

성공하면 서비스 실패 및 서비스에 대한 설명이 반환됩니다. 예를 들어 ` services ` 섹션에서 실행 중이거나 보류 중인 작업 상태와 같이 배포에 대한 정보를 찾을 수 있습니다. 작업 정의, 네트워크 구성 및 타임스탬프가 지정된 이벤트에 대한 정보도 찾을 수 있습니다. 실패 섹션에서는 호출과 관련된 실패(있는 경우)에 대한 정보를 찾을 수 있습니다. 문제 해결에 대한 자세한 정보는 [서비스 이벤트 메시지](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-event-messages.html)를 참조하세요. 서비스 설명에 대한 자세한 정보는 [서비스 설명](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_DescribeServices)을 참조하세요.

```
{
    "services": [
        {
            "networkConfiguration": {
                "awsvpcConfiguration": {
                    "subnets": [
                        "subnet-abcd1234"
                    ], 
                    "securityGroups": [
                        "sg-abcd1234"
                    ], 
                    "assignPublicIp": "ENABLED"
                }
            }, 
            "launchType": "FARGATE", 
            "enableECSManagedTags": false, 
            "loadBalancers": [], 
            "deploymentController": {
                "type": "ECS"
            }, 
            "desiredCount": 1, 
            "clusterArn": "arn:aws:ecs:region:aws_account_id:cluster/fargate-cluster", 
            "serviceArn": "arn:aws:ecs:region:aws_account_id:service/fargate-service", 
            "deploymentConfiguration": {
                "maximumPercent": 200, 
                "minimumHealthyPercent": 100
            }, 
            "createdAt": 1692283199.771, 
            "schedulingStrategy": "REPLICA", 
            "placementConstraints": [], 
            "deployments": [
                {
                    "status": "PRIMARY", 
                    "networkConfiguration": {
                        "awsvpcConfiguration": {
                            "subnets": [
                                "subnet-abcd1234"
                            ], 
                            "securityGroups": [
                                "sg-abcd1234"
                            ], 
                            "assignPublicIp": "ENABLED"
                        }
                    }, 
                    "pendingCount": 0, 
                    "launchType": "FARGATE", 
                    "createdAt": 1692283199.771, 
                    "desiredCount": 1, 
                    "taskDefinition": "arn:aws:ecs:region:aws_account_id:task-definition/sample-fargate:1", 
                    "updatedAt": 1692283199.771, 
                    "platformVersion": "1.4.0", 
                    "id": "ecs-svc/9223370526043414679", 
                    "runningCount": 0
                }
            ], 
            "serviceName": "fargate-service", 
            "events": [
                {
                    "message": "(service fargate-service) has started 2 tasks: (task 53c0de40-ea3b-489f-a352-623bf1235f08) (task d0aec985-901b-488f-9fb4-61b991b332a3).", 
                    "id": "92b8443e-67fb-4886-880c-07e73383ea83", 
                    "createdAt": 1510811841.408
                }, 
                {
                    "message": "(service fargate-service) has started 2 tasks: (task b4911bee-7203-4113-99d4-e89ba457c626) (task cc5853e3-6e2d-4678-8312-74f8a7d76474).", 
                    "id": "d85c6ec6-a693-43b3-904a-a997e1fc844d", 
                    "createdAt": 1510811601.938
                }, 
                {
                    "message": "(service fargate-service) has started 2 tasks: (task cba86182-52bf-42d7-9df8-b744699e6cfc) (task f4c1ad74-a5c6-4620-90cf-2aff118df5fc).", 
                    "id": "095703e1-0ca3-4379-a7c8-c0f1b8b95ace", 
                    "createdAt": 1510811364.691
                }
            ], 
            "runningCount": 0, 
            "status": "ACTIVE", 
            "serviceRegistries": [], 
            "pendingCount": 0, 
            "createdBy": "arn:aws:iam::aws_account_id:user/user_name", 
            "platformVersion": "LATEST", 
            "placementStrategy": [], 
            "propagateTags": "NONE", 
            "roleArn": "arn:aws:iam::aws_account_id:role/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS", 
            "taskDefinition": "arn:aws:ecs:region:aws_account_id:task-definition/sample-fargate:1"
        }
    ], 
    "failures": []
}
```

## 7단계: 테스트
<a name="ECS_AWSCLI_Fargate_test"></a>

### 퍼블릭 서브넷을 사용하여 배포된 작업 테스트
<a name="ECS_AWSCLI_Fargate_test_public"></a>

태스크에 대한 탄력적 네트워크 인터페이스(ENI)를 가져올 수 있도록 서비스의 태스크를 설명합니다.

먼저 태스크 ARN을 가져오세요.

```
aws ecs list-tasks --cluster fargate-cluster --service fargate-service
```

출력에는 태스크 ARN이 포함됩니다.

```
{
    "taskArns": [
        "arn:aws:ecs:us-east-1:123456789012:task/fargate-service/EXAMPLE
    ]
}
```

태스크를 설명하고 ENI ID를 찾습니다. `tasks` 파라미터에 태스크 ARN을 사용합니다.

```
aws ecs describe-tasks --cluster fargate-cluster --tasks arn:aws:ecs:us-east-1:123456789012:task/service/EXAMPLE
```

연결 정보가 출력에 나열됩니다.

```
{
    "tasks": [
        {
            "attachments": [
                {
                    "id": "d9e7735a-16aa-4128-bc7a-b2d5115029e9",
                    "type": "ElasticNetworkInterface",
                    "status": "ATTACHED",
                    "details": [
                        {
                            "name": "subnetId",
                            "value": "subnetabcd1234"
                        },
                        {
                            "name": "networkInterfaceId",
                            "value": "eni-0fa40520aeEXAMPLE"
                        },
                    ]
                }
…
}
```

퍼블릭 IP 주소를 가져오기 위해 ENI를 설명합니다.

```
aws ec2 describe-network-interfaces --network-interface-id  eni-0fa40520aeEXAMPLE
```

퍼블릭 IP 주소가 출력에 있습니다.

```
{
    "NetworkInterfaces": [
        {
            "Association": {
                "IpOwnerId": "amazon",
                "PublicDnsName": "ec2-34-229-42-222.compute-1.amazonaws.com",
                "PublicIp": "198.51.100.2"
            },
…
}
```

웹 브라우저에 퍼블릭 IP 주소를 입력하면 **Amazon ECS **샘플 애플리케이션이 표시되는 웹 페이지가 보여야 합니다.

### 프라이빗 서브넷을 사용하여 배포된 작업 테스트
<a name="ECS_AWSCLI_Fargate_test_private.title"></a>

 작업을 설명하고 `ExecuteCommandAgent`가 실행 중인지 확인하기 위해 `managedAgents`를 찾습니다. 나중에 사용할 수 있도록 `privateIPv4Address`를 기록해 둡니다.

```
aws ecs describe-tasks --cluster fargate-cluster --tasks arn:aws:ecs:us-east-1:123456789012:task/fargate-service/EXAMPLE
```

 관리형 에이전트 정보가 출력에 나열됩니다.

```
{
     "tasks": [
        {
            "attachments": [
                {
                    "id": "d9e7735a-16aa-4128-bc7a-b2d5115029e9",
                    "type": "ElasticNetworkInterface",
                    "status": "ATTACHED",
                    "details": [
                        {
                            "name": "subnetId",
                            "value": "subnetabcd1234"
                        },
                        {
                            "name": "networkInterfaceId",
                            "value": "eni-0fa40520aeEXAMPLE"
                        },
                        {
                            "name": "privateIPv4Address",
                            "value": "10.0.143.156"
                        }
                    ]
                }
            ],
     ...  
     "containers": [
         {
         ...
        "managedAgents": [
                        {
                            "lastStartedAt": "2023-08-01T16:10:13.002000+00:00",
                            "name": "ExecuteCommandAgent",
                            "lastStatus": "RUNNING"
                        } 
                ],
        ...
    }
```

 ` ExecuteCommandAgent`가 실행 중인지 확인한 후 다음 명령을 실행하여 작업의 컨테이너에서 대화형 셸을 실행할 수 있습니다.

```
  aws ecs execute-command --cluster fargate-cluster \
      --task  arn:aws:ecs:us-east-1:123456789012:task/fargate-service/EXAMPLE  \
      --container  fargate-app \
      --interactive \
      --command "/bin/sh"
```

 대화형 셸을 실행한 후 다음 명령을 실행하여 cURL을 설치합니다.

```
apt update 
```

```
apt install curl 
```

 cURL을 설치한 후 이전에 얻은 프라이빗 IP 주소를 사용하여 다음 명령을 실행합니다.

```
 curl 10.0.143.156 
```

 **Amazon ECS ** 샘플 애플리케이션 웹 페이지에 해당하는 HTML이 표시됩니다.

```
<html>
    <head> 
     <title>Amazon ECS Sample App</title> 
     <style>body {margin-top: 40px; background-color: #333;} </style>
    </head>
      <body> 
      <div style=color:white;text-align:center> 
      <h1>Amazon ECS Sample App</h1> 
      <h2>Congratulations!</h2> <p>Your application is now running on a container in Amazon ECS.</p> 
      </div>
      </body>
</html>
```

## 8단계: 정리
<a name="ECS_AWSCLI_Fargate_clean_up"></a>

이 자습서로 완료를 한 후에 사용하지 않는 리소스에 대해 요금이 발생하는 것을 방지하기 위해 연결된 리소스를 정리해야 합니다.

서비스를 삭제합니다.

```
aws ecs delete-service --cluster fargate-cluster --service fargate-service --force
```

클러스터를 삭제합니다.

```
aws ecs delete-cluster --cluster fargate-cluster
```

# AWS CLI를 사용하여 Fargate에 대한 Amazon ECS Windows 태스크 생성
<a name="ECS_AWSCLI_Fargate_windows"></a>

다음 단계는 AWS CLI를 사용하여 Amazon ECS에서 클러스터를 설정하고, 태스크 정의를 등록하고, Windows 태스크를 실행하고, 기타 일반적인 시나리오를 수행하는 데 도움이 됩니다. 최신 버전의 AWS CLI를 사용하고 있는지 확인합니다. 최신 버전으로 업그레이드하는 방법에 대한 자세한 내용은 [AWS CLI 최신 버전의 설치 또는 업데이트](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)를 참조하세요.

**참고**  
듀얼 스택 서비스 엔드포인트를 사용하면 AWS CLI, SDK 및 Amazon ECS API에서 IPv4 및 IPv6 모두를 통해 Amazon ECS와 상호 작용할 수 있습니다. 자세한 내용은 [Amazon ECS 듀얼 스택 엔드포인트 사용](dual-stack-endpoint.md) 섹션을 참조하세요.

**Topics**
+ [사전 조건](#ECS_AWSCLI_Fargate_windows_prereq)
+ [1단계: 클러스터 생성](#ECS_AWSCLI_Fargate_windows_create_cluster)
+ [2단계: Windows 태스크 정의 등록](#ECS_AWSCLI_Fargate_windows_register_task_definition)
+ [3단계: 태스크 정의 나열](#ECS_AWSCLI_Fargate_windows__list_task_definitions)
+ [4단계: 서비스 생성](#ECS_AWSCLI_Fargate_windows_create_service)
+ [5단계: 서비스 나열](#ECS_AWSCLI_Fargate_windows_list_services)
+ [6단계: 실행 서비스 설명](#ECS_AWSCLI_Fargate_windows_describe_service)
+ [7단계: 정리](#ECS_AWSCLI_Fargate_windows_clean_up)

## 사전 조건
<a name="ECS_AWSCLI_Fargate_windows_prereq"></a>

이 자습서에서는 다음 사전 조건이 충족되었다고 가정합니다.
+ 최신 버전의 AWS CLI가 설치 및 구성됩니다. AWS CLI 설치 및 업그레이드에 대한 자세한 내용은 [AWS CLI 최신 버전의 설치 또는 업데이트](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)를 참고하세요.
+ [Amazon ECS 사용 설정](get-set-up-for-amazon-ecs.md)의 단계가 완료되었습니다.
+ IAM 사용자는 [AmazonECS\$1FullAccess](security-iam-awsmanpol.md#security-iam-awsmanpol-AmazonECS_FullAccess) IAM 정책 예제에 지정된 필수 권한을 가집니다.
+ 사용할 VPC 및 보안 그룹이 생성되었습니다. 이 자습서에서는 Docker Hub에서 호스팅되는 컨테이너 이미지를 사용하므로 작업에서 인터넷에 액세스할 수 있어야 합니다. 작업에 인터넷 경로를 제공하려면 다음 옵션 중 하나를 사용합니다.
  + 탄력적 IP 주소가 있는 NAT 게이트웨이와 함께 프라이빗 서브넷을 사용합니다.
  + 퍼블릭 서브넷을 사용하고 퍼블릭 IP 주소를 작업에 할당합니다.

  자세한 내용은 [Virtual Private Cloud 생성](get-set-up-for-amazon-ecs.md#create-a-vpc) 섹션을 참조하세요.

  보안 그룹 및 규칙에 대한 자세한 내용은 *Amazon Virtual Private Cloud 사용 설명서*의 [VPC에 대한 기본 보안 그룹](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#DefaultSecurityGroup)과 [규칙 예](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#security-group-rule-examples)를 참조하세요.
+ (선택 사항) AWS CloudShell은 고객에게 자체 EC2 인스턴스를 생성할 필요 없이 명령줄을 제공하는 도구입니다. 자세한 내용은 *AWS CloudShell 사용 설명서*의 [AWS CloudShell이란?](https://docs.aws.amazon.com/cloudshell/latest/userguide/welcome.html)을 참조하세요.

## 1단계: 클러스터 생성
<a name="ECS_AWSCLI_Fargate_windows_create_cluster"></a>

계정에는 기본적으로 `default` 클러스터가 할당됩니다.

**참고**  
제공된 `default` 클러스터를 사용하는 이점은 후속 명령에서 `--cluster cluster_name` 옵션을 지정할 필요가 없다는 것입니다. 기본 클러스터가 아닌 자체 클러스터를 생성하는 경우, 해당 클러스터에 사용할 각 명령에 `--cluster cluster_name`을 지정해야 합니다.

다음 명령을 사용하여 고유한 이름의 자체 클러스터를 생성합니다.

```
aws ecs create-cluster --cluster-name fargate-cluster
```

출력:

```
{
    "cluster": {
        "status": "ACTIVE", 
        "statistics": [], 
        "clusterName": "fargate-cluster", 
        "registeredContainerInstancesCount": 0, 
        "pendingTasksCount": 0, 
        "runningTasksCount": 0, 
        "activeServicesCount": 0, 
        "clusterArn": "arn:aws:ecs:region:aws_account_id:cluster/fargate-cluster"
    }
}
```

## 2단계: Windows 태스크 정의 등록
<a name="ECS_AWSCLI_Fargate_windows_register_task_definition"></a>

Amazon ECS 클러스터에서 Windows 태스크를 실행하려면 먼저 태스크 정의를 등록해야 합니다. 태스크 정의는 그룹화된 컨테이너의 목록입니다. 다음은 웹 앱을 생성하는 단순 태스크 정의의 예입니다. 사용 가능한 태스크 정의 파라미터에 대한 자세한 정보는 [Amazon ECS 작업 정의](task_definitions.md) 섹션을 참조하세요.

```
{
    "containerDefinitions": [
        {
            "command": ["New-Item -Path C:\\inetpub\\wwwroot\\index.html -Type file -Value '<html> <head> <title>Amazon ECS Sample App</title> <style>body {margin-top: 40px; background-color: #333;} </style> </head><body> <div style=color:white;text-align:center> <h1>Amazon ECS Sample App</h1> <h2>Congratulations!</h2> <p>Your application is now running on a container in Amazon ECS.</p>'; C:\\ServiceMonitor.exe w3svc"],
            "entryPoint": [
                "powershell",
                "-Command"
            ],
            "essential": true,
            "cpu": 2048,
            "memory": 4096,
            "image": "mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019",
            "name": "sample_windows_app",
            "portMappings": [
                {
                    "hostPort": 80,
                    "containerPort": 80,
                    "protocol": "tcp"
                }
            ]
        }
    ],
    "memory": "4096",
    "cpu": "2048",
    "networkMode": "awsvpc",
    "family": "windows-simple-iis-2019-core",
    "executionRoleArn": "arn:aws:iam::012345678910:role/ecsTaskExecutionRole",
    "runtimePlatform": {"operatingSystemFamily": "WINDOWS_SERVER_2019_CORE"},
    "requiresCompatibilities": ["FARGATE"]
}
```

위의 예시 JSON은 두 가지 방법으로 AWS CLI에 전달할 수 있습니다. 작업 정의 JSON을 파일로 저장하고 `--cli-input-json file://path_to_file.json` 옵션을 사용하여 전달할 수 있습니다.

컨테이너 정의에 JSON 파일을 사용하려면

```
aws ecs register-task-definition --cli-input-json file://$HOME/tasks/fargate-task.json
```

**register-task-definition** 명령은 등록을 완료한 후 작업 정의의 설명을 반환합니다.

## 3단계: 태스크 정의 나열
<a name="ECS_AWSCLI_Fargate_windows__list_task_definitions"></a>

언제라도 **list-task-definitions** 명령을 사용하여 계정의 작업 정의를 나열할 수 있습니다. 이 명령은 **run-task** 또는 **start-task**를 호출할 때 함께 사용할 수 있는 `family` 및 `revision` 값을 출력합니다.

```
aws ecs list-task-definitions
```

출력:

```
{
    "taskDefinitionArns": [
        "arn:aws:ecs:region:aws_account_id:task-definition/sample-fargate-windows:1"
    ]
}
```

## 4단계: 서비스 생성
<a name="ECS_AWSCLI_Fargate_windows_create_service"></a>

계정에 대한 작업을 등록한 후 클러스터에서 등록된 작업에 대해 서비스를 생성할 수 있습니다. 이 예제에서는 클러스터에서 실행 중인 `sample-fargate:1` 작업 정의 인스턴스 하나를 사용하여 서비스를 생성합니다. 이 작업에는 인터넷 경로가 필요하므로 이 작업을 수행할 수 있는 두 가지 방법이 있습니다. 한 가지 방법은 퍼블릭 서브넷에서 탄력적 IP 주소가 있는 NAT 게이트웨이로 구성된 프라이빗 서브넷을 사용하는 것입니다. 또 다른 방법은 퍼블릭 서브넷을 사용하고 작업에 퍼블릭 IP 주소를 할당하는 것입니다. 아래 두 가지 예를 모두 제공합니다.

프라이빗 서브넷을 사용하는 예.

```
aws ecs create-service --cluster fargate-cluster --service-name fargate-service --task-definition sample-fargate-windows:1 --desired-count 1 --launch-type "FARGATE" --network-configuration "awsvpcConfiguration={subnets=[subnet-abcd1234],securityGroups=[sg-abcd1234]}"
```

퍼블릭 서브넷을 사용하는 예.

```
aws ecs create-service --cluster fargate-cluster --service-name fargate-service --task-definition sample-fargate-windows:1 --desired-count 1 --launch-type "FARGATE" --network-configuration "awsvpcConfiguration={subnets=[subnet-abcd1234],securityGroups=[sg-abcd1234],assignPublicIp=ENABLED}"
```

**create-service** 명령은 등록을 완료한 후 작업 정의의 설명을 반환합니다.

## 5단계: 서비스 나열
<a name="ECS_AWSCLI_Fargate_windows_list_services"></a>

클러스터의 서비스를 나열합니다. 이전 섹션에서 생성한 서비스가 보일 것입니다. 이 명령에서 반환된 서비스 이름 또는 전체 ARN을 기록해 두었다가 나중에 서비스를 설명하는 데 사용할 수 있습니다.

```
aws ecs list-services --cluster fargate-cluster
```

출력:

```
{
    "serviceArns": [
        "arn:aws:ecs:region:aws_account_id:service/fargate-service"
    ]
}
```

## 6단계: 실행 서비스 설명
<a name="ECS_AWSCLI_Fargate_windows_describe_service"></a>

앞서 검색한 서비스 이름으로 서비스를 설명하여 작업에 관한 정보를 더 많이 가져옵니다.

```
aws ecs describe-services --cluster fargate-cluster --services fargate-service
```

성공하면 서비스 실패 및 서비스에 대한 설명이 반환됩니다. 예를 들어 서비스 섹션에서 실행 중이거나 보류 중인 작업 상태와 같이 배포에 대한 정보를 찾을 수 있습니다. 작업 정의, 네트워크 구성 및 타임스탬프가 지정된 이벤트에 대한 정보도 찾을 수 있습니다. 실패 섹션에서는 호출과 관련된 실패(있는 경우)에 대한 정보를 찾을 수 있습니다. 문제 해결에 대한 자세한 정보는 [서비스 이벤트 메시지](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-event-messages.html)를 참조하세요. 서비스 설명에 대한 자세한 정보는 [서비스 설명](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_DescribeServices)을 참조하세요.

```
{
    "services": [
        {
            "status": "ACTIVE", 
            "taskDefinition": "arn:aws:ecs:region:aws_account_id:task-definition/sample-fargate-windows:1", 
            "pendingCount": 2, 
            "launchType": "FARGATE", 
            "loadBalancers": [], 
            "roleArn": "arn:aws:iam::aws_account_id:role/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS", 
            "placementConstraints": [], 
            "createdAt": 1510811361.128, 
            "desiredCount": 2, 
            "networkConfiguration": {
                "awsvpcConfiguration": {
                    "subnets": [
                        "subnet-abcd1234"
                    ], 
                    "securityGroups": [
                        "sg-abcd1234"
                    ], 
                    "assignPublicIp": "DISABLED"
                }
            }, 
            "platformVersion": "LATEST", 
            "serviceName": "fargate-service", 
            "clusterArn": "arn:aws:ecs:region:aws_account_id:cluster/fargate-cluster", 
            "serviceArn": "arn:aws:ecs:region:aws_account_id:service/fargate-service", 
            "deploymentConfiguration": {
                "maximumPercent": 200, 
                "minimumHealthyPercent": 100
            }, 
            "deployments": [
                {
                    "status": "PRIMARY", 
                    "networkConfiguration": {
                        "awsvpcConfiguration": {
                            "subnets": [
                                "subnet-abcd1234"
                            ], 
                            "securityGroups": [
                                "sg-abcd1234"
                            ], 
                            "assignPublicIp": "DISABLED"
                        }
                    }, 
                    "pendingCount": 2, 
                    "launchType": "FARGATE", 
                    "createdAt": 1510811361.128, 
                    "desiredCount": 2, 
                    "taskDefinition": "arn:aws:ecs:region:aws_account_id:task-definition/sample-fargate-windows:1", 
                    "updatedAt": 1510811361.128, 
                    "platformVersion": "0.0.1", 
                    "id": "ecs-svc/9223370526043414679", 
                    "runningCount": 0
                }
            ], 
            "events": [
                {
                    "message": "(service fargate-service) has started 2 tasks: (task 53c0de40-ea3b-489f-a352-623bf1235f08) (task d0aec985-901b-488f-9fb4-61b991b332a3).", 
                    "id": "92b8443e-67fb-4886-880c-07e73383ea83", 
                    "createdAt": 1510811841.408
                }, 
                {
                    "message": "(service fargate-service) has started 2 tasks: (task b4911bee-7203-4113-99d4-e89ba457c626) (task cc5853e3-6e2d-4678-8312-74f8a7d76474).", 
                    "id": "d85c6ec6-a693-43b3-904a-a997e1fc844d", 
                    "createdAt": 1510811601.938
                }, 
                {
                    "message": "(service fargate-service) has started 2 tasks: (task cba86182-52bf-42d7-9df8-b744699e6cfc) (task f4c1ad74-a5c6-4620-90cf-2aff118df5fc).", 
                    "id": "095703e1-0ca3-4379-a7c8-c0f1b8b95ace", 
                    "createdAt": 1510811364.691
                }
            ], 
            "runningCount": 0, 
            "placementStrategy": []
        }
    ], 
    "failures": []
}
```

## 7단계: 정리
<a name="ECS_AWSCLI_Fargate_windows_clean_up"></a>

이 자습서로 완료를 한 후에 사용하지 않는 리소스에 대해 요금이 발생하는 것을 방지하기 위해 연결된 리소스를 정리해야 합니다.

서비스를 삭제합니다.

```
aws ecs delete-service --cluster fargate-cluster --service fargate-service --force
```

클러스터를 삭제합니다.

```
aws ecs delete-cluster --cluster fargate-cluster
```

# AWS CLI를 사용하여 EC2에 대한 Amazon ECS 태스크 생성
<a name="ECS_AWSCLI_EC2"></a>

다음 단계는 AWS CLI를 사용하여 Amazon ECS에서 클러스터를 설정하고, 태스크 정의를 등록하고, 태스크를 실행하고, 기타 일반적인 시나리오를 수행하는 데 도움이 됩니다. AWS CLI의 최신 버전을 사용합니다. 최신 버전으로 업그레이드하는 방법에 대한 자세한 내용은 [AWS CLI 최신 버전의 설치 또는 업데이트](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)를 참조하세요.

**참고**  
듀얼 스택 서비스 엔드포인트를 사용하면 AWS CLI, SDK 및 Amazon ECS API에서 IPv4 및 IPv6 모두를 통해 Amazon ECS와 상호 작용할 수 있습니다. 자세한 내용은 [Amazon ECS 듀얼 스택 엔드포인트 사용](dual-stack-endpoint.md) 섹션을 참조하세요.

**Topics**
+ [사전 조건](#AWSCLI_EC2_prereq)
+ [클러스터 생성](#AWSCLI_EC2_create_cluster)
+ [Amazon ECS AMI로 컨테이너 인스턴스 시작](#AWSCLI_EC2_launch_container_instance)
+ [컨테이너 인스턴스 나열](#AWSCLI_EC2_list_container_instances)
+ [컨테이너 인스턴스 설명](#AWSCLI_EC2_describe_container_instance)
+ [태스크 정의 등록](#AWSCLI_EC2_register_task_definition)
+ [태스크 정의 나열](#AWSCLI_EC2_list_task_definitions)
+ [서비스 생성](#AWSCLI_EC2_run_task)
+ [서비스 나열](#AWSCLI_EC2_list_tasks)
+ [서비스 설명](#AWSCLI_EC2_describe_service)
+ [실행 중인 태스크 설명](#AWSCLI_EC2_describe_task)
+ [웹 서버 테스트](#AWSCLI_EC2_test_web_server)
+ [리소스 정리](#AWSCLI_EC2_clean_up_resources)

## 사전 조건
<a name="AWSCLI_EC2_prereq"></a>

이 자습서에서는 다음 사전 조건이 충족되었다고 가정합니다.
+ 최신 버전의 AWS CLI가 설치 및 구성됩니다. AWS CLI 설치 및 업그레이드에 대한 자세한 내용은 [AWS CLI 최신 버전의 설치 또는 업데이트](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)를 참고하세요.
+ [Amazon ECS 사용 설정](get-set-up-for-amazon-ecs.md)의 단계가 완료되었습니다.
+ IAM 사용자는 [AmazonECS\$1FullAccess](security-iam-awsmanpol.md#security-iam-awsmanpol-AmazonECS_FullAccess) IAM 정책 예제에 지정된 필수 권한을 가집니다.
+ 사용할 컨테이너 인스턴스 IAM 역할이 생성되었습니다. 자세한 내용은 [Amazon ECS 컨테이너 인스턴스 IAM 역할](instance_IAM_role.md) 섹션을 참조하세요.
+ 사용할 VPC가 생성되었습니다. 자세한 내용은 [Virtual Private Cloud 생성](get-set-up-for-amazon-ecs.md#create-a-vpc) 섹션을 참조하세요.
+ (선택 사항) AWS CloudShell은 고객에게 자체 EC2 인스턴스를 생성할 필요 없이 명령줄을 제공하는 도구입니다. 자세한 내용은 *AWS CloudShell 사용 설명서*의 [AWS CloudShell이란?](https://docs.aws.amazon.com/cloudshell/latest/userguide/welcome.html)을 참조하세요.

## 클러스터 생성
<a name="AWSCLI_EC2_create_cluster"></a>

기본적으로 첫 번째 컨테이너 인스턴스를 시작할 때 계정에 `default` 클러스터가 생성됩니다.

**참고**  
제공된 `default` 클러스터를 사용하는 이점은 후속 명령에서 `--cluster cluster_name` 옵션을 지정할 필요가 없다는 것입니다. 기본 클러스터가 아닌 자체 클러스터를 생성하는 경우, 해당 클러스터에 사용할 각 명령에 `--cluster cluster_name`을 지정해야 합니다.

다음 명령을 사용하여 고유한 이름의 자체 클러스터를 생성합니다.

```
aws ecs create-cluster --cluster-name MyCluster
```

출력:

```
{
    "cluster": {
        "clusterName": "MyCluster",
        "status": "ACTIVE",
        "clusterArn": "arn:aws:ecs:region:aws_account_id:cluster/MyCluster"
    }
}
```

## Amazon ECS AMI로 컨테이너 인스턴스 시작
<a name="AWSCLI_EC2_launch_container_instance"></a>

컨테이너 인스턴스는 Amazon ECS 컨테이너 에이전트를 실행하고 클러스터에 등록된 EC2 인스턴스입니다. 이 섹션에서는 ECS 최적화 AMI를 사용하여 EC2 인스턴스를 시작합니다.

**AWS CLI로 컨테이너 인스턴스 시작하려면**

1. 다음 명령을 사용하여 AWS 리전에 대한 최신 ECS 최적화 Amazon Linux 2 AMI ID를 검색합니다. 이 명령은 AWS Systems Manager Parameter Store를 사용하여 최신 ECS 최적화 AMI ID를 가져옵니다. AMI에는 Amazon ECS 컨테이너 에이전트와 Docker 런타임이 사전 설치되어 있습니다.

   ```
   aws ssm get-parameters --names /aws/service/ecs/optimized-ami/amazon-linux-2/recommended --query 'Parameters[0].Value' --output text | jq -r '.image_id'
   ```

   출력:

   ```
   ami-abcd1234
   ```

1. 컨테이너 인스턴스를 관리할 SSH 액세스와 웹 서버에 대한 HTTP 액세스를 허용하는 보안 그룹을 생성합니다.

   ```
   aws ec2 create-security-group --group-name ecs-tutorial-sg --description "ECS tutorial security group"
   ```

   출력:

   ```
   {
       "GroupId": "sg-abcd1234"
   }
   ```

1. 다음 명령을 실행하여 보안 그룹에 인바운드 규칙을 추가합니다.

   ```
   aws ec2 authorize-security-group-ingress --group-id sg-abcd1234 --protocol tcp --port 80 --cidr 0.0.0.0/0
   ```

   출력:

   ```
   {
       "Return": true,
       "SecurityGroupRules": [
           {
               "SecurityGroupRuleId": "sgr-efgh5678",
               "GroupId": "sg-abcd1234",
               "GroupOwnerId": "123456789012",
               "IsEgress": false,
               "IpProtocol": "tcp",
               "FromPort": 80,
               "ToPort": 80,
               "CidrIpv4": "0.0.0.0/0"
           }
       ]
   }
   ```

   이제 보안 그룹은 지정된 IP 범위에서 SSH 액세스를 허용하며 어디에서나 HTTP 액세스를 허용합니다. 프로덕션 환경에서는 SSH 액세스를 특정 IP 주소로 제한하고 필요에 따라 HTTP 액세스를 제한하는 것을 고려해야 합니다.

1. 컨테이너 인스턴스에 대한 SSH 액세스를 위해 EC2 키 페어를 생성합니다.

   ```
   aws ec2 create-key-pair --key-name ecs-tutorial-key --query 'KeyMaterial' --output text > ecs-tutorial-key.pem
   chmod 400 ecs-tutorial-key.pem
   ```

   프라이빗 키는 SSH 액세스에 대한 적절한 권한이 있는 로컬 시스템에 저장됩니다.

1. ECS 최적화 AMI를 사용하여 EC2 인스턴스를 시작하고 클러스터에 조인하도록 구성합니다.

   ```
   aws ec2 run-instances --image-id ami-abcd1234 --instance-type t3.micro --key-name ecs-tutorial-key --security-group-ids sg-abcd1234 --iam-instance-profile Name=ecsInstanceRole --user-data '#!/bin/bash
   echo ECS_CLUSTER=MyCluster >> /etc/ecs/ecs.config'
   {
       "Instances": [
           {
               "InstanceId": "i-abcd1234",
               "ImageId": "ami-abcd1234",
               "State": {
                   "Code": 0,
                   "Name": "pending"
               },
               "PrivateDnsName": "",
               "PublicDnsName": "",
               "StateReason": {
                   "Code": "pending",
                   "Message": "pending"
               },
               "InstanceType": "t3.micro",
               "KeyName": "ecs-tutorial-key",
               "LaunchTime": "2025-01-13T10:30:00.000Z"
           }
       ]
   }
   ```

   사용자 데이터 스크립트는 인스턴스를 `MyCluster`에 등록하도록 Amazon ECS 에이전트를 구성합니다. 인스턴스는 에이전트에 필요한 권한을 제공하는 `ecsInstanceRole` IAM 역할을 사용합니다.

## 컨테이너 인스턴스 나열
<a name="AWSCLI_EC2_list_container_instances"></a>

컨테이너 인스턴스를 시작한지 몇 분 이내에 Amazon ECS 에이전트가 MyCluster 클러스터에 인스턴스를 등록합니다. 다음 명령을 실행하여 클러스터의 컨테이너 인스턴스를 나열할 수 있습니다.

```
aws ecs list-container-instances --cluster MyCluster
```

출력:

```
{
    "containerInstanceArns": [
        "arn:aws:ecs:us-east-1:aws_account_id:container-instance/container_instance_ID"
    ]
}
```

## 컨테이너 인스턴스 설명
<a name="AWSCLI_EC2_describe_container_instance"></a>

컨테이너 인스턴스의 ARN 또는 ID를 지정한 후 **describe-container-instances** 명령을 사용하여 잔여 및 등록된 CPU 및 메모리 리소스와 같은 인스턴스에 대한 가치 있는 정보를 가져올 수 있습니다.

```
aws ecs describe-container-instances --cluster MyCluster --container-instances container_instance_ID
```

출력:

```
{
    "failures": [],
    "containerInstances": [
        {
            "status": "ACTIVE",
            "registeredResources": [
                {
                    "integerValue": 1024,
                    "longValue": 0,
                    "type": "INTEGER",
                    "name": "CPU",
                    "doubleValue": 0.0
                },
                {
                    "integerValue": 995,
                    "longValue": 0,
                    "type": "INTEGER",
                    "name": "MEMORY",
                    "doubleValue": 0.0
                },
                {
                    "name": "PORTS",
                    "longValue": 0,
                    "doubleValue": 0.0,
                    "stringSetValue": [
                        "22",
                        "2376",
                        "2375",
                        "51678"
                    ],
                    "type": "STRINGSET",
                    "integerValue": 0
                },
                {
                    "name": "PORTS_UDP",
                    "longValue": 0,
                    "doubleValue": 0.0,
                    "stringSetValue": [],
                    "type": "STRINGSET",
                    "integerValue": 0
                }
            ],
            "ec2InstanceId": "instance_id",
            "agentConnected": true,
            "containerInstanceArn": "arn:aws:ecs:us-west-2:aws_account_id:container-instance/container_instance_ID",
            "pendingTasksCount": 0,
            "remainingResources": [
                {
                    "integerValue": 1024,
                    "longValue": 0,
                    "type": "INTEGER",
                    "name": "CPU",
                    "doubleValue": 0.0
                },
                {
                    "integerValue": 995,
                    "longValue": 0,
                    "type": "INTEGER",
                    "name": "MEMORY",
                    "doubleValue": 0.0
                },
                {
                    "name": "PORTS",
                    "longValue": 0,
                    "doubleValue": 0.0,
                    "stringSetValue": [
                        "22",
                        "2376",
                        "2375",
                        "51678"
                    ],
                    "type": "STRINGSET",
                    "integerValue": 0
                },
                {
                    "name": "PORTS_UDP",
                    "longValue": 0,
                    "doubleValue": 0.0,
                    "stringSetValue": [],
                    "type": "STRINGSET",
                    "integerValue": 0
                }
            ],
            "runningTasksCount": 0,
            "attributes": [
                {
                    "name": "com.amazonaws.ecs.capability.privileged-container"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.17"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
                },
                {
                    "name": "com.amazonaws.ecs.capability.logging-driver.json-file"
                },
                {
                    "name": "com.amazonaws.ecs.capability.logging-driver.syslog"
                }
            ],
            "versionInfo": {
                "agentVersion": "1.5.0",
                "agentHash": "b197edd",
                "dockerVersion": "DockerVersion: 1.7.1"
            }
        }
    ]
}
```

Amazon EC2 콘솔이나 **aws ec2 describe-instances --instance-id *instance\$1id*** 명령을 사용하여 인스턴스를 모니터링하는 데 사용할 수 있는 Amazon EC2 인스턴스 ID를 찾을 수도 있습니다.

## 태스크 정의 등록
<a name="AWSCLI_EC2_register_task_definition"></a>

Amazon ECS 클러스터에서 태스크를 실행하려면 먼저 태스크 정의를 등록해야 합니다. 태스크 정의는 그룹화된 컨테이너의 목록입니다. 다음 예제는 `nginx` 이미지를 사용하는 간단한 태스크 정의입니다. 사용 가능한 태스크 정의 파라미터에 대한 자세한 정보는 [Amazon ECS 작업 정의](task_definitions.md) 섹션을 참조하세요.

```
{
    "family": "nginx-task",
    "containerDefinitions": [
        {
            "name": "nginx",
            "image": "public.ecr.aws/ecs-sample-image/amazon-ecs-sample:latest",
            "cpu": 256,
            "memory": 512,
            "essential": true,
            "portMappings": [
                {
                    "containerPort": 80,
                    "hostPort": 80,
                    "protocol": "tcp"
                }
            ]
        }
    ],
    "requiresCompatibilities": ["EC2"],
    "networkMode": "bridge"
}
```

위의 예시 JSON은 두 가지 방법으로 AWS CLI에 전달할 수 있습니다. 작업 정의 JSON을 파일로 저장하고 `--cli-input-json file://path_to_file.json` 옵션을 사용하여 전달할 수 있습니다. 또는 JSON에서 따옴표를 제거하고 명령줄에서 JSON 컨테이너 정의를 전달할 수 있습니다. 명령줄에서 컨테이너 정의를 전달하려는 경우 명령에 여러 버전의 작업 정의를 서로 연결하는 데 사용되는 `--family` 파라미터가 추가로 필요합니다.

컨테이너 정의에 JSON 파일을 사용하려면

```
aws ecs register-task-definition --cli-input-json file://$HOME/tasks/nginx.json
```

**register-task-definition**은 등록 후 작업 정의의 설명을 반환합니다.

```
{
    "taskDefinition": {
        "taskDefinitionArn": "arn:aws:ecs:us-east-1:123456789012:task-definition/nginx-task:1",
        "family": "nginx-task",
        "revision": 1,
        "status": "ACTIVE",
        "containerDefinitions": [
            {
                "name": "nginx",
                "image": "public.ecr.aws/docker/library/nginx:latest",
                "cpu": 256,
                "memory": 512,
                "essential": true,
                "portMappings": [
                    {
                        "containerPort": 80,
                        "hostPort": 80,
                        "protocol": "tcp"
                    }
                ],
                "environment": [],
                "mountPoints": [],
                "volumesFrom": []
            }
        ],
        "volumes": [],
        "networkMode": "bridge",
        "compatibilities": [
            "EC2"
        ],
        "requiresCompatibilities": [
            "EC2"
        ]
    }
}
```

## 태스크 정의 나열
<a name="AWSCLI_EC2_list_task_definitions"></a>

언제라도 **list-task-definitions** 명령을 사용하여 계정의 작업 정의를 나열할 수 있습니다. 이 명령은 **create-service**를 호출할 때 함께 사용할 수 있는 `family` 및 `revision` 값을 출력합니다.

```
aws ecs list-task-definitions
```

출력:

```
{
    "taskDefinitionArns": [
        "arn:aws:ec2:us-east-1:aws_account_id:task-definition/sleep360:1",
        "arn:aws:ec2:us-east-1:aws_account_id:task-definition/sleep360:2",
        "arn:aws:ec2:us-east-1:aws_account_id:task-definition/nginx-task:1",
        "arn:aws:ec2:us-east-1:aws_account_id:task-definition/wordpress:3",
        "arn:aws:ec2:us-east-1:aws_account_id:task-definition/wordpress:4",
        "arn:aws:ec2:us-east-1:aws_account_id:task-definition/wordpress:5",
        "arn:aws:ec2:us-east-1:aws_account_id:task-definition/wordpress:6"
    ]
}
```

## 서비스 생성
<a name="AWSCLI_EC2_run_task"></a>

계정에 태스크를 등록하고 클러스터에 등록된 컨테이너 인스턴스를 시작한 후, 등록한 태스크 정의를 사용하여 원하는 수의 태스크를 동시에 실행하고 유지 관리하는 Amazon ECS 서비스를 생성할 수 있습니다. 이 예제에서는 MyCluster 클러스터에 `nginx:1` 태스크 정의의 단일 인스턴스를 배치합니다.

```
aws ecs create-service --cluster MyCluster --service-name nginx-service --task-definition nginx-task:1 --desired-count 1
```

출력:

```
{
    "service": {
        "serviceArn": "arn:aws:ecs:us-east-1:aws_account_id:service/MyCluster/nginx-service",
        "serviceName": "nginx-service",
        "clusterArn": "arn:aws:ecs:us-east-1:aws_account_id:cluster/MyCluster",
        "taskDefinition": "arn:aws:ecs:us-east-1:aws_account_id:task-definition/nginx-task:1",
        "desiredCount": 1,
        "runningCount": 0,
        "pendingCount": 0,
        "launchType": "EC2",
        "status": "ACTIVE",
        "createdAt": "2025-01-13T10:45:00.000Z"
    }
}
```

## 서비스 나열
<a name="AWSCLI_EC2_list_tasks"></a>

클러스터의 서비스를 나열합니다. 이전 섹션에서 생성한 서비스가 보일 것입니다. 이 명령에서 반환된 서비스 ID 또는 전체 ARN을 기록해 두었다가 나중에 서비스를 설명하는 데 사용할 수 있습니다.

```
aws ecs list-services --cluster MyCluster
```

출력:

```
{
    "taskArns": [
        "arn:aws:ecs:us-east-1:aws_account_id:task/task_ID"
    ]
}
```

## 서비스 설명
<a name="AWSCLI_EC2_describe_service"></a>

서비스에 대한 자세한 내용을 보려면 다음 명령을 사용하여 서비스를 설명을 표시합니다.

```
aws ecs describe-services --cluster MyCluster --services nginx-service
```

출력:

```
{
    "services": [
        {
            "serviceArn": "arn:aws:ecs:us-east-1:aws_account_id:service/MyCluster/nginx-service",
            "serviceName": "nginx-service",
            "clusterArn": "arn:aws:ecs:us-east-1:aws_account_id:cluster/MyCluster",
            "taskDefinition": "arn:aws:ecs:us-east-1:aws_account_id:task-definition/nginx-task:1",
            "desiredCount": 1,
            "runningCount": 1,
            "pendingCount": 0,
            "launchType": "EC2",
            "status": "ACTIVE",
            "createdAt": "2025-01-13T10:45:00.000Z",
            "events": [
                {
                    "id": "abcd1234-5678-90ab-cdef-1234567890ab",
                    "createdAt": "2025-01-13T10:45:30.000Z",
                    "message": "(service nginx-service) has started 1 tasks: (task abcd1234-5678-90ab-cdef-1234567890ab)."
                }
            ]
        }
    ]
}
```

## 실행 중인 태스크 설명
<a name="AWSCLI_EC2_describe_task"></a>

서비스를 설명한 후 다음 명령을 실행하여 서비스의 일부로 실행 중인 태스크에 대한 자세한 정보를 가져옵니다.

```
aws ecs list-tasks --cluster MyCluster --service-name nginx-service
```

 출력: 

```
{
    "tasks": [
        {
            "taskArn": "arn:aws:ecs:us-east-1:aws_account_id:task/MyCluster/abcd1234-5678-90ab-cdef-1234567890ab",
            "clusterArn": "arn:aws:ecs:us-east-1:aws_account_id:cluster/MyCluster",
            "taskDefinitionArn": "arn:aws:ecs:us-east-1:aws_account_id:task-definition/nginx-task:1",
            "containerInstanceArn": "arn:aws:ecs:us-east-1:aws_account_id:container-instance/MyCluster/abcd1234-5678-90ab-cdef-1234567890ab",
            "lastStatus": "RUNNING",
            "desiredStatus": "RUNNING",
            "containers": [
                {
                    "containerArn": "arn:aws:ecs:us-east-1:aws_account_id:container/MyCluster/abcd1234-5678-90ab-cdef-1234567890ab/abcd1234-5678-90ab-cdef-1234567890ab",
                    "taskArn": "arn:aws:ecs:us-east-1:aws_account_id:task/MyCluster/abcd1234-5678-90ab-cdef-1234567890ab",
                    "name": "nginx",
                    "lastStatus": "RUNNING",
                    "networkBindings": [
                        {
                            "bindIP": "0.0.0.0",
                            "containerPort": 80,
                            "hostPort": 80,
                            "protocol": "tcp"
                        }
                    ]
                }
            ],
            "createdAt": "2025-01-13T10:45:00.000Z",
            "startedAt": "2025-01-13T10:45:30.000Z"
        }
    ]
}
```

## 웹 서버 테스트
<a name="AWSCLI_EC2_test_web_server"></a>

**웹 서버를 테스트하려면**

1. 다음 명령을 실행하여 컨테이너 인스턴스의 퍼블릭 IP 주소를 검색합니다.

   ```
   aws ec2 describe-instances --instance-ids i-abcd1234 --query 'Reservations[0].Instances[0].PublicIpAddress' --output text
   ```

   출력:

   ```
   203.0.113.25
   ```

1. IP 주소를 검색한 후 IP 주소로 다음 `curl` 명령을 실행합니다.

   ```
   curl http://203.0.113.25
   ```

   출력:

   ```
   <!DOCTYPE html>
   <html>
   <head>
   <title>Welcome to nginx!</title>
   ...
   </head>
   <body>
   <h1>Welcome to nginx!</h1>
   <p>If you can see this page, the nginx web server is successfully installed and working.</p>
   ...
   </body>
   </html>
   ```

   nginx 시작 페이지에서 서비스가 성공적으로 실행되고 인터넷에서 액세스할 수 있는지 확인합니다.

## 리소스 정리
<a name="AWSCLI_EC2_clean_up_resources"></a>

비용이 발생하지 않도록 하려면 이 자습서에서 생성한 리소스를 정리합니다.

**리소스를 정리하려면**

1. 원하는 태스크가 없도록 서비스를 업데이트한 다음, 서비스를 삭제합니다.

   ```
   aws ecs update-service --cluster MyCluster --service nginx-service --desired-count 0
   {
       "service": {
           "serviceArn": "arn:aws:ecs:us-east-1:123456789012:service/MyCluster/nginx-service",
           "serviceName": "nginx-service",
           "desiredCount": 0,
           "runningCount": 1,
           "pendingCount": 0,
           "status": "ACTIVE"
       }
   }
   ```

1. 실행 중인 태스크가 중지될 때까지 기다린 다음, 서비스를 삭제합니다.

   ```
   aws ecs delete-service --cluster MyCluster --service nginx-service
   {
       "service": {
           "serviceArn": "arn:aws:ecs:us-east-1:123456789012:service/MyCluster/nginx-service",
           "serviceName": "nginx-service",
           "status": "DRAINING"
       }
   }
   ```

1. 생성된 컨테이너 인스턴스를 종료합니다.

   ```
   aws ec2 terminate-instances --instance-ids i-abcd1234
   {
       "TerminatingInstances": [
           {
               "InstanceId": "i-abcd1234",
               "CurrentState": {
                   "Code": 32,
                   "Name": "shutting-down"
               },
               "PreviousState": {
                   "Code": 16,
                   "Name": "running"
               }
           }
       ]
   }
   ```

1. 생성한 보안 그룹 및 키 페어를 정리합니다.

   ```
   aws ec2 delete-security-group --group-id sg-abcd1234
   aws ec2 delete-key-pair --key-name ecs-tutorial-key
   rm ecs-tutorial-key.pem
   ```

1. Amazon ECS 클러스터를 삭제합니다.

   ```
   aws ecs delete-cluster --cluster MyCluster
   {
       "cluster": {
           "clusterArn": "arn:aws:ecs:us-east-1:123456789012:cluster/MyCluster",
           "clusterName": "MyCluster",
           "status": "INACTIVE"
       }
   }
   ```

# CloudWatch Events 이벤트를 수신 대기하도록 Amazon ECS 구성
<a name="ecs_cwet"></a>

Amazon ECS 작업 이벤트를 수신 대기하고 이를 CloudWatch Logs 로그 스트림에 기록하는 간단한 Lambda 함수를 설정하는 방법을 알아봅니다.

## 필수 조건: 테스트 클러스터 설정
<a name="cwet_step_1"></a>

이벤트를 캡처할 실행 클러스터가 없는 경우 [Fargate 워크로드에 대한 Amazon ECS 클러스터 생성](create-cluster-console-v2.md)의 단계를 따라 클러스터를 하나 생성합니다. 본 자습서의 말미에서는 이 클러스터에서 태스크를 실행하여 Lambda 함수가 올바로 구성되었는지 테스트합니다.

## 1단계: Lambda 함수 생성
<a name="cwet_step_2"></a>

이 절차에서는 Amazon ECS 이벤트 스트림 메시지의 대상으로 사용할 간단한 Lambda 함수를 생성합니다.

1. [https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/)에서 AWS Lambda 콘솔을 엽니다.

1. **함수 생성(Create function)**을 선택합니다.

1. **Author from scratch(새로 작성)** 화면에서 다음과 같이 합니다.

   1. **이름(Name)**에 값을 입력합니다.

   1. **런타임(Runtime)**에서 Python 버전(예: **Python 3.9**)을 선택합니다.

   1. **역할(Role)**에서 **기본 Lambda 권한을 가진 새 역할 생성(Create a new role with basic Lambda permissions)**을 선택합니다.

1. **함수 생성(Create function)**을 선택합니다.

1. **함수 코드(Function code)** 섹션에서 다음 예제와 일치하도록 샘플 코드를 수정합니다.

   ```
   import json
   
   def lambda_handler(event, context):
       if event["source"] != "aws.ecs":
          raise ValueError("Function only supports input from events with a source type of: aws.ecs")
          
       print('Here is the event:')
       print(json.dumps(event))
   ```

   다음은 Amazon ECS에서 전송하는 이벤트를 인쇄하는 간단한 Python 3.9 함수입니다. 모든 설정이 올바르게 구성되면 이 자습서가 끝날 때 이 Lambda 함수와 연결된 CloudWatch Logs 로그 스트림에 이벤트 세부 정보가 표시됩니다.

1. **저장**을 선택합니다.

## 2단계: 이벤트 규칙 등록
<a name="cwet_step_3"></a>

 다음에는 Amazon ECS 클러스터로부터 작업 이벤트를 캡처하는 CloudWatch Events 이벤트 규칙을 만듭니다. 이 규칙은 규칙이 정의된 계정의 모든 클러스터에서 전송하는 모든 이벤트를 캡처합니다. 작업 메시지 자체에 작업이 상주하는 클러스터와 같은 이벤트 소스에 대한 정보가 포함되며, 이 정보를 사용하여 프로그래밍 방식으로 이벤트를 필터링 및 정렬할 수 있습니다.

**참고**  
AWS Management Console을 사용하여 이벤트 규칙을 만들 경우 콘솔이 Lambda 함수를 호출할 CloudWatch Events 권한을 부여하는 데 필요한 IAM 권한을 자동으로 추가합니다. AWS CLI를 사용하여 이벤트 규칙을 만드는 경우 이 권한을 명시적으로 부여해야 합니다. 자세한 내용은 [Amazon EventBridge 사용 설명서](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-events.html)의 [Amazon EventBridge의 이벤트](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns.html) 및 *Amazon EventBridge 이벤트 패턴*을 참조하세요.

**Lambda 함수로 이벤트를 라우팅하려면**

1. [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/)에서 CloudWatch 콘솔을 엽니다.

1. 탐색 창에서 **이벤트**, **규칙**, **규칙 생성**을 선택합니다.

1. **이벤트 소스(Event Source)**에서 **ECS**를 이벤트 소스로 선택합니다. 기본적으로 규칙이 모든 Amazon ECS 그룹의 모든 Amazon ECS 이벤트에 적용됩니다. 또는 특정 이벤트 또는 특정 Amazon ECS 그룹을 선택할 수 있습니다.

1. **대상**에서 **대상 추가**를 선택하고 **대상 유형**에서 **Lambda 함수**를 선택한 다음 Lambda 함수를 선택하세요.

1. **세부 정보 구성(Configure details)**을 선택합니다.

1. **규칙 정의(Rule definition)**에 규칙 이름과 설명을 입력한 다음 **규칙 생성(Create rule)**을 선택합니다.

## 3단계: 태스크 정의 생성
<a name="cwet_step_task-def"></a>

작업 정의를 생성합니다.

1. [https://console.aws.amazon.com/ecs/v2](https://console.aws.amazon.com/ecs/v2)에서 콘솔을 엽니다.

1. 탐색 창에서 **태스크 정의**를 선택합니다.

1. **새 태스크 정의 생성(Create new Task Definition)**, **JSON으로 새 수정 생성(Create new revision with JSON)**을 선택합니다.

1. 다음 예제 태스크 정의를 복사하여 상자에 붙여 넣은 다음 **저장(Save)**을 선택합니다.

   ```
   {
      "containerDefinitions": [ 
         { 
            "command": [
               "/bin/sh -c \"echo '<html> <head> <title>Amazon ECS Sample App</title> <style>body {margin-top: 40px; background-color: #333;} </style> </head><body> <div style=color:white;text-align:center> <h1>Amazon ECS Sample App</h1> <h2>Congratulations!</h2> <p>Your application is now running on a container in Amazon ECS.</p> </div></body></html>' >  /usr/local/apache2/htdocs/index.html && httpd-foreground\""
            ],
            "entryPoint": [
               "sh",
               "-c"
            ],
            "essential": true,
            "image": "public.ecr.aws/docker/library/httpd:2.4",
            "logConfiguration": { 
               "logDriver": "awslogs",
               "options": { 
                  "awslogs-group" : "/ecs/fargate-task-definition",
                  "awslogs-region": "us-east-1",
                  "awslogs-stream-prefix": "ecs"
               }
            },
            "name": "sample-fargate-app",
            "portMappings": [ 
               { 
                  "containerPort": 80,
                  "hostPort": 80,
                  "protocol": "tcp"
               }
            ]
         }
      ],
      "cpu": "256",
      "executionRoleArn": "arn:aws:iam::012345678910:role/ecsTaskExecutionRole",
      "family": "fargate-task-definition",
      "memory": "512",
      "networkMode": "awsvpc",
      "runtimePlatform": {
           "operatingSystemFamily": "LINUX"
       },
      "requiresCompatibilities": [ 
          "FARGATE" 
       ]
   }
   ```

1. **생성(Create)**을 선택합니다.

## 4단계: 규칙 테스트
<a name="cwet_step_4"></a>

 마지막으로 Amazon ECS 클러스터로부터 작업 이벤트를 캡처하는 CloudWatch Events 이벤트 규칙을 만듭니다. 이 규칙은 규칙이 정의된 계정의 모든 클러스터에서 전송하는 모든 이벤트를 캡처합니다. 작업 메시지 자체에 작업이 상주하는 클러스터와 같은 이벤트 소스에 대한 정보가 포함되며, 이 정보를 사용하여 프로그래밍 방식으로 이벤트를 필터링 및 정렬할 수 있습니다.

**규칙을 테스트하려면**

1. [https://console.aws.amazon.com/ecs/v2](https://console.aws.amazon.com/ecs/v2)에서 콘솔을 엽니다.

1. **Task definitions**(작업 정의)를 선택합니다.

1. **console-sample-app-static**을 선택한 다음 **Deploy**(배포), **Run new task**(새 작업 실행)를 선택합니다.

1. **Cluster**(클러스터)에서 기본값을 선택한 다음 **Deploy**(배포)를 선택합니다.

1. [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/)에서 CloudWatch 콘솔을 엽니다.

1. 탐색 창에서 **로그**를 선택하고 Lambda 함수의 로그 그룹을 선택합니다(예: **/aws/lambda/***my-function*).

1. 이벤트 데이터를 보려면 로그 스트림을 선택합니다.

# Amazon ECS 작업 중지 이벤트에 대한 Amazon Simple Notification Service 알림 보내기
<a name="ecs_cwet2"></a>

필수 컨테이너 중 하나가 종료되어 작업 실행이 중지된 작업 이벤트만 캡처하는 Amazon EventBridge 이벤트 규칙을 구성합니다. 이 이벤트는 특정 Amazon SNS 속성을 포함하는 작업 이벤트만 지정된 `stoppedReason` 주제로 전송합니다.

## 필수 조건: 테스트 클러스터 설정
<a name="cwet2_step_1"></a>

 이벤트를 캡처할 실행 클러스터가 없는 경우 [Getting started with the console using Linux containers on AWS Fargate](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/getting-started-fargate.html#get-started-fargate-cluster)의 단계를 따라 클러스터를 하나 생성합니다. 본 자습서의 말미에서는 이 클러스터에서 태스크를 실행하여 Amazon SNS 주제와 EventBridge 이벤트 규칙이 올바로 구성되었는지 테스트합니다.

## 전제 조건: Amazon SNS 대한 권한 구성
<a name="cwet2_step_1a"></a>

EventBridge가 Amazon SNS 주제에 게시할 수 있도록 허용하려면 aws sns get-topic-attributes 및 aws sns set-topic-attributes 명령을 사용하세요.

권한을 추가하는 방법에 대한 자세한 내용은 *Amazon Simple Notification Service 개발자 안내서*의 [Amazon SNS 권한](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-use-resource-based.html#eb-sns-permissions)을 참조하세요.

다음 권한을 추가합니다.

```
{
  "Sid": "PublishEventsToMyTopic",
  "Effect": "Allow",
  "Principal": {
     "Service": "events.amazonaws.com"
  },
  "Action": "sns: Publish",
  "Resource": "arn:aws:sns:region:account-id:TaskStoppedAlert",
}
```

## 1단계: Amazon SNS 주제 생성 및 구독
<a name="cwet2_step_2"></a>

 본 자습서를 위해 새 이벤트 규칙의 이벤트 대상으로 사용할 Amazon SNS 주제를 구성합니다.

Amazon SNS 주제 생성 및 구독 방법에 대한 자세한 정보는 *Amazon Simple Notification Service 개발자 안내서*의 [Amazon SNS 시작하기](https://docs.aws.amazon.com/sns/latest/dg/sns-getting-started.html#step-create-queue)를 참조하고 다음 표를 사용하여 선택할 옵션을 결정하세요.


| 옵션 | 값 | 
| --- | --- | 
|  Type  | 표준 | 
| 이름 |  TaskStoppedAlert  | 
| 프로토콜 | 이메일 | 
| 엔드포인트 |  현재 액세스 권한이 있는 이메일 주소  | 

## 2단계: 이벤트 규칙 등록
<a name="cwet2_step_3"></a>

 다음에는 컨테이너가 중지된 작업에 대한 작업 중지 이벤트만 캡처하는 이벤트 규칙을 등록합니다.

Amazon SNS 주제 생성 및 구독 방법에 대한 자세한 정보는 [Amazon EventBridge User Guide](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-get-started.html)(Amazon EventBridge 사용 설명서)의 *Create a rule in Amazon EventBridge*(Amazon EventBridge에서 규칙 생성)를 참조하고 다음 표를 사용하여 선택할 옵션을 결정하세요.


| 옵션 | 값 | 
| --- | --- | 
|  규칙 타입  |  이벤트 패턴이 있는 규칙  | 
| 이벤트 소스 | AWS 이벤트 또는 EventBridge 파트너 이벤트 | 
| 이벤트 패턴 |  사용자 정의 패턴(JSON 편집기)  | 
| 이벤트 패턴 |  <pre>{<br />   "source":[<br />      "aws.ecs"<br />   ],<br />   "detail-type":[<br />      "ECS Task State Change"<br />   ],<br />   "detail":{<br />      "lastStatus":[<br />         "STOPPED"<br />      ],<br />      "stoppedReason":[<br />         "Essential container in task exited"<br />      ]<br />   }<br />}</pre> | 
| 대상 유형 |  AWS 서비스  | 
| 대상 | SNS 주제 | 
| 주제 |  TaskStoppedAlert(1단계에서 생성한 주제)  | 

## 3단계: 규칙 테스트
<a name="cwet2_step_4"></a>

규칙이 시작된 직후 종료되는 태스크를 실행하여 규칙이 작동하고 있는지 확인합니다. 이벤트 규칙이 올바로 구성되었다면 몇 분 후에 이벤트 텍스트가 포함된 이메일 메시지를 수신할 것입니다. 규칙 요구 사항을 충족할 수 있는 기존 태스크 정의가 있는 경우 이를 사용하여 태스크를 실행합니다. 없는 경우 다음 단계에 따라 Fargate 태스크 정의를 등록하고 실행할 수 있습니다.

1. [https://console.aws.amazon.com/ecs/v2](https://console.aws.amazon.com/ecs/v2)에서 콘솔을 엽니다.

1. 탐색 창에서 **작업 정의**를 선택합니다.

1. **새 태스크 정의 생성(Create new task definition)**, **JSON으로 새 태스크 정의 생성(Create new task definition with JSON)**을 선택합니다.

1. JSON 편집기 상자에서 JSON 파일을 편집하고 다음을 편집기에 복사합니다.

   ```
   {
      "containerDefinitions":[
         {
            "command":[
               "sh",
               "-c",
               "sleep 5"
            ],
            "essential":true,
            "image":"public.ecr.aws/amazonlinux/amazonlinux:latest",
            "name":"test-sleep"
         }
      ],
      "cpu":"256",
      "executionRoleArn":"arn:aws:iam::012345678910:role/ecsTaskExecutionRole",
      "family":"fargate-task-definition",
      "memory":"512",
      "networkMode":"awsvpc",
      "requiresCompatibilities":[
         "FARGATE"
      ]
   }
   ```

1. **생성(Create)**을 선택합니다.

**콘솔에서 작업을 실행하려면 다음을 수행하세요.**

1. [https://console.aws.amazon.com/ecs/v2](https://console.aws.amazon.com/ecs/v2)에서 콘솔을 엽니다.

1. **클러스터** 페이지에서 사전 조건에서 생성한 클러스터를 선택합니다.

1. **작업(Tasks)** 탭에서 **새 작업 실행(Run new task)**을 선택합니다.

1. **애플리케이션 유형(Application type)**에서 **작업(Task)**을 선택합니다.

1. **작업 정의**에서 **fargate-task-definition**을 선택합니다.

1. **원하는 작업(Desired tasks)**에 시작할 작업 수를 입력합니다.

1. **생성(Create)**을 선택합니다.

# 여러 줄 또는 스택 추적 Amazon ECS 로그 메시지 연결
<a name="firelens-concatanate-multiline"></a>

AWS for Fluent Bit 버전 2.22.0부터 여러 줄 필터가 포함됩니다. 여러 줄 필터를 사용하면 원래 하나의 컨텍스트에 속하지만 여러 레코드 또는 로그 라인으로 분할된 로그 메시지를 연결할 수 있습니다. 여러 줄 필터에 대한 자세한 내용은 [ Fluent Bit 문서](https://docs.fluentbit.io/manual/pipeline/filters/multiline-stacktrace)를 참조하세요.

분할 로그 메시지의 일반적인 예는 다음과 같습니다.
+ 스택 추적.
+ 여러 줄에 로그를 인쇄하는 애플리케이션.
+ 지정된 런타임 최대 버퍼 크기보다 길기 때문에 분할된 메시지를 로그합니다. GitHub의 예제를 따라 컨테이너 런타임으로 분할된 로그 메시지를 연결할 수 있습니다. [FireLens 예제: 부분/분할 컨테이너 로그 연결](https://github.com/aws-samples/amazon-ecs-firelens-examples/tree/mainline/examples/fluent-bit/filter-multiline-partial-message-mode).

## 필수 IAM 권한
<a name="iam-permissions"></a>

컨테이너 에이전트가 Amazon ECR에서 컨테이너 이미지를 가져오고 컨테이너가 로그를 CloudWatch Logs로 라우팅하는 데 필요한 IAM 권한이 있는지 확인해야 합니다.

이러한 권한의 경우 다음 역할이 있어야 합니다.
+ 태스크 IAM 역할.
+ 작업 실행 IAM 역할.

다음 권한이 필요합니다.
+ `logs:CreateLogStream`
+ `logs:CreateLogGroup`
+ `logs:PutLogEvents`

## 여러 줄 로그 설정을 사용할 시기 지정
<a name="determine-filter"></a>

기본 로그 설정과 함께 CloudWatch Logs 콘솔에 표시되는 예제 로그 코드 조각은 다음과 같습니다. `log`로 시작하는 줄을 보고 여러 줄의 필터가 필요한지 결정할 수 있습니다. 컨텍스트가 동일한 경우, 여러 줄 로그 설정을 사용할 수 있습니다. 이 예제에서는 컨텍스트가 'com.myproject.model.MyProject'입니다.

```
2022-09-20T15:47:56:595-05-00                           {"container_id": "82ba37cada1d44d389b03e78caf74faa-EXAMPLE", "container_name": "example-app", "source=": "stdout", "log": ": "     at com.myproject.modele.(MyProject.badMethod.java:22)",
    {
      "container_id":  "82ba37cada1d44d389b03e78caf74faa-EXAMPLE",
      "container_name: ": "example-app",
      "source": "stdout",
      "log": ": "     at com.myproject.model.MyProject.badMethod(MyProject.java:22)",
      "ecs_cluster": "default",
      "ecs_task_arn": "arn:aws:region:123456789012:task/default/b23c940d29ed4714971cba72cEXAMPLE",
      "ecs_task_definition": "firelense-example-multiline:3"
     }
```

```
2022-09-20T15:47:56:595-05-00                           {"container_id": "82ba37cada1d44d389b03e78caf74faa-EXAMPLE", "container_name": "example-app", "stdout", "log": ": "     at com.myproject.modele.(MyProject.oneMoreMethod.java:18)",
    {
      "container_id":  "82ba37cada1d44d389b03e78caf74faa-EXAMPLE",
      "container_name: ": "example-app",
      "source": "stdout",
      "log": ": "     at com.myproject.model.MyProject.oneMoreMethod(MyProject.java:18)",
      "ecs_cluster": "default",
      "ecs_task_arn": "arn:aws:region:123456789012:task/default/b23c940d29ed4714971cba72cEXAMPLE,
      "ecs_task_definition": "firelense-example-multiline:3"
     }
```

여러 줄 로그 설정을 사용한 이후에는 아래의 예시와 유사한 출력이 나옵니다.

```
2022-09-20T15:47:56:595-05-00                           {"container_id": "82ba37cada1d44d389b03e78caf74faa-EXAMPLE", "container_name": "example-app", "stdout",...
    {
      "container_id":  "82ba37cada1d44d389b03e78caf74faa-EXAMPLE",
      "container_name: ": "example-app",
      "source": "stdout",
      "log:    "September 20, 2022 06:41:48 Exception in thread \"main\" java.lang.RuntimeException: Something has gone wrong, aborting!\n    
    at com.myproject.module.MyProject.badMethod(MyProject.java:22)\n    at   
    at com.myproject.model.MyProject.oneMoreMethod(MyProject.java:18) com.myproject.module.MyProject.main(MyProject.java:6)",
      "ecs_cluster": "default",
      "ecs_task_arn": "arn:aws:region:123456789012:task/default/b23c940d29ed4714971cba72cEXAMPLE",
      "ecs_task_definition": "firelense-example-multiline:2"
     }
```

## 구문 분석 및 연결 옵션
<a name="parse-multiline-log"></a>

줄 바꿈으로 인해 로그를 구문 분석하고 분할된 줄을 연결하려면, 다음 두 옵션 중 하나를 사용할 수 있습니다.
+ 동일한 메시지에 속하는 줄을 구문 분석하고 연결하는 규칙이 포함된 고유한 구문 분석기 파일을 사용합니다.
+ Fluent Bit 기본 제공 구문 분석을 사용합니다. Fluent Bit 기본 제공 구문 분석에서 지원하는 언어 목록은 [Fluent Bit 설명서](https://docs.fluentbit.io/manual/pipeline/filters/multiline-stacktrace)를 참조하세요.

다음 자습서에서는 각 사용 사례에 대한 단계를 안내합니다. 이 단계에서는 여러 줄을 연결하고 Amazon CloudWatch로 로그를 전송하는 방법을 보여줍니다. 로그에 대해 다른 대상을 지정할 수 있습니다.

### 예: 생성한 구문 분석기 사용
<a name="customer-parser"></a>

이 예에서는 다음 단계를 완료합니다.

1. Fluent Bit 컨테이너용 이미지를 빌드하고 업로드합니다.

1. 여러 줄 스택 추적을 실행, 실패 및 생성하는 데모 여러 줄 애플리케이션에 대한 이미지를 빌드하고 업로드합니다.

1. 태스크 정의를 생성하고 태스크를 실행합니다.

1. 로그를 보고 여러 줄에 걸쳐 있는 메시지가 연결된 것처럼 보이는지 확인합니다.

**Fluent Bit 컨테이너용 이미지 빌드 및 업로드**

이 이미지에는 정규식을 지정하는 구문 분석기 파일과 구문 분석기 파일을 참조하는 구성 파일이 포함됩니다.

1. `FluentBitDockerImage`라는 폴더를 생성합니다.

1. 폴더 내에 동일한 메시지에 속하는 줄을 구문 분석하고 연결하는 규칙이 포함된 구문 분석기 파일을 생성합니다.

   1. 구문 분석기 파일에 다음 내용을 붙여넣습니다.

      ```
      [MULTILINE_PARSER]
          name          multiline-regex-test
          type          regex
          flush_timeout 1000
          #
          # Regex rules for multiline parsing
          # ---------------------------------
          #
          # configuration hints:
          #
          #  - first state always has the name: start_state
          #  - every field in the rule must be inside double quotes
          #
          # rules |   state name  | regex pattern                  | next state
          # ------|---------------|--------------------------------------------
          rule      "start_state"   "/(Dec \d+ \d+\:\d+\:\d+)(.*)/"  "cont"
          rule      "cont"          "/^\s+at.*/"                     "cont"
      ```

      정규식 패턴을 사용자 지정할 때 정규식 편집기를 사용하여 표현식을 테스트하는 것이 좋습니다.

   1. 파일을 `parsers_multiline.conf`(으)로 저장합니다.

1. `FluentBitDockerImage` 폴더 내에 이전 단계에서 생성한 구문 분석기 파일을 참조하는 사용자 정의 구성 파일을 생성합니다.

   사용자 정의 구성 파일에 대한 자세한 정보는 *Amazon Elastic Container Service 개발자 안내서*의 [사용자 정의 구성 파일 지정](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/firelens-taskdef.html#firelens-taskdef-customconfig)을 참조하세요.

   1. 파일에 다음 내용을 붙여넣습니다.

      ```
      [SERVICE]
          flush                 1
          log_level             info
          parsers_file          /parsers_multiline.conf
          
      [FILTER]
          name                  multiline
          match                 *
          multiline.key_content log
          multiline.parser      multiline-regex-test
      ```
**참고**  
구문 분석기의 절대 경로를 사용해야 합니다.

   1. 파일을 `extra.conf`(으)로 저장합니다.

1. `FluentBitDockerImage` 폴더 내에서 Fluent Bit 이미지와 생성한 구문 분석기 및 구성 파일로 Dockerfile을 생성합니다.

   1. 파일에 다음 내용을 붙여넣습니다.

      ```
      FROM public.ecr.aws/aws-observability/aws-for-fluent-bit:latest
      
      ADD parsers_multiline.conf /parsers_multiline.conf
      ADD extra.conf /extra.conf
      ```

   1. 파일을 `Dockerfile`(으)로 저장합니다.

1. Dockerfile을 사용하여 구문 분석기 및 사용자 정의 구성 파일이 포함된 사용자 정의 Fluent Bit 이미지를 빌드합니다.
**참고**  
이 파일 경로는 FireLens에서 사용하므로 `/fluent-bit/etc/fluent-bit.conf`를 제외한 Docker 이미지의 아무 곳에나 구문 분석기 파일과 구성 파일을 배치할 수 있습니다.

   1. 이미지를 빌드합니다. `docker build -t fluent-bit-multiline-image.` 

      여기서 `fluent-bit-multiline-image`는 이 예에서 이미지의 이름입니다.

   1. 이미지가 올바르게 생성되었는지 확인합니다. `docker images —filter reference=fluent-bit-multiline-image` 

      성공하면 출력에 이미지와 `latest` 태그가 표시됩니다.

1. Amazon Elastic Container Registry에 사용자 정의 Fluent Bit 이미지를 업로드합니다.

   1. 이미지를 저장할 Amazon ECR 리포지토리를 생성합니다. `aws ecr create-repository --repository-name fluent-bit-multiline-repo --region us-east-1` 

      여기서 `fluent-bit-multiline-repo`는 리포지토리의 이름이고 `us-east-1`은 이 예에서 리전입니다.

      출력은 새 리포지토리의 세부 정보를 제공합니다.

   1. 이전 출력의 `repositoryUri` 값으로 이미지에 태깅합니다. `docker tag fluent-bit-multiline-image repositoryUri` 

      예시: `docker tag fluent-bit-multiline-image xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/fluent-bit-multiline-repo` 

   1. Docker 이미지를 실행하여 올바르게 실행되었는지 확인합니다. `docker images —filter reference=repositoryUri` 

      출력에서 리포지토리 이름이 fluent-bit-multiline-repo에서 `repositoryUri`로 변경됩니다.

   1. `aws ecr get-login-password` 명령을 실행하고 인증하려는 레지스트리 ID를 지정하여 Amazon ECR에 인증합니다. `aws ecr get-login-password | docker login --username AWS --password-stdin registry ID.dkr.ecr.region.amazonaws.com` 

      예시: `ecr get-login-password | docker login --username AWS --password-stdin xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com`

      로그인 성공 메시지가 나타납니다.

   1. 이미지를 Amazon ECR에 푸시합니다. `docker push registry ID.dkr.ecr.region.amazonaws.com/repository name` 

      예시: `docker push xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/fluent-bit-multiline-repo`

**데모 여러 줄 애플리케이션용 이미지 빌드 및 업로드**

이 이미지에는 애플리케이션을 실행하는 Python 스크립트 파일과 샘플 로그 파일이 포함됩니다.

태스크를 실행하면 애플리케이션이 실행을 시뮬레이션한 다음 실패하고 스택 추적을 생성합니다.

1. `multiline-app`이라는 폴더를 생성합니다. `mkdir multiline-app` 

1. Python 스크립트 파일을 생성합니다.

   1. `multiline-app` 폴더 내에 파일을 생성하고 이름을 `main.py`로 지정합니다.

   1. 파일에 다음 내용을 붙여넣습니다.

      ```
      import os
      import time
      file1 = open('/test.log', 'r')
      Lines = file1.readlines()
       
      count = 0
      
      for i in range(10):
          print("app running normally...")
          time.sleep(1)
      
      # Strips the newline character
      for line in Lines:
          count += 1
          print(line.rstrip())
      print(count)
      print("app terminated.")
      ```

   1. `main.py` 파일을 저장합니다.

1. 샘플 로그 파일을 생성합니다.

   1. `multiline-app` 폴더 내에 파일을 생성하고 이름을 `test.log`로 지정합니다.

   1. 파일에 다음 내용을 붙여넣습니다.

      ```
      single line...
      Dec 14 06:41:08 Exception in thread "main" java.lang.RuntimeException: Something has gone wrong, aborting!
          at com.myproject.module.MyProject.badMethod(MyProject.java:22)
          at com.myproject.module.MyProject.oneMoreMethod(MyProject.java:18)
          at com.myproject.module.MyProject.anotherMethod(MyProject.java:14)
          at com.myproject.module.MyProject.someMethod(MyProject.java:10)
          at com.myproject.module.MyProject.main(MyProject.java:6)
      another line...
      ```

   1. `test.log` 파일을 저장합니다.

1. `multiline-app` 폴더 내에 Dockerfile을 생성합니다.

   1. 파일에 다음 내용을 붙여넣습니다.

      ```
      FROM public.ecr.aws/amazonlinux/amazonlinux:latest
      ADD test.log /test.log
      
      RUN yum upgrade -y && yum install -y python3
      
      WORKDIR /usr/local/bin
      
      COPY main.py .
      
      CMD ["python3", "main.py"]
      ```

   1. `Dockerfile` 파일을 저장합니다.

1. Dockerfile을 사용하여 이미지를 빌드합니다.

   1. 이미지를 빌드합니다. `docker build -t multiline-app-image ` 

      여기서 `multiline-app-image`는 이 예에서 이미지의 이름입니다.

   1. 이미지가 올바르게 생성되었는지 확인합니다. `docker images —filter reference=multiline-app-image` 

      성공하면 출력에 이미지와 `latest` 태그가 표시됩니다.

1. Amazon Elastic 컨테이너 레지스트리로 이미지를 업로드합니다.

   1. 이미지를 저장할 Amazon ECR 리포지토리를 생성합니다. `aws ecr create-repository --repository-name multiline-app-repo --region us-east-1` 

      여기서 `multiline-app-repo`는 리포지토리의 이름이고 `us-east-1`은 이 예에서 리전입니다.

      출력은 새 리포지토리의 세부 정보를 제공합니다. 다음 단계에서 필요하므로 `repositoryUri` 값을 기록해 둡니다.

   1. 이전 출력의 `repositoryUri` 값으로 이미지에 태깅합니다. `docker tag multiline-app-image repositoryUri` 

      예시: `docker tag multiline-app-image xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/multiline-app-repo` 

   1. Docker 이미지를 실행하여 올바르게 실행되었는지 확인합니다. `docker images —filter reference=repositoryUri` 

      출력에서 리포지토리 이름이 `multiline-app-repo`에서 `repositoryUri` 값으로 변경됩니다.

   1. 이미지를 Amazon ECR에 푸시합니다. `docker push aws_account_id.dkr.ecr.region.amazonaws.com/repository name` 

      예시: `docker push xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/multiline-app-repo`

**태스크 정의 생성 및 태스크 시작**

1. 파일 이름이 `multiline-task-definition.json`인 태스크 정의 파일을 생성합니다.

1. `multiline-task-definition.json` 파일에 다음 내용을 붙여넣습니다.

   ```
   {
       "family": "firelens-example-multiline",
       "taskRoleArn": "task role ARN,
       "executionRoleArn": "execution role ARN",
       "containerDefinitions": [
           {
               "essential": true,
               "image": "aws_account_id.dkr.ecr.us-east-1.amazonaws.com/fluent-bit-multiline-image:latest",
               "name": "log_router",
               "firelensConfiguration": {
                   "type": "fluentbit",
                   "options": {
                       "config-file-type": "file",
                       "config-file-value": "/extra.conf"
                   }
               },
               "memoryReservation": 50
           },
           {
               "essential": true,
               "image": "aws_account_id.dkr.ecr.us-east-1.amazonaws.com/multiline-app-image:latest",
               "name": "app",
               "logConfiguration": {
                   "logDriver": "awsfirelens",
                   "options": {
                       "Name": "cloudwatch_logs",
                       "region": "us-east-1",
                       "log_group_name": "multiline-test/application",
                       "auto_create_group": "true",
                       "log_stream_prefix": "multiline-"
                   }
               },
               "memoryReservation": 100
           }
       ],
       "requiresCompatibilities": ["FARGATE"],
       "networkMode": "awsvpc",
       "cpu": "256",
       "memory": "512"
   }
   ```

   `multiline-task-definition.json` 태스크 정의에서 다음을 바꿉니다.

   1. `task role ARN`

      태스크 역할 ARN을 찾으려면 IAM 콘솔로 이동합니다. **역할(Roles)**을 선택하고 생성한 `ecs-task-role-for-firelens` 태스크 역할을 찾습니다. 역할을 선택하고 **요약(Summary)** 섹션에 표시되는 **ARN**을 복사합니다.

   1. `execution role ARN`

      실행 역할 ARN을 찾으려면 IAM 콘솔로 이동합니다. **역할(Roles)**을 선택하고 `ecsTaskExecutionRole` 역할을 찾습니다. 역할을 선택하고 **요약(Summary)** 섹션에 표시되는 **ARN**을 복사합니다.

   1. `aws_account_id`

      `aws_account_id`를 찾으려면 AWS Management Console에 로그인합니다. 오른쪽 상단에서 사용자 이름을 선택하고 계정 ID를 복사합니다.

   1. `us-east-1`

      필요한 경우 리전을 바꿉니다.

1. 태스크 정의 파일을 등록합니다. `aws ecs register-task-definition --cli-input-json file://multiline-task-definition.json --region region` 

1. [https://console.aws.amazon.com/ecs/v2](https://console.aws.amazon.com/ecs/v2)에서 콘솔을 엽니다.

1. 탐색 창에서 **태스크 정의**를 선택한 다음 위의 태스크 정의의 첫 번째 줄에서 이 제품군에 태스크 정의를 등록했기 때문에 `firelens-example-multiline` 제품군을 선택합니다.

1. 최신 버전을 선택합니다.

1. **배포**, **작업 실행**을 선택합니다.

1. **작업 실행** 페이지의 **클러스터**에서 클러스터를 선택한 다음 **네트워킹** 아래의 **서브넷**에서 작업에 사용할 수 있는 서브넷을 선택하세요.

1. **생성(Create)**을 선택합니다.

**Amazon CloudWatch의 여러 줄 로그 메시지가 연결된 것으로 나타나는지 확인**

1. [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/)에서 CloudWatch 콘솔을 엽니다.

1. 왼쪽 탐색 창에서 **로그**를 확장하고 **로그 그룹**을 선택합니다.

1. `multiline-test/applicatio` 로그 그룹을 선택합니다.

1. 로그를 선택합니다. 메시지를 봅니다. 구문 분석기 파일의 규칙과 일치하는 줄은 연결되어 단일 메시지로 나타납니다.

   다음 로그 조각은 단일 Java 스택 추적 이벤트에 연결된 줄을 보여줍니다.

   ```
   {
       "container_id": "xxxxxx",
       "container_name": "app",
       "source": "stdout",
       "log": "Dec 14 06:41:08 Exception in thread \"main\" java.lang.RuntimeException: Something has gone wrong, aborting!\n    at com.myproject.module.MyProject.badMethod(MyProject.java:22)\n    at com.myproject.module.MyProject.oneMoreMethod(MyProject.java:18)\n    at com.myproject.module.MyProject.anotherMethod(MyProject.java:14)\n    at com.myproject.module.MyProject.someMethod(MyProject.java:10)\n    at com.myproject.module.MyProject.main(MyProject.java:6)",
       "ecs_cluster": "default",
       "ecs_task_arn": "arn:aws:ecs:us-east-1:xxxxxxxxxxxx:task/default/xxxxxx",
       "ecs_task_definition": "firelens-example-multiline:2"
   }
   ```

   다음 로그 조각은 여러 줄 로그 메시지를 연결하도록 구성되지 않은 Amazon ECS 컨테이너를 실행할 경우 한 줄로 동일한 메시지가 어떻게 나타나는지 보여줍니다.

   ```
   {
       "log": "Dec 14 06:41:08 Exception in thread \"main\" java.lang.RuntimeException: Something has gone wrong, aborting!",
       "container_id": "xxxxxx-xxxxxx",
       "container_name": "app",
       "source": "stdout",
       "ecs_cluster": "default",
       "ecs_task_arn": "arn:aws:ecs:us-east-1:xxxxxxxxxxxx:task/default/xxxxxx",
       "ecs_task_definition": "firelens-example-multiline:3"
   }
   ```

### 예: Fluent Bit 기본 제공 구문 분석 사용
<a name="fluent-bit-parser"></a>

이 예에서는 다음 단계를 완료합니다.

1. Fluent Bit 컨테이너용 이미지를 빌드하고 업로드합니다.

1. 여러 줄 스택 추적을 실행, 실패 및 생성하는 데모 여러 줄 애플리케이션에 대한 이미지를 빌드하고 업로드합니다.

1. 태스크 정의를 생성하고 태스크를 실행합니다.

1. 로그를 보고 여러 줄에 걸쳐 있는 메시지가 연결된 것처럼 보이는지 확인합니다.

**Fluent Bit 컨테이너용 이미지 빌드 및 업로드**

이 이미지에는 Fluent Bit 구문 분석기를 참조하는 구성 파일이 포함됩니다.

1. `FluentBitDockerImage`라는 폴더를 생성합니다.

1. `FluentBitDockerImage` 폴더 내에 Fluent Bit 기본 제공 구문 분석기 파일을 참조하는 사용자 정의 구성 파일을 생성합니다.

   사용자 정의 구성 파일에 대한 자세한 정보는 *Amazon Elastic Container Service 개발자 안내서*의 [사용자 정의 구성 파일 지정](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/firelens-taskdef.html#firelens-taskdef-customconfig)을 참조하세요.

   1. 파일에 다음 내용을 붙여넣습니다.

      ```
      [FILTER]
          name                  multiline
          match                 *
          multiline.key_content log
          multiline.parser      go
      ```

   1. 파일을 `extra.conf`(으)로 저장합니다.

1. `FluentBitDockerImage` 폴더 내에서 Fluent Bit 이미지와 생성한 구문 분석기 및 구성 파일로 Dockerfile을 생성합니다.

   1. 파일에 다음 내용을 붙여넣습니다.

      ```
      FROM public.ecr.aws/aws-observability/aws-for-fluent-bit:latest
      ADD extra.conf /extra.conf
      ```

   1. 파일을 `Dockerfile`(으)로 저장합니다.

1. Dockerfile을 사용하여 사용자 정의 구성 파일이 포함된 사용자 정의 Fluent Bit 이미지를 빌드합니다.
**참고**  
이 파일 경로는 FireLens에서 사용하므로 `/fluent-bit/etc/fluent-bit.conf`를 제외한 Docker 이미지의 아무 곳에나 구성 파일을 배치할 수 있습니다.

   1. 이미지를 빌드합니다. `docker build -t fluent-bit-multiline-image.` 

      여기서 `fluent-bit-multiline-image`는 이 예에서 이미지의 이름입니다.

   1. 이미지가 올바르게 생성되었는지 확인합니다. `docker images —filter reference=fluent-bit-multiline-image` 

      성공하면 출력에 이미지와 `latest` 태그가 표시됩니다.

1. Amazon Elastic Container Registry에 사용자 정의 Fluent Bit 이미지를 업로드합니다.

   1. 이미지를 저장할 Amazon ECR 리포지토리를 생성합니다. `aws ecr create-repository --repository-name fluent-bit-multiline-repo --region us-east-1` 

      여기서 `fluent-bit-multiline-repo`는 리포지토리의 이름이고 `us-east-1`은 이 예에서 리전입니다.

      출력은 새 리포지토리의 세부 정보를 제공합니다.

   1. 이전 출력의 `repositoryUri` 값으로 이미지에 태깅합니다. `docker tag fluent-bit-multiline-image repositoryUri` 

      예시: `docker tag fluent-bit-multiline-image xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/fluent-bit-multiline-repo` 

   1. Docker 이미지를 실행하여 올바르게 실행되었는지 확인합니다. `docker images —filter reference=repositoryUri` 

      출력에서 리포지토리 이름이 fluent-bit-multiline-repo에서 `repositoryUri`로 변경됩니다.

   1. `aws ecr get-login-password` 명령을 실행하고 인증하려는 레지스트리 ID를 지정하여 Amazon ECR에 인증합니다. `aws ecr get-login-password | docker login --username AWS --password-stdin registry ID.dkr.ecr.region.amazonaws.com` 

      예시: `ecr get-login-password | docker login --username AWS --password-stdin xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com`

      로그인 성공 메시지가 나타납니다.

   1. 이미지를 Amazon ECR에 푸시합니다. `docker push registry ID.dkr.ecr.region.amazonaws.com/repository name` 

      예시: `docker push xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/fluent-bit-multiline-repo`

**데모 여러 줄 애플리케이션용 이미지 빌드 및 업로드**

이 이미지에는 애플리케이션을 실행하는 Python 스크립트 파일과 샘플 로그 파일이 포함됩니다.

1. `multiline-app`이라는 폴더를 생성합니다. `mkdir multiline-app` 

1. Python 스크립트 파일을 생성합니다.

   1. `multiline-app` 폴더 내에 파일을 생성하고 이름을 `main.py`로 지정합니다.

   1. 파일에 다음 내용을 붙여넣습니다.

      ```
      import os
      import time
      file1 = open('/test.log', 'r')
      Lines = file1.readlines()
       
      count = 0
      
      for i in range(10):
          print("app running normally...")
          time.sleep(1)
      
      # Strips the newline character
      for line in Lines:
          count += 1
          print(line.rstrip())
      print(count)
      print("app terminated.")
      ```

   1. `main.py` 파일을 저장합니다.

1. 샘플 로그 파일을 생성합니다.

   1. `multiline-app` 폴더 내에 파일을 생성하고 이름을 `test.log`로 지정합니다.

   1. 파일에 다음 내용을 붙여넣습니다.

      ```
      panic: my panic
      
      goroutine 4 [running]:
      panic(0x45cb40, 0x47ad70)
        /usr/local/go/src/runtime/panic.go:542 +0x46c fp=0xc42003f7b8 sp=0xc42003f710 pc=0x422f7c
      main.main.func1(0xc420024120)
        foo.go:6 +0x39 fp=0xc42003f7d8 sp=0xc42003f7b8 pc=0x451339
      runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003f7e0 sp=0xc42003f7d8 pc=0x44b4d1
      created by main.main
        foo.go:5 +0x58
      
      goroutine 1 [chan receive]:
      runtime.gopark(0x4739b8, 0xc420024178, 0x46fcd7, 0xc, 0xc420028e17, 0x3)
        /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc420053e30 sp=0xc420053e00 pc=0x42503c
      runtime.goparkunlock(0xc420024178, 0x46fcd7, 0xc, 0x1000f010040c217, 0x3)
        /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc420053e70 sp=0xc420053e30 pc=0x42512e
      runtime.chanrecv(0xc420024120, 0x0, 0xc420053f01, 0x4512d8)
        /usr/local/go/src/runtime/chan.go:506 +0x304 fp=0xc420053f20 sp=0xc420053e70 pc=0x4046b4
      runtime.chanrecv1(0xc420024120, 0x0)
        /usr/local/go/src/runtime/chan.go:388 +0x2b fp=0xc420053f50 sp=0xc420053f20 pc=0x40439b
      main.main()
        foo.go:9 +0x6f fp=0xc420053f80 sp=0xc420053f50 pc=0x4512ef
      runtime.main()
        /usr/local/go/src/runtime/proc.go:185 +0x20d fp=0xc420053fe0 sp=0xc420053f80 pc=0x424bad
      runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc420053fe8 sp=0xc420053fe0 pc=0x44b4d1
      
      goroutine 2 [force gc (idle)]:
      runtime.gopark(0x4739b8, 0x4ad720, 0x47001e, 0xf, 0x14, 0x1)
        /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc42003e768 sp=0xc42003e738 pc=0x42503c
      runtime.goparkunlock(0x4ad720, 0x47001e, 0xf, 0xc420000114, 0x1)
        /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc42003e7a8 sp=0xc42003e768 pc=0x42512e
      runtime.forcegchelper()
        /usr/local/go/src/runtime/proc.go:238 +0xcc fp=0xc42003e7e0 sp=0xc42003e7a8 pc=0x424e5c
      runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003e7e8 sp=0xc42003e7e0 pc=0x44b4d1
      created by runtime.init.4
        /usr/local/go/src/runtime/proc.go:227 +0x35
      
      goroutine 3 [GC sweep wait]:
      runtime.gopark(0x4739b8, 0x4ad7e0, 0x46fdd2, 0xd, 0x419914, 0x1)
        /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc42003ef60 sp=0xc42003ef30 pc=0x42503c
      runtime.goparkunlock(0x4ad7e0, 0x46fdd2, 0xd, 0x14, 0x1)
        /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc42003efa0 sp=0xc42003ef60 pc=0x42512e
      runtime.bgsweep(0xc42001e150)
        /usr/local/go/src/runtime/mgcsweep.go:52 +0xa3 fp=0xc42003efd8 sp=0xc42003efa0 pc=0x419973
      runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003efe0 sp=0xc42003efd8 pc=0x44b4d1
      created by runtime.gcenable
        /usr/local/go/src/runtime/mgc.go:216 +0x58
      one more line, no multiline
      ```

   1. `test.log` 파일을 저장합니다.

1. `multiline-app` 폴더 내에 Dockerfile을 생성합니다.

   1. 파일에 다음 내용을 붙여넣습니다.

      ```
      FROM public.ecr.aws/amazonlinux/amazonlinux:latest
      ADD test.log /test.log
      
      RUN yum upgrade -y && yum install -y python3
      
      WORKDIR /usr/local/bin
      
      COPY main.py .
      
      CMD ["python3", "main.py"]
      ```

   1. `Dockerfile` 파일을 저장합니다.

1. Dockerfile을 사용하여 이미지를 빌드합니다.

   1. 이미지를 빌드합니다. `docker build -t multiline-app-image ` 

      여기서 `multiline-app-image`는 이 예에서 이미지의 이름입니다.

   1. 이미지가 올바르게 생성되었는지 확인합니다. `docker images —filter reference=multiline-app-image` 

      성공하면 출력에 이미지와 `latest` 태그가 표시됩니다.

1. Amazon Elastic 컨테이너 레지스트리로 이미지를 업로드합니다.

   1. 이미지를 저장할 Amazon ECR 리포지토리를 생성합니다. `aws ecr create-repository --repository-name multiline-app-repo --region us-east-1` 

      여기서 `multiline-app-repo`는 리포지토리의 이름이고 `us-east-1`은 이 예에서 리전입니다.

      출력은 새 리포지토리의 세부 정보를 제공합니다. 다음 단계에서 필요하므로 `repositoryUri` 값을 기록해 둡니다.

   1. 이전 출력의 `repositoryUri` 값으로 이미지에 태깅합니다. `docker tag multiline-app-image repositoryUri` 

      예시: `docker tag multiline-app-image xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/multiline-app-repo` 

   1. Docker 이미지를 실행하여 올바르게 실행되었는지 확인합니다. `docker images —filter reference=repositoryUri` 

      출력에서 리포지토리 이름이 `multiline-app-repo`에서 `repositoryUri` 값으로 변경됩니다.

   1. 이미지를 Amazon ECR에 푸시합니다. `docker push aws_account_id.dkr.ecr.region.amazonaws.com/repository name` 

      예시: `docker push xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/multiline-app-repo`

**태스크 정의 생성 및 태스크 시작**

1. 파일 이름이 `multiline-task-definition.json`인 태스크 정의 파일을 생성합니다.

1. `multiline-task-definition.json` 파일에 다음 내용을 붙여넣습니다.

   ```
   {
       "family": "firelens-example-multiline",
       "taskRoleArn": "task role ARN,
       "executionRoleArn": "execution role ARN",
       "containerDefinitions": [
           {
               "essential": true,
               "image": "aws_account_id.dkr.ecr.us-east-1.amazonaws.com/fluent-bit-multiline-image:latest",
               "name": "log_router",
               "firelensConfiguration": {
                   "type": "fluentbit",
                   "options": {
                       "config-file-type": "file",
                       "config-file-value": "/extra.conf"
                   }
               },
               "memoryReservation": 50
           },
           {
               "essential": true,
               "image": "aws_account_id.dkr.ecr.us-east-1.amazonaws.com/multiline-app-image:latest",
               "name": "app",
               "logConfiguration": {
                   "logDriver": "awsfirelens",
                   "options": {
                       "Name": "cloudwatch_logs",
                       "region": "us-east-1",
                       "log_group_name": "multiline-test/application",
                       "auto_create_group": "true",
                       "log_stream_prefix": "multiline-"
                   }
               },
               "memoryReservation": 100
           }
       ],
       "requiresCompatibilities": ["FARGATE"],
       "networkMode": "awsvpc",
       "cpu": "256",
       "memory": "512"
   }
   ```

   `multiline-task-definition.json` 태스크 정의에서 다음을 바꿉니다.

   1. `task role ARN`

      태스크 역할 ARN을 찾으려면 IAM 콘솔로 이동합니다. **역할(Roles)**을 선택하고 생성한 `ecs-task-role-for-firelens` 태스크 역할을 찾습니다. 역할을 선택하고 **요약(Summary)** 섹션에 표시되는 **ARN**을 복사합니다.

   1. `execution role ARN`

      실행 역할 ARN을 찾으려면 IAM 콘솔로 이동합니다. **역할(Roles)**을 선택하고 `ecsTaskExecutionRole` 역할을 찾습니다. 역할을 선택하고 **요약(Summary)** 섹션에 표시되는 **ARN**을 복사합니다.

   1. `aws_account_id`

      `aws_account_id`를 찾으려면 AWS Management Console에 로그인합니다. 오른쪽 상단에서 사용자 이름을 선택하고 계정 ID를 복사합니다.

   1. `us-east-1`

      필요한 경우 리전을 바꿉니다.

1. 태스크 정의 파일을 등록합니다. `aws ecs register-task-definition --cli-input-json file://multiline-task-definition.json --region us-east-1` 

1. [https://console.aws.amazon.com/ecs/v2](https://console.aws.amazon.com/ecs/v2)에서 콘솔을 엽니다.

1. 탐색 창에서 **태스크 정의**를 선택한 다음 위의 태스크 정의의 첫 번째 줄에서 이 제품군에 태스크 정의를 등록했기 때문에 `firelens-example-multiline` 제품군을 선택합니다.

1. 최신 버전을 선택합니다.

1. **배포**, **작업 실행**을 선택합니다.

1. **작업 실행** 페이지의 **클러스터**에서 클러스터를 선택한 다음 **네트워킹** 아래의 **서브넷**에서 작업에 사용할 수 있는 서브넷을 선택하세요.

1. **생성(Create)**을 선택합니다.

**Amazon CloudWatch의 여러 줄 로그 메시지가 연결된 것으로 나타나는지 확인**

1. [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/)에서 CloudWatch 콘솔을 엽니다.

1. 왼쪽 탐색 창에서 **로그**를 확장하고 **로그 그룹**을 선택합니다.

1. `multiline-test/applicatio` 로그 그룹을 선택합니다.

1. 로그를 선택하고 메시지를 봅니다. 구문 분석기 파일의 규칙과 일치하는 줄은 연결되어 단일 메시지로 나타납니다.

   다음 로그 조각은 단일 이벤트로 연결된 Go 스택 추적을 보여줍니다.

   ```
   {
       "log": "panic: my panic\n\ngoroutine 4 [running]:\npanic(0x45cb40, 0x47ad70)\n  /usr/local/go/src/runtime/panic.go:542 +0x46c fp=0xc42003f7b8 sp=0xc42003f710 pc=0x422f7c\nmain.main.func1(0xc420024120)\n  foo.go:6 +0x39 fp=0xc42003f7d8 sp=0xc42003f7b8 pc=0x451339\nruntime.goexit()\n  /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003f7e0 sp=0xc42003f7d8 pc=0x44b4d1\ncreated by main.main\n  foo.go:5 +0x58\n\ngoroutine 1 [chan receive]:\nruntime.gopark(0x4739b8, 0xc420024178, 0x46fcd7, 0xc, 0xc420028e17, 0x3)\n  /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc420053e30 sp=0xc420053e00 pc=0x42503c\nruntime.goparkunlock(0xc420024178, 0x46fcd7, 0xc, 0x1000f010040c217, 0x3)\n  /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc420053e70 sp=0xc420053e30 pc=0x42512e\nruntime.chanrecv(0xc420024120, 0x0, 0xc420053f01, 0x4512d8)\n  /usr/local/go/src/runtime/chan.go:506 +0x304 fp=0xc420053f20 sp=0xc420053e70 pc=0x4046b4\nruntime.chanrecv1(0xc420024120, 0x0)\n  /usr/local/go/src/runtime/chan.go:388 +0x2b fp=0xc420053f50 sp=0xc420053f20 pc=0x40439b\nmain.main()\n  foo.go:9 +0x6f fp=0xc420053f80 sp=0xc420053f50 pc=0x4512ef\nruntime.main()\n  /usr/local/go/src/runtime/proc.go:185 +0x20d fp=0xc420053fe0 sp=0xc420053f80 pc=0x424bad\nruntime.goexit()\n  /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc420053fe8 sp=0xc420053fe0 pc=0x44b4d1\n\ngoroutine 2 [force gc (idle)]:\nruntime.gopark(0x4739b8, 0x4ad720, 0x47001e, 0xf, 0x14, 0x1)\n  /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc42003e768 sp=0xc42003e738 pc=0x42503c\nruntime.goparkunlock(0x4ad720, 0x47001e, 0xf, 0xc420000114, 0x1)\n  /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc42003e7a8 sp=0xc42003e768 pc=0x42512e\nruntime.forcegchelper()\n  /usr/local/go/src/runtime/proc.go:238 +0xcc fp=0xc42003e7e0 sp=0xc42003e7a8 pc=0x424e5c\nruntime.goexit()\n  /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003e7e8 sp=0xc42003e7e0 pc=0x44b4d1\ncreated by runtime.init.4\n  /usr/local/go/src/runtime/proc.go:227 +0x35\n\ngoroutine 3 [GC sweep wait]:\nruntime.gopark(0x4739b8, 0x4ad7e0, 0x46fdd2, 0xd, 0x419914, 0x1)\n  /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc42003ef60 sp=0xc42003ef30 pc=0x42503c\nruntime.goparkunlock(0x4ad7e0, 0x46fdd2, 0xd, 0x14, 0x1)\n  /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc42003efa0 sp=0xc42003ef60 pc=0x42512e\nruntime.bgsweep(0xc42001e150)\n  /usr/local/go/src/runtime/mgcsweep.go:52 +0xa3 fp=0xc42003efd8 sp=0xc42003efa0 pc=0x419973\nruntime.goexit()\n  /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003efe0 sp=0xc42003efd8 pc=0x44b4d1\ncreated by runtime.gcenable\n  /usr/local/go/src/runtime/mgc.go:216 +0x58",
       "container_id": "xxxxxx-xxxxxx",
       "container_name": "app",
       "source": "stdout",
       "ecs_cluster": "default",
       "ecs_task_arn": "arn:aws:ecs:us-east-1:xxxxxxxxxxxx:task/default/xxxxxx",
       "ecs_task_definition": "firelens-example-multiline:2"
   }
   ```

   다음 로그 조각은 여러 줄 로그 메시지를 연결하도록 구성되지 않은 ECS 컨테이너를 실행할 경우 동일한 이벤트가 어떻게 나타나는지 보여줍니다. 로그 필드에는 한 줄이 포함됩니다.

   ```
   {
       "log": "panic: my panic",
       "container_id": "xxxxxx-xxxxxx",
       "container_name": "app",
       "source": "stdout",
       "ecs_cluster": "default",
       "ecs_task_arn": "arn:aws:ecs:us-east-1:xxxxxxxxxxxx:task/default/xxxxxx",
       "ecs_task_definition": "firelens-example-multiline:3"
   ```

**참고**  
로그가 표준 출력 대신 로그 파일로 이동하는 경우 필터 대신 [Tail 입력 플러그 인](https://docs.fluentbit.io/manual/pipeline/inputs/tail#multiline-support)에서 `multiline.parser` 및 `multiline.key_content` 구성 파라미터를 지정하는 것이 좋습니다.

# Amazon ECS Windows 컨테이너에서 Fluent Bit 배포
<a name="tutorial-deploy-fluentbit-on-windows"></a>

Fluent Bit는 다양한 운영 체제에서 지원하는 빠르고 유연한 로그 프로세서 및 라우터입니다. Amazon CloudWatch Logs, Firehose Amazon S3 및 Amazon OpenSearch Service와 같은 다양한 AWS 대상으로 로그를 라우팅하는 데 사용할 수 있습니다. Fluent Bit는 [Datadog](https://www.datadoghq.com/), [Splunk](https://www.splunk.com/) 및 사용자 지정 HTTP 서버와 같은 일반적인 파트너 솔루션을 지원합니다. Fluent Bit에 대한 자세한 내용은 [https://fluentbit.io/](https://fluentbit.io/) 웹 사이트를 참조하세요.

**AWS for Fluent Bit** 이미지는 고가용성을 위해 대부분 리전의 Amazon ECR 퍼블릭 갤러리와 Amazon ECR 리포지토리에 있는 Amazon ECR에 사용할 수 있습니다. 자세한 내용은 GitHub 웹 사이트의 [https://github.com/aws/aws-for-fluent-bit](https://github.com/aws/aws-for-fluent-bit) 섹션을 참조하세요.

이 자습서에서는 Amazon ECS에서 실행 중인 Windows 인스턴스에 Fluent Bit 컨테이너를 배포하여 중앙 집중식 로깅을 위해 Windows 작업에서 생성된 로그를 Amazon CloudWatch로 스트리밍하는 방법을 안내합니다.

이 자습서에서는 다음 접근 방식을 사용합니다.
+ Fluent Bit는 대몬(daemon) 스케줄링 전략과 함께 서비스로 실행됩니다. 이 전략은 Fluent Bit의 단일 인스턴스가 항상 클러스터의 컨테이너 인스턴스에서 실행되도록 합니다.
  + 전달 입력 플러그인을 사용하여 포트 24224에서 수신 대기합니다.
  + 도커 런타임에서 노출된 포트를 사용하여 Fluent Bit로 로그를 전송할 수 있도록 포트 24224를 호스트에 노출합니다.
  + Fluent Bit가 지정된 대상으로 로그 레코드를 전송하도록 허용하는 구성이 있습니다.
+ fluentd 로깅 드라이버를 사용하여 다른 모든 Amazon ECS 작업 컨테이너를 실행합니다. 자세한 내용은 도커 설명서 웹 사이트의 [Fluentd logging driver](https://docs.docker.com/engine/logging/drivers/fluentd/)(Fluentd 로깅 드라이버)를 참조하세요.
  + 도커 는 호스트 네임스페이스 내의 로컬 호스트에 있는 TCP 소켓 24224에 연결합니다.
  + Amazon ECS 에이전트는 클러스터 이름, 작업 정의 패밀리 이름, 작업 정의 개정 번호, 작업 ARN 및 컨테이너 이름을 포함하는 레이블을 컨테이너에 추가합니다. fluentd docker 로깅 드라이버의 label 옵션을 사용하여 동일한 정보가 로그 레코드에 추가됩니다. 자세한 내용은 도커 설명서 웹 사이트의 [labels, labels-regex, env, and env-regex](https://docs.docker.com/config/containers/logging/fluentd/#labels-labels-regex-env-and-env-regex)(labels, labels-regex, env 및 env-regex)를 참조하세요.
  + fluentd 로깅 드라이버의 `async` 옵션이 `true`로 설정되어 있기 때문에 Fluent Bit 컨테이너가 다시 시작되면 도커는 Fluent Bit 컨테이너가 다시 시작될 때까지 로그를 버퍼링합니다. fluentd-buffer-limit 옵션을 설정하여 버퍼 제한을 높일 수 있습니다. 자세한 내용은 도커 설명서 웹 사이트의 [fluentd-buffer-limit](https://docs.docker.com/config/containers/logging/fluentd/#fluentd-buffer-limit)을 참조하세요.

 작업 흐름은 다음과 같습니다.
+ Fluent Bit 컨테이너는 호스트에 노출된 포트 24224에서 시작하고 수신 대기합니다.
+ Fluent Bit는 작업 정의에 지정된 작업 IAM 역할 자격 증명을 사용합니다.
+ 동일한 인스턴스에서 실행되는 다른 작업은 fluentd docker 로깅 드라이버를 사용하여 포트 24224의 Fluent Bit 컨테이너에 연결합니다.
+ 애플리케이션 컨테이너가 로그를 생성하면 도커 런타임은 해당 레코드에 태그를 지정하고, 레이블에 지정된 추가 메타데이터를 추가한 다음 호스트 네임스페이스의 포트 24224에 전달합니다.
+ Fluent Bit는 포트 24224에서 로그 레코드를 수신하는데, 이 포트가 호스트 네임스페이스에 노출되기 때문입니다.
+ Fluent Bit는 내부 처리를 수행하고 지정된 대로 로그를 라우팅합니다.

이 자습서에서는 다음을 수행하는 기본 CloudWatch Fluent Bit 구성을 사용합니다.
+ 각 클러스터 및 작업 정의 패밀리에 대한 새 로그 그룹을 생성합니다.
+ 새 작업이 시작될 때마다 위에 생성된 로그 그룹의 각 작업 컨테이너에 대한 새 로그 스트림을 생성합니다. 각 스트림에는 컨테이너가 속한 작업 ID가 표시됩니다.
+ 클러스터 이름, 작업 ARN, 작업 컨테이너 이름, 작업 정의 패밀리, 작업 정의 개정 번호를 비롯한 추가 메타데이터를 각 로그 항목에 추가합니다.

  예를 들어 `container_1` 및 `container_2`가 포함된 `task_1`과 `container_3`이 포함된 t`ask_2`가 있는 경우 CloudWatch 로그 스트림은 다음과 같습니다.
  + `/aws/ecs/windows.ecs_task_1`

    `task-out.TASK_ID.container_1`

    `task-out.TASK_ID.container_2`
  + `/aws/ecs/windows.ecs_task_2`

    `task-out.TASK_ID.container_3`

**참고**  
듀얼 스택 서비스 엔드포인트를 사용하면 AWS CLI, SDK 및 Amazon ECS API에서 IPv4 및 IPv6 모두를 통해 Amazon ECS와 상호 작용할 수 있습니다. 자세한 내용은 [Amazon ECS 듀얼 스택 엔드포인트 사용](dual-stack-endpoint.md) 섹션을 참조하세요.

**Topics**
+ [사전 조건](#tutorial-deploy-fluentbit-on-windows-prereqs)
+ [1단계: IAM 액세스 역할 생성](#tutorial-deploy-fluentbit-on-windows-iam-access-role)
+ [2단계: Amazon ECS Windows 컨테이너 인스턴스 생성](#tutorial-deploy-fluentbit-on-windows-instance)
+ [3단계: Fluent Bit 구성](#tutorial-deploy-fluentbit-on-windows-configure-fluentbit)
+ [4단계: 로그를 CloudWatch로 라우팅하는 Windows Fluent Bit 작업 정의 등록](#tutorial-deploy-fluentbit-on-windows-register-task-definition)
+ [5단계: 대몬(daemon) 스케줄링 전략을 사용하여 `ecs-windows-fluent-bit` 작업 정의를 Amazon ECS 서비스로 실행](#tutorial-deploy-fluentbit-on-windows-run-task)
+ [6단계: 로그를 생성하는 Windows 작업 정의 등록](#tutorial-deploy-fluentbit-on-windows-register-task-def-logs)
+ [7단계: `windows-app-task` 작업 정의 실행](#tutorial-deploy-fluentbit-on-windows-run-task-fluentbit)
+ [8단계: CloudWatch에서 로그 확인](#tutorial-deploy-fluentbit-on-windows-verify)
+ [9단계: 정리](#tutorial-deploy-fluentbit-on-windows-cleanup)

## 사전 조건
<a name="tutorial-deploy-fluentbit-on-windows-prereqs"></a>

이 자습서에서는 다음 사전 조건이 충족되었다고 가정합니다.
+ 최신 버전의 AWS CLI가 설치 및 구성됩니다. 자세한 내용은 [AWS CLI 최신 버전 설치 또는 업데이트](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)를 참조하세요.
+ `aws-for-fluent-bit` 컨테이너 이미지는 다음 Windows 운영 체제에서 사용할 수 있습니다.
  + Windows Server 2019 Core
  + Windows Server 2019 Full
  + Windows Server 2022 Core
  + Windows Server 2022 Full
+ [Amazon ECS 사용 설정](get-set-up-for-amazon-ecs.md)의 단계가 완료되었습니다.
+ 클러스터가 있습니다. 이 자습서에서 클러스터 이름은 **FluentBit-cluster**입니다.
+ EC2 인스턴스를 실행할 퍼블릭 서브넷이 포함된 VPC가 있습니다. 기본 VPC를 사용할 수 있습니다. Amazon CloudWatch 엔드포인트가 서브넷에 도달할 수 있도록 하는 프라이빗 서브넷을 사용할 수도 있습니다. Amazon CloudWatch 엔드포인트에 대한 자세한 내용은 **AWS 일반 참조의 [Amazon CloudWatch endpoints and quotas](https://docs.aws.amazon.com/general/latest/gr/cw_region.html)를 참조하세요. VPC 생성을 위해 Amazon VPC 마법사를 사용하는 방법에 대한 자세한 내용은 [Virtual Private Cloud 생성](get-set-up-for-amazon-ecs.md#create-a-vpc) 섹션을 참조하세요.

## 1단계: IAM 액세스 역할 생성
<a name="tutorial-deploy-fluentbit-on-windows-iam-access-role"></a>

Amazon ECS IAM 역할을 생성합니다.

1.  Amazon ECS 컨테이너 인스턴스 역할 "ecsInstanceRole"을 생성합니다. 자세한 내용은 [Amazon ECS 컨테이너 인스턴스 IAM 역할](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/instance_IAM_role.html)을 참조하세요.

1. 이름이 `fluentTaskRole`인 Fluent Bit 작업에 대한 IAM 역할을 생성합니다. 자세한 내용은 [Amazon ECS 작업 IAM 역할](task-iam-roles.md) 섹션을 참조하세요.

    이 IAM 역할에 부여된 IAM 권한은 작업 컨테이너에서 수임합니다. Fluent Bit에서 CloudWatch로 로그를 전송하도록 허용하려면 작업 IAM 역할에 다음 권한을 연결해야 합니다.

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
       {
           "Effect": "Allow",
           "Action": [
               "logs:CreateLogStream",
               "logs:CreateLogGroup",
               "logs:DescribeLogStreams",
               "logs:PutLogEvents"
           ],
           "Resource": "*"
       }
       ]
   }
   ```

------

1. 책을 역할에 연결합니다.

   1. `fluent-bit-policy.json` 파일에 위 내용을 저장합니다.

   1. 다음 명령을 실행하여 인라인 정책을 `fluentTaskRole` IAM 역할에 연결합니다.

      ```
      aws iam put-role-policy --role-name fluentTaskRole --policy-name fluentTaskPolicy --policy-document file://fluent-bit-policy.json
      ```

## 2단계: Amazon ECS Windows 컨테이너 인스턴스 생성
<a name="tutorial-deploy-fluentbit-on-windows-instance"></a>

Amazon ECS Windows 컨테이너 인스턴스를 생성합니다.

**Amazon ECS 인스턴스 생성**

1. `aws ssm get-parameters` 명령을 사용하여 VPC를 호스팅하는 리전에 대한 AMI ID를 검색합니다. 자세한 내용은 [Amazon ECS 최적화 AMI 메타데이터 검색](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/retrieve-ecs-optimized_windows_AMI.html)을 참조하세요.

1. Amazon EC2 콘솔을 사용하여 인스턴스를 시작합니다.

   1. [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/)에서 Amazon EC2 콘솔을 엽니다.

   1. 탐색 모음에서 사용할 리전을 선택합니다.

   1. **EC2 대시보드**에서 **인스턴스 시작(Launch Instance)**을 선택합니다.

   1. **Name**(이름)에 고유한 이름을 입력합니다.

   1. **Application and OS Images (Amazon Machine Image)**(애플리케이션 및 OS 이미지(Amazon Machine Image))에서 첫 번째 단계에서 검색한 AMI를 선택합니다.

   1. **인스턴스 유형**에서 `t3.xlarge`를 선택합니다.

   1. **키 페어(로그인)**에서 키 페어를 선택합니다.

   1. **Network settings**(네트워크 설정)의 **Security group**(보안 그룹)에서 기존 보안 그룹을 선택하거나 새 보안 그룹을 생성합니다.

   1. **Network settings**(네트워크 설정)의 **Auto-assign Public IP**(퍼블릭 IP 자동 할당)에서 **Enable**(활성화)을 선택합니다.

   1. **Advanced details**(고급 세부 정보)의 **IAM instance profile**(IAM 인스턴스 프로파일)에서 **ecsInstanceRole**을 선택합니다.

   1. 다음 사용자 데이터로 Amazon ECS 컨테이너 인스턴스를 구성합니다. **Advanced Details**(고급 세부 정보)에서 다음 스크립트를 **User data**(사용자 데이터) 필드에 붙여 넣고 *cluster\$1name*을 클러스터의 이름으로 바꿉니다.

      ```
      <powershell>
      Import-Module ECSTools
      Initialize-ECSAgent -Cluster cluster-name -EnableTaskENI -EnableTaskIAMRole -LoggingDrivers '["awslogs","fluentd"]'
      </powershell>
      ```

   1. 준비가 되었으면 승인 필드를 선택한 다음 **인스턴스 시작(Launch Instances)**을 선택합니다.

   1. 확인 페이지에서 인스턴스가 실행 중인지 확인할 수 있습니다. **인스턴스 보기**를 선택하여 확인 페이지를 닫고 콘솔로 돌아갑니다.

## 3단계: Fluent Bit 구성
<a name="tutorial-deploy-fluentbit-on-windows-configure-fluentbit"></a>

AWS에서 제공하는 다음 기본 구성을 사용하여 빠르게 시작할 수 있습니다.
+ Fluent Bit 공식 설명서**의 [Amazon CloudWatch](https://docs.fluentbit.io/manual/v/1.9-pre/pipeline/outputs/cloudwatch)용 Fluent Bit 플러그인을 기반으로 하는 [Amazon CloudWatch](https://github.com/aws/aws-for-fluent-bit/blob/mainline/ecs_windows_forward_daemon/cloudwatch.conf)

또는 AWS에서 제공하는 다른 기본 구성을 사용할 수 있습니다. 자세한 내용은 Github 웹 사이트의 `aws-for-fluent-bit`에서 [Windows 이미지용 엔트리포인트 재정의](https://github.com/aws/aws-for-fluent-bit/tree/mainline/ecs_windows_forward_daemon#overriding-the-entrypoint-for-the-windows-image)를 참조하세요.

기본 Amazon CloudWatch Fluent Bit 구성은 아래와 같습니다.

다음 변수를 바꿉니다.
+ *region*을 Amazon CloudWatch Logs를 전송하려는 리전으로 바꿉니다.

```
[SERVICE]
    Flush               5
    Log_Level           info
    Daemon              off

[INPUT]
    Name                forward
    Listen              0.0.0.0
    Port                24224
    Buffer_Chunk_Size   1M
    Buffer_Max_Size     6M
    Tag_Prefix          ecs.

# Amazon ECS agent adds the following log keys as labels to the docker container.
# We would use fluentd logging driver to add these to log record while sending it to Fluent Bit.
[FILTER]
    Name                modify
    Match               ecs.*
    Rename              com.amazonaws.ecs.cluster ecs_cluster
    Rename              com.amazonaws.ecs.container-name ecs_container_name
    Rename              com.amazonaws.ecs.task-arn ecs_task_arn
    Rename              com.amazonaws.ecs.task-definition-family ecs_task_definition_family
    Rename              com.amazonaws.ecs.task-definition-version ecs_task_definition_version

[FILTER]
    Name                rewrite_tag
    Match               ecs.*
    Rule                $ecs_task_arn ^([a-z-:0-9]+)/([a-zA-Z0-9-_]+)/([a-z0-9]+)$  out.$3.$ecs_container_name false
    Emitter_Name        re_emitted

[OUTPUT]
    Name                cloudwatch_logs
    Match               out.*
    region              region
    log_group_name      fallback-group
    log_group_template  /aws/ecs/$ecs_cluster.$ecs_task_definition_family
    log_stream_prefix   task-
    auto_create_group   On
```

Fluent Bit에 들어오는 모든 로그에는 지정한 태그가 있으며, 태그를 지정하지 않은 경우에는 자동으로 생성됩니다. 태그를 사용하여 다양한 로그를 각기 다른 대상으로 라우팅할 수 있습니다. 자세한 내용은 Fluent Bit 공식 설명서**의 [Tag](https://docs.fluentbit.io/manual/concepts/key-concepts#tag)(태그)를 참조하세요.

위에서 설명한 Fluent Bit 구성에는 다음과 같은 속성이 있습니다.
+ 전달 입력 플러그인은 TCP 포트 24224에서 들어오는 트래픽을 수신 대기합니다.
+ 해당 포트에서 수신된 각 로그 항목에는 전달 입력 플러그인이 `ecs.` 문자열을 레코드 접두사로 수정하는 태그가 있습니다.
+ Fluent Bit 내부 파이프라인은 Match 정규식을 사용하여 필터를 수정하기 위해 로그 항목을 라우팅합니다. 이 필터는 로그 레코드 JSON의 키를 Fluent Bit가 사용할 수 있는 형식으로 바꿉니다.
+ 그러면 수정된 로그 항목이 rewrite\$1tag 필터에서 사용됩니다. 이 필터는 로그 레코드의 태그를 out.*TASK\$1ID*.*CONTAINER\$1NAME* 형식으로 변경합니다.
+ 새 태그는 CloudWatch 출력 플러그인의 `log_group_template` 및 `log_stream_prefix` 옵션을 사용하여 앞서 설명한 것과 같이 로그 그룹과 스트림을 생성하는 출력 cloudwatch\$1logs 플러그인으로 라우팅됩니다. 자세한 내용은 Fluent Bit 공식 설명서**의 [Configuration parameters](https://docs.fluentbit.io/manual/v/1.9-pre/pipeline/outputs/cloudwatch#configuration-parameters)(구성 파라미터)를 참조하세요.

## 4단계: 로그를 CloudWatch로 라우팅하는 Windows Fluent Bit 작업 정의 등록
<a name="tutorial-deploy-fluentbit-on-windows-register-task-definition"></a>

로그를 CloudWatch로 라우팅하는 Windows Fluent Bit 작업 정의를 등록합니다.

**참고**  
이 작업 정의는 Fluent Bit 컨테이너 포트 24224를 호스트 포트 24224에 노출시킵니다. 외부로부터의 액세스를 방지하기 위해 EC2 인스턴스 보안 그룹에서 이 포트가 열려 있지 않은지 확인합니다.

**태스크 정의를 등록하려면**

1. 다음 콘텐츠를 가진 `fluent-bit.json`이라는 파일을 생성합니다:

   다음 변수를 바꿉니다.
   + **task-iam-role을 작업 IAM 역할의 Amazon 리소스 이름(ARN)으로 바꿉니다.
   + **region을 작업이 실행되는 리전으로 바꿉니다.

   ```
   {
     "family": "ecs-windows-fluent-bit",
     "taskRoleArn": "task-iam-role",
     "containerDefinitions": [
       {
         "name": "fluent-bit",
         "image": "public.ecr.aws/aws-observability/aws-for-fluent-bit:windowsservercore-latest",
         "cpu": 512,
         "portMappings": [
           {
             "hostPort": 24224,
             "containerPort": 24224,
             "protocol": "tcp"
           }
         ],
         "entryPoint": [
           "Powershell",
           "-Command"
         ],
         "command": [
           "C:\\entrypoint.ps1 -ConfigFile C:\\ecs_windows_forward_daemon\\cloudwatch.conf"
         ],
         "environment": [
           {
             "name": "AWS_REGION",
             "value": "region"
           }
         ],
         "memory": 512,
         "essential": true,
         "logConfiguration": {
           "logDriver": "awslogs",
           "options": {
             "awslogs-group": "/ecs/fluent-bit-logs",
             "awslogs-region": "region",
             "awslogs-stream-prefix": "flb",
             "awslogs-create-group": "true"
           }
         }
       }
     ],
     "memory": "512",
     "cpu": "512"
   }
   ```

1. 다음 명령을 실행하여 작업 정의를 등록합니다.

   ```
   aws ecs register-task-definition --cli-input-json file://fluent-bit.json --region region
   ```

   `list-task-definitions` 명령을 실행하여 계정의 작업 정의를 나열할 수 있습니다. 출력에는 `run-task` 또는 `start-task`에 사용할 수 있는 패밀리 및 리비전 값이 표시됩니다.

## 5단계: 대몬(daemon) 스케줄링 전략을 사용하여 `ecs-windows-fluent-bit` 작업 정의를 Amazon ECS 서비스로 실행
<a name="tutorial-deploy-fluentbit-on-windows-run-task"></a>

계정에 대한 작업 정의를 등록한 후 클러스터에서 작업을 실행할 수 있습니다. 이 자습서에서는 `FluentBit-cluster` 클러스터에서 `ecs-windows-fluent-bit:1` 작업 정의의 인스턴스 1개를 실행합니다. Fluent Bit의 단일 인스턴스가 항상 각 컨테이너 인스턴스에서 실행되도록 하는 대몬(daemon) 스케줄링 전략을 사용하는 서비스에서 작업을 실행합니다.

**태스크를 실행하려면**

1. 다음 명령을 실행하여 `ecs-windows-fluent-bit:1` 작업 정의(이전 단계에서 등록됨)를 서비스로 시작합니다.
**참고**  
이 작업 정의는 `awslogs` 로깅 드라이버를 사용하며, 컨테이너 인스턴스에는 필요한 권한이 있어야 합니다.

   다음 변수를 바꿉니다.
   + **region을 서비스가 실행되는 리전으로 바꿉니다.

   ```
   aws ecs create-service \
       --cluster FluentBit-cluster \
       --service-name FluentBitForwardDaemonService \
       --task-definition ecs-windows-fluent-bit:1 \
       --launch-type EC2 \
       --scheduling-strategy DAEMON \
       --region region
   ```

1. 다음 명령을 실행하여 작업을 나열합니다.

   다음 변수를 바꿉니다.
   + **region을 서비스 작업이 실행되는 리전으로 바꿉니다.

   ```
   aws ecs list-tasks --cluster FluentBit-cluster --region region
   ```

## 6단계: 로그를 생성하는 Windows 작업 정의 등록
<a name="tutorial-deploy-fluentbit-on-windows-register-task-def-logs"></a>

로그를 생성하는 작업 정의를 등록합니다. 이 작업 정의는 1초마다 `stdout`에 증분 숫자를 기록하는 Windows 컨테이너 이미지를 배포합니다.

작업 정의는 Fluent Bit 플러그인이 수신 대기하는 포트 24224에 연결되는 fluentd 로깅 드라이버를 사용합니다. Amazon ECS 에이전트는 클러스터 이름, 작업 ARN, 작업 정의 패밀리 이름, 작업 정의 개정 번호 및 작업 컨테이너 이름을 포함하는 태그를 사용하여 각 Amazon ECS 컨테이너에 레이블을 추가합니다. 이러한 키-값 레이블은 Fluent Bit에 전달됩니다.

**참고**  
이 작업은 `default` 네트워크 모드를 사용합니다. 하지만 작업에서 `awsvpc` 네트워크 모드를 사용할 수도 있습니다.

**태스크 정의를 등록하려면**

1. 다음 콘텐츠를 가진 `windows-app-task.json`이라는 파일을 생성합니다:

   ```
   {
     "family": "windows-app-task",
     "containerDefinitions": [
       {
         "name": "sample-container",
         "image": "mcr.microsoft.com/windows/servercore:ltsc2019",
         "cpu": 512,
         "memory": 512,
         "essential": true,
         "entryPoint": [
           "Powershell",
           "-Command"
         ],
         "command": [
           "$count=1;while(1) { Write-Host $count; sleep 1; $count=$count+1;}"
         ],
         "logConfiguration": {
           "logDriver": "fluentd",
           "options": {
             "fluentd-address": "localhost:24224",
             "tag": "{{ index .ContainerLabels \"com.amazonaws.ecs.task-definition-family\" }}",
             "fluentd-async": "true",
             "labels": "com.amazonaws.ecs.cluster,com.amazonaws.ecs.container-name,com.amazonaws.ecs.task-arn,com.amazonaws.ecs.task-definition-family,com.amazonaws.ecs.task-definition-version"
           }
         }
       }
     ],
     "memory": "512",
     "cpu": "512"
   }
   ```

1. 다음 명령을 실행하여 작업 정의를 등록합니다.

   다음 변수를 바꿉니다.
   + **region을 작업이 실행되는 리전으로 바꿉니다.

   ```
   aws ecs register-task-definition --cli-input-json file://windows-app-task.json --region region
   ```

   `list-task-definitions` 명령을 실행하여 계정의 작업 정의를 나열할 수 있습니다. 출력에는 `run-task` 또는 `start-task`에 사용할 수 있는 패밀리 및 리비전 값이 표시됩니다.

## 7단계: `windows-app-task` 작업 정의 실행
<a name="tutorial-deploy-fluentbit-on-windows-run-task-fluentbit"></a>

`windows-app-task` 작업 정의를 등록한 후 `FluentBit-cluster` 클러스터에서 실행합니다.

**태스크를 실행하려면**

1. 이전 단계에서 등록한 `windows-app-task:1` 작업 정의를 실행합니다.

   다음 변수를 바꿉니다.
   + **region을 작업이 실행되는 리전으로 바꿉니다.

   ```
   aws ecs run-task --cluster FluentBit-cluster --task-definition windows-app-task:1 --count 2 --region region
   ```

1. 다음 명령을 실행하여 작업을 나열합니다.

   ```
   aws ecs list-tasks --cluster FluentBit-cluster
   ```

## 8단계: CloudWatch에서 로그 확인
<a name="tutorial-deploy-fluentbit-on-windows-verify"></a>

Fluent Bit 설정을 확인하려면 CloudWatch 콘솔에서 다음 로그 그룹을 확인합니다.
+ `/ecs/fluent-bit-logs` - 컨테이너 인스턴스에서 실행 중인 Fluent Bit 대몬(daemon) 컨테이너에 해당하는 로그 그룹입니다.
+ `/aws/ecs/FluentBit-cluster.windows-app-task` - `FluentBit-cluster` 클러스터 내 `windows-app-task` 작업 정의 패밀리에 대해 실행된 모든 작업에 해당하는 로그 그룹입니다.

   `task-out.FIRST_TASK_ID.sample-container` - 이 로그 스트림에는 sample-container 작업 컨테이너에 있는 작업의 첫 번째 인스턴스에서 생성된 모든 로그가 포함됩니다.

  `task-out.SECOND_TASK_ID.sample-container` - 이 로그 스트림에는 sample-container 작업 컨테이너에 있는 작업의 두 번째 인스턴스에서 생성된 모든 로그가 포함됩니다.

 `task-out.TASK_ID.sample-container` 로그 스트림에는 다음과 유사한 필드가 있습니다.

```
{
    "source": "stdout",
    "ecs_task_arn": "arn:aws:ecs:region:0123456789012:task/FluentBit-cluster/13EXAMPLE",
    "container_name": "/ecs-windows-app-task-1-sample-container-cEXAMPLE",
    "ecs_cluster": "FluentBit-cluster",
    "ecs_container_name": "sample-container",
    "ecs_task_definition_version": "1",
    "container_id": "61f5e6EXAMPLE",
    "log": "10",
    "ecs_task_definition_family": "windows-app-task"
}
```

**Fluent Bit 설정 확인**

1. [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/)에서 CloudWatch 콘솔을 엽니다.

1. 탐색 창에서 **로그 그룹**을 선택합니다. 컨테이너에 Fluent Bit를 배포한 리전에 있는지 확인합니다.

   해당 AWS 리전의 로그 그룹 목록에서 다음을 확인해야 합니다.
   + `/ecs/fluent-bit-logs`
   + `/aws/ecs/FluentBit-cluster.windows-app-task`

   이러한 로그 그룹을 보면 Fluent Bit 설정이 확인됩니다.

## 9단계: 정리
<a name="tutorial-deploy-fluentbit-on-windows-cleanup"></a>

이 자습서를 완료한 후에는 사용하지 않는 리소스에 요금이 발생하지 않도록 연결된 리소스를 정리합니다.

**자습서 리소스를 정리하려면**

1. `windows-simple-task` 작업과 `ecs-fluent-bit` 작업을 중지합니다. 자세한 내용은 [Amazon ECS 태스크 중지](standalone-task-stop.md) 섹션을 참조하세요.

1. 다음 명령을 실행하여 `/ecs/fluent-bit-logs` 로그 그룹을 삭제합니다. 로그 그룹 삭제에 대한 자세한 내용은 AWS Command Line Interface 참조**의 [delete-log-group](https://docs.aws.amazon.com/cli/latest/reference/logs/delete-log-group.html)을 참조하세요.

   ```
   aws logs delete-log-group --log-group-name /ecs/fluent-bit-logs
   aws logs delete-log-group --log-group-name /aws/ecs/FluentBit-cluster.windows-app-task
   ```

1. 다음 명령을 실행하여 인스턴스를 종료합니다.

   ```
   aws ec2 terminate-instances --instance-ids instance-id
   ```

1. 다음 명령을 실행하여 IAM 역할을 삭제합니다.

   ```
   aws iam delete-role --role-name ecsInstanceRole
   aws iam delete-role --role-name fluentTaskRole
   ```

1. 다음 명령을 실행하여 Amazon ECS 클러스터를 삭제합니다.

   ```
   aws ecs delete-cluster --cluster FluentBit-cluster
   ```

# Amazon ECS에서 EC2 Linux 컨테이너에 대해 gMSA 사용
<a name="linux-gmsa"></a>

Amazon ECS는 *그룹 관리형 서비스 계정*(gMSA)이라는 특수한 종류의 서비스 계정을 통해 EC2의 Linux 컨테이너에 대한 Active Directory 인증을 지원합니다.

.NET Core 애플리케이션과 같은 Linux 기반 네트워크 애플리케이션은 Active Directory를 사용하여 사용자와 서비스 간의 인증 및 권한 부여 관리를 용이하게 할 수 있습니다. Active Directory와 통합되고 도메인 가입된 서버에서 실행되는 애플리케이션을 설계하여 이 기능을 사용할 수 있습니다. 하지만 Linux 컨테이너는 도메인에 가입할 수 없으므로 gMSA로 실행할 Linux 컨테이너를 구성해야 합니다.

gMSA로 실행되는 Linux 컨테이너는 컨테이너의 호스트 Amazon EC2 인스턴스에서 실행되는 `credentials-fetcher` 대몬(daemon)을 사용합니다. 즉, 대몬(daemon)은 Active Directory 도메인 컨트롤러에서 gMSA 보안 인증을 검색한 다음 이러한 보안 인증을 컨테이너 인스턴스로 전송합니다. 서비스 계정에 대한 자세한 내용은 Microsoft Learn 웹 사이트에서 [Create gMSAs for Windows containers](https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/manage-serviceaccounts)를 참조하세요.

## 고려 사항
<a name="linux-gmsa-considerations"></a>

Linux 컨테이너에 gMSA를 사용하기 전에 다음 사항을 고려하세요.
+ 컨테이너가 EC2에서 실행되는 경우 Windows 컨테이너와 Linux 컨테이너에 gMSA를 사용할 수 있습니다. Fargate의 Linux 컨테이너에서 gMSA를 사용하는 방법에 대한 자세한 내용은 [Fargate의 Linux 컨테이너에서 gMSA 사용](fargate-linux-gmsa.md) 섹션을 참조하세요.
+ 사전 조건을 완료하려면 도메인에 가입된 Windows 컴퓨터가 필요할 수 있습니다. 예를 들어, PowerShell을 사용하여 Active Directory에서 gMSA를 생성하려면 도메인에 가입된 Windows 컴퓨터가 필요할 수 있습니다. RSAT Active Director PowerShell 도구는 Windows에서만 사용할 수 있습니다. 자세한 내용은 [Installing the Active Directory administration tools](https://docs.aws.amazon.com/directoryservice/latest/admin-guide/ms_ad_install_ad_tools.html)를 참조하세요.
+ **도메인 없는 gMSA** 및 **각 인스턴스를 단일 도메인에 가입** 중에서 선택할 수 있습니다. 도메인 없는 gMSA를 사용하면 컨테이너 인스턴스는 도메인에 가입되지 않고, 인스턴스의 다른 애플리케이션은 보안 인증을 사용하여 도메인에 액세스할 수 없고, 다른 도메인에 가입하는 작업은 동일한 인스턴스에서 실행될 수 있습니다.

  그런 다음 CredSpec 및 선택적으로 도메인 없는 gMSA에 대한 Active Directory 사용자 보안 인증으로 데이터 스토리지를 선택합니다.

  Amazon ECS는 Active Directory 보안 인증 사양 파일(CredSpec)을 사용합니다. 이 파일은 gMSA 계정 컨텍스트를 컨테이너에 전파하는 데 사용되는 gMSA 메타데이터를 포함합니다. CredSpec 파일을 생성하고 다음 표의 컨테이너 인스턴스의 운영 체제별 CredSpec 스토리지 옵션 중 하나에 저장합니다. 도메인 없는 방법을 사용하려면 CredSpec 파일의 선택적 섹션에서 다음 표의 컨테이너 인스턴스의 운영 체제별 *domainless user credentials*스토리지 옵션 중 하나에 보안 인증을 지정할 수 있습니다.    
<a name="gmsa-table"></a>[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/AmazonECS/latest/developerguide/linux-gmsa.html)

## 사전 조건
<a name="linux-gmsa-prerequisites"></a>

Amazon ECS에서 Linux 컨테이너 기능에 gMSA를 사용하려면 먼저 다음 사항을 충족해야 합니다.
+ 컨테이너에서 액세스할 리소스를 포함하는 Active Directory 도메인을 설정합니다. Amazon ECS는 다음 설정을 지원합니다.
  + Directory Service Active Directory. Directory Service는 Amazon EC2에 호스트되는 AWS 관리형 Active Directory입니다. 자세한 내용은 *AWS Directory Service 관리 안내서*의 [AWS 관리형 Microsoft AD 시작하기](https://docs.aws.amazon.com/directoryservice/latest/admin-guide/ms_ad_getting_started.html)를 참조하세요.
  + 온프레미스 Active Directory. Amazon ECS Linux 컨테이너 인스턴스가 도메인에 가입할 수 있도록 해야 합니다. 자세한 내용은 [AWS Direct Connect](https://docs.aws.amazon.com/whitepapers/latest/aws-vpc-connectivity-options/aws-direct-connect.html) 섹션을 참조하세요.
+ Active Directory에 기존 gMSA 계정이 있습니다. 자세한 내용은 [Amazon ECS에서 EC2 Linux 컨테이너에 대해 gMSA 사용](#linux-gmsa) 섹션을 참조하세요.
+ Amazon ECS Linux 컨테이너 인스턴스에 `credentials-fetcher` 대몬(daemon)을 설치하여 실행하고 있습니다. 또한 Active Directory에 인증하기 위해 `credentials-fetcher` 대몬(daemon)에 초기 보안 인증 세트를 추가했습니다.
**참고**  
`credentials-fetcher` 대몬(daemon)은 Amazon Linux 2023 및 Fedora 37 이상에서만 사용할 수 있습니다. Amazon Linux 2에서는 대몬(daemon)을 사용할 수 없습니다. 자세한 내용은 GitHub의 [aws/credentials-fetcher](https://github.com/aws/credentials-fetcher)를 참조하세요.
+ `credentials-fetcher` 대몬(daemon)을 Active Directory에 인증하기 위해 보안 인증을 설정합니다. 보안 인증은 gMSA 계정에 액세스할 수 있는 Active Directory 보안 그룹의 멤버여야 합니다. [인스턴스를 도메인에 가입시킬지, 아니면 도메인 없는 gMSA를 사용할지 결정합니다.](#linux-gmsa-initial-creds)에 에는 여러 옵션이 있습니다.
+ 필요한 IAM 권한을 추가했습니다. 필요한 권한은 초기 보안 인증 및 보안 인증 사양 저장을 위해 선택하는 방법에 따라 달라집니다.
  + 초기 보안 인증에 *도메인 없는 gMSA*를 사용하는 경우 AWS Secrets Manager에 대한 IAM 권한이 작업 실행 역할에 필요합니다.
  + 보안 인증 사양을 SSM Parameter Store에 저장하는 경우 Amazon EC2 Systems Manager Parameter Store에 대한 IAM 권한이 작업 실행 역할에 필요합니다.
  + 보안 인증 사양을 Amazon S3에 저장하는 경우에는 Amazon Simple Storage Service에 대한 IAM 권한이 작업 실행 역할에 필요합니다.

## Amazon ECS에서 gMSA 지원 Linux 컨테이너 설정
<a name="linux-gmsa-setup"></a>
<a name="linux-gmsa-setup-infra"></a>
**인프라 준비**  
다음 단계는 고려 사항과 한 번 수행하는 설정입니다. 이 단계를 완료하면 컨테이너 인스턴스 생성을 자동화하여 이 구성을 재사용할 수 있습니다.

초기 보안 인증을 제공하는 방법을 결정하고 재사용 가능한 EC2 시작 템플릿에 EC2 사용자 데이터를 구성하여 `credentials-fetcher` 대몬(daemon)을 설치합니다.

1. <a name="linux-gmsa-initial-creds"></a>

**인스턴스를 도메인에 가입시킬지, 아니면 도메인 없는 gMSA를 사용할지 결정합니다.**
   + <a name="linux-gmsa-initial-join"></a>

**EC2 인스턴스를 Active Directory 도메인에 가입**

     
     + <a name="linux-gmsa-initial-join-userdata"></a>

**사용자 데이터로 인스턴스 가입**

       EC2 시작 템플릿의 EC2 사용자 데이터에 Active Directory 도메인에 가입하는 단계를 추가합니다. 여러 Amazon EC2 Auto Scaling 그룹에서 동일한 시작 템플릿을 사용할 수 있습니다.

       Fedora Docs의 [Joining an Active Directory or FreeIPA domain](https://docs.fedoraproject.org/en-US/quick-docs/join-active-directory-freeipa/) 단계를 사용할 수 있습니다.
   + <a name="linux-gmsa-initial-domainless"></a>

**도메인 없는 gMSA를 위한 Active Directory 사용자 만들기**

     `credentials-fetcher` 대몬(daemon)에는* *도메인 없는 gMSA라는 기능이 있습니다. 이 기능에는 도메인이 필요하지만 EC2 인스턴스를 도메인에 가입시킬 필요는 없습니다. 도메인 없는 gMSA를 사용하면 컨테이너 인스턴스는 도메인에 가입되지 않고, 인스턴스의 다른 애플리케이션은 보안 인증을 사용하여 도메인에 액세스할 수 없고, 다른 도메인에 가입하는 작업은 동일한 인스턴스에서 실행될 수 있습니다. 대신 AWS Secrets Manager에서 CredSpec 파일에 보안 암호의 이름을 입력합니다. 보안 암호에는 사용자 이름, 암호 및 로그인할 도메인이 포함되어야 합니다.

     이 기능은 Linux 및 Windows 컨테이너에서 지원되며 사용할 수 있습니다.

     이 기능은 *gMSA support for non-domain-joined container hosts* 기능과 유사합니다. Windows 기능에 대한 자세한 내용은 Microsoft Learn 웹 사이트의 [gMSA architecture and improvements](https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/manage-serviceaccounts#gmsa-architecture-and-improvements)를 참조하세요.

     1. Active Directory 도메인에서 사용자를 만듭니다. Active Directory의 사용자는 작업에서 사용하는 gMSA 서비스 계정에 액세스할 수 있는 권한이 있어야 합니다.

     1. Active Directory에서 사용자를 만든 후 AWS Secrets Manager에서 비밀을 생성합니다. 자세한 내용은 [AWS Secrets Manager 보안 암호 생성](https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_secret.html)을 참조하세요.

     1. 사용자의 사용자 이름, 암호 및 도메인을 각각 `username`, `password` 및 `domainName`이라는 JSON 키-값 쌍에 입력합니다.

        ```
        {"username":"username","password":"passw0rd", "domainName":"example.com"}
        ```

     1. 서비스 계정의 CredSpec 파일에 구성을 추가합니다. 추가 `HostAccountConfig`에는 Secrets Manager에 있는 보안 암호의 Amazon 리소스 이름(ARN)이 포함됩니다.

        Windows에서 `PluginGUID`는 다음 예제 코드 조각의 GUID와 일치해야 합니다. Linux에서는 `PluginGUID`가 무시됩니다. 예제에서 `MySecret`은 보안 암호의 Amazon 리소스 이름 (ARN)으로 바꿉니다.

        ```
            "ActiveDirectoryConfig": {
                "HostAccountConfig": {
                    "PortableCcgVersion": "1",
                    "PluginGUID": "{859E1386-BDB4-49E8-85C7-3070B13920E1}",
                    "PluginInput": {
                        "CredentialArn": "arn:aws:secretsmanager:aws-region:111122223333:secret:MySecret"
                    }
                }
        ```

     1. *도메인 없는 gMSA* 기능을 사용하려면 작업 실행 역할에 추가 권한이 필요합니다. [(선택 사항) 도메인 없는 gMSA 보안 암호](#linux-gmsa-domainless-secret) 단계를 따릅니다.

1. <a name="linux-gmsa-install"></a>

**인스턴스 구성 및 `credentials-fetcher` 대몬(daemon) 설치**

   EC2 시작 템플릿에서 사용자 데이터 스크립트를 사용하여 `credentials-fetcher` 대몬(daemon)을 설치할 수 있습니다. 다음 예제에서는 두 가지 유형의 사용자 데이터인 `cloud-config` YAML 또는 bash 스크립트를 보여줍니다. 이러한 예제는 Amazon Linux 2023(AL2023)용입니다. `MyCluster`를 이러한 인스턴스를 조인할 Amazon ECS 클러스터의 이름으로 바꿉니다.
   + <a name="linux-gmsa-install-yaml"></a>

**`cloud-config` YAML**

     ```
     Content-Type: text/cloud-config
     package_reboot_if_required: true
     packages:
       # prerequisites
       - dotnet
       - realmd
       - oddjob
       - oddjob-mkhomedir
       - sssd
       - adcli
       - krb5-workstation
       - samba-common-tools
       # https://github.com/aws/credentials-fetcher gMSA credentials management for containers
       - credentials-fetcher
     write_files:
     # configure the ECS Agent to join your cluster.
     # replace MyCluster with the name of your cluster.
     - path: /etc/ecs/ecs.config
       owner: root:root
       permissions: '0644'
       content: |
         ECS_CLUSTER=MyCluster
         ECS_GMSA_SUPPORTED=true
     runcmd:
     # start the credentials-fetcher daemon and if it succeeded, make it start after every reboot
     - "systemctl start credentials-fetcher"
     - "systemctl is-active credentials-fetcher && systemctl enable credentials-fetcher"
     ```
   + <a name="linux-gmsa-install-userdata"></a>

**bash 스크립트**

     bash 스크립트에 더 익숙하고 `/etc/ecs/ecs.config`에 쓸 변수가 여러 개인 경우 다음 `heredoc` 형식을 사용합니다. 이 형식은 **cat**으로 시작하는 라인과 `EOF` 사이의 모든 항목을 구성 파일에 작성합니다.

     ```
     #!/usr/bin/env bash
     set -euxo pipefail
     
     # prerequisites
     timeout 30 dnf install -y dotnet realmd oddjob oddjob-mkhomedir sssd adcli krb5-workstation samba-common-tools
     # install https://github.com/aws/credentials-fetcher gMSA credentials management for containers
     timeout 30 dnf install -y credentials-fetcher
     
     # start credentials-fetcher
     systemctl start credentials-fetcher
     systemctl is-active credentials-fetcher && systemctl enable credentials-fetcher
     
     cat <<'EOF' >> /etc/ecs/ecs.config
     ECS_CLUSTER=MyCluster
     ECS_GMSA_SUPPORTED=true
     EOF
     ```

   `credentials-fetcher` 대몬(daemon)에 대한 선택적 구성 변수를 `/etc/ecs/ecs.config`에서 설정할 수 있습니다. 위 예제와 유사한 YAML 블록 또는 `heredoc`의 사용자 데이터에 변수를 설정하는 것이 좋습니다. 이렇게 하면 파일을 여러 번 편집하여 발생할 수 있는 부분 구성 문제를 방지할 수 있습니다. ECS 에이전트 구성에 대한 자세한 내용은 GitHub의 [Amazon ECS Container Agent](https://github.com/aws/amazon-ecs-agent/blob/master/README.md#environment-variables)를 참조하세요.
   + 또는, 소켓을 다른 위치로 이동하도록 `credentials-fetcher` 대몬(daemon) 구성을 변경하는 경우 `CREDENTIALS_FETCHER_HOST` 변수를 사용할 수 있습니다.

**권한 및 보안 암호 설정**  
각 애플리케이션과 각 작업 정의에 대해 다음 단계를 한 번 수행합니다. 최소 권한을 부여하는 모범 사례를 따르고 정책에서 사용되는 권한의 범위를 좁히는 것이 좋습니다. 이렇게 하면 각 작업에서 필요한 보안 암호만 읽을 수 있습니다.

1. <a name="linux-gmsa-domainless-secret"></a>

**(선택 사항) 도메인 없는 gMSA 보안 암호**

   인스턴스가 도메인에 가입되지 않은 도메인 없는 방법을 사용하는 경우 이 단계를 따릅니다.

   작업 실행 IAM 역할에 다음 권한을 인라인 정책으로 추가해야 합니다. 이렇게 하면 `credentials-fetcher` 대몬(daemon)이 Secrets Manager 보안 암호에 액세스할 수 있게 됩니다. `MySecret` 예제를 `Resource` 목록에 있는 보안 암호의 Amazon 리소스 이름(ARN)으로 바꿉니다.

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "secretsmanager:GetSecretValue"
               ],
               "Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:my-secret-AbCdEf"
           }
       ]
   }
   ```

------
**참고**  
자체 KMS 키를 사용하여 보안 암호를 암호화하는 경우 이 역할에 필요한 권한을 추가하고 이 역할을 AWS KMS 키 정책에 추가해야 합니다.

1. 

**SSM Parameter Store 또는 S3를 사용하여 CredSpec를 저장할지 결정**

   Amazon ECS에서는 작업 정의의 `credentialSpecs` 필드에서 파일 경로를 참조하는 다음과 같은 방법을 지원합니다.

   인스턴스를 단일 도메인에 가입시키는 경우 문자열에서 ARN 시작 부분에 `credentialspec:` 접두사를 사용합니다. 도메인 없는 gMSA를 사용하는 경우에는 `credentialspecdomainless:`를 사용합니다.

   CredSpec에 대한 자세한 내용은 [보안 인증 사양 파일](#linux-gmsa-credentialspec) 섹션을 참조하세요.
   + <a name="linux-gmsa-credspec-s3"></a>

**Amazon S3 버킷**

     보안 인증 사양을 Amazon S3 버킷에 추가합니다. 그런 다음 작업 정의의 `credentialSpecs` 필드에서 Amazon S3 버킷의 Amazon 리소스 이름(ARN)을 참조합니다.

     ```
     {
         "family": "",
         "executionRoleArn": "",
         "containerDefinitions": [
             {
                 "name": "",
                 ...
                 "credentialSpecs": [
                     "credentialspecdomainless:arn:aws:s3:::${BucketName}/${ObjectName}"
                 ],
                 ...
             }
         ],
         ...
     }
     ```

     또한 작업에 Amazon S3 버킷에 대한 액세스 권한을 부여하려면 Amazon ECS 작업 실행 IAM 역할에 다음 권한을 인라인 정책으로 추가합니다.

------
#### [ JSON ]

****  

     ```
     {
         "Version":"2012-10-17",		 	 	 
         "Statement": [
             {
                 "Sid": "VisualEditor",
                 "Effect": "Allow",
                 "Action": [
                     "s3:Get*",
                     "s3:List*"
                 ],
                 "Resource": [
                     "arn:aws:s3:::amzn-s3-demo-bucket",
                     "arn:aws:s3:::amzn-s3-demo-bucket/{object}"
                 ]
             }
         ]
     }
     ```

------
   + <a name="linux-gmsa-credspec-ssm"></a>

**SSM Parameter Store 파라미터**

     보안 인증 사양을 SSM Parameter Store 파라미터에 추가합니다. 그런 다음 작업 정의의 `credentialSpecs` 필드에서 SSM Parameter Store 파라미터의 Amazon 리소스 이름(ARN)을 참조합니다.

     ```
     {
         "family": "",
         "executionRoleArn": "",
         "containerDefinitions": [
             {
                 "name": "",
                 ...
                 "credentialSpecs": [
                     "credentialspecdomainless:arn:aws:ssm:aws-region:111122223333:parameter/parameter_name"
                 ],
                 ...
             }
         ],
         ...
     }
     ```

     또한 작업에 SSM Parameter Store 파라미터에 대한 액세스 권한을 부여하려면 Amazon ECS 작업 실행 IAM 역할에 다음 권한을 인라인 정책으로 추가합니다.

------
#### [ JSON ]

****  

     ```
     {
         "Version":"2012-10-17",		 	 	 
         "Statement": [
             {
                 "Effect": "Allow",
                 "Action": [
                     "ssm:GetParameters"
                 ],
                 "Resource": "arn:aws:ssm:us-east-1:123456789012:parameter/my-parameter"
             }
         ]
     }
     ```

------

## 보안 인증 사양 파일
<a name="linux-gmsa-credentialspec"></a>

Amazon ECS는 Active Directory 보안 인증 사양 파일(*CredSpec*)을 사용합니다. 이 파일은 gMSA 계정 컨텍스트를 Linux 컨테이너에 전파하는 데 사용되는 gMSA 메타데이터를 포함합니다. CredSpec를 생성하여 작업 정의의 `credentialSpecs` 필드에서 참조합니다. CredSpec 파일에는 보안 암호가 포함되어 있지 않습니다.

다음은 예 CredSpec 파일입니다.

```
{
    "CmsPlugins": [
        "ActiveDirectory"
    ],
    "DomainJoinConfig": {
        "Sid": "S-1-5-21-2554468230-2647958158-2204241789",
        "MachineAccountName": "WebApp01",
        "Guid": "8665abd4-e947-4dd0-9a51-f8254943c90b",
        "DnsTreeName": "example.com",
        "DnsName": "example.com",
        "NetBiosName": "example"
    },
    "ActiveDirectoryConfig": {
        "GroupManagedServiceAccounts": [
            {
                "Name": "WebApp01",
                "Scope": "example.com"
            }
        ],
        "HostAccountConfig": {
            "PortableCcgVersion": "1",
            "PluginGUID": "{859E1386-BDB4-49E8-85C7-3070B13920E1}",
            "PluginInput": {
                "CredentialArn": "arn:aws:secretsmanager:aws-region:111122223333:secret:MySecret"
            }
        }
    }
}
```
<a name="linux-gmsa-credentialspec-create"></a>
**CredSpec 생성**  
도메인에 가입된 Windows 컴퓨터에서 CredSpec PowerShell 모듈을 사용하여 CredSpec를 생성합니다. Microsoft Learn 웹 사이트에서 [Create a credential spec](https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/manage-serviceaccounts#create-a-credential-spec)의 단계를 따릅니다.

# Fargate의 Linux 컨테이너에서 gMSA 사용
<a name="fargate-linux-gmsa"></a>

Amazon ECS는 *그룹 관리형 서비스 계정*(gMSA)이라는 특수한 종류의 서비스 계정을 통해 Fargate의 Linux 컨테이너에 대한 Active Directory 인증을 지원합니다.

.NET Core 애플리케이션과 같은 Linux 기반 네트워크 애플리케이션은 Active Directory를 사용하여 사용자와 서비스 간의 인증 및 권한 부여 관리를 용이하게 할 수 있습니다. Active Directory와 통합되고 도메인 가입된 서버에서 실행되는 애플리케이션을 설계하여 이 기능을 사용할 수 있습니다. 하지만 Linux 컨테이너는 도메인에 가입할 수 없으므로 gMSA로 실행할 Linux 컨테이너를 구성해야 합니다.

## 고려 사항
<a name="fargate-linux-gmsa-considerations"></a>

Fargate의 Linux 컨테이너에 gMSA를 사용하기 전에 다음을 고려합니다.
+ 플랫폼 버전 1.4 이상을 실행해야 합니다.
+ 사전 조건을 완료하려면 도메인에 가입된 Windows 컴퓨터가 필요할 수 있습니다. 예를 들어, PowerShell을 사용하여 Active Directory에서 gMSA를 생성하려면 도메인에 가입된 Windows 컴퓨터가 필요할 수 있습니다. RSAT Active Director PowerShell 도구는 Windows에서만 사용할 수 있습니다. 자세한 내용은 [Installing the Active Directory administration tools](https://docs.aws.amazon.com/directoryservice/latest/admin-guide/ms_ad_install_ad_tools.html)를 참조하세요.
+ **도메인이 없는 gMSA**를 사용해야 합니다.

  Amazon ECS는 Active Directory 보안 인증 사양 파일(CredSpec)을 사용합니다. 이 파일은 gMSA 계정 컨텍스트를 컨테이너에 전파하는 데 사용되는 gMSA 메타데이터를 포함합니다. CredSpec 파일을 생성하여 Amazon S3 버킷에 저장합니다.
+ 작업은 하나의 Active Directory만 지원할 수 있습니다.

## 사전 조건
<a name="fargate-linux-gmsa-prerequisites"></a>

Amazon ECS에서 Linux 컨테이너 기능에 gMSA를 사용하려면 먼저 다음 사항을 충족해야 합니다.
+ 컨테이너에서 액세스할 리소스를 포함하는 Active Directory 도메인을 설정합니다. Amazon ECS는 다음 설정을 지원합니다.
  + Directory Service Active Directory. Directory Service는 Amazon EC2에 호스트되는 AWS 관리형 Active Directory입니다. 자세한 내용은 *AWS Directory Service 관리 안내서*의 [AWS 관리형 Microsoft AD 시작하기](https://docs.aws.amazon.com/directoryservice/latest/admin-guide/ms_ad_getting_started.html)를 참조하세요.
  + 온프레미스 Active Directory. Amazon ECS Linux 컨테이너 인스턴스가 도메인에 가입할 수 있도록 해야 합니다. 자세한 내용은 [AWS Direct Connect](https://docs.aws.amazon.com/whitepapers/latest/aws-vpc-connectivity-options/aws-direct-connect-network-to-amazon.html) 섹션을 참조하세요.
+ Active Directory에 기존 gMSA 계정이 있고 gMSA 서비스 계정에 액세스할 권한이 있는 사용자가 있습니다. 자세한 내용은 [도메인 없는 gMSA를 위한 Active Directory 사용자 만들기](#fargate-linux-gmsa-initial-domainless) 섹션을 참조하세요.
+ Amazon S3 버킷이 있습니다. 자세한 내용은 *Amazon S3 사용자 안내서*의 [버킷 생성](https://docs.aws.amazon.com/AmazonS3/latest/userguide/create-bucket-overview.html)을 참조하세요.

## Amazon ECS에서 gMSA 지원 Linux 컨테이너 설정
<a name="fargate-linux-gmsa-setup"></a>
<a name="linux-gmsa-setup-infra"></a>
**인프라 준비**  
다음 단계는 고려 사항과 한 번 수행하는 설정입니다.
+ <a name="fargate-linux-gmsa-initial-domainless"></a>

**도메인 없는 gMSA를 위한 Active Directory 사용자 만들기**

  도메인이 없는 gMSA를 사용하는 경우 컨테이너는 도메인에 참여하지 않습니다. 컨테이너에서 실행되는 다른 애플리케이션은 자격 증명을 사용하여 도메인에 액세스할 수 없습니다. 다른 도메인을 사용하는 작업은 동일한 컨테이너에서 실행할 수 있습니다. AWS Secrets Manager에서 CredSpec 파일에 보안 암호의 이름을 제공합니다. 보안 암호에는 사용자 이름, 암호 및 로그인할 도메인이 포함되어야 합니다.

  이 기능은 *gMSA support for non-domain-joined container hosts* 기능과 유사합니다. Windows 기능에 대한 자세한 내용은 Microsoft Learn 웹 사이트의 [gMSA architecture and improvements](https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/manage-serviceaccounts#gmsa-architecture-and-improvements)를 참조하세요.

  1. Active Directory 도메인에서 사용자를 구성합니다. Active Directory의 사용자는 작업에서 사용하는 gMSA 서비스 계정에 액세스할 수 있는 권한이 있어야 합니다.

  1. Active Directory 도메인 이름을 확인할 수 있는 VPC와 서브넷이 있습니다. Active Directory 서비스 이름을 가리키는 도메인 이름을 사용하여 DHCP 옵션을 통해 VPC를 구성합니다. VPC에 대한 DHCP 옵션 구성 방법에 대한 자세한 내용은 **Amazon Virtual Private Cloud 사용 설명서의 [Work with DHCP option sets](https://docs.aws.amazon.com/vpc/latest/userguide/DHCPOptionSet.html)를 참조하세요.

  1. AWS Secrets Manager에서 암호를 생성합니다.

  1. 자격 증명 사양 파일을 생성합니다.

**권한 및 보안 암호 설정**  
각 애플리케이션과 각 작업 정의에 대해 다음 단계를 한 번 수행합니다. 최소 권한을 부여하는 모범 사례를 따르고 정책에서 사용되는 권한의 범위를 좁히는 것이 좋습니다. 이렇게 하면 각 작업에서 필요한 보안 암호만 읽을 수 있습니다.

1. Active Directory 도메인에서 사용자를 만듭니다. Active Directory의 사용자는 작업에서 사용하는 gMSA 서비스 계정에 액세스할 수 있는 권한이 있어야 합니다.

1. Active Directory 사용자를 만든 후 AWS Secrets Manager에서 보안 암호를 생성합니다. 자세한 내용은 [AWS Secrets Manager 보안 암호 생성](https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_secret.html)을 참조하세요.

1. 사용자의 사용자 이름, 암호 및 도메인을 각각 `username`, `password` 및 `domainName`이라는 JSON 키-값 쌍에 입력합니다.

   ```
   {"username":"username","password":"passw0rd", "domainName":"example.com"}
   ```

1. <a name="fargate-linux-gmsa-domainless-secret"></a>작업 실행 IAM 역할에 다음 권한을 인라인 정책으로 추가해야 합니다. 이렇게 하면 `credentials-fetcher` 대몬(daemon)이 Secrets Manager 보안 암호에 액세스할 수 있게 됩니다. `MySecret` 예제를 `Resource` 목록에 있는 보안 암호의 Amazon 리소스 이름(ARN)으로 바꿉니다.

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "secretsmanager:GetSecretValue"
               ],
               "Resource": [
               "arn:aws:secretsmanager:us-east-1:111122223333:secret:MySecret"
               ]
           }
       ]
   }
   ```

------
**참고**  
자체 KMS 키를 사용하여 보안 암호를 암호화하는 경우 이 역할에 필요한 권한을 추가하고 이 역할을 AWS KMS 키 정책에 추가해야 합니다.

1. <a name="linux-gmsa-credspec-ssm"></a>보안 인증 사양을 Amazon S3 버킷에 추가합니다. 그런 다음 작업 정의의 `credentialSpecs` 필드에서 Amazon S3 버킷의 Amazon 리소스 이름(ARN)을 참조합니다.

   ```
   {
       "family": "",
       "executionRoleArn": "",
       "containerDefinitions": [
           {
               "name": "",
               ...
               "credentialSpecs": [
                   "credentialspecdomainless:arn:aws:s3:::${BucketName}/${ObjectName}"
               ],
               ...
           }
       ],
       ...
   }
   ```

   또한 작업에 Amazon S3 버킷에 대한 액세스 권한을 부여하려면 Amazon ECS 작업 실행 IAM 역할에 다음 권한을 인라인 정책으로 추가합니다.

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Sid": "VisualEditor",
               "Effect": "Allow",
               "Action": [
               "s3:GetObjectVersion",
               "s3:ListBucket"
               ],
               "Resource": [
                   "arn:aws:s3:::{bucket_name}",
                   "arn:aws:s3:::{bucket_name}/{object}"
               ]
           }
       ]
   }
   ```

------

## 보안 인증 사양 파일
<a name="fargate-linux-gmsa-credentialspec"></a>

Amazon ECS는 Active Directory 보안 인증 사양 파일(*CredSpec*)을 사용합니다. 이 파일은 gMSA 계정 컨텍스트를 Linux 컨테이너에 전파하는 데 사용되는 gMSA 메타데이터를 포함합니다. CredSpec를 생성하여 작업 정의의 `credentialSpecs` 필드에서 참조합니다. CredSpec 파일에는 보안 암호가 포함되어 있지 않습니다.

다음은 예 CredSpec 파일입니다.

```
{
    "CmsPlugins": [
        "ActiveDirectory"
    ],
    "DomainJoinConfig": {
        "Sid": "S-1-5-21-2554468230-2647958158-2204241789",
        "MachineAccountName": "WebApp01",
        "Guid": "8665abd4-e947-4dd0-9a51-f8254943c90b",
        "DnsTreeName": "example.com",
        "DnsName": "example.com",
        "NetBiosName": "example"
    },
    "ActiveDirectoryConfig": {
        "GroupManagedServiceAccounts": [
            {
                "Name": "WebApp01",
                "Scope": "example.com"
            }
        ],
        "HostAccountConfig": {
            "PortableCcgVersion": "1",
            "PluginGUID": "{859E1386-BDB4-49E8-85C7-3070B13920E1}",
            "PluginInput": {
                "CredentialArn": "arn:aws:secretsmanager:aws-region:111122223333:secret:MySecret"
            }
        }
    }
}
```
<a name="fargate-linux-gmsa-credentialspec-create"></a>
**CredSpec 생성 및 Amazon S3에 업로드**  
도메인에 가입된 Windows 컴퓨터에서 CredSpec PowerShell 모듈을 사용하여 CredSpec를 생성합니다. Microsoft Learn 웹 사이트에서 [Create a credential spec](https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/manage-serviceaccounts#create-a-credential-spec)의 단계를 따릅니다.

자격 증명 사양 파일을 생성한 후 Amazon S3 버킷에 업로드합니다. AWS CLI 명령을 실행 중인 컴퓨터나 환경에 CredSpec 파일을 복사합니다.

다음 AWS CLI 명령을 실행하여 Amazon S3에 CredSpec를 업로드합니다. `amzn-s3-demo-bucket`을 Amazon S3 버킷 이름으로 바꿉니다. 파일을 모든 버킷과 위치에 개체로 저장할 수 있지만 작업 실행 역할에 연결하는 정책에서 해당 버킷과 위치에 대한 액세스를 허용해야 합니다.

PowerShell의 경우 다음 명령을 사용합니다.

```
$ Write-S3Object -BucketName "amzn-s3-demo-bucket" -Key "ecs-domainless-gmsa-credspec" -File "gmsa-cred-spec.json"
```

다음 AWS CLI 명령은 `sh` 및 호환 쉘에서 사용되는 백슬래시 연속 문자를 사용합니다.

```
$ aws s3 cp gmsa-cred-spec.json \
s3://amzn-s3-demo-bucket/ecs-domainless-gmsa-credspec
```

# AWS CLI를 사용하여 도메인이 없는 gMSA로 Amazon ECS Windows 컨테이너 사용
<a name="tutorial-gmsa-windows"></a>

다음 자습서에서는 AWS CLI를 사용하여 Active Directory에 액세스할 수 있는 보안 인증이 있는 Windows 컨테이너를 실행하는 Amazon ECS 작업을 생성하는 방법을 보여 줍니다 도메인 없는 gMSA를 사용하면 컨테이너 인스턴스는 도메인에 가입되지 않고, 인스턴스의 다른 애플리케이션은 보안 인증을 사용하여 도메인에 액세스할 수 없고, 다른 도메인에 가입하는 작업은 동일한 인스턴스에서 실행될 수 있습니다.

**Topics**
+ [사전 조건](#tutorial-gmsa-windows-prerequisites)
+ [1단계: Active Directory 도메인 서비스(AD DS)에서 gMSA 계정 생성 및 구성](#tutorial-gmsa-windows-step1)
+ [2단계: Secrets Manager로 보안 인증 업로드](#tutorial-gmsa-windows-step2)
+ [3단계: 도메인이 없는 gMSA 정보를 포함하도록 CredSpec JSON 수정](#tutorial-gmsa-windows-step3)
+ [4단계: Amazon S3에 CredSpec 업로드](#tutorial-gmsa-windows-step4)
+ [5단계: (선택 사항) Amazon ECS 클러스터 생성](#tutorial-gmsa-windows-step5)
+ [6단계: 컨테이너 인스턴스에 대한 IAM 역할 생성](#tutorial-gmsa-windows-step6)
+ [7단계: 사용자 지정 작업 실행 역할 생성](#tutorial-gmsa-windows-step7)
+ [8단계: Amazon ECS Exec에 대한 작업 역할 생성](#tutorial-gmsa-windows-step8)
+ [9단계: 도메인 없는 gMSA를 사용하는 작업 정의 등록](#tutorial-gmsa-windows-step9)
+ [10단계: 클러스터에 Windows 컨테이너 인스턴스 등록](#tutorial-gmsa-windows-step10)
+ [11단계: 컨테이너 인스턴스 확인](#tutorial-gmsa-windows-step11)
+ [12단계: Windows 작업 실행](#tutorial-gmsa-windows-step12)
+ [13단계: 컨테이너에 gMSA 보안 인증이 있는지 확인](#tutorial-gmsa-windows-step13)
+ [14단계: 정리](#tutorial-gmsa-windows-step14)
+ [Windows 컨테이너에 대한 Amazon ECS 도메인 없는 gMSA 디버깅](#tutorial-gmsa-windows-debugging)

## 사전 조건
<a name="tutorial-gmsa-windows-prerequisites"></a>

이 자습서에서는 다음 사전 조건이 충족되었다고 가정합니다.
+ [Amazon ECS 사용 설정](get-set-up-for-amazon-ecs.md)의 단계가 완료되었습니다.
+ IAM 사용자는 [AmazonECS\$1FullAccess](security-iam-awsmanpol.md#security-iam-awsmanpol-AmazonECS_FullAccess) IAM 정책 예제에 지정된 필수 권한을 가집니다.
+  최신 버전의 AWS CLI가 설치 및 구성됩니다. AWS CLI 설치 또는 업그레이드에 관한 자세한 정보는 [AWS Command Line Interface 설치](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)를 참조하세요.
**참고**  
듀얼 스택 서비스 엔드포인트를 사용하면 AWS CLI, SDK 및 Amazon ECS API에서 IPv4 및 IPv6 모두를 통해 Amazon ECS와 상호 작용할 수 있습니다. 자세한 내용은 [Amazon ECS 듀얼 스택 엔드포인트 사용](dual-stack-endpoint.md) 섹션을 참조하세요.
+ 컨테이너에서 액세스할 리소스를 포함하는 Active Directory 도메인을 설정합니다. Amazon ECS는 다음 설정을 지원합니다.
  + Directory Service Active Directory. Directory Service는 Amazon EC2에 호스트되는 AWS 관리형 Active Directory입니다. 자세한 내용은 *AWS Directory Service 관리 안내서*의 [AWS 관리형 Microsoft AD 시작하기](https://docs.aws.amazon.com/directoryservice/latest/admin-guide/ms_ad_getting_started.html)를 참조하세요.
  + 온프레미스 Active Directory. Amazon ECS Linux 컨테이너 인스턴스가 도메인에 가입할 수 있도록 해야 합니다. 자세한 내용은 [AWS Direct Connect](https://docs.aws.amazon.com/whitepapers/latest/aws-vpc-connectivity-options/aws-direct-connect-network-to-amazon.html) 섹션을 참조하세요.
+ Active Directory 도메인 이름을 확인할 수 있는 VPC와 서브넷이 있습니다.
+ **도메인 없는 gMSA** 및 **각 인스턴스를 단일 도메인에 가입** 중에서 선택할 수 있습니다. 도메인 없는 gMSA를 사용하면 컨테이너 인스턴스는 도메인에 가입되지 않고, 인스턴스의 다른 애플리케이션은 보안 인증을 사용하여 도메인에 액세스할 수 없고, 다른 도메인에 가입하는 작업은 동일한 인스턴스에서 실행될 수 있습니다.

  그런 다음 CredSpec 및 선택적으로 도메인 없는 gMSA에 대한 Active Directory 사용자 보안 인증으로 데이터 스토리지를 선택합니다.

  Amazon ECS는 Active Directory 보안 인증 사양 파일(CredSpec)을 사용합니다. 이 파일은 gMSA 계정 컨텍스트를 컨테이너에 전파하는 데 사용되는 gMSA 메타데이터를 포함합니다. CredSpec 파일을 생성하고 다음 표의 컨테이너 인스턴스의 운영 체제별 CredSpec 스토리지 옵션 중 하나에 저장합니다. 도메인 없는 방법을 사용하려면 CredSpec 파일의 선택적 섹션에서 다음 표의 컨테이너 인스턴스의 운영 체제별 *domainless user credentials*스토리지 옵션 중 하나에 보안 인증을 지정할 수 있습니다.    
<a name="gmsa-table"></a>[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/AmazonECS/latest/developerguide/tutorial-gmsa-windows.html)
+ (선택 사항) AWS CloudShell은 고객에게 자체 EC2 인스턴스를 생성할 필요 없이 명령줄을 제공하는 도구입니다. 자세한 내용은 *AWS CloudShell 사용 설명서*의 [AWS CloudShell이란?](https://docs.aws.amazon.com/cloudshell/latest/userguide/welcome.html)을 참조하세요.

## 1단계: Active Directory 도메인 서비스(AD DS)에서 gMSA 계정 생성 및 구성
<a name="tutorial-gmsa-windows-step1"></a>

Active Directory 도메인에서 gMSA 계정을 생성하고 구성합니다.

**참고**  
이 단계에서는 컨테이너의 자격 증명을 제공하는 그룹 관리형 서비스 계정(gMSA) 및 도메인 인증에 사용되는 일반 사용자 계정과 같은 두 개의 개별 계정을 생성합니다. 이러한 계정은 용도가 서로 다르며 이름이 서로 달라야 합니다.

1. 

**키 배포 서비스 루트 키 생성**
**참고**  
Directory Service를 사용할 경우 이 단계를 건너뛸 수 있습니다.

   KDS 루트 키와 gMSA 권한은 AWS 관리형 Microsoft AD를 사용하여 구성됩니다.

   도메인에서 아직 gMSA 서비스 계정을 생성하지 않았다면 먼저 키 배포 서비스(KDS) 루트 키를 생성해야 합니다. KDS는 gMSA 암호를 생성하고 교체하여 승인된 호스트에 배포하는 역할을 합니다. `ccg.exe`는 gMSA 보안 인증을 검색해야 하는 경우 KDS에 연락하여 현재 암호를 검색합니다.

   KDS 루트 키가 이미 생성되었는지 확인하려면 `ActiveDirectory` PowerShell 모듈을 사용하여 도메인 컨트롤러에서 도메인 관리자 권한으로 다음 PowerShell cmdlet을 실행합니다. 모듈에 대한 자세한 내용은 Microsoft Learn 웹 사이트의 [ActiveDirectory Module](https://learn.microsoft.com/en-us/powershell/module/activedirectory/?view=windowsserver2022-ps)을 참조하세요.

   ```
   PS C:\> Get-KdsRootKey
   ```

   명령에서 키 ID를 반환하는 경우 이 단계의 나머지 부분은 건너뛸 수 있습니다. 그렇지 않으면 다음 명령을 실행하여 KDS 루트 키를 생성합니다.

   ```
   PS C:\> Add-KdsRootKey -EffectiveImmediately
   ```

   명령의 인수 `EffectiveImmediately`는 키가 즉시 유효함을 의미하지만 KDS 루트 키가 복제되어 모든 도메인 컨트롤러에서 사용할 수 있으려면 10시간을 기다려야 합니다.

1. 

**gMSA 계정 생성**

   gMSA 계정을 생성하고 `ccg.exe`에서 gMSA 암호를 검색하도록 허용하려면 도메인에 대한 액세스 권한이 있는 Windows Server 또는 클라이언트에서 다음 PowerShell 명령을 실행합니다. `ExampleAccount`를 gMSA 계정에 대해 원하는 이름으로 바꾸고 `example-domain`을 Active Directory 도메인 이름(예: 도메인이 `contoso.com`인 경우 `contoso` 사용)으로 바꾸세요.

   1. 

      ```
      PS C:\> Install-WindowsFeature RSAT-AD-PowerShell
      ```

   1. 

      ```
      PS C:\> New-ADGroup -Name "ExampleAccount Authorized Hosts" -SamAccountName "ExampleAccountHosts" -GroupScope DomainLocal
      ```

   1. 

      ```
      PS C:\> New-ADServiceAccount -Name "ExampleAccount" -DnsHostName "example-domain" -ServicePrincipalNames "host/ExampleAccount", "host/example-domain" -PrincipalsAllowedToRetrieveManagedPassword "ExampleAccountHosts"
      ```

   1. 만료되지 않는 영구 암호로 사용자를 생성합니다. 이러한 보안 인증은 AWS Secrets Manager에 저장되며 각 작업에서 도메인에 가입하는 데 사용됩니다. 위에서 생성한 gMSA 계정과는 별도의 사용자 계정입니다. `ExampleServiceUser`를 이 서비스 사용자 계정에 대해 원하는 이름으로 바꾸세요.

      ```
      PS C:\> New-ADUser -Name "ExampleServiceUser" -AccountPassword (ConvertTo-SecureString -AsPlainText "Test123" -Force) -Enabled 1 -PasswordNeverExpires 1
      ```

   1. 

      ```
      PS C:\> Add-ADGroupMember -Identity "ExampleAccountHosts" -Members "ExampleServiceUser"
      ```

   1. 액티브 디렉터리에 CredSpec 개체를 생성하기 위한 PowerShell 모듈을 설치하고 CredSpec JSON을 출력합니다.

      ```
      PS C:\> Install-PackageProvider -Name NuGet -Force
      ```

      ```
      PS C:\> Install-Module CredentialSpec
      ```

   1. 

      ```
      PS C:\> New-CredentialSpec -AccountName ExampleAccount
      ```

1. 이전 명령의 JSON 출력을 `gmsa-cred-spec.json`이라는 파일에 복사합니다. 이는 CredSpec 파일입니다. 3단계 [3단계: 도메인이 없는 gMSA 정보를 포함하도록 CredSpec JSON 수정](#tutorial-gmsa-windows-step3)에서 사용됩니다.

## 2단계: Secrets Manager로 보안 인증 업로드
<a name="tutorial-gmsa-windows-step2"></a>

Active Directory 보안 인증을 안전한 자격 증명 스토리지 시스템에 복사하여 각 작업에서 검색할 수 있도록 합니다. 이는 도메인 없는 gMSA 방법입니다. 도메인 없는 gMSA를 사용하면 컨테이너 인스턴스는 도메인에 가입되지 않고, 인스턴스의 다른 애플리케이션은 보안 인증을 사용하여 도메인에 액세스할 수 없고, 다른 도메인에 가입하는 작업은 동일한 인스턴스에서 실행될 수 있습니다.

이 단계에서는 AWS CLI를 사용합니다. 기본 셸 `bash`의 AWS CloudShell에서 이러한 명령을 실행할 수 있습니다.
+ 다음 AWS CLI 명령을 실행하고 환경에 맞게 사용자 이름, 암호 및 도메인 이름을 변경합니다. 사용자 이름에 대해 서비스 사용자 계정 이름(gMSA 계정 이름 아님)을 사용합니다. 보안 암호의 ARN을 보관하고 다음 단계 [3단계: 도메인이 없는 gMSA 정보를 포함하도록 CredSpec JSON 수정](#tutorial-gmsa-windows-step3)에서 사용합니다.

  다음 명령은 `sh` 및 호환 셸에서 사용되는 백슬래시 연속 문자를 사용합니다. 이 명령은 PowerShell과 호환되지 않습니다. PowerShell에서 사용하려면 명령을 수정해야 합니다.

  ```
  $ aws secretsmanager create-secret \
  --name gmsa-plugin-input \
  --description "Amazon ECS - gMSA Portable Identity." \
  --secret-string "{\"username\":\"ExampleServiceUser\",\"password\":\"Test123\",\"domainName\":\"contoso.com\"}"
  ```

## 3단계: 도메인이 없는 gMSA 정보를 포함하도록 CredSpec JSON 수정
<a name="tutorial-gmsa-windows-step3"></a>

CredSpec를 스토리지 옵션 중 하나에 업로드하기 전에 이전 단계의 Secrets Manager에 있는 보안 암호의 ARN을 사용하여 CredSpec에 정보를 추가합니다. 자세한 내용은 Microsoft Learn 웹 사이트에서 [Additional credential spec configuration for non-domain-joined container host use case](https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/manage-serviceaccounts#additional-credential-spec-configuration-for-non-domain-joined-container-host-use-case)를 참조하세요.

1. 다음 정보를 CredSpec 파일의 `ActiveDirectoryConfig` 안에 추가합니다. ARN을 이전 단계의 Secrets Manager에 있는 보안 암호로 바꿉니다.

   단, `PluginGUID` 값은 다음 예제 코드 조각의 GUID와 일치해야 하며 필수 항목입니다.

   ```
   "HostAccountConfig": {
         "PortableCcgVersion": "1",
         "PluginGUID": "{859E1386-BDB4-49E8-85C7-3070B13920E1}",
         "PluginInput": "{\"credentialArn\": \"arn:aws:secretsmanager:aws-region:111122223333:secret:gmsa-plugin-input\"}"
       }
   ```

   다음 형식(`\"arn:aws:ssm:aws-region:111122223333:parameter/gmsa-plugin-input\"`)의 ARN을 사용하여 SSM Parameter Store의 보안 암호를 사용할 수도 있습니다.

1. 수정한 CredSpec 파일은 다음 예제와 같아야 합니다.

   ```
   {
     "CmsPlugins": [
       "ActiveDirectory"
     ],
     "DomainJoinConfig": {
       "Sid": "S-1-5-21-4066351383-705263209-1606769140",
       "MachineAccountName": "ExampleAccount",
       "Guid": "ac822f13-583e-49f7-aa7b-284f9a8c97b6",
       "DnsTreeName": "example-domain",
       "DnsName": "example-domain",
       "NetBiosName": "example-domain"
     },
     "ActiveDirectoryConfig": {
       "GroupManagedServiceAccounts": [
         {
           "Name": "ExampleAccount",
           "Scope": "example-domain"
         },
         {
           "Name": "ExampleAccount",
           "Scope": "example-domain"
         }
       ],
       "HostAccountConfig": {
         "PortableCcgVersion": "1",
         "PluginGUID": "{859E1386-BDB4-49E8-85C7-3070B13920E1}",
         "PluginInput": "{\"credentialArn\": \"arn:aws:secretsmanager:aws-region:111122223333:secret:gmsa-plugin-input\"}"
       }
     }
   }
   ```

## 4단계: Amazon S3에 CredSpec 업로드
<a name="tutorial-gmsa-windows-step4"></a>



이 단계에서는 AWS CLI를 사용합니다. 기본 셸 `bash`의 AWS CloudShell에서 이러한 명령을 실행할 수 있습니다.

1. AWS CLI 명령을 실행 중인 컴퓨터나 환경에 CredSpec 파일을 복사합니다.

1. 다음 AWS CLI 명령을 실행하여 Amazon S3에 CredSpec를 업로드합니다. `MyBucket`을 Amazon S3 버킷 이름으로 바꿉니다. 파일을 모든 버킷과 위치에 개체로 저장할 수 있지만 작업 실행 역할에 연결하는 정책에서 해당 버킷과 위치에 대한 액세스를 허용해야 합니다.

   다음 명령은 `sh` 및 호환 셸에서 사용되는 백슬래시 연속 문자를 사용합니다. 이 명령은 PowerShell과 호환되지 않습니다. PowerShell에서 사용하려면 명령을 수정해야 합니다.

   ```
   $ aws s3 cp gmsa-cred-spec.json \
   s3://MyBucket/ecs-domainless-gmsa-credspec
   ```

## 5단계: (선택 사항) Amazon ECS 클러스터 생성
<a name="tutorial-gmsa-windows-step5"></a>

기본적으로 계정에는 `default`라는 Amazon ECS 클러스터가 있습니다. 이 클러스터는 AWS CLI, SDK 및 CloudFormation에서 기본적으로 사용됩니다. 추가 클러스터를 사용하여 작업 및 인프라를 그룹화 및 구성하고 일부 구성에 기본값을 할당할 수 있습니다.

AWS Management Console, AWS CLI, SDK 또는 CloudFormation를 사용하여 클러스터를 생성할 수 있습니다. 클러스터의 설정 및 구성은 gMSA에 영향을 주지 않습니다.

이 단계에서는 AWS CLI를 사용합니다. 기본 셸 `bash`의 AWS CloudShell에서 이러한 명령을 실행할 수 있습니다.

```
$ aws ecs create-cluster --cluster-name windows-domainless-gmsa-cluster
```

**중요**  
자체 클러스터를 생성하는 경우, 해당 클러스터에 사용할 각 명령에 `--cluster clusterName`을 지정해야 합니다.

## 6단계: 컨테이너 인스턴스에 대한 IAM 역할 생성
<a name="tutorial-gmsa-windows-step6"></a>

컨테이너 인스턴스는* *ECS 작업에서 컨테이너를 실행하는 호스트 컴퓨터입니다(예: Amazon EC2 인스턴스). 각 컨테이너 인스턴스는 Amazon ECS 클러스터에 등록합니다. Amazon EC2 인스턴스를 시작해 클러스터에 등록하기 전에 사용할 컨테이너 인스턴스의 IAM 역할을 생성해야 합니다.

컨테이너 인스턴스 역할을 생성하려면 [Amazon ECS 컨테이너 인스턴스 IAM 역할](instance_IAM_role.md)을 참조하세요. 기본값 `ecsInstanceRole`에는 이 자습서를 완료하기에 충분한 권한이 있습니다.

## 7단계: 사용자 지정 작업 실행 역할 생성
<a name="tutorial-gmsa-windows-step7"></a>

Amazon ECS는 각 작업을 시작하는 데 필요한 권한에 대해 컨테이너 인스턴스 역할 대신 다른 IAM 역할을 사용할 수 있습니다. 이 역할을 작업 실행 역할**이라고 합니다. ECS에서 작업을 실행하는 데 필요한 권한(최소 권한 권한이라고도 함)만 포함된 작업 실행 역할을* *생성하는 것이 좋습니다. 최소 권한 원칙에 대한 자세한 내용은 *AWS Well-Architected Framework*의 [SEC03-BP02 Grant least privilege access](https://docs.aws.amazon.com/wellarchitected/latest/framework/sec_permissions_least_privileges.html)를 참조하세요.

1. 작업 실행 역할을 생성하려면 [작업 실행 역할 생성](task_execution_IAM_role.md#create-task-execution-role)을 참조하세요. 기본 권한을 사용하면 컨테이너 인스턴스가 Amazon Elastic Container Registry와 애플리케이션의 `stdout` 및 `stderr`에 컨테이너 이미지를 풀하고 Amazon CloudWatch Logs에 기록할 수 있습니다.

   이 자습서에서는 역할에 사용자 지정 권한이 필요하므로 역할에 `ecsTaskExecutionRole`과 다른 이름을 지정할 수 있습니다. 이 자습서의 이후 단계에서는 `ecsTaskExecutionRole`을 사용합니다.

1. 이 역할에만 존재하는 인라인 정책이나 재사용할 수 있는 정책으로 사용자 지정 정책을 생성하여 다음 권한을 추가합니다. 첫 번째 명령문에서 `Resource`의 ARN을 Amazon S3 버킷 및 위치로 바꾸고, 두 번째 명령문에서 `Resource`를 Secrets Manager의 보안 암호의 ARN으로 바꿉니다.

   Secrets Manager에서 보안 암호를 사용자 지정 키로 암호화하는 경우 키의 `kms:Decrypt`도 허용해야 합니다.

   Secrets Manager 대신 SSM Parameter Store를 사용하는 경우 `secretsmanager:GetSecretValue` 대신 파라미터에 대해 `ssm:GetParameter`를 허용해야 합니다.

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "s3:GetObject"
               ],
               "Resource": "arn:aws:s3:::MyBucket/ecs-domainless-gmsa-credspec/gmsa-cred-spec.json"
           },
           {
               "Effect": "Allow",
               "Action": [
                   "secretsmanager:GetSecretValue"
               ],
               "Resource": "arn:aws:secretsmanager:us-east-1:111122223333:secret:gmsa-plugin-AbCdEf"
           }
       ]
   }
   ```

------

## 8단계: Amazon ECS Exec에 대한 작업 역할 생성
<a name="tutorial-gmsa-windows-step8"></a>

이 자습서에서는 Amazon ECS Exec을 사용하여 실행 중인 작업 내에서 명령을 실행하여 기능을 확인합니다. ECS Exec를 사용하려면 서비스 또는 작업에서 ECS Exec을 켜고 작업 실행 역할이 아닌 작업 역할에 `ssmmessages` 권한이 있어야 합니다. 필요한 IAM 정책은 [ECS Exec 권한](task-iam-roles.md#ecs-exec-required-iam-permissions)를 참조하세요.

이 단계에서는 AWS CLI를 사용합니다. 기본 셸 `bash`의 AWS CloudShell에서 이러한 명령을 실행할 수 있습니다.

AWS CLI를 사용하여 작업 역할을 생성하려면 다음 단계를 따릅니다.

1. 다음 콘텐츠로 `ecs-tasks-trust-policy.json`이라는 파일을 생성합니다.

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Principal": {
                   "Service": "ecs-tasks.amazonaws.com"
               },
               "Action": "sts:AssumeRole"
           }
       ]
   }
   ```

------

1. IAM 역할을 생성합니다. 이름 `ecs-exec-demo-task-role`은 바꿀 수 있지만 다음 단계를 위해 그대로 유지하세요.

   다음 명령은 `sh` 및 호환 셸에서 사용되는 백슬래시 연속 문자를 사용합니다. 이 명령은 PowerShell과 호환되지 않습니다. PowerShell에서 사용하려면 명령을 수정해야 합니다.

   ```
   $ aws iam create-role --role-name ecs-exec-demo-task-role \
   --assume-role-policy-document file://ecs-tasks-trust-policy.json
   ```

   파일 `ecs-tasks-trust-policy.json`을 삭제할 수 있습니다.

1. 다음 콘텐츠로 `ecs-exec-demo-task-role-policy.json`이라는 파일을 생성합니다.

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "ssmmessages:CreateControlChannel",
                   "ssmmessages:CreateDataChannel",
                   "ssmmessages:OpenControlChannel",
                   "ssmmessages:OpenDataChannel"
               ],
               "Resource": "*"
           }
       ]
   }
   ```

------

1. IAM 역할을 생성하여 이전 단계의 역할에 연결합니다.

   다음 명령은 `sh` 및 호환 셸에서 사용되는 백슬래시 연속 문자를 사용합니다. 이 명령은 PowerShell과 호환되지 않습니다. PowerShell에서 사용하려면 명령을 수정해야 합니다.

   ```
   $ aws iam put-role-policy \
       --role-name ecs-exec-demo-task-role \
       --policy-name ecs-exec-demo-task-role-policy \
       --policy-document file://ecs-exec-demo-task-role-policy.json
   ```

   파일 `ecs-exec-demo-task-role-policy.json`을 삭제할 수 있습니다.

## 9단계: 도메인 없는 gMSA를 사용하는 작업 정의 등록
<a name="tutorial-gmsa-windows-step9"></a>



이 단계에서는 AWS CLI를 사용합니다. 기본 셸 `bash`의 AWS CloudShell에서 이러한 명령을 실행할 수 있습니다.

1. 다음 콘텐츠로 `windows-gmsa-domainless-task-def.json`이라는 파일을 생성합니다.

   ```
   {
     "family": "windows-gmsa-domainless-task",
     "containerDefinitions": [
       {
         "name": "windows_sample_app",
         "image": "mcr.microsoft.com/windows/servercore/iis",
         "cpu": 1024,
         "memory": 1024,
         "essential": true,
         "credentialSpecs": [
                   "credentialspecdomainless:arn:aws:s3:::ecs-domainless-gmsa-credspec/gmsa-cred-spec.json"
         ],
         "entryPoint": [
           "powershell",
           "-Command"
         ],
         "command": [
           "New-Item -Path C:\\inetpub\\wwwroot\\index.html -ItemType file -Value '<html> <head> <title>Amazon ECS Sample App</title> <style>body {margin-top: 40px; background-color: #333;} </style> </head><body> <div style=color:white;text-align:center> <h1>Amazon ECS Sample App</h1> <h2>Congratulations!</h2> <p>Your application is now running on a container in Amazon ECS.</p>' -Force ; C:\\ServiceMonitor.exe w3svc"
         ],
         "portMappings": [
           {
             "protocol": "tcp",
             "containerPort": 80,
             "hostPort": 8080
           }
         ]
       }
     ],
     "taskRoleArn": "arn:aws:iam::111122223333:role/ecs-exec-demo-task-role",
     "executionRoleArn": "arn:aws:iam::111122223333:role/ecsTaskExecutionRole"
   }
   ```

1. 다음 명령을 실행하여 작업 정의를 등록합니다.

   다음 명령은 `sh` 및 호환 셸에서 사용되는 백슬래시 연속 문자를 사용합니다. 이 명령은 PowerShell과 호환되지 않습니다. PowerShell에서 사용하려면 명령을 수정해야 합니다.

   ```
   $ aws ecs register-task-definition \
   --cli-input-json file://windows-gmsa-domainless-task-def.json
   ```

## 10단계: 클러스터에 Windows 컨테이너 인스턴스 등록
<a name="tutorial-gmsa-windows-step10"></a>

Amazon EC2 Windows 인스턴스를 시작하고 ECS 컨테이너 에이전트를 실행하여 클러스터의 컨테이너 인스턴스로 등록합니다. ECS는 작업이 시작되는 클러스터에 등록된 컨테이너 인스턴스에서 작업을 실행합니다.

1. AWS Management Console에서 Amazon ECS용으로 구성된 Amazon EC2 Windows 인스턴스를 시작하려면 [Amazon ECS Windows 컨테이너 인스턴스 시작](launch_window-container_instance.md)를 참조하세요. 사용자 데이터**에 대한 단계에서 중지합니다.

1. gMSA의 경우 ECS 컨테이너 에이전트를 시작하기 전에 사용자 데이터에서 환경 변수 `ECS_GMSA_SUPPORTED`를 설정해야 합니다.

   ECS Exec의 경우 에이전트는 `-EnableTaskIAMRole` 인수로 시작해야 합니다.

   작업이 EC2 IMDS 웹 서비스에 도달하여 역할 보안 인증을 검색하는 것을 방지하여 인스턴스 IAM 역할을 보호하려면 `-AwsvpcBlockIMDS` 인수를 추가합니다. 이는 `awsvpc` 네트워크 모드를 사용하는 작업에만 적용됩니다.

   ```
   <powershell>
   [Environment]::SetEnvironmentVariable("ECS_GMSA_SUPPORTED", $TRUE, "Machine")
   Import-Module ECSTools
   Initialize-ECSAgent -Cluster windows-domainless-gmsa-cluster -EnableTaskIAMRole -AwsvpcBlockIMDS
   </powershell>
   ```

1. **요약** 패널에서 인스턴스 구성 요약을 검토하고 준비가 되면 **인스턴스 시작**을 선택합니다.

## 11단계: 컨테이너 인스턴스 확인
<a name="tutorial-gmsa-windows-step11"></a>

AWS Management Console을 사용하여 클러스터에 컨테이너 인스턴스가 있는지 확인할 수 있습니다. 하지만 gMSA의 경우 속성으로** 표시되는 추가 기능이 필요합니다. 이러한 속성은 AWS Management Console에 표시되지 않으므로 이 자습서에서는 AWS CLI를 사용합니다.

이 단계에서는 AWS CLI를 사용합니다. 기본 셸 `bash`의 AWS CloudShell에서 이러한 명령을 실행할 수 있습니다.

1. 클러스터의 컨테이너 인스턴스를 나열합니다. 컨테이너 인스턴스의 ID는 EC2 인스턴스의 ID와 다릅니다.

   ```
   $ aws ecs list-container-instances
   ```

   출력:

   ```
   {
       "containerInstanceArns": [
           "arn:aws:ecs:aws-region:111122223333:container-instance/default/MyContainerInstanceID"
       ]
   }
   ```

   예를 들어 `526bd5d0ced448a788768334e79010fd`는 유효한 컨테이너 인스턴스 ID입니다.

1. 이전 단계의 컨테이너 인스턴스 ID를 사용하여 컨테이너 인스턴스의 세부 정보를 가져옵니다. `MyContainerInstanceID`를 ID로 바꿉니다.

   다음 명령은 `sh` 및 호환 셸에서 사용되는 백슬래시 연속 문자를 사용합니다. 이 명령은 PowerShell과 호환되지 않습니다. PowerShell에서 사용하려면 명령을 수정해야 합니다.

   ```
   $ aws ecs describe-container-instances \
        ----container-instances MyContainerInstanceID
   ```

   참고로 출력 내용이 매우 깁니다.

1. `attributes` 목록에 `name`이라는 키와 `ecs.capability.gmsa-domainless` 값을 갖는 개체가 있는지 확인합니다. 다음은 이 개체의 예입니다.

   출력:

   ```
   {
       "name": "ecs.capability.gmsa-domainless"
   }
   ```

## 12단계: Windows 작업 실행
<a name="tutorial-gmsa-windows-step12"></a>

Amazon ECS 작업을 실행합니다. 클러스터에 컨테이너 인스턴스가 1개만 있는 경우 `run-task`를 사용할 수 있습니다. 컨테이너 인스턴스가 여러 개 있는 경우 `start-task`을 사용하고 작업을 실행할 컨테이너 인스턴스 ID를 지정한 다음 작업 정의에 배치 제약을 추가하여 이 작업이 실행되는 컨테이너 인스턴스의 유형을 제어하는 것이 더 쉬울 수 있습니다.

이 단계에서는 AWS CLI를 사용합니다. 기본 셸 `bash`의 AWS CloudShell에서 이러한 명령을 실행할 수 있습니다.

1. 

   다음 명령은 `sh` 및 호환 셸에서 사용되는 백슬래시 연속 문자를 사용합니다. 이 명령은 PowerShell과 호환되지 않습니다. PowerShell에서 사용하려면 명령을 수정해야 합니다.

   ```
   aws ecs run-task --task-definition windows-gmsa-domainless-task \
       --enable-execute-command --cluster windows-domainless-gmsa-cluster
   ```

   명령에서 반환된 작업 ID를 메모합니다.

1. 다음 명령을 실행하여 작업이 시작되었는지 확인합니다. 이 명령은 대기하며 작업이 시작될 때까지 셸 프롬프트를 반환하지 않습니다. `MyTaskID`을 전 단계의 작업 ID로 바꿉니다.

   ```
   $ aws ecs wait tasks-running --task MyTaskID
   ```

## 13단계: 컨테이너에 gMSA 보안 인증이 있는지 확인
<a name="tutorial-gmsa-windows-step13"></a>

작업의 컨테이너에 Kerberos 토큰 gMSA가 있는지 확인합니다.

이 단계에서는 AWS CLI를 사용합니다. 기본 셸 `bash`의 AWS CloudShell에서 이러한 명령을 실행할 수 있습니다.

1. 

   다음 명령은 `sh` 및 호환 셸에서 사용되는 백슬래시 연속 문자를 사용합니다. 이 명령은 PowerShell과 호환되지 않습니다. PowerShell에서 사용하려면 명령을 수정해야 합니다.

   ```
   $ aws ecs execute-command \
   --task MyTaskID \
   --container windows_sample_app \
   --interactive \
   --command powershell.exe
   ```

   PowerShell 프롬프트가 출력됩니다.

1. 컨테이너 내의 PowerShell 터미널에서 다음 명령을 실행합니다.

   ```
   PS C:\> klist get ExampleAccount$
   ```

   출력에서 `Principal`이 이전에 생성한 것인지 확인합니다.

## 14단계: 정리
<a name="tutorial-gmsa-windows-step14"></a>

이 자습서로 완료를 한 후에 사용하지 않는 리소스에 대해 요금이 발생하는 것을 방지하기 위해 연결된 리소스를 정리해야 합니다.

이 단계에서는 AWS CLI를 사용합니다. 기본 셸 `bash`의 AWS CloudShell에서 이러한 명령을 실행할 수 있습니다.

1. 작업을 중지합니다. `MyTaskID`를 12단계 [12단계: Windows 작업 실행](#tutorial-gmsa-windows-step12)의 작업 ID로 바꿉니다.

   ```
   $ aws ecs stop-task --task MyTaskID
   ```

1. Amazon EC2 인스턴스를 종료합니다. 이후 클러스터의 컨테이너 인스턴스는 1시간 후에 자동으로 삭제됩니다.

   Amazon EC2 콘솔을 사용하여 인스턴스를 찾고 종료할 수 있습니다. 또는 다음 명령을 실행할 수 있습니다. 명령을 실행하려면 1단계 [11단계: 컨테이너 인스턴스 확인](#tutorial-gmsa-windows-step11)의 `aws ecs describe-container-instances` 명령 출력에서 EC2 인스턴스 ID를 찾습니다. i-10a64379는 EC2 인스턴스 ID의 예입니다.

   ```
   $ aws ec2 terminate-instances --instance-ids MyInstanceID
   ```

1. Amazon S3에서 CredSpec 파일을 삭제합니다. `MyBucket`을 Amazon S3 버킷 이름으로 바꿉니다.

   ```
   $ aws s3api delete-object --bucket MyBucket --key ecs-domainless-gmsa-credspec/gmsa-cred-spec.json
   ```

1. Secrets Manager에서 보안 암호를 삭제합니다. SSM Parameter Store를 대신 사용한 경우 파라미터를 삭제합니다.

   다음 명령은 `sh` 및 호환 셸에서 사용되는 백슬래시 연속 문자를 사용합니다. 이 명령은 PowerShell과 호환되지 않습니다. PowerShell에서 사용하려면 명령을 수정해야 합니다.

   ```
   $ aws secretsmanager delete-secret --secret-id gmsa-plugin-input \
        --force-delete-without-recovery
   ```

1. 작업 정의를 등록 취소하고 삭제합니다. 작업 정의를 등록 취소하면 시작하는 데 사용할 수 없도록 비활성으로 표시됩니다. 그려면 작업 정의를 삭제할 수 있습니다.

   1. 버전을 지정하여 작업 정의를 등록 취소합니다. ECS는 1부터 시작하는 번호를 지정하여 작업 정의 버전을 자동으로 만듭니다. 컨테이너 이미지의 레이블과 같은 형식으로 버전을 참조합니다(예: `:1`)

      ```
      $ aws ecs deregister-task-definition --task-definition windows-gmsa-domainless-task:1
      ```

   1. 작업 정의를 삭제합니다.

      ```
      $ aws ecs delete-task-definitions --task-definition windows-gmsa-domainless-task:1
      ```

1. (선택 사항) 클러스터를 생성한 경우 ECS 클러스터를 삭제합니다.

   ```
   $ aws ecs delete-cluster --cluster windows-domainless-gmsa-cluster
   ```

## Windows 컨테이너에 대한 Amazon ECS 도메인 없는 gMSA 디버깅
<a name="tutorial-gmsa-windows-debugging"></a>



Amazon ECS 작업 상태  
ECS는 작업 시작을 정확히 한 번 시도합니다. 문제가 있는 모든 작업은 중지되고 `STOPPED` 상태로 설정됩니다. 작업과 관련된 문제에는 두 가지 일반적인 유형이 있습니다. 첫 번째는 시작할 수 없는 작업입니다. 둘째, 컨테이너 중 하나에서 애플리케이션이 중지된 작업입니다. AWS Management Console에서 작업의 **중지 이유** 필드에서 작업이 중지된 이유를 확인합니다. AWS CLI에서는 작업을 설명하고 `stoppedReason`을 봅니다. AWS Management Console 및 AWS CLI의 단계에 대한 내용은 [Amazon ECS 중지된 작업 오류 보기](stopped-task-errors.md)를 참조하세요.

Windows 이벤트  
컨테이너의 gMSA에 대한 Windows 이벤트는 `Microsoft-Windows-Containers-CCG` 로그 파일에 기록되며 이벤트 뷰어에서 `Logs\Microsoft\Windows\Containers-CCG\Admin`의 애플리케이션 및 서비스 섹션에서 확인할 수 있습니다. 자세한 디버깅 팁은 Microsoft Learn 웹사이트의 [Troubleshoot gMSAs for Windows containers](https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/gmsa-troubleshooting#non-domain-joined-container-hosts-use-event-logs-to-identify-configuration-issues)를 참조하세요.

ECS 에이전트 gMSA 플러그인  
Windows 컨테이너 인스턴스의 ECS 에이전트용 gMSA 플러그인에 대한 로깅은 `C:/ProgramData/Amazon/gmsa-plugin/` 디렉터리에 있습니다. 이 로그에서 도메인 없는 사용자 보안 인증이 Secrets Manager와 같은 스토리지 위치에서 다운로드되었는지, 보안 인증 형식을 올바르게 읽었는지 확인합니다.

# Amazon ECS의 EC2 Windows 컨테이너에 대해 gMSA를 사용하는 방법 알아보기
<a name="windows-gmsa"></a>

Amazon ECS는 *그룹 관리형 서비스 계정*(gMSA)이라는 특수한 종류의 서비스 계정을 통해 Windows 컨테이너에 대한 Active Directory 인증을 지원합니다.

.NET 애플리케이션과 같은 Windows 기반 네트워크 애플리케이션은 종종 Active Directory를 사용하여 사용자와 서비스 간의 인증 및 권한 부여 관리를 용이하게 합니다. 개발자는 일반적으로 이러한 목적으로 Active Directory와 통합되고 도메인에 가입된 서버에서 실행되도록 애플리케이션을 설계합니다. Windows 컨테이너는 도메인에 가입할 수 없으므로 gMSA와 함께 실행되도록 Windows 컨테이너를 구성해야 합니다.

gMSA로 실행 중인 Windows 컨테이너는 호스트 Amazon EC2 인스턴스에 의존하여 Active Directory 도메인 컨트롤러에서 gMSA 자격 증명을 검색하고 이를 컨테이너 인스턴스에 제공합니다. 자세한 내용은 [Windows 컨테이너용 gMSA 생성](https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/manage-serviceaccounts) 섹션을 참조하세요.

**참고**  
이 기능은 Fargate의 Windows 컨테이너에서 지원되지 않습니다.

**Topics**
+ [고려 사항](#windows-gmsa-considerations)
+ [사전 조건](#windows-gmsa-prerequisites)
+ [Amazon ECS에서 Windows 컨테이너에 대한 gMSA 설정](#windows-gmsa-setup)

## 고려 사항
<a name="windows-gmsa-considerations"></a>

Windows 컨테이너에 gMSA를 사용할 때는 다음 사항을 고려해야 합니다.
+ 컨테이너 인스턴스에 Amazon ECS 최적화 Windows Server 2016 Full AMI를 사용할 경우 컨테이너 호스트 이름은 자격 증명 사양 파일에 정의된 gMSA 계정 이름과 같아야 합니다. 컨테이너에 대한 호스트 이름을 지정하려면 `hostname` 컨테이너 정의 파라미터를 사용합니다. 자세한 내용은 [네트워크 설정](task_definition_parameters.md#container_definition_network) 섹션을 참조하세요.
+ **도메인 없는 gMSA** 및 **각 인스턴스를 단일 도메인에 가입** 중에서 선택할 수 있습니다. 도메인 없는 gMSA를 사용하면 컨테이너 인스턴스는 도메인에 가입되지 않고, 인스턴스의 다른 애플리케이션은 보안 인증을 사용하여 도메인에 액세스할 수 없고, 다른 도메인에 가입하는 작업은 동일한 인스턴스에서 실행될 수 있습니다.

  그런 다음 CredSpec 및 선택적으로 도메인 없는 gMSA에 대한 Active Directory 사용자 보안 인증으로 데이터 스토리지를 선택합니다.

  Amazon ECS는 Active Directory 보안 인증 사양 파일(CredSpec)을 사용합니다. 이 파일은 gMSA 계정 컨텍스트를 컨테이너에 전파하는 데 사용되는 gMSA 메타데이터를 포함합니다. CredSpec 파일을 생성하고 다음 표의 컨테이너 인스턴스의 운영 체제별 CredSpec 스토리지 옵션 중 하나에 저장합니다. 도메인 없는 방법을 사용하려면 CredSpec 파일의 선택적 섹션에서 다음 표의 컨테이너 인스턴스의 운영 체제별 *domainless user credentials*스토리지 옵션 중 하나에 보안 인증을 지정할 수 있습니다.    
<a name="gmsa-table"></a>[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/AmazonECS/latest/developerguide/windows-gmsa.html)

## 사전 조건
<a name="windows-gmsa-prerequisites"></a>

Amazon ECS에서 Windows 컨테이너 기능에 gMSA를 사용하려면 먼저 다음 사항을 충족해야 합니다.
+ 컨테이너에서 액세스할 리소스를 포함하는 Active Directory 도메인을 설정합니다. Amazon ECS는 다음 설정을 지원합니다.
  + Directory Service Active Directory. Directory Service는 Amazon EC2에 호스트되는 AWS 관리형 Active Directory입니다. 자세한 내용은 *AWS Directory Service 관리 안내서*의 [AWS 관리형 Microsoft AD 시작하기](https://docs.aws.amazon.com/directoryservice/latest/admin-guide/ms_ad_getting_started.html)를 참조하세요.
  + 온프레미스 Active Directory. Amazon ECS Linux 컨테이너 인스턴스가 도메인에 가입할 수 있도록 해야 합니다. 자세한 내용은 [AWS Direct Connect](https://docs.aws.amazon.com/whitepapers/latest/aws-vpc-connectivity-options/aws-direct-connect-network-to-amazon.html) 섹션을 참조하세요.
+ Active Directory에 기존 gMSA 계정이 있습니다. 자세한 내용은 [Windows 컨테이너용 gMSA 생성](https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/manage-serviceaccounts) 섹션을 참조하세요.
+ ***도메인 없는 gMSA* 또는 Amazon ECS를 사용하도록 선택한 경우 Amazon ECS 작업을 호스팅하는 Windows 컨테이너 인스턴스는 Active Directory에* *‘도메인 가입’되어 있어야 하며 gMSA 계정에 액세스할 수 있는 Active Directory 보안 그룹의 구성원이어야 합니다.**

  도메인 없는 gMSA를 사용하면 컨테이너 인스턴스는 도메인에 가입되지 않고, 인스턴스의 다른 애플리케이션은 보안 인증을 사용하여 도메인에 액세스할 수 없고, 다른 도메인에 가입하는 작업은 동일한 인스턴스에서 실행될 수 있습니다.
+ 필요한 IAM 권한을 추가했습니다. 필요한 권한은 초기 보안 인증 및 보안 인증 사양 저장을 위해 선택하는 방법에 따라 달라집니다.
  + 초기 보안 인증에 *도메인 없는 gMSA*를 사용하는 경우 AWS Secrets Manager에 대한 IAM 권한이 Amazon EC2 인스턴스 역할에 필요합니다.
  + 보안 인증 사양을 SSM Parameter Store에 저장하는 경우 Amazon EC2 Systems Manager Parameter Store에 대한 IAM 권한이 작업 실행 역할에 필요합니다.
  + 보안 인증 사양을 Amazon S3에 저장하는 경우에는 Amazon Simple Storage Service에 대한 IAM 권한이 작업 실행 역할에 필요합니다.

## Amazon ECS에서 Windows 컨테이너에 대한 gMSA 설정
<a name="windows-gmsa-setup"></a>

Amazon ECS에서 Windows 컨테이너에 대한 gMSA를 설정하려면 사전 조건 구성을 포함하는 전체 자습서 [AWS CLI를 사용하여 도메인이 없는 gMSA로 Amazon ECS Windows 컨테이너 사용](tutorial-gmsa-windows.md)를 따르면 됩니다.

다음 섹션에서는 CredSpec 구성에 대해 자세히 설명합니다.

**Topics**
+ [예: CredSpec](#windows-gmsa-example)
+ [도메인 없는 gMSA 설정](#windows-gmsa-domainless)
+ [태스크 정의에서 자격 증명 사양 파일 참조](#windows-gmsa-credentialspec)

### 예: CredSpec
<a name="windows-gmsa-example"></a>

Amazon ECS는 gMSA 계정 컨텍스트를 Windows 컨테이너에 전파하는 데 사용되는 gMSA 메타데이터가 포함된 보안 인증 사양 파일을 사용합니다. 자격 증명 사양 파일을 생성하여 태스크 정의의 `credentialSpec` 필드에서 참조할 수 있습니다. 자격 증명 사양 파일에 암호가 포함되어 있지 않습니다.

다음은 자격 증명 사양 파일의 예입니다.

```
{
    "CmsPlugins": [
        "ActiveDirectory"
    ],
    "DomainJoinConfig": {
        "Sid": "S-1-5-21-2554468230-2647958158-2204241789",
        "MachineAccountName": "WebApp01",
        "Guid": "8665abd4-e947-4dd0-9a51-f8254943c90b",
        "DnsTreeName": "contoso.com",
        "DnsName": "contoso.com",
        "NetBiosName": "contoso"
    },
    "ActiveDirectoryConfig": {
        "GroupManagedServiceAccounts": [
            {
                "Name": "WebApp01",
                "Scope": "contoso.com"
            }
        ]
    }
}
```

### 도메인 없는 gMSA 설정
<a name="windows-gmsa-domainless"></a>

컨테이너 인스턴스를 단일 도메인에 가입시키는 대신 도메인 없는 gMSA를 사용하는 것이 좋습니다. 도메인 없는 gMSA를 사용하면 컨테이너 인스턴스는 도메인에 가입되지 않고, 인스턴스의 다른 애플리케이션은 보안 인증을 사용하여 도메인에 액세스할 수 없고, 다른 도메인에 가입하는 작업은 동일한 인스턴스에서 실행될 수 있습니다.

1. CredSpec를 스토리지 옵션 중 하나에 업로드하기 전에 Secrets Manager 또는 SSM Parameter Store에서 보안 암호의 ARN을 사용하여 CredSpec에 정보를 추가합니다. 자세한 내용은 Microsoft Learn 웹 사이트에서 [Additional credential spec configuration for non-domain-joined container host use case](https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/manage-serviceaccounts#additional-credential-spec-configuration-for-non-domain-joined-container-host-use-case)를 참조하세요.

**도메인 없는 gMSA 보안 인증 형식**  
다음은 Active Directory에 대한 도메인 없는 gMSA 보안 인증의 JSON 형식입니다. 보안 인증을 Secrets Manager 또는 SSM Parameter Store에 저장합니다.

   ```
   {
       "username":"WebApp01",
       "password":"Test123!",
       "domainName":"contoso.com"
   }
   ```

1. 다음 정보를 CredSpec 파일의 `ActiveDirectoryConfig` 안에 추가합니다. ARN을 Secrets Manager 또는 SSM Parameter Store의 보안 암호를 바꿉니다.

   단, `PluginGUID` 값은 다음 예제 코드 조각의 GUID와 일치해야 하며 필수 항목입니다.

   ```
       "HostAccountConfig": {
           "PortableCcgVersion": "1",
           "PluginGUID": "{859E1386-BDB4-49E8-85C7-3070B13920E1}",
           "PluginInput": "{\"credentialArn\": \"arn:aws:secretsmanager:aws-region:111122223333:secret:gmsa-plugin-input\"}"
       }
   ```

   다음 형식(`\"arn:aws:ssm:aws-region:111122223333:parameter/gmsa-plugin-input\"`)의 ARN을 사용하여 SSM Parameter Store의 보안 암호를 사용할 수도 있습니다.

1. 수정한 CredSpec 파일은 다음 예제와 같아야 합니다.

   ```
   {
     "CmsPlugins": [
       "ActiveDirectory"
     ],
     "DomainJoinConfig": {
       "Sid": "S-1-5-21-4066351383-705263209-1606769140",
       "MachineAccountName": "WebApp01",
       "Guid": "ac822f13-583e-49f7-aa7b-284f9a8c97b6",
       "DnsTreeName": "contoso",
       "DnsName": "contoso",
       "NetBiosName": "contoso"
     },
     "ActiveDirectoryConfig": {
       "GroupManagedServiceAccounts": [
         {
           "Name": "WebApp01",
           "Scope": "contoso"
         },
         {
           "Name": "WebApp01",
           "Scope": "contoso"
         }
       ],
       "HostAccountConfig": {
         "PortableCcgVersion": "1",
         "PluginGUID": "{859E1386-BDB4-49E8-85C7-3070B13920E1}",
         "PluginInput": "{\"credentialArn\": \"arn:aws:secretsmanager:aws-region:111122223333:secret:gmsa-plugin-input\"}"
       }
     }
   }
   ```

### 태스크 정의에서 자격 증명 사양 파일 참조
<a name="windows-gmsa-credentialspec"></a>

Amazon ECS에서는 작업 정의의 `credentialSpecs` 필드에서 파일 경로를 참조하는 다음과 같은 방법을 지원합니다. 이러한 각 옵션에 컨테이너 인스턴스를 단일 도메인에 가입시키는지, 아니면 도메인 없는 gMSA를 사용하는지에 따라 각각 `credentialspec:` 또는 `domainlesscredentialspec:`를 입력할 수 있습니다.

#### Amazon S3 버킷
<a name="gmsa-credspec-s3"></a>

Amazon S3 버킷에 자격 증명 사양을 추가한 다음 태스크 정의의 `credentialSpecs` 필드에서 Amazon S3 버킷의 Amazon 리소스 이름(ARN)을 참조합니다.

```
{
    "family": "",
    "executionRoleArn": "",
    "containerDefinitions": [
        {
            "name": "",
            ...
            "credentialSpecs": [
                "credentialspecdomainless:arn:aws:s3:::${BucketName}/${ObjectName}"
            ],
            ...
        }
    ],
    ...
}
```

또한 작업에 Amazon S3 버킷에 대한 액세스 권한을 부여하려면 Amazon ECS 작업 실행 IAM 역할에 다음 권한을 인라인 정책으로 추가해야 합니다.

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "VisualEditor",
            "Effect": "Allow",
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Resource": [
                "arn:aws:s3:::{bucket_name}",
                "arn:aws:s3:::{bucket_name}/{object}"
            ]
        }
    ]
}
```

------

#### SSM Parameter Store 파라미터
<a name="gmsa-credspec-ssm"></a>

SSM Parameter Store 파라미터에 자격 증명 사양을 추가한 다음 태스크 정의의 `credentialSpecs` 필드에서 SSM Parameter Store 파라미터의 Amazon 리소스 이름(ARN)을 참조합니다.

```
{
    "family": "",
    "executionRoleArn": "",
    "containerDefinitions": [
        {
            "name": "",
            ...
            "credentialSpecs": [
                "credentialspecdomainless:arn:aws:ssm:region:111122223333:parameter/parameter_name"
            ],
            ...
        }
    ],
    ...
}
```

또한 작업에 SSM Parameter Store 파라미터에 대한 액세스 권한을 부여하려면 Amazon ECS 작업 실행 IAM 역할에 다음 권한을 인라인 정책으로 추가해야 합니다.

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssm:GetParameters"
            ],
            "Resource": "arn:aws:ssm:*:111122223333:parameter/example*"
        }
    ]
}
```

------

#### 로컬 파일
<a name="gmsa-credspec-file"></a>

로컬 파일의 자격 증명 사양 세부 정보를 사용하여 태스크 정의의 `credentialSpecs` 필드에 있는 파일 경로를 참조합니다. 참조되는 파일 경로는 `C:\ProgramData\Docker\CredentialSpecs` 디렉터리를 기준으로 해야 하며 백슬래시('\$1')를 파일 경로 구분자로 사용해야 합니다.

```
{
    "family": "",
    "executionRoleArn": "",
    "containerDefinitions": [
        {
            "name": "",
            ...
            "credentialSpecs": [
                "credentialspec:file://CredentialSpecDir\CredentialSpecFile.json"
            ],
            ...
        }
    ],
    ...
}
```

# EC2 Image Builder를 사용하여 사용자 지정된 Amazon ECS 최적화 AMI 구축
<a name="image-builder-tutorial"></a>

AWS에서는 Amazon ECS 최적화 AMI가 컨테이너 워크로드를 실행하기 위한 요구 사항 및 권장 사항으로 미리 구성되어 있으므로 이를 사용하도록 권장합니다. 소프트웨어를 더 추가하기 위해 AMI를 사용자 지정해야 하는 경우가 있을 수 있습니다. 서버 이미지의 생성, 관리 및 배포를 위해 EC2 Image Builder를 사용할 수 있습니다. 계정에서 생성된 사용자 지정된 이미지에 대한 소유권은 사용자에게 있습니다. EC2 Image Builder 파이프라인을 사용하여 이미지에 대한 업데이트 및 시스템 패치를 자동화하거나 독립 실행형 명령을 사용하여 정의된 구성 리소스로 이미지를 생성할 수 있습니다.

이미지에 대한 레시피를 생성합니다. 레시피에는 상위 이미지와 추가 구성 요소가 포함됩니다. 또한 사용자 지정된 AMI를 배포하는 파이프라인도 생성합니다.

이미지에 대한 레시피를 생성합니다. Image Builder 이미지 레시피는 출력 AMI 이미지에 대해 원하는 구성을 생성하기 위해 기본 이미지 및 기본 이미지에 적용할 구성 요소를 정의하는 문서입니다. 또한 사용자 지정된 AMI를 배포하는 파이프라인도 생성합니다. 자세한 내용은 **EC2 Image Builder 사용 설명서의 [How EC2 Image Builder works](https://docs.aws.amazon.com/imagebuilder/latest/userguide/how-image-builder-works.html)를 참조하세요.

EC2 Image Builder에서 다음과 같은 Amazon ECS 최적화 AMI 중 하나를 '상위 이미지'로 사용하는 것이 좋습니다.
+ Linux
  + Amazon ECS 최적화 AL2023 x86
  + Amazon ECS 최적화 Amazon Linux 2023(arm64) AMI
  + Amazon ECS 최적화 Amazon Linux 2 커널 5 AMI
  + Amazon ECS 최적화 Amazon Linux 2 x86 AMI
+ Windows
  + Amazon ECS 최적화 Windows 2022 Full x86
  + Amazon ECS 최적화 Windows 2022 Core x86
  + Amazon ECS 최적화 Windows 2019 Full x86
  + Amazon ECS 최적화 Windows 2019 Core x86
  + Amazon ECS 최적화 Windows 2016 Full x86

'사용 가능한 최신 OS 버전 사용'을 선택하는 것이 좋습니다. 파이프라인은 상위 이미지의 시맨틱 버전 관리를 사용하므로 자동으로 예약된 작업에서 종속성 업데이트를 감지하는 데 도움이 됩니다. 자세한 내용은 **EC2 Image Builder 사용 설명서의 [Semantic versioning](https://docs.aws.amazon.com/imagebuilder/latest/userguide/ibhow-semantic-versioning.html)을 참조하세요.

AWS에서는 보안 패치와 새 컨테이너 에이전트 버전을 사용해 Amazon ECS 최적화 AMI 이미지를 정기적으로 업데이트합니다. 이미지 레시피에서 AMI ID를 상위 이미지로 사용하는 경우 상위 이미지에 대한 업데이트를 정기적으로 확인해야 합니다. 업데이트가 있는 경우 업데이트된 AMI를 사용하여 레시피의 새 버전을 생성해야 합니다. 그러면 사용자 지정 이미지가 상위 이미지의 최신 버전을 통합됩니다. 새로 생성된 AMI로 Amazon ECS 클러스터에서 EC2 인스턴스를 자동으로 업데이트하는 워크플로를 생성하는 방법에 대한 자세한 내용은 [How to create an AMI hardening pipeline and automate updates to your ECS instance fleet](https://aws.amazon.com/blogs/security/how-to-create-an-ami-hardening-pipeline-and-automate-updates-to-your-ecs-instance-fleet/)을 참조하세요.

관리형 EC2 Image Builder 파이프라인을 통해 게시되는 상위 이미지의 Amazon 리소스 이름(ARN)을 지정할 수도 있습니다. Amazon은 관리형 파이프라인을 통해 Amazon ECS 최적화 AMI 이미지를 정기적으로 게시합니다. 이 이미지에는 퍼블릭 액세스가 가능합니다. 이미지에 액세스하려면 올바른 권한이 있어야 합니다. Image Builder 레시피에서 AMI 대신 이미지 ARN을 사용하는 경우 파이프라인은 실행될 때마다 상위 이미지의 최신 버전을 자동으로 사용합니다. 이 접근 방식을 사용하면 업데이트할 때마다 새 레시피 버전을 수동으로 생성할 필요가 없습니다.

## Amazon ECS 최적화 AMI 정리
<a name="cleanup-ecs-optimized-ami"></a>

Amazon ECS 최적화 AMI를 상위 이미지로 사용하는 경우 이미지를 정리하여 일시적인 문제를 방지해야 합니다. Amazon ECS 최적화 AMI는 Amazon ECS 에이전트가 Amazon ECS에서 컨테이너 인스턴스로 자동 시작하고 등록하도록 사전 구성되어 있습니다. 적절한 정리 없이 기본 이미지로 사용하면 사용자 지정 AMI에 문제가 발생할 수 있습니다.

나중에 사용할 수 있도록 이미지를 정리하려면 다음 명령을 실행하여 ecs-init 패키지 및 Docker 프로세스를 중지하는 구성 요소를 생성합니다.

```
sudo systemctl stop ecs
sudo systemctl stop docker
```

이미지를 저장할 때 로그 파일이 보존되지 않도록 현재 인스턴스에서 모든 로그 파일을 제거합니다. [Security best practices for EC2 Image Builder](https://docs.aws.amazon.com/imagebuilder/latest/userguide/security-best-practices.html)의 스크립트 예제를 사용하여 인스턴스에서 다양한 파일을 정리합니다.

Amazon ECS 특정 데이터를 정리하려면 다음 명령을 실행합니다.

```
sudo rm -rf /var/log/ecs/*
sudo rm /var/lib/ecs/data/agent.db
```

사용자 지정 Amazon ECS 최적화 AMI 생성에 대한 자세한 내용은 AWS 지식 센터의 [How do I create a custom AMI from an Amazon ECS-optimized AMI?](https://forums.aws.amazon.com/knowledge-center/ecs-create-custom-amis/)를 참조하세요.

## 코드형 인프라(IaC)에서 이미지 ARN 사용
<a name="infrastructure-as-code-arn"></a>

EC2 Image Builder 콘솔 또는 코드형 인프라(예: CloudFormation)나 AWS SDK를 사용하여 레시피를 구성할 수 있습니다. 레시피에서 상위 이미지를 지정하는 경우 EC2 AMI ID, Image Builder 이미지 ARN, AWS Marketplace 제품 ID 또는 컨테이너 이미지를 지정할 수 있습니다. AWS에서는 Amazon ECS 최적화 AMI의 AMI ID와 Image Builder 이미지 ARN을 모두 공개적으로 게시합니다. 다음은 이미지의 ARN 형식입니다.

```
arn:${Partition}:imagebuilder:${Region}:${Account}:image/${ImageName}/${ImageVersion}
```

`ImageVersion` 형식은 다음과 같습니다. *major*, *minor*, *patch*를 최신 값으로 바꿉니다.

```
<major>.<minor>.<patch>
```

`major`, `minor`, `patch`를 특정 값으로 바꾸거나 이미지의 버전 없는 ARN을 사용하여 파이프라인이 상위 이미지의 최신 버전을 사용해 최신 상태를 유지할 수 있습니다. 버전이 없는 ARN은 와일드카드 형식 'x.x.x'를 사용하여 이미지 버전을 나타냅니다. 이 접근 방식을 사용하면 Image Builder 서비스에서 이미지의 최신 버전을 자동으로 확인할 수 있습니다. 버전 없는 ARN을 사용하면 참조가 항상 사용 가능한 최신 이미지를 가리키므로 배포에서 이미지를 최신 상태로 유지하는 프로세스가 간소화됩니다. 콘솔에서 레시피를 생성하면 EC2 Image Builder는 상위 이미지의 ARN을 자동으로 식별합니다. IaC를 사용하여 레시피를 생성할 때 ARN을 식별하고 원하는 이미지 버전을 선택하거나 버전 없는 ARN을 사용하여 사용 가능한 최신 이미지를 표시해야 합니다. 기준에 맞는 이미지만 필터링하여 표시할 수 있도록 자동화된 스크립트를 생성하는 것이 좋습니다. 다음 Python 스크립트는 Amazon ECS 최적화 AMI 목록을 검색하는 방법을 보여줍니다.

스크립트는 두 개의 선택적 인수(`owner` 및 `platform`, 기본값: 각각 'Amazon' 및 'Windows')를 허용합니다. 소유자 인수의 유효한 값은 `Self`, `Shared`, `Amazon` 및 `ThirdParty`입니다. 플랫폼 인수의 유효한 값은 `Windows` 및 `Linux`입니다. 예를 들어, `owner` 인수를 `Amazon`으로 설정하고 `platform`을 `Linux`로 설정한 상태에서 스크립트를 실행하면 스크립트는 Amazon ECS 최적화 이미지를 포함하여 Amazon에서 게시한 이미지 목록을 생성합니다.

```
import boto3
import argparse

def list_images(owner, platform):
    # Create a Boto3 session
    session = boto3.Session()
    
    # Create an EC2 Image Builder client
    client = session.client('imagebuilder')

    # Define the initial request parameters
    request_params = {
        'owner': owner,
        'filters': [
            {
                'name': 'platform',
                'values': [platform]
            }
        ]
    }

    # Initialize the results list
    all_images = []

    # Get the initial response with the first page of results
    response = client.list_images(**request_params)

    # Extract images from the response
    all_images.extend(response['imageVersionList'])

    # While 'nextToken' is present, continue paginating
    while 'nextToken' in response and response['nextToken']:
        # Update the token for the next request
        request_params['nextToken'] = response['nextToken']

        # Get the next page of results
        response = client.list_images(**request_params)

        # Extract images from the response
        all_images.extend(response['imageVersionList'])

    return all_images

def main():
    # Initialize the parser
    parser = argparse.ArgumentParser(description="List AWS images based on owner and platform")
    
    # Add the parameters/arguments
    parser.add_argument("--owner", default="Amazon", help="The owner of the images. Default is 'Amazon'.")
    parser.add_argument("--platform", default="Windows", help="The platform type of the images. Default is 'Windows'.")

    # Parse the arguments
    args = parser.parse_args()

    # Retrieve all images based on the provided owner and platform
    images = list_images(args.owner, args.platform)

    # Print the details of the images
    for image in images:
        print(f"Name: {image['name']}, Version: {image['version']}, ARN: {image['arn']}")

if __name__ == "__main__":
    main()
```

## CloudFormation에서 이미지 ARN 사용
<a name="arn-with-cloudformation"></a>

Image Builder 이미지 레시피는 출력 이미지의 의도한 구성을 달성하는 데 필요한 상위 이미지 및 구성 요소를 지정하는 청사진입니다. `AWS::ImageBuilder::ImageRecipe` 리소스를 사용합니다. `ParentImage` 값을 이미지 ARN으로 설정합니다. 파이프라인이 항상 최신 버전의 이미지를 사용하도록 원하는 이미지의 버전 없는 ARN을 사용합니다. 예를 들어 `arn:aws:imagebuilder:us-east-1:aws:image/amazon-linux-2023-ecs-optimized-x86/x.x.x`입니다. 다음 `AWS::ImageBuilder::ImageRecipe` 리소스 정의는 Amazon 관리형 이미지 ARN을 사용합니다.

```
ECSRecipe:
    Type: AWS::ImageBuilder::ImageRecipe
    Properties:
      Name: MyRecipe
      Version: '1.0.0'
      Components:
        - ComponentArn: [<The component arns of the image recipe>]
      ParentImage: "arn:aws:imagebuilder:us-east-1:aws:image/amazon-linux-2023-ecs-optimized-x86/x.x.x"
```

[https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-imagerecipe.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-imagerecipe.html) 리소스에 대한 자세한 내용은 **AWS CloudFormation 사용 설명서를 참조하세요.

`AWS::ImageBuilder::ImagePipeline` 리소스의 `Schedule` 속성을 설정하여 파이프라인에서 새 이미지의 생성을 자동화할 수 있습니다. 일정에는 시작 조건과 cron 표현식이 포함됩니다. 자세한 내용은 AWS CloudFormation 사용 설명서**의 [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-imagepipeline.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-imagepipeline.html)를 참조하세요.

 다음 `AWS::ImageBuilder::ImagePipeline` 예제에서 파이프라인은 매일 오전 10시 협정 세계시(UTC)에 빌드를 실행합니다. 다음 `Schedule` 값을 설정합니다.
+ `PipelineExecutionStartCondition`를 `EXPRESSION_MATCH_AND_DEPENDENCY_UPDATES_AVAILABLE`으로 설정합니다. 빌드는 시맨틱 버전에서 와일드카드 'x'를 사용하는 상위 이미지나 구성 요소와 같은 종속 리소스가 업데이트된 경우에만 시작됩니다. 이렇게 하면 빌드는 해당 리소스의 최신 업데이트를 통합합니다.
+ ScheduleExpression을 cron 표현식 `(0 10 * * ? *)`로 설정합니다.

```
ECSPipeline:
    Type: AWS::ImageBuilder::ImagePipeline
    Properties:
      Name: my-pipeline
      ImageRecipeArn: <arn of the recipe you created in previous step>
      InfrastructureConfigurationArn: <ARN of the infrastructure configuration associated with this image pipeline>
      Schedule:
        PipelineExecutionStartCondition: EXPRESSION_MATCH_AND_DEPENDENCY_UPDATES_AVAILABLE
        ScheduleExpression: 'cron(0 10 * * ? *)'
```

## Terraform에서 이미지 ARN 사용
<a name="arn-with-terraform"></a>

Terraform에서 파이프라인의 상위 이미지 및 일정을 지정하는 접근 방식은 AWS CloudFormation의 방식과 일관됩니다. `aws_imagebuilder_image_recipe` 리소스를 사용합니다. `parent_image` 값을 이미지 ARN으로 설정합니다. 파이프라인이 항상 최신 버전의 이미지를 사용하도록 원하는 이미지의 버전 없는 ARN을 사용합니다. 자세한 내용은 Terraform 설명서의 [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/imagebuilder_image_recipe#argument-reference](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/imagebuilder_image_recipe#argument-reference)을 참조하세요.

`aws_imagebuilder_image_pipeline resource`의 일정 구성 블록에서 `schedule_expression` 인수 값을 원하는 cron 표현식으로 설정하여 파이프라인 실행 빈도를 지정하고 `pipeline_execution_start_condition`을 `EXPRESSION_MATCH_AND_DEPENDENCY_UPDATES_AVAILABLE`로 설정합니다. 자세한 내용은 Terraform 설명서의 [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/imagebuilder_image_pipeline#argument-reference](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/imagebuilder_image_pipeline#argument-reference)을 참조하세요.

# Amazon ECS에서 AWS Deep Learning Containers 사용
<a name="deep-learning-containers"></a>

AWS Deep Learning Containers는 Amazon ECS의 TensorFlow 및 Apache MXNet(Incubating)에서 모델을 교육하고 제공하기 위한 Docker 이미지 세트를 제공합니다. Deep Learning Containers는 TensorFlow, NVIDIA CUDA(GPU 인스턴스용) 및 Intel MKL(CPU 인스턴스용) 라이브러리에 최적의 환경을 사용할 수 있습니다. Deep Learning Containers용 컨테이너 이미지는 Amazon ECS 태스크 정의에서 참조하기 위해 Amazon ECR에서 사용할 수 있습니다. Amazon Elastic Inference와 함께 Deep Learning Containers를 사용하면 추론 비용을 낮출 수 있습니다

Amazon ECS에서 Elastic Inference 없이 Deep Learning Containers 사용을 시작하려면 *AWS Deep Learning AMIs 개발자 안내서*의 [Amazon ECS 설정](https://docs.aws.amazon.com/deep-learning-containers/latest/devguide/deep-learning-containers-ecs-setup.html)을 참조하세요.

# 자습서: 블루/그린 배포를 사용하여 서비스 생성
<a name="create-blue-green"></a>

Amazon ECS가 Amazon ECS 콘솔의 서비스 생성 마법사에 블루/그린 배포를 통합했습니다. 자세한 내용은 [Amazon ECS 롤링 업데이트 배포 생성](create-service-console-v2.md) 섹션을 참조하세요.

다음 자습서에서는 AWS CLI에서 블루/그린 배포 유형을 사용하는 Fargate 작업이 포함된 Amazon ECS 서비스를 생성하는 방법을 설명합니다.

**참고**  
CloudFormation에 블루/그린 배포 수행에 대한 지원이 추가되었습니다. 자세한 정보는 *AWS CloudFormation 사용 설명서*의 [CloudFormation을 사용하여 CodeDeploy를 통한 Amazon ECS 블루/그린 배포 수행](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/blue-green.html)을 참조하세요.

## 사전 조건
<a name="create-blue-green-prereqs"></a>

이 자습서에서는 다음 사전 조건이 충족되었다고 가정합니다.
+ 최신 버전의 AWS CLI가 설치 및 구성됩니다. AWS CLI 설치 또는 업그레이드에 관한 자세한 정보는 [AWS Command Line Interface 설치](https://docs.aws.amazon.com/cli/latest/userguide/installing.html)를 참조하세요.
+ [Amazon ECS 사용 설정](get-set-up-for-amazon-ecs.md)의 단계가 완료되었습니다.
+ IAM 사용자는 [AmazonECS\$1FullAccess](security-iam-awsmanpol.md#security-iam-awsmanpol-AmazonECS_FullAccess) IAM 정책 예제에 지정된 필수 권한을 가집니다.
+ 사용할 VPC 및 보안 그룹이 생성되었습니다. 자세한 내용은 [Virtual Private Cloud 생성](get-set-up-for-amazon-ecs.md#create-a-vpc) 섹션을 참조하세요.
+ Amazon ECS CodeDeploy IAM 역할이 생성됩니다. 자세한 정보는 [Amazon ECS CodeDeploy IAM 역할](codedeploy_IAM_role.md) 섹션을 참조하세요.

## 1단계: Application Load Balancer 생성
<a name="create-blue-green-loadbalancer"></a>

블루/그린 배포 유형을 사용하는 Amazon ECS 서비스에서는 Application Load Balancer 또는 Network Load Balancer 중 하나를 사용해야 합니다. 이 자습서에서는 Application Load Balancer를 사용합니다.

**Application Load Balancer를 생성하려면**

1. [create-load-balancer](https://docs.aws.amazon.com/cli/latest/reference/elbv2/create-load-balancer.html) 명령을 사용하여 Application Load Balancer를 생성합니다. 속해 있는 보안 그룹과 가용 영역이 다른 서브넷 2개를 지정합니다.

   ```
   aws elbv2 create-load-balancer \
        --name bluegreen-alb \
        --subnets subnet-abcd1234 subnet-abcd5678 \
        --security-groups sg-abcd1234 \
        --region us-east-1
   ```

   출력에는 다음 형식과 함께 로드 밸런서의 Amazon 리소스 이름(ARN)이 포함됩니다.

   ```
   arn:aws:elasticloadbalancing:region:aws_account_id:loadbalancer/app/bluegreen-alb/e5ba62739c16e642
   ```

1. 다음과 같이 [create-target-group](https://docs.aws.amazon.com/cli/latest/reference/elbv2/create-target-group.html) 명령을 사용하여 대상 그룹을 만듭니다. 이 대상 그룹은 서비스에 설정된 원래 작업 세트로 트래픽을 라우팅합니다.

   ```
   aws elbv2 create-target-group \
        --name bluegreentarget1 \
        --protocol HTTP \
        --port 80 \
        --target-type ip \
        --vpc-id vpc-abcd1234 \
        --region us-east-1
   ```

   출력에는 다음 형식의 대상 그룹 ARN이 포함됩니다.

   ```
   arn:aws:elasticloadbalancing:region:aws_account_id:targetgroup/bluegreentarget1/209a844cd01825a4
   ```

1. [create-listener](https://docs.aws.amazon.com/cli/latest/reference/elbv2/create-listener.html) 명령을 사용하여 대상 그룹에 요청을 전달하는 기본 규칙이 있는 로드 밸런서 리스너를 생성합니다.

   ```
   aws elbv2 create-listener \
        --load-balancer-arn arn:aws:elasticloadbalancing:region:aws_account_id:loadbalancer/app/bluegreen-alb/e5ba62739c16e642 \
        --protocol HTTP \
        --port 80 \
        --default-actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:region:aws_account_id:targetgroup/bluegreentarget1/209a844cd01825a4 \
        --region us-east-1
   ```

   출력에는 다음 형식의 리스너 ARN이 포함됩니다.

   ```
   arn:aws:elasticloadbalancing:region:aws_account_id:listener/app/bluegreen-alb/e5ba62739c16e642/665750bec1b03bd4
   ```

## 2단계: Amazon ECS 클러스터 생성
<a name="create-blue-green-cluster"></a>

[create-cluster](https://docs.aws.amazon.com/cli/latest/reference/ecs/create-cluster.html) 명령을 사용하여 이름이 `tutorial-bluegreen-cluster`인 클러스터를 생성합니다.

```
aws ecs create-cluster \
     --cluster-name tutorial-bluegreen-cluster \
     --region us-east-1
```

출력에는 다음 형식의 클러스터 ARN이 포함됩니다.

```
arn:aws:ecs:region:aws_account_id:cluster/tutorial-bluegreen-cluster
```

## 3단계: 작업 정의 등록
<a name="create-blue-green-taskdef"></a>

[register-task-definition](https://docs.aws.amazon.com/cli/latest/reference/ecs/register-task-definition.html) 명령을 사용하여 Fargate와 호환되는 태스크 정의를 등록합니다. 이를 위해서는 `awsvpc` 네트워크 모드를 사용해야 합니다. 다음은 이 자습서에서 사용된 태스크 정의 예제입니다.

먼저, 다음 내용으로 이름이 `fargate-task.json`인 파일을 생성합니다. 작업 실행 역할에 ARN을 사용해야 합니다. 자세한 정보는 [Amazon ECS 태스크 실행 IAM 역할](task_execution_IAM_role.md) 섹션을 참조하세요.

```
{
    "family": "sample-fargate", 
    "networkMode": "awsvpc", 
    "containerDefinitions": [
        {
            "name": "sample-app", 
            "image": "public.ecr.aws/docker/library/httpd:latest", 
            "portMappings": [
                {
                    "containerPort": 80, 
                    "hostPort": 80, 
                    "protocol": "tcp"
                }
            ], 
            "essential": true, 
            "entryPoint": [
                "sh",
		"-c"
            ], 
            "command": [
                "/bin/sh -c \"echo '<html> <head> <title>Amazon ECS Sample App</title> <style>body {margin-top: 40px; background-color: #333;} </style> </head><body> <div style=color:white;text-align:center> <h1>Amazon ECS Sample App</h1> <h2>Congratulations!</h2> <p>Your application is now running on a container in Amazon ECS.</p> </div></body></html>' >  /usr/local/apache2/htdocs/index.html && httpd-foreground\""
            ]
        }
    ], 
    "requiresCompatibilities": [
        "FARGATE"
    ], 
    "cpu": "256", 
    "memory": "512"
}
```

그런 다음, 생성한 `fargate-task.json` 파일을 사용하여 태스크 정의를 등록합니다.

```
aws ecs register-task-definition \
     --cli-input-json file://fargate-task.json \
     --region us-east-1
```

## 4단계: Amazon ECS 서비스 생성
<a name="create-blue-green-service"></a>

[create-service](https://docs.aws.amazon.com/cli/latest/reference/ecs/create-service.html) 명령을 사용하여 서비스를 생성합니다.

먼저, 다음 내용으로 이름이 `service-bluegreen.json`인 파일을 생성합니다.

```
{
    "cluster": "tutorial-bluegreen-cluster",
    "serviceName": "service-bluegreen",
    "taskDefinition": "tutorial-task-def",
    "loadBalancers": [
        {
            "targetGroupArn": "arn:aws:elasticloadbalancing:region:aws_account_id:targetgroup/bluegreentarget1/209a844cd01825a4",
            "containerName": "sample-app",
            "containerPort": 80
        }
    ],
    "launchType": "FARGATE",
    "schedulingStrategy": "REPLICA",
    "deploymentController": {
        "type": "CODE_DEPLOY"
    },
    "platformVersion": "LATEST",
    "networkConfiguration": {
       "awsvpcConfiguration": {
          "assignPublicIp": "ENABLED",
          "securityGroups": [ "sg-abcd1234" ],
          "subnets": [ "subnet-abcd1234", "subnet-abcd5678" ]
       }
    },
    "desiredCount": 1
}
```

그런 다음, 생성한 `service-bluegreen.json` 파일을 사용하여 서비스를 생성합니다.

```
aws ecs create-service \
     --cli-input-json file://service-bluegreen.json \
     --region us-east-1
```

출력에는 다음 형식의 서비스 ARN이 포함됩니다.

```
arn:aws:ecs:region:aws_account_id:service/service-bluegreen
```

## 5단계: AWS CodeDeploy 리소스 생성
<a name="create-blue-green-codedeploy"></a>

다음 단계를 사용하여 CodeDeploy 애플리케이션, CodeDeploy 배포 그룹의 Application Load Balancer 대상 그룹 및 CodeDeploy 배포 그룹을 생성합니다.

**CodeDeploy 리소스를 생성하려면**

1. [create-application](https://docs.aws.amazon.com/cli/latest/reference/deploy/create-application.html) 명령을 사용하여 CodeDeploy 애플리케이션을 생성합니다. `ECS` 컴퓨팅 플랫폼을 지정합니다.

   ```
   aws deploy create-application \
        --application-name tutorial-bluegreen-app \
        --compute-platform ECS \
        --region us-east-1
   ```

   출력에는 다음 형식의 애플리케이션 ID가 포함됩니다.

   ```
   {
       "applicationId": "b8e9c1ef-3048-424e-9174-885d7dc9dc11"
   }
   ```

1. [create-target-group](https://docs.aws.amazon.com/cli/latest/reference/elbv2/create-target-group.html) 명령을 사용하여 CodeDeploy 배포 그룹을 생성할 때 사용할 2차 Application Load Balancer 대상 그룹을 생성합니다.

   ```
   aws elbv2 create-target-group \
        --name bluegreentarget2 \
        --protocol HTTP \
        --port 80 \
        --target-type ip \
        --vpc-id "vpc-0b6dd82c67d8012a1" \
        --region us-east-1
   ```

   출력에는 다음 형식의 대상 그룹 ARN이 포함됩니다.

   ```
   arn:aws:elasticloadbalancing:region:aws_account_id:targetgroup/bluegreentarget2/708d384187a3cfdc
   ```

1. [create-deployment-group](https://docs.aws.amazon.com/cli/latest/reference/deploy/create-deployment-group.html) 명령을 사용하여 CodeDeploy 배포 그룹을 생성합니다.

   먼저, 다음 내용으로 이름이 `tutorial-deployment-group.json`인 파일을 생성합니다. 이 예제에서는 생성한 리소스를 사용합니다. `serviceRoleArn`에서 Amazon ECS CodeDeploy IAM 역할의 ARN을 지정합니다. 자세한 정보는 [Amazon ECS CodeDeploy IAM 역할](codedeploy_IAM_role.md) 섹션을 참조하세요.

   ```
   {
      "applicationName": "tutorial-bluegreen-app",
      "autoRollbackConfiguration": {
         "enabled": true,
         "events": [ "DEPLOYMENT_FAILURE" ]
      },
      "blueGreenDeploymentConfiguration": {
         "deploymentReadyOption": {
            "actionOnTimeout": "CONTINUE_DEPLOYMENT",
            "waitTimeInMinutes": 0
         },
         "terminateBlueInstancesOnDeploymentSuccess": {
            "action": "TERMINATE",
            "terminationWaitTimeInMinutes": 5
         }
      },
      "deploymentGroupName": "tutorial-bluegreen-dg",
      "deploymentStyle": {
         "deploymentOption": "WITH_TRAFFIC_CONTROL",
         "deploymentType": "BLUE_GREEN"
      },
      "loadBalancerInfo": {
         "targetGroupPairInfoList": [
           {
             "targetGroups": [
                {
                    "name": "bluegreentarget1"
                },
                {
                    "name": "bluegreentarget2"
                }
             ],
             "prodTrafficRoute": {
                 "listenerArns": [
                     "arn:aws:elasticloadbalancing:region:aws_account_id:listener/app/bluegreen-alb/e5ba62739c16e642/665750bec1b03bd4"
                 ]
             }
           }
         ]
      },
      "serviceRoleArn": "arn:aws:iam::aws_account_id:role/ecsCodeDeployRole",
      "ecsServices": [
          {
              "serviceName": "service-bluegreen",
              "clusterName": "tutorial-bluegreen-cluster"
          }
      ]
   }
   ```

   그런 다음, CodeDeploy 배포 그룹을 생성합니다.

   ```
   aws deploy create-deployment-group \
        --cli-input-json file://tutorial-deployment-group.json \
        --region us-east-1
   ```

   출력에는 다음 형식의 배포 그룹 ID가 포함됩니다.

   ```
   {
       "deploymentGroupId": "6fd9bdc6-dc51-4af5-ba5a-0a4a72431c88"
   }
   ```

## 6단계: CodeDeploy 배포 생성 및 모니터링
<a name="create-blue-green-verify"></a>

다음 단계를 사용하여 애플리케이션 사양 파일(AppSpec 파일)과 CodeDeploy 배포를 생성하고 업로드합니다.

**CodeDeploy 배포를 생성하고 모니터링하려면**

1. 다음 단계를 사용하여 AppSpec 파일을 생성하고 업로드합니다.

   1. CodeDeploy 배포 그룹의 내용으로 이름이 `appspec.yaml`인 파일을 생성합니다. 이 예제에서는 자습서 앞부분에서 생성한 리소스를 사용합니다.

      ```
      version: 0.0
      Resources:
        - TargetService:
            Type: AWS::ECS::Service
            Properties:
              TaskDefinition: "arn:aws:ecs:region:aws_account_id:task-definition/first-run-task-definition:7"
              LoadBalancerInfo:
                ContainerName: "sample-app"
                ContainerPort: 80
              PlatformVersion: "LATEST"
      ```

   1. [s3 mb](https://docs.aws.amazon.com/cli/latest/reference/s3/mb.html) 명령을 사용하여 AppSpec 파일용 Amazon S3 버킷을 생성합니다.

      ```
      aws s3 mb s3://tutorial-bluegreen-bucket
      ```

   1. [s3 cp](https://docs.aws.amazon.com/cli/latest/reference/s3/cp.html) 명령을 사용하여 AppSpec 파일을 Amazon S3 버킷으로 업로드합니다.

      ```
      aws s3 cp ./appspec.yaml s3://tutorial-bluegreen-bucket/appspec.yaml
      ```

1. 다음 단계를 사용하여 CodeDeploy 배포를 생성합니다.

   1. CodeDeploy 배포의 내용으로 이름이 `create-deployment.json`인 파일을 생성합니다. 이 예제에서는 자습서 앞부분에서 생성한 리소스를 사용합니다.

      ```
      {
          "applicationName": "tutorial-bluegreen-app",
          "deploymentGroupName": "tutorial-bluegreen-dg",
          "revision": {
              "revisionType": "S3",
              "s3Location": {
                  "bucket": "tutorial-bluegreen-bucket",
                  "key": "appspec.yaml",
                  "bundleType": "YAML"
              }
          }
      }
      ```

   1. [create-deployment](https://docs.aws.amazon.com/cli/latest/reference/deploy/create-deployment.html) 명령을 사용하여 배포를 생성합니다.

      ```
      aws deploy create-deployment \
           --cli-input-json file://create-deployment.json \
           --region us-east-1
      ```

      출력에는 다음 형식의 배포 ID가 포함됩니다.

      ```
      {
          "deploymentId": "d-RPCR1U3TW"
      }
      ```

   1. [get-deployment-target](https://docs.aws.amazon.com/cli/latest/reference/deploy/get-deployment-target.html) 명령을 사용하여 배포의 세부 정보를 가져와 이전 출력의 `deploymentId`를 지정합니다.

      ```
      aws deploy get-deployment-target \
           --deployment-id "d-IMJU3A8TW" \
           --target-id tutorial-bluegreen-cluster:service-bluegreen \
           --region us-east-1
      ```

      다음 출력처럼 `Succeeded` 상태가 될 때까지 배포 세부 정보를 계속 가져옵니다.

      ```
      {
          "deploymentTarget": {
              "deploymentTargetType": "ECSTarget",
              "ecsTarget": {
                  "deploymentId": "d-RPCR1U3TW",
                  "targetId": "tutorial-bluegreen-cluster:service-bluegreen",
                  "targetArn": "arn:aws:ecs:region:aws_account_id:service/service-bluegreen",
                  "lastUpdatedAt": 1543431490.226,
                  "lifecycleEvents": [
                      {
                          "lifecycleEventName": "BeforeInstall",
                          "startTime": 1543431361.022,
                          "endTime": 1543431361.433,
                          "status": "Succeeded"
                      },
                      {
                          "lifecycleEventName": "Install",
                          "startTime": 1543431361.678,
                          "endTime": 1543431485.275,
                          "status": "Succeeded"
                      },
                      {
                          "lifecycleEventName": "AfterInstall",
                          "startTime": 1543431485.52,
                          "endTime": 1543431486.033,
                          "status": "Succeeded"
                      },
                      {
                          "lifecycleEventName": "BeforeAllowTraffic",
                          "startTime": 1543431486.838,
                          "endTime": 1543431487.483,
                          "status": "Succeeded"
                      },
                      {
                          "lifecycleEventName": "AllowTraffic",
                          "startTime": 1543431487.748,
                          "endTime": 1543431488.488,
                          "status": "Succeeded"
                      },
                      {
                          "lifecycleEventName": "AfterAllowTraffic",
                          "startTime": 1543431489.152,
                          "endTime": 1543431489.885,
                          "status": "Succeeded"
                      }
                  ],
                  "status": "Succeeded",
                  "taskSetsInfo": [
                      {
                          "identifer": "ecs-svc/9223370493425779968",
                          "desiredCount": 1,
                          "pendingCount": 0,
                          "runningCount": 1,
                          "status": "ACTIVE",
                          "trafficWeight": 0.0,
                          "targetGroup": {
                              "name": "bluegreentarget1"
                          }
                      },
                      {
                          "identifer": "ecs-svc/9223370493423413672",
                          "desiredCount": 1,
                          "pendingCount": 0,
                          "runningCount": 1,
                          "status": "PRIMARY",
                          "trafficWeight": 100.0,
                          "targetGroup": {
                              "name": "bluegreentarget2"
                          }
                      }
                  ]
              }
          }
      }
      ```

## 7단계: 정리
<a name="create-blue-green-cleanup"></a>

이 자습서를 완료한 후에는 사용하지 않는 리소스에 요금이 발생하지 않도록 연결된 리소스를 정리합니다.

**자습서 리소스 정리**

1. [delete-deployment-group](https://docs.aws.amazon.com/cli/latest/reference/deploy/delete-deployment-group.html) 명령을 사용하여 CodeDeploy 배포 그룹을 삭제합니다.

   ```
   aws deploy delete-deployment-group \
        --application-name tutorial-bluegreen-app \
        --deployment-group-name tutorial-bluegreen-dg \
        --region us-east-1
   ```

1. [delete-application](https://docs.aws.amazon.com/cli/latest/reference/deploy/delete-application.html) 명령을 사용하여 CodeDeploy 애플리케이션을 삭제합니다.

   ```
   aws deploy delete-application \
        --application-name tutorial-bluegreen-app \
        --region us-east-1
   ```

1. [delete-service](https://docs.aws.amazon.com/cli/latest/reference/ecs/delete-service.html) 명령을 사용하여 Amazon ECS 서비스를 삭제합니다. `--force` 플래그를 사용하면 작업이 없는 상태로 축소되지 않은 서비스도 삭제할 수 있습니다.

   ```
   aws ecs delete-service \
        --service arn:aws:ecs:region:aws_account_id:service/service-bluegreen \
        --force \
        --region us-east-1
   ```

1. [delete-cluster](https://docs.aws.amazon.com/cli/latest/reference/ecs/delete-cluster.html) 명령을 사용하여 Amazon ECS 클러스터를 삭제합니다.

   ```
   aws ecs delete-cluster \
        --cluster tutorial-bluegreen-cluster \
        --region us-east-1
   ```

1. [s3 rm](https://docs.aws.amazon.com/cli/latest/reference/s3/rm.html) 명령을 사용하여 Amazon S3 버킷에서 AppSpec 파일을 삭제합니다.

   ```
   aws s3 rm s3://tutorial-bluegreen-bucket/appspec.yaml
   ```

1. [s3 rb](https://docs.aws.amazon.com/cli/latest/reference/s3/rb.html) 명령을 사용하여 Amazon S3 버킷을 삭제합니다.

   ```
   aws s3 rb s3://tutorial-bluegreen-bucket
   ```

1. [delete-load-balancer](https://docs.aws.amazon.com/cli/latest/reference/elbv2/delete-load-balancer.html) 명령을 사용하여 Application Load Balancer를 삭제합니다.

   ```
   aws elbv2 delete-load-balancer \
        --load-balancer-arn arn:aws:elasticloadbalancing:region:aws_account_id:loadbalancer/app/bluegreen-alb/e5ba62739c16e642 \
        --region us-east-1
   ```

1. [delete-target-group](https://docs.aws.amazon.com/cli/latest/reference/elbv2/delete-target-group.html) 명령을 사용하여 두 개의 Application Load Balancer 대상 그룹을 삭제합니다.

   ```
   aws elbv2 delete-target-group \
        --target-group-arn arn:aws:elasticloadbalancing:region:aws_account_id:targetgroup/bluegreentarget1/209a844cd01825a4 \
        --region us-east-1
   ```

   ```
   aws elbv2 delete-target-group \
        --target-group-arn arn:aws:elasticloadbalancing:region:aws_account_id:targetgroup/bluegreentarget2/708d384187a3cfdc \
        --region us-east-1
   ```