ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • github actions -> ecr -> ecs with ec2 multi module
    AWS 2022. 10. 28. 23:54

    github action이 ecr로 이미지를 올릴 수 있게 iam 에 가서 사용자를 하나 만들어준다.

     

     

    AmazonEC2ContainerRegistryFullAccess 일단은 이거 하나만 추가해준다.

     

    태그 대충 붙여준다.

     

     

     

    만들어준다.

     

    다운로드 해주고 삭제하지 말자.

     

    일단은 github actions의 workflow를 만들어준다.

    on:
      workflow_dispatch:
      push:
        branches: [ master ]
        paths:
          - 'module1/**'
    #  pull_request:
    #    branches: [ master ]
    #    paths:
    #      - 'module1/**'
    
    name: Spring Project `module1` CI on ECR
    
    jobs:
      deploy:
        name: Deploy
        runs-on: ubuntu-latest
    
        steps:
          - name: Checkout
            uses: actions/checkout@v2
    
          - name: Set up JDK 11
            uses: actions/setup-java@v1
            with:
              java-version: 11
    
          - name: Cache Gradle packages
            uses: actions/cache@v2
            with:
              path: |
                ~/.gradle/caches
                ~/.gradle/wrapper
              key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
              restore-keys: |
                ${{ runner.os }}-gradle-
          - name: Grant execute permission for gradlew
            run: chmod +x gradlew
            shell: bash
    
          - name: Build with Gradle
            run: ./gradlew build
            shell: bash
    
          - name: Configure AWS credentials
            uses: aws-actions/configure-aws-credentials@v1
            with:
              aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
              aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
              aws-region: ${{ secrets.AWS_REGION }}
    
          - name: Login to Amazon ECR
            id: login-ecr
            uses: aws-actions/amazon-ecr-login@v1
    
          - name: Build, tag, and push the image to Amazon ECR
            id: build-image
            env:
              ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
              ECR_REPOSITORY: ${{ secrets.REPO_NAME }}
              IMAGE_TAG: module1
            run: |
              # Build a docker container and push it to ECR 
              docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG ./module1
              echo "Pushing image to ECR..."
              docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
              echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"

    이렇게 있고 중요한것은 secrets가 붙은것들이다. AWS_ACCESS_KEY_ID 는 아까 받은 파일에 ACCESS KEY를 뜻하는 거고, AWS_SECRET_ACCESS_KEY는 아까 받은 파일에 SECRET KEY를 뜻한다. AWS_REGION은 나는 ECR이 ap-northeast-2에 있다. repo_name은 각자 알아서 ecr 레포이름을 뜻한다.

     

    이정도로 알아두고, 깃허브에서 secret를 등록해준다.

    이렇게 등록한다.

     

    다음으로 ecs에서 클러스터를 만들어주자.

     

    여기까지 했으면 ecr에 이미지가 올라가 있을 것이다.

     

    다음으로 ecs를 만들어보자

    ecs with ec2로 만들어주자.

     

    클러스터 이름은 multimodule-cluster로 만들고

    온디맨드인스턴스

    유형은 일단은 t2.micro로 만든다. (프리티어 무료)

    키페어는 예전에 만들어둔게 있어서 그거 쓴다.

    포트도 그냥 80번으로 만든다.(나중에 ec2페이지 가서 수정가능)

    없다면 iam 에 가서 역할을 만들어준다. 사용자가 아니다.

    AmazonEC2ContainerServiceforEC2Role 1개만 넣어서 이름 짓고 만든다.

    다시클러스터 만들기로 돌아와서 태그는 클러스터 이름과 똑같이 Name multimodule-clulster로 만들어준다.

    cloudwatch는 일단은 설정 안한다.

     

    클러스터 만들면 다음으로 작업정의를 만든다.

    ec2 선택하고, 다음

    태스크 이름은 multimodule-task 로 만들어주자.

    태스크 역할 매우 중요하다. 이게 iam 에서 역할만들기로 간다. 사용자 아니다.

    아래에 잘 보면 다른 aws 서비스의 사용사례에서 ecs로 선택해야한다.

    일단 이렇게 4개로 해주자. 나중에 다 완성하고 천천히 바꿔보면서 뭐가 필요하고 뭐가 필요없는지 알아보자.

    이렇게 만들면 다시 태스크 정의에서 태스크 역할을 선택가능하다.

     

    먼저 이 블로그부터 가서 로그에 대해 확인한다.

    https://minddong.tistory.com/69

     

    자 일단 이렇게하고 아무것도 선택하지말고 밑으로 내리면 json이 있다.

    json을 누른다음

    https://betterprogramming.pub/deploy-a-spring-boot-app-on-aws-ecs-with-github-actions-669928f62043

     

    Deploy a Spring Boot App on AWS ECS With GitHub Actions

    Deploying to AWS ESC just became more convenient with GitHub actions

    betterprogramming.pub

    여기서 json을 가져온다.

    {
      "executionRoleArn": "arn:aws:iam::497654570788:role/ecsTaskExecutionRole",
      "containerDefinitions": [
        {
          "logConfiguration": {
                    "logDriver": "awslogs",
                    "options": {
                        "awslogs-group": "/ecs/ec2-task",
                        "awslogs-region": "ap-south-1",
                        "awslogs-stream-prefix": "ecs"
                    },
                    "secretOptions": null
          },
          "entryPoint": null,
          "portMappings": [
            {
              "hostPort": 80,
              "protocol": "tcp",
              "containerPort": 9090
            }
          ],
          "command": null,
          "linuxParameters": null,
          "cpu": 0,
          "environment": [],
          "resourceRequirements": null,
          "ulimits": null,
          "dnsServers": null,
          "mountPoints": [],
          "workingDirectory": null,
          "secrets": null,
          "dockerSecurityOptions": null,
          "memory": 500,
          "memoryReservation": null,
          "volumesFrom": [],
          "stopTimeout": null,
          "image": "497654570788.dkr.ecr.ap-south-1.amazonaws.com/learn:latest",
          "startTimeout": null,
          "firelensConfiguration": null,
          "dependsOn": null,
          "disableNetworking": null,
          "interactive": null,
          "healthCheck": null,
          "essential": true,
          "links": null,
          "hostname": null,
          "extraHosts": null,
          "pseudoTerminal": null,
          "user": null,
          "readonlyRootFilesystem": null,
          "dockerLabels": null,
          "systemControls": null,
          "privileged": null,
          "name": "learn"
        }
      ],
      "placementConstraints": [],
      "memory": "500",
      "taskRoleArn": "arn:aws:iam::497654570788:role/ecsTaskExecutionRole",
      "family": "ec2-task",
      "pidMode": null,
      "requiresCompatibilities": [
        "EC2"
      ],
      "networkMode": "bridge",
      "cpu": "450"
    }

    바꿔줄 부분을 바꿔준다. 

    마지막으로 태그에 Name multimodule-task로 지어준다.

     

    작업정의 했으면 다음으로

    서비스를 만들어준다.

    서비스에 생성 누른다.

    시작유형 ec2 , 나머지는 다 채워져있음, 서비스 이름은 module1 로 하고 2개 만들꺼니까 작업개수는 2개로 해준다.

    태그는 module1-service로 해주자.

    일단은 alb 없이 해보자. 제발 2개좀 뜨면 좋겠는데.. autoscalling 도 끄자. 생성!

     

    환경변수는 

    이렇게 넣어주면 된다.

     

    t4g.small 로 만들기 때문에 기본으로 amd 아키텍처로 만들어진 이미지를 arm아키텍처로 만들어야한다. 그래서 yml파일을 변경한다.

    on:
      workflow_dispatch:
      push:
        branches: [ master ]
        paths:
          - 'module1/**'
    #  pull_request:
    #    branches: [ master ]
    #    paths:
    #      - 'module1/**'
    
    name: Spring Project `module1` CI on ECR
    
    jobs:
      deploy:
        name: Deploy
        runs-on: ubuntu-latest
    
        steps:
          - name: Checkout
            uses: actions/checkout@v2
    
          - name: Set up JDK 11
            uses: actions/setup-java@v1
            with:
              java-version: 11
    
          - name: Cache Gradle packages
            uses: actions/cache@v2
            with:
              path: |
                ~/.gradle/caches
                ~/.gradle/wrapper
              key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
              restore-keys: |
                ${{ runner.os }}-gradle-
          - name: Grant execute permission for gradlew
            run: chmod +x gradlew
            shell: bash
    
          - name: Build with Gradle
            run: ./gradlew build
            shell: bash
    
          - name: Configure AWS credentials
            uses: aws-actions/configure-aws-credentials@v1
            with:
              aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
              aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
              aws-region: ${{ secrets.AWS_REGION }}
    
          - name: Login to Amazon ECR
            id: login-ecr
            uses: aws-actions/amazon-ecr-login@v1
    
          - name: Docker Setup QEMU
            uses: docker/setup-qemu-action@v2
    
          - name: Docker Setup Buildx
            uses: docker/setup-buildx-action@v2
    
          - name: Build, tag, and push the image to Amazon ECR
            id: build-image
            env:
              ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
              ECR_REPOSITORY: ${{ secrets.REPO_NAME }}
              IMAGE_TAG: module1
            run: |
              # Build a docker container and push it to ECR 
              docker buildx build --platform linux/arm64 -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG --push ./module1

     

    사용자가 직접 서비스를 생성해서 돌리는것은 성공했다. 이제 자동으로 돌려보자.

    지금 t4g.small인스턴스에서 2개의 module1 이 동적포트로 해서 돌고있다. 

    포트 범위는 동적이면 

    32768 에서 61000이므로 ec2에서 인바운드 규칙을 편집해준다. <-- 65535 로 바꿨다. 잘못된 정보다.

    32768 ~ 65535 까지 동적포트다.

    포트를 열고 확인해보면 잘 된다.

     

    다음으로 module1.yml 을 수정해서 full 자동화를 만들어보자.

    on:
      workflow_dispatch:
      push:
        branches: [ master ]
        paths:
          - 'module1/**'
    #  pull_request:
    #    branches: [ master ]
    #    paths:
    #      - 'module1/**'
    
    name: Spring Project `module1` CI on ECR
    
    jobs:
      deploy:
        name: Deploy
        runs-on: ubuntu-latest
    
        steps:
          - name: Checkout
            uses: actions/checkout@v2
    
          - name: Set up JDK 11
            uses: actions/setup-java@v1
            with:
              java-version: 11
    
          - name: Cache Gradle packages
            uses: actions/cache@v2
            with:
              path: |
                ~/.gradle/caches
                ~/.gradle/wrapper
              key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
              restore-keys: |
                ${{ runner.os }}-gradle-
          - name: Grant execute permission for gradlew
            run: chmod +x gradlew
            shell: bash
    
          - name: Build with Gradle
            run: ./gradlew build
            shell: bash
    
          - name: Configure AWS credentials
            uses: aws-actions/configure-aws-credentials@v1
            with:
              aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
              aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
              aws-region: ${{ secrets.AWS_REGION }}
    
          - name: Login to Amazon ECR
            id: login-ecr
            uses: aws-actions/amazon-ecr-login@v1
    
          - name: Docker Setup QEMU
            uses: docker/setup-qemu-action@v2
    
          - name: Docker Setup Buildx
            uses: docker/setup-buildx-action@v2
    
          - name: Build, tag, and push the image to Amazon ECR
            id: build-image
            env:
              ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
              ECR_REPOSITORY: ${{ secrets.REPO_NAME }}
              IMAGE_TAG: module1
            run: |
              # Build a docker container and push it to ECR 
              docker buildx build --platform linux/arm64 -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG --push ./module1
              echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
    
          - name: Download task definition
            run: |
              aws ecs describe-task-definition --task-definition multimodule-task --query taskDefinition > task-definition.json
    
          - name: Fill in the new image ID in the Amazon ECS task definition
            id: task-def
            uses: aws-actions/amazon-ecs-render-task-definition@v1
            with:
              task-definition: task-definition.json
              container-name: module1
              image: ${{ steps.build-image.outputs.image }}
    
          - name: Deploy Amazon ECS task definition
            uses: aws-actions/amazon-ecs-deploy-task-definition@v1
            with:
              task-definition: ${{ steps.task-def.outputs.task-definition }}
              service: module1-service
              cluster: multimodule-cluster
              wait-for-service-stability: true

    문제는 task-definition을 다운받을 때 위에서 우리가 만들어준 사용자가 권한이 없어서 task-definition을 다운받지 못한다.

    그때 만든 사용자 이름이 multimodule-user 이므로 해당사용자를 찾아서 권한을 추가해준다.

    AmazonECS_FullAccess 이거 한개만 추가해보고 다시 돌려보자.

    위에 보면 wait-for-service-stability 옵션이 true여서 완전히 안정화 될때까지 github action이 돌게 된다. 한 3분 정도 기다리면 된다.

     

    여기까지 하고, ALB를 만들어서 붙여보자.

    ec2 대시보드에 간다.

    로드밸런서 클릭

    생성 누르고 Application Load Balancer 클릭

    로드밸런서 이름은 multimodule-ALB 로 하자.

    internet-facing으로 하고, ipv4 로 하고, vpc ap-northeast-2a 와 ap-northeast-2c 로 하자.

    보안그룹은 하나 만들어주자. 80번 하고 443 번 모두 열어준다. 나중에 http요청오면 https로 바꿀꺼기 때문.

    리스너 포트는 일단은 80으로 하고 만들어준다.(나중에 리다이렉트 설정으로 바꾸면 됨 사진 첨부할꺼임)

    태그도 적어준다.

    대상그룹이 매우 중요하다.

    밑에 create target group로 만들어주자.

    instance 누르고 다음 버튼 클릭, 아무것도 하지말고 만들기 클릭

    그런다음 alb로 돌아와서 만들기 누르면 된다.

     

    다음으로 route53에 가서 로드밸런서를 연결시켜준다.

     

    https://minddong.tistory.com/67

     

    [AWS 자동 배포 시스템] 6. 로드밸런서 구축

    이번 포스팅에서는 로드밸런서를 구축하려고 한다. 추후 로드밸런서를 통하여 private subnet(2a, 2c)에 있는 EC2에 접근할 예정이다. 먼저 서울 리전에 ACM 퍼블릭 인증서를 발급받자. 다음으로 elb의

    minddong.tistory.com

    여기에 설명이 아주 잘되어있다. 참고용으로 보자.

     

    로드밸런서를 만들었으니 이제 https로 리다이렉트 설정 해주자.

    예전에 acm을 만들었는데 지금보니까 없어졌다. 다시 만들어주자.

    요청 누르면 된다.

    검증대기중이면, 인증서 누르고 route53에서 레코드 생성 누르면, 발급됨 상태가 된다.

     

    다시 로드밸런서로 가서 리다이렉트 설정 해주자.

     

    다음으로, ecs로 가서 일단 생성된 서비스를 전부 지우고, ec2에 접속해서 컨테이너도 agent빼고 다 날려준다. 서비스를 다시 만들겠다.

     

    대상그룹에서 https 를 설정했어야하는데.. 못했다. route53에서 로드밸런서와 연결된 도메인 삭제, 대상그룹삭제, 로드밸런서 삭제, 하고 다시 만들자. 대상그룹에서 이번에는 https로 만든다.

     

    서비스를 만들면서 alb를 체크해주고, 역할은 뭔지 잘 모르겠으니, 새역할생성으로 하자. 컨테이너 module1:0:8080 으로 하면 잘 되겠지??

     

    도커 중지된 컨테이너 한방 삭제 docker rm $(docker ps -a -q -f status=exited)

     

    인증사진

    일단 로드밸런서 없이 했고, 다음은 로드밸런서가 있어야한다.

     

    아까까지는 실패했는데 지금 성공함

    작업그룹을 80번으로 다 만들자

    로드밸런서를 만들어준다. ALB로 만들고 http 만 하고 일단은 module1로 대상그룹 설정하고 만든다.

    만든 로드밸런서를 route53에 추가해주고 일단 잘 작동되는지 좀 기다린다.

    정상적으로 작동된다면 그때부터 https 붙이고 교체하면 된다.

     

    https://jybaek.tistory.com/912

     

    Elastic Container Service - CPU, Memory 설정 최적화

    컨테이너와 컨테이너 인스턴스라는 용어로 본문에 많이 등장합니다. 컨테이너 인스턴스는 클러스터에 묶여있는 EC2 인스턴스를 나타냅니다. 표준 표현을 따르다 보니 본문을 읽는

    jybaek.tistory.com

    메모리 cpu를 얼마나 해줄지

Designed by Tistory.