Dev

Docker – 이미지와 컨테이너, 10분 정리

March 3, 2019

Docker – 이미지와 컨테이너, 10분 정리

Docker 설치

Docker - 이미지와 컨테이너, 10분 정리

MacOS의 경우 brew를 사용해서 손쉽게 설치할 수 있다.

brew cask install docker

Ubunut의 경우 도커 문서에서 제공하는 설치 방법을 참고하고, 윈도우의 경우 도커 공식 홈페이지에서 제공하는 파일을 사용해서 설치를 진행한다.

설치 확인을 위한 간단한 예제

설치가 끝나면 아래 명령어를 터미널(iterm)이나 커맨드(cmd or powershell)에서 실행해보자. 터미널에 hello world가 출력되면 도커 설치가 제대로 된 것이다.

$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:2557e3c07ed1e38f26e389462d03ed943586f744621577a99efb77324b0fe535
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/

Docker 이미지 관련 명령어

시스템과 서비스에 필요한 코드를 모아둔 최소한의 단위를 이미지(image)라 한다. 도커는 실행에 필요한 시스템과 서비스를 운영하는데 필요한 단위를 컨테이너(container)로 관리하는데 컨테이너는 이미지를 기반으로 운영된다. 도커의 이미지는 도커가 설치된 곳이라면 어디서든 컨테이너로 작동시킬 수 있다. 도커의 시작은 이미지를 이해하는 것에서 시작한다.

이미지 검색(docker search)

도커는 공식적인 저장소에서 필요한 도커 이미지를 검색하는 방법을 제공한다. 검색결과에서 OFFICIAL[OK]로 표시된 것은 공식 이미지다. 공식 이미지의 경우 사용자명(wodby)이 붙지 않는다. 예를 들어서 nodemhart/alpine-node의 경우 node는 공식이미지이며, mhart/alpine-node는 공식이미지가 아니다.

$ docker search nginx
NAME                                                   DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
nginx                                                  Official build of Nginx.                        10940               [OK]
...
wodby/nginx                                            Generic nginx                                   0                                       [OK]

$ docker search --filter=is-automated=true nginx
NAME                                                   DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
jwilder/nginx-proxy                                    Automated Nginx reverse proxy for docker con…   1537                                    [OK]
...
wodby/nginx                                            Generic nginx                                   0                                       [OK]

이미지 다운로드(docker image pull)

도커 이미지를 다운 받는 방법은 pull 명령어를 사용해서 도커 이미지와 버전(centos:latest)을 사용해서 원하는 이미지를 다운받을 수 있다. 버전을 명시하지 않으면 가장 최신의 이미지를 다운 받는다.

// 최신버전
$ docker pull centos:latest
latest: Pulling from library/centos
a02a4930cb5d: Pull complete
Digest: sha256:184e5f35598e333bfa7de10d8fb1cebb5ee4df5bc0f970bf2b1e7c7345136426
Status: Downloaded newer image for centos:latest

// 특정 버전
$ docker pull centos:7
7: Pulling from library/centos
a02a4930cb5d: Extracting [===============================>                   ]  47.91MB/75.17MB
Digest: sha256:184e5f35598e333bfa7de10d8fb1cebb5ee4df5bc0f970bf2b1e7c7345136426
Status: Downloaded newer image for centos:7

// 모든 버전
$ docker pull -a centos
5.11: Pulling from library/centos
2068b24f564b: Downloading [=============>                                     ]  23.13MB/87.09MB
...
centos7.6.1810: Pulling from library/centos
Digest: sha256:5d4f4e6051c7cc10f2e712f9dc3f86a2bd67e457bced7ca52a71c243099c0121
centos7: Pulling from library/centos
Digest: sha256:184e5f35598e333bfa7de10d8fb1cebb5ee4df5bc0f970bf2b1e7c7345136426
latest: Pulling from library/centos
Digest: sha256:184e5f35598e333bfa7de10d8fb1cebb5ee4df5bc0f970bf2b1e7c7345136426
Status: Downloaded newer image for centos

이미지 목록 표시(docker image ls)

다운 받은 이미지를 확인하기 위해선 ls라는 명령어를 사용하면 되는데, 이미지와 관련된 내용을 확인하기 때문에 image라는 관리 커맨드(management command)를 사용하면 된다. 예를 들어 컨테이너 목록은 docker container이며 도커의 네트워크 목록은 docker network ls이다.

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              f09fe80eb0e7        2 weeks ago         109MB
centos              latest              1e1148e4cc2c        2 months ago        202MB

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              f09fe80eb0e7        2 weeks ago         109MB
centos              latest              1e1148e4cc2c        2 months ago        202MB

이미지 태그 설정(docker image tag)

동일한 이미지를 다양한 방법으로 사용해야 할 경우 해당 이미지에 별도의 이름(tag)을 설정할 수 있다.

$ docker image tag nginx:latest webserver:1.0
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              f09fe80eb0e7        2 weeks ago         109MB
webserver           1.0                 f09fe80eb0e7        2 weeks ago         109MB
centos              latest              1e1148e4cc2c        2 months ago        202MB

이미지 삭제(docker image rm)

다운로드 받은 이미지를 삭제하는 방법은 rm 명령어를 사용하면 된다. 이미지를 삭제하기 때문에 image라는 관리 커맨드를 사용한다.

$ docker image rm webserver:1.0
Untagged: webserver:1.0

$ docker rmi nginx
Untagged: nginx:latest
Untagged: [email protected]:dd2d0ac3fff2f007d99e033b64854be0941e19a2ad51f174d9240dda20d9f534
Deleted: sha256:f09fe80eb0e75e97b04b9dfb065ac3fda37a8fac0161f42fca1e6fe4d0977c80
Deleted: sha256:355e42205f69706706acf084bc2ed484ea5c034a8861b5bcebb7d8bf141fd686
Deleted: sha256:70cc0be2e302cca187cfadaaf528005d004bec56d46ae890a8a06bdd96768ef1
Deleted: sha256:0a07e81f5da36e4cd6c89d9bc3af643345e56bb2ed74cc8772e42ec0d393aee3

Docker 컨테이너

이미지가 생성되면 컨테이너를 생성할 수 있다.

Docker 컨테이너의 라이프 사이클

  1. 컨테이너 생성(docker create)
    도커 이미지를 사용해서 컨테이너를 생성한다. 도커 이미지엔 서버를 동작시키기 위하여 필요한 디렉토리 및 파일이 포함되어야 한다. 컨테이너를 생성하면 이미지의 스냅샷을 만든다. 스냅샷이란 특정 시간에 스토리지 내부에 존재하는 파일과 디렉토리를 저장한 것을 말한다. 컨테이너를 생성하면 구동하지 않는다.
  2. 컨테이너 생성 및 구동(docker run)
    도커 이미지를 사용해서 컨테이너를 생성하고 곧바로 구동까지 진행한다.
  3. 컨테이너 구동(docker start)
    중지 상태인 컨테이너를 구동할 때 사용
  4. 컨테이너 중지(docker stop)
    실행 상태인 컨테이너를 중지할 떄 사용
  5. 컨테이너 삭제(docker rm)
    컨테이너를 삭제할 때 사용

컨테이너 생성 및 실행(docker run)

기존의 이미지를 기반으로 컨테이너를 생성하고 실행하는 방법은 아래와 같다. run 명령어 뒷 부분의 -it--name "test"은 옵션이며, centos는 이미지 이름이다. /bin/cal은 해당 이미지 내부에서 실행할 명령이다.

// centos 이미지의 `/bin/cal` 명령어를 `test`라는 컨테이너로 실행
$ docker run -it --name "test" centos /bin/cal
Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
a02a4930cb5d: Pull complete
Digest: sha256:184e5f35598e333bfa7de10d8fb1cebb5ee4df5bc0f970bf2b1e7c7345136426
Status: Downloaded newer image for centos:latest
    February 2019
Su Mo Tu We Th Fr Sa
                1  2
 3  4  5  6  7  8  9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28

// 동일한 컨테이너 이름으로 실행 불가
$ docker run -it --name "test" centos /bin/cal
docker: Error response from daemon: Conflict. The container name "/test1" is already in use by container "fef7f7a3333db51772bfa04dc263712ff8d7161b3e09617fb20f7803f8f1974c". You have to remove (or rename) that container to be able to reuse that name.
See 'docker run --help'.

// 컨테이너 실행 중단
$ docker stop fef7f
fef7f

// 컨테이너 삭제(이미지 삭제가 아님)
$ docker rm fef7f
fef7f

// 실행 후 컨테이너 삭제(`--rm`)
$ docker run -it --rm --name "test" centos /bin/cal
    February 2019
Su Mo Tu We Th Fr Sa
                1  2
 3  4  5  6  7  8  9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28

$ docker run -it --rm --name "test" centos /bin/cal
    February 2019
Su Mo Tu We Th Fr Sa
                1  2
 3  4  5  6  7  8  9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28

  • -it; 현재 터미널이나 콘솔에 결과를 출력
  • --rm; 실행 후 컨테이너 삭제
  • --name "<NAME>"; 컨테이너 이름
  • centos; 이미지 이름
  • /bin/cal; 컨테이너에서 실행하는 커맨드
$ docker run -it --name "test2" centos /bin/bash
[[email protected] /]#

컨테이너의 백그라운드 실행(docker container run)

컨테이너를 시스템 백그라운드에서 계속해서 실행해고자 할 때 -d 옵션을 사용하면 된다.

$ docker run -d centos /bin/ping localhost
Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
a02a4930cb5d: Pull complete
Digest: sha256:184e5f35598e333bfa7de10d8fb1cebb5ee4df5bc0f970bf2b1e7c7345136426
Status: Downloaded newer image for centos:latest
1038715c65eef3ab578e546b6b6a1abebcd4d0ecabe685aa28c3f726435bd1a1

// 컨테이너에서 발생하는 로그를 확인
$ docker logs 1038715
...
64 bytes from localhost (127.0.0.1): icmp_seq=40 ttl=64 time=0.034 ms
64 bytes from localhost (127.0.0.1): icmp_seq=41 ttl=64 time=0.050 ms
64 bytes from localhost (127.0.0.1): icmp_seq=42 ttl=64 time=0.037 ms
  • -d; 백그라운드에서 실행
  • /bin/ping localhost; 컨테이너에서 실행하는 커맨드

컨테이너의 네트워크 설정(docker container run)

컨테이너의 내부 포트와 호스트 컴퓨터의 포트를 연결하기 하기 위한 명령어로 -p를 사용하여 호스트와 컨테이너의 포트를 적어주면 된다.

$ docker run -d -p 8080:80 httpd
Unable to find image 'httpd:latest' locally
latest: Pulling from library/httpd
6ae821421a7d: Pull complete
0ceda4df88c8: Pull complete
24f08eb4db68: Pull complete
ddf4fc318081: Pull complete
fc5812428ac0: Pull complete
Digest: sha256:5e7992fcdaa214d5e88c4dfde274befe60d5d5b232717862856012bf5ce31086
Status: Downloaded newer image for httpd:latest
88e529c70d3a4a85f5e1aa77eca3923865cd7123c0f77b15fdf0c84916358203

// 해당 컨테이너의 포트를 확인하는 방법
$ docker port httpd
80/tcp -> 0.0.0.0:8080
  • -p [Host]:[Container]; 호스트와 컨테이너 포트를 매핑
    `

Dockerfile의 예제

Dockerfile은 도커 이미지를 작성하는데 필요한 파일이다. 도커 허브에서 다운로드 받아서 사용하면 되는 경우가 많긴 하지만 해당 이미지를 만들어야 될 경우가 많다.

앞에서 도커 이미지와 컨테이너 사용법에 대해서 간략하게 소개했으니 이번에는 django 관련 도커 이미지를 만들고 컨테이너로 실행하는 방법을 실습을 통해서 실행해보자.

일단 호스트 환경에서 django 개발 환경을 설정한다.

// django 개발을 위한 가상환경 설정
$ mkdir handson-django
$ python -m venv venv
$ venv\Scripts\activate

pip를 사용해서 웹 프레임워크를 설치하고, 간단한 예제를 하나 만든다.

// pip를 사용한 django 설치하고 requirements.txt 파일을 생성하자
(venv) $ pip install django
(venv) $ pip freeze > requirements.txt
(venv) $ django-admin startproject HandsOnDocker
(venv) $ cd HandsOnDocker
(venv) $ python manage.py migrate
(venv) $ python manage.py runserver

기본적인 설정이 끝나면 django의 새로운 페이지를 하나 추가한다.

(venv) $ python manage.py startapp pages

HandsOnDocker\setting.py을 수정하자.

ALLOWED_HOSTS = ['*']

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'pages'
]

HandsOnDocker\urls.py를 추가한다.

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('pages.urls')),
]

pages\views.py에 아래 내용을 추가한다.

from django.http import HttpResponse


def homePageView(request):
  return HttpResponse('Hello, Hands-On Docker')

pages\urls.py에 아래 내용을 추가한다.

from django.urls import path

from .views import homePageView

urlpatterns = [
    path('', homePageView, name='home')
]

제대로 작동하는지 확인한다.

(venv) $ python manage.py runserver

이제 Dockerfile를 작성하자.

# `FROM`은 base image를 지정, Base image를 지정할때는 버젼까지 정확히 지정하는 것을 권장
FROM python:latest

# `EXPOSE`는 Docker container 외부에 노출할 포트를 지정
EXPOSE 8000

# `ENV`는 환경변수를 지정할 때 사용
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# `RUN`은 shell command를 해당 docker image에 실행시킬때 사용
RUN apt update -y && apt upgrade -y

# `ADD`는 파일과 디렉토리를 호스트에서 docker image로 copy
ADD . /app

# `WORKDIR`은 Working directory를 지정
WORKDIR /app

RUN pip install -r requirements.txt

# `CMD`를 사용하여 docker container가 시작할때 실행할 커맨드를 지정
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

도커 이미지를 만드는 방법과 실행은 아래와 같다.

(venv) $ docker build -t python-django .

만든 이미지를 컨테이너로 실행하는 방법은 아래와 같다.

(venv) $ docker run -it -p 8000:8000 --rm python-django

단순하게 도커 이미지를 생성하는 방법과 도커 이미지를 사용해서 컨테이너를 활용하는 방법을 알아보았다. 이후에 여러 도커 컨테이너를 사용하여 규모있는 소프트웨어를 작성하는 방법을 알아보겠다.