도커 이미지와 컨테이너는 도커를 이해하는데 가장 중요한 개념입니다. 우선 이미지에 대해 알아보겠습니다. 이미지는 어떤 애플리케이션을 실행하기 위한 환경이라고 예를 들 수 있으며 환경은 파일들의 집합입니다.
간단히 예제로 알아보겠습니다.
도커에서는 docker pull <IMAGE_NAME> 명령어로 이미지를 풀 받을 수 있습니다.
$ docker pull centos
Using default tag: latest
/usr/bin/docker-credential-desktop.exe: Invalid argument
latest: Pulling from library/centos
Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Status: Image is up to date for centos:latest
docker.io/library/centos:latest
이미지는 :를 기준으로 이미지 이름, 태그로 구분됩니다. 태그를 따로 지정해주지 않으면 latest가 기본값으로 저장됩니다.
이제 풀을 받았으니
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest 5d0da3dc9764 2 years ago 231MB
centos/latest 이미지가 추가되었습니다. 도커에서는 하나의 이미지를 저장소(Repository)라고 부릅니다. 태그는 따로 지정해주지 않았으므로 latest가 기본값으로 저장되었고 TAG는 이미지를 버저닝 하기 위해 사용됩니다.
컨테이너는 이미지 환경 위에서 특정한 프로세스를 격리시켜 실행한 것입니다.
즉, 컨테이너 안에서 이미지가 실행되는 것 입니다. 컨테이너는 docker run 명령어를 통해 실행 할 수 있습니다. 지금 살펴볼 예제에서는 셸을 실행하기 위해서 -it 명령어를 사용했습니다.
docker run -it <이미지이름:태그> <명령어>로 centos 기반의 컨테이너를 실행 시켜보겠습니다.
$ docker run -it centos:latest bash
[root@538d2df82b5b /]#
셸 프롬포트가 변경되었습니다. 자칫 오해할 수 있는 것이 우분투 환경에서 Centos OS환경에 접속한 것처럼 보이지만 다른 서버에 SSH프로토콜을 사용하여 접속한 것처럼 보일 수도 있다는 것 입니다. 실제로는 호스트OS와 격리된 환경에서 bash 프로그램을 실행했다고 이해하는 것이 맞습니다.
새로운 명령어를 하나 더 배우겠습니다.
앞에서 docker images 명령어를 사용하여 풀 받은 이미지들의 목록을 확인할 수 있었는데요
이번에는 현재 실행중인 컨테이너의 목록을 확인할 수 있는 docker ps입니다. 컨테이너로 실행하고 있는 셸을 놔두고 다른 터미널을 열고 docker ps 명령어 입력해보겠습니다.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
538d2df82b5b centos:latest "bash" 4 minutes ago Up 4 minutes loving_keldysh
4분전에 실행한 컨테이너가 실행되고 있는 것이 보입니다. docker ps 명령어로 실행하고 있는 컨테이너 정보를 확인할 수 있다는 것을 알 수 있습니다.
여기서 CONTAINER ID는 앞으로 도커 컨테이너를 조작할 때 사용하는 아이디이기 때문에 필수적으로 알아두어야 합니다. 컨테이너를 조작할 때 아이디를 사용할 수 도 있고 이름을 사용할 수 도 있습니다. 이름은 docker run 할 때 --name 옵션을 사용해서 이름을 지정할 수 있지만, 지정하지 않는다면 자동으로 이름이 부여됩니다.
위의 예제에서는 이미지를 컨테이너로 실행시켜보았는데요. 이번에는 셸을 종료하고 컨테이너 목록을 확인해보겠습니다. exit 명령어를 이용하여 종료할 수 있습니다.
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
538d2df82b5b centos:latest "bash" About an hour ago Exited (130) 5 seconds ago loving_keldysh
5초 전에 컨테이너가 종료 되었다는 것을 볼 수 있습니다.
이번에는 restart 명령어를 사용해서 컨테이너를 살려보겠습니다.
$ docker restart 538d2df82b5b
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
538d2df82b5b centos:latest "bash" About an hour ago Up 10 seconds loving_keldysh
10초 전에 컨테이너가 다시 살아난것을 볼 수 있습니다. 하지만 셸과 입출력을 주고받을 수 있는 상태가 아직 아니기 때문에 컨테이너로 실행된 프로세스와 터미널 상에서 입출력을 주고 받기 위해서는 attach 명령어를 사용해야합니다.
$ docker attach 538d2df82b5b
[root@538d2df82b5b /]#
다시 도커 컨테이너 안으로 들어온것을 볼 수 있습니다. 지금까지 도커 컨테이너의 생명 주기에 대해 알아보았습니다. 도커를 실행하기 위한 run, 종료된 컨테이너를 다시 실행하기 위해 restart, 외에도 컨테이너를 강제 종료 하기위한 stop 명령어도 있으며, 종료된 컨테이너를 삭제하는 rm 명령어도 있습니다.
도커에서 이미지는 불변한 저장 매체입니다. 한 번 생성된 이미지를 실행한다고해서 변형이 되지 않습니다. 대신 도커에서는 이미지 위에 새로운 이미지를 만들어 내는 것은 가능합니다.
예제로 알아보겠습니다.
$ docker pull ubuntu:bionic
$ docker run --it ubuntu:bionic bash
root@c4c9ebe5e6e5:/#
현재 실행한 컨테이너에 git을 설치해보겠습니다.
root@c4c9ebe5e6e5:/# apt update
root@c4c9ebe5e6e5:/# apt install -y git
root@c4c9ebe5e6e5:/# git --version
git version 2.17.1
다른 셸에서 diff를 실행해보겠습니다.
$ docker diff c4c9ebe5e6e5 | head
C /bin
A /bin/less
A /bin/lessfile
A /bin/lesskey
A /bin/lesspipe
A /bin/lessecho
C /usr
C /usr/lib
A /usr/lib/sasl2
A /usr/lib/ssl
패키지 하나를 설치하면서 많은 파일들이 생성되고 교체된것을 볼 수 있습니다. 즉, 컨테이너가 다른 작업을 한다해도 원래의 이미지가 달라지지 않습니다. 이를 확인해보기 위해 원래 이미지에서 새로운 컨테이너를 하나 더 실행하고 git이 설치되었는지 확인해보겠습니다.
$ docker run -it ubuntu:bionic bash
$ git --version
bash: git: command not found
방금 전까지 컨테이너에서는 git이 설치되었지만 새로 실행한 컨테이너에는 git이 설치되지 않았습니다. 지금부터 ubuntu:bionic 이미지에 git이 설치된 새로운 이미지를 생성해보겠습니다.
$ docker commit c4c9ebe5e6e5 ubuntu:git
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu git bbdf07de9f23 16 seconds ago 203MB
git버전의 이미지가 생성된 것을 볼 수 있습니다.
$ docker run -i -t ubuntu:git bash
$ git --version
git version 2.17.1
git이 설치되어있습니다.
지금부터는 이미지를 삭제하는 방법에 대해 설명드리겠습니다. 하나 알아두어야 하는 중요한 것은 이미지에서 파생된 컨테이너가 하나라도 실행중에 있다면 이미지는 삭제할 수 없습니다.
즉, 컨테이너 종료 -> 컨테이너 삭제 -> 이미지 삭제
docker rm이 컨테이너를 삭제하는 명령어이고 docker rmi가 이미지를 삭제하는 명령어 입니다.
먼저 컨테이너를 지우고 이미지를 삭제하겠습니다.
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a0adb4f35e51 ubuntu:git "bash" 2 minutes ago Exited (127) 1 second ago sweet_wu
$ docker rm a0adb4f35e51
a0adb4f35e51
$ docker rmi ubuntu:git
Untagged: ubuntu:git
Deleted: sha256:bbdf07de9f2352df0235ac6e24d7eaf711e256c26e345556648fa8162970341b
Deleted: sha256:c4610ee8dedb063d2b5e0a540232396b4129179fcf0bbf4c941ace82cbe8ef71
지금까지 도커 생명주기에 대해 설명드렸습니다. 도커 이미지를 pull로 받아오고 commit으로 새로운 이미지를 만들고 rmi 명령어로 이미지를 삭제해보았습니다.