[docker] 간단한 어플을 실제로 배포해보기

이상훈·2023년 6월 23일
0

CICD

목록 보기
10/10

 react로 간단한 애플리케이션을 만들고 테스트해보고 배포해보겠다. 전체적인 흐름은 소스 코드를 작성한 후 local에서 테스트한 후 travis CI를 통해 전체 소스를 AWS에 보내 Elasticbeanstalk에서 이미지를 만들어 컨테이너를 실행해 배포하는 방식이다.

개발

리액트 기본 명령어

  • react app 설치 : 현재 디렉토리에 react-app을 설치하는 명령어다. 정상적으로 설치가 되면 디렉토리 안에 여러 폴더들이 생긴다.

    npx create-react-app ./

  • react app 실행 : react 앱을 실행한다. 아래와 같은 화면이 뜬다.

    npm run start

  • 테스트 실행

    npm run test

  • 빌드

    npm run build


도커로 리액트 앱 실행하기

1. Dockerfile 작성하기
 현재까지는 Dockerfile을 그냥 한 개만 작성해서 사용했지만 Dockerfile은 개발 환경과 운영 환경을 위한 것으로 따로 작성하는 것이 좋다. 아래는 개발 환경을 위한 Dockerfile이다. 파일 이름을 편의상 Dockerfile.dev라 하겠다. 이제껏 만들었던 Dockerfile과 별 다를 바 없다.

Dockerfile.dev

FROM node:alpine

WORKDIR /usr/src/app

COPY package.json ./

RUN npm install

COPY ./ ./

CMD ["npm", "run", "start"]

2. 이미지 빌드
 빌드할 Dockerfile 이름을 -f 옵션으로 명시해주자.

docker build -f Dockerfile.dev -t strangehoon/docker-react-app ./


3. local의 node_modules 폴더 삭제
 npm install 명령어를 입력하면 package.json의 dependencies의 파일들이 다운받아져서 node_modules 폴더 안으로 들어간다. local 환경에서 react 앱을 실행하려면 당연히 node_modules 폴더가 필요하지만, docker 환경에서 리액트 앱을 실행하려면 굳이 local의 node modules가 필요하지 않다. local의 node_modules가 있으면 오히려 빌드 시간이 늘어나는데 COPY ./ ./ 명령어 실행 시 이미 컨테이너에 node_modules가 있는데 한번더 복사가 되어 중복되기 때문이다.


4. 컨테이너 실행
리액트쪽 업그레이드로 인하여 -it를 붙여줘야 한다.

docker run -it -p 3000:3000 strangehoon/docker-react-app


5. Docker Volume 이용해서 컨테이너 실행

docker run -it -p 3000:3000 -v /usr/src/app/node_modules -v ${PWD}:/usr/src/app strangehoon/docker-react-app


6. Docker Compose로 간편화하기

docker-compose.yml

version: "3"
services:
  react:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
     - "3000:3000"
    volumes:
     - /usr/src/app/node_modules
     - ./:/usr/src/app
    stdin_open: true

stdin_open : 리액트 앱을 끌 때 필요

docker compose로 컨테이너 실행

docker-compose up


7. 테스트

docker run -it strangehoon/docker-react-app npm run test

테스트 실행 코드를 docker compose 안에 넣어주면 더 좋다. 아래 코드를 docker-compose.yml에 넣어주자.

tests:
    build:
      context: .
      dockerfile: Dockerfile.dev
    volumes:
      - /usr/src/app/node_modules
      - ./:/usr/src/app
      command: ["npm", "run", "test"]     

운영환경으로 전환하기

  • 개발환경에서 리액트가 실행되는 과정 : 리액트 컨테이너 안에 개발 서버가 있고 정적 파일들이 있다. 브라우저에서 http 요청을 리액트 애플리케이션에 보내면 개발 서버를 통해 브라우저에서 요청한 정적 파일들을 개발 서버가 제공해준다.

  • 운영환경에서 리액트가 실행되는 과정 : 개발에서 사용하는 서버는 개발 환경에 특화된 기능들이 있어서 무겁지만, 운영환경에서는 개발 환경에 특화된 기능들이 필요 없다. 따라서 더 가볍고 빠른 Nginx를 웹 서버로 사용한다. Nginx는 브라우저에서 요청이 오면 개발환경에서와 달리 정적 파일들을 빌드 형태로 제공해준다.

앞서 작성한 dockerfile.dev는 개발환경 전용이므로 운영환경 전용 dockerfile을 작성해보자.

Dockerfile

FROM node:16-alpine as builder
WORKDIR '/usr/src/app'
COPY package.json .
RUN npm install
COPY ./ ./
RUN npm run build

FROM nginx
EXPOSE 80
COPY --from=builder /usr/src/app/build /usr/share/nginx/html

이전에 작성했던 docker-compose.yml의 파일명을 docker-compose-dev.yml로 바꾸고 운영환경 전용 compose 파일을 다시 작성해보자.

docker-compose.yml

version: "3"
services:
  react:
    build: 
      context: .
      dockerfile: Dockerfile
    ports:
     - '80:80'
    volumes:
     - /usr/src/app/node_modules
     - ./:/usr/src/app
    stdin_open: true  

테스트 & 배포

travis CI를 통해 테스트, 빌드

 먼저 앞서 작성한 React 애플리케이션 코드들을 Github repository에 push하자. repository 이름은 docker-react-app으로 하겠다. CICD 툴로 Github actions, Jenkins 등이 있지만 여기서는 Travis CI를 사용하겠다.
Travis CI는 Github에서 진행되는 오픈소스 프로젝트를 위한 지속적인 통합 CI 서비스다. Travis CI를 이용하면 Github repository에 있는 프로젝트를 특정 이벤트에 따라 자동으로 테스트, 빌드하거나 배포할 수 있다,

먼저 Travis CI 웹 사이트에 들어가 자신이 관리하고자 하는 Github repository를 연동하자.

 이제부터는 Github에서 Travis CI로 소스를 어떻게 전달 시킬거며 전달 받은 것을 어떻게 Test 하며 그 테스트가 성공했을 때 어떻게 AWS에 전달해서 배포할 것인지를 설정해줘야 한다. 이러한 설정을 위해서 Travis CI에서는 .travis.yml 파일이 필요하다.

.travis.yml

# sudo : 관리자 권한 갖기
sudo: required

# language : 언어(플랫폼 선택)
language: generic

# services : 도커 환경 구성
services:
  - docker

# before_install : 스크립트를 실행할 수 있는 환경 구성
before_install:
  - echo "start creating an image with dockerfile"
  - docker build -t strangehoon/docker-react-app -f Dockerfile.dev .

# script : 실행할 스크립트(테스트 실행)
script:
  - docker run -e CI=true strangehoon/docker-react-app npm run test -- --coverage

.travis.yml 파일을 작성하고 다시 깃허브에 커밋 푸시하자. 푸시가 끝나고 travis에 들어가보면 정상적으로 테스트가 완료되고 이미지 빌드가 수행되었음을 확인할 수 있다.


AWS의 Elastic BeanStalk에 배포

 AWS Elastic Beanstalk는 Apache, Nginx같은 친숙한 서버에서 Java, NET, PHP, Node.js, Python, Ruby, Go 및 Docker와 함께 개발된 웹 응용 프로그램 및 서비스를 배포하고 확장하기 위한 서비스다. 아래서 보는 도표와 같이 Elastic Beanstalk은 EC2 인스턴스나 데이터베이스 같이 많은 것들을 포함한 "환경"을 구성하며 만들고 있는 소프트웨어를 업데이트할 때마다 자동으로 이 환경을 관리해준다.

AWS에 가서 Elastic Beanstalk 환경을 생성하자. 그리고 앞서 .travis.yml에 아래 코드를 추가하자.

.travis.yml

deploy:
 edge: true
 # provider : 외부 서비스 표시(s3, elasticbeanstalk, firebase 등)
 provider: elasticbeanstalk
 
 # region : 현재 사용하고 있는 AWS의 서비스가 위치하고 있는 물리적 장소
 region: "ap-northeast-2"
 
 # app : 생성된 애플리케이션의 이름
 app: "docker-react-app"
 
 # 생성된 애플리케이션 env의 이름
 env: "Docker-react-app-env-3"
 
 # 해당 elasticbeanstalk을 위한 s3 버킷 이름
 bucket_name: "elasticbeanstalk-ap-northeast-2-624450342306"
 
 # 애플리케이션 이름과 동일
 bucket_path: "docker-react-app"
 
 # 어떤 브랜치에 Push할때 AWS에 배포할 건지
 on:
   branch: master

 흥미로운 점은 Elastic Beanstalk 환경을 생성할 때 자동으로 S3 버킷 1개가 생성되었다는 점이다. S3 버킷은 Elastic Beanstalk 환경의 구성과 애플리케이션 버전에 관련된 파일을 저장하는 데 사용된다. 각각의 Elastic Beanstalk 환경은 고유한 버킷을 가지며, 이 버킷에는 배포된 애플리케이션의 코드와 로그 파일들이 저장된다. 따라서 Elastic Beanstalk의 운영을 단순화하고, 애플리케이션 배포 및 관리를 편리하게 해줌과 동시에 애플리케이션 배포 시 소스 코드를 유지하고 복원할 수 있으며, 로그 파일을 중앙 집중식으로 저장하여 추후 분석이나 모니터링에 활용할 수 있다.


Travis CI의 AWS 접근을 위한 API 생성

 현재까지 Travis CI에서 AWS에 어떤 파일을 전해줄지, AWS에서 어떤 서비스를 이용할건지 .travis.yml 파일에 명시하였다. 하지만 Travis CI와 AWS가 실질적으로 소통할 수 있게 인증하는 부분은 설정해주지 않았다.

인증을 위해서는 AWS에서 제공해주는 key가 필요하다. key는 IAM USER를 생성함으로써 얻을 수 있다. 참고로 일상적인 작업이든 관리 작업이든 Root 사용자를 사용하는 것은 보안상 좋지 않기 때문에 IAM User를 생성하여 적당한 권한을 부여해주는 것이 좋다. 여기서는 AdministratorAccess-AWSElasticBeanstalk라는 정책 권한을 부여했다.

이렇게 얻어진 key들은 보안상 노출되면 안 되기 때문에 .travis.yml에 적으면 안된다. 대신 Travis 웹 사이트 해당 저장소 대시보드의 Environment Variables탭에 보관하고 필요할 때마다 local 환경에서 가져올 수 있게 해줘야 한다.

local 환경에서 Travis CI에서 보관중인 key들을 가져올 수 있게 아래 코드를 .travis.yml에 추가해주자.

deploy:
  edge:true
  provider: elasticbeanstalk
  region: "ap-northeast-2"
  app: "docker-react-app"
  env: "Docker-react-app-env-3"
  bucket_name: "elasticbeanstalk-ap-northeast-2-624450342306"
  bucket_path: "docker-react-app"
  on:
    branch: master
  access_key_id: $AWS_ACCESS_KEY
  secret_access_key: $AWS_SECRET_ACCESS_KEY

다시 빌드하고 푸시한다음 aws의 Elastic Beanstalk탭에서 환경으로 이동 버튼 or 도메인을 클릭하면 정상적으로 react 애플리케이션이 실행되었음을 확인할 수 있다.

profile
Problem Solving과 기술적 의사결정을 중요시합니다.

0개의 댓글

관련 채용 정보