본문 바로가기
웹/Infra

nodejs, gitlab, elastic beanstalk CICD구축

by sun__ 2021. 7. 26.

nodejs서버(DockerFile로 배포가능하면 무엇이든 가능)를 gitlab에 커밋 - AWS S3에 코드를 업로드 - AWS elastic beanstalk + docker + pm2 배포

 

위 과정의 자동화에 대한 포스팅이다.

 

<사전 준비사항>

- AWS Route53을 통한 도메인 생성

- AWS certificate manager를 통한 ssl 인증서 발급

- AWS IAM계정 파두기

- AWS S3 버킷 생성

- 키페어 하나 준비해두기

- EC2 인스턴스 보안그룹 입맛에 맞게 생성 

-> 나중에 필요하면 따로 포스팅할 예정.

 

<Elastic beanstalk 환경생성>

새 환경 생성 버튼 클릭

웹 서버 환경 -> 선택 클릭

 

어플리케이션 이름과 환경 이름 설정

 

관리형 플랫폼 - docker 선택 후 추가옵션 구성 버튼 클릭

로드 밸런서와 오토스케일링 붙일거니까 고가용성 선택

 

인스턴스, 로드밸런서, 보안에서 편집사항 있음.

 

인스턴스 보안 그룹 적절히 지정해서 선택

로드밸런서에서 리스너 추가

 

다음과 같이 추가

 

가상머신 권한에 EC2 키페어 추가

 

환경생성 

 

http로 샘플 애플리케이션이 돌아가는 것 확인

 

 

 

<Route53으로 우리 도메인 연결>

사용할 레코드 생성

별칭으로 방금 생성한 elastic beanstalk 환경에 연결

 

SSL인증이 된 우리 라우터에 연결된 것 확인

 

<gitlab runner 구동>

gitlab runner를 로컬에서 돌려도 되지만, ec2 인스턴스에서 도커로 상시 구동되도록 했다. 돈이 아깝다면 그냥 로컬에서 돌리는게 좋다.

 

ubuntu18로 ec2 인스턴스 만들고 ssh 연결 해서 gitlab-runner와 docker를 cli로 설치해준다.

gitlab-runner 설치:

https://docs.gitlab.com/runner/install/linux-manually.html

 

docker 설치:

https://docs.docker.com/engine/install/ubuntu/

 

깃랩 러너를 등록해준다.

sudo gitlab-runner register

 

여기에 깃랩프로젝트 - settings - cicd - runners expand 에서 나오는 정보와 러너의 태그를 정해준다.


여러 개의 러너를 등록할 수도 있다. 

 

혹시 gitlab-runner 데몬이 종료됐다면 다음과 같이 다시 켜주면 된다.

sudo gitlab-runner start

 

<.gitlab-ci.yml 작성>

프로젝트의 루트 폴더에 작성한다. 

 

runner가 등록된 gitlab 프로젝트의 정해둔 branch가 원격 저장소에 push되면 이 yml파일을 기반으로 runner가 동작한다.

 

gitlab 프로젝트 - settings - cicd - variables에 변수들을 등록할 수 있다.

 

AWS 키페어를 등록할 때의 예시다. END RSA PRIVATE KEY 줄 뒤에 개행(enter)가 반드시 필요하다. 없으면 에러난다..ㅠ

 

.gitlab-ci.yml 예시. 

  1. 깃랩에 올라가는 소스코드 전체를 zip으로 묶어서 S3에 업로드
  2. S3에 올린 소스코드를 기반으로한 어플리케이션 생성
  3. 애플리케이션을 beanstalk 환경 위에서 배포 
#여러 단계로 ci/cd를 수행할 수 있음
stages:
  - run

#gitlab cicd variables에 등록한 변수들을 $와 함께 사용할 수 있움
variables:
  AWS_EB_APP_NAME: ${MY_AWS_EB_APP_NAME}
  AWS_EB_ENV_NAME: ${MY_AWS_EB_ENV_NAME}
  APP_VERSION: "1.0.0"
  S3_BUCKET: ${AWS_S3_EB_BUCKET}
  AWS_ID: ${MY_AWS_ID}
  AWS_ACCESS_KEY_ID: ${MY_AWS_ACCESS_KEY_ID}
  AWS_SECRET_ACCESS_KEY: ${MY_AWS_SECRET_ACCESS_KEY}
  AWS_REGION: ${AWS_REGION}
  AWS_PLATFORM: Docker

deploy_eb:
  stage: run
  image: python:latest
  allow_failure: false
  before_script:
    ##
    ## AWS에서 발급받은 키페어를 .ssh밑에 저장해둔다
    ##
    - mkdir ~/.ssh
    - echo "$SSH_PRIVATE_KEY" >> ~/.ssh/yourKeyName
    - chmod 700 ~/.ssh/yourKeyName

  script: |
    echo "#######################################################"
    echo "#####create elastic beanstalk application(version)#####"
    echo "#######################################################"

    apt-get update
    apt-get install zip
    pip install awscli

	echo "setting environmnet variable"
    export AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}  
    export AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
    export AWS_DEFAULT_REGION=${AWS_REGION}
    
    echo "Creating zip file"  
    zip -r ${AWS_EB_APP_NAME}.zip .

    echo "Creating AWS Version Label"
    AWS_VERSION_LABEL=${AWS_EB_APP_NAME}-${APP_VERSION}-${CI_PIPELINE_ID}
    S3_KEY="front/src/$AWS_VERSION_LABEL.zip" 

    echo "Uploading to S3"
    aws s3 cp ${AWS_EB_APP_NAME}.zip s3://${S3_BUCKET}/${S3_KEY} --region ${AWS_REGION}

    echo "Creating new app version" 
    aws elasticbeanstalk create-application-version \
      --application-name ${AWS_EB_APP_NAME} \
      --version-label $AWS_VERSION_LABEL \
      --region ${AWS_REGION} \
      --source-bundle S3Bucket=${S3_BUCKET},S3Key=${S3_KEY} \
      --description "${CI_COMMIT_DESCRIPTION}" \
      --auto-create-application \


    echo "#######################################################"
    echo "#####deploy elastic beanstalk application(version)#####"  
    echo "#######################################################"

    pip install awsebcli --upgrade --user
    AWS_VERSION_LABEL=${AWS_EB_APP_NAME}-${APP_VERSION}-${CI_PIPELINE_ID} 

    export AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} 
    export AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}    
    export PATH=~/.local/bin:$PATH

    echo "eb init start"
    eb init -i ${AWS_EB_APP_NAME} -p ${AWS_PLATFORM} -k bobsikgoo_key.cer --region ${AWS_REGION}

    echo "eb deploy start"
    eb deploy ${AWS_EB_ENV_NAME} --version ${AWS_VERSION_LABEL}
  only:
    refs:
      - yourBranch
  tags: #runner's tag
  - yourRunnerzTag

 

<Dockerfile 작성>

beanstalk은 도커를 배포한다. 이 때, Dockerfile로 도커 컨테이너를 설정해줄 수 있다. 깃랩 원격 저장소에 올라가지 않는 중요한 파일을 beanstalk이 만들어준 S3컨테이너(외부에서 접근 불가)에 넣고, 배포하면서 꺼내 쓰는 방식을 선택했다.

 

도커로 배포할 땐 pm2대신 pm2-runtime을 쓰라는 글을 봐서 그렇게 했다. 

# Common build stage
FROM ubuntu:18.04

RUN apt-get update
RUN apt-get install sudo -y
RUN sudo apt-get install zip -y
RUN sudo apt-get install curl -y 

#aws cli 다운로드
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
RUN unzip awscliv2.zip 
RUN sudo ./aws/install 

#node 다운로드
RUN curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
RUN sudo apt-get install nodejs -y

COPY . ./app

WORKDIR /app

#.env 가져오기
RUN aws s3 cp yourSecretFilezS3URI ./.env 

RUN npm install
RUN npm install pm2 -g

EXPOSE 3000

#ecosystem.config에 반영 가능한 걸로 보임
ENV NODE_ENV development 

CMD ["pm2-runtime", "start", "ecosystem.config.js"]

 

private repository써서 중요파일까지 한번에 올린다면 이렇게 간단하게 해도 될듯하다.

# Common build stage
FROM node:14.14.0-alpine3.12

COPY . ./app

WORKDIR /app

RUN npm install
RUN npm install pm2 -g

EXPOSE 3000

#ecosystem.config에 반영 가능한 걸로 보임
ENV NODE_ENV development 

CMD ["pm2-runtime", "start", "ecosystem.config.js"]

<ecosystem.config.js 작성>

pm2의 세부 설정을 작성하는 파일. 기본 스크립트 설정만 했다.

 

module.exports = {
  apps : [{
    name: "app1",
    script: 'npm run start',
    //instances: 0 
    //exec_mode: 'cluster'
  }],
};

 

21.8.9월 추가

<cluster 모드를 사용한다면?>

ecosystem.config.js의 스크립트를 말그대로 메인 자바스크립트 파일 경로를 써줘야 한다.

module.exports = {
  apps: [
    {
      name: 'app1',
      script: 'dist/server.js',
      instances: 0,
      exec_mode: 'cluster',
      //merge_logs: true,
    },
  ],
};

 

package.js에 등록해둔 npm run start를 쓰지 못하므로 Dockerfile에 npm run build를 추가했음.

# Common build stage
FROM node:14.14.0-alpine3.12

COPY . ./app

WORKDIR /app

RUN npm install
RUN npm install pm2 -g
RUN npm run build

EXPOSE 3000

#ecosystem.config에 반영 가능한 걸로 보임
ENV NODE_ENV development 

CMD ["pm2-runtime", "start", "ecosystem.config.js"]

 

21.8.25추가

빌드후 정적파일을 nginx로 배포

nginx.config

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       80;
        server_name  www.bobsikgoo.com;

        location / {
            root   /app/build;
            index  index.html index.htm;
            try_files $uri $uri/ /index.html;
        }

        location /api/ {
            proxy_pass https://api.bobsikgoo.com;
            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;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

    include servers/*;
}

 

dockerfile. multi stage build 사용

# Common build stage
FROM node:16.6.0-alpine3.11

WORKDIR /app

COPY . /app

RUN npm install
RUN npm run build

#production stage
FROM nginx:alpine

WORKDIR /app

COPY --from=0 /app/build/ /app/build/
COPY --from=0 /app/nginx.conf /etc/nginx/nginx.conf

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

<참고>

 

Deploying a Node app on Elastic Beanstalk with Gitlab CI

When we hear “Deployment” when talking about a new project and the need to get it up and running, we start thinking about all the possible…

javascript.plainenglish.io

 

 

Node.js 프로젝트를 Docker로 배포하기 #3

많은 개발자들이 Node.js 프로젝트에 pm2나 forever 같은 프로세스 관리자를 사용하고 있다. 이런 프로세스 관리자를 사용하면 프로세스의 기동/중지 그리고 로그 관리를 편하게 할 수 있는 장점이

medium.com

외 공식 문서들..

' > Infra' 카테고리의 다른 글

초보를 위한 쿠버네티스 안내서 - 실습준비  (0) 2021.09.21
k8s - Kube arch object  (0) 2021.09.21
k8s - Kube Architecture  (0) 2021.09.21
k8s - Container Orchestration  (0) 2021.09.21
nodejs로 AWS S3 연동  (0) 2021.07.16