( 참고 : [교재] 핵심만 콕! 쿠버네티스 )
쿠버네티스 네트워킹
Service 리소스 = 쿠버네티스의 네트워크 담당
- Pod와 마찬가지로 YAML 형식으로 정의
- Pod IP와는 다른 “독자적인 IP” 부여 받아 서비스의 Endpoint 제공
- 라벨링 시스템으로 Pod로 트래픽 전달
1. Service 소개
Pod 자체에도 IP가 있는데…굳이 왜 Service 통해서?
kubectl run mynginx --image nginx
kubectl get pod -o wide
# ....... 10.42.0.26
# 이렇게 접속해도 되는데...굳이?
kubectl exec mynginx -- curl -s 10.42.0.26
1-1. 불안정한 Pod vs 안정적인 Service
Pod = 불안정한 자원
-
쉽게 생성 가능 & 사용 끝나면 쉽게 삭제
-
무슨 이유로든, 종료될 수 있는 리소스로 생각
( = 불안정한 Endpoint 제공 )
-
Pod의 IP로 서비스 호출하면…..계속해서 바뀐 IP 추적해야!
\(\rightarrow\) 따라서, 안정적인 서비스 endpoint를 제공하는 “Service”
Service 리소스 덕분에, 사용자는 계속 동일한 IP로 접근 가능!
1-2. 서비스 탐색 (Service Discovery)
안정적인 IP제공 뿐만 아니라, “서비스 탐색 기능”도 제공
\(\rightarrow\) “이름을 기반으로 DNS 참조 가능”
- ex) myservice라는 Service 리소스 생성하면, 사용자는 myservice라는 도메인 주소로 요청 가능!
1-3. Service 첫 만남
Service 리소스 생성하기 : myservice.yaml
# myservice.yaml
apiVersion: v1
kind: Service
metadata:
labels:
hello: world
name: myservice
spec:
ports:
- port: 8080
protocol: TCP
targetPort: 80
selector:
run: mynginx
kind
: Service 리소스 선언metadata
labels
: 라벨 부여name
: 이름 지정 ( 도메인 주소로 활용 )
spec
ports
: service의 포트들 관련 정보port
: 포트 지정protocol
: 프로토콜 지정 ( ex. TCP, UDP, HTTP )targetPort
: 트래픽을 전달할 컨테이너 포트 지정
selector
: 트래픽을 전달할 컨테이너의 라벨- 여기서는 mynginx라벨을 가짐
라벨 셀렉터를 사용하여 Pod 선택하는 이유
이유 : Loosely Coupled (느슨한 연결)
-
Pod IP = STRICT
- 특정 리소스를 직접 참조
-
Label Selector = LOOSE
-
특정 리소스를 간접 참조
-
매번 새로운 Pod 정보를, Service에 등록/삭제할 필요가 없음
( just 라벨 달기만하면 끝! )
-
Service 리소스 생성, 조회, Pod IP 확인
kubectl apply -f myservice.yaml
kubectl get service # svc
# NAME, TYPE, CLUSTER-IP, EXTERNEL-IP, PORT(S), AGE
# myservice의 ip는 10.43.152.73:8080
kubectl get pod -o wide
# mynginx pod의 ip는 10.42.0.226
-
myservice의 Service IP를 확인해보면,
mynginx Pod IP와 다른 고유의 IP를 가진 것을 알 수 있음
curl 요청할 client pod 생성 후, 3가지 방식으로 트래픽 전달하기
# client Pod 생성
kubectl run client --image nginx
# 방법 1) Pod IP 통해
kubectl exec client -- curl 10.42.0.226
# 방법 2) Service IP 통해
kubectl exec client -- curl 10.43.152.73:8080
# 방법 3) Service 이름 통해
kubectl exec client -- curl myservice:8080
myservice라는 이름을 가진 서비스의 IP주소를 확인하기 위해서는?
( 이미 10.43.152.73인걸 알지만, 모른다고 했을 때 )
# nslookup 명령 설치
kubectl exec client -- sh -c "apt update && apt install -y dnsutils"
# myservice의 DNS 조회
kubectl exec client -- nslookup myservice
- service의 이름이 도메인 주소의 역할을 한다
- DNS의 이름 :
- 단순히 myservice (X)
myservice.default.svc.cluster.local
1-4. Service 도메인 주소 법칙
법칙 : <서비스 이름>.<네임스페이스>.svc.cluster.local
# 1) Service의 "전체" 도메인 주소 조회
kubectl exec client -- nslookup myservice.default.svc.cluster.local
# 2) Service의 "일부" 도메인 주소 조회
kubectl exec client -- nslookup myservice.default
# 3) Service츼 이름으로 조회
kubectl exec client -- nslookup myservice
1-5. 클러스터 DNS 서버
위처럼, “도메인 주소” 사용 가능한 이유는?
\(\rightarrow\) 쿠버네티스에서 제공하는 “DNS 서버” 덕분에
( 확인 in /etc/resolv/conf
파일 )
kubectl exec client -- cat /etc/resolv.conf
# nameserver 10.43.0.10
- 쿠버네티스의 모든 Pod는 이 “10.43.0.10” IP를 통해 DNS를 조회 한다
해당 IP의 주인은? ( kube-system
에서 확인)
kubectl get svc -n kube-system
# NAME TYPE CLUSTER-IP EXTERNEL-IP PORT(S)
# kube-dns ClusterIP 10.43.0.10 <none> ...
- 주인은 바로 “kube-dns”
어떠한 pod들이 매핑되는지?
kubectl get pod -n kube-system -l k8s-app=kube-cns
# NAME READY STATUS RESTARTS AGE
# coredns-6c6bb68 1/1 Running 0 46h
-
coredns-xxx라는 pod가 조회됨
\(\rightarrow\) 클러스터 DNS 서버
-
모든 Pod들은, 내/외부 DNS질의를 바로 이 “coredns”를 통해 수행함!
( = 쿠버네티스의 자체적인 DNS 시스템 )
2. Service의 종류
4종류
- 1) ClusterIP
- 2) NodePort
- 3) LoadBalancer
- 4) ExternalName
2-1. ClusterIP
간단 소개
- 가장 기본이 되는 타입 ( default 값 )
- cluster “내부”에서만 접근 가능
(외부에서 접근 못하는) ClusterIP가 필요한 이유?
- 1) 네트워크 보안 및 관리
- 2) 더 확장된 쿠버네티스 네트워킹을 위한 기본 빌딩 블록
ClusterIP 타입의 Service 생성하는 파일 ( cluster-ip.yaml
)
- ( + 이에 대응하는 Pod도 생성)
# cluster-ip.yaml
apiVersion: v1
kind: Service
metadata:
name: cluster-ip
spec:
# type: ClusterIP # 생략가능 (default)
ports:
- port: 8080
protocol: TCP
targetPort: 80
selector:
run: cluster-ip
---
apiVersion: v1
kind: Pod
metadata:
labels:
run: cluster-ip
name: cluster-ip
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
kubectl run cluster-ip --image nginx --expose --port 80 \
--dry-run=client -o yaml > cluster-ip.yaml
pod & service 생성한 뒤, 조회
# pod & service 둘 다 생성됨
kubectl apply -f cluster-ip.yaml
# 조회
kubectl get svc cluster-ip -o yaml | grep type
# type : ClusterIP
# (clusterIP 타입의) Service를 통해 접속
kubectl exec client -- curl -s cluster-ip
2-2. NodePort
- ClusterIP : 외부 X
- NodePort : 외부 O
localhost의 특정 포트를 service의 특정포트와 연결시켜서, “외부 트래픽을 service까지 전달”
# node-port.yaml
apiVersion: v1
kind: Service
metadata:
name: node-port
spec:
type: NodePort
ports:
- port: 8080
protocol: TCP
targetPort: 80
nodePort: 30080
selector:
run: node-port
---
apiVersion: v1
kind: Pod
metadata:
labels:
run: node-port
name: node-port
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
type
: Service의 타입을 지정nodePort
: 호스트 서버(노드)에서 사용할 포트 번호- 범위 : 30000~32767
kubectl apply -f node-port.yaml
kubectl get svc
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# node-port NodePort 10.43.94.27 <none> 8080:30080/TCP 42h
- Port 매핑
- service port : 8080
- node port : 30080
마스터, 워커 node 모두가 “동일한 NodePort”로 서비스에 접근
kubectl get pod node-port -o wide
MASTER_IP = $$(kubectl get node master -o jsonpath="{.status.addresses[0].address}")
WORKER_IP = $$(kubectl get node worker -o jsonpath="{.status.addresses[0].address}")
# 접속 with MASTER
curl $$MASTER_IP:30080
# 접속 with NODE
curl $$WORKER_IP:30080
2-3. LoadBalancer
- NodePort : 외부 O
- LoadBalancer : 외부 O
각 node로 트래픽을 분산
public cloud (AWS,GCP,Azure 등) 플랫폼에서 제공하는 로드밸런서를 service 리소스에 연결할 수 있음
( 일반적으로, cloud 플랫폼에서 제공하는 경우에 사용 )
but, NodePort 말고 LoadBalancer를 쓰는 이유는?
-
1) 보안적인 측면
- 노드포트 대역 (30000~32767)을 외부에 노출할 필요 X
-
2) 로드밸런서가 cluster 앞단에 존재하면, 사용자가 각각의 서버 IP를 직접 알 필요 X
( 로드밸런서의 IP or 도메인주소 만으로도 요청 가능 )
ClusterIP : “Pod” 레벨에서의 안정적인 서비스 endpoint 제공
Loadbalancer : “Node” 레벨에서의 안정적인 서비스 endpoint 제공
LoadBalancer 생성 & 조회
kubectl apply -f load-bal.yaml
kubectl get svc load-bal
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
# load-bal LoadBalancer 10.43.230.45 10.0.1.1 8080:30088/TCP
- 기존과는 다르게, ‘EXTERNAL-IP’에 IP가 생성된 것을 확인 가능
- 각 cloud 플랫폼에서 제공하는 LoadBalancer의 IP & DNS 확인 가능
Loadbalancer의 endpoint에 연결
- 로드밸런서 IP + 서비스 port
curl 10.0.1.1:8080
2-4. ExternalName
외부 DNS 주소에 (클러스터 내부에서 사용 할)”별칭” 부여
- ex) ‘google-svc’라는 별칭으로 google.com 연결
external.yaml
# external.yaml
apiVersion: v1
kind: Service
metadata:
name: google-svc # 별칭
spec:
type: ExternalName
externalName: google.com # 외부 DNS
ExternalName 리소스 생성 및 조회
kubectl apply -f external.yaml
kubectl run call-google --image curlimages/culr \ -- curl -s -H "Host:google.com" google-svc
kubectl logs call-google
언제사용?
- cluster에 편입되지 않는 “외부 서비스”에 쿠버네티스 네트워킹 기능을 연결하고 싶은 경우
3. 네트워크 모델
쿠버네티스 : “NAT를 통한 네트워킹 싫어함”
NAT 통신을 이용한 container간 통신?
\(\rightarrow\) 모든 container이 동일한 IP & 포트로만 구분
\(\rightarrow\) 포트 충돌 가능성! 클러스터 관리자의 중재가 필요
이를 극복하기 위해,
container의 네트워크 환경을 node 레벨의 네트워크 환경과 분리하여 고립도를 높임