IT STUDY LOG
[AWS] 09. 컨테이너 배포 본문
# 학습 목표
- Cloud와 Deployment의 의미를 각각 알고, 서비스를 남에게 배포할 수 있다.
- 클라우드 컴퓨팅이 무엇인지 설명할 수 있다.
- 애플리케이션 배포가 어떻게 변화되어 왔는지 이해할 수 있다.
- AWS의 각 서비스가 어떤 목적에 부합하는지 이해할 수 있다.
- S3의 목적과, 정적 웹 사이트 배포 방법을 이해할 수 있다.
- EC2의 주요 용어를 이해할 수 있다. (AMI, 인스턴스, 인스턴스 유형, 스토리지 타입, 퍼블릭/프라이빗 IP)
- EC2의 인스턴스 시작/중지/종료에 대해 이해할 수 있다.
- RDS와 EC2에서의 MySQL 사용이 어떻게 다른지 이해할 수 있다.
- CloudFront의 목적을 이해할 수 있다.
- Auto Scaling의 특징 및 역할을 알 수 있다.
- 로드 밸런서 중 ELB, 그 중에서 Application Load Balancer의 목적을 이해할 수 있다.
- AWS 인프라 중 VPC에 대해서 이해할 수 있다.
- Route 53의 목적을 이해하고, 도메인을 연결해 HTTPS로 배포할 수 있다.
- 빌드 및 배포시 필요한 환경 설정을 할 수 있다.
- 배포 시 발생하는 문제를 이해하고 고칠 수 있다.
# 학습 내용
1. Amazon ECS/ECR
ECS
- ECS란 "Elastic Container Service"의 약어로, AWS에서 제공하는 컨테이너 오케스트레이션 서비스
ECS를 지원하는 세 가지 종류
ECS (EC2 launch type), EC2 launch type
- 가상 머신(VM) 위에서 컨테이너를 실행하는 방식
- EC2 인스턴스를 직접 관리해야 하므로, 조금 더 복잡한 설정이 필요
ECS (Fargate launch type), Fargate launch type
- 서버리스(serverless) 방식으로 컨테이너를 실행하는 방식
- EC2 인스턴스를 직접 관리하지 않아도 되기 때문에 간편하게 컨테이너를 실행 가능
ECS Anywhere, ECS Anywhere
- 로컬 데이터 센터나 에지 컴퓨팅(Edge Computing) 환경에서도 ECS를 사용할 수 있도록 지원하는 서비스
- 이를 통해 온프레미스(On-Premises) 환경에서도 컨테이너 오케스트레이션을 적용 가능
ECS 관련 개념
ECS 클러스터
- Amazon EC2 인스턴스나 AWS Fargate 태스크를 호스팅하는 가상 컴퓨팅 환경
- CS 클러스터는 하나 이상의 인스턴스 또는 태스크를 실행하는 데 사용
- 작업이 실행되는 EC2들의 집합
ECS 서비스
- ECS 서비스는 컨테이너의 논리적 그룹
- 서비스는 지속적으로 실행되는 하나 이상의 작업으로 구성
- 작업은 하나 이상의 컨테이너 인스턴스를 실행
작업 (Task)
- 인스턴스에서 실행되는 실제 컨테이너 작업
- 하나 이상의 동일한 작업 정의를 기반으로 실행되는 하나 이상의 컨테이너 인스턴스를 나타내는 개체로 작업은 컨테이너 인스턴스 그룹으로 구성
- 작업은 특정 시점에 한 번 실행할 수도 있고, 주기적으로 실행되거나, 다른 이벤트에 따라 트리거 될 수 있음
- 작업은 ECS 서비스와 함께 사용되는 경우 지속적으로 실행되는 서비스의 일부가 될 수 있음
- 작업은 작업 정의(Task Definition)에서 정의된 컨테이너 이미지와 컨테이너 설정을 사용하여 실행
- 작업은 ECS 클러스터 내에서 실행되며, 작업을 실행할 EC2 인스턴스나 Fargate 태스크를 선택 가능
- 작업은 실행 중인 컨테이너 인스턴스에서 실행됨
- ECS에서 중요한 개념 중 하나이며, 컨테이너 기반 애플리케이션을 관리하고 실행하는 데 매우 유용
작업 정의
- 작업에 대한 컨테이너 및 환경 정의
- 작업 정의는 컨테이너 이미지와 실행 구성을 설명하는 객체
- 작업 정의는 ECS 서비스 또는 작업을 생성할 때 사용
- 작업 정의는 컨테이너 이미지, CPU 및 메모리 요구 사항, 컨테이너 실행 시 사용해야 하는 명령 등을 지정
클러스터 관리 엔진
- 클러스터 리소스 및 작업 상태 관리
스케쥴러
- 클러스터 상태를 고려한 작업 배치
에이전트
- EC2 인스턴스 및 매니저와 통신
2. Docker 이미지와 Amazon ECS를 이용한 풀스택 앱 배포
Step 0 : 사전 작업: 소스 코드 수정하기
- 백엔드 코드 backend/app.js 는 3333번 포트를 노출하는 것으로 변경
- const port = 80 + const port = 3333
- 프론트엔드 코드 frontend/script.js의 첫번째 줄의 AJAX 요청을 다음과 같이 변경
- fetch('http://localhost:3333/') + fetch(`http://${location.hostname}:3333/`)
- (optional) Apple M1을 이용하는 경우, Dockerfile 수정
- FROM httpd:2.4 + FROM --platform=linux/amd64 httpd:2.4 - FROM node:16-alpine + FROM --platform=linux/amd64 node:16-alpine
Step 1 : Build a ship a Compose Application
프로젝트 구조 확인
$ tree sprint-docker-app/
...
2 directories, 6 files
docker-compose.yml 파일 수정
- push를 염두해 이미지 이름 및 태그를 바르게 지정
version: "3.0"
services:
frontend:
build: frontend
image: <도커허브아이디>/frontend:1.0
restart: 'always'
ports:
- target: 80
published: 80
x-aws-protocol: http
depends_on:
- backend
container_name: frontend_container
backend:
build: backend
image: <도커허브아이디>/backend:1.0
restart: 'always'
ports:
- target: 3333
published: 3333
x-aws-protocol: http
container_name: backend_container
- 포트 구성에서 target과 published를 일치하도록 만든 이유
> 컨테이너 내부에서 사용하는 포트(target)와, ECS(호스트)에서 사용할 포트(published)를 일치시키기 위해
- x-aws-protocol 속성의 의미
> Compose 파일의 서비스가 포트 80 또는 443만 노출하는 경우 Application Load Balancer가 생성되지만, 그렇지 않으면 ECS 통합이 Network Load Balancer를 프로비저닝
> x-aws-protocol를 사용하면 고유한 포트를 사용하는 HTTP 서비스는 포트 선언 내에서 사용자 지정 확장이 있는 http 프로토콜을 요청하여 ALB를 강제로 사용 가능
docker-compose.yml 파일을 이용해서 로컬에서 도커 기동 및 정상 작동 확인
$ docker compose up -d
[+] Running 3/3
⠿ Network "myproject_default" Created 0.5s
⠿ Container myproject_backend_1 Started 0.7s
⠿ Container myproject_frontend_1 Started 1.4s
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
eec2dd88fd67 myproject_frontend "/docker-entrypoint...." 4 seconds ago Up 3 seconds 0.0.0.0:80->80/tcp myproject_frontend_1
2c64e62b933b myproject_backend "python3 /app/main.py" 4 seconds ago Up 3 seconds myproject_backend_1
http://localhost 에 잘 연결되었는지 확인
기동한 컨테이너 중지
$ docker compose down
[+] Running 3/3
⠿ Container myproject_frontend_1 Removed 0.5s
⠿ Container myproject_backend_1 Removed 10.3s
⠿ Network "myproject_default" Removed 0.4s
이미지 빌드
$ docker compose build
[+] Building 1.2s (16/16) FINISHED
=> [myhubuser/starter-front internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 31B 0.0s
=> [myhubuser/starter-back internal] load build definition from Dockerfile 0.0s
...
이미지를 내 Docker Hub에 push
- ECS에 애플리케이션을 배포하기 위해서는 공개된 레파지토리에 이미지 푸시가 되어야함
- http://hub.docker.com 이미지가 repository에 push되었는지 확인
$ docker login
...
Login Succeeded
$ docker compose push
[+] Running 0/16
⠧ Pushing Pushing frontend: f009a503aca1 Pushing [===========================================... 2.7s
...
Step 2 : Create an ECS context to target Amazon ECS
$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" unzip awscliv2.zip sudo ./aws/install
- "docker context create" requires exactly 1 argument 에러가 나면서 context가 생성이 되지 않는 경우 공식 문서 참고
$ curl -L https://raw.githubusercontent.com/docker/compose-cli/main/scripts/install/install_linux.sh | sh
- 아이디/비밀번호 방식의 로그인이 아닌, 프로그래밍 방식의 액세스를 위해서 액세스 키 발급이 필요 ※ 민감한 정보로 노출에 유의할 것, 액세스 키 및 시크릿 키는 비밀번호와 동일하게 취급
액세스 키 관리(콘솔)
1. AWS 계정 ID나 계정 별칭, IAM 사용자 이름 및 암호를 사용하여 IAM 콘솔에 로그인AWS 계정 ID를 받으려면 관리자에게 문의
2. 오른쪽 상단의 탐색 모음에서 사용자 이름을 선택한 다음 Security credentials(보안 자격 증명)를 선택
액세스 키 생성
1. 액세스 키 섹션에서 Create access key(액세스 키 생성)를 선택 (이미 두 개의 액세스 키가 있는 경우, 이 버튼은 비활성화되어 있으며 액세스 키를 삭제해야 새로 생성 가능)
2. Access key best practices & alternatives(액세스 키 모범 사례 및 대안) 페이지에서 액세스 키가 필요하다고 판단되면 Other(기타), Next(다음)를 차례로 선택
3. (선택 사항) 액세스 키에 대한 설명 태그 값을 설정 이렇게 하면 IAM 사용자에게 태그 키-값 페어가 추가
4. 모두 마쳤으면 Create access key(액세스 키 생성)를 선택
5. Retrieve access keys(액세스 키 검색) 페이지에서 Show(표시)를 선택하여 사용자의 비밀 액세스 키 값을 표시하거나 Download .csv file(.csv 파일 다운로드)을 선택 ※ 이것이 비밀 액세스 키를 저장할 수 있는 유일한 기회
6. 비밀 액세스 키를 안전한 위치에 저장한 후 Done(완료)을 선택
액세스 키 비활성화
1. Access keys(액세스 키) 섹션에서 비활성화하려는 키를 찾은 다음 Actions(작업), Deactivate(비활성화)를 차례로 선택
2. 확인 메시지가 나타나면 Deactivate(비활성화)를 클릭 비활성화된 액세스 키는 여전히 두 개의 액세스 키 제한에 포함
액세스 키 활성화
1. Access keys(액세스 키) 섹션에서 활성화하려는 키를 찾은 다음 Actions(작업), Activate(활성화)를 차례로 선택
더이상 필요하지 않은 액세스 키 삭제
1. Access keys(액세스 키) 섹션에서 삭제하려는 키를 찾은 다음 Actions(작업), Delete(삭제)를 차례로 선택
2. 대화 상자의 지침에 따라 먼저 Deactivate(비활성화)를 수행한 다음 삭제를 확인 액세스 키를 영구적으로 삭제하기 전에 액세스 키가 더 이상 사용되고 있지 않은지 확인
Amazon ECS 컨텍스트 생성 (공식 문서 참고)
- 컨테이너의 실행이 내 호스트 PC가 아닌, ECS 플랫폼 상에서 이루어지도록 만듦
1. sudo 명령어를 이용해 ECS context 생성, 이 때 발급한 secret and token 사용
- environment variables 같은 경우 ~/.aws/config 등에 환경 변수 설정해 context를 생성하는 것
$ sudo docker context create ecs myecscontext
? Create a Docker context using: [Use arrows to move, type to filter]
An existing AWS profile
> AWS secret and token credentials
AWS environment variables
- 정상적으로 만들어졌는지 확인
$ sudo docker context ls
NAME TYPE DESCRIPTION DOCKER ENDPOINT
default * moby Current DOCKER_HOST based configuration unix:///var/run/docker.sockmyecscontext ecs credentials read from environment
2. 생성한 ECS Context로 배포 환경 전환 (맥락 이동)
$ sudo docker context use myecscontext
myecscontext
$ sudo docker context ls
NAME TYPE DESCRIPTION DOCKER ENDPOINT
default moby Current DOCKER_HOST based configuration unix:///var/run/docker.sock
myecscontext * ecs credentials read from environment
3. 명령어 수행 시 편의를 위해 환경 변수에 액세스 키 설정
$ AWS_ACCESS_KEY="*****" AWS_SECRET_KEY="******" docker compose ls
NAME STATUS
$ export AWS_ACCESS_KEY="*****"
$ export AWS_SECRET_KEY="******"
Step 3 : Run the Compose application on Amazon ECS
compose 파일을 실행해 ECS(not local) 상에서 컨테이너 생성 (시간 소요 주의)
$ sudo docker compose up
WARNING services.build: unsupported attribute
WARNING services.build: unsupported attribute
[+] Running 18/18
⠿ myproject CreateComplete 206.0s
⠿ FrontendTCP80TargetGroup CreateComplete 0.0s
⠿ CloudMap CreateComplete 46.0s
⠿ FrontendTaskExecutionRole CreateComplete 19.0s
⠿ Cluster CreateComplete 5.0s
⠿ DefaultNetwork CreateComplete 5.0s
⠿ BackendTaskExecutionRole CreateComplete 19.0s
⠿ LogGroup CreateComplete 1.0s
⠿ LoadBalancer CreateComplete 122.0s
⠿ Default80Ingress CreateComplete 1.0s
⠿ DefaultNetworkIngress CreateComplete 0.0s
⠿ BackendTaskDefinition CreateComplete 2.0s
⠿ FrontendTaskDefinition CreateComplete 3.0s
⠿ FrontendServiceDiscoveryEntry CreateComplete 1.0s
⠿ BackendServiceDiscoveryEntry CreateComplete 2.0s
⠿ BackendService CreateComplete 65.0s
⠿ FrontendTCP80Listener CreateComplete 3.0s
⠿ FrontendService CreateComplete 66.0s
- ECS 컨텍스트 상에서 docker compose up을 한 경우, 실제로 생성되는 AWS 리소스(CloudMap을 비롯하여 총 21개의 리소스가 생성)
compose 파일을 AWS 리소스 집합으로 변환해주는 CloudFormation 파일로 변환
$ sudo docker compose convert
WARNING services.build: unsupported attribute
WARNING services.build: unsupported attribute
AWSTemplateFormatVersion: 2010-09-09
Resources:
BackendService:
Properties:
Cluster:
Fn::GetAtt:
- Cluster
- Arn
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100...
ECS 상에서 컨테이너 실행되었는지 확인
$ sudo docker compose ps
NAME SERVICE STATUS PORTS
task/myproject/8c142dea1282499c83050b4d3e689566 backend Running
task/myproject/a608f6df616e4345b92a3d596991652d frontend Running mypro-LoadB-1ROWIHLNOG5RZ-1172432386.eu-west-3.elb.amazonaws.com:80->80/http
ECS에서 기동되는 컴포즈 컨테이너 로그 확인
$ sudo docker compose logs
backend | * Serving Flask app "main" (lazy loading)
backend | * Environment: production
backend | WARNING: This is a development server. Do not use it in a production deployment.
backend | Use a production WSGI server instead.
...
frontend | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
frontend | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
frontend | /docker-entrypoint.sh: Configuration complete; ready for start up
frontend | 172.31.22.98 - - [02/Mar/2021:08:35:27 +0000] "GET / HTTP/1.1" 200 212 "-" "ELB-HealthChecker/2.0" "-"
backend | 172.31.0.11 - - [02/Mar/2021 08:35:27] "GET / HTTP/1.0" 200 -
backend | 172.31.0.11 - - [02/Mar/2021 08:35:57] "GET / HTTP/1.0" 200 -
frontend | 172.31.22.98 - - [02/Mar/2021:08:35:57 +0000] "GET / HTTP/1.1" 200 212 "-" "curl/7.75.0" "94.239.119.152"
frontend | 172.31.22.98 - - [02/Mar/2021:08:35:57 +0000] "GET / HTTP/1.1" 200 212 "-" "ELB-HealthChecker/2.0" "-"
AWS Elastic Container Service로 이동해 아래 대시보드 확인
EC2의 로드 밸런서 확인
- 자동으로 로드 밸런서가 하나 생성되고, 각 리스너마다 Fargate 서비스가 대상 그룹으로 지정되어 있는 것 확인 가능
로드 밸런서 DNS 주소로 접속 시 로컬 환경과 마찬가지로 컨테이너가 작동하는 것을 확인
모든 리소스를 삭제하기 위해서는 docker compose down 실행 (시간 소요 주의, clean up을 위해 중지 금지)
$ sudo docker compose down
[+] Running 2/4
⠴ myproject DeleteInProgress User Initiated 8.5s
⠿ DefaultNetworkIngress DeleteComplete 1.0s
⠿ Default80Ingress DeleteComplete 1.0s
⠴ FrontendService DeleteInProgress 7.5s...
# References
- openai (챗 gpt)
https://docs.docker.com/compose/compose-file/compose-file-v3/
https://docs.docker.com/engine/reference/run/#managing-etchosts
https://docs.docker.com/engine/context/working-with-contexts/
https://www.docker.com/blog/docker-compose-from-local-to-amazon-ecs/
https://docs.docker.com/cloud/ecs-integration/#install-the-docker-compose-cli-on-linux
https://aws.amazon.com/ko/blogs/containers/deploy-applications-on-amazon-ecs-using-docker-compose/
'devops bootcamp 4 > 클라우드 서비스 운영' 카테고리의 다른 글
[지속적 통합] 02. 지속적 통합 (0) | 2023.04.20 |
---|---|
[지속적 통합] 01. CI/CD 리뷰 (0) | 2023.04.20 |
[AWS] 08. 보안 (0) | 2023.04.18 |
[AWS] 08. 서비스 노출 (0) | 2023.04.17 |
[AWS] 07. 수평확장 (0) | 2023.04.17 |