본문 바로가기
Study/AWS

AWS Container Service(ECR,ECS)

by 왕방개 2024. 5. 3.

0.ECR과 ECS 를 이용한 CI/CD Pipeline 설정

=>CI/CD:지속적인 인도와 지속적인 배포

코드의 변경을 지속적으로 관리할 수 있도록 하고 변경된 내용을 빠르게 배포하자는 것

코드의 변경을 지속적으로 관리할 수 있도록 하고 변경된 내용을 빠르게 배포하자는 것

배포를 할 때 개발자가 하는 것이 아니고 프로그램이나 프레임워크가 수행하도록 하고 기존 서비스가 중지되지 않도록 수행하는것을 기본으로 함

 

코드를 변경해서 배포를 하기 위해서는 빌드 과정을 거쳐야 하는데 마이크로 서비스가 아니고 모놀리식의 형태가 만들어지면 빌드시간이 길어지게 되며 빌드 시간 동안 서비스가 중지되어야 한다면 오랜 시간 동안 사용자는 서비스를 받을 수 가 없게 됩니다

 

서버 가상화를 이용하기 전에는 하나의 서버에 애플리케이션 하나를 설치해놓고 서비스를 했기 때문에 이 서버에 새로운 애플리케이션을 배포하려면 기존 애플리케이션을 중지해야만 했는데 가상화 개념이 도입되면서 격리해서 애플리케이션을 배포할 수 있게 되었습니다

 

1.ECR

=>Docker Hub 와 비슷한 이미지 저장소

=>Elastic Container Registry 의 약자로 AWS 에서 제공하는 이미지 저장소

=>이미지 저장소는 Docker Hub 와 같은 무료 이미지 저장소를 이용할 수 있고 별도의 저장소를 만들어서 사용하는 것이 가능

ECS 는 AWS 에서 별도로 만든 저장소

=>ECR 를 사용하는 이유는 이미지 저장을 S3을 이용하기 때문에 가용성이 높음

=>Private 과 Public 모두 가능

대부분의 개발자들은 Kubernetes 를 직접 사용하지 않고 public cloud 에서 제공하는 오케스트레이션 도구를 많이 이용

 

2)구성요소

=>클러스터

-ECS 의 가장 기본적인 단위

-Docker 컨테이너를 실행할 수 있는 가상의 공간

-EC2를 이용해서 생성하는 것도 가능

EC2 를 이용해서 생성하게 되면 리소스를 높은 것을 선택

 

=>Task:Kubernetes 의 Pod 와 유사

-컨테이너를 실행하는 최소 단위

-하나의 Task 에 여러 개의 Image 가 붙여서 실행된다면 내부 통신이 가능

 

=>Task Definition:docker-compose 와 유사

-Docker 명령에서 사용하는 대부분의 옵션을 정의

 

3)Image Repository

=>Docker Hub: Docker 의 공식 이미지 저장소

=>Private Repository: 서버용 운영체제를 설치한 후 저장소를 생성 - 대기업군이 사용하는 방식

=>CSP에서 제공하는 Repository

 

-클라우드 환경에서 개발하는 개발자가 되고자 하는 경우 기업 규모를 보고 사용해봐야하는 레포지토리가 다름

 

4)ECR 서비스 

=>Image Repository

-Docker Hub: Dockern의 공식 이미지 저장소

-Private RepositoryL 서버용 운영체제를 설치한 후 저장소 생성

 

2.ECR(AWS 의 Image Repository)에 이미지를 업로드 할 수 있는 권한을 가진 유저로 로그인

 

1)Image Repository
=>Docker Hub: Docker의 공식 이미지 저장소
=>Private Repository: 서버용 운영체제를 설치한 후 저장소를 생성 - 대기업군이 사용하는 방식
=>CSP에서 제공하는 Repository

2)ECR 서비스에서 Repository 생성
- Private 인지 Public 인지만 선택하면 됩니다.

3)ECR에 이미지를 업로드 할 수 있는 정책 생성 
=>IAM 서비스 접속
=>왼쪽 메뉴에서 정책을 선택
=>정책 생성 클릭하고 JSON을 클릭하고 작성
- ap-northeast-2 은 repository 리전으로 수정
- 641022061021 는 유저를 구분하기 위한 아이디 값이므로 repository 정보에서 가져와서 수정
- djangoapiserver 는 repository 이름이므로 수정

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:CompleteLayerUpload",
                "ecr:UploadLayerPart",
                "ecr:InitiateLayerUpload",
                "ecr:BatchCheckLayerAvailability",
                "ecr:PutImage"
            ],
            "Resource": "arn:aws:ecr:ap-northeast-2:641022061021:repository/djangoapiserver"
        },
        {
            "Effect": "Allow",
            "Action": "ecr:GetAuthorizationToken",
            "Resource": "*"
        }
    ]
}

 

=>정책 이름을 입력하고 생성

 

4)GIT HUB에서 AWS 서비스에 접속하는 OpenID Connect를 사용
=>IAM에서 자격 증명 공급자를 클릭
=>공급자 추가를 클릭
=>OpenID Connect를 선택
=>공급자 URL 과 대상을 설정
https://token.actions.githubusercontent.com

sts.amazonaws.com


5)이전 정책을 사용하는 역할 생성

=>IAM의 왼쪽 메뉴에서 역할 선택
=>역할 생성을 클릭
=>웹 자격 증명을 선택
=>자격 증명 공급자를 선택해서 github를 선택하고 나머지 정보 입력
=>역할 이름을 입력하고 권한 추가 탭에서 이전에 만든 정책을 추가

6)자격 증명 공급자에 이전에 만든 역할을 할당
=>자격 증명 공급자에서 역할 할당을 눌러서 역할을 생성해도 됩니다.

7)소스 코드의 github 액션 파일을 수정해서 로그인되는지 확인
=>role-to-assume 부분을 자신의 역할의 ARN으로 수정

name: django ecs ci/cd

on:
  push:
    branches: ["main"]
  pull_request:
    branches: ["main"]

permissions:
  id-token: write
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3
      
      #파이썬 설치
      - name: Set Up Python 3.10
        uses: actions/setup-python@v4
        with:
          python-version: '3.10'
        
      #의존성 설정
      - name: Install Dependencies
        run: |
          python -m pip install --upgrade pip
          pip install django
          pip install djangorestframework

      #Docker-compose 수행
      - name: Build Docker Compose
        run: docker-compose

      #AWS 로그인
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::641022061021:role/DjangoECR
          role-session-name: sampleSessionName
          aws-region: ap-northeast-2

 

3.코드를 푸시하면 ECR에 이미지를 업로드하고 업로드 한 이미지를 가지고 ECS에 업데이트해서 서비스 하도록 코드를 작성

1)ECS 서비스에 Task를 배포해서 서비스하는 클러스터를 생성
=>ECS 서비스에서 클러스터를 생성

=>태스크 정의를 클릭

=>클러스터에서 위에서 만든 태스크를 기반으로 서비스를 생성
- 시작 유형을 선택하고 FARGATE 선택
- 배포 구성에서 서비스를 선택하고 패밀리에서 작업을 선택한 후 서비스 이름을 입력하고 태스크(파드)의 개수를 선택

=>태스크의 개수를 2개 이상 선택한 경우 로드밸런서를 설정

=>로드밸런서의 End Point로 접속

2)태스크의 definition JSON 파일을 다운로드 받아서 프로젝트의 루트 디렉토리에 복사
=>image 값은 제거

 

3)git action 파일을 수정한 후 push

name: django ecs ci/cd

on:
  push:
    branches: ["main"]
  pull_request:
    branches: ["main"]

permissions:
  id-token: write
  contents: read

env:
  AWS_REGION: ap-northeast-2
  ECR_REPOSITORY: djangoapiserver
  ECS_SERVICE: djangoservice
  ECS_CLUSTER: itstudycluster
  ECS_TASK_DEFINITION: ./djangotask-revision1.json
  CONTAINER_NAME: djangoapiserver

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3
      
      #파이썬 설치
      - name: Set Up Python 3.10
        uses: actions/setup-python@v4
        with:
          python-version: '3.10'
        
      #의존성 설정
      - name: Install Dependencies
        run: |
          python -m pip install --upgrade pip
          pip install django
          pip install djangorestframework

      #Docker-compose 수행
      - name: Build Docker Compose
        run: docker-compose

      #AWS 로그인
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::641022061021:role/DjangoECR
          role-session-name: sampleSessionName
          aws-region: ap-northeast-2

      #ECR 로그인
      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@62f4f872db3836360b72999f4b87f1ff13310f3a

      #ECR에 이미지 푸시
      - name: Build, tag, and push image to Amazon ECR
        id: build-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          IMAGE_TAG: ${{ github.sha }}
        run: |
          # Build a docker container and
          # push it to ECR so that it can
          # be deployed to ECS.
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
        

      #Push 된 이미지를 기반으로 Task를 다시 만들어서 서비스
      - name: Fill in the new image ID in the Amazon ECS task definition
        id: task-def
        uses: aws-actions/amazon-ecs-render-task-definition@c804dfbdd57f713b6c079302a4c01db7017a36fc
        with:
          task-definition: ${{ env.ECS_TASK_DEFINITION }}
          container-name: ${{ env.CONTAINER_NAME }}
          image: ${{ steps.build-image.outputs.image }}
  
      - name: Deploy Amazon ECS task definition
        uses: aws-actions/amazon-ecs-deploy-task-definition@df9643053eda01f169e64a0e60233aacca83799a
        with:
          task-definition: ${{ steps.task-def.outputs.task-definition }}
          service: ${{ env.ECS_SERVICE }}
          cluster: ${{ env.ECS_CLUSTER }}
          wait-for-service-stability: true

=>에러 발생: 자격 증명 공급자에 권한을 부여할 때 ECR 권한은 부여를 했지만 ECS 권한을 부여하지 않아서 ECS 에는 작업을 수행하지 못함

 

4)이전에 만든 역할에 ECS 권한을 추가
=>코드에 변경 내용이 없는데 Git Action을 다시 수행하고자 하면 이 경우에는 Git Hub에서 Action을 선택하고 re-run jobs를 클릭

 

4.로드 밸런서에 도메인을 연결

=>Route 53 서비스의 호스팅 영역에서 연결하고자 하는 호스팅 영역을 선택  

=>레코드 생성 클릭한 후 서브도메인을 입력하고 별칭을 선택해서 로드 밸런서를 선택

 

5.HTTPS 적용

=>지금은 모바일에서 HTTP 사용을 금지
현재의 웹 서비스를 HTTPS로 배포가 되어야 합니다.
서버가 HTTPS로 배포가 되면 클라이언트도 HTTPS로 배포가 되어야 합니다.

1)AWS Certificate Manager 서비스에 접속
=>도메인을 입력해서 인증서 요청
=>인증서를 클릭하고 Route 53에서 레코드 생성 클릭

2)로드 밸런서에 접속
=>리스너 추가 클릭
https 로 변경을 하고 인증서를 선택
=>도메인 연결이 안되면 Route 53 에서 도메인을 다시 등록

 

6.Spring Boot Application을 이용한 CI/CD 구축

1)Spring Boot Application 생성

2)변경 내용 적용 여부를 확인하기 위해서 Controller 생성

import java.util.HashMap;
import java.util.Map;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FrontController {
	@GetMapping("/")
	public Map<String, Object> home(){
		Map<String, Object> data = 
				new HashMap<String, Object>();
		data.put("result", "success");
		return data;
	}
}

 

3)설정 파일을 properties를 사용하지 않고 yml을 사용하므로 application.properties 파일의 이름을 application.yml로 변경을 하고 실행 포트만 설정

server:
  port: 80

 

=>웹 서버 나 클라이언트를 배포할 때 80번 포트로 배포를 수행해야 포트 번호를 적지 않아도 됩니다.
=>실행 한 후 결과 확인

 

4)Dockerfile을 만들어서 도커 이미지로 실행
=>Dockerfile 작성

FROM amazoncorretto:17
CMD ["./mvnw", "clean", "package"]
ARG JAR_FILE=target/*.jar
COPY ./build/libs/*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]

 

=>명령
gradlew clean build

docker build -f Dockerfile -t springapiserver:0.0.1 .

docker run -p 80:80 -dit springapiserver:0.0.1

 

5)프로젝트에 docker-compose.yml 파일을 만들고 실행

=>docker-compose.yml 파일을 만들고 실행

version: "3"

services:
  web:
    build:
      context:
      dockerfile: Dockerfile
    command: "java -jar app.jar"
    ports:
      - "80:80"

=>테스트 명령
docker-compose -f docker-compose.yml up --build