[따라하며 배우는 도커와 CI환경] 6. 간단한 어플을 실제로 배포해보기(개발 환경 부분)
이번 시간부터는 간단한 애플리케이션를 배포하면서 도커를 배워보자.
✔️ 리액트 환경 세팅
리액트를 사용하려면 node를 반드시 설치해야 한다.
$ npx create-react-app ./
node 설치 후, 위의 명령어를 통해 리액트 앱을 위한 환경을 세팅한다.
명령어가 실행되면 다음과 같은 파일들이 생성된다.
✔️ 도커로 리액트 앱 실행
이제 도커를 통해 리액트 앱을 실행해보자.
도커로 리액트 앱을 실행하기 위해서는 다음과 같은 과정을 수행해야 한다.
1️⃣ 도커 파일 생성 및 빌드
다음과 같이 도커 파일을 생성하자.
Dockerfile.dev
FROM node:alpine
WORKDIR /usr/src/app
COPY package.json ./
RUN npm install
COPY ./ ./
CMD ["npm", "run", "start"]
이제 도커 파일을 통해 이미지를 생성해야 한다. 다음의 명령어를 통해 빌드하자.
$ docker build -f Dockerfile.dev -t [이미지 이름] ./
❗️ 도커 파일의 이름이 Dockerfile일 경우에는 파일 이름을 명시하지 않아도 되지만, Dockerfile.dev 라는 이름으로 만들었기 때문에 -f 옵션을 통해 파일 이름을 지정해주었다.
📌 팁! 로컬에 있는 node_modules는 지워주자.
이미지를 빌드할 때 이미 npm install로 모든 모듈들을 도커 이미지에 다운받기 때문에, 로컬 머신에 node_modules가 필요없다.
또한, COPY ./ ./ 를 통해 파일을 복사할 때 node_modules가 복사된다. 이미 npm install로 생성하였는데 불필요하게 한 번 더 복사가 되므로 로컬에 있는 node_modules는 지우도록 하자.
2️⃣ 도커 이미지로 리액트 앱 실행
$ docker run -p 3000:3000 [이미지 이름]
위의 명령어를 통해 도커 컨테이너를 생성하고 실행할 수 있다.
리액트는 기본적으로 3000 포트를 사용하기 때문에 3000번으로 포트 매핑을 해주었다.
이렇게 실행해주면, create-react-app 을 통해 생성된 기본적인 리액트 앱이 잘 실행되는 것을 확인할 수 있다.
3️⃣ 도커 볼륨 사용
이제 COPY 대신 Volume을 사용해서 소스 코드 변경 시 재빌드하지 않아도 적용이 되도록 해보자!
$ docker run -p 3000:3000 -v /usr/src/app/node_modules -v $(pwd):/usr/src/app [이미지 이름]
위의 명령어에 대한 설명은 이전 포스트에서 설명했다.
/src/App.js 을 다음과 같이 변경 후, 빌드하지 않고 바로 변경된 부분이 적용된다.
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
안녕하세요! <!-- Learn React 에서 변경됨 -->
</a>
</header>
</div>
);
}
export default App;
docker run -p 3000:3000 -v /usr/src/app/node_modules -v $(pwd):/usr/src/app [이미지 이름]
간편하긴 하지만 명령어가 너무 길다...
간단하게 실행할 수 있는 방법을 알아보자.
4️⃣ 도커 컴포즈로 실행
지난 포스트에서 도커 컴포즈(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
각 옵션의 의미는 다음과 같다.
이제 도커 컴포즈를 통해 앱을 실행하자.
$ docker-compose up
잘 실행되는 것을 확인할 수 있다.
5️⃣ 리액트 앱 테스트
이제 도커 환경에서 리액트 앱을 테스트해보자.
$ docker run [이미지 이름] npm run test
기본적으로 위의 명령어를 통해 리액트 앱을 테스트할 수 있다.
그러나 이렇게 실행하게 되면, 위에서 도커 볼륨을 사용하기 전에 그랬듯이 테스트 코드에 대한 변경사항이 자동으로 반영되지 않는다.
테스트 소스 코드 변경 시 변경 사항이 바로 적용이 되도록, 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
# 추가된 부분
tests:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- /usr/src/app/node_modules
- ./:/usr/src/app
command: ["npm", "run", "test"]
이제 다음과 같이 앱을 실행하자.
$ docker-compose up --build
실행하면 리액트 앱과 테스트가 모두 실행되는 것을 확인할 수 있다.
이제 /src/App.test.js 를 수정하면 바로 테스트에 적용된다!
✔️ 운영환경을 위한 Nginx 사용
지금까지 개발환경에서 리액트 앱을 실행하였다.
이제 도커를 사용해서 운영환경에서 리액트를 실행해보자.
다음은 운영환경에서 앱을 실행하는 과정이다.
운영환경에서는 개발서버가 아닌 Nginx 서버를 사용한다.
Nginx 는 동시접속 처리에 특화된 웹 서버 프로그램으로, 요청에 응답하기 위해 비동기 이벤트 기반 구조를 가진다.
개발 서버에 존재하는 개발에 특화된 기능은 운영 서버에 불필요하고 속도를 늦출 수 있기 때문에 운영 서버를 따로 둔다.
1️⃣ 도커 파일 생성
개발 환경에서는 build를 하지 않고도 실행할 수 있지만, 운영 환경에서는 build를 반드시 해줘야 한다.
도커 파일의 구조는 다음과 같은 차이가 있다.
운영 환경에서의 도커 파일의 구조를 더 자세하게 살펴보자.
이것은 2가지 Stage로 나눌 수 있는데, Builder Stage와 Run Stage 이다.
📌 Builder Stage
빌드 파일을 생성하기 위한 stage.
리액트에서는 npm run build를 통해 빌드 파일을 생성한다.
📌 Run Stage
Nginx를 실행하여 웹 브라우저 요청에 따라 정적 파일을 제공해주는 stage.
빌드된 파일을 이용한다.
다음과 같이 도커 파일을 작성하자.
Dockerfile 파일
# Builder Stage
FROM node:alpine as builder
WORKDIR /usr/src/app
COPY package.json ./
RUN npm install
COPY ./ ./
CMD ["npm", "run", "build"]
# Run stage
FROM nginx
COPY --from=builder /usr/src/app/build /usr/share/nginx/html
2️⃣ 도커 이미지 빌드 및 실행
$ docker build -t [이미지 이름] ./
위의 명령어를 통해 도커 이미지를 빌드한다.
이번에는 도커 파일 이름이 Dockerfile 이므로 파일 이름을 따로 지정해줄 필요는 없다.
$ docker run -p 8080:80 [이미지 이름]
Nginx 의 기본 포트 번호는 80번이다.
위의 명령어를 통해, 로컬 포트 8080번과 컨테이너 포트 80번을 매핑하여 컨테이너를 실행할 수 있다.
localhost:8080 으로 잘 실행되는 것을 확인할 수 있다!
참고
- https://www.inflearn.com/course/따라하며-배우는-도커-ci
- https://whatisthenext.tistory.com/123
- https://ko.wikipedia.org/wiki/Nginx