1. 프록시

1) 프록시가 없다면?

- 사용자 요청이 직접 웹서버에 전달 → 서버 부담 증가

- 단일 웹서버 : 장애 발생 시 서비스 가용성에 치명적인 문제

- 다중 웹서버 : hotspot → 한 서버에 트래픽이 몰리는 현상, 사용자 입장에서 레이턴시가 증가하는 문제 

 

2) 프록시

- 사용자의 요청을 대리로 받아 서버들에게 적절히 분배

- 다중 호스트에 트래픽을 분산시킬 수 있는 로드밸런싱 구현이 가능

- html, js, css 등의 정적 파일을 캐싱할 수 있는 캐시서버 구현

- 학교나 사내망에서 특정 사이트 접근을 제어하는 차단 기능 구현

- 무중단 배포를 통한 서비스 경험 향상 및 내구성 증가

- SSL 암호화 적용을 통한 보안 강화 가능

- 프록시 서버 종류

① 포워드 프록시 : 사용자의 존재를 서버에게서 숨김

② 리버스 프록시 : 서버의 존재를 사용자에게서 숨김

 

3) nginx

- 기본 구성값으로 웹서버 실행 가능, 점유율 높음

- config 파일의 간단한 수정만으로 리버스 프록시 구현 가능

- 쿠버네티스의 인그레스 컨트롤러로 엔진엑스 인그레스 컨트롤러 선택 가능

- API 트래픽 처리를 고급 http 기능으로 사용 가능한 API gateway 구성 가능

- MSA 트래픽 처리를 위한 MicroGateway로 사용 가능

- /etc/nginx 하위에 있는 nginx.conf 파일에 대한 변경을 통해 구성 가능

 

 

2. nginx 리버스 프록시

1) nginx 리버스 프록시

- nginx 기본 설정 : 80번 포트

- 기본 분배 방식 : round-robin

- 요청이 더 적게 들어오는 서버에 배정을 늘리는 least_conn 방식 채택 가능

- weight 설정 등을 통해 비중을 다르게 가져갈 수도 있음

 

2) nignx 리버스 프록시 실습

$ sudo apt update
$ sudo apt-get -y install nginx
$ sudo nginx -v

먼저, 위와 같은 명령어로 nginx를 hostos에 설치한 후 진행한다.

nginx는 기본적으로 80번 포트를 사용하기 때문에 포트바인딩이 80번 포트로 되어 있다면 기존에 돌고 있는 컨테이너를 종료시켜줘야 한다.

위 명령어로 서비스가 잘 가동되고 있는 것을 확인할 수 있다.

위와 같이 nginx:master로 80번 포트가 잡힌 것을 볼 수 있다.

먼저, myweb:1.1 컨테이너의 노출 포트번호를 확인해보면 80번 포트로 되어 있는 것을 확인할 수 있다.

위와 같이 3개의 컨테이너를 띄워준다.

<h1>포트번호 : xxxxx, 컨테이너명 : mywebx</h1>

nginx 내부의 index.html 파일 내용을 바꿔주기 위해 위와 같이 수정한 후

위 명령어를 이용해 index.html을 각각 컨테이너명에 복사해준다.

위와 같이 세 개의 컨테이너가 잘 띄워진 것을 확인할 수 있다.

 

☆ 사용자 입장에서는 서버 3개의 주소로 직접 접속하지 않아도 nginx 서버 접속 시 번갈하가며 분배되도록 host nginx의 reverse proxy 설정을 해야 한다. → 프록시의 역할

 

reverse proxy 설정은 /etc/nginx/nginx.conf 파일을 통해 할 수 있다. (해당 파일을 백업해둔 후 진행하자..)

위와 같이 nignx.conf 파일을 수정해준다. 

80번 포트로 접속 시 localhost:11111, 22222, 33333을 번갈아가면서 배정하라는 의미이다.

위와 같이 nginx 서버를 restart해준 후 active 상태를 확인해준다.

이제 그냥 localhost(80번포트)로 접속해도 위와 같이 번갈아가면서 배정되는 것을 확인할 수 있다.

호스트에 설치되어 있던 리버스 프록시를 컨테이너화 시키기 위해 먼저 서버 중단 후 현재 리버스 프록시 설정된 파일을 백업해둔다.

해당 백업파일을 이용하여 새로운 컨테이너의 nginx.conf 파일을 갱신해주면 리버스 프록시를 수행할 수 있다.

위와 같이 nginx를 제거하면 리버스 프록시는 사라지지만 개별 컨테이너는 삭제되지 않은 상태이다.

위와 같이 nginx 컨테이너를 하나 더 띄워주었다.

컨테이너 입장에서는 127.0.0.1이 localhost이므로 nginx.conf 파일의 server 부분을 내부 IP 주소(192.168.56.101)로 수정해주어야 한다.

해당 컨테이너의 nginx.conf 파일을 위와 같이 갱신해준다.

해당 컨테이너를 재시작한 후 접속해보면 위와 같이 프록시가 잘 설정된 것을 확인할 수 있다.

events { worker_connections 1024; }
http {
	upstream lb-node {
		server hostip:11111 weight=80;
		server hostip:22222 weight=10;
		server hostip:33333 weight=10;
	}
	server {
		listen 80 default_server;
		location / {
			proxy_pass	http://lb-node;
		}
	}
}

위와 같이 weight를 주면 가중치에 따라 각 서버가 받는 하중을 다르게 가져가도록 설정할 수도 있다.

 

 

3. HAproxy

1) HAproxy

- 하드웨어 기반의 L4/L7 스위치를 대체하기 위한 프록시 솔루션

- TCP 및 HTTP 기반 애플리케이션을 위한 고가용성, 로드밸런싱 및 프록시 기능 제공

- 주요 기능 : SSL 지원, 로드밸런싱, 액티브 헬스체크, keep alived 등

- L4 스위치 대체 기능 : IP를 통한 트래픽 전달 수행, 요청에 대한 처리는 round-robin 방식을 기본으로 함

- L7 스위치 대체 기능 : HTTP 기반의 URI를 통한 트래픽 전달 가능 , 동일한 도메인의 하위에 존재하는 여러 WAS 사용 가능

 

2) HAproxy를 활용한 컨테이너 L7 스위치 프록시 실습 : HTTP 기반

먼저, haproxy-network라는 네트워크를 생성하고 ls와 route 명령어로 조회해보면 172.21번대 대역을 사용하는 것을 확인할 수 있다.

chadchae1009/haproxy:echo를 받아오고 실행했다.

컨테이너 상태를 확인해보면 위와 같이 잘 띄워졌고, 8080포트를 이용하고 있는 것을 확인할 수 있다.

global
	stats socket /var/run/api.sock user haproxy group haproxy mode 660 level admin expose-fd listeners 
	log stdout format raw local0 info

defaults
	mode http
	timeout client 10s
	timeout connect 5s
	timeout server 10s
	timeout http-request 10s
	log global

frontend stats
	bind *:8404
	stats enable
	stats uri /
	stats refresh 10s

frontend myfrontend
	bind :80
	default_backend webservers

backend webservers
	server s1 서버명:포트 check // 172.17.0.x:8080
	server s2 서버명:포트 check // 컨테이너명:8080
	server s3 서버명:포트 check

위와 같은 haproxy.cfg 파일을 생성해준다.

global 부분은 기본 설정이고, defaults의 mode는 http를 줄 경우 L7, tcp를 줄 경우 L4이다.

frontend stats의 경우 haproxy의 통계를 잡기 위해 8404번 포트를 오픈했다.

frontend myfrontend는 디폴트 설정에 대한 그룹설정으로 80번 포트로 들어오는 것을 webservers로 보낸다는 의미이다.

backend webservers에는 해당 리버스 프록시가 연결해줄 서버 목록들을 적어준다.

$ docker run -d --name=haproxy-con --net=haproxy-network -p 80:80 -p 8404:8404 \
-v $(pwd):/usr/local/etc/haproxy:ro haproxytech/haproxy-alpine:2.5

위와 같이 haproxy를 설치한 후 실행한다.

$(pwd)을 이용하여 pwd 수행의 결과와 컨테이너 내부를 연결해주기 위한 볼륨설정을 해주었기 때문에 haproxy.cfg 파일을 따로 보내주지 않아도 자동으로 동기화된다.

위와 같이 8404 포트로 접속 시 report 페이지에 잘 접속되는 것을 확인할 수 있다.

또한, localhost(80번포트)에 접속 시 위와 같이 부하분산이 적용된 백엔드 서버들을 순차적으로 오가는 것을 볼 수 있다.

 

2) HAproxy를 활용한 컨테이너 L4 스위치 프록시 실습 : URI 기반

global
	stats socket /var/run/api.sock user haproxy group haproxy mode 660 level admin expose-fd listeners \
	log stdout format raw local0 info

defaults
	mode http
	timeout client 10s
	timeout connect 5s
	timeout server 10s
	timeouthttp-request 10s
	log global

frontend stats
	bind *:8404
	stats enable
	stats uri /
	stats refresh 10s

frontend myfrontend
	bind :80
	default_backend webservers

	acl 서버명1 path_beg /서버명1
	acl 서버명2 path_beg /서버명2
	acl 서버명3 path_beg /서버명3

	use_backend 서버명1_backend if 서버명1
	use_backend 서버명2_backend if 서버명2
	use_backend 서버명3_backend if 서버명3

backend webservers
	balance roundrobin
	server s1 서버명1:포트 check
	server s2 서버명2:포트 check
	server s3 서버명3:포트 check

backend 서버명1_backend
	server s1 서버명1:포트 check
backend 서버명2_backend
	server s2 서버명2:포트 check
backend 서버명3_backend
	server s3 서버명3:포트 check

위와 같이 haproxy.cfg 파일을 수정해준다.

acl과 path_beg은 우측의 /서버명으로 접근 시 좌측의 서버명으로 이동시킨다. 또한, roundrobin 방식으로 배정된다.

이는 서버명/추가uri를 붙이는 경우 추가 uri로 특정 서버를 구분할 수 있게 된다.

위와 같이 특정 uri로 구분이 가능한 것을 확인할 수 있다.

하지만, 이 방식에서는 사용자가 좀 더 몰릴 것으로 예상되는 uri에 더 많은 자원을 배정하기에는 무리가 있다.

 

따라서 다음과 같은 방식으로 특정 URI에 서버를 여러개 붙일 수 있다.

global
	stats socket /var/run/api.sock user haproxy group haproxy mode 660 level admin expose-fd listeners \
	log stdout format raw local0 info

defaults
	mode http
	timeout client 10s
	timeout connect 5s
	timeout server 10s
	timeouthttp-request 10s
	log global

frontend stats
	bind *:8404
	stats enable
	stats uri /
	stats refresh 10s

frontend myfrontend
	bind :80
	default_backend webservers

	acl 서버명1 path_beg /uri1
	acl 서버명2 path_beg /uri1
	acl 서버명3 path_beg /uri2
	acl 서버명4 path_beg /uri2

	use_backend 그룹명1_backend if 서버명1
	use_backend 그룹명1_backend if 서버명2
	use_backend 그룹명2_backend if 서버명3
	use_backend 그룹명2_backend if 서버명4

backend webservers
	balance roundrobin
	server s1 서버명1:포트 check
	server s2 서버명2:포트 check
	server s3 서버명3:포트 check
	server s4 서버명4:포트 check

backend 그룹명1_backend
	server s1 서버명1:포트 check
	server s2 서버명2:포트 check
backend 그룹명2_backend
	server s3 서버명3:포트 check
	server s4 서버명4:포트 check

이제 URI가 1인지 2인지에 따라 전달되는 서버가 달라지기 때문에 URI 별로 프록시 설정이 가능하다.

위와 같이 수정해주면 된다.

위와 같이 4개의 컨테이너를 생성 및 실행해준다.

마지막으로 테스트해보기 위한 컨테이너를 실행해보면 다음과 같은 결과를 확인할 수 있다.

localhost/80 : web 1, 2, 3, 4가 로드밸런싱 ∵ default_backend (round robin 방식)

localhost/item : web 1, 2가 로드밸런싱 ∵ item_server 그룹 

localhost/basket : web 3, 4가 로드밸런싱 ∵ basket_server 그룹

 

'네트워크캠퍼스 > DOCKER' 카테고리의 다른 글

도커 DNS  (0) 2024.02.08
사용자 정의 네트워크 실습  (0) 2024.02.07
도커 사용자 정의 네트워크 구성  (0) 2024.02.06
도커 네트워크  (0) 2024.02.05
아틸러리를 활용한 스트레스 테스트  (0) 2024.02.05

1. 도커 DNS

1) 개념

- 사용자 정의 네트워크 내부 컨테이너의 이름을 자동으로 확인하도록 도커 호스트에 생성

- 127.0.0.11 대역 활용

- docker0에는 작동하지 않음

- 동일 network alias 할당을 통해 round robin 방식으로 응답 → 로드밸런서처럼 사용할 수 있음

- 컨테이너 생성 시 호스트 시스템에서 다음 세 파일을 복사하여 컨테이너 내부에 적용 → 컨테이너간 이름 조회 가능

① /etc/hostname

② /etc/hosts

③ /etc/resolv.conf

 

2) DNS 조회 방식

- 도커 DNS는 libnetwork라는 sandbox의 구현체에 구현

- 핵심 네트워킹 및 서비스 검색 기능 제공 → 등록된 모든 컨테이너를 이름으로 찾게 도와줌

- --name 혹은 --net-alias에 명칭을 적으면 DNS에 등록되는 방식

① ping 컨테이너명 입력

② DNS resolver를 이용하여 컨테이너 내부에 등록된 이름인지 검색

③ 컨테이너 내부에 등록된 이름이 아니라면 도커엔진 내의 DNS 서버에 질의

④ 질의한 타겟에게 결과를 전달

⑤ 최종적으로 전달된 내역을 토대로 연결

 

 

2. 도커 DNS 실습

먼저, dnsnet이라는 네트워크를 생성해준다.

route 명령어로 확인해보면 172.19 대역에 배정되어 있는 것을 확인할 수 있다.

$ docker run -d --name=es1 --net=dnsnet --net-alias=esnet-tg \
 -p 9201:9200 -p 9301:9300 -e "discovery.type=single-node" elasticsearch:7.17.10

$ docker run -d --name=es2 --net=dnsnet --net-alias=esnet-tg \
 -p 9202:9200 -p 9302:9300 -e "discovery.type=single-node" elasticsearch:7.17.10

위와 같이 elasticsearch를 이용하여 컨테이너 2개를 실행해준다.

이때 --net-alias 옵션을 통해 esnet-tg이라는 타겟 그룹을 생성해줬고, 이를 통해 현재 그룹은 1개인데 컨테이너는 2개가 된 상태이다.

조회해보면 위와 같이 컨테이너 2개가 잘 돌아가고 있는 것을 확인할 수 있다.

위와 같이 inspect 명령어로 조회하여 해당 컨테이너들의 IP를 기억해두고 진행한다.

$ docker run -it --rm --name=request-container --net=dnsnet busybox nslookup esnet-tg

사용자 정의 네트워크에 DNS 기능이 자동으로 활성화되는지 확인해보기 위해 busybox라는 이미지의 컨테이너를 실행한 후 busybox의 nslookup 기능을 이용하여 esnet-tg을 조회해보면 DNS 관련 정보를 확인할 수 있다.

위와 같이 해당 서버 IP 주소로 조회해보면 각 컨테이너가 등록된 DNS 서버의 이름이 정확하게 나오는 것을 확인할 수 있다.

es3이라는 컨테이너를 띄워준 후 다시 조회해보면 마찬가지로 잘 등록되어 있고,

elasticsearch의 특성 상 9200번 포트를 모두 열어야 하므로 같은 네트워크를 사용하는 centos를 활용해 조회해보도록 한다.

centos:8 버전의 컨테이너를 띄운 후 bash로 진입하여 alias로 설정했던 esnet-tg 그룹에서 9200번 포트를 사용하는 모든 요소를 검색해보면 위와 같은 정보를 확인할 수 있고, 해당 name을 기억한 후 같은 명령을 다시 내려본다.

위와 같이 name 부분이 계속 달라지는 것을 볼 수 있고, 이는 라운드로빈 형태로 최대한 순회하여 컨테이너 접속을 하고 있는 것을 의미한다.

$ docker inspect 컨테이너명

컨테이너에서 alias에 대한 정보는 위와 같이 inspect 명령어로 확인할 수 있다.

 

 

3. 도커 DNS로 Load Balancing 구현하기

먼저, lbdns라는 새로운 네트워크를 생성해주었고, route 명령어로 조회해보면 172.20 대역을 사용하고 있는 것을 확인할 수 있다.

위 명령어를 이용하여 lbdns 네트워크를 이용하고 nnet-tg이라는 별명을 가진 nlb1과 nlb2 컨테이너를 실행해주었다.

위와 같이 해당 컨테이너의 IP 주소를 알 수 있다.

등록된 DNS를 확인하기 위해 dnsutil을 설치해주었고, dig [타겟그룹명] 명령어를 사용하여 조회할 수 있다.

dns를 이용한 로드밸런싱을 확인하기 위해  nnet-request라는 컨테이너를 생성 및 실행했다.

bash로 접속 후 위와 같이 ping 명령어를 날려보면 nnet-tg이라는 그룹에 들어오는 요청을 nnet-tg에 속한 IP들로 랜덤하게 배분하는 것을 확인할 수 있다.

<실습> 아래 토폴로지를 보고 브릿지와 컨테이너를 구성해보자.

토폴로지 구성

먼저, create 명령어로 frontnet과 backnet을 생성해주었고, 목록을 조회해보면 네트워크가 잘 생성된 것을 확인할 수 있다.

inspect 명령어로 조회해보면 frontnet의 대역은 172.20으로, backnet의 대역은 172.21으로 설정된 것을 확인할 수 있다.

route 명령어로 조회하여 확인할 수도 있다.

frontnet 네트워크에는 front-con이라는 컨테이너를, backnet 네트워크에는 back-con과 db-con이라는 컨테이너를 생성하고 실행해주었다.

각 컨테이너들의 bash 창에서 ifconfig를 조회해보면 위와 같은 결과를  확인할 수 있다.

front-con 컨테이너는 frontnet의 172.20 대역을 사용하고 있고, back-con과 db-con 컨테이너는 backnet의 172.21 대역을 사용하고 있는 것을 확인할 수 있다.

또한, 네트워크 자체에 inspect 명령어를 수행해봐도 위와 같은 결과를 확인할 수 있다.

front-con 컨테이너를 backnet 네트워크에 연결하기 위해 connect 명령어를 사용하여 연결해주었고,

front-con 컨테이너에서 ip를 조회해보면 위와 같이 backnet의 172.21 대역이 잘 추가되어 있는 것을 확인할 수 있다.

front-con 컨테이너는 backnet 네트워크에 연결이 된 상태이기 때문에 backnet의 컨테이너인 back-con과 db-con에 ping을 수행해보면 잘 통신되는 것을 확인할 수 있다. 

또한, 연결된 엔드포인트를 모두 해제해준 후 disconnect 명령어로 네트워크 연결을 해제할 수 있고, 컨테이너가 모두 종료된 상태에서 rm 명령어로 네트워크 자체를 삭제할 수 있다.

'네트워크캠퍼스 > DOCKER' 카테고리의 다른 글

컨테이너 프록시  (0) 2024.02.08
도커 DNS  (0) 2024.02.08
도커 사용자 정의 네트워크 구성  (0) 2024.02.06
도커 네트워크  (0) 2024.02.05
아틸러리를 활용한 스트레스 테스트  (0) 2024.02.05

1. 사용자 정의 네트워크 구성

자동으로 생성된 브릿지 docker0은 기본 기능이다보니 빠진 기능이 많고, 보통 사용자가 정의한 네트워크를 구성하여 사용한다.

먼저, 위 명령을 이용하여 사용자 정의 bridge network 생성이 가능하다.

도커는 기본적으로 HostOS와 bridge 간 연결을 하는데 이는 --net 옵션으로 네트워크 설정을 할 수 있다.

※ --net 옵션에 줄 수 있는 효과

bridge 브릿지 접속을 하도록 설정
none 네트워크 외부 노출을 하지 않음
container:컨테이너명
container:컨테이너ID
다른 컨테이너의 네트워크 활용
(다른 컨테이너의 대역을 빌림)
host 컨테이너가 host os의 네트워크를 함께 쓰도록 설정
macvlan 물리 네트워크에 컨테이너 MAC 주소를 통한 직접 연결 사용
NETWORK 기타 사용자 정의 네트워크 활용

 

위와 같이 포트포워딩 정보 없이 컨테이너를 띄웠는데도 불구하고 연 적도 없는 80번 포트가 열리는 것을 확인할 수 있다.

위와 같이 nginx가 그냥 호스트 주소로도 잘 돌아가는 것을 확인할 수 있다.

nginx의 80번 포트에 대한 PID를 조회해보면 host 내부 프로세스처럼 잡히는 것을 볼 수 있다.

해당 컨테이너는 자체적인 IP 주소를 갖지 않는 것을 볼 수 있다.

호스트의 IP를 쓰기 때문에 따로 배정받을 필요가 없는 것이고, 이는 docker0을 쓰지 않는다는 의미이다.

 

1) 사용자 정의 네트워크 생성

먼저, network create 명령어로 생성 후 확인해보면 아무 옵션도 주지 않은 경우 기본 bridge로 만들어지는 것을 볼 수 있다.

route를 이용하여 현재 ip routing table을 조회해보면 위와 같이 인터페이스명이 br로 시작하는 브릿지가 생성된 것을 확인할 수 있다.

172.18 대역으로 브릿지가 생성되었다.

ifconfig로 조회해보면 가장 상단에 해당 인터페이스를 볼 수 있다.

현재까지의 네트워크 구성은 위 그림과 같다.

또한, inspect 명령어를 통해 자세한 네트워크 상황을 조회해볼 수 있다. 

마찬가지로 아무 설정하지 않았을 경우 기본값은 브릿지로 생성되는 것을 확인할 수 있다.

위와 같이 터미널을 각각 띄워 해당 네트워크 브릿지에 2개의 컨테이너를 연결한다.

ifconfig 명령어로 각각 배정받은 ip 주소를 확인할 수 있다.

route 명령어를 통해 연결되어 있는 대역을 확인할 수 있고, 위쪽에서 새로 생성했던 172.18 대역에 연결된 것을 알 수 있다.

현재까지의 네트워크 구성은 위 그림과 같다.

inspect로 조회해보면 브릿지 입장에서도 확인할 수 있고, 연결된 컨테이너들도 볼 수 있다.

brctl show를 수행해보면 위와 같이 2개의 브릿지를 확인할 수 있고, 생성한 브릿지가 2개의 인터페이스를 가지는 것을 볼 수 있다.

컨테이너는 무조건 하나 당 하나 이상의 가상이더넷을 가지므로 컨테이너 두 개가 띄워진 현재는 위와 같이 설정된다.

network1의 bash 창에서 ping을 해보면 위와 같이 컨테이너 이름만 가지고도 잘 수행되고, network2의 IP 주소도 확인할 수 있다.

사용자 정의 네트워크는 자체적으로 DNS를 구성해주고, 그곳에 알아서 도메인까지 구성된다.

원래 컨테이너 이름만 가지고는 당연히 IP 주소를 조회할 수 없지만, 같은 커스텀 네트워크 내부에서는 예외적으로 docker DNS가 구축되기 때문에 컨테이너 이름만으로도 조회가 가능하다.

위와 같이 아무런 옵션 없이 newnode를 만들어주면 기본브릿지(192.17 대역)로 연결된다.

현재까지의 네트워크 구성은 위 그림과 같다.

따라서 network1 컨테이너에서는 newnode 컨테이너에 ping을 보낼 수 없는 것을 학인할 수 있다.

 

2) 좀 더 상세한 네트워크 만들어보기

위와 같이 좀 더 상세한 옵션들을 지정해준 후 네트워크를 생성하고 조회해보면 목록에 잘 생성된 것을 확인할 수 있다.

라우트 목록을 조회해보면 위에서 설정한 대역으로 브릿지가 생성된 것을 확인할 수 있다.

여기서 다음 컨테이너를 띄우면 IP는 172.33.1 대역으로 가져가게 될 것이다.

컨테이너를 띄운 후 ip를 조회해보면 역시 172.33.1.0 대역으로 진행되고, 처음 만든 컨테이너라 2번으로 배정된다.

자동 순서대로 배정하고 싶지 않으면 위와 같이 --ip 옵션으로 내부 IP를 지정할 수도 있다.

위와 같이 네트워크 자체를 조회해봐도 위와 동일한 정보들을 확인할 수 있다.

brctl로 확인해보면 위와 같이 생성한 브릿지 목록을 확인할 수 있다.

또한, ip addr 명령어로 해당 브릿지들을 확인할 수 있다.

ip route로도 역시 확인 가능하다.

exec를 이용해 net1에 ip addr 명령을 전달하여 조회해봐도 위와 같이 연결 현황을 확인할 수 있다.

최종 네트워크 구성은 위 그림과 같다.

 

3) 브릿지가 다른 경우의 구성

먼저, vswitch에 연결한 net1의 경우 172.33 대역을 사용하고 있다.

반면, mynetwork에 연결한 network1이나 network2는 172.18 대역을 사용하고 있다.

network1에서 net1으로 ping을 보내면 위와 같이 연결이 안되는 것을 확인할 수 있다.

즉, 같은 내부망이어도 현재 구성만으로는 브릿지 간 통신이 불가능하다는 것을 알 수 있다.

 

4) 네트워크 연결

먼저, con-net2라는 새로운 네트워크를 생성해주었고, 위 명령어를 통해 172.19 대역을 사용하고 있는 것을 확인할 수 있다.

위와 같이 connect 명령어를 사용하여 network2 컨테이너를 con-net2에 연결해주었다.

network2의 bash 창에서 확인해보면 위와 같이 eth1에 con-net2의 대역이 추가되어 있는 것을 확인할 수 있다.

이렇게 되면 양쪽 네트워크 모두에 연결된 형태가 되기 때문에 자연스럽게 양쪽 망과 통신이 가능해지게 된다.

con-net2 대역을 사용하는 connet라는 컨테이너를 만들어준 후 network2의 bash창에서 ping을 날려보면 위와 같이 잘 통신되는 것을 확인할 수 있다.

또한, con-net2를 inspect해보면 컨테이너 목록에서 위와 같이 network2를 인지하고 있는 것을 확인할 수 있다.

rm을 이용하여 con-net2 브릿지를 삭제해보면 위와 같이 연결된 컨테이너 엔드포인트가 존재하여 불가능하다는 오류가 발생한다.

컨테이너와 브릿지의 연결은 disconnect 명령어로 진행할 수 있다.

con-net2에 연결되어 있던 conneet 컨테이너를 삭제해주면 con-net2 네트워크도 정상적으로 삭제가 진행되는 것을 볼 수 있다.

'네트워크캠퍼스 > DOCKER' 카테고리의 다른 글

도커 DNS  (0) 2024.02.08
사용자 정의 네트워크 실습  (0) 2024.02.07
도커 네트워크  (0) 2024.02.05
아틸러리를 활용한 스트레스 테스트  (0) 2024.02.05
CLI에서 컨테이너 관리  (0) 2024.01.31

1. 컨테이너의 네트워크

1) 리눅스 네트워크

- 도커 네트워크는 리눅스 커널의 네트워크 스택의 하위 스택, 상위에는 네트워크 드라이버 생성

- CNM이라고 하는 인터페이스 위에 구축

- 인터페이스 특성상 해당 기능이 구현되기만 하면 실행에 문제가 없으므로 OS나 인프라에 구애받지 않고 사용 가능

- 리눅스 네트워크 빌딩 블록 : 리눅스 브릿지, 네트워크 네임스페이스, veth pair, iptables 등이 포함

    → 복잡한 네트워크 정책을 위한 규칙 및 네트워크 분할 및 관리 도구 제공

- 2계층에 해당하는 도구로 MAC 주소를 활용하여 식별하고 통신

※ 리눅스 브릿지 : 커널 내부의 물리적인 스위치를 프로그래밍적으로 가상 구현한 OSI L2 디바이스

    → 트래픽을 검사하여 동적으로 학습되는 MAC Address를 기반으로 트래픽 전달

- 브릿지 네트워크의 기본 대역

① 172.17~31.0.0/16 (65536개)

② 192.168.0~240.0/20 (4096개)

- Docker 0 : 리눅스 커널과 os 도구를 통해 관리하고, Docker0 위에 브릿지들이 위치하여 도커엔진하에 관리됨, 브릿지와 컨테이너 사이에 vethernet이 위치해 연결해줌

위와 같이 기본적으로 할당된 이더넷 브릿지 대역(172.17.0.1)을 확인할 수 있다.

 

2) 도커 네트워크

① 네트워크 네임스페이스

- 커널에 격리된 네트워크 스택으로 자체 인터페이스, 라우터, 방화벽 규칙 보유

- 컨테이너와 리눅스의 보안적인 측면으로 컨테이너를 격리하는 데 사용

- 일반적으로 CNM 네트워크 드라이버는 각 컨테이너별로 별도 네임스페이스가 구현됨

② CNM(Container Network Model) : 도커 네트워크가 이런 요소들을 가져야 한다고 정의해둔 인터페이스

- sandbox : 격리된 네트워크 자체 → ethernet, port, route table, DNS 구성 등을 총체적으로 그룹화

- endpoint : 가상 이더넷의 인터페이스 → IP, MAC 주소 등으로 접근

- network : 가상 스위치, 브릿지

※ CNM을 기반으로 구현한 libnetwork가 docker network이다.

위와 같이 실제로 사용 가능한 모델들을 볼 수 있고, bridge, host, none(아무것도 쓰지 않음)을 확인할 수 있다.

브릿지는 기본적으로 싱글 호스트를 지원하여 내부망으로 연결만 해줄뿐 다른 네트워크와 연결되지 않는다.

※ 멀티호스트 지원은 bridge to bridge 수행을 위해 overlay라는 것을 통해 지원된다.

- 컨테이너는 직접 bridge와 연결될 수 없음 → vethernet : 컨테이너와 1:1로 매칭되어 브릿지 사이에서 중개해주는 역할

- 컨테이너 자체의 엔드포인트 조회 : ifconfig, route, ip a, ip addr, ip add 등

- 브릿지 조회 : brctl show

$ sudo apt install bridge-utils
$ brctl show

docker0 네트워크를 활용하는 컨테이너들이 interfaces에 나열된다.

컨테이너 추가 후 다시 조회해보면 인터페이스가 추가된 것을 볼 수 있다. 인터페이스는 꼭 생성 순서대로 나열되지는 않는다.

exec 명령어를 사용하여 ip addr 명령어를 수행해보면 위와 같이 loopback과 vethernet 주소를 확인할 수 있다.

route 명령어를 통해 해당 컨테이너와 연결된 브릿지를 확인할 수 있다. docker0(172.17.0.0)과 연결된 것을 볼 수 있다.

호스트에서 route 명령어를 수행하면 좀 더 확실하게 조회할 수 있다.

또한, inspect 명령어를 통해 해당 컨테이너의 IP, MAC 정보를 확인할 수 있다.

즉, 컨테이너가 네트워크 통신을 위해 갖는 모든 것들은 샌드박스에 의해 정의된다.

위에서 docker network ls 조회 시 나왔던 bridge는 기본 브릿지이고, docker0 위에 얹혀져 있다.

위 명령어를 통해 브릿지 자체에 대해 inspect 해보면 위와 같이 IPAM 내부에서 네트워크 전체 대역에 대한 내용을 볼 수 있다.

또한, Containers를 통해 할당된 컨테이너들도 확인할 수 있다.

 

Veth는 두 네트워크 네임스페이스 사이의 연결을 위해 동작하는 리눅스 네트워킹 인터페이스이다.

Vethernet은 각 네임스페이스에 단일 인터페이스를 가지는 전이중 링크로 양방향 통신이 되어 한 인터페이스의 트래픽을 다른 인터페이스로 전해주는 역할을 한다. 도커 네트워크 생성 시 Veth를 통해 네임스페이스 간 명시적 연결을 제공한다.

컨테이너의 Eth은 Veth보다 기본적으로 1 작은 값으로 연결된다.

위와 같이 veth 값이 배정된 것을 볼 수 있고, 이 경우 컨테이너 자체의 eth 값은 9, 7, 5번이 될 것이다.

해당 컨테이너의 bash로 진입해둔 상태라면 위 명령어로 veth 값을 조회할 수 있다.

 

docker0은 기본적으로 172.17.0.1을 사용하지만 외부에서는 172.17 대역을 쓰지 않으므로 이를 보완하기 위해 NAT이라는 것을 활용한다.

결국 어떤 서버의 IP 주소를 다시 내부 IP로 변환해줘야 하는데 이때 매핑되는 주소를 iptables라는 명령어로 조회할 수 있다.

위와 같이 0.0.0.0/0 (외부 접속자 누구라도) 으로 접속하면 연결되는 포트번호 등을 확인할 수 있다.

 

 

2. 내부망 host들  상호 간 등록하기

host1과 host2 터미널을 오가거나 scp 등으로 파일을 보낼 때 불편했는데 내부망 호스트들을 상호 간 등록하여 IP주소가 아닌 host 이름으로 해당 작업들을 수행할 수 있다.

1) PC 간

$ sudo vi /etc/hosts

먼저, 위 파일을 열어보면 localhost와 hostos1의 주소만 등록되어 있는 것을 볼 수 있다.

위와 같이 hostos1과 hostos2에 설정했던 주소를 192대 대역으로 입력해준다.

$ ssh 계정명@호스트명

위와 같이 ssh 명령어로 hostos1 PC에서 hostos2를 제어할 수 있게 된다.

또한, w를 입력하면 위와 같이 hostos1이 접속중임을 확인할 수 있다.

 

2) 컨테이너 간

컨테이너들도 서로 다른 PC의 호스트 연결과 비슷한 작업을 할 수 있다.

--add-host=host명:ip주소를 통해 컨테이너의 /etc/hosts에 호스트명:IP주소를 매칭하여 저장한 것을 확인할 수 있다.

또한, dns 등록도 가능하다.

--dns=ip주소를 통해 DNS 서버의 ip 주소를 /etc/resolv.conf에 등록해준다. 

--mac-address=mac주소를 통해 MAC 주소를 지정할 수도 있다.

 

3) 네트워크 관련 지정 옵션

--expose=포트번호 방화벽 열기처럼 해당 포트로의 접속을 외부에 공개
--net=bridge
--net=none
--net=host
container의 네트워크 설정, bridge는 docker0
-h
--hostname=호스트명
host의 이름 설정, pid가 디폴트값
-P
--publish-all=true
--publish-all=false
포트바인딩 시 호스트측 접근 포트를 랜덤 지정
-p host포트:컨테이너포트
--publish published=host포트
--target=타겟포트
지정포트바인딩
--link=컨테이너명:컨테이너ID 동일 호스트의 다른 컨테이너에서 이름으로 연결 가능하게 지정

위와 같이 여러 옵션을 사용하여 네트워크 설정을 할 수 있고, expose 옵션으로 지정했던 포트가 잘 열려있는 것을 확인할 수 있다.

물론, 기본적으로는 history 명령어를 통해 Dockerfile에 설정된 포트를 노출하는 것이 제일 중요하다.

위와 같이 포트바인딩 자체는 알아서 32769:80, 32769:30000으로 배정되어 있는 것을 볼 수 있다.

또한, 위와 같이 6367번 PID로 도커 프록시가 돌고 있고, 해당 프록시가 world(0.0.0.0)의 32769번 포트로 접속하는 것을 172.17.0.6의 80번 포트로 연계해주는 것을 볼 수 있다.

 

 

3. 브릿지와 오버레이의 차이

브릿지는 기본적으로 내부망으로 진입할 수 있는 진입점의 기능을 한다. 다만, 브릿지는 자신의 호스트 내부망만을 담당한다.

따라서 브릿지 간 통신, 즉 외부 호스트끼리 연결하기 위해서는 overlay가 추가로 필요하다. 이는 도커 스웜을 통해 구현할 수 있다.

+ Recent posts