땡글이LAB

[도커/쿠버네티스] 도커 컨테이너 다루기 본문

Devops/도커, 쿠버네티스

[도커/쿠버네티스] 도커 컨테이너 다루기

땡글이B 2022. 7. 13. 00:53

 도커 엔진에서 사용하는 기본 단위는 이미지와 컨테이너이고, 이 두 가지가 도커 엔진의 핵심이다. 두 가지에 대해 간단하게 다뤄보도록 하겠다.

 

도커 이미지

이미지는 컨테이너를 생성할 때 필요한 요소이며, 가상 머신을 생성할 때 사용하는 iso 파일과 비슷한 개념이다. 이미지는 여러 개의 계층으로 된 바이너리 파일로 존재하고, 컨테이너를 생성하고 실행할 때 읽기 전용으로 사용된다. 이미지는 도커 명령어로 내려받을 수 있으므로 별도로 설치할 필요는 없다. 

 

 도커에서 사용하는 이미지의 이름은 기본적으로 "[저장소이름]/[이미지이름]:[태그]"의 형태로 구성된다. ex) alicek106/ubuntu:14.04

  • 저장소(Repository) 이름
    • 이미지가 저장된 장소를 의미한다. 저장소 이름이 명시되지 않은 이미지는 도커에서 기본적으로 제공하는 이미지 저장소인 도커 허브(Docker Hub)의 공식 이미지를 뜻합니다. (이미지 생성 시에 저장소 이름을 명시할 필욘 없으므로 생략하기도 함)
  • 이미지 이름
    • 해당 이미지가 어떤 역할을 하는지 나타낸다. 위의 예시는 우분투 컨테이너를 생성하기 위한 이미지라는 것을 알 수 있다. 이미지의 이름은 생략할 수 없으므로 반드시 설정해야한다. 
  • 태그
    • 이미지의 버전 관리 혹은 리비전(Revision) 관리에 사용한다. 일반적으로 14.04와 같이 버전을 명시하지만 태그를 생략하면 도커 엔진은 이미지의 태그를 latest 로 인식한다.

 

도커 컨테이너

 앞서 설명한 도커 이미지는 Ubuntu, CentOS 등 기본적인 리눅스 운영체제부터 아파치 웹서버, MySQL 데이터베이스 등의 각종 애플리케이션, 하둡(Hadoop)이나 스파크(Spark), 스톰(Storm) 등의 빅데이터 분석 도구까지 갖가지 종류가 있다. 이러한 이미지로 컨테이너를 생성하면 해당 이미지의 목적에 맞는 파일이 들어 있는 파일시스템과 격리된 시스템 자원 및 네트워크를 사용할 수 있는 독립적인 공간이 생성되고, 이것이 바로 도커 컨테이너가 된다.

 

 대부분의 도커 컨테이너는 생성될 때 사용된 도커 이미지의 종류에 따라 알맞은 설정과 파일을 가지고 있기 때문에 도커 이미지의 목적에 맞도록 사용되는 것이 일반적이다. 

 

 컨테이너는 이미지를 읽기 전용으로 사용하되 이미지에서 변경된 사항만 컨테이너 계층에 저장하므로 컨테이너에서 무엇을 하든지 원래 이미지는 영향을 받지 않는다. 또한 생성된 각 컨테이너는 각기 독립된 파일시스템을 제공받으며 호스트와 분리돼 있으므로 특정 컨테이너에서 어떤 애플리케이션을 설치하거나 삭제해도 다른 컨테이너와 호스트는 변화가 없다.

  • 예시로, Ubuntu 도커 이미지로 두 개의 컨테이너를 생성한 뒤 A 컨테이너에 MySQL을 B 컨테이너에 아파치 웹 서버를 설치해도 각 컨테이너는 서로 영향을 주지 않을 뿐더러 호스트에도 아무런 영향을 주지 않습니다.

 

도커 컨테이너 생성해보기

 우선, 도커 컨테이너를 생성하기 전에 도커를 설치해야 한다. Ubuntu 운영체제에선 다음과 같은 명령어로 다운 받을 수 있다.

# Ubuntu 운영체제

> curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

> add-apt-repository deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable


# 이제 도커 설치가 완료되었으니 docker -info를 통해 정상적으로 메시지들이 나오는지 확인해보면 된다. docker -v로 확인해도 무방하다.
> docker -info

 

 이제 본론으로 들어가서 도커 컨테이너를 생성해보자. "docker -v" 명령어를 통해 도커 엔진의 버전을 확인한 뒤, 아래의 명령어를 입력한다.

  • 도커 엔진의 버전을 확인하는 버릇을 들여야 한다는 의미로 삽입한 명령어이다 ㅎㅎ 다양한 컴퓨터에서 도커를 사용할 수 있기 때문에 도커 엔진의 버전을 자주 확인해줘야 한다.

 

 docker run 명령어는 컨테이너를 생성하고 실행하는 역할을 한다. ubuntu:14.04는 컨테이너를 생성하기 위한 이미지의 이름이며, -i -t 옵션은 컨테이너와 상호(interactive) 입출력을 가능하게 한다. 옵션에 대해서 추후 다른 글로 자세히 포스팅하겠습니다.

docker run -i -t ubuntu:14.04

 처음 docker run 명령어를 입력하면 ubuntu:14.04 이미지가 로컬 도커 엔진에 존재하지 않으므로 도커 중앙 이미지 저장소인 도커 허브에서 자동으로 이미지를 내려받는다. 

 그리고 해당 명령어가 종료되면 자동으로 컨테이너 내부에 들어오게 된다.

 

 컨테이너에서 기본 사용자는 root 이고 호스트 이름은 무작위의 16진수 해시값이다. 무작위의 16진수 해시값은 컨테이너의 고유한 ID의 앞 일부분이다.

 

 docker run 명령어로 컨테이너를 실행할 때 -i 옵션으로 상호 입출력을, -t 옵션으로 tty를 활성화해서 배시(bash) 셸을 사용하도록 컨테이너를 설정했다. docker run 명령어에서 이 두 옵션 중 하나라도 사용하지 않으면 셸을 정상적으로 사용할 수 없다. 

 

 컨테이너와 호스트의 파일시스템은 서로 독립적이므로 ls 명령어로 파일시스템을 확인해보면 아무것도 설치되지 않은 상태임을 확인할 수 있다. 

 

그리고 컨테이너 내부 환경에서 도커 환경으로 돌아온다. 컨테이너 내부에서 빠져나오는 방법은 총 3 가지가 있다. "셸에서 'exit' 입력하기" 혹은 "Ctrl + D 를 동시에 누르기" 이다. 그러나 위 방법들은 컨테이너 내부에서 빠져나오면서 컨테이너를 정지시키는 단점이 있다.

 

 컨테이너 내부에서 컨테이너를 종료시키지 않으면서 빠져나오는 다른 방법"Ctrl + P, Q 누르기"이다. exit 명령어는 Bash Shell 을 종료함으로써 컨테이너를 정지시킴과 동시에 컨테이너에서 빠져나오지만 Ctrl + P, Q는 단순히 컨테이너의 Shell에서만 빠져나온다. 그래서 단순히 컨테이너의 셸에서만 빠져나올 때에는 Ctrl + P,Q 를 쓴다.

 

 다시 컨테이너를 생성해본다. 이번에는 CentOS 이미지를 사용한다. 다음 명령어를 입력해 도커 공식 이미지 저장소에서 centos:7 이미지를 내려받는다. docker pull 명령어는 이미지를 내려받을 때 사용한다.

docker pull centos:7

# 도커 엔진에 존재하는 이미지의 목록을 출력한다. 
docker images

 

 컨테이너를 생성할 때에 run 대신 create라는 명령어를 통해 생성할 수도 있다. 아래의 명령어를 입력해 centos:7 이미지로 컨테이너를 생성한다. --name 옵션은 컨테이너의 이름을 설정한다. (mycentos 로 설정함)

  • create 명령어는 run 명령어와는 달리, 실행 후 컨테이너의 내부로 들어가지 않는다.
docker create -i -t --name mycentos centos:7

 

docker start 명령어와 docker attach 명령어를 써서 컨테이너를 시작하고 내부로 들어간다. attach 명령어는 컨테이너의 내부로 들어가는 명령어이다. 

> docker start mycentos

> docker attach mycentos

 아래의 사진은 docker run 명령어와 docker create 명령어의 차이이다. 이후 실습을 위해, Ctrl + P, Q 를 누르고 컨테이너 내부에서 나오도록 한다.

run 과 create의 차이

 

컨테이너 목록 확인 

 docker ps 명령어를 통해 정지되지 않은 컨테이너 목록을 출력시켜본다. 정지된 모든 컨테이너 목록을 출력하려면 -a 옵션을 추가한다. 

# 컨테이너 목록 출력(실행중)
> docker ps

# 모든 컨테이너 목록 출력(실행 + 정지)
> docker ps -a

 docker ps 명령어로 도커 컨테이너의 목록을 살펴보면 컨테이너의 다양한 속성값들을 볼 수 있다. 각 항목들에 대해 자세히 알아본다.

  • CONTAINER ID
    • 컨테이너에게 자동으로 할당되는 고유한 ID. 위 출력결과에선 ID의 일부분 밖에 확인할 수 없지만 컨테이너의 정보를 확인하기 위해 docker inspect 명령어를 사용하면 전체 ID를 확인할 수 있다.
  • IMAGE
    • 컨테이너를 생성할 때 사용된 이미지 이름. 
  • COMMAND
    • 커맨드(command)는 컨테이너가 시작될 때 실행될 명령어이다. 커맨드는 대부분의 이미지에 미리 내장되어 있기 때문에 별도로 설정할 필요는 없다. 위에서 생성한 centos:7, ubuntu:14.04 이미지에는 /bin/bash라는 커맨드가 내장되어 있기 때문에 컨테이너를 생성할 때 별도의 커맨드를 설정하지 않았다. 컨테이너가 시작될 때 /bin/bash 명령어가 실행됐으므로 상호 입출력이 가능한 Shell 환경을 사용할 수 있었다.
  • CREATED
    • 컨테이너가 생성되고 난 후 흐른 시간
  • STATUS
    • 컨테이너의 상태. 실행 중이라면 "Up", 종료된 상태라면 "Exited", 일시 중지된 상태라면 "Pause" 등이 있다.
  • PORTS
    • 컨테이너가 개방한 포트와 호스트에 연결한 포트를 나열한다. 앞에서 컨테이너를 생성할 때는 외부에 노출하도록 설정하지 않았으므로 PORTS 항목에는 아무것도 출력되지 않는다.
  • NAMES
    • 컨테이너의 고유한 이름이다. 컨테이너를 생성할 때 --name 옵션으로 이름을 설정하지 않으면 도커 엔진이 임의로 형용사와 명사를 무작위로 조합해 이름을 설정하기 때문에 우분투 컨테이너의 이름이 gifted_taussig로 설정되어 있다. 컨테이너의 이름은 ID와 마찬가지로 중복될 수는 없지만 docker rename 명령어를 통해 컨테이너의 이름을 변경할 수 있다.

 

컨테이너 삭제

 컨테이너를 삭제할 때에는 docker rm 명령어를 사용한다. 한 번 삭제한 컨테이너는 복구할 수 없으므로 삭제할 때는 신중을 기해야 한다. 위에서 생성한 CentOS, 우분투 컨테이너는 연습 용도였으므로 삭제해보도록 한다. 

 

> docker rm gifted_taussig

> docker rm mycentos

 mycentos를 삭제할 때에는 컨테이너가 실행 중이라 오류가 난다. 그래서 컨테이너를 정지시킨 뒤 삭제하거나 강제로 삭제할 수 있는 옵션을 추가해야 한다. docker stop 명령어를 통해 컨테이너를 정지시키고 삭제해보자.

  • 옵션을 추가해서 삭제할 때에는 "-f" 옵션을 붙여주면 된다. Ex) docker rm -f mycentos 
> docker stop mycentos

> docker rm mycentos

 

 도커를 사용하다보면 연습용으로 생성한 컨테이너가 너무 많아져서 일일이 삭제하기 귀찮은 경우가 있다. 이런 경우에는 docker prune 명령어를 입력해서 모든 컨테이너를 삭제하기도 한다.

> docker container prune

 

 또는 docker ps -a -q 처럼 docker ps 명령어의 -a -q 옵션을 조합해 컨테이너를 삭제할 수도 있다. -a 는 컨테이너의 상태와 관계 없이 모든 컨테이너를, -q는 컨테이너의 ID 만 출력하는 역할을 한다. 이 옵션들을 사용해 출력된 컨테이너 리스트를 변수로 컨테이너를 삭제하면 모든 컨테이너를 간단히 삭제할 수 있다. 즉, 다음 명령어는 컨테이너의 실행 상태와 관계 없이 모든 컨테이너를 정지하고 삭제시킨다.

> docker stop $(docker ps -a -q)

> docker rm $(docker ps -a -q)

 

컨테이너 외부에 노출시키기

  컨테이너는 가상 머신과 마찬가지로 가상 IP 주소를 할당받는다. 기본적으로 도커는 컨테이너에 172.17.0.x의 IP를 순차적으로 할당한다. 컨테이너를 새롭게 생성한 후 ifconfig 명령어로 컨테이너의 네트워크 인터페이스를 확인한다.

위의 사진을 확인해보면 도커의 NAT IP인 172.17.0.2를 할당받은 eth0 인터페이스와 로컬 호스트인 lo 인터페이스가 있다. 아무런 설치를 하지 않았다면 이 컨테이너는 외부에서 접근할 수 없으며 도커가 설치된 호스트에서만 접근할 수 있다. 외부에 컨테이너의 애플리케이션을 노출하기 위해선 eth0의 IP와 포트를 호스트의 IP와 포트에 바인딩해야 한다.

 

> docker run -i -t --name mywebserver -p 80:80 ubuntu:14.04

 -p 옵션은 컨테이너의 포트를 호스트의 포트와 바인딩해 연결할 수 있게 설정해준다. -p의 입력형식은 다음과 같다.

[호스트의 포트]:[컨테이너의 포트]

 즉, 호스트의 7777번 포트와 컨테이너의 80번 포트를 연결하려면 7777:80과 같이 입력하며, 호스트의 특정 IP를 사용하려면 192.168.0.100:7777:80과 같이 바인딩할 IP와 포트를 명시한다. 또한 여러 개의 포트를 외부에 개방하려면 -p 옵션을 여러 번 쓰면 된다. 

> docker run -i -t --name mywebserver -p 3306:3306 -p 127.0.0.1:7777:80 ubuntu:14.04

# (컨테이너 내부에서) 아파치 설치 및 실행
> apt-get update
> apt-get install apache2 -y
> service apache2 start
  • AWS EC2에서는 해당 명령어로는 외부에 개방할 수 없었다... 뭔가 에러가 나는데 해결방법을 못찾았다. 그래서 로컬 컴퓨터에서 도커를 설치한 후, 해당 명령어를 입력해보니 정상작동했다. 책에서는 "외부로 개방"이라는 표현을 썼지만 외부로 개방보다는 "로컬 컨테이너에 인터넷을 통해 접속해보기"라는 표현이 적절할 것 같다는 생각이 들었다. 즉, 해당 명령어를 통해 외부에서 접속을 허용해준다기 보다는 로컬 VPC(private IP) 상에서 접속할 수 있게 만들어주는 것 같다.

 호스트의 IP와 포트를 컨테이너의 IP와 포트로 연결한다는 개념은 매우 중요하다. 아파치 웹 서버는 172 대역을 가진 컨테이너의 NAT IP와 80번 포트로 서비스하므로 접근하려면 172.17.0.x:80의 주소로 접근해야 한다. 그러나 도커의 포트 포워딩 옵션인 -p 를 써서 호스트와 컨테이너를 연결했으므로 호스트의 IP와 포트를 통해 172.17.0.x:80으로 접근할 수 있어졌다. 

 

컨테이너 애플리케이션 구축

 '데이터베이스' 서버와 '웹 서버' 모두를 한 컨테이너에서 실행시키는 것을 "All-in-one 컨테이너"라고 한다. 하지만, 최근은 컨테이너 인프라 환경에 발맞춰 하나의 컨테이너에 하나의 애플리케이션이 있도록 해준다. 이 예제에서 '데이터베이스'와 '웹 서버'를 다른 컨테이너에서 동작하게끔 만들어주고 서로 연동되도록 해본다.

 

[데이터베이스 컨테이너 생성]

docker run -d \
--name wordpressdb \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=wordpress \
mysql:5.7

 

[웹 서버 생성]

docker run -d \
-e WORDPRESS_DB_HOST=mysql \
-e WORDPRESS_DB_USER=root \
-e WORDPRESS_DB_PASSWORD=password \
--name wordpress \
--link wordpressdb:mysql \
-p 80 \
wordpress

 EC2의 인바운드 규칙을 수정해주고 80번 포트로 연동된 포트번호로 접속해주면, 아래의 화면이 나오게 된다.

 근데 위에서 docker run 옵션으로 -d -e --link 등과 같이 보지 못했던 옵션이 사용됐다. 각 옵션에 대해 알아본다.

 

[도커 Run 명령어 옵션]

 해당 글의 앞부분에서 다룬 것과 같이 컨테이너 생성 시에, run -i -t 처럼 -i, -t 옵션으로 run을 실행하게 되면 표준 입출력이 활성화된 상태이고, 상호 작용이 가능한 셸 환경을 사용할 수 있다. 하지만, 대부분의 기본 이미지들은 컨테이너를 시작할 때 /bin/bash 를 커맨드로 설정해 실행함으로써 배시 셸을 쓸 수 있게 설정한다. 즉, docker ps 명령어로 컨테이너 목록을 확인할 때 COMMAND에 표시되는 /bin/bash 가 바로 여기에 해당된다.

 

 그러나 -d 옵션으로 run을 실행하면, 입출력이 없는 상태로 컨테이너를 실행한다. 컨테이너 내부에서 프로그램이 터미널을 차지하는 포그라운드(foreground)로 실행돼 사용자의 입력을 받지 않는다. Detached 모드인 컨테이너는 반드시 컨테이너에서 프로그램이 실행되어야 하며, 포그라운드 프로그램이 실행되지 않으면 컨테이너는 종료된다.

 mysql은 하나의 터미널을 차지하는 mysqld를, 워드프레스는 하나의 터미널을 차지하는 apache2-foreground를 실행하므로 -d 옵션을 지정해 백그라운드로 설정한 것이다. 즉, -d 옵션으로 컨테이너를 백그라운드에서 동작하게 하는 것이다. 

 

 

 --link 옵션은 내부 IP를 알 필요 없이 항상 컨테이너에 별명(alias)로 접근하도록 설정한다. 즉 위에서 워드프레스 웹 서버 컨테이너는 --link 옵션 값에서 wordpressdb 컨테이너를 mysql이라는 이름으로 설정했다.

 즉, 워드프레스 웹 서버 컨테이너는 wordpressdb 의 IP를 몰라도 mysql이라는 호스트명으로 접근할 수 있게 된다. 워드프레스 웹 서버 컨테이너에서 mysql이라는 호스트 이름으로 요청을 전송하면 wordpressdb 컨테이너 내부IP로 접근하는 것을 확인할 수 있다.

 단 --link 옵션을 사용할 때 유의할 점은 --link에 입력된 컨테이너가 실행 중이지 않거나 존재하지 않는다면 --link 를 적용한 컨테이너 또한 실행할 수 없다는 것이다. 

  • --link 옵션은 추후에 사라질 옵션이고, 이제 도커 브리지(bridge) 네트워크를 사용해서 --link 옵션과 동일한 기능을 더욱 손쉽게 사용할 수 있게 되었다. 도커 브리지 네트워크를 사용할 것을 권장한다.

 

도커 볼륨

 이미 생성된 도커 이미지는 어떠한 경우로도 변경되지 않는다. 단지 컨테이너 계층에서 원래 이미지에서 변경된 파일시스템을 저장할 뿐이다. 즉, 컨테이너 계층에 로그인 정보, 게시글 등과 같은 데이터베이스를 운용하면서 쌓이는 데이터가 저장된다.

 

 하지만, 해당 컨테이너를 삭제하면 컨테이너 계층에 저장돼있던 데이터베이스의 정보도 삭제된다는 단점이 있다. 도커 컨테이너는 생성과 삭제가 쉬운데 실수로 컨테이너를 삭제하면 데이터 복구가 불가능하다. 그래서 이를 방지하기 위해 컨테이너의 데이터를 영속적(Persistent) 데이터로 활용할 수 있는 방법이 몇 가지 있다. 그 중 가장 활용하기 쉬운 방법이 "볼륨(Volume)"이다.

 

볼륨을 활용하는 방법에도 여러가지가 있다. 호스트와 볼륨을 공유할 수도 있고, 볼륨 컨테이너를 활용할 수도 있으며 도커가 관리하는 볼륨을 생성할 수도 있다. 첫 번째로 호스트와 볼륨을 공유함으로써 데이터베이스 컨테이너를 삭제해도 데이터는 삭제되지 않도록 설정해본다. 

 

호스트와 볼륨 공유

docker run -d \
--name wordpressdb_hostvolume \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=wordpress \
-v /home/wordpress_db:/var/lib/mysql \
mysql:5.7
docker run -d \
-e WORDPRESS_DB_PASSWORD=password \
--name wordpress_hostvolume \
--link wordpressdb_hostvolume:mysql \
-p 80 \
wordpress

 -v 옵션/home/wordpress_db:/var/lib/mysql 의 값을 주었다. 이는 호스트의 /home/wordpress_db 디렉터리와 컨테이너의 /var/lib/mysql 디렉터리를 공유한다는 뜻이다. 즉, [호스트의 공유 디렉터리]:[컨테이너의 공유 디렉터리] 형태이다. 아래의 그림과 같다. 두 개의 디렉터리는 동기화되는 것이라 그냥 완전히 같은 디렉터리이다.

 

 다시 말해, -v 옵션을 통한 호스트 볼륨 공유는 호스트의 디렉터리를 컨테이너의 디렉토리에 마운트하는 것이다.

 

 

볼륨 컨테이너

docker run -i -t \
--name volumes_from_container \
--volumes-from volume_overide \
ubuntu:14.04

 --volumes-from 옵션을 설정하면, -v 또는 --volume 옵션을 적용한 컨테이너의 볼륨 디렉터리를 공유할 수 있다. 하지만, 이는 직접 볼륨을 공유하는 것이 아니라, -v 옵션을 적용한 컨테이너를 통해 공유하는 것이다. 뿐만 아니라, 여러 개의 컨테이너가 동일한 컨테이너에 --volumes-from 옵션을 사용함으로써 볼륨 컨테이너에 연결해 데이터를 간접적으로 공유받는 방식이다. 즉, 아래의 이미지와 같은 구조를 가지게 된다.

 

 

도커 볼륨

 볼륨을 활용하는 세 번째 방법은 docker volume 명령어를 사용하는 것이다. 지금까지 한 방법과 같이 호스트와 볼륨을 공유해 컨테이너의 데이터를 보존하거나 --volumes-from 옵션을 활용하는 것도 나쁘지 않지만 도커 자체에서 제공하는 볼륨 기능을 활용해 데이터를 보존할 수도 있다. 

 볼륨을 다루는 명령어는 'docker volume' 으로 시작하며, 'docker volume creae' 명령어로 볼륨을 생성한다. 아래의 명령어는 myvolume이라는 볼륨을 생성한다.

# 도커 볼륨(myvolume) 생성
> docker volume create --name myvolume

# 생성된 도커 볼륨 확인
> docker volume ls


# 생성한 볼륨을 사용하는 컨테이너 생성하는 명령어
> docker run -i -t --name myvolume_1 \
-v myvolume:/root/ \
ubuntu:14.04


# 생성된 컨테이너 내에서 파일 생성(root 디렉터리 밑의 volume파일)
> echo hello, volume! >> /root/volume


# myvolume 볼륨을 사용하는 새로운 컨테이너 생성
> docker run -i -t --name myvolume2 \
-v myvolume:/root/ \
ubuntu:14.04

# 볼륨 잘 공유되는지 확인 ("hello, volume!"이라는 메시지가 출력되어야 함.)
> cat /root/volume

 볼륨을 만들고, 생성된 볼륨을 사용하는 컨테이너를 만든 뒤, root 디렉터리 밑에 volume 이라는 파일을 생성한다.

해당 방법에서는 호스트와 볼륨을 공유할 때 사용한 -v 옵션과는 다른 형식으로 입력한다.
[볼륨의 이름]:[컨테이너의 공유 디렉터리]

 

 위의 그림은 도커 볼륨이 사용되는 구조를 의미하는데, 그림에서 알 수 있듯이 볼륨은 디렉터리 하나에 상응하는 단위로서 도커 엔진에서 관리한다. 도커 볼륨도 호스트 볼륨 공유와 마찬가지로 호스트에 저장함으로써 데이터를 보존하지만 파일이 실제로 어디에 저장되는지 사용되는지 알 필요가 없다. 

 

 하지만, "docker inspect" 명령어를 사용하면 도커 볼륨이 실제로 어디에 저장되는지 알 수 있다. docker inspect 명령어는 컨테이너, 이미지, 볼륨 등 도커의 모든 구성 단위의 정보를 확인할 때 사용되며, 정보를 확인할 종류를 명시하기 위해 --type 옵션에 image, volume등을 입력하는 것이 좋다. 다음 명령은 이름이 myvolume인 볼륨의 정보를 출력한다.

> docker inspect --type volume myvolume

위 그림에서 보이는 Driver, Label, Mountpoint에 대해 알아본다.

  • Driver : 볼륨이 쓰는 드라이버
  • Label : 볼륨을 구분하는 라벨
  • Mountpoint : 해당 볼륨이 실제로 호스트의 어디에 저장됐는지를 의미함

 

 docker volume create 명령을 별도로 입력하지 않아도 -v 옵션을 입력할 때 이를 수행하도록 설정할 수 있다. 다음과 같이 컨테이너에서 공유할 디렉터리의 위치를 -v 옵션에 입력하면 해당 디렉터리에 대한 볼륨을 자동으로 생성한다. 

> docker run -i -t volume_auto \
-v /root \
ubuntu:14.04

 위와 같이 입력한 뒤, 'docker volume ls' 명령어를 입력해보면 무작위의 16진수 형태인 볼륨이 자동으로 생성된 것을 확인할 수 있다. 

 도커 볼륨들을 다 지우려면, "docker volume prune" 명령어를 입력하면 된다. 

 

 위에서 살펴본 것들처럼 컨테이너가 아닌 외부에 데이터를 저장하고 컨테이너는 그 데이터로 동작하도록 설계하는 것을 stateless 하다고 한다. 컨테이너 자체는 상태가 없고 상태를 결정하는 데이터는 외부로부터 제공받는다. 컨테이너가 삭제돼도 데이터는 보존되므로 stateless한 컨테이너 설계는 도커를 사용할 때 매우 바람직한 설계라고 볼 수 있다.

 

 이와 반대로 컨테이너가 데이터를 저장하고 있어 상태가 있는 경우 stateful 하다고 말한다. stateful 한 컨테이너 설계는 컨테이너 자체에서 데이터를 보관하므로 지양하는 것이 좋다.

 

  •  -v 옵션 대신 --mount 옵션을 사용할 수도 있다. 두 옵션의 기능은 같지만, 볼륨의 정보를 나타내는 방법이 다르기 때문에 둘 중 사용하기 편한 옵션을 사용하면 된다. --mount 옵션으로 myvolume 이라는 이름의 도커 볼륨을 컨테이너 내부의 /root 에 공유하는 명령어는 아래와 같이 쓸 수 있다.
> docker run -i -t --name mount_option_1 \
--mount type=volume,source=myvolume,target=/root \
ubuntu:14.04
  • 호스트의 디렉터리를 컨테이너 내부에 마운트하는 경우는 아래의 코드처럼 type을 bind로 지정한다. 이 때 source의 값은 호스트의 디렉터리 경로를 지정한다. 
> docker run -i -t --name mount_option_2 \
--mount type=bind,source=/home/wordpress_db,target=/home/testdir \
ubuntu:14.04

 

컨테이너 자원 할당 제한

 run, create 명령어에서 컨테이너의 자원 할당량을 조정하도록 옵션을 입력할 수 있다. 아무런 옵션을 입력하지 않으면 컨테이너는 호스트의 자원을 제한 없이 쓸 수 있게 설정되므로 제품 단계의 컨테이너를 고려한다면 컨테이너의 자원 할당을 제한해 호스트와 다른 컨테이너의 동작을 방해하지 않게 설정하는 것이 좋다. 

 

 현재 컨테이너에 설정된 자원제한을 확인하는 가장 쉬운 방법은 'docker inspect' 명령어를 입력하는 것이다. 지금까지 테스트한 컨테이너 중 하나를 선택해 inspect 명령을 입력하면 상세한 정보를 확인할 수 있다.

 

 

run 명령어로 생성된 컨테이너의 자원 제한을 변경하려면 update 명령어를 사용한다. (아래와 같이)

$ docker update (변경할 자원 제한) (컨테이너 이름)

$ docker update --cpuset-cpus=1 centos ubuntu

 

컨테이너 메모리 제한

$ docker run -d \
--memory="1g" \
--name memory_1g \
nginx

 위의 명령어는 메모리 사용량을 1GB로 제한한 컨테이너를 생성하는 명령어이다. (메모리 입력 단위 : m (megabyte), g (gigabyte))

  • 제한할 수 있는 최소 메모리는 4MB 이다.
$ docker inspect memory_1g | grep \"Memory\"

 

 컨테이너 내에서 동작하는 프로세스가 컨테이너에 할당된 메모리를 초과하면 컨테이너는 자동으로 종료되므로 애플리케이션에 따라 메모리를 적절하게 할당하는 것이 좋다. 

 

 기본적으로 swap 메모리는 메모리의 2배로 설정되지만 별도로 지정할 수 있다. 다음 명령어는 swap 메모리를 500MB로, 메모리를 200MB로 설정된 컨테이너를 생성하는 명령어이다.

$ docker run -it --name swap_500m \
--memory=200m \
--memory-swap=500m \
ubuntu:14.04

 

컨테이너 CPU 제한

--cpu-shares

 --cpu-shares 옵션은 컨테이너에 가중치를 해당 컨테이너가 CPU를 상대적으로 얼마나 사용할 수 있는지를 나타낸다. 즉 컨테이너에 CPU를 한 개씩 할당하는 방식이 아닌, 시스템에 존재하는 CPU를 어느 비중만큼 나눠쓸 것인지를 명시하는 옵션이다. 아래의 명령어는 --cpu-shares 옵션을 사용하는 예시이다.

$ docker run -i -t --name cpu_share \
--cpu-shares 1024 \
ubuntu:14.04

 아무런 설정을 하지 않았을 때, 컨테이너가 가지는 값은 1024로 이는 CPU 할당에서 1의 비중을 뜻한다. 

 

--cpuset-cpus

 호스트에 CPU가 여러 개 있을 때 --cpuset-cpus 옵션을 지정해 컨테이너가 특정 CPU만 사용하도록 설정할 수 있다. 아래의 명령어는 컨테이너가 3번째 CPU만 사용하도록 설정한 것이다. (alicek106/stress 도커 이미지는 미리 준비한 stress 가 설치된 우분투 이미지이다.)

$ docker run -d --name cpuset_2 \
--cpuset-cpus=2 \
alicek106/stress \
stress --cpu 1

다음 예시는 컨테이너가 3번째 CPU만 사용하도록 설정한 것이다. 

 

 

 

 

 

 

References

 

시작하세요! 도커/쿠버네티스 - 교보문고

친절한 설명으로 쉽게 이해하는 컨테이너 관리 | ★ 이 책의 구성 ★◎ 도커의 기본 사용 방법을 익힘으로써 컨테이너의 기본 개념을 학습합니다. (1부 1장, 1부 2장)◎ 도커 스웜 모드를 통해 서

www.kyobobook.co.kr

 

Comments