카테고리 없음

[2장-2] 도커 엔진

여니's 2024. 2. 8. 17:56

 

참고서적 : 시작하세요! 도커/쿠버네티스


 

(6) 도커 볼륨

이미 생성된 이미지는 어떠한 경우로도 변경되지 않음

컨테이너 계층에 원래 이미지에서 변경된 파일 시스템 등을 저장함

 

이미지와 컨테이너 구조

도커 컨테이너 (쓰기 가능) : 컨테이너 레이어

도커 이미지 (읽기 전용) : mysql:5.7

 

mysql 컨테이너 삭제 시

컨테이너 계층에 저장돼있던 데이터베이스의 정보도 삭제된다.

컨테이너의 데이터를 영속적 데이터로 활용하려면

볼륨을 활용하면 된다.

 

볼륨이란 컨테이너가 데이터를 유지하고 저장하는 데

사용되는 데이터 저장영역을 의미함

 

1. 호스트와 볼륨을 공유하기

: 데이터베이서 컨테이너 삭제를 해도 데이터는 삭제되지 않도록 설정 가능함

 

# mysql 데이터베이스 컨테이너 생성
docker run -d \
--platform linux/amd64 \
--name wordpressdb_hostvolume \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=wordpress \
-v /Users/test:/var/lib/mysql \
mysql:5.7

# -v
# 호스트의 ~wordpress_db 디렉터리와 컨테이너의 /var/lib/mysql 디렉터리를 공유한다는 뜻
# [호스트의 공유 디렉터리]:[컨테이너의 공유 디렉터리]

# 워드프레스 웹 서버 컨테이너 생성
docker run -d \
-e WORDPRESS_DB_PASSWORD=password \
--name wordpress_hostvolume \
--link wordpressdb_hostvolume:mysql \
-p 80 \
wordpress

 

 

ls /Users/test 명령어를 입력하면

mysql에 존재하는 실제 데이터베이스에 대응된다.

 

해당 컨테이너들을 삭제하고

해당 폴더를 조회해도

mysql 컨테이너가 사용한 데이터가 그대로 남는다.

 

 

/Users/test1이라는 폴더는 존재하지 않았으나

-v 옵션을 사용함으로써

호스트에 해당 폴더가 생성되었고

이 폴더에 파일이 공유되었다.

 

결과적으로 컨테이너의 파일이 

호스트로 복사된 것임.

 

호스트에 이미 디렉터리와 파일이 존재하고

컨테이너에도 존재할 때

해당 두 디렉터리를 공유하면

그 결과를 확인해보자.

 

> -v 옵션을 사용하면

원래 존재했던 파일은 없어지고

호스트에서 공유된 파일이 존재하는 것을 확인할 수 있음.

이미지에 원래 존재하던 디렉터리에 

호스트의 볼륨을 공유하면

컨테이너의 디렉터리 자체가 호스트에 덮어씌워짐.

 

즉, 

v 옵션을 통한 호스트 볼륨 공유는

호스트의 디렉터리를 컨테이너의 디렉터리에

마운트함.

 


2. 볼륨 컨테이너

v 옵션으로 볼륨을 사용하는 컨테이너를

다른 컨테이너와 공유하는 방법이 있음

 

컨테이너 생성시 --volumes-form 옵션을 설정하면

-v 또는 --volume 옵션을 적용한 컨테이너의 볼륨 디렉터리를

공유할 수 있습니다.

 

직접 볼륨을 공유하는 1번 방식과는 다르게

-v 옵션을 적용한 컨테이너를 통해 공유하는 방식

 

docker run -i -t --name volume_dummy alicek106/volume_test

docker run -i -t \                                                                                
--name volume_override \
-v /Users/???/test:/home/testdir_2 \
alicek106/volume_test

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

 

 

여러 개의 컨테이너가 동일한 컨테이너에

--volumes-from 옵션을 사용함으로써

볼륨을 공유해서 사용할 수 있음

 

호스트(wordpress_db) -> 볼륨 컨테이너(/home/testdir_2) -> 컨테이너 1

                                                                                                -> 컨테이너 2

 

호스트에서 볼륨만 공유하고

별도의 역할을 담당하지 않는 일명 '볼륨 컨테이너'로서

활용하는 것도 가능하다. 

 

볼륨을 사용하려고 하는 컨테이너에

-v 옵션 대신 --volumes-from 옵션을 사용함으로써

볼륨 컨테이너에 연결해 데이터를 간접적으로 공유받는 방식임

 

 

3. 도커 볼륨

: docker volume 명령어를 사용하는 것임

도커 자체에서 제공하는 볼륨 기능을 활용해서

데이터를 보존할 수 있음

 

 

볼륨 생성 명령어

docker volume create

 

docker volume create --name myvolume

 

 

볼륨 생성 시

플러그인 드라이버를 설정해

여러 종류의 스토리지 백엔듣를 쓸 수 있지만

여기서는 기본적으로 제공되는 드라이버인 local을 사용함

 

이 볼륨은 로컬 호스트에 저장되며

도커 엔진에 의해 생성되고 삭제된다.

 

 

특정 볼륨을 사용하는 컨테이너 생성

[볼륨이름]:[컨테이너의공유디렉터리]

 

docker run -i -t --name myvolume_1 \
-v myvolume:/root/ \
ubuntu:14.04

 

 

볼륨을 컨테이너의 /root/ 디렉터리에 마운트하므로

/root 디렉터리에 파일을 쓰면

해당 파일이 볼륨에 저장된다. 

 

 

 

 

도커볼륨 -> 컨테이너1 / 컨테이너2

 

볼륨을 디렉터리 하나에 상응하는 단위로서

도커 엔진에서 관리한다. 

 

도커 볼륨도 호스트 볼륨 공유와 마찬가지로

호스트에 저장함으로써 데이터를 보존하지만

파일이 실제로 어디에 저장되는지 알 필요가 없음 (사용자 입장)

 

docker inspect 명령어를 통해

실제로 어디에 저장되는지는 확인할 수 있긴 함

 

docker inspect --type volume 볼륨명

 

 

컨테이너 정보 출력

docker container inspect 컨테이너명

 

볼륨 정보 출력

docker volume inspect 볼륨명

 

 

도커 볼륨을 사용하고 있는 컨테이너를 삭제해도

볼륨이 자동으로 삭제되지 않음

 

사용되지 않는 볼륨을 한꺼번에 지우려면

docker volume prune 명령어 사용

 

컨테이너가 아닌 외부에 데이터를 저장하고

컨테이너는 그 데이터로동작하도록 설계하는 것을

스테이트리스(stateless)라고 함

 

 

컨테이너 자체는 상태가 없고

상태를 결정하는 데이터는 외부로부터 제공받음

컨테이너가 삭제돼도 데이터는 보존되기 때문에

스테이트리스한 컨테이너 설계는 

도커르 사용할 때 매우 바람직한 설계임

 

 

이와 반대로 

컨테이너가 데이터를 저장하고 있어 상태가 있는 경우를

스테이트풀(stateful)하다고 말함

스테이트풀한 설계는 컨테이너 자체에서 데이터 보관을 하기에

지양하는 것이 좋다. 

 

 


(7) 도커 네트워크

1. 도커 네트워크 구조

컨테이너에 외부와의 네트워크를 제공하기 위해

컨테이너마다 가상 네트워크 인터페이스를 

호스트에 생성하며 이 인터페이스의 이름은 veth로 시작함

 

veth 인터페이스는 사용자가 직접 생성할 필요는 없고

컨테이너가 생성될 때 도커 엔진이 자동으로 생성함

 

veth는 virtual eth라는 의미임

 

ipconfig를 실행하면

실행중인 컨테이너 수만큼 veth로 시작하는 인터페이스가 생성된 것을 확인할 수 있음

 

eth0은 공인IP 또는 내부 IP가 할당되어

실제로 외부와 통신할 수 있는 호스트의 네트워크 인터페이스임

 

veth로 시작하는 인터페이스는

컨테이너를 시작할 때 생성되었고

각 컨테이너의 eth0과 연결되었다.

 

docker0이라는 브리지는

각 veth 인터페이스와 바인딩 돼

호스트의 eth0 인터페이스와 이어주는 역할을 함

 

(도커 컨테이너) eth0 - (호스트~) veth - docker0 - eth0

 

컨테이너의 eth0 인터페이스는

호스트의 veth...라는 인터페이스와 연결됐으며

veth 인터페이스는 docker0 브리지와 바인딩되어

외부와 통신할 수 있다.

 

brctl 명령어를 이용해

docker0 브리지에 veth가 실제로 바인딩 되었는지 확인 가능함

 

brctl show docker0

 


2. 도커 네트워크 기능

도커가 자체적으로 제공하는 대표적인 네트워크 드라이버는

브리지, 호스트, 논, 컨테이너, 오버레이가 있음

 

서드파티 플러그인 솔루션으로는 weave, fiannel, openswitch 등이 있고

더 확장된 네트워크 구성을 위해 사용된다. 

 

 

네트워크 목록 확인

docker network ls

 

 

 

브리지(bridge) 네트워크

: 컨테이너 생성시 자동으로 연결되는 docker0 브리지를 활용하도록 설정되어 있음

172.17.0.X IP 대역을 컨테이너에 순차적으로 할당

 

docker network inspect bridge

 

아무런 설정을 하지 않고 컨테이너를 생성하면

컨테이너느 자동으로 docker0 브리지를 사용함

 

Docker0 브리지는 도커의 기본 네트워크 브리지

이 브리지는 호스트 시스템의 네트워크와 연결되어 외부와의 통신이 가능하게 함

브리지 네트워크는 docker0 아닌 사용자 정의 브리지를 새로 생성해 컨테이너에 연결하는 네트워크 구조임

 

브리지 네트워크 생성

docker network create --driver bridge mybrige

 

mybridge 네트워크를 사용하는 컨테이너 생성

docker run -i -t --name mynetwork_container \

--net mybridge \

ubuntu:14.04

 

컨테이너 내부에서 ip addr show 입력 시

새로운 IP 대역이 할당된 것을 확인할 수 있음

 

브리지 타입의 네트워크를 생성하면

도커는 IP 대역을 차례대로 할당한다. 

 

 

이렇게 생성된 사용자 정의 네트워크는

disconnect, connect를 통해서

컨테이너에 유동적으로 붙이고 뗄 수 있다.

 

docker network disconnect mybridge mynetwork_container

docker network connect mybridge mynetwork_container

 

단, 논 네트워크, 호스트 네트워크 등과 같은 특별한 네트워크 모드에서는

위 명령어 사용이 불가함

 

브리지 네트워크, 오버레이 네트워크와 같이

특정 IP 대역을 갖는 네트워크 모드에서만 사용이 가능하다. 

 

네트워크의 서브넷, 게이트웨이, IP 할당 범위 등을 임의로 설정하려면

docker network create --driver=bridge \

--subnet = 172.72.0.0/16 \

--ip-range=172.72.0.0/24 \

--gateway=172.72.0.1 \

my_custom_network

 

단, --subnet과 --ip-range는 같은 대역이어야함

 


호스트 네트워크

: 네트워크를 호스트로 설정하면

호스트의 네트워크 환경을 그대로 쓸 수 있음

 

브리지 드라이버 네트워크와는 다르게

별도로 생성할 필요 없이

기존의 host라는 이름의 네트워클르 사용함

 

docker run -i -t --name network_host \

--net host \

ubuntu:14.04

 

컨테이너의 네트워크를 호스트 모드로 설정하면

컨테이너 내부의 어플리케이션을

별도의 포트 포워딩 없이 바로 서비스가 가능함

 

이는 실제 호스트에서 어플리케이션을 외부에 노출하는 것과 같음

예를 들어, 호스트 모드를 쓰는 컨테이너에서

아파치 웹 서버를 구동한다면

호스트의 IP와 컨테이너의 아파치 웹 서버 포트인 80으로 바로 접근이 가능함

이미 호스트와 같은 네트워크 있기 때문에 가능한 일임

 


 

논 네트워크

: 말 그대로 아무런 네트워크를 쓰지 않는 다는 것을 의미함

외부와 연결이 단절된다.

 

docker run -i -t --name network_none \
--net none \
ubuntu:14.04

 

--net 옵션으로 none을 설정한 컨테이너 내부에서

네트워크 인터페이스를 확인하면

로컬 호스트를 나타내는 Lo 외에는 아무것도 존재하지 않는다.

 

컨테이너가 서로 통신하지 않아도 되거나, 외부와의 통신만 필요한 경우에 적합함. 

컨테이너가 외부 서비스에 API를 제공하거나 외부 데이터베이스와 연동하는 경우에 사용이 가능하다.


 

컨테이너 네트워크

: 다른 컨테이너의 네트워크 네임스페이스 환경을 공유할 수 있다. 

공유되는 속성은 내부 IP, 네트워크 인터페이스의 맥(MAC)주소 등이다. 

 

docker run -i -t -d --name network_container_1 ubuntu:14.04

docker run -i -t -d --name network_container_2 \
--net container:network_container_1 \
ubuntu:14.04

 

 

위와 같이 다른 컨테이너의 네트워크 환경을 공유하면

내부 IP를 새로 할당받지 않고

호스트에 veth로 시작하는 가상 네트워크 인터페이스도 생성되지 않음

 

-i -t -d 옵션을 함께 사용하면

컨테이너 내부에서 셀을 실행하지만

내부로 들어가지 않으며

컨테이너도 종료되지 않는다

 

위와 같이 테스트용으로 컨테이너를 생성할 때

유용하게 쓸 수 있음

 


브리지 네트워크와 --net-alias

: 브리지 타입의 네트워크와 --net-alias 옵션을 함께 쓰면

특정 호스트 이름으로 컨테이너 여러 개에 접근이 가능함

 

위에서 생성한 mybridge 네트워크를 이용해

컨테이너를 3개 생성

 

 

docker run -i -t -d --name network_alias_container1 \
--net mybridge \
--net-alias alicek106 ubuntu:14.04

docker run -i -t -d --name network_alias_container2 \
--net mybridge \
--net-alias alicek106 ubuntu:14.04

docker run -i -t -d --name network_alias_container3 \
--net mybridge \
--net-alias alicek106 ubuntu:14.04

#각 컨테이너의 IP 확인
docker inspect network_alias_container1 | grep IPAddress

docker run -i -t -d --name network_alias_ping \
--net mybridge \
ubuntu:14.04

# 호스트이름으로 ping 요청 전송
ping -c 1 alicek106

 

 

컨테이너 3개의 IP로 각각 ping이 전송된다

매번 달라지는 IP를 결정하는 것은

별도의 알고리즘이 아닌 라운드 로빈 방식임

 

도커 엔진에 내장된 DNS가 alicek106이라는 호스트 이름을

--net-alias 옵션으로 alicek106을 설정한 컨테이너로 변환하기 때문이다.

 

도커 내장 DNS는 컨테이너 이름을 IP로 변환해줌

컨테이너가 서로 통신을 하거나

외부 리소스와 통신할 때 이 DNS 서버를 사용함

 

-- link 옵션은

컨테이너 IP가 변경돼도 별명으로 컨테이너를 찾을 수 있게

DNS에 의해 자동으로 관리된다. 

 

도커는 기본 브리지 네트워크가 아닌

사용자가 정의한 브리지 네트워크에 사용되는 내장 DNS 서버를 가지며

DNS의 IP는 127.0.0.11임

 

위 예시에서는 이 컨테이너의 IP는 DNS 서버에

alicek10이라는 호스트 이름으로 등록된다.

 

mybridge 네트워크에 속한 컨테이너에서

이 호스트 이름에 접근하면

DNS 서버는 라운드 로빈 방식을 이용해

컨테이너의 IP 리스트를 반환한다. 

 

 

dig : DNS로 도메인 이름에 해당하는 IP를 조회할 때 사용함

apt-get update
apt-get install dnsutils

 

 

dig alicek106 명령어 입력

 

 

 


MacVLAN 네트워크

: MacVLAN은 호스트의 네트워크 인터페이스 카드를 가상화해

물리 네트워크 환경을 컨테이너에게 동일하게 제공함

 

이를 사용하면

컨테이너는 물리 네트워크 상에서 가상의 맥 주소를 가지고

해당 네트워크에 연결된 다른 장치와의 통신이 가능해짐

 

MacVLAN에 연결된 컨테이너는

기본적으로 할당되는 IP 대역인 172.17.X.X 대신

네트워크 장비의 IP를 할당받기 때문임

 

MacVLAN을 사용하는 컨테이너들과

동일한 IP 대역을 사용하는 서버 및 컨테이너들은

서로 통신이 가능함

 

하지만, 기본적으로 호스트와 통신이 불가능하다.

 

서버1 내 컨테이너 A는

서버2와는 통신이 가능하지만,

서버 1과는 통신이 불가함

 

MacVLAN을 사용하려면 적어도 1개의 네트워크 장비와 서버가 필요함

MacVLAN 생성

docker network create -d macvlan --subnet=192.168.0.0/24 \
--ip-range=192.168.0.128/28 --gateway=192.168.0.1 \
-o macvlan_mode=bridge -o parent=eth0 my_macvlan

 

-d : 네트워크 드라이버로 macvlan을 사용한다는 것을 명시함

--subnet : 컨테이너가 사용할 네트워크 정보를 입력함

 

MacVLAN 네트워크를 사용하는 컨테이너 생성

docker run -it --name c1 --hostname c1 \
--network my_macvlan ubuntu:14.04

ip a # inet

ping (inet ip) -c 1