Docker로 React 어플리케이션 실행하기

정다빈·2023년 6월 25일
2
post-thumbnail

최근 키즈노트 FE개발파트는 도커(Docker) 도입을 검토하고 있어요. 사실 도커의 도 모르는 상태인데요, 도입 후 도커랑 어색한 사이이면 안 되겠죠? 이번 포스트에서는 도커에 대해 간단히 알아보고, 도커를 이용해서 리액트 어플리케이션을 실행해 보도록 하겠습니다. 🤓

🐳 도커란 무엇인가요?

도커 이전에 존재했던 가상 머신(Virtual Machine)

가상 머신은 (소프트웨어를 이용해서) 컴퓨터 시스템을 에뮬레이션한 가상 환경을 의미해요. 가상 머신은 실제 컴퓨터 시스템과 유사한 환경을 제공하기 때문에, 가상 환경에서 별도의 OS와 어플리케이션을 실행할 수 있어요.

위와 같이 호스트 컴퓨터 위에서 → 가상 머신을 생성하고 구동하는 하이퍼바이저(Hypervisor)가 실행되고 → 그 위에서 가상 머신이 실행되는 구조에요.

실제로 가상 머신을 실행한 모습은 아래와 같습니다!

가상 머신의 장점

  • 가상 머신은 하나의 호스트 OS 위에서 여러 게스트 OS를 실행할 수 있어요. 예를 들어, 윈도우 OS를 사용하는 호스트 컴퓨터 위에서 리눅스 OS를 실행한다면 개발자는 다양한 환경에서 어플리케이션을 개발하고 테스트할 수 있겠죠?
  • 각각의 가상 머신은 독립된 환경에서 어플리케이션을 실행할 수 있기 때문에 상호 간의 충돌을 방지할 수 있어요. 가상 머신은 독립된 OS와 리소스를 가지기 때문에, 하나의 가상 머신에서 문제가 발생하더라도 다른 가상 머신은 영향을 받지 않으므로 어플리케이션의 안정성을 높일 수 있어요.
  • 가상 머신은 서버의 자원을 가상화하여 리소스를 효율적으로 활용할 수 있도록 도와줍니다. 하나의 물리적 서버에서 여러 가상 머신을 실행하면 서버 자원을 서로 공유하고 관리할 수 있어요.

가상 머신의 단점

하나의 호스트 OS 위에서 여러 개의 게스트 OS를 설치하고 실행할 경우, 오버헤드가 크고 성능이 불안정해진다는 단점이 있어요.

도커의 등장

도커는 가상 머신의 성능 문제를 보완하기 위해 등장했어요. 호스트 OS 위에 게스트 OS를 설치해야 하는 가상 머신과 달리, 도커는 별도의 게스트 OS를 설치하지 않고 컨테이너(Container)라는 격리된 환경을 만들어요.

도커는 어플리케이션과 실행에 필요한 종속성들을 컨테이너로 패키징 하여 환경의 일관성과 이식성을 제공해 줍니다. 때문에 도커는 주로 어플리케이션의 실행과 배포를 위해 사용돼요.

이미지

도커에서 말하는 이미지는 그림, 사진이 아닌 컨테이너를 생성할때 필요한 템플릿 파일이에요. 컨테이너는 이미지를 인스턴스화해서 만들어지기 때문에, 컨테이너를 실행할 때 필요한 환경 설정을 이미지에 정의해 주어야 해요. 이미지는 Dockerfile이라는 텍스트 파일에 정의할 수 있으며, Docker Hub와 같은 공개 레지스트리에 공유할 수 있어요.

빌드를 실행하면 Dockerfile의 명령어들이 순차적으로 실행되고, 이때 명령어가 실행되면서 각각의 이미지 레이어가 생성돼요. 이렇게 만들어진 레이어들은 스택 구조로 쌓이게 됩니다. 빌더는 이전 빌드에서 만들어진 레이어를 재사용하려고 시도하는데요, 만약 레이어가 변경되지 않았다면 캐싱된 레이어를 가져오지만 레이어가 변경되었다면 해당 레이어부터 이후의 모든 레이어들을 다시 빌드 하게 됩니다. Dockerfile의 명령어 순서를 잘 정의해서 최대한 레이어를 재사용하는 것이 중요하겠군요! 🤔

🎣 도커를 직접 사용해 봅시다!

1. 도커 설치하기

다운로드 페이지에서 도커를 설치해 줄게요. 설치가 완료된 후 도커 앱을 실행하면 아래와 같은 화면을 볼 수 있어요.

2. 리액트 어플리케이션 생성하기

Create React App을 이용하여 간단한 리액트 어플리케이션을 생성해 주었어요. 어플리케이션을 실행하면 localhost:3000에서 아래와 같은 화면이 나타나요.

3. 이미지 작성하기

루트 디렉토리에 아래와 같이 Dockerfile을 생성해줄게요.

  • FROM : 디폴트 이미지를 설정할 때 사용하며, DockerfileFROM 명령어로 시작해야 해요. Docker Hub에서 이미지를 가져와서 사용하는 것이 가장 쉽고 일반적이에요.
    저는 리액트 어플리케이션을 실행시켜줄 것이기 때문에, Node.js의 가장 안정적인 버전인 18버전의 slim을 사용했어요. Node.js 이미지 문서를 확인해 보면, slim은 Node.js를 실행하는데 필요한 최소한의 패키지만 포함되어 있다고 설명하고 있어요.
  • COPY : COPY <src> <dest> 문법을 사용하며, 호스트 컴퓨터의 <src> 파일 또는 디렉토리를 → 컨테이너의 <dest>로 복사해요.
    저는 어플리케이션의 모든 파일을 컨테이너에 넣어주고 싶기 때문에, 경로를 . .로 지정해 주었어요. 추후 단계에서 컨테이너를 실행시켜보면, 컨테이너의 루트 디렉토리에 모든 파일들이 옮겨진 것을 확인할 수 있어요.

  • RUN : 이미지를 빌드 하는 과정에서 실행되기 때문에, 일반적으로 어플리케이션 실행에 필요한 라이브러리를 이 단계에서 설치해요.
    저는 npm install로 패키지들을 설치해 줄게요.
  • CMD : 컨테이너를 최초로 실행할 때 사용되는 명령어입니다. Dockerfile에서는 하나의 CMD 명령어를 가질 수 있으며, 둘 이상의 CMD 명령어가 있는 경우 마지막 명령어만 실행돼요.
    저는 리액트 어플리케이션을 실행시키기 위해 npm start를 사용했어요.
  • EXPOSE : 컨테이너가 실행될 때 사용할 포트 번호를 명시해요. EXPOSE 명령어는 포트 번호를 명시하는 단순한 문서 역할을 하기 때문에, 실제 컨테이너 실행에는 영향을 주지 않아요.
    저는 3000번 포트를 사용하겠다고 명시해 주었어요.

4. 이미지 빌드하기

아래 명령어를 이용해서 이미지를 빌드해 줄게요.

docker build -t simple-react-docker-practice .

-t 옵션을 이용해서 이미지에 simple-react-docker-practice라는 태그를 붙어주었어요.

터미널에서 명령어들이 실행되는 것을 확인할 수 있어요. FROM 명령어에 적었던 Node.js는 캐시를 사용했다는 것을 알 수 있네요!

5. 컨테이너 실행하기

아래 명령어를 이용해서 컨테이너를 실행해 줄게요.

docker run -dp 127.0.0.1:3000:3000 simple-react-docker-practice
  • -d : 컨테이너를 백그라운드에서 실행시킬 때 사용하는 옵션이에요. 컨테이너를 백그라운드에서 실행시킨다면 컨테이너의 실행에 필요한 터미널을 계속 열어둘 필요가 없기 때문에 보통 백그라운드에서 실행합니다.
  • -p : 호스트와 컨테이너 간의 포트 연결을 위해 사용하는 옵션이에요. 호스트 주소:컨테이너 포트 번호 형식을 사용하며, 저는 호스트의 localhost:3000과 컨테이너의 3000 포트를 연결해 주었어요. 이러한 매핑 옵션이 없다면 호스트에서 컨테이너의 어플리케이션에 접근을 할 수 없습니다.
    마지막에는 빌드 단계에서 지정했던 이미지의 태그를 넣어주었어요.

터미널에서 리액트 어플리케이션을 종료한 후, http://localhost:3000 으로 접속하면 컨테이너에서 어플리케이션이 실행 중인 것을 확인할 수 있습니다.

6. 코드 수정하기

이번엔 App.tsx 파일에서 코드를 살짝 수정해 볼게요.

7. 컨테이너 재실행하기

"4. 이미지 빌드하기", "5. 컨테이너 실행하기" 단계와 동일하게 컨테이너를 실행시켰더니, 아래와 같이 에러가 발생했어요.

이전 컨테이너가 호스트 3000번 포트를 사용하고 있기 때문에 또다시 3000번 포트로 실행이 불가능한 상태에요. 이를 해결하기 위해서는 이전 컨테이너를 제거해 주어야 합니다.

아래 명령어를 이용해서 현재 실행 중인 컨테이너 목록을 조회해 줄게요.

docker ps

3000번 포트를 사용 중인 컨테이너 아이디를 확인한 후, 컨테이너를 중지시켜 줍니다.

docker stop <container-id>

컨테이너가 중지되었다면 아래 명령어를 이용해서 컨테이너를 제거할 수 있어요.

docker rm <container-id>

다시 컨테이너를 실행한 후 localhost:3000으로 접근하면 정상적으로 실행 중인 것을 확인할 수 있어요. 수정한 대로 잘 나오고 있네요!👍🏻

"1. 도커 설치하기" 단계에서 설치했던 도커 앱에서도 컨테이너의 상태를 확인할 수 있어요.

🐟 마무리

지금까지는 도커에 대해 잘 몰랐기 때문에 굉장히 어색한 사이였는데요, 이제는 1px 정도 친해진 기분이 들어요.
배포 단계에서 환경 설정 문제로 배포에 실패하는 케이스를 간혹 보았는데요, 도커를 도입해서 잘 사용하면 배포 실패 확률을 많이 줄일 수 있지 않을까 하는 기대가 듭니다. 앞으로도 도커와 친해지고 싶어요!

실습에 사용된 코드는 여기서 확인할 수 있습니다.

📚 Reference

profile
Frontend Developer

0개의 댓글