티스토리 뷰

728x90
반응형

목차

     

     

    지난 글에선 AWS 설정의 약 절반 가량을 끝냈다.

     

    이번 글에선 남아있는 AWS의 Code Deploy를 비롯해 깃허브 액션의 설정을 마치고,

     

    기본적인 자동 배포가 이루어지는 것을 확인한 뒤 기초적인 NGINX 설정을 해보도록 하겠다.

     

    CodeDeploy

     

    코드 디플로이는 이름 그대로 프로젝트의 자동 배포를 쉽게 구현할 수 있는 서비스이다.

     

    여기서 사용하는 기능은 코드를 운영환경에 맞게 배포하는 역할을 수행하는 것이지만,

     

    그 외에도 서버리스 람다 함수나 스크립트 파일, 멀티미디어 파일 등의 다양한 컨텐츠도 배포가 가능하다.

     

    여기서 우리의 배포 플로우를 다시 보자면 아래와 같은데,

     

    깃허브 액션을 이용해 CodeDeploy에 명령을 해 S3에 올라간 이미지 파일을 가져다 EC2에 배포하는 식이다.

     

    실은 코드디플로이 부분은 이상하게도 매번 헷갈려서 이참에 제대로 정리해 두고 나중에 꺼내볼 생각이다.

     

    Create IAM Role

     

    먼저 IAM 역할을 하나 생성해 주자.

     

    지난 글에서 만들어본 것과 비슷하다.

     

    먼저 역할 만들기를 누르고

     

    위와 같이 설정한 후 다음을 누른다.

    계속 진행.

     

     

    이름을 적당히 정해주고 만들기를 눌러 생성한다.

     

    완료!

     

    Create application

     

    계속해서 코드 디플로이 서비스를 찾아 들어간다.

     

    이어서 애플리케이션을 만든다.

     

    여기서 애플리케이션이란 배포 대상 프로젝트, 혹은 코드를 모아놓은 묶음이라고 이해하면 된다.

     

    애플리케이션 창으로 넘어가 생성 클릭.

     

    이어서 이름을 적당히 지어주고, 컴퓨팅 플랫폼을 EC2/온프레미스로 설정한 후 생성을 눌러준다.

     

    Create Deployment Group

     

    앱이 성공적으로 생성되었다면 위와 같은 화면을 만나게 된다.

     

    계속해서 배포 그룹을 생성하자.

     

    여기서 배포 그룹이란 배포의 대상이 되는 EC2 인스턴스의 논리적인 그룹을 말한다.

     

    그룹이라지만 우리는 하나의 EC2로 구성한다.

     

    먼저 배포 그룹의 이름과 서비스 역할을 설정한다.

     

    여기서 서비스 역할은 지난 글에서 만들었던 역할을 가져다가 사용하면 된다.

     

    이어서 배포 유형과 환경 구성. 위와 같이 설정하면 된다.

     

    마지막으로 위와 같이 설정해 준 뒤 배포 그룹을 생성한다.

     

    로드 밸런서 활성화는 나중에 도메인에 연결하거나 할 때 다시 활성화해도 된다.

     

    짠. 배포 그룹이 완성되었다.

     

    Create Deployment

     

    하지만 쉴 새 없이 앞으로 나가야 한다. 배포 생성을 눌러주자.

    위와 같이 입력해 준다. 배포 그룹은 방금 생성한 것으로 하고

     

    S3 개정 위치는 지난 글에서 생성한 S3 URI를 복사해서 가져오면 된다.

     

    그다음은 옵션이다. 해도 그만 안 해도 그만.

     

    다반 배포 그룹 재정의에 위에서 정의한 구성 (ex. CodeDeployDefault.OnAtTime)이 제대로 설정되어 있는지만 확인하자.

     

    배포 만들기 성공. 뭔가 혼자 배포를 시작하지만 어차피 실패할 테니 무시해도 상관없다.

     

    Github Actions

     

    이어서 깃허브 액션 쪽을 설정하자.

     

    노드JS 프로젝트가 올라가 있는 레포지토리에서 아래와 같이 선택한다.

     

    그다음 위 스크린샷처럼 이름을 정하고 일단 냅다 커밋.

    그럼 이렇게 최상위 폴더에 방금 생성한 yml 파일이 생성된 것을 확인할 수 있다.

     

    비어있는 .yml 파일을 열고 아래와 같이 입력한다.

    name: Deploy to AWS EC2
    
    on:
      push:
        branches: [ main ]
    
    env:
      AWS_REGION: ap-northeast-2
      S3_BUCKET_NAME: ec2-github-actions
      CODE_DEPLOY_APPLICATION_NAME: CoGen_Rebuild_CodeDeploy
      CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: CoGen_Rebuild_DG
    
    jobs:
      build:
    
        runs-on: ubuntu-latest
    
        strategy:
          matrix:
            node-version: [18.17.x]
    
        steps:
        - name: Checkout
          uses: actions/checkout@v3
    
        - name: Use Node.js ${{ matrix.node-version }}
          uses: actions/setup-node@v2
          with:
            node-version: ${{ matrix.node-version }}
    
        - name: Create .env file
          run: |
            touch .env
            echo PORT=${{ secrets.PORT }} >> .env
            echo DB_URL=${{ secrets.DB_URL }} >> .env
            echo JWT_SECRET=${{ secrets.JWT_SECRET }} >> .env
            echo GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }} >> .env
            echo GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }} >> .env
            echo KAKAO_CLIENT_ID=${{ secrets.KAKAO_CLIENT_ID }} >> .env
            echo KAKAO_CLIENT_SECRET=${{ secrets.KAKAO_CLIENT_SECRET }} >> .env
            echo NAVER_CLIENT_ID=${{ secrets.NAVER_CLIENT_ID }} >> .env
            echo NAVER_CLIENT_SECRET=${{ secrets.NAVER_CLIENT_SECRET }} >> .env    
            cat .env
    
        - name: npm install and build
          run: |
            npm install
            npm run build
    
        - 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 }}
    
        - name: Zip and Upload to AWS S3
          run: |
            zip -r deploy.zip ./.env ./package.json ./dist ./scripts appspec.yml
            aws s3 cp deploy.zip s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip
    
        - name: Deploy to AWS EC2 from S3
          run: |
            aws deploy create-deployment \
              --application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
              --deployment-config-name CodeDeployDefault.AllAtOnce \
              --deployment-group-name ${{ env.CODE_DEPLOY_DEPLOYMENT_GROUP_NAME }} \
              --s3-location bucket=$S3_BUCKET_NAME,bundleType=zip,key=$GITHUB_SHA.zip \

    여기서

    env:
      AWS_REGION: ap-northeast-2
      S3_BUCKET_NAME: your-s3-bucket-name
      CODE_DEPLOY_APPLICATION_NAME: your-codedeploy-app-name
      CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: your-codedeploy-deploy-group-name

    이 부분에 여태 설정해 왔던 이름을 그대로 적어준다.

     

    계속해서

        - name: Create .env file
          run: |
            touch .env
            echo PORT=${{ secrets.PORT }} >> .env
            echo DB_URL=${{ secrets.DB_URL }} >> .env
            echo JWT_SECRET=${{ secrets.JWT_SECRET }} >> .env
            echo GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }} >> .env
            echo GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }} >> .env
            echo KAKAO_CLIENT_ID=${{ secrets.KAKAO_CLIENT_ID }} >> .env
            echo KAKAO_CLIENT_SECRET=${{ secrets.KAKAO_CLIENT_SECRET }} >> .env
            echo NAVER_CLIENT_ID=${{ secrets.NAVER_CLIENT_ID }} >> .env
            echo NAVER_CLIENT_SECRET=${{ secrets.NAVER_CLIENT_SECRET }} >> .env

    이 부분과

        - 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 }}

    이 부분에 들어갈 환경변수를 설정하러 가 보자.

    다시 깃허브 레포지토리로 돌아와 위와 같이 누른다.

     

    이어서 우리에게 필요한 모든 시크릿을 설정해 준다.

     

    예를 들면 위와 같이 입력하면 된다.

     

    완성된 모습. 이렇게 정리하면 .env 파일을 레포지토리에 올리는 위험한 짓을 하지 않아도 된다.

     

    위와 같이 설정하고 메인 브랜치에 커밋 및 푸시를 하면

     

    배포에 성공한 것을 확인할 수 있다.

     

    다만 여기서의 성공은 S3에 빌드 파일이 제대로 올라갔다는 것만 확인해 주는 거고,

     

    실제로 EC2에 배포가 되었는지는 CodeDeploy에 들어가서 확인해야 한다.

     

    appspec.yml

     

    마지막으로 S3에 업로드되고 해당 파일들이 EC2에 제대로 배포가 되었을 때 실행될 환경을 구성하자.

     

    먼저 홈 디렉토리에 appspec.yml을 생성한 뒤 아래와 같이 입력한다.

    version: 0.0
    os: linux
    
    files:
      - source: /
        destination: /home/ubuntu/action
        overwrite: yes
    
    permissions:
      - object: /
        pattern: "**"
        owner: ubuntu
        group: ubuntu
        mode: 755
    
    hooks:
      ApplicationStart:
        - location: scripts/run.sh
          timeout: 300
          runas: ubuntu

    이어서 역시 홈 디렉토리에 /scripts 폴더를 만들고 다음과 같이 run.sh 파일을 구성한다. 

    #!/bin/bash
    
    # # Node.js 설치
    # curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash -
    # sudo apt-get install -y nodejs
    
    # Add Node.js and npm to PATH
    export PATH="/home/ubuntu/.nvm/versions/node/v18.17.0/bin:$PATH"
    
    # 권한 부여
    sudo chown -R $USER:$GROUP /home/ubuntu/action
    
    # 애플리케이션 디렉토리 생성 (이미 존재하면 무시됨)
    sudo mkdir -p /home/ubuntu/action
    
    # 애플리케이션 디렉토리로 이동
    cd /home/ubuntu/action
    
    # npm dependencies 설치
    npm install
    
    # 애플리케이션 실행 (백그라운드에서)
    nohup npm start > output.log 2>&1 &

    위의 주석처리된 부분은 배포 시 EC2가 바뀐다거나 할 때 사용하는 옵션이다.

     

    우리는 이미 노드를 EC2에 설치해 두었고, 고정으로 사용할 것이기 때문에 필요가 없다.

     

    로컬에서 하듯이 홈으로 이동해 프로젝트를 빌드하고 실행한다.

     

    위와 같이 구성한 뒤에 다시 모든 내용을 메인 브랜치에 푸시하면

     

    짠. 배포가 성공한다.

     

    이제는 로컬이 아닌 배포용 EC2로 요청을 보내도 응답이 오는 것을 확인할 수 있다.

     

    NGINX

     

    글이 길어져서 다음으로 넘기려 했으나, 설정 자체에 시간이 그리 많이 들지 않는 특성상 NGINX까지 구성하고 끝내겠다.

     

    NGINX와 그 특징, 리버스 프록시에 대한 내용은 다른 글로 대체하고, 여기서는 바로 설정으로 들어가겠다.

     

    [Network]NGINX 튜토리얼

     

    [Network]NGINX 튜토리얼

    목차 여기저기에서 이름은 많이 주워들은 엔진엑스. 좋다! 빠르다! 가볍다! 길래 쓰지 않을 이유가 없어 보여 한 번 써볼까 하고 기웃거리는 것이 이 글의 목적이다. 엔진엑스는 2004년 10월, 러시

    gnidinger.tistory.com

    먼저, 배포용 EC2에 보안접속을 한다.

     

    이어서 늘 그렇듯 업데이트와 함께 엔진엑스를 설치한다.

    sudo apt-get update
    sudo apt-get install nginx -y

    이어서 설정 파일을 생성한다. 이 파일의 이름은 현재 배포 중인 앱이 어떤 역할을 갖는지 식별하는 용도라

     

    적당히 지어주면 된다. 예를 들면 나는 아래와 같이 임의대로 정해주었다.

    sudo vi /etc/nginx/sites-available/node-ts-board

    문서 편집기가 열리면 아래의 설정을 복붙한다.

    server {
        listen 80;
    
        server_name 배포용_EC2_IP_주소;
    
        location / {
            proxy_pass http://localhost:8080;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }
    }

    위 설정은 80번 포트로 들어오는 모든 HTTP 요청을 localhost의 8080으로 전달하는 설정이다.

     

    여기서 8080은 당연히 현재 실행 중인 노드 앱의 포트를 가리킨다.

     

    문서를 저장하고 닫은 이후에는 방금 만들 설정 파일을 활성화시킨다. 아래와 같이 하면 된다.

    sudo ln -s /etc/nginx/sites-available/node-ts-board /etc/nginx/sites-enabled/

    이어서 아래 명령어를 입력해 현재 엔진엑스의 상태를 체크한다.

    sudo nginx -t
    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /etc/nginx/nginx.conf test is successful

    대략 위와 같이 나오면 잘 돌아가고 있는 것이다.

     

    이제 80번 포트로 들어오는 모든 HTTP 요청을 8080 포트에서 실행 중인 노드 앱으로 전달하게 된다.

     

    마지막으로 엔진엑스가 요청을 받을 수 있도록 별개의 방화벽 설정을 해주어야 한다.

     

    먼저 방화벽 관리 도구인 UFW (Uncomplicated Firewall)를 설치한다.

     

    이는 EC2의 보안그룹과 별개로 추가 보안 계층을 쉽게 적용하도록 도와주는 툴이다.

    sudo apt install ufw -y

    이를 사용할 때 주의할 점은, UFW와 보안그룹을 동시에 잘 관리해야 한다는 것이다.

     

    예를 들어 특정 포트(80)를 개방하고 싶으면 UFW와 보안그룹 양쪽에서 열어줘야만 요청을 받을 수 있다.

     

    다시 돌아와서 엔진엑스 프로필 활성화를 마치자.

    sudo ufw allow 'Nginx Full'
    Rules updated
    Rules updated (v6)

    위와 같은 반응이 온다면 성공이다.

     

    이제 80 포트로 보내면 해당 요청이 8080 포트로 자동으로 리다이렉트 된다!

     

    사실 이 정도로 간단히 구현하면, 처음부터 80 포트로 앱을 구성하는 것과 무슨 차이가 있나 싶기도 하다.

     

    하지만 보안, 성능, 확장성 모든 측면에서 볼 때 NGINX를 사용하는 것이 장기적으로 이득이 된다.

     

    Summary

     

    이렇게 해서 노드JS, AWS, Github Actions를 사용한 CI/CD는 사실상 마무리가 되었다.

     

    하지만 글의 중후반부에 이어진 .yml 설정 파일과 스크립트 파일에 대한 설명을 생략했는데,

     

    이는 적다 보니 글이 너무 길어져서 어쩔 수 없는 선택이었다.

     

    나중에 다른 글에 따로 정리한 뒤에 이곳에 링크를 걸 예정이다.

     

    다음 글은, 이왕 AWS를 사용하는 김에 S3 버킷으로 사진과 썸네일을 업로드하는 것을 해볼까 한다.

     

    일단 자동 배포는 끝!

    반응형
    댓글
    공지사항
    최근에 올라온 글
    최근에 달린 댓글
    Total
    Today
    Yesterday
    링크
    «   2024/06   »
    1
    2 3 4 5 6 7 8
    9 10 11 12 13 14 15
    16 17 18 19 20 21 22
    23 24 25 26 27 28 29
    30
    글 보관함