[Docker] 도커로 Node 웹 애플리케이션 배포하기 - 1. 도커의 기본

tkppp·2022년 7월 26일
0

동기

그동안 잘 써왔던 AWS 프리티어가 이번달부로 종료되었다. 현재 EC2 인스턴스위에 올라가 있는 서비스를 종료하던지 Lightsail, Vultr 와 같은 가상서버 호스팅 서비스(VPS)로 서비스를 마이그레이션하던지 해야했다.

결론은 나 혼자 쓰는 서비스지만 평소에 잘 쓰고 있었기 때문에 한달에 5천원 정도의 비용을 들여 Vultr 로 서비스를 옮기기로 했다.

처음 EC2에 서비스를 배포했을때 환경 세팅 때문에 고생한 경험이 있었기 때문에 도커를 이용해 배포를 진행하기로 했다.

도커란?

도커는 애플리케이션을 신속하게 구축, 테스트 및 배포할 수 있는 소프트웨어 플랫폼이다. 소프트웨어를 컨테이너라는 표준화된 유닛으로 패키징하며, 컨테이너는 라이브러리, 시스템 도구, 코드 등 소프트웨어 실행에 필요한 모든 것이 포함되어 있다. 즉, 도커는 컨테이너 환경에서 독립적으로 애플리케이션을 실행할 수 있도록 컨테이너를 만들고 관리하는 것을 도와주는 도구이다. 도커를 통해 애플리케이션을 실행하면 독립적인 환경에서 일관된 결과를 보장한다.

도커는 컨테이너 기술을 사용하여 프로세스를 호스트OS와 독립된 격리된 컨테이너 환경에서 실행할 수 있게 해주는 운영체제 수준의 가상화 기술이다. 초기에는 컨테이너 구현에 리눅스 컨테이너(LXC)를 사용했지만 현재는 자체 컨테이너 기술을 사용한다. 자세한 내용은 이 포스트을 참조

도커를 사용했을때의 이점

도커는 호스트OS와 격리된 환경을 만들어주기 때문에 로컬 개발 환경을 도커 컨테이너로 구축한다 배포 환경과 개발 환경이 동일해진다. 즉, 같은 컨테이너 환경에서 동작하기 때문에 로컬에서 제대로 동작한다면 배포 환경에서도 제대로 동작함을 보장할 수 있다는 것이다.

EC2 서버에 배포할 때마다 로컬 개발 환경과 달라 항상 제대로 동작하지 않았던 경험이 있었는데 이런 짜증나고 귀찮은 점을 해결할 수 있다.

의문점

분명 도커와 같은 컨테이너 기술은 가상 머신과 달리 게스트 OS가 없고 호스트 OS의 리눅스 커널을 공유한다고 했다. 그런데 왜 컨테이너 내에서도 OS가 포함되는 것일까? 그 이유는 리눅스에 대한 이해가 필요하다.

흔히 우리가 아는 Ubuntu, CentOS 와 같은 리눅스 운영체제를 리눅스 배포판 이다.
리눅스 배포판은 리눅스 커널 + 자유소프트웨어(GNU 소프트웨어 등) 로 구성된다. 즉 리눅스 배포판 버전에 따라에 리눅스 커널의 버전은 다를 수 있으나 리눅스 커널을 동일하게 사용한다.

컨테이너 내에 OS를 세팅하는 것은 해당 배포판과 같은 환경을 제공하는 것이지 OS를 구동하는 핵심인 리눅스 커널은 호스트 OS의 커널을 사용한다는 것이다.

더 자세한 내용은 아래 포스트들을 참조

도커의 구성


Docker Engine, 제대로 이해하기 참조

이미지

도커에서 서비스 운영에 필요한 서버 프로그램, 소스코드 및 라이브러리, 컴파일된 실행 파일을 묶는 형태를 이미지라한다. 다시 말해, 컨테이너를 실행하기 위한 모든 파일과 설정값(환경)을 지닌 것으로, 더 이상의 의존성 파일을 컴파일하거나 이것저것 설치할 필요 없는 상태의 파일을 의미한다. 예를 들어 Ubuntu이미지는 Ubuntu를 실행하기 위한 모든 파일을 가지고 있으며, Oracle 이미지는 Oracle을 실행하는데 필요한 파일과 실행명령어, port 정보 등을 모두 가지고 있다.

이미지는 읽기 전용이며 이미지로 만든 컨테이너의 내부가 변하더라도 변경되지 않는다.

컨테이너

이미지를 실행한 상태로, 응용프로그램의 종속성과 함께 응용프로그램 자체를 패키징 or 캡슐화하여 격리된 공간에서 프로세스를 동작시키는 기술이다.

컨테이너는 호스트의 자원을 공유하며 컨테이너를 삭제할 경우 컨테이너 내에서 변경된 모든 사항은 삭제된다.

도커 사용법

도커 파일(Dockerfile)

컨테이너를 만들기 위한 이미지를 만들기 위해서는 Ubuntu, CentOS 같은 베이스 이미지를 도커 허브에서 받아 컨테이너를 실행해 컨테이너 내에서 환경을 셋업한 후 docker commit 명령어로 이미지를 만드는 방법도 있지만 직접 컨테이너 터미널에서 작업하는 건 불편하고 문제가 생길 수 도 있다. 그렇기 때문에 이미지를 빌드하는 일종의 스크립트인 Dockerfile 을 만들어 이미지를 만든다.

주요 명령어

  • FROM : 베이스 도커 이미지를 지정한다. 보통 OS 나 프로그래밍 언어 이미지를 지정하고 docker hub에서 이미지를 찾을 수 있다
  • RUN : 쉘 커맨드를 도커 이미지에서 실행한다
  • EXPOSE : 도커 컨테이너 외부에 노출할 포트를 지정한다. 단, 컨테이너에서 포트를 자동으로 오픈하지 않기 때문에 컨테이너 실행 시 지정된 포트를 열어주어야 한다
  • ENV : 컨테이너 내의 환경 변수를 지정할때 사용
  • ADD : 파일과 디렉토리를 호스트에서 지정한 도커이미지 디렉토리 안으로 복사한다. 만약 디렉토리가 없다면 새로 생성해서 복사한다. 디렉토리를 ADD하려면 끝이 “/”로 끝나야하고 파일 이름과 디렉토리 이외에도 URL도 가능하다. ADD 할려고 하는 파일이 tar 압축파일 이면 docker가 자동으로 압축을 풀어서 ADD 한다. ADD 할려고 하는 파일이나 디렉토리와 같은 이름의 파일이나 디렉토리가 벌써 image 상에 존재 한다면 덮어 씌우지 않는다
  • COPY : ADD와 기본적으로 동일하나 URL지정이 불가하며 압축파일을 자동으로 풀어주지 않는다.
  • CMD : 도커 컨테이너가 시작될 때 실행할 커맨드를 지정한다
    ENTRYPOINT : 도커 이미지가 실행될 때 기본 커맨드를 지정합니다
  • VOLUME : 호스트의 폴더를 도커 컨테이너에 연결 시킬 수 있습니다. 즉, 도커 내부에서 호스트 컴퓨터에서 지정한 곳의 파일을 읽거나 쓰거나 할 수 있다. 보통 로그 저장에 사용
  • WORKDIR : 작업 폴더를 지정한다. cd 명령어와 유사하지만 디렉토리가 존재하지 않는다면 해당 디렉토리를 만들고 이동한다
  • SHELL : 디폴트로 지정되어 있는 shell 타입을 바꿀 수 있게 해줍니다. 디폴트 쉘은 [“/bin/sh”, “-c”]

CMD와 ENTRYPOINT의 차이

CMD와 ENTRYPOINT 모두 컨테이너 실행시 수행하는 명령어이지만 CMD는 덮어씌워질 수 있고 ENTRYPOINT는 덮어씌워지지 않고 항상 실행된다는 차이가 있다.
예를 들어 docker run 명령어로 컨테이너를 실행할 때 도커 이미지 뒤에 커맨드를 입력하면 CMD는 실행되지 않고 docker run에 쓰인 커맨드가 실행된다.
이와 다르게 ENTRYPOINT로 작성된 명령어는 docker run에 커맨드를 입력하더라도 실행되고 그 후에 docker run으로 전달된 커맨드가 실행된다.

컨테이너 실행 후 항상 실행되어야 하는 커맨드라면 ENTRYPOINT를 사용하고 그렇지 않다면 CMD를 사용하면 된다.

예시

FROM node:16-alpine

# Korean Fonts
RUN apk --update add fontconfig
RUN mkdir -p /usr/share/fonts/nanumfont
RUN wget http://cdn.naver.com/naver/NanumFont/fontfiles/NanumFont_TTF_ALL.zip
RUN unzip NanumFont_TTF_ALL.zip -d /usr/share/fonts/nanumfont
RUN fc-cache -f && rm -rf /var/cache/*

# update pkg manager
RUN apk update

# bash install
RUN apk add bash

# Language
ENV LANG=ko_KR.UTF-8 \
    LANGUAGE=ko_KR.UTF-8

# Set the timezone in docker
RUN apk --no-cache add tzdata && \
        cp /usr/share/zoneinfo/Asia/Seoul /etc/localtime && \
        echo "Asia/Seoul" > /etc/timezone

# Create Directory for the Container
WORKDIR /user/src/app

# add chromium
RUN apk add chromium

# Only copy the package.json file to work directory
COPY package.json .
RUN npm install
RUN npm install -g pm2

# Docker Demon Port Mapping
EXPOSE 80

# RUN SERVER
CMD ["npm", "run", "docker"]

마무리

지금까지 도커의 기본적인 부분을 알아보았는데 다음 포스트에는 도커를 이용해 가상 서버에 배포하는 과정을 다뤄보도록 하겠습니다

0개의 댓글