1편을 글을 요약하자면.. 각 컨테이너들은 docker0 라는 이름의 브릿지인데 172.17.0.0 부터 172.17.16 까지의 아이피 대역을 가지고 있으며 이 docker0와 연결된 컨테이너들은 순차적으로 아이피 값을 할당받으며 네트워크와 연결된다는 내용이다. 구조 그림은 아래와 같다.
기본적으로 docker0라는 브릿지가 아이피 대역에 맞게 컨테이너에 순차적으로 할당해주는 것을 알았고 그 대역이 172.17 인것을 알았다.
이번엔 172.18 대역을 갖는 브릿지를 새로 만들어볼까?
그렇다면 새로만든 브릿지에 연결되는 컨테이너의 구조는 위 그림이 어떻게 그려질까?
어려울 것 없다. docker host 내에 붉은 eth0에 docker1이 위 그림과 똑같은 구조로 하나 더 붙을 뿐이다.
docker network create --driver bridge --ip-range 172.18.1.0/24 --subnet 172.18.1.0/24 --gateway 172.18.1.1 docker1
--driver bridge # 브릿지 네트워크를 만들거고
--ip-range 172.18.1.0/24 # 해당 네트워크 대역은 아이피와 24개의 값을 가질 예정
--subnet 172.18.1.0/24 # 서브넷은 아이피 범위와 동일. (동일해야함)
--gateway 172.18.1.1 # 게이트웨이는 그 대역의 1번값으로 (만약 10번으로 설정하면 1 ~ 9번 아이피는 못쓴대요
docker1 # 브릿지 네트워크의 이름은 docker1로 설정.
각 옵션의 의미와 함께 작성하였다.
우리는 우리가 새롭게 사용할 네트워크 범위를 지정한것이다!
직접 지정해주는 만큼, 실무에선 아마 리눅스 서버 네트워크 정책에 따라 대역을 달리 지정해주지 않을까 예상해본다.
docker network ls
NETWORK ID NAME DRIVER SCOPE
3ff9ff689e9e bridge bridge local
c9e590a32ede host host local
4bf4f35e4f41 none null local
2e971c15425b docker1 bridge local
ls로 브릿지가 정상적으로 확인.
[root@server2 ~]# ifconfig
br-2e971c15425b: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.18.0.1 netmask 255.255.0.0 broadcast 172.18.255.255
ether 02:42:b0:98:59:12 txqueuelen 0 (Ethernet)
RX packets 7 bytes 546 (546.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 30 bytes 3191 (3.1 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ifconfig로 브릿지를 확인해보자. 근데 확인해보니 docker0 처럼 이름이 이쁘게 나오지 않았다.
이유는 모르겠지만... br- 이후에 나오는 16진수 값이 docker1의 network id 와 동일하고, 아이피 대역 및 게이트웨이로 설정한 아이피도 확인할 수 있기 때문에 이게 docker1 라는 것은 확실하다.
docker run -itd --name=myWebserver --net=docker1 -P nginx:1.19
--net 옵션으로 직접 네트워크를 다르게 설정해줄 수 있다. 이를 우리가 만든 docker1 브릿지로 설정하였다. 이렇게 될 경우 생성된 myWebserver 컨테이너는 내부 아이피로 172.18.0.2를 갖게 된다. 현재 docker1 의 네트워크 대역은 172.18.0.x 인데, 게이트웨이가 1번을 할당했으니까 자동으로 다음 아이피인 2번을 할당받는 것이다.
진짠지 확인해보자. inspect 명령어로 생성된 컨테이너의 세부정보를 확인해보자.
> docker inspect myWebserver
"Gateway": "172.18.0.1",
"IPAddress": "172.18.0.2"
확실하다.
네트워크의 세부정보로 어떤 컨테이너가 연결되어있는지 확인할수도 있다.
> docker network inspect docker1
"Containers": {
"c139e8bd6594a5642a36d6af09d0711377d36dbb4a5e776dd7372b1bb4841fe9": {
"Name": "myWebserver",
"EndpointID": "",
"MacAddress": "",
"IPv4Address": "172.18.0.2/24",
"IPv6Address": ""
}
},
단, 네트워크로 세부정보를 확인할땐 그 컨테이너가 동작하고 있을때만 확인 가능하다.
docker run -d --name=httpd-server httpd
따로 --net 으로 브릿지 설정을 안해줬으니 얘는 docker0 에 연결된다.
docker run -d --name=redis-server --net=container:httpd-server redis
--net 옵션으로 container:httpd-server 를 입력했다.
이런 구조일 경우, redis-server 컨테이너는 자신의 네트워크 인터페이스 정보를 httpd-server의 네트워크 정보를 공유하게 된다.
이렇게 생성 할 경우, redis-server는 자체적인 아이피를 갖지 않아서 외부 접근에 안전하다.
> [root@server2 ~]# docker network inspect bridge
"Containers": {
"e1d17a7d46dbfab0a2f2e0c086b8c157417bc65bddf93183f0cf19f101c7c1e3": {
"Name": "httpd-server",
"EndpointID": "14058de2b09706326cc5a038570896374cea540b65abfeb1d395bcd0bdf678b7",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
}
docker0 에서 확인이 안된다. 아이피를 따로 가지고 있는게 없다는걸 확인했다.
이번에는 컨테이너 내에 직접 들어가 NIC 정보를 확인해보자.
[root@server2 ~]# docker ps
CONTAINER ID IMAGE CREATED STATUS PORTS NAMES
9ffa8783a85c redis 39 hours ago Up 4 minutes redis-server
e1d17a7d46db httpd 39 hours ago Up 4 minutes 80/tcp httpd-server
> httpd-server 컨테이너의 아이피 정보
root@e1d17a7d46db:/usr/local/apache2# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255
> redis-server 컨테이너의 아이피 정보
root@e1d17a7d46db:/data# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255
컨테이너 내부에선 공유받은 컨테이너의 네트워크 정보를 아예 똑같이 받고 있는것을 확인할 수 있다. 이렇게 네트워크를 공유하고 있으니 정보 교환을 하기 용이하다는데.
그 정보교환이란게 어떤식으로 활용하는지는 아직 모르겠으니 나중에 알게되면 설명을 추가하겠다.
--net-alias 는 같은 네트워크 대역에서 그룹으로 묶어서 처리하는 기법이다. 주로 백엔드 서버를 여럿 구성하면서 각자의 서버 가용성을 높히는 용도로 활용한다고 한다.
구분하기 쉽게 우선 다른 브릿지를 새로 만들어보자
docker network create --driver bridge --subnet 172.200.1.0/24 --ip-range --gateway 172.200.1.1 netlb
200 대역에 24개의 아이피를 할당받을 netlb 라는 이름의 브릿지를 생성했다.
이번엔 이 대역의 아이피를 할당받는 컨테이너들을 몇개 그룹으로 묶어보자
docker run -itd --name=nettest1 --net=netlb --net-alias inner-net ubuntu:14.04
docker run -itd --name=nettest2 --net=netlb --net-alias inner-net ubuntu:14.04
docker run -itd --name=nettest3 --net=netlb --net-alias inner-net ubuntu:14.04
네트워크 그룹으로 inner-net 이란 이름을 주었다.
이 정보는 컨테이너 세부정보에서 확인할 수 있다.
[root@server2 ~]# docker inspect nettest1
"Networks": {
"netlb": {
"Aliases": [
"inner-net",
"c139e8bd6594"
],
"Gateway": "172.200.1.1",
"IPAddress": "172.200.1.2",
"IPPrefixLen": 24,
}
}
netlb 라는 브릿지내에 Aliases로 소속되어 있는것을 확인할 수 있다.
이 정보를 한번 좀 더 자세히 알아보도록 하자.
우선 inner-net 에 속한 아무 컨테이너에 접속하여 패키지 하나를 설치하자.
apt-get -y install dnsutils
root@c139e8bd6594:/# dig inner-net
; <<>> DiG 9.9.5-3ubuntu0.19-Ubuntu <<>> inner-net
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64719
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;inner-net. IN A
;; ANSWER SECTION:
inner-net. 600 IN A 172.200.1.3
inner-net. 600 IN A 172.200.1.2
inner-net. 600 IN A 172.200.1.4
;; Query time: 19 msec
;; SERVER: 127.0.0.11#53(127.0.0.11)
;; WHEN: Tue Jan 26 17:49:42 UTC 2021
;; MSG SIZE rcvd: 102
inner-net에 속한 아이피들이 ANSWER SECTION 에, QUESTION SECTION에서 inner-net이 있는걸 확인할 수 있다.
무슨뜻이냐.
어떤 요청이 inner-net 으로 오면 inner-net에 속한 컨테이너 3대 중 아무나가 임의로 응답한다. 순서가 따로 지정되어있지 않으니까.
net-alias로 생성된 그룹에 어떤 요청이 올 경우, 그 그룹에 속한 컨테이너 중 무작위로 하나가 응답하는 기능
도커 컨테이너를 사용하는 이유는 빠른 인프라 구축임을 기억하자.
=== HOST ============================================================
|| ┏━━━ backend container1 ||
|| frontend container --- net-alias ━┳━╋━━━ backend container2 ||
|| ┏━━━━━┛ ┗━━━ backend container3 ||
|| ┃ ||
|| Vloume ||
=====================================================================
열심히 그려본 구조이다...
만약 웹 서비스에 사용자가 몰려 수 많은 트래픽을 처리해야하는데, 백앤드 서버가 하나라면? 그 백엔드 서버가 과부화가 걸렸다면? 아니면 어떤 예측 불가능했던 문제로 다운 된다면? 큰일난다.
그래서 보통 그 문제를 해결하기 위해 서버를 여러대 둔다.
구조의 백앤드 컨테이너 3대가 그것을 가정한다
서버가 여러대지만. 이 여러대의 서버는 사용자에게 같은 정보와 서비스를 제공해야 한다.
볼륨 옵션으로 각 컨테이너가 모두 같은 데이터를 공유하도록 한다
즉, 나는 사실 저 구조의 환경을 만들기 위한 초석을 깔고 있던 것이다.
바로 프론트 엔드를 담당할 컨테이너를 만들어 앞서 설명한대로 동작하는지 확인하자
net-alias 로 묶인 백엔드 컨테이너들과 통신할 프론트엔드 컨테이너를 생성하기.
이때, 같은 아이피 대역에 있어야 네트워크 그룹에 호출이 되는것으로 알고있다.
docker run -it --name=frontend --net=netlb ubuntu:14.04 bash
바로 컨테이너에 진입하여 ping 테스트로 타겟을 inner-net 을 줘보자.
root@89846efe319c:/# ping -c 2 inner-net
PING inner-net (172.200.1.2) 56(84) bytes of data.
root@89846efe319c:/# ping -c 2 inner-net
PING inner-net (172.200.1.4) 56(84) bytes of data.
root@89846efe319c:/# ping -c 2 inner-net
PING inner-net (172.200.1.4) 56(84) bytes of data.
root@89846efe319c:/# ping -c 2 inner-net
PING inner-net (172.200.1.3) 56(84) bytes of data.
순환구조(Round Robin)로 할당을 해주지 않는 무작위 방식이다.
핑 테스트를 진행할때 각 컨테이너에 무작위로 요청됨을 확인할 수 있다.
자동으로 다중 서버에 트래픽 경로를 지정해주는 것을 AWS에선 로드밸런싱 이라고 한다.
단, aws 에선 무작위가 아니라 분명 라운드 로빈이 제대로 동작한다.
nginx 내에도 로드밸런싱 기능이 내제되어있다. 활용법은.. 나중에 알아보자.