도커 우분투 이미지 사용 방법

작성 날짜수정 날짜
2020-12-30 2021-01-20

공부하게 된 계기

작년 초부터 좋다고 얘기가 나오길래 해보고 싶었다. 그런데 작년엔 리눅스 관련 지식이 부족했고, 올해는 맥북을 사서 크게 필요성을 못 느꼈다.
최근에 맥에서 Homebrew로 MySQL 5.7 설치해서 쓰려다 피 본 적도 있고, 이번 크리스마스 시즌에 오랜만에 짬도 나고 해서 본가에서 공부했다.

이 글에서 도커에 대한 모든 걸 정리할 생각은 없고, 그냥 간단하게 정리하고 공부하면서 겪었던 난관에 대해서 정리할 것이다.


도커를 사용하는 이유?

웹 애플리케이션마다 개발 환경, 배포 환경이 다르기 때문이다.
JS 기반 언어인 NodeJS, ReactJS 등의 경우 npm으로 관리할 수 있지만, 서버 환경 자체가 다르다던지, node 자체 버전이 다르다던지, DB 환경이 다르다던지 하면 난감해진다.

도커란?

도커는 컨테이너 기반의 오픈소스 가상화 플랫폼이다.
일반적인 가상 머신인 VMware, VirtualBox와 비교해보자.

가상 머신 VS 컨테이너

이름설명
VM 호스트 OS 가상화
Container 프로세스

VM은 말 그대로 호스트 OS에 공간을 할당해서 한 OS를 통째로 올리는 방식이다.
컨테이너는 프로세스를 격리하는 방식이다.
아무래도 OS를 통째로 올리는 것보다는 프로세스 격리가 더 빠를 수밖에 없다.

도커 이미지, 컨테이너

도커는 이미지와 컨테이너로 나뉜다.
이미지는 Ubuntu나 MySQL 같은 것을 라이브러리 형태로 정리한 것이라 생각하면 된다.
컨테이너 실행에 필요한 파일과 설정 값을 가지고 있다. (e.g. MySQL 이미지, Ubuntu 이미지)
컨테이너는 이 이미지를 통해서 생성되는데, 컨테이너에서 여러 작업을 하더라도 이미지는 초기 상태만 저장하고 있는 것이므로 변하지 않는다.

레이어

위와 같이 동작하는 이유는 레이어 방식을 사용하기 때문이다. 도커 이미지에 새로운 걸 설치하면 그 위에 쌓인 레이어에만 적용하기 때문에 아래 레이어는 영향받지 않는다.

도커 설치

설치 관련해서는 생략하겠다. 직접 찾아서 설치하자. 아니면 최하단의 링크를 참조해도 된다.

도커 명령어

$ docker pull [도커 이미지]

도커 이미지를 받아온다. 도커 이미지를 저장하고 있는 도커 허브가 있는데, 거기서 제공하고 있는 도커 이미지를 받아온다.

$ docker run [도커 이미지]

인자로 주어진 이미지로 컨테이너를 실행한다. 여러 가지 옵션들이 있는데, 아래에서 실습할 때 언급할 것이다. run은 정확히 말하면 해당 이미지에서 어떤 명령어를 실행할 지 결정하는 것이다.

$ docker run --rm -it ubuntu:20.04 /bin/bash

위 코드는 ubuntu:20.04 이미지로 /bin/bash 명령어를 실행한다는 뜻이다.
-it : 터미널 입력을 위한 옵션
--rm : 컨테이너가 종료되면, 해당 컨테이너 삭제
/bin/bash를 통해 컨테이너의 bash 쉘로 접근할 수 있다.
-it 옵션을 주지 않으면 그냥 출력만 하고 끝나게 된다. 이유는 도커는 사실 도커 서버-클라이언트 구조로써, 입력에 대한 출력만 뱉어주기 때문에, /bin/bash 명령어에 대한 출력만 뱉고 빠져나간다. 하지만 -it 옵션을 주면 컨테이너의 쉘에 접근할 수 있다.

docker run 옵션

이름설명사용법
-d 백그라운드 실행  
-p 포트 포워딩 -p [외부 포트]:[내부 포트]
--volume 디렉토리 마운팅 --volume [외부 디렉토리]:[내부 디렉토리]
-e 환경변수 설정 -e [이름]=[속성]
--name 컨테이너 이름 설정 --name [컨테이너 이름]
--rm 프로세스 종류시 컨테이너 삭제  
-it 터미널 입력  

원래 --link 옵션으로 컨테이너와 컨테이너를 묶을 수 있는데, deprecated 상태가 되었다.
이제 docker network를 사용해야 한다.

$ docker ps

이 명령어는 현재 실행중인 컨테이너를 보는 명령어이다.
-a 옵션은 현재 종료되어있는 컨테이너까지 모두 보여준다.

아래는 출력물 예시이다. 내가 임의로 만든 nodejs 개발용 ubuntu 서버 이미지가 실행되고 있는 모습이다.

CONTAINER ID   IMAGE                    COMMAND       CREATED       STATUS       PORTS                  NAMES
7e219c83e31d   hackloud/ubuntu:nodejs   "/bin/bash"   4 hours ago   Up 4 hours   0.0.0.0:80->3000/tcp   sweet_ganguly

COMMAND 부분이 /bin/bash라고 적혀 있는데, 이 부분이 생각보다 핵심이다. 아까도 언급했듯이 도커는 명령어를 실행하는 것이다.

$ docker stop [컨테이너 아이디]

docker stop으로 현재 실행중인 컨테이너를 종료할 수 있다. 컨테이너 아이디는 중복이 없다면 처음 몇 글자만 적어도 무방하다.

$ docker rm [컨테이너 아이디]

컨테이너를 삭제하는 명령어다. 종료된 컨테이너만 삭제 가능하다.

$ docker images

도커 이미지 목록을 볼 수 있다.
예시를 보자.

REPOSITORY        TAG       IMAGE ID       CREATED       SIZE
hackloud/ubuntu   nodejs    b0249b80a5c2   6 hours ago   718MB
ubuntu            20.04     f643c72bc252   4 weeks ago   72.9MB

내가 만든 이미지와 ubuntu:20.04 이미지가 있다. docker pull로 받아온 이미지를 여기서 볼 수 있다.

$ docker rmi [컨테이너 아이디]

도커 이미지를 삭제할 수 있다. 도커 이미지는 아무리 도커라도 어느 정도 나가니 안 쓰는 이미지는 삭제해주면 좋다.

나머지 명령어는 필요할 때마다 찾아서 쓰자. 이 정도면 기초적인 거는 모두 가능하다.

컨테이너 명령어 실행 (exec)

$ docker exec -it [컨테이너 아이디] [명령어]

보통 위 명령어를 통해 실행한다. 이미 실행 중인 컨테이너를 실행하는 것이다. 이 명령어는 간단하게 넘어가고, 이제 내가 진행했던 실습을 적어보겠다.

실습

나는 Ubuntu 개발 환경을 만들려고 했다. 그 곳에 NodeJS와 PostgreSQL을 설치해서 NodeJS 개발을 할 예정이었다.
이번뿐만 아니라 NodeJS 개발은 계속 진행할 예정이기 때문에 도커 이미지를 만들었다.
자신만의 도커 이미지를 만들기 위해서는 Dockerfile을 통해 동작을 명시해주어야 한다.

Dcokerfile

FROM ubuntu:20.04

RUN sed -i '@mirror.kakao.com@g' /etc/apt/sources.list

RUN ln -snf /usr/share/zoneinfo/Asia/Seoul /etc/localtime && \
    echo "Asia/Seoul" > /etc/timezone

RUN mkdir /app

RUN apt-get update
RUN apt-get -y install postgresql wget curl git build-essential

RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -
RUN apt-get install -y nodejs

FROM은 어떤 이미지로 컨테이너를 시작할 것인지 지정해주는 것이다.
일단 APT 미러 서버를 카카오서버로 실행해준다.
Ubuntu가 20.04로 오면서 바뀐 건지, 도커 이미지가 그런 건지는 모르겠지만, apt-get을 실행할 때 중간에 타임존을 설정하라고 멈췄다. 그래서 타임존 설정을 해줬다.
최상위 디렉토리에 웹 애플리케이션 디렉토리로 /app 을 만들어준다.
apt-get을 이용해서 PostgreSQL을 포함한 기초 툴들도 설치해준다.
NodeJS는 14.x 버전을 설치했다.

$ docker build -t hackloud/ubuntu:nodejs .

-t 옵션은 tag의 약자로 이미지에 태그를 붙이는 것이라고 생각하면 된다.
위 명령어는 Dockerfile이 존재하는 디렉토리에서 진행해야 한다.

이것저것 막 뜨면서 진행이 된다. 콘솔창을 보면 Dockerfile에 입력한 명령어들이 실행되면서 텍스트가 쭉 내려가는 것을 확인할 수 있다.

REPOSITORY        TAG       IMAGE ID       CREATED        SIZE
hackloud/ubuntu   nodejs    b0249b80a5c2   22 hours ago   718MB

이런 식으로 자신만의 커스텀 이미지를 생성할 수 있다.

$ docker run -it \
  -p 80:3000 \
  --volume=$(pwd)/src/:/app/ \
  hackloud/ubuntu:nodejs \
  /bin/bash

여기까지 잘 읽었다면 위 명령어가 뭘 뜻하는 지 대충 이해가 갈 것이다.

/* ... */
const port = normalizePort(process.env.PORT || '3000')
app.set('port', port)
/* ... */

현재 node 서버는 컨테이너에서 3000번으로 열려있다.
그리고 -p 옵션을 이용해 외부 포트 80번과 연결해줬으므로,
외부에서 80번 포트로 접근하면, 내부의 3000번 포트로 연결된다.

도커 우분투 이미지 사용 방법
도커 우분투 이미지 사용 방법

위와 같이 잘 연결되었다.
그런데 문제가 생겼다. 굳이 이렇게 Ubuntu 이미지를 생성할 필요 없이, 로컬에서 node 도커와 postgre 도커를 돌리면 되는 것이었다. Ubuntu 이미지 만들면서 공부는 제대로 했지만.. 고생을 좀 한 것 같다.

도커 우분투 이미지 사용 방법

일단 PostgreSQL 서버도 잘 동작하고, 구축 자체는 성공적으로 마쳤다.

Reference

  1. 왜 굳이 도커를 써야 하나요?      Written by 44bit
  2. 초보를 위한 도커 안내서 - 도커란 무엇인가?      Written by subicura
  3. 초보를 위한 도커 안내서 - 설치하고 컨테이너 실행하기      Written by subicura
  4. 초보를 위한 도커 안내서 - 이미지 만들고 배포하기      Written by subicura


다음 글은 로컬 환경에서 NodeJS 개발 환경을 구축해볼 것이다. 이번에 못했던 것들을 진행할건데..
이 과정도 글로 쓸 지는 의문이다. docker compose와 docker network에 관해서 이 글에 설명이 없었으니, 다음 글을 쓰게 된다면 거기서 쓰겠다.