잠깐!)

Pod도 IP를 갖고 있고, Node도 IP를 갖고 있다.

Node의 IP 주소, Pod의 IP 주소. Pod은 Node와 다른 IP 대역을 갖는다.

쿠버네티스 클러스터에 서비스를 띄운다고 하자.

그러면 이 서비스는 Pod안에 컨테이너 형태로 운영이 되게 된다.

그런데 Pod의 경우, 구조상 지우고 생성되는게 잦고, 그럴 때마다 IP 주소가 바뀌게 된다.

그러면 외부 클라이언트가 접속하기가 어려워진다.

따라서 별도로 외부에서 접속할 수 있는 IP 주소를 알려주지 않는 이상 접속이 어려워진다.

그래서 하나의 단일 진입점을 만들 필요가 있는거야. 그게 바로 서비스라는 오브젝트다.

 

서비스
 - Kubernetes Cluster 외부에서 접근시 파드에 고정적인 접근 경로를 제공하기 위한 오브젝트
 - 여러 파드에 단일 진입점을 제공하는 오브젝트
 - 서비스 오브젝트에 부여된 IP 주소는 해당 서비스가 종료될 때까지 변하지 않음.

서비스 타입
 - ClusterIP : Kubernetes Cluster 내부에서 접근 가능한 IP 주소를 제공하는 타입
                 외부에서는 ClusterIP의 IP 주소로 접근이 불가함

 

pod들이 IP를 하나씩 갖고는 있지만, 언제 변동될지 모르니까, 변동되지 않는 IP를 부여하는거야. 쿠버네티스 클러스터 안에서는 ClusterIP로 접근할 수 있어.


 - NodePort : Kubernetes Cluster의 모든 노드에 동일한 포트를 개방하는 서비스 타입

(쿠버네티스 노드+Port Number 합성어)

(30000-32767 중 random or 직접 선택도 가능.)
                  Kubernetes Cluster 외부에서 노드의 해당 포트로 접근시 연결된 파드로 트래픽이 전달됨
                  NodePort는 ClusterIP를 포함함. (그래서 클러스터 내에서도 접근이 가능하다.)

 

어느 노드의 ip주소로 접근을 하든, 클러스터 내부로 접근이 가능하다.

만약에 Node1로 접속을 했는데, Node2에 App이 존재해. 그러면 Kube-proxy가 포워딩을 해줘서 Node1 -> Node2로 넘겨준다. 그래서 어느 노드로 접근을 해도 결국 모든 노드에 다 다다를 수 있는거야.

물론, 어느 노드에도 App이 존재하지 않으면, 괜히 컴퓨팅 리소스를 소모한게 되는건 맞다. (그럼 패킷을 폐기해야되니깐)

 

 - LoadBalancer : 일반적으로 클라우드 서비스를 이용하는 경우 사용 가능한 네트워크 서비스 타입

(온프렘에서는 장비가 없으면 사용이 어렵다. Metallb 있기는 한데, 이건 beta version이라...)

                        Kubernetes Cluster 앞단에 LoadBalancer가 위치하여 부하를 분산시킴
                        LoadBalancer 타입은 ClusterIP와 NodePort 기능을 포함함

 

2022/04/03 기준

 

 

내 질문)

그러면 모든 기능을 포함하는 LoadBalancer를 안쓰고 굳이 NodePort를 쓰는 이유가 있나요?

-> 결론만 말하면, NodePort는 deployment를 위한 기능이 아니다!

데모, 테스트를 위한 기능이야!!!

 

LoadBalancer를 쓰려면 쿠버네티스 클러스터 앞단에 실제 로드밸런서 장비가 있어야 한다.

 

NodePort와 LoadBalancer의 가장 큰 차이는 Pod으로의 접근 방식에 있다.

Loadbalancer는 곧바로 pod에 접근을 시켜준다.

그런데 NodePort는 그게 불가능하고, 워커 노드 -> Node Port Service -> Pod으로 접근을 해야한다.

https://blog.leocat.kr/notes/2019/08/22/translation-kubernetes-nodeport-vs-loadbalancer-vs-ingress 근데 기술적으로 아주 정확한 그림은 아니라네.

 

NodePort의 단점은 다음과 같다.

NodePort는 Node의 IP를 노출해야 하는데, Loadbalancer는 LB의 IP만 노출하면 되니, LB 사용 시에 상대적으로 보안성도 강화가 된다.

https://blog.leocat.kr/notes/2019/08/22/translation-kubernetes-nodeport-vs-loadbalancer-vs-ingress

 

[발번역] Kubernetes NodePort vs LoadBalancer vs Ingress?? 언제 무엇을 써야 할까??

본 글은 아래 글을 발번역 한 내용입니다. 누락되거나 잘못 옮겨진 내용이 있을(아니 많을;;) 수 있습니다. 어색하거나 잘못된 표현은 알려주세요. 원글: Kubernetes NodePort vs LoadBalancer vs Ingress? When s

blog.leocat.kr

ㄴ 위 글 참조.

 

NodePort

 

LoadBalancer

 

 

MetalLB로 LoadBalancer 구현

 


 - 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로 서비스 정의

 

서비스 실습해보자.

 

기본적으로 서비스는 kubernetes만 있다.

ClusterIP 실습

 

vim myapp-svc.yaml

여긴 matchLabels 없어도 되나?

서비스는 만들었으니까 이 서비스를 연결할 대상을 만들어보자.

 

vim myapp-rs.yaml

rs 만들어졌다.
이번엔 서비스 만들었다.

 

새롭게 만들어진 Cluster-IP는 Pod내에서 사용 가능 / Control Plane에서도 사용 가능 / 다른 노드에서도 사용 가능

 

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에서도 접근이 잘 되고, 다른 노드들에서도 마찬가지로 접근이 잘 돼.

 

당연히 굳이 cluster ip를 안거치고 pod으로 직접 접근하는 것도 접근 잘 돼.

 

그럼 이제 이해가 좀 가네.

이 IP 들의 의미가...

첫 번째는 node ip, 두 번째는 pod ip. 

Cluster IP의 경우에는 첫 번째 아이피로는 접근 불가, 두 번째 아이피로는 접근 가능

NodePort의 경우에는 첫 번째 아이피로는 접근 가능, 두 번째 아이피로도 부분적으로 접근 가능(?)

 

만들어진 서비스를 자세하게 보자

여기서 Endpoints가 뭐냐하면, Pod의 주소야. ㅋㅋㅋㅋ 위랑 확인해봐. 192.168.233.221 똑같잖아.

 

즉, 이 ClusterIP로 들어온걸 Endpoints (pods)로 뿌려준다. 이거지.

(=>Service Object가 만들어질 때, Service Object에 연결되는 대상을 관리해주는 Object인 Endpoints가 같이 만들어짐.)

 

서비스 오브젝트가 만들어질 때, endpoints가 같이 만들어져서 pod이랑 연결해줌
봐봐. endpoint도 object야. 그리고 보이는 addresses들이 myapp-svc에 연결된 개별 pod의 address인거지. 그래서 pod이 늘어나면 저 주소의 ip도 늘어나게 되는거야.

한번 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

 

[Kubernetes] 6. 쿠버네티스 Service란? (NodePort, nginx 실습)

[주의] 개인 공부를 위해 쓴 글이기 때문에 주관적인 내용은 물론, 쓰여진 정보가 틀린 것일 수도 있습니다! 피드백 부탁드립니다. (- -)(_ _) 꾸벅 [ Service ]  위 그림을 보면, 10.10.10.2의 내부 아이

yoonchang.tistory.com

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을 만들어보자.

appVersion 오타 ㅋㅋ

 

 

원래 EXTERNAL-IP에 none 나오는게 맞는데, 전에 metallb 설치해가지고 외부 아이피 잡힘 ㅋㅋ

 

invalid 왜 생겼는지 모르겠네?

근데 이상한게, 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를 제공하는거라구 했지. 그게 필요 없는거야.

이게 clusterIP

특정 pod를 접근해야 하는 경우가 있어. DB 같은 경우.

이게 headless

왜냐하면 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

 

[k8s] 24. Service - Headless, Endpoint, ExternalName

Service에 대해 자세히 알아보자 우선 이전에 배운 내용을 복습 내부망에서 접속 공유기를 통해서 시작하는 아이피에서 내부망이 형성 세 대의 서버를 이용해서 Master와 Node로 쿠버네티스 클러스

junior-developer.tistory.com

ㄴ 너무너무 잘 설명된 블로그. 무조건 읽어볼 것.

 

 

headless 실습 하나 더 해보자

vim example-headless-svc.yaml

 

StatefulSet 만들었어. Headless랑 같이 쓰인대 보통. 논리적으로 구분되는 각각 pod에 접근할 필요가 있으니깐

주의) 여기서 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

 

admission 2개는 completed, ingress-nginx-controller는 running인 상태가 정상 상태다.
ingress-nginx라는 namespace가 따로 생기네. 왜 그런진 몰겠슴..
EXTERNAL-IP가 없자나.



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 

External-IP 추가되었다. 이거 안하면 Ingress object 설치 되어도 정상 작동 안해.


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

apiVersion에서 최신 버전은 networking.k8s.io/v1인데, 우리는 옛날 버전 써가지구 저거 호환됨. 요즘에 저거 쓰면 deprecated 된다구 경고뜬대.

저렇게 두 덩어리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

nodePort 중복되면 안되니까 바꿔줘야댐.

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)

이렇게 하면 connection refused 나와. 왜?
80:31242, 443:32712로 매칭되어있거든.

 

 

roundrobin으로 loadbalancing함.

질문) 저 포트번호는 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
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기