간단히 혼자서 사용 할 앱이라면 그냥 서버에 직접 모든 세팅을 해두고 실행하면 되지만, 규모가 좀 되는 앱의 경우는 트레픽 부하를 여러 곳으로 나눠줘야 한다.

Docker 이전이라면 VM (Virtual Machine)을 여러가지 만들어서 관리하는게 일반적이었지만, Docker가 나온 이후로는 컨테이너로 관리하는 것이 일반적이게 되었다.

컨테이너 안에 앱을 실행하는데 필요한 모든 걸 담아두면, 서버의 메인 리소스, 패키지, 세팅이 어떻게 되어있나, 내가 실행하려는 앱과의 적합성을 따질 필요 없이 바로 컨테이너 이미지를 설치하고 실행하기만 하면 되기 때문에 운용이 아주 편해진다. 일일이 OS를 설치하고 필요한 패키지들을 설치하고 설정하고를 매 서버마다 해 줄 필요가 없기 때문에 앱을 실행하는데 드는 시간도 절약된다. 어떤 서버에서 실행해도 같인 컨테이너 이미지를 사용한다면 똑같은 앱을 실행할 수 있다.

출처: Docker 공식 홈페이지

위의 개념도에서 알 수 있듯이 하나의 서버에서 여러가지 다른 앱을 구동 할 때도 매우 유용하다. 예를 들어 App AApp BPackage Z라는 패키지를 사용해야 하는데 App A는 버전 1.0을, App B는 버전 2.0을 써야 할 때, VM이라면 또 다시 OS를 설치하고 패키지 앱에 맞는 각각의 패키지를 설치해줘야 하지만, Docker 컨테이너를 쓰면 단일 서버에 App AApp B를 둘 다 간편하게 실행하는 것이 가능하다. 각각의 앱을 실행하는데 필요한 패키지와 설정들은 각각의 컨테이너에서 독립적으로 돌아가기 때문이다.

이번 포스트에서는 Docker의 기초적인 사용법에 대해 알아본다.


#Docker 설치

아래 내용은 서버 OS는 Ubuntu Server 20.04 (LTS), CPU는 amd64 기반을 기준으로 작성하였다.

우선 패키지 리스트를 최신상태로 만들어준다.

sudo apt-get update

Repository들을 HTTPS로 다운 받게 하기 위해 필요한 패키지들을 설치해 준다. 대부분은 이미 기본적으로 설치가 되어있을 것이다.

sudo apt-get install \
 apt-transport-https \
 ca-certificates \
 curl \
 gnupg \
 lsb-release

Docker의 공식 GPG 키를 서버에 추가 해 준다.

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

Docker 설치에 필요한 패키지들이 있는 공식 레지스트리를 등록해 준다.

echo \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

다시 한번 패키지 레지스트리를 최신 상태로 만들어준다.

sudo apt-get update

Docker에 필요한 필수 패키지들을 설치한다.

sudo apt-get install docker-ce docker-ce-cli containerd.io

hello-world 컨테이너 이미지를 실행한다.

sudo docker run hello-world

처음엔 서버에 hello-world 이미지가 없기 때문에 이미지를 다운로드 받는 작업부터 시작 될 것이다. 이미지 다운로드가 끝나고 "Hello from Docker!"로 시작하는 메세지가 나오면 문제 없이 설치가 끝난 것이다.

docker 커맨드는 항상 sudo를 사용해야한다. 매번 sudo를 치는 것이 번거롭다면 자신의 서버 username을 docker 커맨드에 대한 admin 권한을 부여하면 된다. 자신의 usernamejohn이라면 아래와 같은 커맨드를 치면 된다.

sudo usermod -aG docker john

서버에서 로그아웃하고 다시 로그인 하면 sudo 없이 docker 커맨드를 실행해도 잘 실행되는 것을 확인 할 수 있을 것이다.

docker run hello-world

#Docker Image 다운받기

Docker Image는 기본적으로 Docker-Hub에 등록되어 있는 이미지를 다운 받도록 되어있다. Docker에 각 서비스의 공식 이미지는 (예를 들면 ubuntu라던지 nginx) Official image라고 불리운다. 앞서 사용한 hello-world도 Docker에서 만든 공식 Official image이다. Docker 사용자들이 자체적으로 만들어서 Docker-Hub에 등록해 놓은 이미지는 user image라고 하며 username/image_name 의 형식으로 명명되어있다.

샘플 이미지를 다운 받아 보자.

docker pull busybox

자신의 서버에 저장되어 있는 Docker Image의 리스트는 다음 커맨드로 볼 수 있다.

docker images

서버에 저장되어 있는 Docker Image를 삭제하고 싶은 경우는 다음 커맨드를 사용한다.

docker rmi <이미지 이름>

CLI로 Docker Image를 검색하는 것도 가능하다.

docker search <검색어>

#Container List

서버에서 현재 실행되고 있는 Container의 리스트를 볼 때는 아래 커맨드를 사용한다.

docker ps

이미 종료된 Container를 포함한 모든 Container의 리스트를 볼 때는 아래 커맨드를 사용한다.

docker ps -a

필요 없는 Container를 삭제 할 때는 아래 커맨드를 사용한다. 사용하지 않는 컨테이너는 쓸모없이 용량만 차지하기 때문에 삭제해주는 것이 좋다.

docker rm <CONTAINER ID>

이미 종료된 Container (Status가 exited)를 일괄적으로 삭제하고 싶을 때는 아래 커맨드.

docker rm $(docker ps -a -q -f status=exited)

혹은 아래 커맨드로도 종료된 Container의 일괄 삭제가 가능하다.

docker container prune

#Docker Container 실행

Docker Container를 실행하는 커맨드 자체는 간단하다.

docker run <Docker Image 이름>

하지만 이렇게 하면 container가 백그라운드에서 실행되지 않기 때문에 서버에 다른 일을 명령할 수가 없다. 그리고 포트가 지정이 안되어있기 때문에 앱에 접근을 할 수가 없다. 백그라운드에서 실행하기 위해서는 -d 플래그를 추가, 포트를 지정할 땐 -p 플래그를 사용한다.

docker run -d -p 8000:3000 <Docker Image 이름>

포트번호는 외부에서 접속 할 때 쓰는 포트:앱이 구동되고 있는 포트로 지정한다. 위 예시의 경우 http://example.com:8000이 앱에 접속할 때 사용하는 주소가 되고, 앱 자체는 localhost:3000에서 돌아가고 있다고 볼 수 있다.

관리 목적으로 컨테이너에 이름을 저장하고 싶다면 --name 플래그를 사용한다.

docker run -d -p 8000:3000 --name <사용자지정컨테이너이름> <Docker Image 이름>

백그라운드에서 돌아가고 있는 앱에 어느 포트를 지정했나 확인하고 싶은 경우는 port 명령어를 사용한다.

docker port <컨테이너이름>

컨테이너의 구동을 종료하고 싶을 땐 stop 명령어를 사용한다.

docker stop <컨테이너이름>

컨테이너의 구동이 종료되었을 때 자동으로 컨테이너가 삭제되게 실행을 하려면 --rm 플래그를 사용한다. 이렇게 하면 해당 컨테이너의 구동이 멈췄을 때, 서버 시스템에서도 컨테이너가 자동으로 삭제 된다.

docker --rm run <Docker Image 이름>

일단 이정도만 알면 이미 생성되어 있는 컨테이너 이미지들을 실행/운용/삭제 하는데 큰 문제는 없다. 하지만 자기가 만든 앱을 컨테이너화 시키고 싶은 경우 스스로 컨테이너 이미지를 만들어야 한다. 컨테이너 이미지를 만드는 법은 다른 포스트에서 다뤄보도록 한다.