Chapter 4 - Make application with docker

권대규·2021년 8월 7일
0

docker-study

목록 보기
4/4
post-thumbnail

본 포스트는 Inflearn '따라하며 배우는 도커와 CI환경' 강의를 기반으로 작성되었습니다.

이번 시간에는 도커를 이용하여 Node.js application과 같이 사용하는 방법에 대해 포스팅하려 합니다. 좀 더 구체적으로 설명하자면 도커 컨테이너 안에서 Node.js 앱을 실행하는 것을 실습해보려고 합니다. 강의에서는 직접 Node.js를 사용해서 앱을 생성하고 도커 실습을 진행하지만, 저는 옛날에 만들어놨던 boiler-plate를 활용해서 진행하려고 합니다.

우선 실행시킬 앱의 구조는 아래와 같습니다.

간단히 설명하면 그냥 로그인, 회원가입 기능만 구현해 놓은 파트 중 웹 파트입니다. 위와 같은 디렉토리에서 npm run start 명령어를 치면 실행됩니다. 서버 파일도 상위 디렉토리에 있지만, 이번에는 가시적인 효과를 주는 web 부분을 활용해서 실습을 진행하려 합니다. 그러면 이제 이를 기반으로 dockerfile을 작성해봅시다.

Dockerfile 작성하기

Node.js 앱을 도커 내부에서 실행시키기 위해서는 컨테이너를 실행하고 그 안에서 Node.js 앱을 실행해야 합니다. 하지만 컨테이너를 생성하기 위해서는 이미지 파일이 필요하고, 이미지 파일을 생성하려면 Dockerfile을 먼저 작성해야 합니다. 그래서 우선 Dockerfile을 작성해보려 합니다.

Dockerfile Remind

FROM 베이스이미지
RUN command
CMD [시작시 실행될 명령어들]

이를 기반으로 구성해보면 다음과 같습니다.

베이스 이미지로는 node파일로 설정을 하고, 서버를 실행하기 위해서 필요한 모듈들을 설치하기 위해서 기본 명령어로 npm install을 해줍니다. 도커가 메인이기 때문에 node랑 npm에 관련된 설명은 따로 적지는 않겠습니다.

이제 해당 파일을 기반으로 도커파일을 빌드해보겠습니다.
그러면 다음과 같은 오류가 납니다.

이미지 파일을 다운 받는데도 성공했지만 npm run install을 실행하는데서 오류가 났지만 최종적으로는 Successfully built되었다고 나옵니다. 자세히 로그를 읽어보면
no such file or directory, open '/package.json'이라는 오류를 확인할 수 있습니다.

COPY

분명 위 구조를 보면 package.json이 있지만, 도커 파일에는 없다고 나옵니다. 왜냐하면 우리는 베이스 이미지로 node:10을 사용한다고는 했지만 그 외에 파일 스냅샷에 대한 정보는 따로 전달하지 않았기 때문입니다. 그러니 당연히 이미지는 package.json에 대한 정보를 갖고 있지 않은 것입니다.

이는 COPY 부분을 dockerfile에 넣음으로써, 컨테이너를 생성하는데 필요한 파일들을 복사해주는 것입니다.
사용 용례는 다음과 같습니다.

copy from to

아래와 같이 도커파일을 수정해주었습니다.

이때 주의해야할 점은 npm install 이전에 package.json을 복사해줘야해서 COPY를 RUN보다 위쪽에 배치해야한다는 것입니다.

이제 해당 파일을 빌드해보겠습니다. 이번에는 따로 이름을 설정해줘서 빌드해보겠습니다.

이번에는 처음 설치와 다르게 베이스 이미지 관련된 파일들이 캐시에 있어서 금방 실행이 되었고, npm install이 기존에 서버 관련 코딩할때와 유사하게 시간이 오래걸리는 것 말고는 몇 개의 warning만 뜰 뿐 오류없이 잘 실행됨을 확인할 수 있었습니다. 이제 이를 기반으로 컨테이너를 생성해 앱을 실행해보겠습니다.

또 오류가 납니다. 해당 에러에 대한 이유는 위와 똑같습니다. package.json 뿐만 아니라 웹을 구현해 준 다른 파일들을 전달해주지 않았기에 같은 오류가 나는 것입니다. 그렇기에 사실 package.json만 전달해야하는 게 아니라 디렉토리 전체를 복사해야하는 것입니다. 결국 최종 dockerfile은 아래와 같습니다.

아래와 같이 잘 빌드됩니다.

port mapping

하지만 localhost:3000을 접속해보면... 접근이 되지 않습니다 :(

왜냐하면 컨테이너의 네트워크와 우리가 접속하려고 하는 네트워크가 연결이 되지 않았기 때문입니다. 위에서 파일 스냅샷을 컨테이너에 넘겨주었듯이 네트워크에 대한 설정 역시도 넘겨주어야 합니다. 그리고 이러한 과정은 docker run에 포트 매핑을 해주는 parameter를 추가해줌으로써 해결할 수 있습니다. 포트 매핑하는 방법은 다음과 같습니다.

dockr run -p local_port:web_port image

이렇게 포트 매핑을 해주면 localhost:5001로 접속했을 때, 정상적인 홈페이지가 나옴을 확인할 수 있습니다.

WORKDIR

아무 조건 없이 위와 같이 dockerfile을 작성하게 된다면 소스코드 관련 파일들은 전부 root directory에 저장이 됩니다. 하지만 이런 방법은 나중에 코드를 볼 때도 너무 불편하고 혹여나 base image의 파일들과 중복된 이름의 파일들이 있으면 이를 덮어씌워 문제를 발생시킬 수도 있습니다. 그래서 우리가 복사해줄 소스들은 모두 work directory를 따로 만들어서 보관할 필요성이 있습니다. 이는 도커파일에 다음과 같은 문구를 추가해서 설정해줍니다.

WORKDIR directory

아래와 같이 dockerfile을 변경해주었습니다. 이때 COPY보다 위에서 폴더를 설정해주어야 복사하고자 하는 소스코드들이 원하는 work directory에 잘 저장될 것입니다.

빌드하고 컨테이너를 생성해 소스코드가 아래와 같이 우리가 원하는 경로에 잘 저장되어있음을 확인할 수 있습니다.

When we modify source code...

위에서 실습한대로 만약 우리가 계속 개발을 진행한다면 우리는 매번 소스코드를 수정하고 확인할 때마다 도커 이미지를 빌드하고 컨테이너를 생성한 후 앱을 테스트해야 합니다. 해당 과정을 최대한 효율적으로 하기 위해 다음과 같이 dockerfile을 변경할 수 있습니다.

우선, build 시에 파일이 조금이라도 변경 되었을 경우 copy 부분이 run보다 위에 있기 때문에 매번 패키지를 재설치 해주었습니다. 그래서 이를 간소화 하기 위해 dockerfile을 다음과 같이 바꿔줄 수 있습니다.

이렇게 변경할 경우에는 pacakge.json 파일이 변경되었을 때만 빌드 시에 npm install을 실행하고 아닐 경우에는 그저 소스코드만 변경하는 식으로 기존에 방식보다 좀 더 빠르게 빌드됨을 확인할 수 있습니다.

Docker Volume

위에서 말했던 것처럼 불필요한 npm install을 줄여주어 어느정도 최적화를 진행했지만 아직은 빌드 실행과정에서 드는 시간이 너무 깁니다. 그렇기때문에 기존에 시간을 많이 차지했던 COPY 대신에 VOLUME이라는 개념이 존재합니다. 기존에는 local에서 container로 파일을 복사하는 것이라면 Volume의 개념은 container가 local의 파일을 참조하는 방식입니다.

Volume을 사용해서 앱을 실행하는 명령어는 다음과 같습니다.
docker run -p 5000:3000 -v /usr/src/app/node_modules -v $(pwd):/usr/src/app <imageID>

node_modules(패키지 관련 정보) app(소스코드)들에 대해서는 현재 디렉토리에 있는 파일들을 참조한다는 것이고, 이제는 소스코드를 변경할 때 따로 빌드를 하지 않고 단순히 컨테이너를 껐다 켜주면 변경된 점이 바로 반영되는 것을 확인할 수 있습니다.

profile
글많은 개발자

0개의 댓글