[TroubleShooting] P2 배달앱 만들기 Day2

Son_Doobu96·2023년 1월 27일
1

Project2 TroubleSooting

목록 보기
2/4
post-thumbnail

Day2

# Day2의 목표
GitHub Action을 이용해 자동으로 ECR에 도커 이미지를 푸쉬 후 ECS를 이용해 이를 배포한다.
Mongo 이미지를 ECS를 이용해 배포하고 WAS와 연결한다.
배포한 WAS에 HTTPS를 적용한다.

◎ Milestone 4

마일스톤 4단계에서는 ECR의 이미지를 ECS를 통해 배포하고 로드밸런서와 연결합니다.
Mongo 이미지를 ECS를 통해 배포합니다.

■ 처음으로 마주한 문제

Mongo 이미지를 ECS에 배포하는 과정에서부터 문제가 있었다.

바로 개념적인 부분에서 헷갈렸던 것인데 WAS를 ECS로 배포하는 과정은 크게 문제를 겪지 않았었는데 Mongo를 배포하려하니 처음으로 당황했던 점은 WAS는 내가 이미지를 만들어서 그 이미지를
ECR에 푸쉬한 후 배포를 했는데 Mongo는 내가 만들지 않았는데 그게 가능한건가...? 하는
기본 개념이 흔들리는 문제가 있었다.

하지만 그 답은 공식문서에서 금방 찾을 수 있었다.
도커 이미지를 ECR에 푸쉬하는 공식문서

docker tag <이미지ID> aws_account_id.dkr.ecr.region.amazonaws.com/my-repository:tag

처음 생각했던 해답은 결국 ECS에 배포하는 것이 ECR에 푸쉬된 이미지를 활용해 배포하는 것이므로
내 Local의 Mongo이미지를 ECR의 새로운 리포지토리로 푸쉬하면 해결할 수 있겠구나!
라고 생각하고 프로젝트를 진행했다.

하지만 Mongo 이미지를 푸쉬하는데에서도 에러를 만날 수 있었다.
End Of File 에러를 만나게 되었는데. 문제를 해결하기 위해 구글링을 하면서 찾은 출처들에서는
내가 찾아보던 EOF 에러에 대한 대표적인 해결책 출처

--no-include-email

을 통해 문제를 해결해야 한다고 조언하고 있었지만 문제가 잘 해결되지 않았다.

그렇게 구글링을 이어가던 중 .docker 경로에 config.json이라는 aws인증을 정의한
파일이 있다는 내용을 찾게 되었고 이 config.json 파일의 경로가 root 디렉토리가 아니라
home 디렉토리에 있으니 sudo 명령어를 붙이지 말고 docker push를 하면 되지 않을까 생각이 들어
그렇게 해보니 바로 해결됐다...

내가 겪은 문제들을 바탕으로 EOF 에러를 만났을때의 해결책을 정리할 수 있을 것 같다.
1. config.json 파일의 경로를 확인하고 Push를 진행한다.
2. 리포지토리에 푸쉬관련 권한이 제대로 설정되어 있는지를 확인한다.

★ 반전

사실 Mongo와 같은 DockerHub를 통해 Pull받을 수 있는 이미지들은 Local로 Pull후
리포지토리에 푸쉬하는 복잡한 과정을 거치지 않아도 된다... 그냥 DockerHub에 있는걸 가져다 쓰면 된다...ㅠㅠ

■ 두 번째로 마주한 문제

Mongo 이미지를 ECS에 배포한 후 이를 로드밸런서에 연결해 보는 연습을 해보라고 엔지니어님께서 말씀하셨는데 사실 처음에는 이해가 잘 안되었다.
DB에 task가 하나인데 로드밸런서를 왜 달아야 하는거지? 그리고 ALB와 NLB의 차이에 대해서도 머릿속에서 대 혼란이 벌어지기 시작했다.

DB에 로드밸런서를 다는 이유는 로드밸런서를 만들고 설정하는 연습을 위해서라고 답을 들었다.
그리고 ALB와 NLB의 차이는 이번에 Mongo서비스와 로드밸런서를 연결하면서 확실하게 알게 되었다.

ALB =
1. L7계층의 로드밸런서를 지원한다.
2. 앱프로토콜을 사용가능하다.(HTTP/HTTPS)
3. SSL 적용이 가능하다.

NLB =
1. L4계층의 로드밸런서를 지원한다.
2. 앱프로토콜의 사용이 불가능하다.(TCP/IP 사용)
3. SSL적용이 불가능하다.

이러한 차이를 확인해보면서 Mongo의 경우 27017포트와 TCP를 사용하므로 NLB를 적용해야 한다는 것을 확인 후 작업을 계속해서 진행했다.

NLB와 Mongo서비스를 연결하는 작업 또한 꽤 오랜 시간이 걸렸다.
프라이빗 서브넷을 잘 못끼워 넣어 서비스가 제대로 실행되지 않는 문제부터
타깃 그룹을 잘 못 설정하여 서비스가 정상적으로 작동하지 못하는 문제까지 여러 문제를 겪으면서 확실하게 깨닫게 된 부분이 있었다.

로드밸런서는 부하 분산을 위해 서버의 앞 단에 위치한다.
다른 말로 로드밸런서는 누구로부터 받아서 누구에서 전달할지를 정해주는 분배의 저울이다.
즉 리스너와 타겟그룹을 옳바르게 일치시켜 준다면 로드밸런서가 제대로 작동하지 않을 수가 없다.

이러한 깨달음을 얻고 나서 문제는 정말로 쉽게 해결할 수 있었다.

▶ Milestone4에서 배운 점

환경 변수에 대한 이해를 확실히 할 수 있었다는 점에서 매우 뜻깊은 과정이었다.
DB에 아무나 접속하면 안되기 때문에

MONGO_INITDB_ROOT_USERNAME=?

라는 환경변수를 설정해줬었는데 DockerHub의 공식 문서를 읽으면서
이 환경 변수가 몽고 DB에 접속하기 위한 환경 변수를 설정하는 걸 알게 되었다.
DockerHub Mongo 이미지 공식문서

따라서 이 환경 변수를 적절하게 이용해 무분별한 사용자의 접속을 차단할 수 있다는 점도 알게 되었다.

◎ Milestone 5

마일스톤 5단계에서는 MongoDB와 WAS서버를 연결하고 WAS의 ECS배포를 자동화 하는 것에
목표를 두고 있었습니다.

■ 처음으로 마주한 문제

자동화 단계를 진행전에 ECS로 배포한 WAS서버에서 MongoDB에 접속할 수 있도록
task-definition을 개정 후 ECS 서비스 업데이트를 진행했다.
하지만 서비스가 계속해서 중단되는 문제를 만날 수 있었다.

내가 만난 에러 로그
ResourceInitializationError: unable to pull secrets or registry auth: pull command failed:

ResourceInitializationError: unable to pull secrets or registry auth: execution resource retrieval failed: unable to retrieve secret from asm: service call has been retried

구글링으로 해당 문제를 찾아 본 결과 Secret Manager에서 환경변수를 불러오지 못해 발생한 문제였다.
해당 문제를 해결하기 위해 구글링을 하면서 처음으로 AWS의 친절함에 감동했다.
문제 해결을 위해 찾아본 AWS 공식문서

문제의 해결방법을 요약하자면 당신의 권한 또는 역할에서 아래 3개의 권한을 추가해주라는 것이었다.

ssm:GetParameters, secretsmanager:GetSecretValue, kms:Decrypt

이렇게 쉽게 문제가 해결됐다 생각하고 다시 서비스를 생성해보았으나 문제가 계속 반복되고 있었다...
뭐가 문제일까를 계속해서 찾아보다 보니 권한을 줘야 할 태스크 실행 역할이 아닌 엄한 내 사용자에 권한을 주다보니 문제가 해결되지 않고 있던 것이었다..ㅠㅠ 잘 좀 보고 하자

■ 두 번째로 마주한 문제

두번째 문제는 GitHub Actions을 이용해 ECS에 자동으로 배포하는 Workflow를 추가하며 발생했습니다.

GitHub Action의 ECS 자동배포 Workflow의 기본 틀을 이용해서 처음 작성한 yml파일입니다.

name: Deploy to Amazon ECS

on:
  push:
    branches: 
      - main
  pull_request:
    branches:
      - main

env:
  AWS_REGION: ap-northeast-2                          # set this to your preferred AWS region, e.g. us-west-1
  ECR_REPOSITORY: devops03-teamf                      # set this to your Amazon ECR repository name
  ECS_SERVICE: teamf-was-service-v2                   # set this to your Amazon ECS service name
  ECS_CLUSTER: teamf-was-cluster                      # set this to your Amazon ECS cluster name
  ECS_TASK_DEFINITION: teamf-was-task-definition-v2   # set this to the path to your Amazon ECS task definition
                                                       # file, e.g. .aws/task-definition.json
  CONTAINER_NAME: teamf-was-container-v2              # set this to the name of the container in the
                                                       # containerDefinitions section of your task definition

permissions:
  contents: read

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    environment: production

    steps:
    - name: Checkout
      uses: actions/checkout@v3

    - 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: ${{ env.AWS_REGION }}
        aws-output-format: json

    - name: Login to Amazon ECR
      id: login-ecr
      uses: aws-actions/amazon-ecr-login@v1

    - 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 ./TeamF-WAS/
        docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
        echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
    - 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: ${{ 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@v1
      with:
        task-definition: ${{ steps.task-def.outputs.task-definition }}
        service: ${{ env.ECS_SERVICE }}
        cluster: ${{ env.ECS_CLUSTER }}
        wait-for-service-stability: true

주석을 보면서 yml파일을 작성했었는데 Task-Definition만 이름이 아닌 경로를 기입하라고 적혀있는 것이 처음에 이상하다고 생각은 했지만 이름을 입력한 후 작업을 진행했었다.

하지만 걱정 했던대로 역시는 역시 에러를 만나게 되었다.

Task definition file does not exist: teamf-was-task-definition-v2

Task Definition 파일이 존재하지 않는다는 내용의 에러였고 해당 문제를 해결하기 위해 AWS 공식문서를 확인했고 해결책으로 task-definition.json 파일에 작업정의 내용을 복사하여 채워 준 후 파일의 경로로 환경 변수를 변경해주면서 문제를 해결할 수 있었다.
Task Definition AWS 공식문서

▶ Milestone5에서 배운 점

3티어 개념에 대한 확실한 이해

3티어 아키텍처의 개념을 확실하게 정립할 수 있었고 이 과정에서 네트워크에 대한 학습까지 같이
진행할 수 있어서 매우 좋았다.

클라이언트 -(ALB:80:3000)> WAS -(:27017:27017)> DB

이 과정의 반복적인 수행을 통해 이해력을 높일 수 있게 되어 서버를 운영하며 발생하게 되는 문제를 어디에서 해결해야 하는지도 이제는 파악할 수 있게 되었다.
(이게 마일스톤 10번에서 많은 도움이 되었다.)

profile
DevOps를 꿈꾸는 엔지니어 지망생!

0개의 댓글