github actions를 이용한 자동배포 구현이야기

Gwonyeong·2023년 7월 4일
0

유키독

목록 보기
10/11

7월에들어서 나는 소스코드 배포를 위해 aws의 서비스들을 이용해 배포를 시도했다.
회사에서 github actions로 cd를 구현했을 때는 도커를 이용했는데 다음과 같은 순서로 진행했다.

도커를 이용한 배포

  1. github actions의 머신환경 안에서 npm install @nestjs/common 을 실행한 뒤에 (nest 명령어를 사용하기 위해서)
  2. npm build를 실행해준다.
  3. build를 통해 생성된 dist폴더, package.json을 도커 이미지 안에 넣고 npm install을 실행시켜준다.
  4. build된 이미지를 AWS ECR에 push하고
  5. ec2 인스턴스에서 pull 받아 컨테이너를 띄워준다.
    (물론 ecr 레포지토리에 있는 이미지를 삭제하는 로직이나, ec2 인스턴스에서 필요없는 이미지와, 같은 포트를 사용하고 있는 컨테이너를 삭제하는 로직도 함께 실행한다.)

ts파일을 그대로 ec2에 올리는 방법은 별로일까?

내가 ec2의 밖에서 dist 폴더를 만들어 ec2에 올리는 이유는 프리티어 서버 스펙으로 해결하고 싶었기 때문이다.
프리티어의 경우 위의 스펙을 가지는데 1 Gib 메모리가 눈에 띈다. 
npm run build를 실행할 때 메모리를 상당히 크게 사용하는 것으로 확인했는데 도커를 사용하든
, ec2 내에 node를 설치해서 실행하든 컴퓨터의 스팩이 버티지 못했다. (메모리가 부족하다는 에러 메시지가 계속 발생)

이 방법은 소스코드가 변경이 되면 어떠한 경우이든 새로운 도커 이미지를 찍어내야한다는 특징이 있다.

나는 이 특징이 정말 맘에 들지 않았는데 코드를 한 줄, 또는 수백 줄을 바꾸어도 이미지를 새로 만들어야 했기 때문이다.(시간도 약 3~4분이 걸리는데 좀더 빠르게 적용되길 원했다.)

그래서 docker의 volume 명령어를 이용해 다음과 같은 로직을 생각해냈다.

내가 생각한 이상적인 도커 배포방법

  • 일단 github actions를 이용하는 yml파일은 2개가 되어야 한다.
  • 소스코드를 ec2에 올리는 파일, node js 컨테이너를 띄워주는 파일.
  1. 소스코드를 ec2에 올리는 파일은 github에서 소스코드가 변경되면 ec2에서 해당 소스코드 경로를 찾아가 git pull 을 실행시켜주는 간단한 로직이다.
  • 이렇게 되면 소스코드를 변경해도 새로운 도커 이미지를 사용하지 않고 ec2 안에서 컨테이너에서 바라보는 소스코드만 변경하기 때문에 소비되는 시간이 상당히 줄어들 것이라 생각했다.
  1. 소스코드가 변경되면 컨테이너를 재실행 시켜줘야 하므로 해당 소스코드를 바라보고 있는 컨테이너를 restart해준다.

  • 또한 package.json이 변경될 때마다 새로운 이미지를 만들어 node_modules같은 의존성 파일을 컨테이너 안에 넣고 사용하면 되겠다. 라고 생각했는데..

결과적으로 이 방법은 실패했다.
내가 해결하지 못한 에러사항은 다음과 같은데
1. -v 호스트 경로 : 컨테이너 안의 경로

  • 이 명령어는 호스트 경로에 있는 파일들이 컨테이너 안의 경로를 덮어 씌운다는 것.
    - 즉, 이미지 안에 node_modules등의 의존성 파일을 넣어놔도 호스트 경로의 파일이 덮어 씌우기 때문에 사용할 수가 없었다.
  • 그렇다면 컨테이너 안에 있는 node_modules를 호스트 쪽으로 빼줘야 하는데 복사하는 방법은 말이 안된다.
    (파일이 워낙 많아 시간이 오래걸릴 것이고 해당하는 명령어를 찾지도 못했다.)
  1. build된 dist 폴더를 ec2에 옮겨줄 방법을 찾지 못했다.
  • 회사에서 작성한 방법은 dist폴더를 도커 이미지 안에 넣었기 때문에 이미지 자체를 ec2로 들고오면 됐지만 dist안의 소스코드 그대로를 ec2로 옮겨올 방법이 마땅히 생각나지 않았다.
    - git을 이용한다면 dist폴더만을 가지는 레포지토리를 만들어줘야 하는데 매번 빌드해서 dist폴더를 업데이트 시켜주기도 어려울 것 같고, 좋은 방법이 아닌 것 같았다.

결국 나는 지속적으로 새로운 이미지를 만들어주는 방법은 시간이 오래걸리고 비효율적이라 생각해 생각나는 아이디어로 계속 부딪혀 봤지만 실패했다.

아직 도커에 대한 지식이 부족한게 분명하다. 공부를 더 해보고, 도커를 사용하는 회사에서 경험을 해보고, 다시 더 좋은 로직으로 효과적으로 구현해내고 말테다.

name: Deploy to Amazon EC2

on:
  push:
    branches:
      - main
jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - 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: ap-northeast-2

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

      - name: create env
        run: |

          echo "${{secrets.PROD_ENV}}" >> .prod.env

      - name: Delete ECR images
        run: |
          for repo in $(aws ecr describe-repositories --query 'repositories[].repositoryName' --output text); do
            for tag in $(aws ecr list-images --repository-name $repo --query 'imageIds[].imageTag' --output text); do
              aws ecr batch-delete-image --repository-name $repo --image-ids imageTag=$tag;
            done;
          done;

      - name: Build, tag, and push the image(node.js) to Amazon ECR
        id: build-image-node
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          IMAGE_TAG: ${{ github.sha }}
          IMAGE_TAG_NODE: ukeydock

        run: |
          ${{secrets.AWS_DOCKER_LOGIN_CONSOLE}}
          npm install @nestjs/common
          npm run build

          docker build -f prod.dockerfile -t ${{secrets.ECR_REGISTRY}}/ukeydock:prod .
          docker push ${{secrets.ECR_REGISTRY}}/ukeydock:prod

      - name: Get Github Actions IP
        id: ip
        uses: haythem/public-ip@v1.2

      - name: Add Github Actions IP to Security group
        run: |
          aws ec2 authorize-security-group-ingress --group-id ${{ secrets.AWS_SG_ID }} --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32

      - name: Deploy
        uses: appleboy/ssh-action@master

        with:
          host: ${{ secrets.REMOTE_IP }}
          username: ${{ secrets.SSH_ID }}
          key: ${{ secrets.SSH_KEY }}
          port: 22

          script: |
            ${{secrets.AWS_DOCKER_LOGIN_CONSOLE}}

            CONTAINER_ID=$(docker ps -q -f "expose=3000")
            if [ ! -z "$CONTAINER_ID" ]
            then
              docker rm -f $CONTAINER_ID
            fi

            IMAGE_ID=$(docker images -q)
            if [ ! -z "$IMAGE_ID" ]
            then
              docker rmi -f $IMAGE_ID
            fi
            docker pull ${{secrets.ECR_REGISTRY}}/ukeydock:prod


            docker run -d -it --restart unless-stopped -p 3000:3000 ${{secrets.ECR_REGISTRY}}/ukeydock:prod

      - name: Remove Github Actions IP From Security Group
        run: |
          aws ec2 revoke-security-group-ingress --group-id ${{ secrets.AWS_SG_ID }} --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32


profile
부동의 첫사랑

0개의 댓글

관련 채용 정보