Docker

[Docker] 도커 시작하기 pull, rm, ps, etc...

언킴 2022. 3. 1. 14:23
반응형

도커는 Linux 컨테이너를 만들고 사용할 수 있도록 하는 컨테이너화 기술이다.[참고] 도커를 사용하면 매우 가벼운 가상 머신처럼 사용할 수 있고, 컨테이너를 구축 및 배포 및 복사를 하고 환경 간 이동이 유연하게 사용될 수 있다. 또한, 도커의 접근 방식은 전체 App을 분해할 필요 없이 App의 일부를 분해하고, 업데이트 등이 가능하다는 점이 중요하다. 하지만 계속해서 컨테이너화 된 앱을 많이 사용하게 되면 관리가 어려워지게 된다. 이때 컨테이너 간 그룹화하는 작업을 수행할 때 쿠버네티스(Kubernetes)가 사용된다. 쿠버네티스는 다음에 한 번 다루어 보도록 하자. 도커를 처음 시작하면 생소한 단어가 존재한다. 바로 '이미지(Images)'와 '컨테이너(Containers)'다. 

 

Docker Images

도커 이미지는 컨테이너를 생성할 때 필수적인 요소라고 볼 수 있다. 도커 이미지는 컨테이너 실행에 필요한 설정값을 포함하고 있으므로 용량이 엄청나다. 또한 컨테이너에 따른 상태값이 변화하지 않으므로, 라이브러리의 버전이 의도치 않게 바뀜에 따른 의존성 문제가 발생하지 않는다. 컨테이너는 이미지를 실행한 상태를 의미하며, 변하는 값은 해당 컨테이너 안에서만 변경된다. 같은 이미지 내에서 여러개의 컨테이너를 생성하여 사용할 수도 있다. 이미지는 도커 내에 명령어를 실행함으로써 내려받을 수 있기 때문에 도커처럼 별도의 설치가 요구되지는 않는다. 도커 이미지는 [저장소이름]/[이미지이름]:[태그] 형태로 구성되어 있다. 저장소는 이미지가 저장되는 장소를 의미하며 이미지 생성시 생략이 가능하다. 이미지는 해당 이미지가 어떤 역할을 나타내는지 이름으로 설정해줄 수 있다. 마지막으로 태그는 이미지의 버전관리 등 관리용도로 사용한다. 

 

Docker Containers

도커 컨테이너는 소프트웨어 서비스를 실행하는 데 필요한 버전의 프로그래밍 언어, 런타임 및 라이브러리와 같은 종속적인 항복과 App code를 함께 포함하는 패키지이다. 컨테이너는 CPU, 메모리, 리소스 등을 쉽게 공유할 수 있어 유용하다. 이미지는 파일들의 집합이고 컨테이너는 이 파일들의 집합 위에서 실행된 프로세스로 이해하면 된다. 

 

위에서 언급한대로 도커 이미지의 용량은 엄청나기 때문에 도커의 이미지가 변할때마다 새롭게 다운받아 이미지를 구축한다면 매우 비효율적일 것이다. 이를 해결하기 위해 도커 레이어(Docker Layer)라는 개념을 이용한다. 도커 레이어는 이미 구축된 이미지에 다른 기능을 추가하고 싶을 때 기존 이미지에 다른 한 부분만 추가하여 이미지를 구축하는 형태를 의미한다. 

 

이미지와 컨테이너는 도커를 이해하는 데 있어 가장 중요한 개념이다. 먼저 이미지 개념에 대해서 살펴보고 넘어가자. 이미지는 위에서 언급했다시피 어떤 App을 실행하기 위한 환경이라고 이야기할 수 있다. 이 환경은 파일들의 집합이라 용량이 엄청나고, 이 이미지를 기반으로 App을 바로 배포할 수도 있다. 

 

docker images

도커 레지스트리에서 centos 이미지를 받아오고, 이 이미지를 통해 컨테이너를 실행해보자. 

$ docker images

REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

위와 같은 형태로 출력이 되면 현재 도커 내에 이미지는 아무것도 없다는 것을 의미한다. docker pull <IMAGE_NAME>을 통해 도커 이미지를 받아올 수 있다. 

 

docker pull

도커 허브에서 이미지를 다운받는 행위를 pull이라고 한다. 해당 링크에 접속하게 되면 여러가지 컨테이너들이 존재한다. 우리는 인기있는 컨테이너 중에서 centOS 이미지를 가지고올 것이다. 아파치 웹 서버라고하는 프로그램을 컨테이너 위에서 실행시키고 싶다면 아파치 웹 서버가 설치되어 있는 컨테이너를 찾으면 되고, 컨테이너는 httpd를 찾아서 하면 된다.  소프트웨어 옆에 Official Image는 도커에서 인증하는 공식 이미지라는 것을 의미한다. 

 

$ docker pull centos
Using default tag: latest
latest: Pulling from library/centos
a1d0c7532777: Pull complete
Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Status: Downloaded newer image for centos:latest
docker.io/library/centos:latest


$ docker pull httpd

만약 따로 태그를 지정해주지 않으면 latest로 지정된다(가장 최신 버전을 다운받아 온다는 의미이다). 도커는 먼저 이미지를 로컬에서 찾아본 후 없으면 도커 공식 저장소에 접근해 찾아본다. 그 후 이미지를 pull 한다. 마지막에 centos:latest 는 centos라는 이미지, latest라는 태그로 불러온 것을 확인할 수 있다. 상세한 내용을 원한다면 도커 공식 문서를 참고하자.

 

 docker pull [OPTIONS] NAME[:TAG|@DIGEST]

 

도커에서는 download, install 과 같은 명령어 대신 pull이라는 명령어를 사용한다. 이미지를 업로드할 때에는 push, 새로운 이미지를 생성할 때에는 commit, 이미지의 차이를 확인할 때에는 diff 라는 명령어를 사용한다. 이러한 명령어는 Git이나 Subversion에서 사용되는 명령어와 동일하므로 익숙해질 필요가 있다. 도커에 이미지가 제대로 설치되엇는지 확인하기 위해서는 아래의 코드를 입력해 확인할 수 있다. 

$ docker images

REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
centos       latest    5d0da3dc9764   5 months ago    231MB
httpd        latest    faed93b28859   16 hours ago    144MB

 REPOSITORY는 centos, TAG는 latest, 용량은 231MB로 불러오는 것을 확인할 수 있다. 도커에서는 하나의 이미지를 저장소$^{REPOSITORY}$라고 부른다.  IMAGE ID는 이미지를 가리키는 고유한 해시 값을 의미하고, CREATED는 이미지가 생성된 시간을 나타낸다. 

 

docker info

$ docker info

Registry: https://index.docker.io/v1/

docker info를 통해서 client에 지정된 기본 레지스트리 주소를 확인할 수 있다. https://index.docker.io/v1/ 로 작성되어 있는데, 도커 허브의 과거 도메인이라 접근이 안된다. 여기를 통해 접근할 수 있다. 앞선 환경에서 다운로드 받은 centos에 대한 정보는 해당 링크를 따라가면 확인할 수 있다. 

centos

도커에서는 우분투$^\mathsf{Ubuntu}$, 센트OS$^\mathsf{CentOS}$와 같은 리눅스$^\mathsf{Linux}$ 운영체제 이미지와 MySQL, 레디스$^\mathsf{Redis}$와 같이 자주 사용되는 App에 대한 공식 이미지를 제공하고 있다. 해당 링크​에 접속하면 도커 허브에서 제공하는 이미지를 확인할 수 있다. 

 

 

컨테이너(Container) run

우리는 이미지를 호출해서 가지고 왔다. 그렇다면 이제 컨테이너에 대해서 다루어보자. 컨테이너는 이미지 환경 위에서 프로세스릉 생성해 실행시키는 것을 의미한다. 컨테이너를 실행시키기 위해서는 무조건적으로 이미지가 필요하다. 컨테이너는 다음과 같은 코드를 통해 실행시킬 수 있다. 이미지를 실행시키는 행위를 run이라고 부르며, run을 하게 되면 이미지가 컨테이너가 되고, 컨테이너가 실행되면서 컨테이너 내부에 포함되어 있는 실행되도록 조치되어 있는 파일들이 실행되면서 그 프로그램을 사용할 수 있게 되는 것이다. 

 

1. 도커 데스크탑

도커 데스크탑에서 RUN을 하려면 Images를 클릭해 해당 RUN 버튼을 누르면 간단하게 실행시킬 수 있다. 컨테이너 이름을 지정하지 않고 바로 Run을 눌러도 실행이 되지만, 이미지 위에 컨테이너가 많으면 어떤 컨테이너인지 구분하기가 어렵기 때문에 Container Name을 지정해주어 본인이 사용하고자 하는 컨테이너의 이름을 지정해주어 구분짓자.

 

2. command

cmd창에서 사용하기 위해서는 docker run 이라는 코드를 사용하여 위와 같은 동일한 형태를 나타낼 수 있다. 이미지의 이름 앞에는 옵션을 적고, 이미지의 이름 뒤에는 컨테이너 안에서 실행하고 싶은 명령어를 입력할 수 있다. 대괄호로 표시되어 있는 부분은 생략이 가능하다는 뜻이다. 

$ docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

 

$ docker run -it centos:latest bash

[root@acd81f29c8bb /]#

docker run -it <이미지이름:태그> <명령어> 를 사용하여 latest 태그를 가진 centos라는 이미지를 bash 한다고 이해하면 된다. 우리는 CentOS 환경으로 접근을 한 것으로 볼 수 있다.  우리가 실행한 컨테이너를 보고 싶을때에는 docker ps를 통해서 확인할 수 있을 것이다. 

$ docker run --name testing -it centos:latest bash

[root@fd11635fc7b0 /]#


$ docker ps

CONTAINER ID   IMAGE           COMMAND   CREATED          STATUS          PORTS     NAMES
fd11635fc7b0   centos:latest   "bash"    28 seconds ago   Up 27 seconds             testing

새로운 Power Shell을 열어서 출력을 해야된다. 만약 exit 를 사용하거나 ctrl+D를 통해 컨테이너를 나간 후 위 코드를 작성할 시 동일한 결과값이 출력되지 않을 것이다. 마지막 NAMES은 임의로 붙여진 컨테이너의 이름이다. 컨테이너를 조작할 때에는 해당 컨테이너 아이디를 사용할 수도 있고, 이름을 사용할 수도 있다. 이름은 docker run 을 실행할 때 --name 으로 옵션을 설정해 명시적으로 지정할 수 있지만, 지정하지 않을 경우 임의의 이름으로 할당된다. 

 

위에서 언급했든 하나의 이미지는 여러개의 컨테이너를 생성할 수 있다. 아래와 같이 --name을 지정해주어 다른 컨테이너를 생성해보자. 

$ docker run --name testing1 -it centos:latest bash

[root@fd11635fc7b0 /]#


$ docker ps

CONTAINER ID   IMAGE           COMMAND   CREATED          STATUS          PORTS     NAMES
fd11635fc7b0   centos:latest   "bash"    28 seconds ago   Up 27 seconds             testing
47088a3247d9   centos:latest   "bash"    28 seconds ago   Up 27 seconds             testing1

 

그후 컨테이너를 멈추고 싶을 때에는 아래의 코드를 작성해 멈출 수 있다. 

$ docker stop [OPTIONS] CONTAINER [CONTAINER...]

컨테이너의 이름을 작성해도 되고, 컨테이너의 아이디를 입력해도 동일하게 적용된다. 

 

$ docker stop testing

$ docker ps
CONTAINER ID   IMAGE           COMMAND   CREATED          STATUS          PORTS     NAMES
47088a3247d9   centos:latest   "bash"    28 seconds ago   Up 27 seconds             testing1

ps로 확인해보면 testing이라는 이름을 가진 컨테이너가 없어진 것을 확인할 수 있다. 그렇다면 해당 컨테이너는 정말로 없어진 것일까? 아니다. docker ps -a을 입력하면 종료된 컨테이너까지 출력이 되며, stop을 한다고 삭제되는 것은 아니라 컨테이너는 남아있게 된다. 

 

CONTAINER ID   IMAGE     COMMAND              CREATED         STATUS                     PORTS     NAMES
3035c3655844   httpd     "httpd-foreground"   4 minutes ago   Exited (0) 2 minutes ago             testing
47088a3247d9   httpd     "httpd-foreground"   6 minutes ago   Up 6 minutes               80/tcp    testing1

 

docker restart

컨테이너를 죽이고 난 후 다시 살리고 사용하기 위해서는 아래와 같은 코드를 통해 되살릴 수 있다. 제거된 bash까지 보기 위해서는 docker ps -a 을 통해 확인할 수 있다. NAMES을 통해서 호출해도 되고, CONTIANER ID를 통해 호출해도 된다. docker attach <NAMES> or <CONTAINER ID> 를 통해 입력이 가능한 상태로 변경해준다. 

$ docker restart fd11635fc7b0 

fd11635fc7b0 


$ docker ps 

CONTAINER ID   IMAGE           COMMAND   CREATED         STATUS         PORTS     NAMES
fd11635fc7b0   centos:latest   "bash"    2 minutes ago   Up 5 seconds             testing



$ docker restart testing 

testing

$ docker ps 

CONTAINER ID   IMAGE           COMMAND   CREATED         STATUS         PORTS     NAMES
fd11635fc7b0   centos:latest   "bash"    2 minutes ago   Up 5 seconds             testing



$ docker attach testing

[root@fd11635fc7b0 /]#

docker ps 에서 -a 인자는 죽은 컨테이너도 상관없이 모든 컨테이너를 호출하는 코드이다. -q 인자는 컨테이너의 ID를 가져오는 옵션이며 -q를 출력하게 되면 각 컨테이너의 ID를 한 줄에 하나 씩 출력해주게 된다. 또한 $() 문법은 괄호 사이에 오는 명령어를 실행한 다음 출력 결과로 오는 내용을 치환해준다.  아래와 같이 여러가지 형태로 사용할 수 있다. 

 

$ docker ps -a -q

531eda33e46c
63933c72a243


$ docker ps -qa

531eda33e46c
63933c72a243



$ docker ps -aq

531eda33e46c
63933c72a243

 

docker rm -f

도커에서 컨테이너를 생성한 후 삭제하고 싶을 경우 doker rm <CONTAINER ID> 혹은 docker rm <CONTAINER NAME>을 입력해주면 삭제된다. docker stop <CONTAINER ID> 를 통해 컨테이너를 정지시킬수 있고, 이때 컨테이너 아이디를 전부 기입해주지 않고, 컨테이너 아이디가 식별될 정도의 값만(4~5개) 입력해주어도 삭제된다. 추가적으로 현재 실행 중인 컨테이너는 삭제할 수 없다!

 

만약 stop을 하지 않고 컨테이너를 삭제하고 싶다면 아래의 코드를 입력하면 된다.

$ docker rm --force [CONTAINER]

$ docker rm -f [CONTAINER]

 

 

만약 컨테이너가 많을 경우 아이디를 하나하나 기입해서 제거하기에는 너무 오랜 시간이 소요되며 비효율적이다. 이 경우 docker rm -f $(docker ps -aq) 를 통해 모든 컨테이너를 삭제할 수 있다.  전체 삭제할 경우 복구가 안되니 주의하자.

# 전체 삭제
$ docker rm -f $(docker ps -aq)


# 중지된 컨테이너만 제거하고 싶을 경우 
$ docker container prune

WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
531eda33e46cf14d95a174aeed1a2dec66d2f1c8d974fe774475eb85f4435b50
63933c72a24302665e735958b84cf3c32d6bbef4fac0c4a2319d3bbae8de7e68

Total reclaimed space: 10B

 

지금까지 도커에서 컨테이너를 설치하는 법을 다루었다. 컨테이너 위에서 우리가 무엇을 하더라도 이미지는 변화하지 않는다. 컨테이너에서 어떻게든 버전을 바꾸고 뭘하더라도 이미지는 그대로 보존하고 있다. 그 대신 이미지 위에서 무언가를 더해 새로운 이미지를 만들어내는 것은 가능하다. 이미지를 기반으로 만들어진 컨테이너는 변경이 가능하기 때문이다. 마치 깃$^mathsf{Git}$ 저장소에 새로운 커밋$^mathsf{Commit}$ 하는 것 처럼 도커에 새로운 이미지를 생성해보자. 

 

만약 우리가 협업을 하고 있다고 가정해보자. 이떄 docker rm -f 나 prune을 통해서 중지된 컨테이너를 지워버리면 내가 사용한 컨테이너가 아니더라도 지워질 수 있기 때문에 사용을 조심해야된다. 이럴 때 내가 사용한 컨테이너에 대해서만 삭제하는 명령어를 입력하고 싶을 땐 어떻게 해야할까?

$ docker rm $(docker ps -a - q -f ancestor=<IMAGE NAME>

ancestor 인자를 통해 이미지 이름을 선택해줌으로써 내가 사용한 이미지를 삭제할 수 있을 것이다. 

 

docker rmi

이미지를 삭제하고 싶을땐 rm이 아니라 rmi를 통해 삭제할 수 있다. 

$ docker rm 1eb3aee22160

$ docker rmi [OPTIONS] IMAGE [IMAGE...]

 

 

Git with Doker

$ docker pull ubuntu:bionic
...

$ docker run -it ubuntu:bionic bash

root@4f039bde29ec:/#



root@4f039bde29ec:/# apt update

root@4f039bde29ec:/# apt install -y git

root@4f039bde29ec:/# git --version

공식 우분투 이미지(ubuntu:bionic)는 사용자가 루트로 설정되어 있어서 sudo와 같은 명령어를 사용하지 않더라도 apt를 직접 사용해 패키지를 설치할 수 있다. apt를 통해 git을 설치해보자.

 

# git 설치 전 -> 아무것도 출력되지 않음.
$ docker diff 4f039bde29ec
...


# git 설치 후 -> 많은 파일들이 설치되어 있음.
$ docker diff 4f039bde29ec
...
...
...
...
...

하지만 동일한 이미지로 다른 컨테이너를 생성해 git 명령어가 있는지 확인해볼 경우 git --version의 확인이 불가능하다. ubuntu:bionic 이미지에 git이 설치된 새로운 이미지를 생성해서 git이 추가된 이미지를 만들어보자. 이럴때 사용하는 것이 commit이다. commit에 대한 자세한 내용이 궁금하다면 여기를 참고하면 된다. 

 

$ docker run -it --rm ubuntu:bionic bash 

root@7b352be21193:/# git --version
bash: git: command not found




$ docker commit 4f039bde29ec ubuntu:git
sha256:24959eb53c49714e583262cdecc47b69dcc6395a15c776b2c5477df06e5f4912

$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
ubuntu       git       24959eb53c49   4 minutes ago   197MB
ubuntu       bionic    dcf4d4bef137   3 weeks ago     63.2MB
centos       latest    5d0da3dc9764   5 months ago    231MB


root@1eb3aee22160/# git --version
git version 2.17.1
root@1eb3aee22160:/#

commit 한 후 ubuntu:git에 제대로 git이 설치된 것을 확인할 수 있다. 여기서 알아두어야할 부분은 이미지에서 생성된 컨테이너가 하나라도 남아있다면 해당 이미지는 삭제할 수 없다. 따라서 컨테이너를 먼저 종료하고, 삭제까지 해주어야지만 이미지를 삭제할 수 있다.