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가 추가로 필요하다. 이는 도커 스웜을 통해 구현할 수 있다.

※ LXC로부터 시작된 도커의 컨테이너 가상화 기술은 현재는 도커엔진이라는 자체 스펙으로 바뀌었지만, 근간은 여전히 LXC에 있다.

 

1. 컨테이너 내부 측정

처음 가상머신 생성 시 위와 같이 도커가 깔리는 드라이버와 OS가 깔리는 드라이버로 나누었다.

 

/var라는 폴더에 이미지라는 특정 OS와 특정 프로그램이 패키징된 스냅샷을 찍어두고 프로세스를 띄우는 방식으로 진행한다.

이 때 layer라는 개념을 통해 각각의 구성 요소를 조합하게 되고, 이미지 레이어는 Read Only 레이어와 Read, Write가 가능한 컨테이너 레이어가 있다.

 

이미지를 이용해 띄운 컨테이너는 내부적으로 OS가 먼저 실행되며 PID 1번 부여받음, 추가로 네트워크, CPU, 메모리, 디스크 등도 할당받음

이는 리눅스로 수행할 수도 있지만 편의성 증대를 위해 도커라는 기술을 활용한다.

 

내부 구조를 가져오기 위해 먼저 pull과 run을 이용하여 ubuntu 14.04 버전의 bash를 띄워준다.

ls로 조회해보면 시스템 영역에서 사용할법한 디렉터리들(opt, proc, root, run sbin 등)이 위치하는 것을 확인할 수 있다.

이를 chroot 혹은 pivot_root라고 부른다. → root file system을 구성하게 도와주고, 이를 통해 독립성이 보장된다.

 

컨테이너 안에서 조회해보면 위와 같이 디바이스의 사용량이나 가용 자원 등에 대해 나오는데, 특이점은 host docker가 설치된 영역인 /dev/sdb1이 그대로 공유되는 것을 볼 수 있다.

pivot_root와 mount namespace가 위 사례이다.

mount namespace : 장비를 mount시키는 것처럼 가동하는 기술

 

UTS namespace : 컨테이너 아이디와 호스트네임을 동기화시키는 작업

모든 OS는 호스트네임을 가지고, 컨테이너가 생성되면 container id가 부여된다. 해당 ID가 hostname으로 사용된다.

해당 프로세스가 작업을 수행하는데 필요한 것들을 격리시키는 기술인 PID 혹은 IPC namespace라는 기술이 적용된 것을 볼 수 있다.

ifconfig로 확인해보면 위와 같이 eth0에 내부 IP가 할당된 것을 볼 수 있고, 이를 network namespace라고 부른다.

위와 같은 여러 기술이 어우려져 host와는 격리된 환경에서 컨테이너가 하나의 프로세스로 동작한다.

 

 

2. 컨테이너 격리 기술

chroot 프로세스의 루트 디렉토리를 변경, 격리하여 가상의 루트 디렉토리 배정
pivot root 루트 파일시스템을 변경, 컨테이너가 전용 루트 파일시스템을 가지도록 함
mount namespace namespace 내에 파일 시스템 트리 구성
uts namespace host와 다른 별개의 hostname을 가지도록 함
pid namespace pid와 프로세스 분리
(systemd와 분리, 우분투의 1번 프로세스인데 잡히지 않음)
network namespace 네트워크 리소스 할당 (ip, port, route table, ethernet 등)
ipc namespace 전용 process table 보유

 

위와 같이 격리된 namespace 목록은 위와 같이 lsns 명령어로 조회할 수 있다.

 

 

3. 컨테이너의 라이프사이클

① create : image의 스냅샷으로 /var/lib/docker 영역 내에 컨테이너 생성

② start : process 영역에 컨테이너를 생성하여 실행 상태로 만들어줌

③ stop : process 영역에 컨테이너를 제거하여 종료 상태로 만들어줌

④ rm : create로 생성된 스냅샷 삭제

먼저, pull로 ubuntu:16.04 버전을 받아온다.

create 명령어로 새로운 컨테이너를 생성하고 조회해보면 위와 같이 Created 상태의 컨테이너가 만들어진 것을 확인할 수 있다.

Created 상태는 스냅샷을 만들어두기만 하고 프로세스로 가동은 하지 않은 상태이다.

프로세스로 올려서 실행시키기 위해 start 명령을 이용하고 확인해보면 위와 같이 Up 상태로 바뀐 것을 확인할 수 있다.

stop 명령어를 이용하고 확인해보면 위와 같이 Exited 상태로 바뀐 것을 확인할 수 있다.

Exited 상태는 프로세스로 구동만 안하고 있을 뿐 구동 준비는 된 상태이기 때문에 언제든 다시 start가 가능하다.

rm 명령어로 컨테이너를 삭제해주면 위와 같이 아무것도 조회되지 않는 것을 확인할 수 있다.

create와 start를 합친 run 명령어를 이용하면 위와 같이 바로 bash 창으로 들어가는 것이 가능하다.

# apt update
# apt -y install net-tools

각 컨테이너들은 격리환경이기 때문에 필요한 업데이트나 의존성 설정은 처음부터 해줘야 한다.

ifconfig로 확인하면 위와 같이 잘 출력되는 것을 볼 수 있다.

 

 

4. 컨테이너 내부 구조

먼저, ubuntu14.04 버전의 컨테이너를 띄운 후 위와 같은 작업들을 수행했다.

위와 같이 프로세스를 조회해보면 도커 컨테이너가 프로세스로 잡혀있는 것을 확인할 수 있다.

 

※ 스냅샷(이미지)은 Read only이지만, 컨테이너(프로세스)는 Read, Write가 가능하다.

 

root 권한 상태로 변경 후 find 명령어로 container.txt를 찾아보면 위와 같은 결과를 확인할 수 있다.

merged 경로로 이동한 후 ls를 해보면 컨테이너 내부의 파일 구성이 그대로 보이는 것을 확인할 수 있다.

즉, 컨테이너 내부는 사실 overlay2라는 스토리지 영역에 포함된 컨테이너 아이디 폴더에 종속되어 있는 파일들의 집합이라는 것을 알 수 있다.

다른 터미널에서 조회해보면 위와 같이 같은 내용이 나오는 것을 확인할 수 있다.

루트권한에서 a라는 파일을 생성한 후 다른 터미널에서 컨테이너 내부를 조회하면 잘 동기화되는 것을 확인할 수 있다.

 

☆ 즉, 컨테이너 내부에서 생성된 정보는 container layer + snapshot 영역에 저장된다.

 

 

5. 컨테이너 운영 명령어

먼저, 컨테이너 운영을 살펴보기 위한 노트 웹서버를 구축하기 위해 다음과 같은 파일을 작성해준다.

- app.js

const http = require('http');

const server = http.createServer().listen(5678);

server.on('request', (req, res) => {
    console.log('request');
    res.write("HostName: " + process.env.HOSTNAME + "\n");
    res.end();
});

server.on('connection', (socket) => {
    console.log("connected.");
});

 

- Dockerfile

FROM node:20-alpine3.17            // 어떤 os와 프레임워크 위에서 돌릴지
RUN apk add --no-cache tini curl   // 알파인 리눅스이므로 apk로 구동
WORKDIR /app                       // /app이라는 경로 생성 후 cd /app 실행
COPY app.js .                      // Dockerfile과 같은 경로의 app.js를 현재경로에 복사	
EXPOSE 5678                        // 포트바인딩 시 컨테이너 측의 노출포트가 5678
ENTRYPOINT ["/sbin/tini", "--"]	   // 내부적으로 app.js를 실행해주는 명령어
CMD ["node", "app.js"]             // (ENTRYPOINT와 CMD)

 

위 명령어로 이미지를 생성한다.

위와 같이 history 명령어로 nodeapp의 내용을 확인해볼 수 있다.

run 명령어로 컨테이너를 실행하고, 조회해보면 위와 같이 잘 띄워진 것을 확인할 수 있다.

-h 옵션은 hostname을 nodeapp으로 구성하겠다는 의미이다. 해당 태그를 주지 않으면 컨테이너 아이디가 hostname으로 부여된다.

 

※ 세부옵션

--env 컨테이너의 환경변수 지정
-d
--detach=true
백그라운드 실행모드 활성화, 컨테이너 아이디 등록
-t TTY 할당 (bash창 열어주기)
-i
--interactive
대화식 모드 열기 (컨테이너 내부에 명령어 주고받기)
--name 실행되는 컨테이너에 이름 부여 (미지정 시 랜덤한 2단어 조합명으로 부여)
--rm 컨테이너 종료 시 자동으로 컨테이너 제거 (stop 시 삭제)
--restart 컨테이너 종료 시 적ㅈ용할 재시작 정책 지정
(no, on-failure, on-failure:n(횟수), always)
-v
--volume=호스트경로:컨테이너경로
볼륨설정 (볼륨마운트)
-h 컨테이너의 호스트명 지정 (미지정 시 컨테이너 아이디를 호스트명으로 등록)
-p 호스트포트:컨테이너포트
--publish
호스트 포트와 컨테이너 포트를 바인딩
-P
--publish-all=true|false
컨테이너 내부의 EXPOSE 포트를 랜덤포트와 바인딩
--workdir
-w
컨테이너 내부의 작업 경로 (디렉터리)

 

docker top 명령어를 이용하여 컨테이너에서 현재 실행 중인 프로세스의 상태를 볼 수 있다.

docker port 명령어를 이용하여 포트정보를 알 수 있고, IPv4와 IPv6에 대한 정보가 모두 나온다.

위 명령어를 이용해 docker-proxy라는 대리포트 값을 조회할 수 있다.

위에서 얻은 프록시 값으로 위 명령어 입력 시 해당 포트바인딩 명령어의 정보가 저장된 위치가 나온다.

docker stats 명령어로 실시간으로 어떻게 자원을 소비하고 있는지 확인할 수 있다.

해당 컨테이너로 curl이나 브라우저 접속을 유도하면 갑자기 사용량이 증가하는 것을 관찰할 수 있다.

컨테이너명을 여러개 적으면 동시에 조회도 가능하며 흐름에 따른 갱신을 보고싶지 않다면 --no-stream 옵션을 추가하면 된다.

 

 

6. 모니터링용 이미지 및 컨테이너로 상태 감시

1) cadvisor 

→ docker stats로도 상태를 감시할 수 있지만 좀 더 전문적으로 감시할 수 있는 툴

→ 도커허브가 아닌 gcr에 올라와 있기 때문에 아래와 같은 명령어들로 볼륨마운트를 해야만 볼 수 있다.

$ docker run \
--restart=always \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:rw \
--volume=/sys/fs/cgroup:/sys/fs/cgroup:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--volume=/dev/disk/:/dev/disk:ro \
--publish=8765:8080 \
--detach=true \
--name=cadvisor \
--privileged \
--device=/dev/kmsg \
gcr.io/cadvisor/cadvisor:latest

위와 같이 이미지를 받은 후 조회해보면 컨테이너가 잘 띄워진 것을 확인할 수 있다.

해당 IP와 포트로 접속해보면 위와 같이 잘 접속된다.

위와 같이 매트릭 형태로 실시간 트래픽들을 확인할 수 있다.

 

 

리눅스에서 반복문 수행 시 헬스체크를 수행하도록 할 수 있다.

※ 헬스체크 : 서버의 가동 여부를 지속적으로 확인하는 행위

$ while true; do curl 노드서버주소; sleep 초단위; done

위와 같은 반복문 수행 시 sleep으로 딜레이를 주기 때문에 해당 초마다 한 번씩 노드서버에 접속하게 된다.

 

console.log()를 이용하여 nodeapp에 지속적으로 요청을 넣어 찍히는 log를 확인할 수 있다.

 

 

 

 

 

 

 

 

 

 

7. cp 명령어로 컨테이너 내부에 호스트 파일 복사하기

간단한 파일 전송 시에는 볼륨마운트 대신 cp 명령어를 이용하여 넘기기도 한다.

$ docker cp 호스트파일명 컨테이너명:경로와파일명

 

 

 

 

 

 

 

 

 

 

 

 

 

※ 일반적인 기업 내부 프로젝트용 이미지는 OS나 프레임워크 등에 대한 정보가 포함되어 있고 의존성 정보도 노출하기 때문에 프라이빗 저장소를 직접 구축하여 사용하기도 한다. → 도커허브에 공개된 registry라는 공식 이미지를 이용하여 구축하는 경우가 많다.

 

1. registry 구축

먼저, registry를 받아오고 확인해보면 25MB 정도로 용량이 상당히 작은 것을 볼 수 있다.

$ docker run -d \
-v /home/유저명/registry_data:/var/lin/registry \
-p 5000:5000 \
--restart=always \
--name=private-registry \
registry

-v 옵션 : 볼륨 → 호스트의 저장폴더와 컨테이너의 저장폴더를 동기화

위 명령어를 통해 호스트의 /home/jihyun/registry_data 폴더에 있는 파일을 컨테이너의 /var/lin/registry 폴더와 즉시 동기화한다.

포트 5000번으로 포트바인딩을 꺼지지 않고 재시작하도록 하는 registry 컨테이너를 띄운다.

history 명령어로 확인해보면 노출시키는 포트가 5000번이고 VOLUME 역시 이미 컨테이너측의 경로가 지정되어 있다.

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

위 명령어로 저장 요소를 검색해보면 현재 컨테이너에는 별다른 저장자료가 없기 때문에 위와 같이 출력된다.

위와 같이 보통 alias로 등록해두고 사용한다.

도커허브에 올릴 때 레포지토리명을 따로 이미지에 반영해줬듯이 위처럼 사설 레포지토리의 내부망 주소를 태그로 붙여준다.

해당 주소로 push 해보면 현재는 도커 엔진이 신뢰할 수 없는 저장소이기 때문에 위와 같은 오류가 발생한다.

위 오류를 해결하기 위해서 현재 컨테이너를 저장소로 등록해주고 반영해야 한다.

/etc/init.d/docker 파일의 DOCKER_OPTS 부분을 위와 같이 수정한 후 저장한다.

또한, 위와 같이 파일 생성 후 insecure-registries라는 key 값에 해당 IP 주소를 리스트 형식으로 등록해준다.

갱신 내역들을 반영하기 위해 도커를 재시작해준 후 docker info 명령어로 확인해보면 위와 같이 잘 등록된 것을 볼 수 있다.

이 상태로 push 해주면 위와 같이 잘 수행되는 것을 확인할 수 있다.

위와 같이 이미지 목록과 해당 이미지의 태그도 잘 조회되는 것을 확인할 수 있다.

 

 

2. 구축한 레지스트리로 이미지를 받거나 업로드하기

더보기

<시나리오>

1) host2에 host1의 주소를 기반으로 해서 DOCKER_OPS 에 환경설정을 하고 갱신

2) host2에서 이미지 생성하기

3) 해당 이미지를 host1 기반 private 레지스트리에 업로드

4) 업로드된 내역을 catalog로 조회하기

5) pull도 받아보기

먼저, 해당 주소가 안전한 저장소임을 등록하기 위해 위와 같이 환경설정을 해주어야 한다.

마찬가지로 insecure-registries라는 key 값에 해당 IP 주소(host1주소)를 리스트 형식으로 등록해준다.

도커를 재시작한 후 조회해보면 위와 같이 해당 IP가 잘 등록되어 있는 것을 확인할 수 있다.

docker pull을 해보면 위와 같이 host1 주소에 있는 이미지를 당겨서 받아오고 있는 것을 확인할 수 있다.

host2에서 hello-world 이미지를 생성했고, 해당 이미지를 host1의 레지스트리에 push 해주었다.

host1에서 catalog와 태그를 조회해보면 위와 같이 잘 추가된 것을 확인할 수 있다.

마찬가지로 pull을 해보면 사설 저장소에 있던 것을 당겨서 받아오는 것을 확인할 수 있다.

+ Recent posts