잠깐!)
Pod도 IP를 갖고 있고, Node도 IP를 갖고 있다.
쿠버네티스 클러스터에 서비스를 띄운다고 하자.
그러면 이 서비스는 Pod안에 컨테이너 형태로 운영이 되게 된다.
그런데 Pod의 경우, 구조상 지우고 생성되는게 잦고, 그럴 때마다 IP 주소가 바뀌게 된다.
그러면 외부 클라이언트가 접속하기가 어려워진다.
따라서 별도로 외부에서 접속할 수 있는 IP 주소를 알려주지 않는 이상 접속이 어려워진다.
그래서 하나의 단일 진입점을 만들 필요가 있는거야. 그게 바로 서비스라는 오브젝트다.
서비스
- Kubernetes Cluster 외부에서 접근시 파드에 고정적인 접근 경로를 제공하기 위한 오브젝트
- 여러 파드에 단일 진입점을 제공하는 오브젝트
- 서비스 오브젝트에 부여된 IP 주소는 해당 서비스가 종료될 때까지 변하지 않음.
서비스 타입
- ClusterIP : Kubernetes Cluster 내부에서 접근 가능한 IP 주소를 제공하는 타입
외부에서는 ClusterIP의 IP 주소로 접근이 불가함
- NodePort : Kubernetes Cluster의 모든 노드에 동일한 포트를 개방하는 서비스 타입
(쿠버네티스 노드+Port Number 합성어)
(30000-32767 중 random or 직접 선택도 가능.)
Kubernetes Cluster 외부에서 노드의 해당 포트로 접근시 연결된 파드로 트래픽이 전달됨
NodePort는 ClusterIP를 포함함. (그래서 클러스터 내에서도 접근이 가능하다.)
만약에 Node1로 접속을 했는데, Node2에 App이 존재해. 그러면 Kube-proxy가 포워딩을 해줘서 Node1 -> Node2로 넘겨준다. 그래서 어느 노드로 접근을 해도 결국 모든 노드에 다 다다를 수 있는거야.
물론, 어느 노드에도 App이 존재하지 않으면, 괜히 컴퓨팅 리소스를 소모한게 되는건 맞다. (그럼 패킷을 폐기해야되니깐)
- LoadBalancer : 일반적으로 클라우드 서비스를 이용하는 경우 사용 가능한 네트워크 서비스 타입
(온프렘에서는 장비가 없으면 사용이 어렵다. Metallb 있기는 한데, 이건 beta version이라...)
Kubernetes Cluster 앞단에 LoadBalancer가 위치하여 부하를 분산시킴
LoadBalancer 타입은 ClusterIP와 NodePort 기능을 포함함
내 질문)
그러면 모든 기능을 포함하는 LoadBalancer를 안쓰고 굳이 NodePort를 쓰는 이유가 있나요?
-> 결론만 말하면, NodePort는 deployment를 위한 기능이 아니다!
데모, 테스트를 위한 기능이야!!!
LoadBalancer를 쓰려면 쿠버네티스 클러스터 앞단에 실제 로드밸런서 장비가 있어야 한다.
NodePort와 LoadBalancer의 가장 큰 차이는 Pod으로의 접근 방식에 있다.
Loadbalancer는 곧바로 pod에 접근을 시켜준다.
그런데 NodePort는 그게 불가능하고, 워커 노드 -> Node Port Service -> Pod으로 접근을 해야한다.
NodePort의 단점은 다음과 같다.
https://blog.leocat.kr/notes/2019/08/22/translation-kubernetes-nodeport-vs-loadbalancer-vs-ingress
ㄴ 위 글 참조.
- Headless(None) : ClusterIP가 없는 서비스 타입으로 특정 파드에 접근해야하는 경우에 사용하는 서비스 타입
type: ClusterIP
clusterIP: None
- ExternalName : Kubernetes Cluster 내부 파드가 외부의 서비스에 쉽게 접근하기 위한 서비스 타입
서비스 오브젝트 생성 방법
1. kubectl expose
kubectl expose OBJECT --type=SERVICE_TYPE --name SERVICE_NAME
2. Manifest File로 서비스 정의
서비스 실습해보자.
ClusterIP 실습
vim myapp-svc.yaml
서비스는 만들었으니까 이 서비스를 연결할 대상을 만들어보자.
vim myapp-rs.yaml
kubectl run -it network-multitool --image=devops2341/network-multitool:latest
지금, myapp-rs라는 replicasets에 nginx로 애플리케이션을 운영하고
myapp-svc라는 서비스로 cluster ip를 만든거야. 글구 app의 label로 그 둘을 연결시켜준거지.
글구 해당 pod 외부에서 새로운 pod을 띄워서 cluster ip로 nginx에 접근이 되나 확인해본거야.
결과적으로 잘 되는게 확인이 된거지.
Control Plane에서도 접근이 잘 되고, 다른 노드들에서도 마찬가지로 접근이 잘 돼.
그럼 이제 이해가 좀 가네.
이 IP 들의 의미가...
첫 번째는 node ip, 두 번째는 pod ip.
Cluster IP의 경우에는 첫 번째 아이피로는 접근 불가, 두 번째 아이피로는 접근 가능
NodePort의 경우에는 첫 번째 아이피로는 접근 가능, 두 번째 아이피로도 부분적으로 접근 가능(?)
만들어진 서비스를 자세하게 보자
즉, 이 ClusterIP로 들어온걸 Endpoints (pods)로 뿌려준다. 이거지.
(=>Service Object가 만들어질 때, Service Object에 연결되는 대상을 관리해주는 Object인 Endpoints가 같이 만들어짐.)
한번 rs를 3개로 늘려볼게.
짜잔, 늘어남!
이번엔 NodePort를 만들어보자
여기서 selector: app 이거 지정을 안해줄 수도 있어.
원래 이거 지정하면 알아서 endpoint가 만들어지거든?
근데 label 지정 안하면 안만들어지니까 endpoint를 일부러 만들어줘야돼.
확인해보면,
ClusterIP랑 다르게 외부에서 접근할 수 있는 외부 Port가 존재한다! (30000-32767)
Port는 서비스를 위한 Port
TargetPort는 Pod을 위한 Port
NodePort는 쿠버네티스 클러스터 외부에서 접근할 때 사용하는 Port (물리적인 노드에 부여된 Port)
의문)
어 먼가 살짝 이상해. NodePort가 서비스 아냐? 왜 서비스를 위한 port가 있어? 뭐랑 뭐를 연결하려고?
TargetPort는 NodePort와 Pod을 연결할 때 쓴다고 해도...
NodePort 사용시 Traffic의 흐름도 : Client -> NodePort -> Port (Service) -> targetPort(Pod)
이해했다. Node (서버)와 NodePort (서비스 오브젝트)를 연결해줄 때 필요한 Port네.
https://yoonchang.tistory.com/49
Control Plane의 IP:Node Port의 Port로 접근하면 접속이 잘 된다.
근데 쿠버네티스 클러스터 내부에서 저걸로 접근해도 접속이 잘 되네?
생각해보면 당연하다. 왜냐하면 클러스터 내부 Pod에서 노드의 IP로는 당연히 접속이 잘 될거고 안되는데?
Port는 NodePort로 열어놨으니까 당연히 접속이 잘 되겠지.
Node의 IP (192.168.56.21) : 30665번 포트 접속 가능
Pod IP (192.168.233.211) : 80번 포트 접속 가능
NodePort의 Cluster IP (10.107.178.203) : 80번 포트 접속 가능
그런데 Node의 IP : 80번 포트로 접근하면 접속이 안돼.
왜?
뇌피셜)
곰곰히 생각해봤는데 딱히 떠오르는 이유는 없고
192.168.56.21:30665 -> 그냥 이걸로 접속해야만 모든 Node들을 순회하면서 Pod을 찾는건가봐.
192.168.56.21:80은 안열어줬잖아.
근데,,, 클러스터 내부에서 접근을 해도 connection refused가 떠서 조금 헷갈리긴 해.
근데 내/외부 따지는 것도 이상한게, Node의 IP는 내/외부가 안나뉘어져있으니까... NAT도 아닌거고...
기본적으로 클러스터 내부에서 접근을 할 때는 ClusterIP를 사용하는거야.
외부에서 접근할 때 Node의 IP로 접근을 하는거지.
그러니까 기본적으로 Node의 모든 Port는 막혀있는거야.
그런데 NodePort를 이용해서 Node의 특정 Port를 열어줬으면, 그제서야 이제 통신이 가능해지는거지.
80:30665/TCP면, 일단 30665로 들어와서, 내부에 80번으로 열린 서비스가 있나 확인을 하는거야.
이거 같음!
이렇게 쿠버네티스 클러스터 외부에서도 접속이 잘 된다.
이번엔 LoadBalancer Type을 만들어보자.
근데 이상한게, curl http://192.168.56.200하면 접근이 되네???????
외부에서도 http://192.168.56.200 하면 접근되고, http://192.168.56.200:30232하면 접근이 안돼!!!!!!
뭐야 이건 또 왜 반대야!??
일단 이해는 안가지만 넘어가자. 시간이 계속 흘러감..
이제 다른거 더 보자구.
- Headless(None) : ClusterIP가 없는 서비스 타입으로 특정 파드에 접근해야하는 경우에 사용하는 서비스 타입
type: ClusterIP
clusterIP: None
clusterIP : 여러 pod들이 있을 때, 하나의 접속 IP를 제공하는거라구 했지. 그게 필요 없는거야.
특정 pod를 접근해야 하는 경우가 있어. DB 같은 경우.
왜냐하면 DB같은 경우에는, Master-Slave가 나뉘어져 있어서, Write는 무조건 Master에다가 해야돼.
안그러면 무결성이 깨질 수 있거든.
그래서 그럴 때 Master DB를 지정해주는거지.
혹은, StatefulSet의 경우는 각각의 Pod이 서로 다른 저장 공간을 갖잖아?
그럼 서로 구분이 된다는 소린데, 그럴 때도 Headless로 접근을 해야지.
그냥 ClusterIP로 하면 random으로 접근할거아냐.
쿠버네티스 클러스터가 사용하는 dns 체계를 사용해서, headless service가 가리키는 대상들을 말하는거임.
그냥 ping myapp-svc-headless.default.svc.cluster.local 해버리면 headless service와 연결된 모든 pod을 random으로 로드밸런싱 함.
그럼 얼케 pod에 직접 접근하는데?
얼케하냐면,
이렇게 하면 됨. (내가 192-168-9-125 이렇게 만든거 아님. 자동으로 그렇게 생김)
이상하다!
여기서는 pod의 name으로 접근이 안되고 ip를 dns처럼 쳐야만 접근이 됐는데
아래는 또 pod의 name으로 접근이 되네???????? 뭥미?
차이점은 이거 하나밖에 없는디?
일단 넘어가자.
https://junior-developer.tistory.com/74
ㄴ 너무너무 잘 설명된 블로그. 무조건 읽어볼 것.
headless 실습 하나 더 해보자
vim example-headless-svc.yaml
주의) 여기서 ports name이 15자가 넘어가서 ex-sts-port로 바꿈. 이상하게 15자 넘어가면 에러남.
하여튼 statefulset 만들구 headless service 만들었어.
kubectl exec -it example-sts-0 -- /bin/bash
개꿀팁)
hostname > index.html 하면 굳이 들어가서 귀찮게 내용 변경 안해줘도 돼
kubectl exec -it network-multitool -- /bin/bash (쿠버네티스에서 pod 들어갈 때는 -- 쳐야됨!)
이런식으로 접근이 가능해짐.
내 질문)
조금 헷갈리는데, 그럼 클러스터 외부의 사용자가 특정 pod에 접근하는게 불가능한가요? NodePort를 사용하면 ClusterIP가 자동으로 생성되니까요. 아니면 제가 오개념을 갖고 있는건가요?
답변)
일단 유저는 특별한 경우가 아니면 특정 pod에 찾아갈 일이 없다.
예를 들어, web서버를 운영한다고 할 때, 사용자는 이 중 하나에만 접속되면 된다.
Webapp pod과 여러 개의 DB pod이 있다구 하자.
(DB master, DB slave)
근데, webapp이 read를 할 시점에는 어느 db에 접근해도 상관 없지만,
webapp이 write를 할 시점에는 db master에 접근할 필요가 있어.
만약 외부에서 특정 pod을 접근해야 한다고 하면?
session affinity를 이용해서, 영구적으로 접근이 되는건 아니고, 접근하는 시점-그 주변-그 시기에만
특정한 pod쪽으로 연결해주는 그런 기능이 있대.
근데 내가 생각하는 것처럼 외부에서 특정 pod으로 계속 연결해주고 이런게 아니고
Session 관련해서 잠깐 열어주는 그런 느낌인가봐. 아예 용도가 다른듯.
Headless Service는 외부에서 접근하는 용도가 아니다.
pod들이 생성/삭제가 빈번해서 ip가 자꾸 바뀌니까, pod의 ip가 아니라
pod의 name으로 접근하고자 하는 것이다.
아까 위에서 설치한 network multitool는 nettools, iputils, 이런거 몇가지 설치한거임.
(nicolaka/netshoot도 비슷한거임)
근데 갑자기 든 생각인데
이렇게 서로 다른 서비스들이 동일한 replicaset을 가리키면 얼케 되는거임?????? 뭐임
- ExternalName : Kubernetes Cluster 내부 파드가 외부의 서비스에 쉽게 접근하기 위한 서비스 타입
쿠버네티스는 내부에 dns 서버가 있어. 그래서 내부 dns 서버 이용해서 외부 서비스에 접근하고자 할 때 사용.
(정확하게 말하면 kube dns의 구현체가 core dns로 사용되고 있대 (?먼솔?ㅋ))
core dns가 pod나 서비스 오브젝트의 ip주소에 대한 도메인 주소를 자동으로 만들어서 제공해준대.
왜냐하면 pod의 ip는 계속해서 변동하니까 dns주소가 있어야되잖아.
근데 이 기능을 이용해서 쿠버네티스 내부가 아니라 외부를 가리키도록 한 서비스 타입임.
CNAME record랑 비슷한 역할 하는거지 뭐.
vim externalname-svc.yaml
external-app1의 ip 보면 www.naver.com이야.
kube-proxy : 네트워크 관리해주는 넘
3가지 모드 있음
1. userspace 모드 : kube-proxy가 직접 클라이언트의 traffic을 받아서 pod에 연결해줌
2. iptables 모드 : kube-proxy가 iptables 관리하는 역할만 함 (리눅스에 기본적으로 있는 방화벽)
3. IPVS(IP Virtual Server) 모드 : 로드 밸런싱 (리눅스 커널에 있는 L4 로드밸런싱 기술)
------
인그레스 (L7 로드밸런서. http/https 프로토콜에 대해 최적화 되어있음)
Kubernetes Cluster 외부에서 내부로 접근하는 요청을 어떻게 처리할지 정의한 규칙의 모임
인그레스를 사용하기 위해서는 반드시 인그레스 컨트롤러(Ingress Controller)가 필요함
이게 왜 필요해?
서비스가 많아지다보면 NodePort로 해당 포트를 열어야 되는데, 많아질수록 관리가 어려워진대.
Request에 대해 Routing을 해주는 오브젝트인가봐.
온프렘 쿠버네티스에서는 인그레스 컨트롤러를 직접 인그레스와 연동해야 된대.
이때 쿠버네티스에서 제공하는 ingress-nginx를 제일 많이 사용한대.
"버전에 따른 문제가 있을 수 있다. 호환성이 좀 잘 안맞는듯."
https://github.com/kubernetes/ingress-nginx
-----
인그레스 컨트롤러(ingress-nginx-controller) 설치
Ingress nginx Controller 설치(Manifest 파일)
kubectl create -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.47.0/deploy/static/provider/baremetal/deploy.yaml
Ingress nginx Controller Pods 확인
kubectl get pods -n ingress-nginx
Ingress nginx Controller 서비스 확인
kubectl get services -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.107.238.230 <none> 80:32301/TCP,443:30742/TCP 3m7s
ingress-nginx-controller-admission ClusterIP 10.102.251.80 <none> 443/TCP 3m7s
* 현재 ingress-nginx-controller 서비스가 External IP가 설정되어있지 않음.
-> External IP를 node들의 IP로 넣어줄거야.
Ingress nginx Controller 서비스 오브젝트 편집
kubectl edit services ingress-nginx-controller -n ingress-nginx
====
...
21 spec:
22 clusterIP: X.X.X.X
23 externalIPs:
24 - 192.168.56.21
25 - 192.168.56.22
26 - 192.168.56.23
27 externalTrafficPolicy: Cluster
...
====
Ingress nginx Controller 서비스 다시 확인
kubectl get services -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.107.238.230 192.168.56.21,192.168.56.22,192.168.56.23 80:32301/TCP,443:30742/TCP 23m
ingress-nginx-controller-admission ClusterIP 10.102.251.80 <none> 443/TCP 23m
* ingress-nginx-controller 서비스에 External IP가 추가된 것을 확인할 수 있음.
------
vim ingress-basic.yaml
저렇게 두 덩어리rule)가 있는거야.
foo.bar.com/foos1로 접근하는 애는 서비스 s1로 넘겨주고 그럼 얘가 어떤 pod으로 넘길 것. (??)
nodePort 이런거 말하는건가? ㅋㅋ
접속하고자 하는 주소, 애플리케이션에 해당 리소스가 있는지 조합해서 어디로 연결해줄지 결정 가능
애플리케이션 데이터를 까봐야 되는 것임.
실습을 한번 해보자
sudo vim /etc/hosts (root 권한 없이는 저장이 안됨)
그럼 replicasets랑 services를 한번 만들어보쟤. 실습하쟤
cp myapp-rs.yaml web1-rs.yaml 기존꺼 그대루 쓰자구. 헷갈리니까 새로 만들장.
이름만 위 처럼 바꿔줘..
kubectl create -f web1-rs.yaml
글구 web2-rs.yaml도 하나 더 만들어줘.
vim web1-svc1.yaml
web2-svc2.yaml도 하나 더 만들어주고 둘 다 create -f로 생성
ㄴ 아파치 설명 너무 길고 누구 웹서버껀지 구분도 안가니까 아래처럼 다 수정해주자.
로드밸런싱이 되고 있는걸 확인할 수 있다.
이제 ingress로 접근해보자
foo.bar.com/foos1 -> s1:80 (192.168.233.225:80, 192.168.9.68:80)
foo.bar.com/foos2 -> s2:80 (192.168.119.138:80, 192.168.233.226:80)
bar.foo.com -> s2:80 (192.168.119.138:80, 192.168.233.226:80)
질문) 저 포트번호는 ingress에 있는 nodePort의 포트 번호인가요?
31242 이 포트는 ingress-nginx-controller의 NodePort야.
질문)
강사님 그럼 생성 순서가 Replicaset -> Service -> Ingress Object 인가요?
맞다. 왜냐하면 순서 바뀌면 에러 나는 경우가 있다.
'System Engineering > Kubernetes' 카테고리의 다른 글
CKA 취득 목표 (0) | 2022.04.07 |
---|---|
[쫌 어려움] 쿠버네티스 네트워크를 이해해보자 (0) | 2022.04.06 |
kubernetes 7/17 (0) | 2022.04.01 |
쿠버네티스 잘 정리된 블로그 (subicura) (0) | 2022.03.31 |
kubernetes 6/17 (0) | 2022.03.29 |
최근댓글