SOPT 34기 서버파트/Docker 스터디

[Docker] 가상 네트워크

softmoca__ 2024. 5. 7. 00:35
목차

네트워크 

네트워크란 여러개의 장치들이 서로 연결되어서 정보를 주고 받을수 있는 시스템이다.

정보를 주고 받기 위해 고유한 주소 역할을 하는 IP를 사용한다.

 

공인 IP와 사설 IP

IP는 크게 전 세계적으로 고유한 공인 IP와 해당 공유 IP 내에 소속된 사설IP로 나뉜다.

 

위 사진은 현재 내가 사용하고 있는 공인 IP와 사설IP이다.

 

IT 기업이 운영하는 인프라 환경 

공인 IP를 사용하는 네트워크 통신을 공인망이라고 하며 기업 내부에서 사설IP를 사용한 통신망을 사설망 이라고 한다.

 

인터페이스와 포트

네트워크 인터페이스는 인터넷에 연결하기 위해서 컴퓨터에 장착하는 부품이다.

 

네트워크 인터페이스IP를 가질수 있으며 IP를 할당받고 인터넷에 연결을 하기 위해서는 네트워크 장비와 랜선으로 연결이 되어 있어한다.(무선으로 랜선 없이 와이파이로도 연결이 가능)

즉, 방(서버)으로 들어가는 문이 여러개인 것과 비슷하다.

 

보통 서버에서는 여러개의 소프트웨어가 실행이 되며 어떤 소프트웨어로 데이터를 전달할지 지정하는 것이 PORT 넘버이다.

즉, 하나의 방안에 여러명의 사람이 있어 번호로 받을 사람을 지정하는것과 비슷하다.

 

 

NAT와 포트포워딩

네트워크 통신은 크게 아웃바운드와 인바운드로 나눌수 있다.

하나의 서버를 기준으로 서버에서 출발해서 나가는 신호아웃바운드, 다른 클라이언트나 서버에서 자신의 서버로 오는 통신은 인바운드이다.

 

외부 서버는 전 세계적에서 유일한 공인 IP를 가지고 있으며, 내부 서버는 사설망 안에서만 식별 가능한 사설 IP 주소를 가지고 있다.

그럼 어떻게 외부 공인 IP와 내부의 사설 IP가 통신을 하는 걸까 ?

아웃 바운드의 경우(NAT)

192.168.0.4의 서버 1에서 외부 공인 IP 주소인 223.130.200.107로 데이터를 전달하는 것은 어렵지 않다.

그후 다시 외부(223.130.200.107) 사설 서버로 정보를 보내기 위해선

외부 서버에서는 받는 사람에 대한 정보로 124.111.46.91로 보내야 한다.

그래야 네트워크망에서 컴퓨터를 찾아서 올 수 있기 때문이다.

하지만 이 192.168.0.4는 내부에서만 사용하는 IP 주소이기 때문에 밖에서는 이 주소로 찾아올 수 없다.

그래서 실제 네트워크의 출발지인 192.168.0.4로 돌아오려면 추가적인 처리가 필요가 필요하며 이때 사용되는 기술이 공인 IP와 사설 IP를 매핑해주는 NAT(Network Address Translation)이다.

즉, 공인 IP와 사설 IP의 맵핑 테이블을 만들어 놓고 어떤 서버로 전달할지에 대한 정보를 기록한다.
 

NAT를 사용한 외부 공인 IP와 서설 IP의 통신

 외부 서버로 트래픽을 전달할 때 192.168.0.4에서 124.111.46.91에  10001번 포트로 보낸다.

(여기서 포트 10001은 랜덤 숫자이다.)

 

그럼 이 외부 서버는 트래픽을 받을 때 192.168.0.4가 아니라 124.111.46.91에 10001번을 출발지로 알고 있게된다.
그래서 답장을 보낼 때도 이 124.111.46.91에 10001번으로 답장을 보낸다.

 

인바운드의 경우(포트포워딩)

보통 외부에서 사내망으로 요청을 보내는 인바운드 경우에는 사내 서버에서 제공하는 특정 서비스를 사용한다는 것을 의미해서 랜덤 포트 번호가 아닌 사전에 정의된 포트를 사용한다.

 

하지만 NAT 테이블은 동적으로 정보를 관리하기 때문에 외부에서 서버를 접근하는데 혼란이 생길수 있다.

그래서 외부에서 사내망으로 접근을 할 때는 사용자가 직접 NAT 테이블 같은 맵핑 정보를 관리하는  포트 포워딩이라는 기술을 사용한다.

 

 

DNS

의미가 있는 도메인 주소를 사용해서 웹 사이트에 접속을 할수 있도록 DNS 서버는 도메인과 IP 주소 데이터를 맵핑한 정보를 관리한다.

 

도커 가상네트워크 

-인터넷 선이나 공유기가 없이 오로지 한 대의 서버 내에서 논리적으로 정의되어 있는 네트워크.

컨테이너 가상화 기술은 서버 한대를 여러 대의 컨테이너로 격리하는  기술이며 또한  가상 네트워크 역시 서버 한대 안에서 여러 네트워크를 구성하는 기술이다.

그리고 이 네트워크 망 안에서 컨테이너들이 서로 통신할 수 있고, 내부의 컨테이너와 바깥의 서버와도 통신을 할 수 있다.

 

가상 네트워크에 대해 이해를 할 때는 서버 한대 에 초점을 맞추어야 한다.

컨테이너를 실습하는 PC도 가상화 기술을 사용하는 서버 한대의 역할을 하기 때문이다.

 

이 때 각각의 컨테이너들의 IP는 어떻게 정의되고, 컨테이너 간의 통신은 어떻게 이루어 질까 ?

또한 다른 외부 네트워크에서 해당 컨테이너로 접속을 할때는 어떤 경로로 접근을 해야 할까 ?

 

도커를 설치하고 실행시키면 도커는 가상의 네트워크인 브릿지 네트워크가상의 공유기인 docker0(브릿지)를 만든다.

이 브릿지는 가상의 IP 주소를 할당 받고 일반적으로 가상의 172.17.01을 할당 받는다.

 

그러면 이제 도커의 브릿지 네트워크브릿지를 사용해서 각 컨테이너들에게 ip를 할당해 줄 수 있다.

이렇게 브릿지에서 생성된 네트워크는 브릿지를 통해서 서로 통신할 수 있다.

172.17.0.2의 IP를 가진 컨테이너 1에서 272.17.0.5로 요청을 보내면 브릿지를 통해서 4번 컨테이너로 네트워크 패킷이 전달된다.

 

네트워크 신호가 전달 되는 원리

먼저 일반적인 PC나 서버를 설치하면 물리적인 네트워크 인터페이스에 인터넷 선을 꽂아서 사용하게 된다.

이렇게 물리 인터페이스에 인터넷 선을 연결하면 기기의 공인 IP나 사설 IP를 할당받는다.

 

그리고 그 PC 위에서 도커를 설치하고 실행하면 도커는 호스트 OS에 가상의 인터페이스 하나(docker0)를 생성한다.

그 후 컨테이너들을 실행할 때 각각의 컨테이너에 해당하는 가상 인터페이스들이 Veth라는 접두어로 호스트 OS에 만들어진다.

이 Veth 뒤에는 랜덤하게 고유한 번호가 할당된다.(자료에는 편의상 컨테이너 이름과 동일하게 구성)

또한 가상의 인터페이스로 전달되는 네트워크 신호는 각각의 인터페이스로 해당되는 컨테이너로 전달된다.
예를 들어서 호스트 OS에서 VETH2 인터페이스로 네트워크 신호를 보내면 이 VATH2 인터페이스는 컨테이너 2번으로 네트워크 신호를 전달한다.

 

 

 

1번 컨테이너에서 2번 컨테이너로 요청

 1번 컨테이너에서는 172.17.0.3를 도착지로 해서 요청을 보내게 될것이다.그러면 172.17.0.3으로 보내는 요청은 VETH1 인터페이스에서 출발해서 VETH2 인터페이스로 전달되어야 한다.
여기서 가상의 인터페이스 간의 네트워크 패킷을 전달하는 규칙은 HostOS의 커널 소프트웨어인 IP Tables에 정의된다.

(172.17.0.3으로 향하는 요청은 Veth 2번 인터페이스로 전달하자." 라는 규칙)

IP tables는 Linux OS의 패킷 필터링 시스템으로 서버 내부에서 네트워크 트래픽을 제어하고 라우팅 규칙을 정의한다.

내부에서 발생하는 네트워크 트래픽은 IP tables에 정의된 대로 흘러가게 되어   IP Tables에는 특정 IP 주소로 네트워크를 보냈을 때 어떤

인터페이스로 전달할지에 대한 규칙이 설정되어 있다.

 

그래서 도커는 컨테이너가 생성되거나 삭제될 때마다 호스트 OS의  IP Tables 규칙을 업데이트한다.

 

 

정리

도커는 컨테이너의 통신을 위해서 브릿지 네트워크를 정의하고 호스트 OS의 가상 인터페이스들을 생성한다.

그리고 호스트 OS의 IP Tables 규칙을 관리하면서 가상 인터페이스들 간의 통신 규칙을 만든다.

그래서 사용자는 별도의 설정을 하지 않아도 이 같은 브릿지 네트워크에서 생성된 컨테이너들은 서로 통신을 할 수 있는 상태로 구성되어 있다. 그리고 도커는 이 가상 네트워크 내부에서 여러 개의 브릿지 네트워크를 관리할 수 있다.

기본적으로 같은 네트워크 안에 속해 있는 컨테이너들끼리는 통신이 가능하기 때문에 이렇게 브릿지 네트워크 단위로 분리하게 되면 특정 컨테이너들끼리는 통신이 되지 않도록 구성할 수도 있다.

 

실습(네트워크 내부 통신 및 다른 네트워크 간의 통신)

1. 네트워크 리스트 조회
docker network ls
docker network inspect bridge
2. 새로운 네트워크 생성
docker network create --driver bridge --subnet 10.0.0.0/24 --gateway 10.0.0.1 second-bridge
docker network ls
docker network inspect second-bridge
Shell2로 이동
5. 컨테이너의 네트워크 확인
docker ps
docker container inspect ubuntuA
docker container inspect ubuntuB
docker container inspect ubuntuC
Shell2로 이동 

3. ubuntuA, ubuntuB 컨테이너 생성 후 ubuntuB연결
docker run -d --name ubuntuA devwikirepo/pingbuntu
docker run -it --name ubuntuB devwikirepo/pingbuntu bin/bash
Shell3로 이동 ====>
6. ubuntuA의 IP로 Ping 테스트
# ping 172.17.0.2
7. ubuntuC의 IP로 Ping 테스트
# ping 10.0.0.2
Shell3로 이동 ====>

4. ubuntuC 컨테이너를 second-bridge 네트워크에 생성
docker run -it --network second-bridge --name ubuntuC devwikirepo/pingbuntu bin/bash
<==== Shell1로 이동(전페이지)
8. ubuntuA의 IP로 Ping 테스트
# ping 172.17.0.2
9. Ctrl+C로 탈출 후 컨테이너 및 네트워크 삭제
docker rm -f ubuntuA ubuntuB ubuntuC
docker network rm second-bridge

 

A,B 컨테이너는 같은 네트워크, C는 다른 네트워크이다.

그래서 A,B 끼리는 통신이 되지만 C와 A,B는 통신이 되지 않는다.

 

도커 네트워크의 포트포워딩

 

사용자의 PC인 HostOS나 가상 네트워크 바깥에 있는 서버에서 이 컨테이너로 접근하려면 포트포워딩 기술을 사용해야 한다. 

내부 컨테이너에서 외부 서버로 통신을 할 때 NAT는 가상 네트워크가 알아서 설정하기 때문에 특별히 무언가를 지정하지 않아도 내부의 컨테이너는 이 바깥쪽에 있는 외부망을 통해서 다른 서버로 접근할 수 있다.(믈론 실제로 도커가 실행중인 물리 서버 혹은 실습 PC가 물리적인 네트워크로 연결이 되어 있어야 한다.)

 

반대로 외부의 서버에서 여러분의 컨테이너로 접근할 때는 일단 외부 서버에서의 접근은 실제로 도커가 실행 중인 192.168.0.10을 통해서 접근을 한다.

그럼 여기서 포트 포워딩을 사용해서 192.168.0.10의 특정 포트로 접근했을 때 사용자가 지정한 컨테이너로 전달하도록 포트 포워딩을 등록해야 한다.

 

172.17.0.2 서버가 받는 타겟 포트를 80으로 지정하고 실습 PC의 IP인 192.168.0.10의 8001번으로 요청을 보내면 Nginx

컨테이너의 80 포트로 요청이 전달되는 것이다.

호스트 OS의 포트는 중복된 포트만 아니면 아무런 빈 포트를 사용하면 된다.

 

 

실습(포트포워딩)

1. 포트포워딩 없이 nginx 실행  ==> 접속 안됨
docker run -d --name nginx nginx
docker container inspect nginx    

2. 8001 포트에 nginx 실행 및 localhost:8001 접속
docker run -d -p 8001:80 --name nginx2 nginx

3. 8002 포트에 redapp실행 및 127.0.0.1:8002 접속
docker run -d -p 8002:3000 --name redColorApp --env COLOR=red devwikirepo/envnodecolorapp

4. 8003 포트에 blueapp실행 및 IP주소:8003 접속   ==> 같은 와이파이 사용 스마트폰에서 접근 가능
docker run -d -p 8003:3000 --name blueColorApp --env COLOR=blue devwikirepo/envnodecolorapp

5. 8003 포트에 yelloapp실행 시도 ==> 포트 중복 에러 발생
docker run -d -p 8003:3000 --name yellowColorApp --env COLOR=yellow devwikirepo/envnodecolorapp

6. 8004 포트에 greenapp 실행 및 접속(애플리케이션과 다른 포트) ==> 컨테이너는 실행되나 접속이 페이지 작동 안함
docker run -d -p 8004:3030 --name greenColorApp --env COLOR=green devwikirepo/envnodecolorapp

 

 

도커의 DNS

도커는 컨테이너들이 기본적으로 사용할 수 있는 DNS 서버를 제공하며 이 DNS 서버에는 IP 주소와 도메인 명이 저장되어 있다.

여기서 도메인은 컨테이너의 이름으로 자동으로 저장되어 컨테이너들은 기본적으로 컨테이너의 IP가 아닌 컨테이너의 이름으로 서로 통신할 수 있다.

또한 이 DNS 서버는 외부의 DNS 서버와 연동이 되어 있기 때문에 컨테이너는 구글 같은 외부 도메인도 사용할 수 있다.

 

다만 기본으로 생성되는 브릿지 네트워크는 이 DNS 기능이 제공되지 않고 사용자가 직접 생성한 브릿지만 컨테이너의 이름을 통해서 통신할 수 있다

 

세컨드 브릿지를 생성하고 컨테이너 A와 컨테이너 B를 생성한 상태라고 생각해 보면 컨테이너 A에서는 요청을 보낼 때 도메인 명을 컨테이너 B로 지정하면 먼저 도커 DNS를 통해서 컨테이너 B의 IP 주소인 10.0.0.3이라는 IP를 받아오고 이 IP로 요청을 보내는 것이다.

 

컨테이너 B가 다시 시작되어서 IP가 10.0.0.4로 바뀌어도 도메인 서버에 즉시 업데이트가 되기 때문에 컨테이너 A는 컨테이너 B라는 도메인만 사용하면 요청을 보낼 수 있다. 이렇게 도메인 주소를 사용하면 IP 주소가 바뀌는 환경에서 다른 서버들이 영향을 받지 않고 연결이 일관적으로 이루어질 수 있다.

 

네트워크 드라이버 종류

 

브릿지 네트워크

- 도커 브릿지를 활용해 컨테이너간 통신, NAT 및 포트포워딩 기술을 활용해 외부 통신 지원

호스트 네트워크

- 호스트의 네트워크를 공유, 모든 컨테이너는 호스트 머신과 동일한 IP를 사용, 포트 중복 불가능

오버레이 네트워크

- Kubernetes에서 사용, 호스트 머신이 다수일 때 네트워크 관리 기술

Macvlan 네트워크

- 컨테이너에 MAC 주소를 할당하여 물리 네트워크 인터페이스에 직접 연결

 

 

 

 

Leafy 네트워크

네트워크를 새롭게 만든 이유는 기본 네트워크에서는 DNS 기능을 제공하지 않기 때문이다.

DNS 기능을 사용하지 않으면 스프링 부트 애플리케이션에서 DB에 접근할 때 IP를 통해서 접해야 한다.

그런데 IP는 자동으로 할당되기 때문에 데이터베이스 컨테이너가 재시작 되면 IP도 함께 변경될수 있다.

애플리케이션에서 데이터베이스 서버 IP를 가지고 있는 상태에서 이 IP가 바뀌게 되면 데이터베이스의 접속이 불가능해질 것이다.

그래서 Spring Boot 애플리케이션에서는 데이터베이스 서버에 접근할 때 서버의 도메인을 사용해야 한다.

 

컨테이너의 IP가 바뀌면 이 정보는 도커 내부의 DNS 서버에 자동으로 연동되고 그래서 IP가 바뀌더라도 도메인 명은 컨테이너의 이름으로 고정되어 있다. 그래서 Spring Boot 애플리케이션은 Postgres 서버의 도메인을 지정함으로써 IP가 어떻게 바뀌든 간에 데이터베이스 컨테이너로 접근할 수 있게 된다.

 

 

 

 

 

 

 

https://www.inflearn.com/course/lecture?courseSlug=%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-%EC%89%AC%EC%9A%B4-%EB%8F%84%EC%BB%A4