ECR과 ECS를 이용한 컨테이너 이미지 배포 CI/CD

최병훈·2024년 11월 18일
post-thumbnail

1)Spring Boot Project를 만들어서 Git push

  • Spring Boot Project 생성
  • 의존성 설정
  • 80번 포트로 실행할 수 있도록 하기 위해서 application.properties 파일을 삭제하고 application.yaml 파일을 만들어서 작성
    server:
     port: 80
  • 프로젝트에 Controller 클래스를 추가해서 요청에 대한 응답을 생성: FrontController

    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @RestController
    public class FrontController {
       @RequestMapping("/")
       public Map<String, Object> index() {
           Map<String, Object> model = new HashMap<String, Object>();
    
           model.put("result", "success");
    
           return model;
       }
    }
  • 애플리케이션을 실행하고 브라우저서 localhost 로 접속하여 확인
  • GitHub 에 레포지토리를 만들고 push
    레포지토리 : https://github.com/yachae1101/aws-cicd.git
    git init
    git add .
    git commit -m "init"
    git branch -M main
    git remote add origin https://github.com/yachae1101/aws-cicd.git
    git push -u origin main

2)Spring Boot Web Project를 위한 Dockerfile 생성

  • Dockerfile
    FROM amazoncorretto:17
    CMD ["./mvnw", "clean", "package"]
    COPY ./build/libs/*.jar app.jar
    ENTRYPOINT ["java", "-jar", "app.jar"]
  • 애플리케이션 빌드를 수행
    ./gradlew clean build
  • 이미지 빌드를 수행후 이미지 생성 확인
    docker build -t aws-cicd .
    docker images
  • 이미지를 가지고 컨테이너를 만들어서 실행 확인
    docker run -d --name aws-cicd-container -p 80:80 aws-cicd
  • 브라우저에서 localhost 에 접속하여 확인

3)GitHub에 push 될 때 이미지를 빌드하도록 GitHub Actions 파일을 추가

  • .github/workflows 디렉토리를 만들고 그 안에 yaml 파일을 추가해서 작성

    name: AWS CI CD
    on:
      push:
        branches: ["main"]
    
    jobs:
      # Spring Boot 애플리케이션을 빌드하여 도커허 브에 푸시하는 과정
      build-docker-image:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v3
    
          # Java 17 세팅
          - name: Set up JDK 17
            uses: actions/setup-java@v3
            with:
              java-version: '17'
              distribution: 'temurin'
    
          # gradlew 권한 설정
          - name: Grant execute permission for gradlew
            run: chmod +x gradlew
    
          # Gradle 빌드 엑션을 이용해서 프로젝트 빌드
          - name: Build with Gradle
            uses: gradle/gradle-build-action@v2.6.0
            with:
              arguments: build
  • 코드를 push 하고 GitHub Action 을 통해 이미지 빌드가 성공하는지 확인

4)이미지를 만들어서 이미지 레지스트리에 푸시

  • AWS에 저장소를 생성(ECR 서비스에 생성)
    [Amazon Elastic Container Registry] - [프라이빗 리포지토리] - [생성]
  • ECR 에 이미지를 푸시할 수 있는 정책을 생성(IAM 서비스에서 수행)
    • [IAM] - [정책] - [정책 생성]을 클릭하고 JSON을 선택 후 작성
      {
          "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:<계정번호>:repository/<레포지토리이름>"
              },
              {
                  "Effect": "Allow",
                  "Action": "ecr:GetAuthorizationToken",
                  "Resource": "*"
              }
          ]
      }
    • 정책 이름 private-image-push 를 설정하고 [정책 생성] 클릭
  • 자격 증명 공급자에게 역할(웹 자격 증명)을 할당
    • GitHub 조직 : 계정 이름
    • 이미지를 푸시할 수 있는 권한 private-image-push 과 ECR 서비스에 대한 접근 권한을 부여
  • GitHub에서 푸시가 될 때 AWS에 로그인이 되는지 확인

    • Git Action 파일 수정
      role-to-assume 값은 aws의 role에서 생성된 것을 확인해서 작성

      name: AWS CI CD
      on:
        push:
          branches: ["main"]
      
      permissions:
        id-token: write
        contents: read
      
      jobs:
        # Spring Boot 애플리케이션을 빌드하여 도커허 브에 푸시하는 과정
        build-docker-image:
          runs-on: ubuntu-latest
          steps:
            - uses: actions/checkout@v3
      
            # Java 17 세팅
            - name: Set up JDK 17
              uses: actions/setup-java@v3
              with:
                java-version: '17'
                distribution: 'temurin'
      
            # gradlew 권한 설정
            - name: Grant execute permission for gradlew
              run: chmod +x gradlew
      
            # Gradle 빌드 엑션을 이용해서 프로젝트 빌드
            - name: Build with Gradle
              uses: gradle/gradle-build-action@v2.6.0
              with:
                arguments: build
      
            # AWS 로그인
            - name: Configure AWS Credentials
              uses: aws-actions/configure-aws-credentials@v4
              with:
                role-to-assume: <자신의 ARN>
                role-session-name: sampleSessionName
                aws-region: ap-northeast-2
    • git push 후 action 에서 로그인 확인

  • image를 ECR에 push 하기 위한 작업을 git action에 추가

    name: AWS CI CD
    on:
      push:
        branches: ["main"]
    
    permissions:
      id-token: write
      contents: read
    
    env:
      ECR_REPOSITORY: aws-cicd
    
    jobs:
      # Spring Boot 애플리케이션을 빌드하여 도커허 브에 푸시하는 과정
      build-docker-image:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v3
    
          # Java 17 세팅
          - name: Set up JDK 17
            uses: actions/setup-java@v3
            with:
              java-version: '17'
              distribution: 'temurin'
    
          # gradlew 권한 설정
          - name: Grant execute permission for gradlew
            run: chmod +x gradlew
    
          # Gradle 빌드 엑션을 이용해서 프로젝트 빌드
          - name: Build with Gradle
            uses: gradle/gradle-build-action@v2.6.0
            with:
              arguments: build
    
          # AWS 로그인
          - name: Configure AWS Credentials
            uses: aws-actions/configure-aws-credentials@v4
            with:
              role-to-assume: <자신의 ARN>
              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에 push
          - 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
  • git push 후 action 확인
  • AWS ECR에 image가 업로드 되었는지 확인
  • 코드를 수정하고 push 하면, git action에 의해 build되고 ECR 에 업로드된다.

5)배포된 이미지를 가지고 ECS에 배포해서 CICD 마무리

  • ECS 서비스에서 Cluster 와 Task 그리고 Service를 생성
    필요하면 Load Balancer 도 추가
    • Cluster
      • 클러스터 이름 : BH-Cluster
      • 인프라 : AWS Fargate
    • Task
      • Task 이름 : aws-cicd
      • 컨테이너 이름, 컨테이너 : nginx
    • Service 생성
      • 컴퓨팅 옵션 : 시작 유형
      • 배포 구성
    • Load Balancer 추가
      • 로드밸런서 유형 : Application Load Balancer
      • 이름 : BH-loadbalancer
  • 서비스에서 생성 확인
  • 태스크의 json 파일을 다운로드 받아서 프로젝트에 복사를 하고 image 부분을 제거: 이미지는 푸시한 이미지를 다운로드 받을 거라서 기존 이미지는 필요없음
    • 루트 디렉토리 하위에 task-definition.json 파일 생성
    • [Amazon Elastic Container Service] - [태스크 정의] - [태스크] - [JSON] - [클립보드로 복사] 후 task-definition.json 에 붙여넣기
    • image 정의 부분을 제거 (아래 부분을 제거)
        "containerDefinitions": [
          {
            "image": "nginx", <- 제거
  • ECR에 이미지를 푸시하기 위해서 만든 Role에 ECS를 사용할 수 있는 정책을 추가
    AmazonECS_FullAccess 권한을 추가
  • workflow 파일을 수정 후 push

    name: AWS CI CD
    on:
      push:
        branches: ["main"]
    
    permissions:
      id-token: write
      contents: read
    
    env:
      ECR_REPOSITORY: aws-cicd
      AWS_REGION: ap-northeast-2
      ECS_CLUSTER: BH-Cluster
      ECS_SERVICE: aws-cicd-service
      CONTAINER_NAME: nginx
      ECS_TASK_DEFINITION: ./task-definition.json
    
    jobs:
      build-and-deploy:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v3
    
          # Java 17 세팅
          - name: Set up JDK 17
            uses: actions/setup-java@v3
            with:
              java-version: '17'
              distribution: 'temurin'
    
          # gradlew 권한 설정
          - name: Grant execute permission for gradlew
            run: chmod +x gradlew
    
          # Gradle 빌드 엑션을 이용해서 프로젝트 빌드
          - name: Build with Gradle
            uses: gradle/gradle-build-action@v2.6.0
            with:
              arguments: build
    
          # AWS 로그인
          - name: Configure AWS Credentials
            uses: aws-actions/configure-aws-credentials@v4
            with:
              role-to-assume: <자신의 ARN>
              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에 push
          - 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
    
          # 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 }}
    
          # ECS에 태스크를 배포
          - 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

0개의 댓글