도커 볼륨
이전 포스트에서 도커 이미지는, 컨테이너를 띄운 이후 읽기 전용으로 바뀌어 컨테이너에서 일어난 어떤 변경사항도 도커 이미지에 적용되지 않는다고 했다.
물론 commit을 하게 되면 변경사항이 적용된 새 이미지가 생기지만 기존의 이미지는 영향을 받지 않는다.
바꿔 말해 컨테이너는 베이스 이미지에 종속적이고 삭제가 된다면 자신의 상태를 잃어버리게 된다는 것이다.
도커 컨테이너는 생성과 삭제가 빈번하다 보니 이럴때마다 데이터를 잃어버리면 치명적이다.
도커 볼륨은 이를 해결하기 위해 등장한 도커 오브젝트이다. 리눅스 마운트 네임스페이스를 이용한 컨테이너 내의 파일 시스템을 관리한다.
도커 볼륨을 통해 데이터를 Persistent하게 유지하는 총 3가지 방법에 대해 알아보자.
호스트 볼륨 공유
이름에서 알 수 있듯이 호스트 OS의 디렉토리와, 컨테이너 내 디렉토리를 bind한다.
호스트 볼륨 공유는 다음과 같은 Rule을 가진다.
- 만약 호스트 OS 경로에 host_dir 이라는 디렉토리가 없다면, 디렉토리를 생성한다.
- 만약 컨테이너 경로에 container_dir 이라는 디렉토리가 없다면, 디렉토리를 생성한다.
- 만약 둘 다 디렉토리가 있다면, 호스트 OS를 기준으로 덮어씌운다.
먼저 호스트에 /home/ec2-user/host_dir 이라는 디렉토리를 만들고 해당 디렉토리에 파일을 만들어보자.
이후에 docker run 명령어를 통해 호스트 OS의 /home/ec2-user/host_dir 디렉토리를, 컨테이너 파일시스템의 /var/lib/container_dir 디렉토리에 마운트 한다.
docker run -it -d --name my_ubuntu -v /home/ec2-user/host_dir:/var/lib/container_dir ubuntu bash
docker exec -it my_ubuntu bash
그리고 위 명령어로 컨테이너 내부에 접속해보자.
container_dir이라는 디렉토리가 생겼고, 아까 만들었던 test.txt 파일이 있는것을 볼 수 있다.
반대로 컨테이너 내부에서 파일을 생성해본 이후, 호스트 디렉토리를 보면 해당 파일이 있는것을 볼 수 있다.
볼륨 컨테이너
볼륨을 사용하는 두 번째 방법으로는 볼륨만을 위한 컨테이너를 따로 만드는 것이다.
호스트 볼륨 공유만을 위해 존재하는 볼륨 컨테이너를 만든 이후,
해당 볼륨이 필요한 컨테이너들에게 bind 시켜주는 형태이다.
컨테이너1, 2는 다음과 같이 볼륨을 마운트할 수 있다.
docker run -it --volumes-from my_volume_container ubuntu bash
여기서 my_volume_container는 사전에 생성해놓은 볼륨 컨테이너이다.
도커 볼륨
이는 도커 자체에서 제공하는 볼륨 기능이다.
docker volume create [OPTIONS] [VOLUME]
docker volume rm [OPTIONS] VOLUME [VOLUME...]
docker volume inspect [OPTIONS] VOLUME [VOLUME...]
...
등의 명령어들이 제공되며 각 키워드들의 의미는 이전에 다루었기에 익숙하다.
도커 볼륨은 도커 엔진에 의해서 따로 관리된다. 호스트 볼륨 공유와 마찬가지로 호스트 OS에 저장되긴 하지만 파일이 실제로 어디에 저장되어 있는지 유저는 알 필요 없다.
이러한 특성으로 호스트 OS의 파일을 컨테이너 내부로 옮길때 쓰기 보다는, 반대로 컨테이너 내부에서 호스트 OS로 가져올 필요가 있을 때(로그 수집, DB 백업 등) 도커 볼륨을 사용하는것이 맞는 것 같다.
docker volume create --name myvolume
docker run -it -v myvolume:/var/lib/container1_dir ubuntu bash
docker run -it -v myvolume:/var/lib/container2_dir ubuntu bash
컨테이너 1과 2는 같은 볼륨을 공유하므로 데이터의 동기화가 일어난다.
Stateless한 컨테이너
컨테이너는 볼륨의 도움으로 Stateful 하게 될 수 있음을 소개했다.
하지만 Stateful한 컨테이너의 설계는 바람직하지 않다.
이는 컨테이너의 등장 배경과 오늘날 컨테이너가 어떻게 쓰이는지를 생각해보면 좋은데,
만약 1개의 서버 컨테이너로 서비스를 운영하다가, 사용자가 몰리거나 부하가 일어나면
Scale-Out을 통해 컨테이너를 여러 개로 늘려야 하는 상황이 있을 수 있다.
이때 컨테이너가 Stateful 하게 되면 확장에 유연하지 못하기 때문에 Stateless 하게 설계해야 자유로운 스케일 조정이 가능하다.
수백, 수천개의 컨테이너로 이루어진 서비스라면 더더욱 컨테이너가 상태를 가지지 않는게 중요하다.
도커 네트워크
이전 포스트에서 소개한 여러가지 리눅스 네임스페이스에서, 네트워크 네임스페이스가 있었다.
도커 네트워크는 이 네트워크 네임스페이스를 이용해 컨테이너 내에서 독립적인 네트워크 환경을 잘 이용할 수 있게 해준다.
호스트 OS에서 ifconfig 명령어를 입력해보자.
enX0이라고 되어있는 네트워크 인터페이스는 eth0과 표기법만 다를뿐 실제로는 같은 인터페이스다.
현재 1 개의 running 상태인 컨테이너가 있어, veth 인터페이스와 docker0 브릿지를 확인할 수 있다.
docker inspect 2cc
2cc 컨테이너에 대해 살펴보자.
172.17.0.2라는 내부 IP가 할당된 것을 볼 수 있다.
이 값은 도커 엔진에 의해 자동으로 할당된 것이며, 다음 컨테이너를 생성하면 172.17.0.3이라는 IP가 할당될 것이다.
자동으로 할당 되기에 내부 IP는 컨테이너가 종료되면 언제든지 바뀔 수 있다는 특징이 있다.
호스트 OS의 veth.. 인터페이스는 도커 엔진이 컨테이너를 띄울 때 해당 컨테이너만을 위해 자동으로 생성해주며 이를 이용해 컨테이너와 통신하게 된다.
docker0 네트워크
위에서 설명한 docker0은 브릿지 네트워크이다.
도커 엔진은 도커 컨테이너를 생성할 때 네트워크를 따로 지정하지 않으면 docker0 브릿지 네트워크를 사용하도록 되어있다.
이 네트워크는 172.17.0.X IP 대역을 컨테이너들에게 순차적으로 할당한다.
이외에도 여러 가지의 네트워크 종류가 있는데, 이는 도커 스웜에 대한 포스트에서 한번에 다루겠다.
'Infra > Docker' 카테고리의 다른 글
[Docker] Docker Daemon (0) | 2023.06.27 |
---|---|
[Docker] Dockerfile (1) | 2023.05.20 |
[Docker] 도커 이미지와 컨테이너 (0) | 2023.05.18 |
[Docker] Docker란 무엇인가 (0) | 2023.05.18 |
[Docker] 도커 시작하기 (2) | 2023.04.05 |