도커와 CI 환경 - 4

지원·2024년 3월 15일
0

Docker

목록 보기
4/7

이번에는 개발환경에서는 리액트 앱을 개발하고 만든 리액트 앱을 테스트 및 배포를 해보자.

간단하게 보면 개봘환경에서 개발 -> 개발 된 것을 테스트 -> Production 환경에 배포

  • 더 자세한 흐름으로 알아보자.
  • 개발환경에서 개발 -> Github 에 소스를 push -> Featrue 브랜치에서 Main 브랜치에 Pull 요청
  • Travis CI 에서 Main 브랜치에서 push 된 코드를 가져가서 개발된 소스가 잘 작동하는지 먼저 Test 를 한다.
  • 만약 테스트가 성공하면 호스팅 사이트(AWS , Azure , Google...)로 보내서 배포를 한다.

리액트 앱 설치하기

  • node 를 받으면 리액트는 매우 간단하게 설치할 수 있다.
  • npx create-react-app DIR_NAME (리액트를 설치하고자 하는 디렉토리 이름)
  • 만약 현재 있는 경로에 설치하고 싶다면 npx create-react-app ./

다른 명령어들

  • npm run start : 실행
  • npm run test : 테스트 (개발 완료 후 문제가 있는지 없는지 확인)
  • npm run build
    -> 테스트도 완료가 됐다면 배포를 해서 다른 사람들도 이용할 수 있도록 하는 배포 명령어
    -> 실행하면 배포를 할 때 사용할 수 있는 build 폴더와 그 안에 많은 파일들이 생성된다.

이제는 도커를 이용하여 리액트 앱을 실행해보자.

도커를 이용하여 리액트 앱 실행하기

도커로 어플을 실행하기 위한 흐름

  • 도커 이미지 생성 -> 이미지를 이용해 컨테이너 만들기 -> 컨테이너 안에서 앱을 실행
  • 도커 이미지를 생성하기 위해서는 Dockerfile 을 작성

현재까지는 Dockerfile 을 그냥 한 가지만 만들었지만, 실제로는 개발 단계를 위한 Dockerfile 과 실제 배포 이후를 위한 Dockerfile 을 따로 작성하는게 좋다.

  • 이제는 그냥 Dockerfile 이 아닌 Dockerfile.dev 라는 파일로 작성해보자.

개발 환경에서의 도커 파일 작성은 현재까지 도커 파일 작성했던 것과 똑같이 하면 된다.

#Dockerfile.dev

FROM node:alpine

WORKDIR /usr/src/app

COPY pacage.json ./

RUN npm install

COPY ./ ./

CMD ["npm" , "run" , "start"]
  • 전에 배운 내용이지만 COPY package.json ./ 을 해주는 이유는?
  • COPY ./ ./ 이후에 npm install 을 하게 되면 약간의 소스 변경을 하고 나서 종속성도 계속 다운로드 받기 때문에 먼저 종속성 부분을 먼저 COPY 해오고 npm install 을 한다.
  • npm run start 로 실행되기 떄문에 CMD 부분에 넣어준다.

이렇게 Dockerfile.dev 를 작성하고 나면 이 도커 파일로 이미지를 만들면 된다.

  • docker build ./ 으로 생성

하지만 에러가 발생한다..

  • 그 이유는 원래 이미지를 빌드할 때 해당 디렉토리만 정해주면 Dockerfile 을 자동으로 찾아서 빌드를 하지만, 현재는 Dockerfile 이 아닌 Dockerfile.dev 밖에 없다.
  • 그래서 자동으로 도커 파일을 찾지 못해 에러가 발생한다.
  • 이러한 문제를 해결하기 위해서는 build 할 때 어떠한 파일을 참조할지 알려주면 된다.
  • 임의로 알려주는 방법은 빌드를 할 때 그냥 docker build . 이 아닌 -f 옵션을 사용해야 한다.

docker run -f Dockerfile.dev ./

  • -f 는 이미지를 빌드 할 때 쓰일 도커 파일을 임의로 지정해준다.
  • 그래서 이런식으로 -f 옵션을 사용하면 정상적으로 이미지 빌드가 된다.

  • 현재 디렉토리에 보면 node_modules 라는 폴더가 있는데 이것을 삭제해도 괜찮다.
  • 그 이유는 node_modules 에는 리액트 앱을 실행할 떄 필요한 모듈들이 들어있지만 이미지를 빌드할 때 이미 npm install 로 모든 모듈들을 도커 이미지에 다운 받기 떄문에 굳이 로컬 머신에 node_modules 을 필요로 하지 않는다.
  • node_modules 자체가 사이즈가 크기 떄문에 지워주도록 하자.

생성된 도커 이미지로 리액트 앱 실행해보기

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

docker run supportkim/docker-react-app

리액트는 기본적으로 3000번 포트로 실행되기 때문에 3000번 포트로 실행해보면 에러가 발생한다..

  • 이유는 이전과 같이 포트 매핑을 해줘야 하는데 안 해줬기 때문이다.
  • 컨테이너 안에서 실행되고 있는 리액트 앱에 도달하지 못한 것이다.
  • 즉 브라우저의 3000번 포트와 컨테이너 안에 있는 3000번 포트를 매핑해줘야 한다.

docker run -it -p 3000:30000 supportkim/docker-react-app

  • 리액트쪽에서 업그레이드를 해서 -it 옵션을 꼭 사용해야한다.
  • 실행해보면 정상적으로 동작하는 것을 확인할 수 있다.

도커 볼륨을 이용한 소스 코드 변경

  • COPY 를 했을때는 로컬에 있던 파일들을 도커 컨테이너에 "복사"
  • Volume 은 도커 컨테이너에서 로컬에 있는 파일들을 "매핑(참조)"

docker run -it -p 3000:3000 -v /usr/src/app/node_modules -v $(pwd):/usr/src/app supportkim/docker-react-app(IMAGE_NAME)

  • 첫 번째 -v 는 호스트 디렉토리에 node_modules 는 없기 때문에 매핑하지 말라고 하는 것
  • 두 번째 -v 는 pwd 경로에 있는 디렉토리 혹은 파일을 /usr/src/app 경로에서 참조하라는 것 (WORKDIR 에서 pwd 에 있는 파일들을 참조하자는 것)

소스 코드를 바꾸면 빌드하지 않아도 바로 반영 되는 것을 알 수 있다.

도커 컴포즈로 좀 더 간단하게 앱 실행 하기

  • 앞서 리액트 앱을 실행할 때 위에 있는 명령어처럼 매우 길어서 불편한 부분이 있다.
  • 이걸 간단히 하기 위해서 Docker Compose 파일을 작성해보자.
  • Docker compose 파일에서 도커 파일 사용 + 포트 맵핑을 해주면 된다.
version: '3' # 도커 컴포즈 버전
services:   # 이곳에 실행하려는 컨테이너들을 정의
  react:    # 컨테이너 이름
    build:  # 현 디렉토리에 있는 Dockerfile 사용
      context: . # 도커 이미지를 구성하기 위한 파일과 폴더들이 있는 위치 
      			 #(현재는 Dockerfile.dev 와 같은 경로에 있기 때문에 . 으로 명시)
      dockerfile: Dockerfile.dev # 도커 파일 어떤 것인지 지정
    ports: # 포트 매핑 -> 로컬 포트 : 컨테이너 포트
    - "3000:3000"
    volumes: # 로컬 머신에 있는 파일들 맵핑
      - /usr/src/app/node_modules # node_modules 는 참조 X
      - ./:/usr/src/app # WORKDIR 에서 현재 디렉토리 참조 O
    stdin_open: true # 리액트 앱을 끌때 필요 (버그 수정)
  • 작성한 후 docker-compose up 명령어만 입력하면 어플리케이션이 실행된다.

리액트 앱 테스트 하기

  • npm run test : 리액트 앱에서 테스트 진행

도커를 이용한 리액트 앱에서 테스트 진행

  • docker build -f dockerfile.dev .
  • docker run -it IMAGE_NAME npm run test

여기서 좀 더 나아가서 테스트도 소스 코드 변경하면 자동으로 반영되는 것 처럼 테스트 소스도 추가 하면 바로 반영되었으면 좋을텐데 어떻게 할 수 있을까?

  • 기존에 있던 테스트 말고 새로운 테스트 소스 코드를 만든후 다시 테스트를 진행해도 추가가 되지 않는다.
  • 어플리케이션을 껐다가 다시 켜도 테스트가 더 추가로 진행되지 않는다.
  • 바로 반영 하기 위해서 똑같이 Volume 을 사용하면 된다.

소스 코드 변경을 위해서 Volume 을 이용했듯이 이번에도 Volume 을 이용하면 되는데, Test 를 위한 컨테이너를 Compose 파일에 하나 더 만들어주면 된다.

# 이 부분을 추가
tests:
    build:
      context: .
      dockerfile: Dockerfile.dev
    volumes:
      - /usr/src/app/node_modules
      - ./:/usr/src/app
    command: ["npm" , "run" , "test"]
  • 다시 docker-compose up --build 로 켜주면 리액트 컨테이너와 테스트 컨테이너가 켜지고 테스트 2개 모두 진행이 된다.
  • 만약 테스트를 하나 더 늘리고 저장을 하면 바로 3개의 테스트가 진행이 된다.

운영환경을 위한 Nginx

현재까지는 리액트앱을 개발 환경에서 다뤄봤는데 이제는 운영 환경(배포 후)을 다뤄보자.
-그전에 Nginx 라는 것을 알아야한다.

Nginx 가 필요한 이유?

  • 먼저 개발환경에서 리액트가 실행되는 과정과 운영 환경에서 리액트가 실행되는 과정이 다르다.
  • 개발 환경에서는 브라우저에서 3000번 포트로 요청이 리액트 컨테이너로 가면 컨테이너 안에 개발 서버에서 해당 요청을 받고 뷰를 보여준다.
  • 하지만 운영 환경에서는 리액트 컨테이너 안에 개발 서버라는 것이 없기 떄문에 뷰를 보여줄 수 없다.
  • 이때 Nginx 라는 웹 서버가 개발 환경의 개발 서버 역할을 해주는 것이다.

그렇다면 왜 개발환경 서버와 운영환경 서버를 다른걸 써야할까?

  • 개발서버를 그대로 운영 환경에서도 써도 될 것 같은데 왜 그럴까?
  • 개발에서 사용하는 서버는 소스를 변경하면 자동으로 전체 앱을 다시 빌드해서 변경 소스를 반영해주는 것 같이 개발 환경에 특화된 기능들이 있기에 그러한 기능이 없는 Nginx 서버보다 더욱 적합하다.
  • 운영환경에서는 소스를 변경할 떄 다시 반영해줄 필요가 없고 개발에 필요한 기능들이 필요하지 않기에 더 깔끔하고 빠른 Nginx 를 웹 서버로 사용한다.

운영 환경 도커 이미지를 위한 Dockerfile 작성

  • 위에서 운영 환경에서는 Nginx 가 필요하다는 것을 알게됐기 떄문에 이제는 Nginx 를 포함하는 리액트 운영환경 이미지를 생성해보자.
  • npm run build 명령어를 실행하면 build 파일이 생성되는데, 이 빌드 파일을 Nginx 서버가 브라우저에서 보일 수 있게 해준다.
# 여기 FROM 부터 다음 FROM 전까지는 모두 builder stage 라는 것을 명시
FROM node:alpine as builder

WORKDIR '/usr/src/app'

COPY package.json .

RUN npm install

COPY ./ ./

RUN npm run build

FROM nginx

COPY --from=builder /usr/src/app/build /usr/share/nginx/html
  • 위에 Dockerfile 은 크게 두 개로 구분할 수 있다.
  • 첫 번째 단계는 빌드 파일들을 생성하는 Builder Stage
  • 두 번쨰 단계는 Nginx 를 가동하고 첫 번째 단계에서 생성된 빌드 폴더의 파일들을 웹 브라우저의 요청에 따라 제공해주는 Run Stage
  • 첫 번째 FROM 부터 다음 FROM 나오기 직전이 Builder Stage
  • 두 번째 FROM 부터 Run Stage

Builder Stage

  • builder stage 란 빌드 파일들을 생성하는 것인데 생성된 파일과 폴더들은 /usr/src/app/build 로 들어가게 된다.
  • as builder 으로 다음 FROM 나오기 전까지가 builder stage 라는 것을 알려준다.

Run Stage

  • FROM nginx 는 nginx 를 위한 베이스 이미지를 명시해준다.
  • --from=builder 는 다른 Stage 에 있는 파일을 복사할 때 다른 Stage 이름을 명시해줘야 하기 때문에 위에 있는 builder 를 복사해온다.
  • builder stage 에서 생성된 파일들은 /usr/src/app/build 에 들어가게 되며 그곳에 저장된 파일들을 /usr/share/nginx/html 로 복사를 시켜줘서 nginx 가 웹 브라우저의 http 요청이 올떄 마다 알맞은 파일을 전해줄 수 있게 만든다.
  • /usr/share/nginx/html 로 복사해주는 이유는 이 장소에 파일을 넣어 두면 Nginx 가 알아서 Client 에서 요청이 들어올 때 알맞은 정적 파일들을 제공해준다.
  • 설정으로 장소를 바꿀 수 있다.

해당 Dockerfile 을 만들고 build 한 후 docker run -p 8080:80 supportkim/docker-react-app 명령어를 실행하면 정상적으로 실행이 된다.

앞으로는 테스트 하고 배포를 해보자!

참고자료

profile
덕업일치

0개의 댓글