✔️ Service Discovery
✔️ 환경 변수를 이용한 Service Discovery
Service Discovery
는 클라우드 환경에서 중요하다.
클라이언트가 있고 서버가 있을 때 서버가 ASG(AutoScaling Group)을 통해 확장하거나 축소한다.
만약 확장한다면 새로 생성된 서버의 ip를 어떻게 알 수 있을까 ?
클라우드 레벨에서는 새로 생성된 서버의 ip를 확인할 수 있지만 클라이언트의 어플리케이션은 이 정보를 어떻게 알 수 있을까?
일반적으로 서버 앞에 LB를 두고 LB가 자동으로 ASG과 연동이 되면서 스케일 인이 되면 백엔드로 자동으로 등록되고 스케일 아웃 시에는 백엔드에서 제거한다.
유일한 진입점(LB)을 만들어 해결한다. 그리고 LB에 이름을 붙인다.
클라이언트의 App은 고정된 이름을 가진 LB에 접속하고 분산이 이루어진다.
이런 방식으로 어플리케이션이 해당 서버를 찾는 것을 Service Discovery
줄여서 SD
라고 한다.
구체적 예시를 들어보자 워드프레스(WP)가 있으면 WP
는 MySQL
DB를 찾아야 한다.MySQL
가 랜덤한 ip 주소를 가진 컨테이너일 때 WP
가 어떻게 MySQL
을 찾을까 ?
그래서 우리는 MySQL
앞에 SVC
를 만들고 이 SVC
의 백엔드로 연결시킨다. (레이블과 셀렉터로 연결이 된다.)SVC
자체의 ip도 랜덤하기 때문에 WP
도 SVC
의 ip를 알 수 없다.
고정된 이름이 필요하다. 따라서 WP
도 DB를 찾기위해서 SD를 해야한다.
vagrant@k8s-node1 ~/svc kubectl create -f myweb-rs.yaml -f myweb-svc.yaml
replicaset.apps/myweb-rs created
service/myweb-svc created
vagrant@k8s-node1 ~/svc kubectl get rs,po,svc
NAME DESIRED CURRENT READY AGE
replicaset.apps/myweb-rs 3 3 3 8s
NAME READY STATUS RESTARTS AGE
pod/myweb-rs-6mzrh 1/1 Running 0 8s
pod/myweb-rs-sw2m7 1/1 Running 0 8s
pod/myweb-rs-vjkjc 1/1 Running 0 8s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 24s
service/myweb-svc ClusterIP 10.233.13.143 <none> 80/TCP 8s
클라이언트에 사용할 파드를 하나 띄워보자
vagrant@k8s-node1 ~/svc kubectl run nettool -it --image ghcr.io/c1t1d0s7/network-multitool --rm
If you don't see a command prompt, try pressing enter.
/ # env
KUBERNETES_PORT=tcp://10.233.0.1:443
MYWEB_SVC_PORT_80_TCP_PORT=80
KUBERNETES_SERVICE_PORT=443
MYWEB_SVC_PORT_80_TCP_PROTO=tcp
HOSTNAME=nettool
SHLVL=1
HOME=/root
MYWEB_SVC_PORT_80_TCP=tcp://10.233.13.143:80
TERM=xterm
KUBERNETES_PORT_443_TCP_ADDR=10.233.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
MYWEB_SVC_SERVICE_HOST=10.233.13.143
KUBERNETES_SERVICE_PORT_HTTPS=443
MYWEB_SVC_PORT=tcp://10.233.13.143:80
MYWEB_SVC_SERVICE_PORT=80
KUBERNETES_PORT_443_TCP=tcp://10.233.0.1:443
KUBERNETES_SERVICE_HOST=10.233.0.1
PWD=/
MYWEB_SVC_PORT_80_TCP_ADDR=10.233.13.143
env
를 입력하면 환경변수가 출력된다. 환경변수의 이름과 값을 확인해보자
모든 파드는 실행시 현재 시점의 서비스 목록을 환경변수로 제공한다.
/ # env | grep MYWEB
MYWEB_SVC_PORT_80_TCP_PORT=80
MYWEB_SVC_PORT_80_TCP_PROTO=tcp
MYWEB_SVC_PORT_80_TCP=tcp://10.233.13.143:80
MYWEB_SVC_SERVICE_HOST=10.233.13.143
MYWEB_SVC_PORT=tcp://10.233.13.143:80
MYWEB_SVC_SERVICE_PORT=80
MYWEB_SVC_PORT_80_TCP_ADDR=10.233.13.143
nettool
이라는 파드를 띄우는 시점에 존재하는 서비스들의 정보가 컨테이너에 환경변수로 반영된다. Injection
된다.
- MYWEB - 서비스의 이름이다.
- SVC - SVC라는 타입이다.
- PORT - 포트 정보를 가진다.
- 80 - 포트 번호
- TCP - 프로토콜
- PORT - 포트에서의 포트번호 (etcd에서 해당되는 서비스의 정보를 읽어서 세팅해준다.)
환경변수명의 구조는 정해져있는 것이다.
vagrant@k8s-node1 ~ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 6m49s
myweb-svc ClusterIP 10.233.13.143 <none> 80/TCP 6m33s
kubernetes
서비스는 설치부터 항상 존재한다.
/ # env | grep KUBERNETES
KUBERNETES_PORT=tcp://10.233.0.1:443
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT_443_TCP_ADDR=10.233.0.1
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.233.0.1:443
KUBERNETES_SERVICE_HOST=10.233.0.1
여기서도 비슷한 형태의 환경변수 구성을 볼 수 있다.
vagrant@k8s-node1 ~/svc kubectl create -f myweb-svc-named.yaml
service/myweb-svc-named created
vagrant@k8s-node1 ~/svc kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 8m32s
myweb-svc ClusterIP 10.233.13.143 <none> 80/TCP 8m16s
myweb-svc-named ClusterIP 10.233.21.79 <none> 80/TCP 6s
myweb-svc-named
서비스를 하나 추가하면
/ # env | grep NAMED
아무것도 출력되지 않는다.
파드가 시작되는 시점에 서비스 목록을 가지고 와서 환경변수로 세팅한다.
파드가 생성된 이후에 만들어진 것은 환경변수에 반영되지 않는다.
어플리케이션에서 서비스 이름을 미리 구성할 수 있다.
어플리케이션을 만들 때 환경변수를 미리 참조하는 것이다.
그래서 WP같은 경우 wp-config.php
에 DB 관련 세팅을 하는데 env.환경변수명
하면 값이 배치된다.
만약의 DB의 호스트명을 가져와야 하고 이때 DB의 호스트명을 ABC
라고 한다면
env.ABC_SERVICE_HOST
라고 설정해두면 나중에 env.ABC_SERVICE_HOST
변수를 읽어서 값으로 대치한다.
이로써 어플리케이션이 서비스를 디스커버리 할 수 있게 된다.
환경 변수를 이용한 SD는 서비스를 먼저 만들어놔야 한다.
그리고 어플리케이션 파드를 나중에 띄워야 그 시점에서 가지고 있는 서비스의 목록을 변수화 시킬 수 있다.
✔️ DNS를 이용한 Service Discovery
모든 Unix 시스템은 etc/resolv.conf
파일에 지정되어 있는 DNS
에게 질의한다.
/ # cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local kornet
nameserver 169.254.25.10
options ndots:5
169.254.25.10
주소를 가진 DNS에게 질의하게 되며 이것은 kube-dns이다.
vagrant@k8s-node1 ~/svc kubectl get po -n kube-system
coredns-8474476ff8-4bmms 1/1 Running 8 (79m ago) 4d5h
coredns-8474476ff8-q7svm 1/1 Running 9 (80m ago) 4d5h
정확하게는 해당 명령으로 확인할 수 있는 coredns
라는 이름의 파드이다.
이것이 DNS 서버이며 이 DNS에 질의를 하게된다.
host
명령은 DNS 서버에게 질의하는 명령어이다.
/ # host myweb-svc
myweb-svc.default.svc.cluster.local has address 10.233.13.143
호스트에게 myweb-svc
를 질의하면 ip가 출력된다.
coredns
에게 myweb-svc
서비스에 대한 DNS QUERY를 날린 것이다.
그러면 DNS 서버는 우리에게 DNS Answer를 준다.
myweb-svc
의 실제 이름은 myweb-svc.default.svc.cluster.local
이다.
이 이름을 FQDN(Fully Qualified Domain Name)
이라고 한다.
완전한 도메인 이름의 형태이며 이는 특정 시스템을 완전하게 구별할 수 있는 주소이다.
myweb-svc
- 서비스의 이름default
- Namespace, myweb-svc 서비스 오브젝트가 포함되어 있는 NSsvc
- 오브젝트 타입cluster.local
- 클러스터 내부에서만 사용하는 도메인
우리 회사의 도메인이 abc.com 이라고 해보자
이 도메인을 회사 내부에서만 사용한다면 관습적으로 local
을 붙여 abc.local
로 사용한다.
내부 서버끼리 통신할 때는 이렇게 사용한다.
kube-dns는 쿠버네티스 내에서만 Internal 하게 사용하므로 cluster.local
이 기본 도메인이다.
~/kubespray/inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yaml
160 cluster_name: cluster.local
현재 쿠버네티스 클러스터 내에서 사용하는 도메인이다.cluster_name
이 cluster.local
로 되어 있기 때문에 FQDN
에도 cluster.local
이 붙는 것이다. (변경할 수 있다.)
🔍 DNS 질의 과정
/ # host myweb-svc
myweb-svc.default.svc.cluster.local has address 10.233.13.143
/ # host myweb-svc.default
myweb-svc.default.svc.cluster.local has address 10.233.13.143
/ # host myweb-svc.default.svc
myweb-svc.default.svc.cluster.local has address 10.233.13.143
/ # host myweb-svc.default.svc.cluster.local
myweb-svc.default.svc.cluster.local has address 10.233.13.143
모두 같은 결과를 낸다.
그렇다고 무조건 같은 결과를 내는 것은 아니다.
/ # cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local kornet
nameserver 169.254.25.10
options ndots:5
/etc/resolv.conf
파일을 보면 search
라는 설정이 있다.
myweb-svc
라고 질의하면 내부적으로는 .default.svc.cluster
를 뒤에 붙여 DNS 서버에게 질의한다.응답이 돌아오지 않으면 자체적으로 .svc.cluster.local
을 붙여서 질의한다.
그래도 응답이 돌아오지 않으면 .cluster.local kornet
을 붙여서 질의한다.
최종적으로 응답이 돌아오지 않으면 그러한 도메인이 없다는 NXDOMAIN
오류를 낸다.
NXDOMAIN
- None Existent DOMAIN : 존재하지 않는 도메인
따라서 default.svc.cluster.local
svc.cluster.local
cluster.local kornet
이 순서가 질의할 순서가 된다.
이런 search domain
을 지정해놓으면 이름만 가지고 질의할 수 있다.
'DevOps > Kubernetes' 카테고리의 다른 글
[Kubernetes] Service - NodePort (1) | 2022.05.23 |
---|---|
[Kubernetes] Service - Service Discovery (2) (0) | 2022.05.21 |
[Kubernetes] Service - ClusterIP (0) | 2022.05.20 |
[Kubernetes] Service & DNS (서비스와 DNS) (0) | 2022.05.20 |
[Kubernetes] CronJob (크론잡) (0) | 2022.05.20 |
영차영차 성장 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!