Amazon ECS와 Amazon SageMaker를 이용해서 꽃 이미지 분류를 위한 AI 웹 애플리케이션을 마이크로서비스 아키텍처(MSA)로 구축하는 방법을 소개합니다. 그리고 AWS CodePipeline과 Amazon SageMaker Pipelines를 이용해서 CI/CD를 구축하여 서비스를 민첩하게 운영하는 방법도 함께 소개합니다.
마이크로서비스 아키텍처(MSA)와 인공지능(AI)은 현대화 애플리케이션 구현에서 가장 많이 언급되는 기술입니다. 애플리케이션은 규모가 커질 경우 다양한 환경에서 구동되는 마이크로서비스가 만들어지는데 이를 운영할 수 있는 환경이 필요합니다. 그리고 인공지능 서비스를 위해서는 기계 학습 모델을 생성 및 학습하고 학습된 모델을 운영할 수 있는 환경이 필요합니다.
서비스 구축에 사용되는 Amazon ECS와 AWS Fargate는 AI 웹 애플리케이션을 컨테이너기반 마이크로서비스로 구성하여 운영을 자동화하고 손쉽게 배포, 관리 및 확장할 수 있도록 합니다. 마이크로서비스를 구성은 Web 계층과 WAS 계층으로 분리하여 서버 부하에 따른 확장을 효율적으로 하고 사용자에게 노출 되는 부분을 최소화 하여 보안을 강화합니다. Web 계층과 WAS 계층에는 기능 확장을 위해서 여러 마이크로 서비스들이 배포될 수 있습니다. 그리고 Amazon SageMaker는 기계 학습 모델을 학습하고 배포하여 이미지를 추론하는데 사용할 수 있도록 합니다. 또한, AWS CodePipeline는 코드를 컨테이너로 빌드하고 배포하는 과정을 자동화하고 Amazon SageMaker Pipelines를 이용해서 모델을 학습하고 배포하는 과정을 자동화합니다. 이를 통해서 소프트웨어의 품질 개선과 출시 주기를 단축하여 운영의 효율성을 가져갈 수 있습니다.
![architecture-4](https://private-user-images.githubusercontent.com/1788481/245367596-6a07e849-c30c-4162-85b4-40222992dc73.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0NTM2NzU5Ni02YTA3ZTg0OS1jMzBjLTQxNjItODViNC00MDIyMjk5MmRjNzMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MTI3YmQ5NzBkNjE4MThhNDkxYWRiOTBiMzA5YWY4NzgwZTFhMmRhZTRkOGU0Mzk4OGJlY2Y0NzhkOWU2NWE4MyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.mCwwzkpJX1JXUHcB6QobzxJAcCD1rXUwu0e3v0uzCxo)
Amazon ECS는 AWS Fargate를 사용해서 Web Service와 WAS(Web Application Server) Service로 구성된 애플리케이션을 운영합니다. 그리고 Amazon SageMaker는 모델을 학습하고 학습된 모델을 Amazon SageMaker Endpoint를 통해 API 형태로 WAS 에 제공합니다. NAT gateway는 네트워크 주소 변환 서비스로 Private Subnet 에 위치한 WAS Service 가 외부의 서비스와 연결이 필요한 경우 사용됩니다. 하지만 외부 서비스에서는 WAS Service 에 연결을 시작할 수 없어 보안을 강화할 수 있습니다. Application Load Balancer는 Service에서 운영되고 있는 복제된 여러 개의 Task에 트래픽을 분산합니다. Task는 한 개 이상의 컨테이너를 정의할 수 있습니다. 이번 아키텍처에서는 Task 에 하나의 컨테이너를 정의하여 운영합니다. 본 시스템에서 사용자는 Web Service에서 제공하는 UI를 통해 AI 웹 애플리케이션에 접근합니다. Web Service는 비즈니스 로직을 수행을 위해서 WAS Service를 호출하고 WAS Service는 이미지 분류와 같은 AI 기능을 수행하기 위해서 Amazon SageMaker Endpoint를 호출합니다.
코드의 통합과 배포를 자동화할 수 있는 CI/CD 서비스를 제공합니다. 애플리케이션 개발자는 AWS CodePipeline를 통해서 빠르고 안정적으로 애플리케이션을 빌드하고 Amazon ECS로 구성된 인프라 배포하는 과정을 자동화합니다. 먼저 AWS CodeCommit을 통해서 개발 중인 코드를 형상 관리 할 수 있습니다. 그리고 코드는 특정 브랜치에 업데이트 되거나 머지되어 변경 사항이 생기면 AWS CodeBuild를 통해서 컨테이너 이미지를 빌드하고 ECR 에 업로드됩니다. 이후 AWS CodeDeploy를 통해서 ECS 환경에 배포합니다.
기계 학습 Model을 학습하고 배포할 수 있는 CI/CD 서비스를 제공합니다. 모델 엔지니어는 AWS SageMaker Pipeline을 통해서 학습과 배포를 자동화하고 워크플로를 시각화하고 관리할 수 있습니다. 본 글에서는 학습, 모델 등록 그리고 배포 구성되어 있습니다. 학습을 시작하면 Amazon S3에서 학습 데이터를 다운로드하고 학습을 시작합니다. 학습이 완료된 모델은 다음 스텝에서 사용할 수 있도록 S3 에 저장하고 저장된 모델을 사용할 수 있도록 등록합니다. 이후 Amazon SageMaker Endpoint로 배포되어 API를 제공합니다.
Amazon ECS는 완전 관리형 컨테이너 오케스트레이션 서비스로서 컨테이너화된 애플리케이션을 손쉽게 배포, 관리 및 확장할 수 있도록 도와줍니다. Amazon ECS 컨트롤 플레인은 나머지 AWS 환경과 긴밀하게 통합되어 클라우드에서 컨테이너 워크로드를 실행하기 위한 안전하고 사용하기 쉬운 솔루션을 제공합니다.
AWS Fargate는 Amazon EC2 인스턴스의 서버나 클러스터를 관리할 필요 없이 컨테이너를 실행하기 위해 Amazon ECS에서 사용할 수 있는 기술입니다. Fargate를 사용하면 더 이상 컨테이너를 실행하기 위해 가상 머신의 클러스터를 프로비저닝, 구성 또는 조정할 필요가 없습니다. 따라서 서버 유형을 선택하거나, 클러스터를 조정할 시점을 결정하거나, 클러스터 패킹을 최적화할 필요가 없습니다.
AWS CodePipeline 은 소프트웨어를 릴리스하는 데 필요한 단계를 모델링, 시각화 및 자동화할 수 있게 해주는 지속적 전달 서비스입니다. AWS CodePipeline을 사용하여 코드 빌드, 사전 프로덕션 환경으로의 배포, 애플리케이션 테스트 및 프로덕션으로 릴리스를 비롯한 전체 릴리스 프로세스를 모델링합니다. 그러면 AWS CodePipeline이 정의된 워크플로우에 따라 코드 변경이 있을 때마다 애플리케이션을 빌드, 테스트, 배포합니다. 파트너 도구 및 자체 사용자 지정 도구를 릴리스 프로세스 중 원하는 단계에 통합하여 포괄적이며 지속적 전달 솔루션을 형성할 수 있습니다.
Amazon SageMaker는 종합 관리형 기계 학습 서비스입니다. Amazon SageMaker를 통해 데이터 사이언티스트와 개발자들은 기계 학습 모델을 빠르고 쉽게 구축하고 훈련할 수 있습니다. 그리고 이들 모델을 프로덕션 지원 호스팅 환경에 직접 배포할 수 있습니다. 탐색 및 분석에 필요한 내장형 Jupyter 작성 노트북 인스턴스를 제공하기 때문에 서버를 관리할 필요가 없습니다. 또한 대규모 데이터를 효율적으로 실행하는 데 최적화된 일반 기계 학습 알고리즘도 제공합니다.
Amazon SageMaker Pipelines를 사용하면 데이터 준비에서 모델 배포에 이르기까지 완전히 자동화된 ML 워크플로를 생성할 수 있으므로 프로덕션에서 수천 개의 ML 모델로 확장할 수 있습니다. SageMaker Pipelines는 Amazon SageMaker Studio에 연결되는 Python SDK도 함께 제공하므로, 시각적 인터페이스를 활용하여 워크플로의 각 단계를 구축할 수 있습니다. 그런 다음, 단일 API를 사용하여 각 단계를 연결하고 포괄적인 워크플로를 생성할 수 있습니다.
다음부터 진행되는 내용 중 'VPC 생성', 'Amazon ECS 클러스터 구성', 'AWS Fargate 기반 Web Service 구성' 그리고 'AWS Fargate 기반 WAS Service 구성'은 CDK를 이용해서도 편하게 구성하실 수 있습니다. CDK 사용을 원하신다면 CDK를 이용한 인프라 설치를 참고 부탁드립니다.
AWS가 전 세계에서 데이터 센터를 클러스터링하는 물리적 위치를 리전이라고 합니다. 이번 블로그에서는 Seoul (ap-northeast-2) 리전에서 진행합니다. 그리고 각 리전은 가용 영역(Availability Zone)이라고 알려진 격리된 위치를 여러 개 가지고 있는데 한 가용 영역에서 장애가 발생하더라도 다른 가용 영역에서 서비스를 운영할 수 있도록 2개의 가용 영역으로 구성합니다. 구성을 위해서 VPC 콘솔로 이동 후 Create VPC 버튼을 눌러서 VPC 생성을 시작합니다.
Resources to create으로 VPC and more를 선택합니다. 2개의 AZ를 구성할 예정이기 때문에 Number of Availability Zones (AZs) 값으로 2를 선택합니다. 그리고 Number of public subnets 은 2, Number of private subnets는 2를 선택합니다. 전체 구성은 아래와 같습니다.
구성을 완료한 다음에 Create VPC 버튼을 누르고 기다리면 VPC와 Subnet이 생성된 것을 확인할 수 있습니다.
Amazon ECS(Elastic Container Service) 콘솔로 이동 후 왼쪽 메뉴에서 Clusters를 선택하고 Create Cluster 버튼을 눌러서 클러스터를 생성을 시작합니다.
![1](https://private-user-images.githubusercontent.com/1788481/239425240-28445be5-3374-43f4-b611-72b928a5e5c2.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzIzOTQyNTI0MC0yODQ0NWJlNS0zMzc0LTQzZjQtYjYxMS03MmI5MjhhNWU1YzIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MWIyYjMyMDEyYzQzYTViYzZjNDY4ZTU5NTJkZTQ5YTA5ZWQwMTliNTNhOTBiZTI1MWU5ODllZGM0NzBiOTI4MCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.ZCqxJ1geew0p3ktb8iTstg7XDXopcMOuTuH4LhPQVjI)
클러스터는 아래 그림과 같이 구성합니다. 이름은 AppEcsCluster로 입력합니다. 그리고 Multi Available Zone 에 클러스터를 구성하기 때문에 각 Available Zone 에 위치한 Private Subnet을 각각 선택합니다. 또한 AWS Fargate를 사용하기 때문에 Infrastructure에서 AWS Fargate (serverless)를 선택합니다.
![2](https://private-user-images.githubusercontent.com/1788481/239425247-c16d52f1-9f8e-40aa-88aa-fb4f19ebaa45.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzIzOTQyNTI0Ny1jMTZkNTJmMS05ZjhlLTQwYWEtODhhYS1mYjRmMTllYmFhNDUucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZjM0YzEyNWJiZjUzOWNlYTlhYTNhMzBjZGI5YTBiMTdhZTM3NWVhYzRhY2RlNWM0OGU0MmQxMDBiODc4NjcyYyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.oARYeI9lnxZqHFYnbR9wSp9VhILY2NWhPEMF6fnFDKI)
![3](https://private-user-images.githubusercontent.com/1788481/241763348-46bbb48d-59de-43a9-8540-aeeea82e75c1.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MTc2MzM0OC00NmJiYjQ4ZC01OWRlLTQzYTktODU0MC1hZWVlYTgyZTc1YzEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ODMxZmY4MjhjODY5MTgzMjBjMTVjZjYwM2Q2MGNhNzg5MjZiNWMwNDkwY2NhOTQyMDJhZTM0MWNlOGViNmYzNSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.EdM7Xib1Qiuy78AHd6ASzMpxifIABWgCmqi_4nXkVIg)
![4](https://private-user-images.githubusercontent.com/1788481/239425255-e598504f-85ab-447c-8df2-4319226701e4.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzIzOTQyNTI1NS1lNTk4NTA0Zi04NWFiLTQ0N2MtOGRmMi00MzE5MjI2NzAxZTQucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZmViMTA2Mjk4NTYxNmRmZDAzOGRlMzQyYmM2NDkzY2FkNWMyMDllYWE1MjRmYjNiYWMxZGQ0Y2QwZTdlZTNlNCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.lmTVhtwIgWgKBco8p05egTu7JnANF1VWzW3dAUq0k_E)
구성을 완료한 다음에 Create 버튼을 누르고 기다리면 Amazon ECS 클러스터가 생성된 것을 확인할 수 있습니다.
![5](https://private-user-images.githubusercontent.com/1788481/239425506-a18254a4-362e-488a-84f2-b6bf7f6bafd3.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzIzOTQyNTUwNi1hMTgyNTRhNC0zNjJlLTQ4OGEtODRmMi1iNmJmN2Y2YmFmZDMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MTgwNDQ4ZTE0ZTEyNzg4NjRiOWVlOWI5NWQ2ZDYyZDAxNjc5ZDM4N2E3Y2MxYjM3M2VhMzVmZTcxZTc0OTgxMiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.QMx-ydLtG_nxzTRUBG5jiYK-uent318EGScuVsFcduM)
다음 명령어를 수행하여 애플리케이션 구성에 필요한 코드를 다운로드합니다.
git clone https://github.com/hijigoo/ecs-fargate-sagemaker-based-webservice
AWS Fargate 기반 Web 서비스를 구성하기 위해서 여러 단계를 거칩니다. 먼저 다운로드한 프로젝트에서 Web Application을 Docker로 빌드합니다. 그리고 빌드한 이미지를 Amazon ECR 에 등록하여 AWS ECS Service 에 배포할 준비를 합니다. 다음으로 Web 서비스와 로드 밸런서에 적용할 Security Group을 생성하고 로드 밸런서를 생성합니다. 마지막으로 Web 서비스 구성을 위한 태스크 정의를 하고 Web 서비스를 생성합니다.
다운로드한 프로젝트에서 Web Application을 빌드합니다. 콘솔이나 터미널에서 /web 폴더로 이동 후 다음 명령어로 Docker 빌드를 진행합니다.
docker build -t app-web .
Mac M1, M2 환경에서는 기본 linux/arm64로 빌드되기 때문에 다음 명령어로 Docker 빌드를 수행합니다.
docker buildx build --platform=linux/amd64 -t app-web .
Docker 이미지가 빌드되었는지 확인합니다.
docker images
Amazon ECR(Elastic Container Registry) 콘솔로 이동 후 왼쪽 메뉴에서 Repositories를 선택합니다. 그리고 Private 탭에서 Create repository 버튼을 눌러서 레파지토리 생성을 시작합니다.
![1](https://private-user-images.githubusercontent.com/1788481/241572967-d3b7c698-c72e-4a00-92b8-3d1f093671ef.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MTU3Mjk2Ny1kM2I3YzY5OC1jNzJlLTRhMDAtOTJiOC0zZDFmMDkzNjcxZWYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YWM5N2YzYWQwNGIwOThkMDE0ZDcxYmU2MjlhZTU0NTJiMDMyNWEzMmZmZDJlNmM2MDBkNTlmOTdkY2I0MDJiZCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.ZKHLiTfmZiTeKIa6ahw1XIhY7mWhfeuc0R6CUsckgIU)
레파지토리는 다음 그림과 같이 구성합니다. 이름은 app-web으로 입력하고 나머지는 그대로 둡니다.
![2](https://private-user-images.githubusercontent.com/1788481/241572973-c11ff57f-b3c8-455c-bef3-976548fe968b.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MTU3Mjk3My1jMTFmZjU3Zi1iM2M4LTQ1NWMtYmVmMy05NzY1NDhmZTk2OGIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NGZlZmIzNWRkMTYxNjE3Zjk4ZjY3OWIxZDYzNjA5NzAwY2M5OGQ1MWVmNTkyMzVjOGUzMzE5MjJkZTk0NjQyZSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.0SnAtsOTf9DJpV4SKk9LPOEqxLk-3YcfxS0lUD9DkQY)
구성을 완료한 다음에 맨 아래에 있는 Create 버튼을 누르고 기다리면 레파지토리가 생성된 것을 확인할 수 있습니다.
![3](https://private-user-images.githubusercontent.com/1788481/241572974-9e7e97fd-7f1d-4b70-ba4c-e7d26b136931.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MTU3Mjk3NC05ZTdlOTdmZC03ZjFkLTRiNzAtYmE0Yy1lN2QyNmIxMzY5MzEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MDA3NDQ0ZmVlN2U4MTI1YzY2Y2RkMGZhN2Q1ZmE0NjZmNDFiYWI2Njc3OTAwMjc3MzA3YTZkZDE4MjBlNGVjNCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.ezhd_-3sS-dk1gcP8zT17ZejPEYxgJaM7vMc913ExuE)
다음으로 생성한 레파지토리의 app-web 링크를 눌러서 이동합니다. 그리고 오른쪽의 View push commands 버튼을 눌러서 계정을 인증하고 빌드한 이미지를 생성한 레파지토리에 푸시합니다. 앞에서 이미지를 이미 빌드한 경우에 빌드 명령어는 제외해도 괜찮습니다.
![4](https://private-user-images.githubusercontent.com/1788481/241574124-00b58583-7101-4d60-bc39-8f00fe9208a6.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MTU3NDEyNC0wMGI1ODU4My03MTAxLTRkNjAtYmMzOS04ZjAwZmU5MjA4YTYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MTZlMzU3MjY0MWVkOThhNDUyZDBlY2Y5ZGViZDlhMGRhZjU0MTg2MWE4MTQxOWQ0MmQwMmE0ODM0NmRkMTEyZCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.ZIdO-RmWnKAEXyedz3OM67J_oVoSN2KFQJyr-E2nRsU)
이미지 푸시를 완료하면 다음과 같이 등록된 것을 확인할 수 있습니다.
![5](https://private-user-images.githubusercontent.com/1788481/241576459-2c162950-c223-4a20-88f6-ca65d2b0187e.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MTU3NjQ1OS0yYzE2Mjk1MC1jMjIzLTRhMjAtODhmNi1jYTY1ZDJiMDE4N2UucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NzIxZDkyODIwZDg4YzFkOTM0MzY3M2Q2Nzg5YzhiYzQ1ZGMyYWQ0ZTc2ZGRmN2I0ZDM1MDlkY2YyMDAxNmYxYSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.03VPGu4rYoO3pqs9NtE1FWZxVSZtr27sgkZmqg2IA_U)
AWS ECS에서 구동되는 Web 서비스에 적용할 보안 그룹과 서비스 앞에서 트래픽을 분산할 로드 배런서에 적용할 보안 그룹을 생성합니다. 먼저 로드 밸런서에 적용할 보안 그룹을 생성합니다. EC2 콘솔로 이동 후 왼쪽 메뉴에서 Security Groups를 선택합니다. 그리고 Create security group 버튼을 눌러서 보안 그룹 생성을 시작합니다. Security group name은 app-web-alb-sg로 지정합니다. VPC는 처음 생성한 app-vpc를 선택합니다. 외부와 HTTP 통신을 위해서 80 포트를 인바운드 값으로 허용하고 Source로 Anywhere를 선택합니다. 구성을 완료한 다음에 Create security group 버튼을 눌러서 보안 그룹을 생성합니다.
![1](https://private-user-images.githubusercontent.com/1788481/241872125-6a3f5456-5b5c-4d83-83e7-a05370ee7978.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MTg3MjEyNS02YTNmNTQ1Ni01YjVjLTRkODMtODNlNy1hMDUzNzBlZTc5NzgucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MWFlOWVjNzQzZjZlY2YxYWQ2ZjFjYmY5MTE4NGRmYWNkZDg1NzlkMmY4NDE5MWIwY2IzMDM0ZjA0Y2IwYzkzZCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.rJGJDd2IdxYBiwWzrpF-B30nRhW-61GP5CXcF6FtR54)
다음으로 ECS 서비스에 적용할 보안 그룹을 생성합니다. Security group name 은 app-web-sg로 지정합니다. VPC는 처음 생성한 app-vpc를 선택합니다. 8000 포트 트래픽을 인바운드 값으로 허용하고 Source로 방금 생성한 app-web-alb-sg를 선택합니다. 구성을 완료한 다음에 Create security group 버튼을 눌러서 보안 그룹을 생성합니다.
![2](https://private-user-images.githubusercontent.com/1788481/241918904-9a189f8b-0b60-410b-b27d-8710eed86fd0.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MTkxODkwNC05YTE4OWY4Yi0wYjYwLTQxMGItYjI3ZC04NzEwZWVkODZmZDAucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MmM5ZGVmMGQ4N2RiYTJiM2FlNjg0MjJjZjM0Y2QxYjM2N2I4ZjUxNGMzZTMwNmIxMzRmOWYxYTUxZDdlNGYwYiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.eUBDmnrAV4x0oTLkwsMoS2HQ-ndWUXkwkA6pMeW3VKE)
기다리면 다음과 같이 두 개의 보안 그룹이 생성된 것을 확인할 수 있습니다. 보기 편하게 Name 값을 Security Group Name 과 동일하게 변경합니다.
![3](https://private-user-images.githubusercontent.com/1788481/241919719-6694397b-d770-461e-ac4e-893c481a30b1.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MTkxOTcxOS02Njk0Mzk3Yi1kNzcwLTQ2MWUtYWM0ZS04OTNjNDgxYTMwYjEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MjE0MTM2YmJkOTY3NjdhODQxOGQxODQ4ODAyODZkOWNlNDkxMGRjMzdiMWRkNzEzN2ViMDIwYzA2NGI4Yjc3YSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.00Dc8IWcqP1qd84ItTA3ci-u6wFOBzFIDA9lBCeKLSQ)
AWS ECS의 Web 서비스 구성에 사용할 로드 밸런서를 생성합니다. EC2 콘솔로 이동 후 왼쪽 메뉴에서 Load balancers를 선택합니다. 그리고 Create load balancer 버튼을 눌러서 로드 밸런서 구성을 시작합니다. Application Load Balancer의 Create 버튼을 눌러서 생성을 시작합니다.
![1](https://private-user-images.githubusercontent.com/1788481/242352051-af78d083-6afb-420a-92f3-32a6f6206457.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1MjA1MS1hZjc4ZDA4My02YWZiLTQyMGEtOTJmMy0zMmE2ZjYyMDY0NTcucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NWIxYzBkODljN2JlOTU3NWE0ZGJlN2FkYzQ3OGYwZmQwMDk1YzI1NjhiNDdhMTQ1MzI2MTIwYWU5ODI0MjQxNCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.rODJf_UuySEpR6A_Gbt3ww_A8bZHpop2Oqv-XUxaL10)
Load balancer name는 app-web-alb를 입력하고 Scheme 은 Internet-facing을 선택합니다. Networking 구성에서 VPC는 생성해 둔 app-vpc를 선택하고 Subnets에는 public subnets 두 개를 선택합니다. 그리고 Security groups에는 미리 생성해 둔 app-web-alb-sg를 선택합니다.
![2](https://private-user-images.githubusercontent.com/1788481/242352076-f0ddfd81-b722-483e-a1a7-dd71e0adc4e1.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1MjA3Ni1mMGRkZmQ4MS1iNzIyLTQ4M2UtYTFhNy1kZDcxZTBhZGM0ZTEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ODVmMzdlYjc4ZjMxZDhmNjUzNjdiYWUxMDI4Mzg1NDcyZDQzY2FlYmEyNTlhNzgyYzNhZTJiY2M5YjcyZWE5YyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.iua0swIpeFxJRbWBaRn0zquSq-tdOyODMiyKslag4kM)
![3](https://private-user-images.githubusercontent.com/1788481/242352084-258d0d78-2a1d-4f40-abfa-a502e5e37231.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1MjA4NC0yNThkMGQ3OC0yYTFkLTRmNDAtYWJmYS1hNTAyZTVlMzcyMzEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MGM3MzcyYWU4OTZhYzYyYzA2MmZmNTk3OWNlZTMwMjYwMmFmNWVkOTE3YmQzOTA4ODNhYzM2NGE2Yjk2ZWQ3MiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.LIUHGHEKbJuqTqduLYeY9LcjXeNcPl9lFHNE3YN1aaQ)
![4](https://private-user-images.githubusercontent.com/1788481/242352088-eb7bafa5-6508-4fdb-a29b-e028c4474c9f.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1MjA4OC1lYjdiYWZhNS02NTA4LTRmZGItYTI5Yi1lMDI4YzQ0NzRjOWYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MjY5ZGE0ZDdhMDc1MDMyMmJmZTUxYThiNTdmMDEyNTA1NDM2ZDhjMDhmMzMxMWI1NGUwYmZjNDI5Nzk5ZGE5MiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.-xMuIi73zYXxh0Kvf4O64Gc5fs19TdxJytkF22BQNGg)
Listeners and routing에서 Create target group 버튼을 눌러서 신규 타겟 그룹의 구성을 시작합니다. Choose a target type는 IP addresses를 선택하고 Target group name 값으로 app-web-alb-tg를 입력하고 Port는 8000을 입력합니다. VPC는 app-vpc를 선택합니다. 그리고 Health check path 값으로 /health를 입력합니다. Next 버튼을 눌러서 다음 단계를 넘어간 뒤 Create target group 버튼을 눌러서 타겟 그룹을 생성을 완료합니다.
![5](https://private-user-images.githubusercontent.com/1788481/242352092-7aa1ce60-8388-4302-852c-1fb635fbb0fa.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1MjA5Mi03YWExY2U2MC04Mzg4LTQzMDItODUyYy0xZmI2MzVmYmIwZmEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MmJlY2YwMTAwZGIyMjI2YjQxMjIwNzVlNjQ1YTQ0MDRjYzIwZDg1OGI1OGJkNTNkNTg5YjViZWU2NWQ1MGJkYyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.Jrl6P8gSyg5FdLxr0H9r5WkgOHds_0OEz5_jMabdyug)
![6](https://private-user-images.githubusercontent.com/1788481/242383099-6801ec6a-818b-4281-b4fc-889a22568fe4.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM4MzA5OS02ODAxZWM2YS04MThiLTQyODEtYjRmYy04ODlhMjI1NjhmZTQucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MDBjNTFjNzExZjkwN2U4MTMzZGY1OTFiMmJlM2JiZTc5MmUxMzU3YzVjODc4ZmE1YjU1OWRiYWU2YTUwM2FhYyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.iYMmQaqidFZBi-9k5IjkMB7JjP0ncXx2ruNHnK5JbKU)
![7](https://private-user-images.githubusercontent.com/1788481/242352101-f46520a7-41cd-4ef0-9843-741487c0406f.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1MjEwMS1mNDY1MjBhNy00MWNkLTRlZjAtOTg0My03NDE0ODdjMDQwNmYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YjVmY2I5MDJjNDg4Njg0ZWIzNzM4ODEyZmQyYWFkNTI2YjA3NTI4ZDFkYzVkMWRmYzdiZWFiMWJkZTVhMDRmMyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.fnHmp6eR7K5JiGRw6p5SzLzqz1y828dJqJ5DeDdt_fg)
![9](https://private-user-images.githubusercontent.com/1788481/242352103-05ef5fae-ff64-420e-9bf1-b4ff12a4b771.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1MjEwMy0wNWVmNWZhZS1mZjY0LTQyMGUtOWJmMS1iNGZmMTJhNGI3NzEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MTM1ZTRmOThlZTkxNzJkNzAxMDhkYzY2M2YzZDBjZGY1MzBlMTk1ZDA4ZGJmNjQ4NTQxZWM0NWIyNTFmOWU5OCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.W8ueMGMVEJ_w5ZOw1IIjXVCD66fIR23aYwW8UI5LyvI)
Create load balancer 버튼을 눌러서 로드 밸런서 생성을 완료합니다.
![10](https://private-user-images.githubusercontent.com/1788481/242352106-1b0fda5e-c3e8-4995-92ee-713ce87e2619.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1MjEwNi0xYjBmZGE1ZS1jM2U4LTQ5OTUtOTJlZS03MTNjZTg3ZTI2MTkucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZGRjODVlMGUyMWJhZmRjOGNkYTVmYWNlZDI0ZjRlYjYyNTM3ZTExNTQ0YWU4Yzc0NjJjNmFjMGQ2ZmVjOGJiNyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.JZ1Sne5i1WRX2Rr54oCWjIvyDkrdL7hst68k6NoE3BU)
Amazon ECS에서 Docker 컨테이너를 실행하기 위해서 태스크를 정의합니다. 하나의 태스크에서 한 개 이상의 컨테이너를 정의할 수 있습니다. 즉 서비스를 실행하기 위한 최소 단위라고 생각할 수 있습니다. Amazon ECS 콘솔로 이동 후 왼쪽 메뉴에서 Task definition을 열고 Create new task definition 버튼을 눌러서 태스크 정의를 시작합니다.
![1](https://private-user-images.githubusercontent.com/1788481/241712540-a90b05e1-bb2a-4a19-8592-d75a526fe276.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MTcxMjU0MC1hOTBiMDVlMS1iYjJhLTRhMTktODU5Mi1kNzVhNTI2ZmUyNzYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZjMyNDM0Y2NkYmVkOGZhZTI2YWNjOTMxNWUwOTZmZTY2YjkwMzk4ZDM3ZGRmZDEyZDEyNTJlZDA3YTBmYmRlNSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.13rV2353jcvHPTRctfr0NU3wwLcT1dn2y6beEmTUg2s)
태스크 정의는 다음 그림과 같이 구성합니다. Task definition family는 app-web-td로 지정합니다. 그리고 태스크를 구성할 컨테이너 정보를 입력합니다. Name 은 app-web으로 지정하고 Image URI는 ECR 콘솔에서 앞 단계에서 푸시한 이미지 URI를 찾아서 입력합니다. 포트는 8000으로 입력합니다. Next 버튼을 눌러서 다음으로 진행합니다.
모두 기본값으로 남기고 다시 Next 버튼을 눌러서 다음 진행 단계로 넘어갑니다. 구성을 확인하고 맨 아래에 있는 Create 버튼을 누르고 기다리면 태스크 정의가 생성된 것을 확인할 수 있습니다.
![3](https://private-user-images.githubusercontent.com/1788481/242002259-c32dd2c0-ec4c-4702-928a-7212677a7178.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjAwMjI1OS1jMzJkZDJjMC1lYzRjLTQ3MDItOTI4YS03MjEyNjc3YTcxNzgucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZmQyYzJhNTA3NmFkNzVmNWNkYzY5NGFiYjY2NmMzYTUxNTM2YzU5OTBlZmVmY2M0MmEyYTYyMGU5NmEzM2M3ZCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.BaYFORJ2x-F8P5dIHbXH7MEhgl8pRtcs_-iftkCf-js)
AWS ECS에서 구동되는 Web 서비스 구성을 위해서 AWS ECS 클러스터 콘솔로 이동합니다. 처음에 생성한 AppEcsCluster 링크를 클릭해서 들어간 뒤, Services 탭에서 Create 버튼을 눌러 서비스 구성을 시작합니다.
![1](https://private-user-images.githubusercontent.com/1788481/241870066-f2d9d52f-c540-400e-802f-ba540d3cee29.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MTg3MDA2Ni1mMmQ5ZDUyZi1jNTQwLTQwMGUtODAyZi1iYTU0MGQzY2VlMjkucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZTVjNmQ0OGM1ZTQxNmFhY2E1OGZjOWNiZjExMDI2M2ZhNjhjODM3M2FiYjI5MjY4NTIxOTI4NjVkZjlkOWM3MSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ._n-mZLWRNmdsgcwglCBlsjEg_k8JYhK0FfUr-BNoA-4)
Environment는 다음과 같이 구성합니다. Compute options으로 Launch Type을 선택하고, Application type으로 Service를 선택합니다. 그리고 family 값으로 앞서 생성한 task definition 인 app-web-td을 선택합니다. Service Name으로는 app-web-service를 입력합니다. Desired tasks 값으로 2를 입력합니다.
![2](https://private-user-images.githubusercontent.com/1788481/241870068-879595fb-e543-40dc-9817-28512fde554b.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MTg3MDA2OC04Nzk1OTVmYi1lNTQzLTQwZGMtOTgxNy0yODUxMmZkZTU1NGIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NjhiZDk4NTI2MWU2ODBkZjE5MWIxOThkZDE4NmRmMzEzZDFhYTA4MGZjM2NiOTc0MTM5NTgzNjg0YWQxNmY2YSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.03W-6nwMd0HDD3S3dUV159zN8DWr7L3J7ZPswUhPQ_0)
![3](https://private-user-images.githubusercontent.com/1788481/242003929-ed0509fa-d887-4ecd-9457-a3dfed5a04bd.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjAwMzkyOS1lZDA1MDlmYS1kODg3LTRlY2QtOTQ1Ny1hM2RmZWQ1YTA0YmQucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YWMxOTE1MDU4OTQxNjRiN2Y5NWI0MWQ2MDU2MjAxZjZlZWIyNGZlZTEwYmU4NzEwN2E0NGMzYjM3MmZkZmI5NSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.gJESpFn-AwSaRf3xfrdgtXus2uyeNa1Z2Cfo67B4bwU)
Networking 구성에서 VPC는 생성해 둔 app-vpc를 선택하고 Subnets에는 private subnets 두 개를 선택합니다. 그리고 Security group에는 미리 생성해 둔 app-web-sg를 적용합니다. 그리고 로드 밸런서를 통해 접근할 예정이기 때문에 Public IP는 disable 해놓습니다.
![4](https://private-user-images.githubusercontent.com/1788481/242005479-daf8cbce-ec3b-4ea9-8932-edd587f0c333.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjAwNTQ3OS1kYWY4Y2JjZS1lYzNiLTRlYTktODkzMi1lZGQ1ODdmMGMzMzMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YTlmMGI0Yjc3NDA5MmRjNDJiZGMzZDNiN2RmYWIzYTFkOTc3OTRlNjdlY2UyNmQ4NWM4YWRhODYzYmVkNDk1MSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.S-Cfx8faBzwzl5EsskG4OK_cot-pKiGwI53K5i9_SWc)
Load Balancing 구성에서 Load balancer type으로 Application Load Balancer를 선택합니다. Use an existing load balancer를 선택하고 Load balancer로 app-web-alb를 선택합니다. Use an existing target group을 선택하고 app-web-alb-tg를 선택합니다.
![alb2-1](https://private-user-images.githubusercontent.com/1788481/242352369-2e263fd0-e5ab-4602-982f-4fc5364b397a.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1MjM2OS0yZTI2M2ZkMC1lNWFiLTQ2MDItOTgyZi00ZmM1MzY0YjM5N2EucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZDcwNmNiZDlmNWI0ZmU5OGU1ZTdiYzQ4NjhhOGRmZWVjZmViNzE2YjAxYTBlZGVlZjdhYjJhODVlMDY5NGUxYSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.6g7RxBH10kx2dmh0KgDccnobkrPoEO5JNcjU2n33O9A)
![alb2-2](https://private-user-images.githubusercontent.com/1788481/242352379-45af48c9-a0c3-45e3-8a86-8dd8bab71630.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1MjM3OS00NWFmNDhjOS1hMGMzLTQ1ZTMtOGE4Ni04ZGQ4YmFiNzE2MzAucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZTllNGZjMzExNWNkMWJjYTExYWRhYWM5NWRkOGMyYzA4ZjBiYmU0Y2U4MmMwMDFlMDE3MDA5NTBiZWEzN2Y4MCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.vfEK8cpN90v5zR6JAm-PeoETBcBgC104pjs9P8_xTAo)
Service auto scaling 구성에서 Use service auto scaling를 체크합니다. Minimum number of tasks 값으로 2를 입력하고 Maximum number of tasks 값으로 4를 입력합니다. Policy name 값으로 app-web-asg-policy을 입력합니다. ECS service metric으로 ECSServiceMetricAverageCPUUtilization을 선택하고 Target value로 70을 입력합니다. Scale-out cooldown period 과 Scale-in cooldown period 모두 300으로 입력합니다. 모든 구성을 완료한 다음에 Create 버튼을 눌러서 서비스를 생성합니다.
![7-asg](https://private-user-images.githubusercontent.com/1788481/242010661-6422f76d-bc8d-4016-8c66-12a10b537f17.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjAxMDY2MS02NDIyZjc2ZC1iYzhkLTQwMTYtOGM2Ni0xMmExMGI1MzdmMTcucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NzcxMDk1YzNlODY2YmMwNTJhOTZmYjMxODVkYWQyYWMzNmNkNGVlNzk2MDQyNmYwODA3ZGVjMWQ1ODI5MGI2MiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.PVc7xf3tX7mX9cPnj70NpXb8oDJwiK3DiqIT1ekNukg)
![8-asg](https://private-user-images.githubusercontent.com/1788481/242010667-2e2428d0-bb8c-4620-b147-113bd231777a.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjAxMDY2Ny0yZTI0MjhkMC1iYjhjLTQ2MjAtYjE0Ny0xMTNiZDIzMTc3N2EucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NDJkZGNiZjY1MDZiZmMwZTFmYzUyNDNhYTQ3MWY1MDA1ZGJmMzhmYTk0ZTRjZGM2NzQ0ZmIwYzE0YjIxMGU1MiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.nW5nW_Q5DaKqduaoESy4vkNqOTFJV9jMDoTIfDDX2dQ)
Services 탭에서 app-web-service를 선택하고 Tasks 탭에 선택해서 들어가면 다음과 같이 태스크가 구동되는 것을 확인할 수 있습니다.
![9](https://private-user-images.githubusercontent.com/1788481/242285073-7c2d73b1-2548-43af-a998-2e208a369478.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjI4NTA3My03YzJkNzNiMS0yNTQ4LTQzYWYtYTk5OC0yZTIwOGEzNjk0NzgucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ODU2OTk0ZjhjOWQyODRjNTJjZGNiMzcyMDMwMTVjM2MwZDAxYTc5MGUzODU0ODE3NDM0NGRiNjc4MzFmZjljOCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.Rncy0rkUFIssoyDNZIhnYlfAq-elPmq0zZm4N5bEpbA)
앞서 생성한 로드 밸런서인 app-web-alb 에 들어가서 DNS name을 복사합니다. 복사한 URL을 통해서 접속할 수 있는지 웹 브라우저에서 확인합니다.
![alb-11](https://private-user-images.githubusercontent.com/1788481/243182876-8a8786c8-d967-4f75-b458-0f1681af7ea0.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MzE4Mjg3Ni04YTg3ODZjOC1kOTY3LTRmNzUtYjQ1OC0wZjE2ODFhZjdlYTAucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NGQ5NGQ4NmMxZTZkZTgwNmMxYTE2OGQ5OWViNjE2OGY4NTY5ODU3OTc2YmJmOGFlYzlhOGQ0NWJhN2I5NTZlYyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.HsrIPKNuYonm5Irtff8qRkJzVNXStFuW3RNce12tass)
이번 단계는 AWS Fargate 기반 WAS Service 구성과 비슷한 흐름으로 진행되지만 다른 부분이 있기 때문에 주의해서 보시기 바랍니다. Web Service를 구성했던 것과 마찬가지로 AWS Fargate 기반 WAS 서비스를 구성하기 위해서 여러 단계를 거칩니다. 먼저 다운로드한 프로젝트에서 WAS Application을 Docker로 빌드합니다. 그리고 빌드한 이미지를 Amazon ECR 에 등록하여 AWS ECS Service에 배포할 준비를 합니다. 다음으로 Web 서비스와 로드 밸런서에 적용할 Security Group을 생성하고 로드 밸런서를 생성합니다. 마지막으로 WAS 서비스 구성을 위한 태스크 정의를 하고 WAS 서비스를 생성합니다.
이미지 분류를 위해서 학습한 모델이 배포된 Amazon SageMaker Endpoint 에 접근합니다. 접근을 위해서는 AWS SDK 인 boto3를 사용합니다. boto3를 사용하면 내부적으로 자격증명(Credentials)을 확인하기 때문에 편하게 접근할 수 있습니다. 다음 코드는 Amazon SageMaker Endpoint를 호출하는 코드 블록입니다. was/app/main.py에서 확인할 수 있습니다.
client = boto3.client("sagemaker-runtime")
endpoint_name = 'image-classifier'
response = client.invoke_endpoint(
EndpointName=endpoint_name,
Body=body,
ContentType='application/json',
Accept='Accept'
)
다운로드한 프로젝트에서 WAS Application을 빌드합니다. 콘솔이나 터미널에서 /was 폴더로 이동 후 다음 명령어로 Docker 빌드를 진행합니다.
docker build -t app-was .
Mac M1, M2 환경에서는 기본 linux/arm64로 빌드되기 때문에 다음 명령어로 Docker 빌드를 수행합니다.
docker buildx build --platform=linux/amd64 -t app-was .
Docker 이미지가 빌드되었는지 확인합니다.
docker images
Amazon ECR(Elastic Container Registry) 콘솔로 이동 후 왼쪽 메뉴에서 Repositories를 선택합니다. 기존에 등록한 app-web 레파지토리가 있는 것을 볼 수 있습니다. 우리는 WAS Application 레파지토리가 추가로 필요하기 때문에 Private 탭에서 Create repository 버튼을 눌러서 레지스트리를 생성을 시작합니다.
![1](https://private-user-images.githubusercontent.com/1788481/242164250-2403522d-e9e3-4802-a9bd-f52909f3e327.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjE2NDI1MC0yNDAzNTIyZC1lOWUzLTQ4MDItYTliZC1mNTI5MDlmM2UzMjcucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZjUyODQzYjY1OGNjOWQ0ZmUwYWNiZjgzZTUwYTA0MDRmY2UyY2Q3ZTQ0ZjNiY2E4NDJjZGI2MjM2Y2UwYTI1OSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.r1tOcsK3xHa4NBq_hoN5BCry6TvwRICLb8VnUtreoMc)
레파지토리는 다음 그림과 같이 구성합니다. 이름은 app-was로 입력하고 나머지는 그대로 둡니다.
![2](https://private-user-images.githubusercontent.com/1788481/242164257-016c07a9-d8de-44f9-a3ad-7c37a7d3380e.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjE2NDI1Ny0wMTZjMDdhOS1kOGRlLTQ0ZjktYTNhZC03YzM3YTdkMzM4MGUucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YWU1YjczM2FhZjc3NTM2MzhjNWU1ODU2ODUwOTcyMmFiNjUyZjE3NDNjOWE0YzhjODViMzk2Y2NhZjAyN2VmNyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.Hc_9BnHMZiDZG37WNW68y2Oj8Q0bmzD5Gx2YZJ8Z7TY)
구성을 완료한 다음에 맨 아래에 있는 Create 버튼을 누르고 기다리면 레파지토리가 생성된 것을 확인할 수 있습니다. 현재까지 총 2개의 레파지토리가 생성되었습니다.
![3](https://private-user-images.githubusercontent.com/1788481/242164261-574d46aa-4304-4c70-8d04-68a2eb30b8da.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjE2NDI2MS01NzRkNDZhYS00MzA0LTRjNzAtOGQwNC02OGEyZWIzMGI4ZGEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9Mjg2YjE5N2U0MzRjYTdhZjI1ZDc4NTgzN2ZkMjUxYTcwMDFkZGY1Njc3ODRhNjYxOGEyYTFlOWZhYjk0NTk0OCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.wyTJqcyzyV9mxoXqppvMrc4_vanpt4weUgxDiTlnowg)
다음으로 생성한 레파지토리의 app-was 링크를 눌러서 이동합니다. 그리고 오른쪽의 View push commands 버튼을 눌러서 계정을 인증하고 빌드한 이미지를 생성한 레파지토리에 푸시합니다. 앞에서 이미지를 이미 빌드한 경우에 빌드 명령어는 제외해도 괜찮습니다.
![4](https://private-user-images.githubusercontent.com/1788481/242164264-e2609f9d-8f7e-4ed7-b973-d310872ed9e7.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjE2NDI2NC1lMjYwOWY5ZC04ZjdlLTRlZDctYjk3My1kMzEwODcyZWQ5ZTcucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NzJkYzNhZjc2MzAxZDRlZDdhYzY0NTU1NWJiMjg5MjE5Y2UzM2JmMDZkZjMyZDg3YmYxNWRkNzIyMzJlYTU3NCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.zrdVrcY_ABeyVJVzWuRGZWW0BwqMEPXHq50BTWtZbq0)
이미지 푸시를 완료하면 다음과 같이 등록된 것을 확인할 수 있습니다.
![5](https://private-user-images.githubusercontent.com/1788481/242164268-0cb17fbf-abdc-4b72-8fbf-bce70411b594.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjE2NDI2OC0wY2IxN2ZiZi1hYmRjLTRiNzItOGZiZi1iY2U3MDQxMWI1OTQucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NGQwNzUyM2MxZGNmNDExNTAyMDFmYmJhNGM1ZjUwZjhhOWIyZjNjOGQ3Zjc1NTdjNzI1NGQzMWExNGY1ZjZlOSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.emB0vmAT_L3cyoCfd6lROqMPAGDGp3w8NT4pvlLK3ws)
AWS ECS에서 구동되는 WAS 서비스에 적용할 보안 그룹과 서비스 앞에서 트래픽을 분산할 로드 배런서에 적용할 보안 그룹을 생성합니다. 먼저 로드 밸런서에 적용할 보안 그룹을 생성합니다. EC2 콘솔로 이동 후 왼쪽 메뉴에서 Security Groups를 선택합니다. 그리고 Create security group 버튼을 눌러서 보안 그룹 생성을 시작합니다. Security group name 은 app-was-alb-sg로 지정합니다. VPC는 처음 생성한 app-vpc를 선택합니다. app-web-service와 HTTP 통신을 위해서 80 포트를 인바운드 값으로 허용하고 Source로 app-web-sg을 선택합니다. 구성을 완료한 다음에 Create security group 버튼을 눌러서 보안 그룹을 생성합니다.
![1](https://private-user-images.githubusercontent.com/1788481/242275219-fad61608-a6ac-4427-9af8-c1f87ced7f23.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjI3NTIxOS1mYWQ2MTYwOC1hNmFjLTQ0MjctOWFmOC1jMWY4N2NlZDdmMjMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9OTc4ODI0ODNmYTllYWU0NjYyYWMwNTBmOGNlMmNiN2Y4MTc4Zjk3ZDg1MWI2YzZiZjI2ZjljY2ExYmVhYjZlMiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.1DuPR3B_tePsQUnM6Sl3mauwBXAyjo6P_eh-eA8Gc2Y)
다음으로 ECS 서비스에 적용할 보안 그룹을 생성합니다. Security group name 은 app-was-sg로 지정합니다. VPC는 처음 생성한 app-vpc를 선택합니다. 8081 포트 트래픽을 인바운드 값으로 허용하고 Source로 방금 생성한 app-was-alb-sg를 선택합니다. 구성을 완료한 다음에 Create security group 버튼을 눌러서 보안 그룹을 생성합니다.
![2](https://private-user-images.githubusercontent.com/1788481/242275231-0501297b-cdf6-4446-bc6b-4a0e96e19f14.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjI3NTIzMS0wNTAxMjk3Yi1jZGY2LTQ0NDYtYmM2Yi00YTBlOTZlMTlmMTQucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YWFlYTU0MjQ1ZGJmNjRhY2M1N2ZlNGE3Y2YyNDZjZDE1ZDI1MzliMWVkZWVhOTRjNzc3YmM4ZDBiYmYwYjlhMSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.ULAVLLfXQQovbK99eaKZehiTmONRgs62KYouy3B1PeE)
기다리면 다음과 같이 두 개의 보안 그룹이 추가된 것을 확인할 수 있습니다. 보기 편하게 Name 값을 Security Group Name 과 동일하게 변경합니다.
![3](https://private-user-images.githubusercontent.com/1788481/242275243-3830fb05-d680-42c1-a25c-993e742ce870.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjI3NTI0My0zODMwZmIwNS1kNjgwLTQyYzEtYTI1Yy05OTNlNzQyY2U4NzAucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YzA2YmYxNmM3YWU0MDMyYWJkMzJlMjEyNTYwNjg0YzcwZDMzNTFhNjEzODM4NGVjNzZjZTljOWEwZWJjNzg0MCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.YrIwI8iSI9gX_Rsoe3xtxQk8XPMV284sQFQVeLAIwOY)
AWS ECS의 WAS 서비스 구성에 사용할 로드 밸런서를 생성합니다. EC2 콘솔로 이동 후 왼쪽 메뉴에서 Load balancers를 선택합니다. 그리고 Create load balancer 버튼을 눌러서 로드 밸런서 구성을 시작합니다. Application Load Balancer의 Create 버튼을 눌러서 생성을 시작합니다. Load balancer name은 app-was-alb로 입력하고 Scheme 은 Internal을 선택합니다. Networking 구성에서 VPC는 생성해 둔 app-vpc를 선택하고 Subnets에는 private subnets 두 개를 선택합니다. 그리고 Security groups에는 미리 생성해 둔 app-was-alb-sg를 선택합니다.
![1](https://private-user-images.githubusercontent.com/1788481/242358581-675bfa24-758c-401c-8d9d-a943c696397f.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1ODU4MS02NzViZmEyNC03NThjLTQwMWMtOGQ5ZC1hOTQzYzY5NjM5N2YucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MmRlYTE3MTFlMWY0ODFlNTQyZjU1YmVkZGViNWU1NGMxNzQ3MWEwMDljYTExYTVmNjQ3NWUyNmM1MDIyYzI1OSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.n9Ac3BUkGChgvhDqETgRNLtvfTmXSs6rZtULTHsJk2o)
![2](https://private-user-images.githubusercontent.com/1788481/242358591-10d6a524-fc17-4545-ae3d-4281a46618e0.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1ODU5MS0xMGQ2YTUyNC1mYzE3LTQ1NDUtYWUzZC00MjgxYTQ2NjE4ZTAucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZmYyYWIxMzM5OGJhOWEwMDc1MjVlZDBlMTY3MGEzMTFmMWNiY2M2MDQ0MDdkYmQ2ZDNkOWY0NGI0ZGFiYThlZCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.6QK1pwoO-rhM_yv2PxtlUS9VvuKFeCM84YW8Dk5XM6E)
![3](https://private-user-images.githubusercontent.com/1788481/242358593-0422c34f-c888-46f0-93c8-e707f7335fdc.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1ODU5My0wNDIyYzM0Zi1jODg4LTQ2ZjAtOTNjOC1lNzA3ZjczMzVmZGMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9Yjg3YzI0NjBiOTliMmE1ZDQ2OWQzZDgwMDBkMmU0ZDhiMWZlNDUwOThjODBlYzNhNzhhMDZmMTdmY2E4NDQyNSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.6aCGYbff75HW7riZbeuM0nVdATonORRcDIhMsi61oCc)
Listeners and routing에서 Create target group을 누르고 신규 타겟 그룹을 생성합니다. Choose a target type는 IP addresses를 선택하고 Target group name 값으로 app-was-alb-tg를 입력하고 Port는 8081을 입력합니다. VPC는 app-vpc를 선택합니다. 그리고 Health check path 값으로 /health를 입력합니다. Next 버튼을 눌러서 다음 단계를 넘어간 뒤 Create target group 버튼을 눌러서 타겟 그룹을 생성을 완료합니다.
![4](https://private-user-images.githubusercontent.com/1788481/242358598-50f1a9d3-a53a-46e1-9183-515acf7d764c.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1ODU5OC01MGYxYTlkMy1hNTNhLTQ2ZTEtOTE4My01MTVhY2Y3ZDc2NGMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MDM0ODcyNjMzMjI5ZjU4N2VlN2YxMjY4M2JlNTE0NTU3ZTE4NWVjOTg1NWZkNjRmNmZiMjExMGZmNjBjOWY3ZSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.vPvGJRWkUku_g13l0JLb3wext4m60IwGGKy-tUio4FE)
![5](https://private-user-images.githubusercontent.com/1788481/242381136-450cc4ad-e187-4fa2-9989-d084af3e92ce.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM4MTEzNi00NTBjYzRhZC1lMTg3LTRmYTItOTk4OS1kMDg0YWYzZTkyY2UucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NmY0ZGQyYTQyMzJiMDQ2N2JlMGM3ZDVhNGFjYjViNWU2MzMyZDk0NmFlMjE2MzhjMDFiNzY3YTNiNWQxYWM4NCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.u7xWhhHRNFBJR0FoqSdx-vnJG9Q9ATIrPprWkIfgKuU)
![6](https://private-user-images.githubusercontent.com/1788481/242358606-41a2859a-d0ab-4a44-863f-685d9661c3ee.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1ODYwNi00MWEyODU5YS1kMGFiLTRhNDQtODYzZi02ODVkOTY2MWMzZWUucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NjA1YzMwM2NlMWVhM2ExODIyY2NiYTNkY2ZhN2VhMWRlMzk2YzE2N2M4ZWZlNTIyYzJjNzMzMjc5MDdhN2EzZiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.SDh66bmBjS_2uLcUtKasYpHgFlOgcL8hKoqiHd-f6ho)
다시 로드 밸런서 구성 페이지로 돌아옵니다. Select a target group 옆에 새로고침 아이콘 버튼을 눌러서 방금 생성한 타겟 그룹을 가져오고 선택합니다.
![7](https://private-user-images.githubusercontent.com/1788481/242358610-5b35fbe6-24c4-4257-8672-3d67c619ac30.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1ODYxMC01YjM1ZmJlNi0yNGM0LTQyNTctODY3Mi0zZDY3YzYxOWFjMzAucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NTE2YmZlNzQ0ZDlmYjgzMWE1MzgwNWJmOTk0MGY3OGE2MGU0MWRiYmE5MTU0YjU3Njg2N2ZkMGM2OGNjY2EwNyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.72TzKdey_WqviV2IBcpXM7ZKpKdxfa95oJGKCe100zU)
Create load balancer 버튼을 눌러서 로드 밸런서 생성을 완료합니다.
![8](https://private-user-images.githubusercontent.com/1788481/242358612-98c39d68-c42b-4ca0-a961-e98e78687fb8.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1ODYxMi05OGMzOWQ2OC1jNDJiLTRjYTAtYTk2MS1lOThlNzg2ODdmYjgucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZWMxODRmMmM2ZGI2MGIxOWQ4OGU4NWE1OGRhNGJmYTMyOGZhYWYwMzZmNDA0NjdiZmI1ODliZDQxYzIzYzc0MiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.7sRCbkaRg2RNcziba6oe2q0PdznYgN_S9Byk6ZUOeLY)
생성한 app-was-alb를 눌러서 DNS name을 확인하고 복사해 둡니다. WAS 서비스 구성이 마치면 해당 주소로 접속할 수 있으며 Web 서비스의 애플리케이션에서 접근할 수 있는 주소입니다.
![alb-9](https://private-user-images.githubusercontent.com/1788481/243183056-a35481d5-9d1f-4151-9eb6-eecbaefa397e.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MzE4MzA1Ni1hMzU0ODFkNS05ZDFmLTQxNTEtOWViNi1lZWNiYWVmYTM5N2UucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZjU4N2E4MjllN2QxNTRhZDNjM2Q2YTUxOGUwYzQxYmI4ZGU4N2NkMDIyOGRmZDliNjY1MzNhNTQwNGJlNzg3YSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.TPPsgQxjqVzRWDlggr9lbNUx-SBXlKeLNjF1HbdxcBM)
Task definition을 구성하기 전에 Task에서 Amazon SageMaker Endpoint를 호출하기 위한 역할을 먼저 생성합니다. Identity and Access Management(IAM) 콘솔로 이동합니다. 왼쪽 메뉴에서 Roles를 선택하고 Create role 버튼을 눌러서 역할 생성을 시작합니다.
![0-1](https://private-user-images.githubusercontent.com/1788481/242175726-e39a12ee-f494-4d77-a552-751a823fd437.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjE3NTcyNi1lMzlhMTJlZS1mNDk0LTRkNzctYTU1Mi03NTFhODIzZmQ0MzcucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YzI3YzhhZTFjN2E1ZDc4MTM5NWE5MmFhZTBjNjM1YjU3NTM3MWI0Mjc3MzExNDgwOGViY2Q1ODExYjU4OGYzNCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.UPKF6eH89-TKp1A1yhBnveMOn0X8e4LWthMOttfA3jc)
Trusted entity type으로 AWS service를 선택합니다. User Case 아래 있는 Use cases for other AWS services에서 Elastic Container Service를 선택합니다. 그리고 다시 Elastic Container Service Task를 선택합니다. 구성은 다음과 같습니다. Next 버튼을 눌러서 다음 진행 단계로 넘어갑니다.
![0-2](https://private-user-images.githubusercontent.com/1788481/242175738-c4e81f64-342a-4386-a0d8-df474d7a0ac8.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjE3NTczOC1jNGU4MWY2NC0zNDJhLTQzODYtYTBkOC1kZjQ3NGQ3YTBhYzgucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ODI2ZTM4NGIwYjIxMWVjMjU0MmMyODYxYWI0YWE4MWYwNTYyNzUzNjgxOGU0ZWViNDljOTBjMGNkZjRkYWZiYyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.mfSI5dBcqQgXu29Qu21zGg-mZmxLcqLC_ihtFj0142Q)
Add permissions 단계에서 Create policy를 눌러서 정책 생성을 시작합니다.
![0-3](https://private-user-images.githubusercontent.com/1788481/242175751-c00a4792-c7bc-418d-bad2-03ab4586d40b.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjE3NTc1MS1jMDBhNDc5Mi1jN2JjLTQxOGQtYmFkMi0wM2FiNDU4NmQ0MGIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YTgzNGI4NDFiMjE2NWU3NWY4MDQzOTdiY2FjZWQ4M2QyODFjOTdlY2I4NDRmNmE0M2I2MjJjNjUwODU3MzE2NiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.4OobgLD2U1zILCqlPiZwS05Q-jbDORBPPlTpwYtSt3s)
Policy editor에서 JSON을 선택하고 아래와 같이 입력하고 Next 버튼을 눌러서 다음 단계로 넘어갑니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "sagemaker:InvokeEndpoint",
"Resource": "*"
}
]
}
![0-4](https://private-user-images.githubusercontent.com/1788481/242175756-e528911f-8bf5-4d56-bcfc-cf5bce38e7c6.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjE3NTc1Ni1lNTI4OTExZi04YmY1LTRkNTYtYmNmYy1jZjViY2UzOGU3YzYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9OWQyYmI0YzJjMjNiZGYyY2Y1ZDJlM2UyZGZhNTY3YTU5NjBiYTUyYjdjN2M1YTU4NTNkOGQwNjc2MWZhYzg0NCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.kRDbKOOrHJUWYB8n84IISNcbWSaJgmrodJ_xT13SUc8)
Policy name 에 InvokeSageMakerEndpoint을 입력하고 맨 아래에 있는 Create policy 버튼을 눌러서 정책을 생성합니다.
![0-5](https://private-user-images.githubusercontent.com/1788481/242175760-c55065e6-ecf1-4200-b9ab-d2dfa1ff28c0.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjE3NTc2MC1jNTUwNjVlNi1lY2YxLTQyMDAtYjlhYi1kMmRmYTFmZjI4YzAucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZDMwNWVjNDY1MDk0ZjQyNWQ5NmMxMWI0MmQ3OGEyMjdlZTUxNzU2ODFhMDM2Zjk4MGVmNjRlYzA4ZTJhNjgzNCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.duIzxituEft_WtkhYUcZZSsfpTBN4u0PLhmRAwqLDZU)
InvokeSageMakerEndpoint로 검색하면 다음과 같이 정책이 생성된 것을 확인할 수 있습니다.
![0-6](https://private-user-images.githubusercontent.com/1788481/242175768-1dd1342f-81b0-491e-8ae5-1e2981a03311.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjE3NTc2OC0xZGQxMzQyZi04MWIwLTQ5MWUtOGFlNS0xZTI5ODFhMDMzMTEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZGE3Y2YxYTQ0M2IyMWIzZWFjNmZmNGQ0NTIyOTE2MTkwOWI2MGNkOGEzOTU1NGFlYmQzNDZlN2U1ODk0MjU4OCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.VzVgOSRKDFZ0Q25ZLdd5E0ioCXQB8DM5SPMWqAd5_Fg)
역할을 생성하던 페이지로 다시 돌아온 뒤 Create Policy 버튼 옆에 있는 새로고침 아이콘 버튼을 눌러서 정책 리스트를 다시 로드합니다. InvokeSageMakerEndpoint을 검색하면 방금 생성한 정책이 나옵니다. 나온 정책을 선택하고 Next 버튼을 눌러서 다음 단계로 진행합니다.
![0-7](https://private-user-images.githubusercontent.com/1788481/242175769-e94ff1f5-3171-4817-a675-f38bdcc6b54e.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjE3NTc2OS1lOTRmZjFmNS0zMTcxLTQ4MTctYTY3NS1mMzhiZGNjNmI1NGUucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NDE3MjAyZGRhYjhhZDBlZWQ5YzE1ZDNkMTdhZjJkZDFiNmVkMmE2ZGI0OTM5ZGYyYjgyZGIzNzlmZGIyNDUzMCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.IH2xTuvXfUAQgrtfoc1WYGYxO4DVUasD1Fj4WQp6d3Q)
Role name으로 ecsWasTaskRole을 입력하고 Create role 버튼을 눌러서 역할 생성을 완료합니다.
![0-8](https://private-user-images.githubusercontent.com/1788481/242175771-214abdd0-67a7-4fab-846b-260a33bb4968.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjE3NTc3MS0yMTRhYmRkMC02N2E3LTRmYWItODQ2Yi0yNjBhMzNiYjQ5NjgucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9Njg0YjM5ZjMxODU4OTU2NDJiMzU1YzlkZTQ1NTM1NDg2NTYwMjdhZDIxOWRhMjczN2I3OTk0ZTk5MjUwMTEzMyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.frbemn4KQQQvuD0qoQIvmf8NPqx0lL4K3dXGtvsDdmM)
Amazon ECS 콘솔로 이동 후 왼쪽 메뉴에서 Task definition을 선택합니다. 기존에 등록한 app-web 레파지토리가 있는 것을 볼 수 있습니다. Create new task definition 버튼을 눌러서 태스크 정의를 시작합니다.
![1](https://private-user-images.githubusercontent.com/1788481/242168578-a4cb9be8-9e55-413b-86cb-d7aae34dccce.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjE2ODU3OC1hNGNiOWJlOC05ZTU1LTQxM2ItODZjYi1kN2FhZTM0ZGNjY2UucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MWE2MzBhYzBjYTI5ZWQyNTFkODNjNGQzYTIxZThlYWViMGY5YWY4OTJhOTI5YzViMWExZWI2ZGNmNGU1N2U2ZSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.SI1LBAZE8b29J_XnCjgiSXSLpEqmmEra3eKgoKAju7E)
태스크 정의는 다음 그림과 같이 구성합니다. Task definition family는 app-was-td로 지정합니다. 그리고 태스크를 구성할 컨테이너 정보를 입력합니다. Name 은 app-was로 지정하고 Image URI는 ECR 콘솔에서 앞 단계에서 푸시한 이미지 URI를 찾아서 입력합니다. 포트는 8081로 입력합니다. Environment 칸에 있는 Task role 에 앞서 생성한 ecsWasRole을 선택하여 입력합니다. Next 버튼을 눌러서 다음으로 진행합니다.
![2](https://private-user-images.githubusercontent.com/1788481/242168579-5e4c9828-12c6-4f46-bbf9-e189b134fac9.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjE2ODU3OS01ZTRjOTgyOC0xMmM2LTRmNDYtYmJmOS1lMTg5YjEzNGZhYzkucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9OWYwYmMwNWE1M2I0MjkxOTkwYzExOGFkN2E4YWQ1MTRmZDljNWJkZGIzNzE2OGQwOTE5MzdhNzA0YWE4NjYzNiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.-pWeXO8DXHPoy56VDReqII5rZu9DV6LHFjYEN48fVwA)
![2-1](https://private-user-images.githubusercontent.com/1788481/242176784-63fa0856-98e6-4704-acf3-fc649004179d.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjE3Njc4NC02M2ZhMDg1Ni05OGU2LTQ3MDQtYWNmMy1mYzY0OTAwNDE3OWQucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MDNmZmNjZjA5MzM2YTBiZWYzMGEyN2MwZmNmYWQzMjQ5MTYzMTAzMDZiNjJiNjIyMmIyOTZjZWM0MTlmYjdiYiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.G7xpRYt40JoCuGHVralkpMeeA2EjbGTHGbiW5kyv6ZU)
Next 버튼을 눌러서 다음 진행 단계로 넘어갑니다. 구성을 확인하고 맨 아래에 있는 Create 버튼을 누르고 기다리면 태스크 정의가 생성된 것을 확인할 수 있습니다.
![3](https://private-user-images.githubusercontent.com/1788481/242176793-c39dfaae-f206-47aa-87d6-8517df60ec14.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjE3Njc5My1jMzlkZmFhZS1mMjA2LTQ3YWEtODdkNi04NTE3ZGY2MGVjMTQucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9Yjk3NmU0NDRjY2M4ZjBiZGE3YzQ4MDZiMDVhMTAzMjdjNjhjMWZmYjYxMzMzMjIyNDdkNzA1ZGNjODcxZDRmYSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.JROJoA2b7-6elYxb5SM3j_xScuRZ7fHfysRiOUw3L8I)
AWS ECS에서 구동되는 WAS 서비스 구성을 위해서 AWS ECS 클러스터 콘솔로 이동합니다. 처음에 생성한 AppEcsCluster 링크를 클릭해서 들어간 뒤, Services 탭을 보면 기존에 구성한 Web 서비스가 있는 것을 볼 수 있습니다. Create 버튼을 눌러 WAS 서비스 구성을 시작합니다.
![1](https://private-user-images.githubusercontent.com/1788481/242285913-8d7f52b9-a9f3-434f-aeb8-4b6867805eb6.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjI4NTkxMy04ZDdmNTJiOS1hOWYzLTQzNGYtYWViOC00YjY4Njc4MDVlYjYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MzQ5NTU0YzQ1YjMyMjI3ODI3MTQzMTYxYjUyZTAxNmUxNjNmMDEzN2FmZWQ1MmM4MzRlNGQzMjEyMjhjYjEyOCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.YNeANXYJwhmSElH9mRm6reAEB7XRQgnn5NSfKVqc1BU)
Environment는 다음과 같이 구성합니다. Compute options로 Launch Type을 선택하고, Application type으로 Service를 선택합니다. 그리고 family 값으로 앞서 생성한 task definition 인 app-was-td를 선택합니다. Service Name으로는 app-was-service를 입력합니다. Desired tasks 값으로 2를 입력합니다.
![2](https://private-user-images.githubusercontent.com/1788481/242285924-f833f315-3b2b-423b-b8eb-b899c105eeca.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjI4NTkyNC1mODMzZjMxNS0zYjJiLTQyM2ItYjhlYi1iODk5YzEwNWVlY2EucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MmI0OTE4YWUzZjdkYmFmOTMwZmU3OTM5OTMzYWY3YzE0ZWRkYmFmZjgwOWNlZDBmN2RiZTYwZTM2NDkwNTQxMiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.DGsxJYgkLHwMMcc-ERnZLuIqemxV0TTiPTQexPGXAPw)
![3](https://private-user-images.githubusercontent.com/1788481/242285926-f4d1d260-4464-4a59-b3d5-59ef88c1922c.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjI4NTkyNi1mNGQxZDI2MC00NDY0LTRhNTktYjNkNS01OWVmODhjMTkyMmMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NzdhNmI1YjQwZDcwNjNjZTRhYjE3OTAzZTAxM2E2OTdmNjNmZTA3NTg2NWNkOTVkZjdiYWNjMmQ1MTE2N2NmMSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.3lIYe8hdqqgXvbanJjm_d5Q3AXV0rq68647Pl4KKRPY)
Networking 구성에서 VPC는 생성해 둔 app-vpc를 선택하고 Subnets에는 private subnets 두 개를 선택합니다. 그리고 Security group에는 미리 생성해 둔 app-was-sg를 적용합니다. 그리고 로드 밸런서를 통해 접근할 예정이기 때문에 Public IP는 disable 해놓습니다.
![4](https://private-user-images.githubusercontent.com/1788481/242285931-9c006b3e-a915-4280-822e-b7c7906feeef.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjI4NTkzMS05YzAwNmIzZS1hOTE1LTQyODAtODIyZS1iN2M3OTA2ZmVlZWYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9Zjg4NTBjZWQxMjdkMTg1ZTEwNzEyYzlmYWMyYjBjZWYwZWRkZTg0NDRlMjdkNmQwOWExN2JmOGExYmMyZjdiYiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.PZ4iZjL0hOv9ShNSuK_91KzUjEOD0LxdoiT7LjhJXc4)
Load Balancing 구성에서 Load balancer type으로 Application Load Balancer를 선택합니다. Use an existing load balancer를 선택하고 Load balancer로 app-was-alb를 선택합니다. Use an existing target group을 선택하고 app-was-alb-tg를 선택합니다.
![alb2-1](https://private-user-images.githubusercontent.com/1788481/242359066-fd218e66-bb5a-4db7-bebe-972f62c99437.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1OTA2Ni1mZDIxOGU2Ni1iYjVhLTRkYjctYmViZS05NzJmNjJjOTk0MzcucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NGI4NzhiNzlkZGEyOTZkNWM4NjE5ZjJkZWFkYjE4MGE2ZjdiZTRhMjUwOTgwYTQwODFjZTBmNWM0NTQyMTc2NyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.YhDfffV9nJAGgCtSzC2gH_OOALV2Wmqs8ysTbviwezw)
![alb2-2](https://private-user-images.githubusercontent.com/1788481/242359069-89b76348-d491-4d39-95e4-2ec4d09681d5.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjM1OTA2OS04OWI3NjM0OC1kNDkxLTRkMzktOTVlNC0yZWM0ZDA5NjgxZDUucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YzhiOTg2MjkzNmJkMzhmOWUwYjUyNmI4NDVjN2U3MjRiMWY5Y2VmMmJiNTEwYWMwZTM0YjZiMmY1MjJlYzY5MiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.dt9FUllQ9U4IqRv4JCz5QFfX0TZlzqJvQOBbYTk-HTY)
Service auto scaling 구성에서 Use service auto scaling을 체크합니다. Minimum number of tasks 값으로 2를 입력하고 Maximum number of tasks 값으로 4를 입력합니다. Policy name 값으로 app-was-asg-policy을 입력합니다. ECS service metric으로 ECSServiceMetricAverageCPUUtilization을 선택하고 Target value로 70을 입력합니다. Scale-out cooldown period 과 Scale-in cooldown period 모두 300으로 입력합니다. 모든 구성을 완료한 다음에 Create 버튼을 눌러서 서비스를 생성합니다.
![7](https://private-user-images.githubusercontent.com/1788481/242285944-4718b952-272c-427e-bfcc-34930f1592b5.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjI4NTk0NC00NzE4Yjk1Mi0yNzJjLTQyN2UtYmZjYy0zNDkzMGYxNTkyYjUucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MDcwNDgyZGM0NTIzNzg4OTMyNTVmZDNkOWRlOWM4MzA0NzJhMzg2YThlMGZkMDkzNDdhNWZjNzAxNjRlYmM5MSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.IT3RGi-p9ltG-kR09QHkJEYiMkAwrmx9SgR-qyVrqNA)
![8](https://private-user-images.githubusercontent.com/1788481/242285948-00cff2ba-f12d-4146-80d5-72bc3714bd2d.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjI4NTk0OC0wMGNmZjJiYS1mMTJkLTQxNDYtODBkNS03MmJjMzcxNGJkMmQucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YjY2YmI1MzEyM2RhNzA3MDBiMTFhY2I0ZWEwZDZkODMzNDRjMTVmNmI3OTQ3YTY2ZjNkM2QwNjc1OWY3NGFlOSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.2iBHwgmxlhXodur1bUzsqplPBN2aRnuoTyYM3-A_49k)
Services 탭에서 app-was-service를 선택하고 Tasks 탭에 선택해서 들어가면 다음과 같이 태스크가 구동되는 것을 확인할 수 있습니다.
![11](https://private-user-images.githubusercontent.com/1788481/242285964-8335dfc5-35b3-4cef-b86a-ce901c802d8f.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjI4NTk2NC04MzM1ZGZjNS0zNWIzLTRjZWYtYjg2YS1jZTkwMWM4MDJkOGYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZTZjNjg0MTJjMmFiYWQxOGUzZTAzOTg0Yjk3MzcyMTVmZGRmZTU2MmUyZWFmZWRlMmI5YWM1ZjQwZDViN2RhNSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.9w_ujOrdZmIdangjMJj02e11zcMWWxOIAXOGPBAXUFs)
WAS 서비스의 로드 밸런서는 프라이빗 서브넷에 있기 때문에 직접 접속할 수 없습니다. 그렇기 때문에 Web 서비스에 배포된 애플리케이션에서 제공하는 웹 페이지를 통해서 접속을 확인합니다. 앞서 생성한 Web 애플리케이션에 접속합니다. 그리고 왼쪽 위에 있는 'WAS 접속 확인 페이지' 버튼을 눌러서 이동합니다. 텍스트 입력 창에 WAS 서비스의 로드 밸런서인 app-was-alb의 주소를 입력하고 'WAS 접속 확인' 버튼을 누릅니다. {"was-health":{"message":"WAS-Connected"}} 메시지가 보이면 정상적으로 배포되어 Web 서비스에서 접근이 가능한 상태입니다.
CI/CD를 구성하기 위해서 CodeCommit와 CodeBuild를 먼저 구성하고 CodePipeline 과 연결합니다.
CodeCommit 레파지토리를 생성하고 다운받았던 web 과 app 프로젝트 코드를 새로 생성한 레파지토리에 올려야 합니다. 먼저 AWS CodeCommit 콘솔로 이동 후 Create repository 버튼을 눌러서 생성을 시작합니다.
![commit-1](https://private-user-images.githubusercontent.com/1788481/242482806-26beeddc-7b68-4dd6-be76-7ce72c24957f.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjQ4MjgwNi0yNmJlZWRkYy03YjY4LTRkZDYtYmU3Ni03Y2U3MmMyNDk1N2YucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MjUxZTdiNDA4YTFjMjFlZjA3ODU1ZmQ4OTk5YjViMzYyNWI1YzJhYWY1ZWRjMjcxNzI3ZmEyZWIyM2Y0MDA0YiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.c8ssA6QdTkbMN0QCZ0dEPoO9OTnDFPDRij9WXg8xaW8)
Repository name 은 app-web으로 입력하고 Create 버튼을 눌러서 레파지토리 생성을 완료합니다. 그리고 가이드에 따라서 빈 레파지토리를 클론합니다.
![commit-2](https://private-user-images.githubusercontent.com/1788481/242482813-25b49439-3701-4a5b-bbe7-4a639b91d74b.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjQ4MjgxMy0yNWI0OTQzOS0zNzAxLTRhNWItYmJlNy00YTYzOWI5MWQ3NGIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9OTBlNzA0YjJiZTI5ZDI4Njg2MGUzOTAwOTJiZGVlZDA4YzI4YmRkY2Q4YTJkMGQzNWRlMzg2YjY2NzcyMTRkZCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.xI3clu8XIaAKlHCW0u5c-x01UvNk3NnRxdVrKaWnaB8)
![commit-3](https://private-user-images.githubusercontent.com/1788481/242482815-2866e7f7-715c-4d61-b4ea-3c5aadc61a0d.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjQ4MjgxNS0yODY2ZTdmNy03MTVjLTRkNjEtYjRlYS0zYzVhYWRjNjFhMGQucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YTcxNWQwY2U5ZTAzOWFlNmU5NjNkY2QyZjljMzI3NmYzY2IzNmI0ZDJlMTFjYjU2ODNmYmI1ZGU0MDQxYTkzNiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.wDZbU0bH1at7oiVO4znlONSoQOZeTS72NIb8uEH1BWY)
기존 사용하던 web 프로젝트 폴더 안의 내용을 모두 복사해서 클론한 app-web 폴더에 붙여넣습니다. 그리고 app/router.js 파일에서 BASE_URL을 앞서 생성한 app-was-alb 주소로 변경합니다. 프로토콜은 HTTP 입니다.
// Redirect
const request = require('request');
BASE_URL = "HTTP://[app-was-alb 도메인 주소]"
변경한 코드를 저장한 다음에 푸시합니다. 푸시가 완료되면 다음과 같이 확인할 수 있습니다.
![commit-4](https://private-user-images.githubusercontent.com/1788481/242482818-1c450d66-c743-4d14-987e-27f684c54459.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjQ4MjgxOC0xYzQ1MGQ2Ni1jNzQzLTRkMTQtOTg3ZS0yN2Y2ODRjNTQ0NTkucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ODViYWI2YzBjMTdmZGQ5ZWQxZGE5ZTU2OWZiZTJkMmFkNDhhNDMyMGZlNzI1MmQ2ZDI5MmJmYjI3MjM2NzNmNyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.1G1k6XQ0BeVaIsK132C6_AgcU1yAY7i1FfRcgxhfhVk)
WAS 프로젝트 코드도 위와 동일한 방법으로 진행합니다. Repository name 은 app-was로 입력합니다. 완료되면 아래와 같이 두 개의 레파지토리에 코드가 모두 업로드된 것을 확인할 수 있습니다.
![commit-5](https://private-user-images.githubusercontent.com/1788481/242482821-7ee7f841-f258-4080-bf6f-bc610472f116.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjQ4MjgyMS03ZWU3Zjg0MS1mMjU4LTQwODAtYmY2Zi1iYzYxMDQ3MmYxMTYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MGY3MmUzYmM0ODk1YWIzODcxN2QwNWIyNmVjMDliZTEwYjlhMzIxYzU5OTlhMjk5OTM2NTM1YjQ1ZWZiNDEzNyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.C4e7Uyxlpis9deM4T1BhWRlWCqndKg5Zm4FCduMHUWg)
AWS CodePipeline 콘솔로 이동 후 Create pipeline 버튼을 눌러서 구성을 시작합니다.
![1](https://private-user-images.githubusercontent.com/1788481/242532804-07d920af-1d60-4df5-ad86-6ac263506090.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjUzMjgwNC0wN2Q5MjBhZi0xZDYwLTRkZjUtYWQ4Ni02YWMyNjM1MDYwOTAucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NWFlMDg5NzY5N2Y4ODJkMjZjNjBjYmEyZjIxZmQxOGFmNTU3ZGVmMjg2YzgyZGMyZWEyNjBhMmQ1OGIyMjlmMCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.C5oXDnYXcVpqpoPjmHi5C1fGS9M0HNEbG9AjAzso2N0)
Pipeline name 값으로 app-web-pipeline을 입력하고 Next 버튼을 눌러서 다음 단계를 진행합니다.
![2](https://private-user-images.githubusercontent.com/1788481/242532829-ae729821-a4b8-4925-9068-34c89bc1327a.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjUzMjgyOS1hZTcyOTgyMS1hNGI4LTQ5MjUtOTA2OC0zNGM4OWJjMTMyN2EucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YmVlNTJhMTFlMTI4MzJmNzNmNWU1OTA4OTM3NjVlZTgyY2ExOWMwZGFlMjgwM2MyOWI2ZmE4NjM0ZjUzOTA2ZSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.p4qS0p2vJIDTG8f5_dn6qScsG1ew-sckZfpU4lRlfuk)
Source provider으로 AWS CodeCommit을 선택하고 Repository name 은 app-web을 선택합니다. Branch name 은 main을 선택합니다. Next 버튼을 눌러서 다음 단계를 진행합니다.
![3](https://private-user-images.githubusercontent.com/1788481/242532834-7c82fd3b-653b-483c-9ed9-17540294a089.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjUzMjgzNC03YzgyZmQzYi02NTNiLTQ4M2MtOWVkOS0xNzU0MDI5NGEwODkucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MDI0ZjlhNDNlYWM4MGE2YzQ3YjI5NzU3N2U5MzcyZmE0ODZlZDVlNWViZTI1NmM2YTY0OTczZmZkY2NiZGEwOSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.WmTViu_mcGldRNjzRMrpCuq_J9aEN71xeYarJmPYYpw)
Build provider으로 AWS CodeBuild를 선택하고 Project name 아래 있는 Create project 버튼을 눌러서 빌드 프로젝트 생성을 시작합니다.
팝업으로 뜬 창에서 Project name으로 appWebBuild을 입력합니다. Environment에서 Operating system 은 Amazon Linux2를 선택하고 Runtime(s) 은 Standard를 선택하고 Image는 aws/codebuild/amazonlinux2-aarch64-standard:4.0를 선택합니다. Privileged는 체크합니다. 나머지는 그대로 유지합니다.
![build2-1](https://private-user-images.githubusercontent.com/1788481/242684356-914d6c08-eaea-4f31-b7f6-17a1210871a0.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjY4NDM1Ni05MTRkNmMwOC1lYWVhLTRmMzEtYjdmNi0xN2ExMjEwODcxYTAucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9OWY0ZWVlYTQxZjE1MTExYmY4ZDE1NjFiNzJhYWJiMWFmNjg3MzNmZGY4ZjQ0YTY5ZWM4NTViZjE0YmQ1NDAxYiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.0Ls032X03X73eW-nFjsCya1zmHev508abP0OThrLQcM)
![build2-2](https://private-user-images.githubusercontent.com/1788481/242684370-3f970514-809f-416c-a9af-0ebf9cfd681b.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjY4NDM3MC0zZjk3MDUxNC04MDlmLTQxNmMtYTlhZi0wZWJmOWNmZDY4MWIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NDdhYTdjYTAzM2ZlZWMyNmVkYTVmYmM1ZWU3N2NjNzYzZTNkODg4NjY5ODMzYTIxNzNlMzY2ZWZiMzBiOTdhYiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.ncQxxOsk3ZxkSCO0LAbkMbwLgjfL69LXHJvAuK_yIoo)
Buildspec에서 Insert build commands를 선택합니다. Switch to editor 버튼을 눌러서 에디터 창을 오픈합니다. 아래 코드에서 ECR_URI 값을 앞서 생성한 app-web의 ECR 주소로 변경하고 전체 복사하여 붙여 넣습니다. 아래로 스크롤을 내린 뒤 CloudWatch logs - optional 체크를 해제합니다. 입력을 모두 마치면 Continue to CodePipeline 버튼을 눌러서 빌드 프로젝트 생성을 완료하고 팝업을 닫습니다.
version: 0.2
phases:
pre_build:
commands:
- ECR_URI=933988069619.dkr.ecr.us-west-2.amazonaws.com/app-web
- IMAGE_TAG=latest
- echo Logging in to Amazon ECR...
- aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin $ECR_URI
build:
commands:
- echo Building the Docker image...
- docker build -t app-web .
- docker tag app-web:latest $ECR_URI:$IMAGE_TAG
post_build:
commands:
- echo Pushing the Docker image...
- docker push $ECR_URI:latest
- printf '[{"name":"app-web","imageUri":"%s"}]' $ECR_URI:$IMAGE_TAG > imagedefinitions.json
artifacts:
files: imagedefinitions.json
![build2-3](https://private-user-images.githubusercontent.com/1788481/242684376-68f97391-2685-4e43-858d-5b454f9d5023.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjY4NDM3Ni02OGY5NzM5MS0yNjg1LTRlNDMtODU4ZC01YjQ1NGY5ZDUwMjMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9N2I1MDcxMmJlNmM3NzY0MzVjMWZjNjJjM2E3OGEzMmQ1OTMzZWEzNGM1YjZlZTAxZmM0ZWZkY2ZhMDhhMTc0NCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.3vnAUMo07Pj0NmrBYmyquDqszdJMWAX0my6N16QO1jo)
Deploy provider으로 Amazon ECS를 선택하고 Cluster name으로 AppEcsCluster를 선택합니다. Service name으로 app-web-service을 선택합니다. Next 버튼을 눌러서 다음 리뷰를 진행합니다. 리뷰를 마친 뒤 Create pipeline 버튼을 눌러서 구성을 완료합니다.
![build2-4](https://private-user-images.githubusercontent.com/1788481/242684384-049285b0-a9b3-40f8-a0c2-d397dd5a9043.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjY4NDM4NC0wNDkyODViMC1hOWIzLTQwZjgtYTBjMi1kMzk3ZGQ1YTkwNDMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MGQ0YzJjZDNmZmFjOGUwOWE2OGY3ZTM4ODYyZWM5YzAzNjZlOGI4M2I5M2YzODQ5NmQyZWRmNTFiMTdhMzQxZSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.Uos6TR3fIBCW3wu8ObYBA6Bbs0sxisGh1ue__QyJEqY)
빌드 과정에서 ECR 에 로그인이 필요하기 때문에 정책을 추가해야 합니다. Identity and Access Management(IAM) 콘솔로 이동합니다. 왼쪽 메뉴에서 Roles를 선택하고 codebuild-appWebBuild-service-role을 검색해서 선택합니다. Add permissions 버튼을 누르고 Attach policies를 선택합니다. AmazonEC2ContainerRegistryPowerUser를 검색하고 체크하고 Add permissions 버튼을 눌러서 정책을 추가합니다. 추가가 완료되면 다음과 같이 두 개의 정책이 있는 것을 확인할 수 있습니다.
![build2-5](https://private-user-images.githubusercontent.com/1788481/242684389-4a47f6cc-56d6-4c3c-bde6-f652ae7602a4.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjY4NDM4OS00YTQ3ZjZjYy01NmQ2LTRjM2MtYmRlNi1mNjUyYWU3NjAyYTQucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9N2I1NjEzYmUzMTM4NmM0YTJiMWZmOTQ2NzJiNjk0Yzk1M2M0OWQ3YTBiYWQxODY0YmExYWE5ZGJkYzMyYzhiYiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.vucrbBtTC_asOH6xNnsALtIr__X3DTPJzMC-_5JHGck)
다시 파이프라인으로 돌아가서 Release change 버튼을 선택해서 파이프라인을 실행합니다.
동일한 방식으로 app-was를 위한 파이프라인을 생성합니다. 생성할 때 사용되는 값들은 web 대신 was로 변경합니다. Buildspec 에 있는 코드도 was 에 맞게 수정합니다. 구성이 완료되면 아래와 같이 두 개의 파이프라인이 생성된 것을 확인할 수 있습니다.
![build-9](https://private-user-images.githubusercontent.com/1788481/242695695-333195e1-f780-4a08-8283-31d0a1bec8d7.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjY5NTY5NS0zMzMxOTVlMS1mNzgwLTRhMDgtODI4My0zMWQwYTFiZWM4ZDcucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZTJhNmQzN2YxODIwOTQ5Mjk4ZjJkMmVkMTdhYWRjMDY3YTU3Yjg1OTJhZDEwYzM4MTI3ZjUzOTY5NjRjYzNhOSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.ZKbBZiOiPtYFrwPBI5PTYdYS2svURClcVe4LTAPFbVo)
기계 학습 모델을 학습하고 배포하는 환경을 구성하기 위해서 웹 기반 통합 개발 환경(IDE)인 Amazon SageMaker Studio를 이용합니다. Amazon SageMaker 콘솔로 이동 후 왼쪽 메뉴에서 Domains를 선택하고 Create Domain 버튼을 눌러서 도메인 생성을 시작합니다.
![studio-1](https://private-user-images.githubusercontent.com/1788481/242810836-9aae352b-626b-4016-ac99-9f223e30f059.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjgxMDgzNi05YWFlMzUyYi02MjZiLTQwMTYtYWM5OS05ZjIyM2UzMGYwNTkucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ODY3M2FmNDhiZWZiZjEyMzQ3MzcxMDdmZmQzZDkyZDhhZGNmYTBkZjc5NjYxNjA1ZTk0ZGU1ZWM5ZmU4MTNlMyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.GUfkbeHLQ7u2qu2-uXpn6S32gpsxJazC_edkLaNWOs4)
Quick setup (1 min)을 선택하고 Name으로 app-sagemaker-studio을 입력하고 Execution role 은 Create a new role을 선택합니다. 팝업으로 뜬 창에서 Any S3 bucket을 선택하고 나머지는 그대로 두고 Create role 버튼을 눌러서 롤을 생성합니다. 그리고 나머지 설정은 그대로 유지하고 Submit 버튼을 눌러서 Domain을 생성합니다.
![studio-2](https://private-user-images.githubusercontent.com/1788481/242810844-2357af63-d516-4490-b947-fa0a875bf763.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjgxMDg0NC0yMzU3YWY2My1kNTE2LTQ0OTAtYjk0Ny1mYTBhODc1YmY3NjMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ODcyYzc0YTJjMzY2ZmFlMGM3ZGYzNjJkM2NhODQzNTc3ODAzNzRiMWNjNmZiZGRkZDI0ZTQ2MTBjYWNlZjJhMSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.q05JW8drjsD7ucziIdA-kyXyA3cefd4rqR7yoCj9P5Y)
![studio-3](https://private-user-images.githubusercontent.com/1788481/242810864-1e8b27e9-d773-4958-89f0-13264336d774.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjgxMDg2NC0xZThiMjdlOS1kNzczLTQ5NTgtODlmMC0xMzI2NDMzNmQ3NzQucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YzUzNjczZDQ5MWE5YmM2NDg0ZDc4NjE4NzIzNzUyZTFhNGE5ZDQ5ZmNiY2RhNGMzZjI4NDU5ZWUzYjhkMTQ3NSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ._plC9TH0Ewei40OlXLvkDZASj3dWgr_OPbrcL3VHRG4)
도메인 생성시 뜨는 팝업에서 vpc는 app-vpc를 선택하고 subnet 은 public subnet 하나를 선택합니다.
도메인이 생성되면 도메인 이름을 선택해서 들어간 다음에 생성된 사용자 오른쪽에 있는 Launch 버튼을 펼쳐서 Studio 에 접속합니다.
![studio-4](https://private-user-images.githubusercontent.com/1788481/242810873-024e3c39-1440-4127-a4db-d3f72070c160.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MjgxMDg3My0wMjRlM2MzOS0xNDQwLTQxMjctYTRkYi1kM2Y3MjA3MGMxNjAucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NTFiNzdmMTUxNTBiZDNjZDBlM2Y4ZWZkMGM5ZWE2YzZlNDU2NzljYjYzNDYzYWZhZjIyZDQ4MTgyMzc4ZmQ2OSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.JIgp5JQRqS5gyiaS8A-1DiIZiZAphWNpBVLDhfRefhU)
Amazon SageMaker에서 학습에 사용되는 데이터는 Amazon S3에서 다운로드해서 사용됩니다. 그렇기 때문에 먼저 학습에 필요한 데이터를 Amazon S3에 업로드해야 합니다. Amazon S3 에 app-ml-dataset-[yourname] 버킷을 생성합니다. 여기서는 app-ml-dataset-0410으로 생성했습니다. 그리고 생성한 버킷에 접속해서 다운로드한 프로젝트의 /datasets/flowsers 폴더를 전부 업로드합니다. 다음 그림과 같이 astilbe의 경로는 /app-ml-dataset-0410/flowers/astilbe 가 됩니다.
![data-0](https://private-user-images.githubusercontent.com/1788481/243084882-0a4b372a-a5e6-4184-adaf-2e304383f026.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MzA4NDg4Mi0wYTRiMzcyYS1hNWU2LTQxODQtYWRhZi0yZTMwNDM4M2YwMjYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NmY3N2FmMGY0NGI0NTBhOGQ3YWJlMDkzODQxZjBkNmI1OTdjN2UwNWRiYmJlOWVkOWUwYmNhOTFlNzEyZjk5MyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.zignquP7xPa43ohr_cgiOQxT-HxqKouq0-bsPTiRVKk)
다음으로 학습 단계에 필요한 코드를 SageMaker Studio에 업로드합니다. 먼저 SageMaker Studio에서 접속해서 왼쪽 메뉴에서 폴더 아이콘을 클릭한 뒤 src 폴더를 생성합니다. 그리고 다운로드한 프로젝트에서 /ml/src/train.py 과 /ml/src/flower.py 파일을 /src/train.py 경로와 src/train.py 경로에 각각 업로드 합니다.
train.py 파일에는 학습 데이터 로드, 모델 생성, 모델 학습 그리고 학습한 모델을 저장하는 코드가 있습니다. Amazon SageMaker 는 학습을 시작하기 전에 S3 에 있는 학습 데이터를 지정된 경로에 다운 받기 때문에 코드에서 불러와서 사용할 수 있습니다. 그리고 학습이 완료된 모델을 지정된 경로에 저장하면 Amazon SageMaker 는 S3에 업로드 합니다. 다음 코드는 모델을 생성하는 함수로 이미지 추론을 위해서 MobileNetV2 모델을 생성합니다.
def build_model(dropout=0.2, category_num=3):
print(" --- BUILD MODEL --- ")
mobile_net_layers = tf.keras.applications.MobileNetV2(include_top=False,
weights='imagenet',
pooling='avg',
input_shape=(224, 224, 3))
mobile_net_layers.trainable = False
model = tf.keras.Sequential([
mobile_net_layers,
tf.keras.layers.Dropout(dropout),
tf.keras.layers.Dense(category_num, activation='softmax')
])
model.summary()
return model
그리고 생성된 모델과 학습 데이터를 이용해서 모델을 학습하는 코드입니다.
def train_model(model, x, y, learning_rate=0.0001, batch_size=32, epochs=50):
print(" --- TRAIN MODEL --- ")
adam = tf.keras.optimizers.Adam(learning_rate=learning_rate)
model.compile(loss='categorical_crossentropy', optimizer=adam, metrics=['accuracy'])
history = model.fit(x, y,
shuffle=True,
batch_size=batch_size,
epochs=epochs,
validation_split=0.2)
return history
마지막으로 학습이 완료된 모델을 특정 경로에 저장하는 코드입니다.
def store(model, model_path="/opt/ml/model"):
print(" --- STORE --- ")
print(model_path)
# Store Keras
model.save(model_path + "/1")
이제 앞서 확인한 train.py을 이용해서 학습 단계를 생성하고 학습 단계만 있는 파이프라인을 구성합니다. 이를 위해서 다운로드한 프로젝트에서 /ml/build-pipeline-train.ipynb을 SageMaker Studio에서 /build-pipelin-train.ipynb 경로로 업로드 합니다. 업로드한 파일 열면 뜨는 Set up notebook environment 창에서 Image를 TensorFlow 2.12.0 Python 3.10 CPU Optimized로 선택하고 Select 버튼을 눌러서 노트북 환경 설정을 마칩니다. 여기서 구성하는 환경은 학습 환경이 아닌 파이프라인 생성을 위한 환경이기 때문에 GPU를 사용하지 않습니다.
![train-4](https://private-user-images.githubusercontent.com/1788481/242960906-c6148994-c3b7-4896-915b-ae0e6574ed5a.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0Mjk2MDkwNi1jNjE0ODk5NC1jM2I3LTQ4OTYtOTE1Yi1hZTBlNjU3NGVkNWEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZTMxNTU0MDA4YjRmZTA2YWE5MDI5ZmYyMzNmZDNhNjQ2YjdlOTZlZDJjZjUzMjJiMTE5Zjg5ZDRjMDZiZDBjYiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.gRn9F3BE_cth-Me3rwZL3OfalRKbsLJV3HZ2vpGZ88Y)
파일에서 train_data_uri 값으로 앞서 업로드한 학습 데이터 경로를 대입하여 기본값으로 사용합니다. 과정을 단순화하기 위해서 학습 데이터와 테스트 데이터는 같은 데이터를 사용합니다. 다음 코드는 학습되는 컴퓨팅 환경을 구성하는 부분으로 학습 모델에 따라 다르게 설정할 수 있습니다.
tf_estimator=TensorFlow(
source_dir='src',
entry_point='train.py',
dependencies=[],
instance_count=1,
instance_type='ml.p3.2xlarge',
framework_version='2.11.0',
role=role,
hyperparameters=hyperparameters,
sagemaker_session=sagemaker_session,
compiler_config=TrainingCompilerConfig(),
py_version="py39",
disable_profiler=True,
metric_definitions=[
{"Name": "training_loss", "Regex": "loss: ([0-9.]*?) "},
{"Name": "training_accuracy", "Regex": "accuracy: ([0-9.]*?) "},
{"Name": "validation_loss", "Regex": "val_loss: ([0-9.]*?) "},
{"Name": "validation_accuracy", "Regex": "val_accuracy: ([0-9.]*?)$"}
],
base_job_name="app-flower-classifier"
)
구성을 완료하고 상단에 있는 재생 아이콘 버튼을 눌러서 모든 코드 블록을 실행해서 파이프라인을 구성하고 생성합니다. 생성된 파이프라인을 확인하기 위해서 왼쪽의 메뉴에서 홈 아이콘 버튼을 눌러서 메뉴가 펼쳐지면 Pipelines 버튼을 선택해서 이동합니다. 이동하면 다음과 같이 AppMlPipeline-Train 이 생성된 것을 확인할 수 있습니다.
![train-6](https://private-user-images.githubusercontent.com/1788481/243153915-b80267e1-0b79-4257-bb7a-46b586fc4bef.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MzE1MzkxNS1iODAyNjdlMS0wYjc5LTQyNTctYmI3YS00NmI1ODZmYzRiZWYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YzM4NTU0Yzg2YmMxM2E3NjYzOTNjOTQwYTNiZjUwN2QwOTBjOWU0YTViYjMxMTc1NDFkMGQ1MmMyOTQ4OTg4MyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.Xa3TExuB7xTAZYSaTJdr5-XorMUzOUMnDssJIZqdl5E)
AppMlPipeline-Train을 선택해서 들어간 다음 Graph 탭으로 이동하면 Train 스탭이 생긴 것을 확인할 수 있습니다. 이제 오른쪽 위에 있는 Create execution을 눌러서 파이프라인을 시작합니다. 필요한 값들을 입력하고 Start 버튼을 눌러서 실행합니다.
![train-7](https://private-user-images.githubusercontent.com/1788481/243153921-ab51e076-346e-43d1-864c-ef72c24a5c79.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MzE1MzkyMS1hYjUxZTA3Ni0zNDZlLTQzZDEtODY0Yy1lZjcyYzI0YTVjNzkucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9OTc4MDBmYTQ1ZTJjZTBmYjZjZGE0MTNjYmJhNGM2ZjUyYjAxNjc2OWIyMDllYzkwNjNkMDhhYTlhNzBiZDUyNSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.dZqNwujtmrZGKoNwGEUpCwtVZvglhy2p_pvPYdreYKM)
![train-8](https://private-user-images.githubusercontent.com/1788481/243153925-b556304e-baf4-4d0f-8d6c-f0b098888e52.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MzE1MzkyNS1iNTU2MzA0ZS1iYWY0LTRkMGYtOGQ2Yy1mMGIwOTg4ODhlNTIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZDljNDE2MjNjODkzMmVhMzM1MTk1ODcxMDdkYWVmNmJmYTExNjE3N2ZlYTFlMTA3NDFlM2IzZDVlNGIzNGM3ZiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.ytArVl0rjdXjpXYLoCmz1VD9q44OYTkX3DgAx1kVH_8)
학습이 완료되면 다음과 같이 초록색으로 표시되며 Output 탭에서 학습 결과를 확인할 수 있습니다.
![train-10](https://private-user-images.githubusercontent.com/1788481/243084966-13573914-4fc6-4662-bf17-e2e212d7e6cc.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MzA4NDk2Ni0xMzU3MzkxNC00ZmM2LTQ2NjItYmYxNy1lMmUyMTJkN2U2Y2MucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MzMyZGQyODY5NTc4OWQyYjA0ZjI5NDViMTQ5ZTVkZjFlNzFkNGNkYjRiYTM0YmI5NzNhMWRkMDdiMzA3Yjk3MiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.QX2jCp0FUQYbDpxXKbkl7nyiC2L9GCG5LbbCwc4ahqI)
다음으로 모델 등록 단계가 추가된 파일을 업로드합니다. 이를 위해서 다운로드한 프로젝트에서 모델 생성 단계 /ml/build-pipelin-model.ipynb을 SageMaker Studio에서 /build-pipelin-model.ipynb 경로에 업로드 합니다. 업로드한 파일 열면 뜨는 Set up notebook environment 창에서 Image를 TensorFlow 2.12.0 Python 3.10 CPU Optimized로 선택하고 Select 버튼을 눌러서 노트북 환경 설정을 마칩니다. 추가된 단계는 다음과 같습니다.
# 4. Create Model
from sagemaker.model import Model
from sagemaker.inputs import CreateModelInput
from sagemaker.workflow.steps import CreateModelStep
model = Model(
image_uri="763104351884.dkr.ecr.ap-northeast-2.amazonaws.com/tensorflow-inference:2.11.0-cpu",
model_data=step_train.properties.ModelArtifacts.S3ModelArtifacts,
sagemaker_session=sagemaker_session,
predictor_cls=sagemaker.predictor.RealTimePredictor,
role=role
)
inputs = CreateModelInput(
instance_type="ml.m5.large",
)
step_create_model = CreateModelStep(
name="CreateModel",
model=model,
inputs=inputs,
)
학습 단계에서 했던 과정과 동일하게 train_data_uri 값으로 앞서 업로드한 학습 데이터 경로를 대입하여 기본값으로 사용합니다. 왼쪽의 메뉴에서 홈 아이콘 버튼을 눌러서 메뉴가 펼쳐지면 Pipelines 버튼을 선택해서 이동합니다. 이동하면 다음과 같이 AppMlPipeline-Model 이 생성된 것을 확인할 수 있습니다.
![model-1](https://private-user-images.githubusercontent.com/1788481/243162533-31d17cee-ff76-4511-8c49-b3d64701e9ca.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MzE2MjUzMy0zMWQxN2NlZS1mZjc2LTQ1MTEtOGM0OS1iM2Q2NDcwMWU5Y2EucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YTZkNGQ4M2NkM2QwMTIyZjQ1YTRlNGMwMWI2ZTRkMTI5MGMzMTg3NjU0Y2EzNGQ3OTM4YmQ5N2JlMDZkNjliNSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.J-WfxrE91_H0kosy0RCp6nZ1a97CD6cvKgL8MT7NIoU)
AppMlPipeline-Model을 선택해서 들어간 다음 Graph 탭으로 이동하면 CreateModel 스탭이 추가된 것을 확인할 수 있습니다. 이제 오른쪽 위에 있는 Create execution을 눌러서 파이프라인을 시작합니다. 필요한 값들을 입력하고 Start 버튼을 눌러서 실행합니다.
![model-2](https://private-user-images.githubusercontent.com/1788481/243162547-0729a2f6-40a0-437a-a8db-49824bf6f3f2.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MzE2MjU0Ny0wNzI5YTJmNi00MGEwLTQzN2EtYThkYi00OTgyNGJmNmYzZjIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9OWYzZjQyMWJjNTg4M2ExZGExODQwM2IwMDgwYWZiMTdlMjU3MmVmMDM1Nzg3MTIzZDZkNzU5NGVlMGM1ZTZlOSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.IYXqlkLx87hY1fPVnoLtb1EL5hR9X5UgeSVpoHSKVzo)
![model-3](https://private-user-images.githubusercontent.com/1788481/243162549-67a9df6b-61cd-4584-9490-b84b49e7764b.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MzE2MjU0OS02N2E5ZGY2Yi02MWNkLTQ1ODQtOTQ5MC1iODRiNDllNzc2NGIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YTJmZWM4ZGY3N2E4OGYwN2UxOTdjNTE0MDEyYjgwZTJjYmRhODY4MDhiN2YyMWM3YWZkM2I3ODUzOGY5NDI3ZiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.xoK25st7Pn5H5GBu_1lUOUGlcxn7N0ycq418IcpqtZ0)
파이프라인이 완료되어 학습과 모델이 생성되면 다음과 같은 화면을 볼 수 있습니다.
![model-4](https://private-user-images.githubusercontent.com/1788481/243162550-e8a04397-61ec-41a2-ab56-4dda56f7255f.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MzE2MjU1MC1lOGEwNDM5Ny02MWVjLTQxYTItYWI1Ni00ZGRhNTZmNzI1NWYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YzU4MGRkOGNmNDFkNDgzYjMzZjc5ZmQ2NzM0ODkxNjA1YzUzZGE3ZGFkZGZmYmIxZmIxZDEzMTg0M2MyY2M2OCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.6WANxUuS7bVcOLOQdgYG13JcjiADBGjsJxkPPX6-l2A)
배포 단계에는 SageMaker Endpoint를 생성하고 생성한 Endpoint 에 모델을 배포합니다. 먼저 배포 단계에 필요한 코드를 SageMaker Studio 에 업로드합니다. SageMaker Studio에 접속해서 왼쪽 메뉴에서 폴더 아이콘을 클릭한 뒤 src 폴더를 생성합니다. 그리고 다운로드한 프로젝트에서 /ml/src/deploy.py 파일을 /src/deploy.py 경로에 업로드 합니다.
이제 앞서 올린 deploy.py을 이용해서 SageMaker Endpoint 에 배포하는 단계를 생성하고 파이프라인을 구성합니다. 이를 위해서 다운로드한 프로젝트에서 /ml/build-pipelin-deploy.ipynb을 SageMaker Studio에서 /build-pipelin-deploy.ipynb 경로로 업로드 합니다. 업로드한 파일 열면 뜨는 Set up notebook environment 창에서 Image를 TensorFlow 2.12.0 Python 3.10 CPU Optimized로 선택하고 Select 버튼을 눌러서 노트북 환경 설정을 마칩니다. 추가된 단계는 다음과 같습니다.
# 5. Create Endpoint and Deploy
from sagemaker.workflow.steps import ProcessingStep
from sagemaker.sklearn.processing import SKLearnProcessor
sklearn_processor = SKLearnProcessor(
framework_version="1.0-1",
instance_type="ml.m5.large",
instance_count=1,
# base_job_name="comprehen",
sagemaker_session=sagemaker_session,
role=role,
)
step_create_model = ProcessingStep(
name="CreateEndpoint",
processor=sklearn_processor,
job_arguments=[
"--model-name",
step_create_model.properties.ModelName,
],
code="src/deploy.py",
)
학습 단계에서 했던 과정과 동일하게 train_data_uri 값으로 앞서 업로드한 학습 데이터 경로를 대입하여 기본값으로 사용합니다. 왼쪽의 메뉴에서 홈 아이콘 버튼을 눌러서 메뉴가 펼쳐지면 Pipelines 버튼을 선택해서 이동합니다. 이동하면 다음과 같이 AppMlPipeline-Deploy 가 생성된 것을 확인할 수 있습니다.
![deploy-1](https://private-user-images.githubusercontent.com/1788481/243167540-36b4c416-4eb8-43d5-b563-e96a9171517f.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MzE2NzU0MC0zNmI0YzQxNi00ZWI4LTQzZDUtYjU2My1lOTZhOTE3MTUxN2YucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NmYzYTc4YTNiMTQ0NzM0YjQwMDQ1ZmJhYTc5Njg3NzQ0MDEzMmRmZDVlZGYwOGQ4ZjhkNjllMDc2ZDcxMTYwMiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.D41VFnaMKCH6DEQ9JWMRCu2ONEctIKzsEESbmQcuges)
AppMlPipeline-Deploy을 선택해서 들어간 다음 Graph 탭으로 이동하면 DeployEndpoint 스탭이 생긴 것을 확인할 수 있습니다. 이제 오른쪽 위에 있는 Create execution을 눌러서 파이프라인을 시작합니다. 필요한 값들을 입력하고 Start 버튼을 눌러서 실행합니다.
![deploy-2](https://private-user-images.githubusercontent.com/1788481/243167542-8a546ca3-55e6-47f2-8d2d-d6313297af48.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MzE2NzU0Mi04YTU0NmNhMy01NWU2LTQ3ZjItOGQyZC1kNjMxMzI5N2FmNDgucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NGYwZjRjN2NlNGNlOWE5NzNjNmY4M2RmNDQzNzVlYTQxMDkyZDMwZmVkODZjYWFiYjlmM2NmOWU0NDExNTU2YSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.otnprQBzqBfViOh7WQ5XqpzesoRFhxJow02SLPEru-w)
![deploy-3](https://private-user-images.githubusercontent.com/1788481/243167544-346a20f9-6bf3-4162-ae84-9790969f34b9.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MzE2NzU0NC0zNDZhMjBmOS02YmYzLTQxNjItYWU4NC05NzkwOTY5ZjM0YjkucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YzYxODFlZjM2OTFlMWRhNWMwNzU4ZTI0M2JhMGM0N2IxM2RhMGE5OWI1MjYyYTgyOTkwOGYyYjk2OWJlNmYwMyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.iIhGO6ogGdRMHHfigqHuWAfdJ8X3_yf4a-IRePagNis)
파이프라인이 완료되어 학습과 모델이 생성되고 엔드포인트에 배포까지 완료되면 다음과 같은 화면을 볼 수 있습니다.
![deploy-4](https://private-user-images.githubusercontent.com/1788481/243167545-15d29280-e37f-4391-bf1a-e1680b07ef56.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM4Njk1MjgsIm5iZiI6MTcyMzg2OTIyOCwicGF0aCI6Ii8xNzg4NDgxLzI0MzE2NzU0NS0xNWQyOTI4MC1lMzdmLTQzOTEtYmYxYS1lMTY4MGIwN2VmNTYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxNyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTdUMDQzMzQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZjhhNGRlOTc0YzRmNWZhZWNhYWE0M2YyZTQwNTIyZmNkYTlkNTI0MmZlYzdiZWZiMWM3YjdiMTIzYzVhYjQ0ZSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.g6-Bp6_qlPU2yEPuX_tjlv1v1-HhSuRp5Bt2SL7J34M)
로드 밸런서(app-web-alb-sg)의 도메인 주소를 통해서 WAS 서비스에서 구동되고 있는 애플리케이션에 접속합니다. 빨간 사진기 버튼을 눌러서 학습한 꽃 이미지 중 하나를 선택합니다. 노란 돋보기 버튼을 눌러서 분석을 요청하고 기다립니다. 기다리면 분석과 함께 설명이 나오는 것을 확인할 수 있습니다.
실습 후 추가 과금을 방지하기 위해서 사용한 리소스를 모두 삭제해야 합니다. Amazon S3 콘솔로 이동해서 직접 생성한 버킷을 모두 삭제하고 'codepipeline-', 'sagemaker-' 로 시작하는 생성된 버킷도 모두 삭제합니다. Amazon ECR 콘솔로 이동해서 생성한 Repository를 모두 삭제합니다.
CodePipeline 콘솔로 이동해서 왼쪽 메뉴의 Repositories, Build projects, Pipelines 에 들어가서 생성한 리소스를 모두 삭제합니다. Amazon Elastic Container Service 콘솔로 이동해서 생성한 Cluster를 삭제합니다. EC2 콘솔로 이동해서 왼쪽 메뉴의 Target Groups, Load Balancers, Security Groups 에 들어가서 생성한 리소스를 모두 삭제합니다.
Amazon SageMaker 콘솔로 이동합니다. 그리고 오른쪽 메뉴에서 Domains로 이동합니다. 생성한 도메인을 선택해서 들어간 다음 사용자를 선택합니다. Delete App 버튼을 눌러서 사용중인 App 을 모두 삭제하고 Edit 버튼을 눌러서 사용자도 함께 삭제합니다. 사용자가 삭제되었으면 생성한 도메인을 삭제합니다. 그리고 왼쪽 메뉴 Models, Endpoints, Endpoint configuration 에 들어가서 파이프라인에서 생성한 리소스를 모두 삭제합니다.
마지막으로 VPC 콘솔로 이동해서 생성한 NAT Gateways, Subnets, Route Tables, Network ACLs, Internet Gateways, Security Groups 을 삭제하고 VPC 를 삭제합니다.
이 글에서는 AWS에서 제공하는 다양한 서비스를 이용하여 꽃 이미지 분류를 위한 AI 애플리케이션 구축하는 방법을 소개했습니다. 컨테이너화된 애플리케이션을 쉽게 배포, 관리, 확장할 수 있도록 도와주는 완전 관리형 컨테이너 오케스트레이션 서비스인 Amazon ECS와 기계 학습 모델을 학습하고 배포하여 운영할 수 있는 Amazon SageMaker를 대규모 트래픽에도 유연하게 확장할 수 있도록 했습니다. 그리고 Amazon SageMaker Pipelines를 이용하여 기계 학습 모델 학습 및 배포를 자동화하고 AWS CodePipeline을 이용해서 컨테이너 통합 및 배포를 위한 CI/CD 파이프라인을 구축하는 방법을 소개했습니다. 애플리케이션 규모가 커지더라도 마이크로서비스 및 모델의 확장과 운영에 유연한 아키텍처로 최신 AI 애플리케이션을 구현하는데 참고가 될 수 있을 것으로 기대됩니다.
See CONTRIBUTING for more information.
This library is licensed under the MIT-0 License. See the LICENSE file.