Elastic Beanstalk 소개

Elastic Beanstalk은 AWS에서 제공하는 관리형 서비스로, 웹 애플리케이션과 서비스를 쉽게 배포하고 관리할 수 있게 해줍니다. 개발자는 인프라 관리에 신경 쓰지 않고 코드를 업로드하기만 하면, Elastic Beanstalk이 자동으로 인프라를 프로비저닝하고 애플리케이션을 배포해줍니다.

IAM 역할과 정책의 중요성

Elastic Beanstalk은 다양한 AWS 서비스와 상호작용하기 때문에, 필요한 권한을 관리하기 위해 IAM(Identity and Access Management) 역할과 정책이 중요합니다. 올바른 IAM 역할과 정책을 설정하면 애플리케이션이 안전하게 운영되며, 불필요한 권한으로 인한 보안 리스크를 줄일 수 있습니다.

 

 

1. Elastic Beanstalk을 위한 IAM 역할 및 정책 이해

IAM 역할(Role)과 정책(Policy) 개요

IAM 역할(Role)은 특정 AWS 리소스에 접근할 수 있는 권한을 가진 엔터티입니다. 사용자는 역할을 통해 AWS 서비스와 상호작용할 수 있으며, 역할에는 정책(Policy)이 연결되어 있어, 허용된 액션과 리소스를 정의합니다.

Elastic Beanstalk에서의 IAM 역할 사용 사례

Elastic Beanstalk에서 IAM 역할은 애플리케이션이 다른 AWS 서비스 (예: S3, DynamoDB, RDS)와 상호작용할 수 있도록 하는 중요한 구성 요소입니다. 예를 들어, 애플리케이션이 S3에서 파일을 읽거나 쓰기 위해서는 적절한 권한이 있는 IAM 역할이 필요합니다.

 

 

2. Elastic Beanstalk을 위한 IAM 역할 생성

필요한 권한 식별

Elastic Beanstalk에는 기본적으로 EC2 인스턴스, Auto Scaling, Load Balancer 등의 서비스에 대한 권한이 필요합니다. 하지만, 애플리케이션에 따라 추가적으로 S3, CloudWatch, RDS 등 다른 AWS 서비스에 접근해야 할 수도 있습니다.

IAM 역할 생성 단계별 가이드

  • 서비스 정책 생성 : 아래 JSON을 복사하여 " AWSElasticBeanstalkService"  이름으로 IAM 정책을 생성합니다. 
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowCloudformationOperationsOnElasticBeanstalkStacks",
            "Effect": "Allow",
            "Action": [
                "cloudformation:*"
            ],
            "Resource": [
                "arn:aws:cloudformation:*:*:stack/awseb-*",
                "arn:aws:cloudformation:*:*:stack/eb-*"
            ]
        },
        {
            "Sid": "AllowDeleteCloudwatchLogGroups",
            "Effect": "Allow",
            "Action": [
                "logs:DeleteLogGroup"
            ],
            "Resource": [
                "arn:aws:logs:*:*:log-group:/aws/elasticbeanstalk*"
            ]
        },
        {
            "Sid": "AllowECSTagResource",
            "Effect": "Allow",
            "Action": [
                "ecs:TagResource"
            ],
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "ecs:CreateAction": [
                        "CreateCluster",
                        "RegisterTaskDefinition"
                    ]
                }
            }
        },
        {
            "Sid": "AllowS3OperationsOnElasticBeanstalkBuckets",
            "Effect": "Allow",
            "Action": [
                "s3:*"
            ],
            "Resource": [
                "arn:aws:s3:::elasticbeanstalk-*",
                "arn:aws:s3:::elasticbeanstalk-*/*"
            ]
        },
        {
            "Sid": "AllowLaunchTemplateRunInstances",
            "Effect": "Allow",
            "Action": "ec2:RunInstances",
            "Resource": "*",
            "Condition": {
                "ArnLike": {
                    "ec2:LaunchTemplate": "arn:aws:ec2:*:*:launch-template/*"
                }
            }
        },
        {
            "Sid": "AllowELBAddTags",
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:AddTags"
            ],
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "elasticloadbalancing:CreateAction": [
                        "CreateLoadBalancer"
                    ]
                }
            }
        },
        {
            "Sid": "AllowOperations",
            "Effect": "Allow",
            "Action": [
                "autoscaling:AttachInstances",
                "autoscaling:CreateAutoScalingGroup",
                "autoscaling:CreateLaunchConfiguration",
                "autoscaling:CreateOrUpdateTags",
                "autoscaling:DeleteLaunchConfiguration",
                "autoscaling:DeleteAutoScalingGroup",
                "autoscaling:DeleteScheduledAction",
                "autoscaling:DescribeAccountLimits",
                "autoscaling:DescribeAutoScalingGroups",
                "autoscaling:DescribeAutoScalingInstances",
                "autoscaling:DescribeLaunchConfigurations",
                "autoscaling:DescribeLoadBalancers",
                "autoscaling:DescribeNotificationConfigurations",
                "autoscaling:DescribeScalingActivities",
                "autoscaling:DescribeScheduledActions",
                "autoscaling:DetachInstances",
                "autoscaling:DeletePolicy",
                "autoscaling:PutScalingPolicy",
                "autoscaling:PutScheduledUpdateGroupAction",
                "autoscaling:PutNotificationConfiguration",
                "autoscaling:ResumeProcesses",
                "autoscaling:SetDesiredCapacity",
                "autoscaling:SuspendProcesses",
                "autoscaling:TerminateInstanceInAutoScalingGroup",
                "autoscaling:UpdateAutoScalingGroup",
                "cloudwatch:PutMetricAlarm",
                "ec2:AssociateAddress",
                "ec2:AllocateAddress",
                "ec2:AuthorizeSecurityGroupEgress",
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:CreateLaunchTemplate",
                "ec2:CreateLaunchTemplateVersion",
                "ec2:DescribeLaunchTemplates",
                "ec2:DescribeLaunchTemplateVersions",
                "ec2:DeleteLaunchTemplate",
                "ec2:DeleteLaunchTemplateVersions",
                "ec2:CreateSecurityGroup",
                "ec2:DeleteSecurityGroup",
                "ec2:DescribeAccountAttributes",
                "ec2:DescribeAddresses",
                "ec2:DescribeImages",
                "ec2:DescribeInstances",
                "ec2:DescribeKeyPairs",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeSnapshots",
                "ec2:DescribeSubnets",
                "ec2:DescribeVpcs",
                "ec2:DescribeInstanceAttribute",
                "ec2:DescribeSpotInstanceRequests",
                "ec2:DescribeVpcClassicLink",
                "ec2:DisassociateAddress",
                "ec2:ReleaseAddress",
                "ec2:RevokeSecurityGroupEgress",
                "ec2:RevokeSecurityGroupIngress",
                "ec2:TerminateInstances",
                "ecs:CreateCluster",
                "ecs:DeleteCluster",
                "ecs:DescribeClusters",
                "ecs:RegisterTaskDefinition",
                "elasticbeanstalk:*",
                "elasticloadbalancing:ApplySecurityGroupsToLoadBalancer",
                "elasticloadbalancing:ConfigureHealthCheck",
                "elasticloadbalancing:CreateLoadBalancer",
                "elasticloadbalancing:DeleteLoadBalancer",
                "elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
                "elasticloadbalancing:DescribeInstanceHealth",
                "elasticloadbalancing:DescribeLoadBalancers",
                "elasticloadbalancing:DescribeTargetHealth",
                "elasticloadbalancing:RegisterInstancesWithLoadBalancer",
                "elasticloadbalancing:DescribeTargetGroups",
                "elasticloadbalancing:RegisterTargets",
                "elasticloadbalancing:DeregisterTargets",
                "iam:ListRoles",
                "iam:PassRole",
                "logs:CreateLogGroup",
                "logs:PutRetentionPolicy",
                "logs:DescribeLogGroups",
                "rds:DescribeDBEngineVersions",
                "rds:DescribeDBInstances",
                "rds:DescribeOrderableDBInstanceOptions",
                "s3:GetObject",
                "s3:GetObjectAcl",
                "s3:ListBucket",
                "sns:CreateTopic",
                "sns:GetTopicAttributes",
                "sns:ListSubscriptionsByTopic",
                "sns:Subscribe",
                "sns:SetTopicAttributes",
                "sqs:GetQueueAttributes",
                "sqs:GetQueueUrl",
                "codebuild:CreateProject",
                "codebuild:DeleteProject",
                "codebuild:BatchGetBuilds",
                "codebuild:StartBuild"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

 

AWS Elastic Beanstalk과 관련된 리소스에 대해 다양한 권한을 부여하는 정책입니다. 각 섹션(Statement)별로 설명드리겠습니다.

1. AllowCloudformationOperationsOnElasticBeanstalkStacks

  • 설명: 이 섹션은 CloudFormation 스택에서 모든 작업(cloudformation:*)을 허용합니다. 하지만, 해당 스택의 이름이 awseb-* 또는 eb-*로 시작하는 경우에만 허용됩니다.
  • 주요 권한: CloudFormation 관련 작업 전체(cloudformation:*).
  • 적용 대상 리소스: arn:aws:cloudformation:*:*:stack/awseb-*, arn:aws:cloudformation:*:*:stack/eb-*.

2. AllowDeleteCloudwatchLogGroups

  • 설명: 이 섹션은 Elastic Beanstalk과 관련된 CloudWatch 로그 그룹을 삭제할 수 있는 권한을 부여합니다.
  • 주요 권한: CloudWatch 로그 그룹 삭제(logs:DeleteLogGroup).
  • 적용 대상 리소스: arn:aws:logs:*:*:log-group:/aws/elasticbeanstalk*.

3. AllowECSTagResource

  • 설명: 이 섹션은 ECS 리소스에 태그를 붙일 수 있는 권한을 부여합니다. 단, 이 권한은 CreateCluster나 RegisterTaskDefinition과 같은 작업이 수행될 때만 유효합니다.
  • 주요 권한: ECS 리소스에 태그 부착(ecs:TagResource).
  • 적용 대상 리소스: 모든 리소스(*).
  • 조건: ecs:CreateAction이 CreateCluster 또는 RegisterTaskDefinition일 때.

4. AllowS3OperationsOnElasticBeanstalkBuckets

  • 설명: Elastic Beanstalk과 관련된 S3 버킷에 대해 모든 S3 작업을 허용합니다.
  • 주요 권한: S3 관련 작업 전체(s3:*).
  • 적용 대상 리소스: arn:aws:s3:::elasticbeanstalk-*, arn:aws:s3:::elasticbeanstalk-*/*.

5. AllowLaunchTemplateRunInstances

  • 설명: 이 섹션은 EC2 인스턴스를 실행(RunInstances)할 수 있는 권한을 부여합니다. 단, 실행되는 인스턴스는 특정 조건에 따라야 합니다.
  • 주요 권한: EC2 인스턴스 실행(ec2:RunInstances).
  • 적용 대상 리소스: 모든 리소스(*).
  • 조건: ec2:LaunchTemplate ARN이 arn:aws:ec2:*:*:launch-template/*와 일치해야 합니다.

6. AllowELBAddTags

  • 설명: Elastic Load Balancer(ELB)에 태그를 추가할 수 있는 권한을 부여합니다. 단, 이 권한은 로드 밸런서가 생성될 때만 유효합니다.
  • 주요 권한: ELB 태그 추가(elasticloadbalancing:AddTags).
  • 적용 대상 리소스: 모든 리소스(*).
  • 조건: elasticloadbalancing:CreateAction이 CreateLoadBalancer일 때.

7. AllowOperations

  • 설명: 이 섹션은 Elastic Beanstalk 환경에서 애플리케이션을 운영하는 데 필요한 다양한 AWS 서비스에 대한 권한을 광범위하게 허용합니다.
  • 주요 권한: Auto Scaling, EC2, ECS, Elastic Beanstalk, ELB, IAM, CloudWatch, RDS, S3, SNS, SQS, CodeBuild 등 여러 서비스에 대한 권한.
  • 적용 대상 리소스: 모든 리소스(*).

이 정책은 Elastic Beanstalk 환경에서의 인프라와 애플리케이션 관리를 위한 매우 광범위한 권한을 포함하고 있으며, Elastic Beanstalk에 필요한 거의 모든 작업을 수행할 수 있도록 설계되었습니다. 각 권한은 특정 리소스에 제한을 두거나 특정 조건 하에서만 허용되도록 구성되어 있어, 보안성을 유지하면서도 필요한 작업을 수행할 수 있게 합니다.

 

 

  • 서비스 역할 생성 : "aws-elasticbeanstalk-service-role"  이름으로 elastic beanstalk 역할 생성

 

 

  • AWSElasticBeanstalkService 정책에 aws-elasticbeanstalk-service-role 역할 연결

 

 

  • aws-elasticbeanstalk-ec2-role 역할 생성, 아래 정책을 추가합니다.
  • AmazonEC2ContainerRegistryReadOnly,AWSElasticBeanstalkWebTier,
  • AWSElasticBeanstalkWorkerTier
  • AWSElasticBeanstalkMulticontainerDocker,

 

 

  • 생성한 두 역할을 할당 합니다.

 

 

AWS Access Key ID 생성 방법

  • AWS Management Console 로그인
  • IAM 콘솔로 이동
    • 콘솔 상단의 검색창에 IAM을 입력하고, IAM (Identity and Access Management)을 선택하여 IAM 콘솔로 이동합니다.
  • 사용자(User) 선택
    • IAM 대시보드에서 왼쪽 메뉴에서 Users를 클릭합니다.
    • Access Key를 생성할 사용자를 선택합니다. (만약 사용자가 없다면, 새 사용자를 생성해야 합니다.)

 

 

 

  • 사용자(User) 생성
    • Provide user access to the AWS Management Console의 경우 Console 로그인이 필요할 경우만 체크 합니다.
    • 현재 단계에선 group, permission, policy등 설정하지 않고 Next 후 create user 합니다.

 

 

  • 사용자 세부 정보에서 ‘보안 자격 증명’으로 이동
    • 선택한 사용자의 이름을 클릭하여 사용자의 세부 정보를 엽니다.
    • ‘Security credentials’ 탭을 클릭합니다.
  • Access Keys (Access Key ID 및 Secret Access Key) 생성
    • ‘Access keys’ 섹션에서 Create access key 버튼을 클릭합니다.
    • 팝업창이 나타나면, Create access key 버튼을 클릭하여 새 Access Key ID와 Secret Access Key를 생성합니다.

  • Access Keys (Access Key ID 및 Secret Access Key) 생성
    • Command Line Interface를 선택 후 생성합니다.

 

  •  Access Key ID와 Secret Access Key 저장
    • 생성된 Access Key ID와 Secret Access Key를 즉시 안전한 장소에 저장합니다. Secret Access Key는 한 번만 표시되므로, 이후에 복구할 수 없습니다.

 

1. Windows

AWS CLI 설치

  1. 설치 파일 다운로드:
  2. 설치:
    • 다운로드한 .msi 파일을 실행하여 설치 마법사의 지침을 따릅니다.
  3. 설치 확인:
    • 명령 프롬프트 또는 PowerShell을 열고 다음 명령어를 입력하여 설치가 성공적으로 되었는지 확인합니다:
aws --version

 

AWS CLI 설정

  • 명령 프롬프트 또는 PowerShell을 열고 다음 명령어를 입력하여 AWS CLI를 설정합니다:
aws configure


AWS Access Key ID: AWS Management Console에서 생성한 액세스 키 ID를 입력합니다.
AWS Secret Access Key: Access Key ID에 대한 비밀 액세스 키를 입력합니다.
Default region name: ap-northeast-2 리전을 입력합니다.
Default output format: JSON을 사용합니다.

 

 

 

2. macOS

AWS CLI 설치

Homebrew 사용 (권장):

  • Homebrew가 설치되어 있다면 다음 명령어를 사용하여 AWS CLI를 설치합니다:
brew install awscli

 

설치 확인:

  • 터미널을 열고 다음 명령어를 입력하여 설치가 성공적으로 되었는지 확인합니다:
aws --version

 

AWS CLI 설정

  • 명령 프롬프트 또는 PowerShell을 열고 다음 명령어를 입력하여 AWS CLI를 설정합니다:
aws configure


AWS Access Key ID: AWS Management Console에서 생성한 액세스 키 ID를 입력합니다.
AWS Secret Access Key: Access Key ID에 대한 비밀 액세스 키를 입력합니다.
Default region name: ap-northeast-2 리전을 입력합니다.
Default output format: JSON을 사용합니다.

 

 

3. Linux

AWS CLI 설치

  • 대부분의 리눅스 배포판에서는 패키지 관리자를 통해 AWS CLI를 설치할 수 있습니다.
  • Ubuntu에서는 다음 명령어를 사용합니다:
sudo apt update
sudo apt install awscli

 

  • CentOS에서는:
sudo yum install awscli

 

설치 확인:

  • 터미널을 열고 다음 명령어를 입력하여 설치가 성공적으로 되었는지 확인합니다:
aws --version

 

AWS CLI 설정

  • 명령 프롬프트 또는 PowerShell을 열고 다음 명령어를 입력하여 AWS CLI를 설정합니다:
aws configure


AWS Access Key ID: AWS Management Console에서 생성한 액세스 키 ID를 입력합니다.
AWS Secret Access Key: Access Key ID에 대한 비밀 액세스 키를 입력합니다.
Default region name: ap-northeast-2 리전을 입력합니다.
Default output format: JSON을 사용합니다.

 

Scenario

 

1. CodeRepository에 node.js 코드 푸시

2. node.js 코드 ECR로 푸시

3. ECS에서 ECR 컨테이너 지정 후 EC2환경 서비스

4. node.js 코드 실행 확인

 

 

사전 준비

Test Node.js 코드

https://yes5.tistory.com/45

 

Node.js Express 실행 확인 index.html 포함

Node.js 설치먼저, Node.js를 설치해야 합니다.Node.js 다운로드:Node.js 공식 웹사이트로 이동합니다.LTS (Long Term Support) 버전을 다운로드합니다. 이는 안정적이고 장기적으로 지원되는 버전입니다.Node.js

yes5.tistory.com

 

AWS CLI 설치 및 구성

  • AWS CLI가 설치되어 있지 않다면, AWS CLI 설치 가이드를 참고하세요.
  • AWS CLI를 설치한 후, 다음 명령어를 사용하여 AWS 자격 증명을 구성합니다:
aws configure

1. KEYID
2. PASSWORD
3. REGION (ap-northeast-2)
4. 생략 enter

 

Git 설치

  • Git이 설치되어 있지 않다면, Git 다운로드 페이지에서 설치하세요.

Docker 설치 및 설정

https://yes5.tistory.com/46

 

Docker 설치 및 설정 deploying WSL2 distributionsensuring main distro is deployed error 해결

1. Docker 설치Docker는 대부분의 운영 체제에서 설치할 수 있습니다. 아래는 주요 운영 체제별 설치 방법입니다.WindowsDocker Desktop for Windows를 다운로드하고 설치합니다.설치 과정에서 기본 설정을 따

yes5.tistory.com

 

 

AWS CodeCommit 리포지토리 생성

  • AWS Management Console 또는 AWS CLI를 사용하여 리포지토리를 생성할 수 있습니다.

 

IAM 사용자 생성 및 권한 부여

  • AWS Management Console에서 IAM 사용자에게 CodeCommit에 접근할 수 있는 권한을 부여하세요. 사용자에게 AWSCodeCommitFullAccess 정책을 추가하면 됩니다.

 

HTTPS Git 자격 증명 생성 (선택 사항)

  • AWS Management Console의 IAM 서비스에서 "HTTPS Git 자격 증명"을 생성하여 사용자의 Git 자격 증명을 설정할 수 있습니다. 이 자격 증명을 사용하면 Git 명령을 통해 AWS CodeCommit에 접근할 수 있습니다.
  • https://yes5.tistory.com/42
 

AWS code repository 생성 git

https://git-scm.com/download Git - DownloadsDownloads macOS Windows Linux/Unix Older releases are available and the Git source repository is on GitHub. GUI Clients Git comes with built-in GUI tools (git-gui, gitk), but there are several third-party tools

yes5.tistory.com

 

로컬 Git 리포지토리 설정 및 푸시

기존 프로젝트가 있는 경우:

  • 기존 프로젝트 디렉토리로 이동하여 Git 리포지토리를 초기화하고 원격 리포지토리를 추가합니다.
cd /path/to/your/local/repo
git init
git remote add origin https://git-codecommit.ap-northeast-2.amazonaws.com/v1/repos/my-express-app

 

새 프로젝트를 시작하는 경우:

  • 새로운 디렉토리를 생성하고 Git 리포지토리를 초기화한 후, 원격 리포지토리를 추가합니다.
mkdir my-express-app
cd my-express-app
git init
git remote add origin https://git-codecommit.ap-northeast-2.amazonaws.com/v1/repos/my-express-app

git config --global user.email "you@example.com"
git config --global user.name "Your Name"
  • Git을 처음 설정할 때 사용자 이름과 이메일 주소를 지정해야 합니다. 이 정보를 사용하여 커밋을 할 때 작성자가 누구인지 식별합니다.

 

변경 사항 커밋 및 푸시:

  • 파일을 추가하고 커밋한 후, 변경 사항을 AWS CodeCommit 리포지토리에 푸시합니다.
git add .
git commit -m "Initial commit"

# master 브랜치 생성 및 리모트에 푸시
git branch -M master
git push -u origin master

 

Dockerfile 작성

먼저, Express 애플리케이션을 Docker 컨테이너로 빌드할 수 있도록 Dockerfile을 작성해야 합니다. 프로젝트 루트 디렉토리에 Dockerfile을 추가합니다.

# Node.js 이미지를 기반으로 합니다
FROM node:18

# 작업 디렉토리를 설정합니다
WORKDIR /app

# 패키지 파일들을 컨테이너로 복사합니다
COPY package*.json ./

# 의존성 패키지를 설치합니다
RUN npm install

# 애플리케이션 소스 파일들을 컨테이너로 복사합니다
COPY . .

# 애플리케이션이 실행될 포트를 설정합니다
EXPOSE 3000

# 애플리케이션을 실행합니다
CMD ["node", "index.js"]

 

Docker 이미지 빌드:

Docker 이미지를 빌드합니다:

docker build -t my-express-app .

 

Docker 이미지 실행 (로컬 테스트):

로컬에서 Docker 컨테이너를 실행하여 애플리케이션이 잘 작동하는지 확인합니다:

docker run -p 3000:3000 my-express-app

 

 

AWS ECR(Elastic Container Registry) 설정

ECR 리포지토리 생성:

AWS 관리 콘솔에 로그인하고 ECR 서비스로 이동하여 새 리포지토리를 생성합니다.

 

ECR 로그인:

AWS CLI를 사용하여 ECR에 로그인합니다:

aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin <YOUR_ACCOUNT_ID>.dkr.ecr.ap-northeast-2.amazonaws.com
# <YOUR_ACCOUNT_ID> 입력

 

Docker 이미지 태깅 및 푸시:

ECR 리포지토리에 Docker 이미지를 태깅하고 푸시합니다:

docker tag my-express-app:latest <YOUR_ACCOUNT_ID>.dkr.ecr.ap-northeast-2.amazonaws.com/my-express-app:latest
docker push <YOUR_ACCOUNT_ID>.dkr.ecr.ap-northeast-2.amazonaws.com/my-express-app:latest

# <YOUR_ACCOUNT_ID> 입력

 

ECR에 푸시 된 컨테이너 이미지

 

 

AWS ECS(Elastic Container Service) 설정

ECS 클러스터 등록

  •  이름만 지정하여 클러스터를 생성합니다.

 

IAM 역할 생성

IAM 역할은 ECS 인스턴스가 ECS와 통신할 수 있도록 필요한 권한을 제공합니다.

  • AWS Management Console에서 IAM으로 이동합니다.
  • 역할을 선택하고, 역할 생성을 클릭합니다.
  • EC2를 선택하여 EC2 인스턴스에 사용할 역할을 생성합니다.
  • 정책을 추가하여 ECS 관련 권한을 설정합니다. 필요한 권한은 AmazonEC2ContainerServiceforEC2Role 정책을 포함합니다.
  • 역할을 생성한 후, 역할의 IAM 역할 ARN을 기록해 둡니다.

 

인스턴스에 ECS 에이전트 설치:

  • ECS-optimized AMI를 사용하는 경우, ECS 에이전트가 이미 설치되어 있습니다. ECS-optimized AMI는 Amazon Linux 2 또는 Windows Server AMI로 제공됩니다.
  • EC2 인스턴스를 시작할 때, ECS-optimized Amazon Linux 2 AMI를 선택하여 인스턴스를 생성합니다.

https://aws.amazon.com/marketplace/pp/prodview-do6i4ripwbhs2

 

AWS Marketplace: Amazon ECS-Optimized Amazon Linux 2 (AL2) x86_64 AMI

Operating System Linux/Unix, Amazon Linux 2.0.20240709

aws.amazon.com

위 AMI의 Software Price는 무료입니다. 다른 AMI 사용시 Software 요금이 부과될 수 있습니다.

 

 

EC2 인스턴스를 생성할 때 고급 세부 정보에 IAM 인스턴스 프로파일을 생성해놓은 IAM role으로 선택합니다.

사용자 데이터에 해당 명령문을 입력합니다.

#!/bin/bash
echo ECS_CLUSTER=my-express-app >> /etc/ecs/ecs.config

#my-express-app은 ECS클러스터의 이름으로 클러스터 이름과 맞게 입력합니다.

 

 

ECS Task definition

  •  Json을 사용하여 새 테스크 정의를 생성합니다.

{
  "family": "my-express-app",
  "containerDefinitions": [
    {
      "name": "my-express-app",
      "image": "431997274392.dkr.ecr.ap-northeast-2.amazonaws.com/my-express-app:latest",
      "memory": 256,
      "memoryReservation": 128,
      "cpu": 128,
      "portMappings": [
        {
          "containerPort": 3000,
          "hostPort": 3000,
          "protocol": "tcp"
        }
      ]
    }
  ],
  "cpu": "256",
  "memory": "512",
  "networkMode": "bridge",
  "requiresCompatibilities": ["EC2"]
}
  • Task memory와 cpu 할당을 생성한 인스턴스(t3.micro 2 vCpu, 1GB RAM )이하로 설정해야합니다. 
  • container memory와 cpu 할당은 Task 할당 이하로 설정해야합니다.

 

ECS Cluster Task 실행

  • Task definition에서 정의한 패밀리와 시작유형을 EC2로 지정합니다.

 

ECS Cluster 실행 확인

  • Task가 실행중으로 변경되면, ECS cluster에 배정된 인스턴스ip:3000포트로 확인합니다. ( http:// ) ( https:// )

 

AWS

VPC - Internet gateways, NAT gateways, Route tables, Subnets

VPC Security - Network ACLs

EC2

 

 

1. VPC 생성

name : test-vpc

CIDR : 10.90.0.0/16

 

2. Internet gateway 생성

Internet gateway

name : test-igw

 

Internet gateway vpc connect

vpc 연결 : test-vpc

 

 

3. Private Subnet, Public Subnet 생성

Private Subnet-01

vpc : test-vpc

name : test-pri-sub01

CIDR : 10.90.10.0/24

Availability Zone : ap-northeast-2b

 

Public Subnet-01

vpc : test-vpc

name : test-pub-sub01

CIDR : 10.90.1.0/24

Availability Zone : ap-northeast-2a

 

Public Subnet-02

vpc : test-vpc

name : test-pub-sub02

CIDR : 10.90.3.0/24

Availability Zone : ap-northeast-2b

 

 

4. NAT gateway 생성

NAT gateway

name : test-natGateway

 

subnet

test-pub-sub01

 

Allocate Elastic IP address

할당 받은 IP를 생성한 NAT gateway에 배정

 

 

5. Route table 설정

Private Route table

vpc : test-vpc

name : test-routeTable-pri

explicit subnet association : test-pri-sub01

 

routes

0.0.0.0/0 - NAT gateway

10.90.0.0/16 local

 

 

Public Route table

vpc : test-vpc

name : test-routeTable-pub

explicit subnet association : test-pub-sub01

 

routes

0.0.0.0/0 - Internet gateway

10.90.0.0/16 local

 

6. Network ACLs 설정

Private Network ACL

Inbound Rules:

100 HTTP TCP 80 0.0.0.0/0 DENY
110 HTTPS TCP 443 0.0.0.0/0 DENY
120 SSH TCP 22 0.0.0.0/0 DENY
130 Ephemeral TCP 1024-65535 0.0.0.0/0 ALLOW
140 Custom Rule TCP 80 Subnet Range ALLOW
150 Custom Rule TCP 443 Subnet Range ALLOW
160 Custom Rule TCP 22 Subnet Range ALLOW
* ALL Traffic ALL ALL 0.0.0.0/0 DENY

Outbound Rules:

100 HTTP TCP 80 0.0.0.0/0 ALLOW
110 HTTPS TCP 443 0.0.0.0/0 ALLOW
120 Ephemeral TCP 1024-65535 0.0.0.0/0 ALLOW
* ALL Traffic ALL ALL 0.0.0.0/0 DENY

여기서 "Subnet Range"는 사용 중인 서브넷의 IP 주소 범위를 의미합니다. 여기선 10.90.10.0/24

 

Public Network ACL

Inbound Rules:

100 HTTP TCP 80 0.0.0.0/0 ALLOW
110 HTTPS TCP 443 0.0.0.0/0 ALLOW
120 SSH TCP 22 0.0.0.0/0 ALLOW
130 Ephemeral TCP 1024-65535 0.0.0.0/0 ALLOW
* ALL Traffic ALL ALL 0.0.0.0/0 DENY

Outbound Rules:

100 HTTP TCP 80 0.0.0.0/0 ALLOW
110 HTTPS TCP 443 0.0.0.0/0 ALLOW
120 Ephemeral TCP 1024-65535 0.0.0.0/0 ALLOW
* ALL Traffic ALL ALL 0.0.0.0/0 DENY

 

7. Test EC2 생성 

 

ssm-pub 인스턴스를 public 서브넷에 생성

ssm-pri 인스턴스를 private 서브넷에 생성, Key 생성(ssm-test) 후 배정

 

 

ssm-pub 인스턴스에서 ssm-pri ssh 접속

ssh -i /home/ohsung/ssm-test.pem ec2-user@10.90.10.236

 

private subnet에 있는 ssm-pri 인스턴스에서 NAT gateway를 통해 인터넷 통신 확인

AWS

lambda

cloud Watch - event bridge

IAM

 

Etc

slack

 

 

1. IAM role 생성

AmazonEC2ReadOnlyAccess 정책 배정

 

 

2. lambda function생성

Runtime - Python 3.9

Permissions - 1번에서 만든 role 사용

 

  • code 작성 ( local 환경 )

Lambda 함수에서 `requests` 모듈을 사용하는 경우, 해당 모듈을 포함한 배포 패키지를 만들어야 합니다. Lambda는 기본적으로 `requests` 라이브러리를 포함하지 않으므로, 직접 포함시켜야 합니다.

mkdir lambda_function
cd lambda_function
pip install requests -t .
import boto3
import json
import os
import requests

def lambda_handler(event, context):
    # EC2 클라이언트 생성
    ec2 = boto3.client('ec2')
    
    # 사용 가능한 EBS 볼륨 찾기
    volumes = ec2.describe_volumes(
        Filters=[
            {
                'Name': 'status',
                'Values': ['available']
            }
        ]
    )
    
    available_volumes = volumes['Volumes']
    
    # 사용 가능한 EBS 볼륨이 있는지 확인
    if not available_volumes:
        print("No available volumes found.")
        return
    
    # 사용 가능한 EBS 볼륨 정보 생성
    volume_info = ""
    for volume in available_volumes:
        volume_info += f"Volume ID: {volume['VolumeId']}, Size: {volume['Size']} GiB, Availability Zone: {volume['AvailabilityZone']}\n"
    
    # 사용 가능한 EBS 볼륨 정보 출력
    print("Available volumes:\n", volume_info)
    
    # Slack Webhook URL
    slack_webhook_url = os.environ['SLACK_WEBHOOK_URL']
    
    # Slack으로 메시지 전송
    slack_message = {
        'text': f"Available EBS Volumes:\n{volume_info}"
    }
    
    response = requests.post(slack_webhook_url, data=json.dumps(slack_message), headers={'Content-Type': 'application/json'})
    
    if response.status_code != 200:
        raise ValueError(f"Request to Slack returned an error {response.status_code}, the response is:\n{response.text}")
    
    return {
        'statusCode': 200,
        'body': json.dumps('Slack message sent successfully!')
    }

 

  • .zip으로 압축
zip -r ../lambda_function.zip .

 

  • zip 파일 업로드

 

  • Slack app 생성 ( SLACK_WEBHOOK_URL )
  1. Slack API 페이지에 접속합니다.
  2. "Create a Slack App"을 클릭합니다.
  3. App 이름과 Development Slack Workspace를 선택하고 "Create App"을 클릭합니다.
  4. "Incoming Webhooks"을 활성화합니다.
  5. "Add New Webhook to Workspace"을 클릭하고, Webhook을 보낼 채널을 선택합니다.
  6. Webhook URL을 복사해 둡니다

 

  • lambda 환경 변수에 `SLACK_WEBHOOK_URL` 등록

 

  •  Slack 채널 추가 및 앱 등록 후 lambda code test

 

  • cron 등록

cloud watch -> events -> rules -> create rule -> rule type ( schedule ) -> continue in EventBridge Scheduler

 

cron(0 0 ? * 2 *)

0 0은 00:00 (자정)을 의미하고, ?는 특정한 일자를 지정하지 않음을 의미합니다. * * 2 *은 매주 월요일을 나타냅니다.

 

EC2 인스턴스 1대 이상 준비

https://yes5.tistory.com/29

 

AWS EC2 생성 (ubuntu 프리티어)

EC2 검색 > 인스턴스 인스턴스 시작 클릭 이름 지정 OS 선택 (여기선 ubuntu Server 22.04 LTS ) 인스턴스 유형 t2.micro 키 페어 선택 없다면 새 키 페어 생성 .pem으로 생성 putty 사용자라면 .ppk 네트워크 설

yes5.tistory.com

인스턴스 ID 클릭 > 태그 > 태그 관리

DAY : 정지, 가동 기능을 사용 할 요일 선택

TIME : 가동 할 시간 선택 (범위 밖의 시간은 정지 상태)

AUTOSTOP_ENABLE : true 사용, false 미사용

저장

 

IAM 검색 > 액세스 관리 > 정책

 

정책 생성

 

정책 편집기 > JSON

 

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ec2:StartInstances",
                "ec2:StopInstances"
            ],
            "Resource": "arn:aws:ec2:*:*:instance/*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "ec2:DescribeInstances",
                "ec2:DescribeTags",
                "logs:CreateLogGroup",
                "logs:PutLogEvents",
                "ec2:DescribeInstanceStatus"
            ],
            "Resource": "*"
        }
    ]
}

위 코드 내용 복붙

 

다음

 

정책 이름 : EC2_Auto_Start_Stop

설명 : EC2_Auto_Start_Stop

> 정책 생성

 

IAM > 엑세스 관리 > 역할 > 역할 만들기

 

AWS 서비스

 

사용 사례 > Lambda

 

다음

 

권한정책 > 검색창 EC2_Auto_Start_Stop 입력 > 선택 > 다음

 

역할 이름 : EC2_Auto_Start_Stop_Role > 역할 생성

 

Lambda 검색 >  함수 > 함수 생성

 

함수 이름 : EC2_Auto_Start_Stop_Lambda

런타임 : Python 3.8

 

기본 실행 역할 변경 > 기존 역할 사용 

 

EC2_Auto_Start_Stop_Role 선택 > 함수 생성

 

# -*- coding: utf-8 -*-
import boto3
from datetime import datetime

# 서울 리전
region = 'ap-northeast-2'
# 월 ~ 일요일 
t = ["월", "화", "수", "목", "금", "토", "일"]

def lambda_handler(event, context):
    # 람다 호출된 시점의 시간을 구합니다.
    print("start")
    now_date = t[datetime.today().weekday()]
    now_hour = int(datetime.now().strftime('%H')) + 9
    print(f"now >> date: {now_date}, hour: {now_hour}")

    # ec2 인스턴스의 모든 태그를 조회합니다.
    ec2 = boto3.client('ec2', region_name=region)
    response = ec2.describe_tags(
        Filters=[
            {
                'Name': 'resource-type',
                'Values': ['instance']
            }
        ]
    )
    
    # 값 임시 저장
    enable_instances = []
    day_instances = {}
    time_instances = {}
    
    # AUTO_STOP_ENABLE 태그가 true인 값만 추출합니다
    for tag in response['Tags']:
        if tag['Key'] == "AUTOSTOP_ENABLE" and tag['Value'].lower() == "true":
            enable_instances.append(tag['ResourceId'])
        if tag['Key'] == "DAY":
            day_instances[tag['ResourceId']] = tag['Value']
        if tag['Key'] == "TIME":
            time_instances[tag['ResourceId']] = tag['Value']

    for instance in enable_instances:
        try:
            # 요일이 일치하는지 확인합니다.
            days = day_instances[instance].split(",")            
            is_day = False
            for d in days:
                if now_date == d:
                    is_day = True
            
            # 시간이 일치하는지 확인합니다.
            times = time_instances[instance].split("~")
            is_start_time = False
            is_end_time = False
            if int(times[1].strip()) == now_hour:
                is_end_time = True
            elif int(times[0].strip()) == now_hour:
                is_start_time = True

            if is_day == True and is_end_time == True:
                # 중지 인스턴스 호출
                ec2.stop_instances(InstanceIds=[instance])
            elif is_day == True and is_start_time == True:
                # 시작 인스턴스 호출
                ec2.start_instances(InstanceIds=[instance])
        except Exception as ex:
            print(ex)
    
    print("end")

코드 소스 > 코드 복붙 > Deploy

 

트리거 추가 

 

EventBridge 선택

 

룰 이름 : EC2_Auto_Start_Stop

cron(0 */1 * * ? *) 매시 정각에 람다 호출 

추가

 


설정 끝 테스트 시작

 

먼저 test, auto-start-stop 인스턴스 모두 종료

test 인스턴스의 태그
auto-start-stop 인스턴스의 태그

람다 함수가 실행 되면 test 인스턴스만 실행되어야 한다. ( 현재 시간 14시 )

 

Test 클릭

 

now >> date : 현재요일, hour: 현재시간 표시

 

스크립트 실행 결과 test 인스턴스만 실행된 것 확인

+ Recent posts