실습으로 배우는 Docker 입문 | 1. Docker 이미지 컨테이너 관리 메커니즘

Docker는 심플하면서도 실용적인 기능을 제공하며, 경량형 가상 환경으로 애플리케이션 배포에 활용되어 빠르게 확산되어 이용되고 있다. 이 자료는 Docker에 관심이 있으면서도 아직 경험해 보지 못한 사람을 위해 실제로 실습을 해보면서 Docker를 이해하기 위한 자료를 제공한다. 이번 장에서는 Docker 개요 및 가장 기본인 이미지와 컨테이너 관리에 대한 실제 조작 방법을 단계별로 소개한다.

Docker 실습

지금까지 Docker 자체에 대한 설명을 하였다. Docker를 제대로 이해하려면 직접 동작을 해보는 것이 가장 좋을 것이다. 꼭 한번 대충 실습을 해보길 권장한다.

Hello World를 표시해 보자.

설치가 되 프로그래머에게 익숙한 hello world를 해 봅시다.

% docker run hello-world

docker run는 이미지에서 컨테이너를 시작하는 명령어이다. 위 명령어는 hello-world 라는 이미지로 부터 컨테이너를 시작한다는 의미이다. 그러나 로컬에 hello-world 이미지가 없기 때문에, Docker 데몬이 hello-world 이미지를 Docker Hub(Docker 사가 운영하는 PaaS 형의 Docker Registry)에서 다운로드하여 이미지의 컨테이너를 시작한다. 이 컨테이너는 다음과 같이 표준 출력을 하고 종료된다.

Unable to find image 'hello:latest' locally
docker: Error response from daemon: pull access denied for hello, repository does not exist or may require 'docker login': denied: requested access to the resource is denied.
See 'docker run --help'.
% docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
b8dfde127a29: Pull complete
Digest: sha256:9f6ad537c5132bcce57f7a0a20e317228d382c3cd61edae14650eec68b2b345c
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

컨테이너에 Linux를 동작 시켜보자.

앞에서 hello-world 예제에서는 명령 라인에서 이미지 수집과 컨테이너 시작을 쉽게 할 수 있다는 것을 확인하였다.

다음은 좀 더 복잡한 예를 들어, Alpine Linux라는 컨테이너 용으로 개발된 경량 Linux 배포판의 컨테이너를 조작하는 방법을 소개한다. 이 튜토리얼을 통해 Docker를 사용하는데 있어서 가장 기본이 되는 다음 사항을 배울 수 있다.

  • 이미지 가져 오기 (pull)
  • 이미지의 나열 (images)
  • 컨테이너의 라이프 사이클 관리
    • 생성(create)
    • 시작(start)
    • 정지(stop)
    • 삭제(rm)
  • 컨테이너의 표시 (ps)

우선 alpine의 이미지를 받아 오자. 이미지를 받아 오려면 pull 명령을 사용한다.

% docker pull alpine
Using default tag: latest
latest: Pulling from library/alpine
5843afab3874: Pull complete
Digest: sha256:234cb88d3020898631af0ccbbcca9a66ae7306ecd30c9720690858c1b007d2a0
Status: Downloaded newer image for alpine:latest
docker.io/library/alpine:latest

images 명령어으로 받은 이미지 목록을 확인할 수 있다. 앞에서 hello world와 alpine의 이미지가 표시되고 있는 것을 확인할 수 있다.

% docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
alpine        latest    d4ff818577bc   26 hours ago   5.6MB
hello-world   latest    d1165f221234   3 months ago   13.3kB

그럼, 다음 alpine 이미지에서 컨테이너를 시작해 보자. 컨테이너의 시작은 run 명령어를 사용한다.

명령어 문법은 아래와 같다.

`docker run <이미지 이름> <컨테이너에서 시작하는 명령>`

run는 컨테이너를 생성(create)하고, 그 컨테이너를 시작(start)까지 진행한다. 고급 옵션은 Docker 공식 문서를 참조하여라.

% docker run alpine echo "hello from alpine"
hello from alpine

<컨테이너에서 시작하는 명령>으로 echo 명령을 지정했기에 컨테이너를 시작한 직후에 echo 명령을 실행하고 컨테이너는 종료되었다.

지금까지는 컨테이너 시작할 때 1개만 명령을 실행하고, 바로 종료가 되었는데, 컨테이너에서 대화형 명령 작업을 하고 싶은 경우에는 run 명령에 옵션 -it을 붙여 컨테이너에 연결을 해보록 하자. 다음 예제의 경우는 컨테이너를 기동하고 쉘이 실행되었기에 컨테이너에서 Linux 명령을 사용할 수 있게 되었다.

% docker run -it alpine bin/sh
/ # ls
bin    dev    etc    home   lib    media  mnt    opt    proc   root   run    sbin   srv    sys    tmp    usr    var

그리고 1개의 터미널을 더 열어서 ps 명령을 실행하여 보자. ps 명령은 현재 실행중인 컨테이너를 확인하는 명령이다. 현재 또 하나의 터미널에서 alpine 이미지에서 컨테이너를 시작하고 bin / sh 명령을 실행하는 것을 알 수 있다.

% docker ps
CONTAINER ID   IMAGE     COMMAND    CREATED          STATUS          PORTS     NAMES
d0736179149d   alpine    "bin/sh"   56 seconds ago   Up 55 seconds             nifty_keller

여기서 stop 명령을 실행하면, 컨테이너를 중지할 수 있다. 위에 alpine 컨테이너를 기동한 터미널을 열어서, 컨테이너가 정지하고 있는 것을 확인 할 수 있다.

% docker stop d0736179149d
d0736179149d

stop은 컨테이너를 종료하는 것은 아니고, 어디까지나 중지할 뿐이다. 중지한 컨테이너를 start 명령으로 다시 시작할 수 있다. ps 명령 컨테이너가 실제로 시작되고 있는지 확인한다.

% docker start d0736179149d
d0736179149d
% docker ps
CONTAINER ID   IMAGE     COMMAND    CREATED         STATUS          PORTS     NAMES
d0736179149d   alpine    "bin/sh"   5 minutes ago   Up 13 seconds             nifty_keller

그러나 이대로는 다시 컨테이너를 조작할 수 없다. 터미널에서 컨테이너에 연결하려면 attach 명령을 사용한다. 인자는 컨테이너 ID이다.

% docker attach d0736179149d
/ # ls
bin    dev    etc    home   lib    media  mnt    opt    proc   root   run    sbin   srv    sys    tmp    usr    var
/ #

컨테이너를 종료(정지 + 삭제)하려면 컨테이너에 연결한 상태에서 exit 명령어로 실행한다. (윈도우 Ctrl+C으로 가능하다.)

/ # exit

또는 stop 명령으로 정지시키고, rm 명령으로 컨테이너를 제거할 수 있다.

% docker stop 30cf0829bee2
30cf0829bee2
% docker rm 30cf0829bee2
30cf0829bee2

일단 컨테이너를 삭제하면 해당 컨테이너를 start 명령으로 재기동 할 수 없다.

% docker start 30cf0829bee2
Error response from daemon: No such container: 30cf0829bee2
Error: failed to start containers: 30cf0829bee2

컨테이너에서 Web 서버를 움직여 본다

지금까지 Alpine Linux의 이미지를 예로 이미지 및 컨테이너 관리 방법에 대해 설명하였다.

다음은 마지막 예로, 좀 더 실용적으로 Docker에 의해 Web 서버의 배포를 소개해 보도록 하겠다.

여기에서는 seqvence/static-site라는 Docker Hub 에서 공개된 이미지를 사용한다. 이 이미지의 컨테이너 내부에서는 Nginx(Web 서버)가 포함되어 있고, 액세스할 수 있는 Web 브라우저에 컨테이너내의 정적 Web 페이지 를 제공한다. Docker는 게스트 측의 포트를 호스트 측에 매핑시킬 수 있기에, Web 브라우저에 의한 호스트 포트에 대한 액세스를 게스트로 전송할 수 있다. 이렇게 하여 Docker에 Web 서버를 시작하여 Web 어플리케이션을 제공할 수 있다.

우선 컨테이너를 시작해 봅자. “Your Name"부분은 적당한 이름을 넣는다.

% docker run --name static-site -e AUTHOR="Docker" -d -p 80:80 seqvence/static-site
Unable to find image 'seqvence/static-site:latest' locally
latest: Pulling from seqvence/static-site
Image docker.io/seqvence/static-site:latest uses outdated schema1 manifest format. Please upgrade to a schema2 image for better future compatibility. More information at https://docs.docker.com/registry/spec/deprecated-schema-v1/
fdd5d7827f33: Pull complete
a3ed95caeb02: Pull complete
716f7a5f3082: Pull complete
7b10f03a0309: Pull complete
aff3ab7e9c39: Pull complete
Digest: sha256:41b286105f913fb7a5fbdce28d48bc80f1c77e3c4ce1b8280f28129ae0e94e9e
Status: Downloaded newer image for seqvence/static-site:latest
9277612d90a1c6eb434c976db6bd6f1e1c651b05c0c35b1cc053656f53544ba1

처음 시작하게 되면 위와 같이 이미지 다운로드가 진행되고, 도커가 실행되거 있다는 것을 아래와 같이 확인할 수 있다.

% docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED          STATUS          PORTS                                        NAMES
9277612d90a1   seqvence/static-site   "/bin/sh -c 'cd /usr..."   54 seconds ago   Up 52 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp, 443/tcp   static-site

위의 명령 옵션은 다음과 같다.

옵션 의미
-name static-site 컨테이너 이름으로 static-site를 지정한다.
-e AUTHOR=“Docker” 컨테이너에 환경 변수 Author 며 “Docker"를 건네준다. 이 컨테이너는 환경 변수 Author를 Web 페이지를 표시하는 데 사용하고있다.
-d Detach mode(분리 모드)로 부팅 (컨테이너가 데몬으로 백그라운드로 시작한다.)
-p 80:80 컨테이너의 개방된 포트(80)를 호스트 포트(80)에 할당한다.

위의 경우 게스트의 80번 포트를 호스트의 80번 포트에 할당하였기에 브라우저로 80번 포트에 액세스하면 Docker 컨테이너에서 Web 응용 프로그램이 생성한 Web 페이지가 표시되게 된다.

static-site의 실행 결과

(주) 사용하는 Docker Engine을 통해 액세스할 URI가 다르다.

  • Linux, Docker for Windows(Windows 10 이상), Docker for Mac (OS X 10.10 Yosemite 이상)의 경우 localhost:80에서 결과를 확인할 수 있다.
  • 그 외에는 docker-machine ip default로 Docker 데몬의 IP 주소를 확인하도록 한다.

그러면, -p 옵션을 변경하여, 호스트 측의 다른 포트에 할당할 수 있다. 다음의 경우는 두번째 컨테이너를 시작하여 게스트 측의 80 포트를 호스트의 8080 포트에 할당한다. 따라서 Web 브라우저에서 localhost:8080에 액세스하여 Web 페이지를 표시되게 할 수 있다.

% docker run --name static-site2 -e AUTHOR="My second Docker" -d -p 8080:80 seqvence/static-site
8996b832b603037d37e7d32c456fdc259929fe0a9094968ad2762c0c9651db3b

이것으로 간단한 예제를 사용하여 호스트에서 Docker 컨테이너의 Web 서버에 액세스되는 것을 확인하였다. 방화벽 설정(Linux에서는 iptables)를 변경하고 외부에서 호스트의 HTTP 포트에 액세스 가능하면 Docker의 Web 서버를 외부에 공개 할 수 있다.

이를 응용하여 클라우드 서버에 Docker를 설치하여 두면 Docker 명령에서 이미지 검색에서 컨테이너의 Web 서버 시작까지를 포함한 배포 작업을 쉽게 할 수 있다. 또한 Web 페이지의 내용을 간단히 변경하여, 호스트 측에서 다시 새로운 Docker 이미지를 가져와 컨테이너를 시작한 것으로 가능한 것을 확인 하였다.

정리

여기서는 Docker 개요 기존 이미지 및 컨테이너 작업 방법을 설명하였다. Web 서버를 배포하는 방법에 대해서도 소개하였다. 이번에서는 이미지 및 컨테이너 관리는 어렵지 않게 응용 프로그램의 배포도 쉽게 할 수 이해했을 것으로 생각된다. 그러나 실제로 Docker에서 응용 프로그램을 배포하는데 자신의 이미지를 작성하고 배포해야 한다. 다음에는 이미지를 만드는 방법 소개하겠다.