분산된 프로젝트를 도커 컨테이너로 실행시켜보자[TIL / Docker]

알락·2022년 11월 17일
0
post-thumbnail

배포 준비

만들어진 서비스는 최종적으로 사람들에게 제공되어야 한다. 사람들에게 서비스를 제공하는 방식은 여러가지의 형태가 존재할 것이다. 보통 작은 서비스 같은 경우는 다음과 같이 배포가 될 것이다.

서비스 배포 절차

  1. 아마존이나 마이크로소프트 등 클라우드 서비스 제공 업체에서 서버 대여.
  2. 대여한 서버 환경설정.
  3. 작성된 웹서비스 파일 서버에 올리기.
  4. 서버 실행

Docker

여러 부가설명을 다 제하고 핵심만 얘기해보겠다. Docker는 배포 중 꼭 해야하는 단계인 환경설정을 쉽게 만든다. 이는 서비스가 컨테이너 형식으로 서버에서 구동되기 때문이다.

기존에는 서비스를 제공하기 위해서는 서비스가 필요한 라이브러리나 프레임워크, 그리고 다른 프로그램들을 설치해주는 작업이 필요했다. 하지만 이런 각각의 툴들이 충돌하는 문제가 생기기도 하고, 환경설정에서 너무 많은 시간을 소비하기도 한다. 툴들이 충돌하는 문제를 제한하기 위해서 가상 머신을 이용하였지만, 가상 머신은 구동하기가 무겁다는 단점이 있다.

컨테이너는 이런 문제들을 해결하는 사용하기 쉬운 대안이었다. 서비스가 잘 구동되는 환경을 이미지로 만들어 제공한다. 이 이미지로 컨테이너를 만든다. 서비스가 구동이 되는 환경을 컨테이너에 다 구현하여 어디서든 사용할 수 있게 하는 것이 도커의 사용 목적이다.

왜 필요할까?

대규모 서비스의 경우는 트래픽이 상당히 많다. 이런 트래픽을 나눠서 처리하기 위해 분산처리 시스템을 이용하게 된다. 똑같은 기능을 하는 서버를 여러 개로 두어 사용하는 것이다. 심지어 데이터베이스도 여러 개 두어 데이터를 저장하기도 한다. 이럴 때, 도커를 통해 만들어 놓은 이미지를 통해 컨테이너만 만들어 실행시키면 새로운 서버를 실행시키는 게 손쉬워질 것이다.
마이크로서비스 아키텍처 같은 분산시스템을 구현 하는데 비용을 아끼는 방법이 도커의 컨테이너 배포 형식이라고 생각한다.


프로젝트에 적용

⌞ 적용하게 된 배경 설정

사실 도커를 공부해보고 싶어서지만 나름의 설정을 해서 도커를 이용해보려고 한다. 설정은 다음과 같다.
만든 웹서비스를 호스팅 업체의 서버를 대여하여 배포해보고 싶은데, 도커의 이미지 기능을 활용하여 쉽게 서버 측 프로그램을 옮겨보려고 한다. 그리고 본격적으로 웹서비스를 옮기기 전 현재 로컬에서 컨테이너로 만들어 작동시켜, 원하는 대로 웹서비스의 기능들이 제공되는지 테스트해보려고 한다.
배포할 웹서비스의 기본 구조를 보자.

[프로젝트 기본구조]

현재 리액트를 이용하는 클라이언트(Front-End)와 자료저장 및 읽기의 클라이언트 요청을 처리해주는 서버(Back-End), 그리고 데이터들이 저장되어 있는 DBMS 로 구성되어 있다. 클라이언트-백엔드-DBMS 서버를 각각 따로 두어 기능을 제공해본다.

그리고 이를 docker-compose 기능을 사용하지 않고 구현한다. docker-compose를 이용하여 구현하는 더 간단한 방법은 이후 포스팅에서 다루도록 하겠다.

⌞ 실행

1. 재료준비

클라이언트와 백엔드, 그리고 DBMS가 작동하는 최소한의 환경을 마련해줘야 한다. 클라이언트의 React, 그리고 서버의 node.js 가 작동하기 위해서는 Node Package Manager만 있으면 된다. 공식적으로 node.js 가 구동되는 이미지를 제공하고 있기 때문에 그 이미지를 이용하려고 한다.
그리고 mongoDB는 DBMS만 설치되어 작동이 되면 문제없다. mongoDB에서 제공해주는 이미지를 이용하려고 한다.

[이미지 가져오기]

// shell
> docker pull node:lts
> docker pull bitnami/mongodb:6.0.1

개발자들이 배포하는 이미지들은 docker hub 사이트에서 살펴볼 수 있기 때문에 필요한게 있으면 찾아볼 수 있다.

클라이언트와 백엔드는 작성한 프로그램을 npm이 작동하는 이미지에 복사하여 올려놓고 새로운 이미지로 만들어야 한다. 이미지는 이처럼 아무나 만들어 사용할 수 있다.

[Dockerfile 작성]

// 서버와 클라이언트 각각의 디렉터리 중
// 가장 상위 디렉터리에 Dockerfile 이라는 이름을 갖는 파일을 만들고
// 다음과 같이 작성한다.

BASE node:lts

COPY ./ /root
CMD npm run start

[이미지 생성]

// 클라이언트 최상위 디렉터리
> docker build -t backend:latest .
// 서버 최상위 디렉터리
> docker build -t frontend:latest .

위에서 수행한 것은 클라이언트와 서버의 이미지를 생성하는 과정이다. 생성된 이미지는 docker GUI에서도 확인 가능하고 CLI에서도 확인 가능하다.

생성된 이미지 확인하기

> docker image list

2. 컨테이너 생성 및 실행

내가 배포하려고 하는 웹서비스는 클라이언트, 서버, 데이터베이스 간에 종속성이 생긴다. 이를테면 서버는 데이터베이스를 필요로하고, 클라이언트는 서버를 필요로 한다. 그렇기 때문에 다른 기능에 종속받지 않고 있는 mongoDB의 컨테이너 생성과 실행을 먼저 하려고 한다.

[mongodb 컨테이너 생성]

> docker run -d --name mongodb -p 27018:27017 mongodb:6.0.1

위의 docker 명령인 run은 컨테이너를 생성하고 실행하는 명령어다. 맨 뒤에는 컨테이너로 생성할 이미지를 넣어주면 된다. 만약 본인이 갖고 있는 이미지 중 뒤에 달리는 버전을 뜻하는 태그가 매칭되는 게 없으면 새롭게 docker hub에서 이미지를 가져와 생성하기 때문에 주의하자.

  • -d 는 해당 컨테이너를 백그라운드에서 실행한다. 빼고 실행할 시 현재 사용하는 터미널이 만드는 컨테이너의 로그로 가득찰테니 필요에 의해서 사용하기 바란다.
  • --name [이름] docker 상에서 사용될 별칭을 지정한다.
  • -p 포트번호를 지정할 수 있다. 특히 위처럼 콜론(:)으로 구분하여 (로컬호스트의 포트번호):(컨테이너의 포트번호)를 매칭하여 줄 수 있다. 로컬호스트에 지정된 포트번호에 어떤 요청을 한다면 해당 포트번호와 짝지어져있는 컨테이너에서 실행이 된다.
  • 해당 옵션들은 순서 상관없이 형식만 맞추어 작성해주면 된다.

[서버 컨테이너 생성]

> docker run -d --name toy_backend -p 4001:4000 --link mongodb backend

서버 컨테이너 실행 명령은 --link [컨테이너 이름]이 추가된다. 지정한 컨테이너 이름을 해당 컨테이너에서 host를 지칭할 수 있게 된다. 만약 서버에서 mongodb에 연결을 위해 host이름을 지정해주어야 할 때, 여기서 지정한 컨테이너 이름을 대신 사용해주면 된다. 다음과 같이 이용하면 된다.

[서버 컨테이너의 데이터베이스 연결 설정]

const mongoose = require("mongoose");

// 원래는 "mongodb://localhost:27017/simpledb" 였던 것
const db = mongoose.createConnection("mongodb://mongodb:27017/simpledb")

module.exports = db;

[클라이언트 컨테이너 생성]

> docker run -d --name toy_frontend -p 3001:3000 --link toy_backend frontend

클라이언트 컨테이너 실행은 서버 컨테이너 실행과 똑같다. 다만 --link 옵션에 지정하는 컨테이너 이름을 실행에 필요한 서버로 대체해주어야 한다.

실행되는 모습

[docker 상태]

[웹서비스 실행]

개선할 점

  • 사실 위에서 설명한 내용만 해낸 것은 아니다. 위는 개략적인 도커 명령 위주 작업만 설명했는데, 작동하고 있는 클라이언트나 서버의 코드 상으로 수정이 필요한 부분을 컨테이너에 bash로 접근하여 고쳐주었다.
  • localhost의 브라우저로 최종실행을 시키고 있기 때문에 사실상 localhost -> 클라이언트 컨테이너-> localhost -> 서버 컨테이너 -> 몽고db 컨테이너의 흐름으로 작동하고 있다. 중간에 등장하는 localhost를 없애고 바로 서버 컨테이너에 연결할 방법을 찾아봐야겠다.
  • docker-compose를 이용하면 위의 일련의 작업들을 한 번에 해결시켜 줄 수 있다. 이번에는 공부 목적으로 이용을 안 하였지만 더 편한 방법으로 상호 연결되어있는 서비스를 쉽게 도커로 실행시킬 수 있다.
profile
블록체인 개발 공부 중입니다, 프로그래밍 공부합시다!

0개의 댓글