EndPoint를 통해 서비스 포트 : 80 ➜ 타겟 포트 : 8080 연결
기본 서비스 LB 방법 ➜ Round Robin
보통은 위 그림과 같이 Memcahed/Rredis 등의 In memory DB
(VM의 메모리를 통합 관리하는 메모리 에 인증 정보 저장
네트워크 당 세션 고정
ClientIP / None 선택 가능
Client IP
➜ IP에 따라 세션 고정
🎈 Cluster IP - Sesseion Affinity 실습
myweb-rs-ses.yaml
백앤드 RS 구성 yaml 파일
apiVersion: apps/v1
kind: ReplicaSet ✔️
metadata:
name: myweb-rs-ses
spec:
replicas: 3
selector:
matchLabels:
app: web
env: dev
template:
metadata:
labels:
app: web
env: dev
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb
ports:
- containerPort: 8080
protocol: TCP
myweb-svc-ses.yaml
Sesseion Affinity 서비스 구성 yaml 파일
apiVersion: v1
kind: Service ✔️
metadata:
name: myweb-svc-ses
spec:
type: ClusterIP ✔️
sessionAffinity: ClientIP ✔️
selector: # 파드 셀렉터
app: web
ports:
- port: 80 # 서비스 포트
targetPort: 8080 # 타겟(파드) 포트
생성 된 서비스, 엔드포인트, 레플리카셋, 파드 확인
$ kubectl get svc,ep,rs,pod
# 서비스
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 2d19h
# 엔드포인트
NAME ENDPOINTS AGE
endpoints/kubernetes 192.168.100.110:6443 2d19h
# 레플리카셋
NAME DESIRED CURRENT READY AGE
replicaset.apps/myweb-rs 3 3 3 46s
# 파드
NAME READY STATUS RESTARTS AGE
pod/myweb-rs-dlwsv 1/1 Running 0 47s
pod/myweb-rs-n2clt 1/1 Running 0 47s
pod/myweb-rs-twdgr 1/1 Running 0 47s
pod/nettool 1/1 Running 3 18h
세션 고정 확인을 위한 웹 서버 파드(nettool) 생성
$ kubectl run nettool -it --image ghcr.io/c1t1d0s7/network-multitool --rm
--rm
옵션 : 파드 사용이 끝나면 자동으로 파드 삭제 (파드에서 exit 시 삭제)
세션 고정 확인
# curl 10.233.0.1 # 서비스 리소스의 Cluster IP
포트에 이름을 정해줄 수 있음
서비스의 타겟 포트에 RS의 포트 이름(named 포트) 작성하여 이름 참조
가능
➜ 보통 앱 + 포트번호로 구성
myweb-rs-named.yaml
Named Port RS 구현 yaml 파일
apiVersion: apps/v1
kind: ReplicaSet ✔️
metadata:
name: myweb-rs-named
spec:
replicas: 3
selector:
matchLabels:
app: web
env: dev
template:
metadata:
labels:
app: web
env: dev
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb
ports:
- containerPort: 8080
protocol: TCP
name: web8080 ✔️
myweb-svc-named
Named Port 서비스 구현 yaml 파일
apiVersion: v1
kind: Service ✔️
metadata:
name: myweb-svc-named
spec:
type: ClusterIP ✔️
selector:
app: web
ports:
- port: 80
targetPort: web8080 ✔️
어플리케이션이 포트 여러 개
사용
ex. 웹 서비스
myweb-rs-multi.yaml
Multi Port RS 구성 yaml 파일
apiVersion: apps/v1
kind: ReplicaSet ✔️
metadata:
name: myweb-rs-multi
spec:
replicas: 3
selector:
matchLabels:
app: web
env: dev
template:
metadata:
labels:
app: web
env: dev
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb
ports:
- containerPort: 8080 ✔️
protocol: TCP
- containerPort: 8443 ✔️
protocol: TCP
myweb-svc-multi.yaml
Multi Port RS 구성 yaml 파일
멀티 포트일 경우 이름을 부여하여 연결
apiVersion: v1
kind: Service ✔️
metadata:
name: myweb-svc-multi
spec:
type: ClusterIP ✔️
selector:
app: web
ports:
- port: 80
targetPort: 8080
name: http ✔️
- port: 443
targetPort: 8443
name: https ✔️
쿠버네티스에서 쓰는 네트워크 개념의 서비스 x
파드
는 랜덤한 IP
를 가지며 여러 개의 서비스에 연결 가능
LB (Cluster IP)를 통해 유일한 진입 통로 생성
서비스
도 랜덤한 IP
를 부여 받음
애플리케이션은 이름
을 통해 서비스를 할 파드 찾음
🎈 서비스 디스커버리 실습
$ kubectl create -f myweb-rs.yaml -f myweb-svc.yaml
k8s는 파드 생성 순간 존재하는 각 서비스들을 가리키는 환경 변수 세팅
➜ 환경 변수를 통해 서비스의 IP 주소와 포트 번호 확인 가능
파드 생성 이후 서비스 생성 시 환경 변수가 설정되지 않아 서비스 디스커버리 불가능
웹 서버 파드 생성
$ kubectl run nettool -it --image ghcr.io/c1t1d0s7/network-multitool --rm
전체 환경 변수(env) 확인
/ # env
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.233.0.1:443
MYWEB_SVC_PORT_80_TCP_PORT=80
MYWEB_SVC_PORT_80_TCP_PROTO=tcp
HOSTNAME=nettool
SHLVL=1
HOME=/root
MYWEB_SVC_PORT_80_TCP=tcp://10.233.0.228: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.0.228
MYWEB_SVC_SERVICE_PORT=80
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.233.0.1:443
MYWEB_SVC_PORT=tcp://10.233.0.228:80
KUBERNETES_SERVICE_HOST=10.233.0.1
PWD=/
MYWEB_SVC_PORT_80_TCP_ADDR=10.233.0.228
웹서버 파드 관련 서비스 환경 변수(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.0.228:80
MYWEB_SVC_SERVICE_HOST=10.233.0.228
MYWEB_SVC_SERVICE_PORT=80
MYWEB_SVC_PORT=tcp://10.233.0.228:80
MYWEB_SVC_PORT_80_TCP_ADDR=10.233.0.228
모든 파드는 실행 시 현재 시점의 서비스 목록을 환경변수로 제공
파드를 띄우는(시작되는) 시점
에 현재 존재하는 서비스의 정보가 환경변수 형태로 반영
시작 이후에 생성 된 정보는 환경 변수에 반영 x
➜ etcd에서 해당 정보를 읽어서 셋팅
svc.spec.ports.port
정보를 읽어서 셋팅svc.spec.ports.protocol
읽어서 셋팅➜ 현재 하나의 서비스가 총 7개의 형식으로 구성
ex. Wordpress의 경우
wp-config.php 에 DB 관련 설정 할 때, env.환경변수명
을 추가하면 실제 그 값으로 대체
➜ 만약 DB의 호스트명을 가져와야한다면 env.###_SERVICE_HOST
등으로 작성
(더 많이 사용하는 방법)
DNS 서비스는 나중에 서비스가 추가되더라도 해당 서비스 정보가 coredns에게 자동으로 생성되기 때문에 나중에 추가 된 서비스에 대해서도 질의 가능
🎈 kube-dns 서버 정보 확인
/ # cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local ✔️
nameserver 169.254.25.10 ✔️ # kube-dns (coredns)
options ndots:5
search
도메인 : 질의할 순서
options ndots:5
== 우리가 질문할 도메인에 .이 5개 있어야하다는 의미🎈 서비스의 DNS 주소 질의
host [서비스 이름]
/ # host myweb-svc # DNS Query (질의)
myweb-svc.default.svc.cluster.local has address ✔️ 10.233.0.228 # DNS Answer(응답)
myweb-svc.default.svc.cluster.local == FQDN
(Fully Qualified Domain Name)
➜ 실제 DNS 이름
(도메인 전체 이름을 표기)
FQDN 구조
[서비스 이름].[서비스 오브젝트가 포함된 네임스페이스].[오브젝트 타입].[도메인(cluster.local)]
cluster.local
➜ 쿠버네티스 내부
에서만 사용하는 기본 도메인
➕ 회사 내부 서버에서만 사용하는 도메인에는 관습적으로 xxx.local을 붙이는 것과 비슷한 개념
서비스를 생성하면 자동으로 FQDN을 DNS 서버에 등록
해당 FQDN을 가지고 DNS 서버에 질의
➕ myweb-svc에 대해 자세하게 질의 🌟
-v ➜ 자세한 정보 출력 옵션 / ;; ➜ 주석 / ; ➜ 의미 존재하는 문장
/ # host -v myweb-svc
Trying "myweb-svc.default.svc.cluster.local"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28505
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;myweb-svc.default.svc.cluster.local. IN A
;; ANSWER SECTION:
myweb-svc.default.svc.cluster.local. 5 IN A 10.233.0.228
Received 104 bytes from 169.254.25.10#53 in 0 ms
Trying "myweb-svc.default.svc.cluster.local"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32324
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; QUESTION SECTION:
;myweb-svc.default.svc.cluster.local. IN AAAA
;; AUTHORITY SECTION:
cluster.local. 5 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1653013687 7200 1800 86400 5
Received 146 bytes from 169.254.25.10#53 in 0 ms
Trying "myweb-svc.default.svc.cluster.local"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62583
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; QUESTION SECTION:
;myweb-svc.default.svc.cluster.local. IN MX
;; AUTHORITY SECTION:
cluster.local. 5 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1653013687 7200 1800 86400 5
Received 146 bytes from 169.254.25.10#53 in 0 ms
🎈 Search Domain 사용하여 질의
➜ 모두 동일한 결과 출력
/ # host myweb-svc
myweb-svc.default.svc.cluster.local has address 10.233.0.228
/ # host myweb-svc.default
myweb-svc.default.svc.cluster.local has address 10.233.0.228
/ # host myweb-svc.default.svc
myweb-svc.default.svc.cluster.local has address 10.233.0.228
/ # host myweb-svc.default.svc.cluster.local
myweb-svc.default.svc.cluster.local has address 10.233.0.228
🎈 DNS를 이용한 SD 실습
nettool Pod (dev NS) ➜ myweb-svc SVC (default NS)
웹 서버 파드 생성 및 실행
$ kubectl run nettool -it --image ghcr.io/c1t1d0s7/network-multitool -n dev --rm
서비스 정보 확인
# host myweb-svc
🌟 서비스 정보 확인 시 주의 사항
서비스가 어느 NS에 위치
하고 있는지 같이 명시하여 질문
➜ 서로 다른 NS에 동일한 이름의 서비스가 존재할 수 있기 때문
Full Name 쓰는 것이 the best
# host myweb-svc.[NS]
Add-On (애드온)
모든 Kubernetes Cluster의 Node에 node-cache
(DNS cache server)를 구성하는 기법
대규모 통신에서 사용 (부하 감소)
💡 파드의 DNS 질의 과정
nodelocal DNS 캐시 사용
Pod --dns➜ 169.254.25.10 (node-cache)Pod ➜ DNS Cache Server ➜ coredns SVC(kube-system NS) ➜ coredns POD
nodelocal DNS 캐시 사용 X
Pod --dns➜ coredns SVC(kube-system NS) ➜ coredns POD
파드의 DNS 서버 정보 확인
/ # cat /etc/resolv.conf
search dev.svc.cluster.local svc.cluster.local cluster.local default.svc.cluster.local
nameserver 169.254.25.10 ✔️
options ndots:5
모든 파드는 기본적으로 DNS 서버로 nameserver 169.254.25.10
를 바라보고 있음
노드에는 Node Local Interface
라는 가상 인터페이스 존재 (169.254.25.10)
파드 안의 App에서 전송하는 Domain Resolve 요청을 더 빠르게 처리
DNS Forwarder
(실질적인 정보를 가지고 있진 않지만 질의는 받아줌)
➜ 파드가 어떤 노드에 존재하던 일단 Node Local Interface에 질의
node-cache에 대한 네트워크 소켓 정보 확인
$ sudo ss -tnlp
...
LISTEN ... 169.254.25.10:9254 ... ✔️ users:(("node-cache",pid=3078,fd=7))
...
🎈 coredns-config.yml 파일 확인
coredns-config 파일 : Bind DNS의 Zone 파일과 비슷한 역할
DNS가 내부 네트워크의 사이트 주소에 대해 질의받은 내용에 대해 답변을 하기 위한 답변서
$ cd /etc/kubernetes
$ sudo more coredns-config.yml
고정 포트 (NodePort)로 각 노드의 IP에 서비스를 노출
🎈 서비스 타입 종류
svc.spec.type
NodePort 범위 : 30000 ~ 32767
➕ kubeadm 시, kube-apiserver.yaml manifest 파일로 kube-proxy에 대한 노드 포트 범위 설정 가능
기본적으로 2767개의 서비스만 생성 가능하며 포트 개수를 조정해 서비스 지원 범위 늘릴 수 있음
/etc/kubernetes/manifests/kube-apiserver.yaml
...
- --service-node-port-range=30000-32767
...
🎈 NodePort 실습
컨트롤 플레인은 노드 3개에 전부 동일 인터페이스 포트
(31772 - 임의설정값) 할당
외부에서 이 포트를 통해 접근한 다음 myweb-svc에 80번 포트를 통해 접속
➜ 접속 시 iptables에 기록
서비스에서 로드밸런싱을 하여 8080 포트로 파드에 접속
💡 NodePort 서비스는 기본 포트(31313)가 있고 그 위에 서비스를 생성해 서비스 포트(80)가 추가로 열어 Label Selector를 통해 타겟 파드(8080)에 연결하도록 구성한 것
➜ 클러스터 IP 기능에 클러스터 IP 추가
myweb-svc-np.yaml
NodePort 범위 내에 있는 아무 포트나 설정 가능
apiVersion: v1
kind: Service ✔️
metadata:
name: myweb-svc-np
spec:
type: NodePort ✔️
selector:
app: web
ports:
- port: 80
targetPort: 8080
nodePort: 31313 ✔️
서비스, RS, 파드 상세 정보 확인
$ kubectl get svc,rs,po -o wide
# 서비스
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 3h10m <none>
service/myweb-svc-np NodePort✔️ 10.233.60.76 <none> 80:31313/TCP 32s app=web
# RS
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
replicaset.apps/myweb-rs 3 3 3 17m myweb ghcr.io/c1t1d0s7/go-myweb app=web,env=dev
# 파드
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/myweb-rs-6fjdx 1/1 Running 0 17m 10.233.90.160 node1 <none> <none>
pod/myweb-rs-phtbp 1/1 Running 0 17m 10.233.90.162 node1 <none> <none>
pod/myweb-rs-rpww5 1/1 Running 0 17m 10.233.90.161 node1 <none> <none>
🎈 웹 브라우저 접속 확인하기
IP주소:포트 조합으로 접속 가능
➜ 자동으로 로드밸런싱 구현
LB + NodePort + Cluster IP
외부 로드 밸런서
를 지원하는 클라우드 공급자 상에서 서비스에 대한 로드 밸런서 프로비저닝
k8s는 k8s 내부
에 있는 것은 세팅 가능
하지만 외부
에 있는 장치는 설정 불가능
Add-On
내부에 Controller 파드를 만들어서 외부 스위치 기능을 수행할 수 있게 해주는 서비스 프록시
➜ addon 설정 yml 파일 수정 후, 플레이북 실행시켜 적용
~/kubespray/inventory/mycluster/group_vars/k8s-cluster/addons.yml
...
139 metallb_enabled: true
140 metallb_speaker_enabled: true
141 metallb_ip_range:
142 - "192.168.100.240-192.168.100.249" # 해당 IP로 외부 접속 가능
...
168 metallb_protocol: "layer2"
...
~/kubespray/inventory/mycluster/group_vars/k8s-cluster/k8s-cluster.yml
129 kube_proxy_strict_arp: true
kubespray 디렉토리에서 플레이북 실행
ansible-playbook -i inventory/mycluster/inventory.ini cluster.yml -b
layer2
(소규모)내부
에 파드 형태(컨트롤러)
로 구성BGP
(대규모 : 10대 이상)myweb-svc-lb.yaml
apiVersion: v1
kind: Service
metadata:
name: myweb-svc-lb
spec:
type: LoadBalancer ✔️
selector:
app: web
ports:
- port: 80
targetPort: 8080
nodePort: 31313
생성 된 로드밸런서 서비스, RS, 파드 상세 정보 확인
$ kubectl get svc,rs,po -o wide
# 서비스
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 147m <none>
service/myweb-svc-lb LoadBalancer✔️ 10.233.18.71 192.168.100.240 80:31313/TCP 67s app=web
# RS
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
replicaset.apps/myweb-rs-lb 3 3 3 67s myweb ghcr.io/c1t1d0s7/go-myweb app=web,env=dev
# 파드
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/myweb-rs-lb-2sc8h 1/1 Running 0 67s 10.233.96.16 node2 <none> <none>
pod/myweb-rs-lb-hfclf 1/1 Running 0 67s 10.233.90.12 node1 <none> <none>
pod/myweb-rs-lb-sw89x 1/1 Running 0 67s 10.233.92.10 node3 <none> <none>
MetalLB - 외부로의 로드밸런싱 확인
$ curl 192.168.100.240 ✔️
Hello World!
myweb-rs-lb-2sc8h ✔️
$ curl 192.168.100.240
Hello World!
myweb-rs-lb-sw89x ✔️
$ curl 192.168.100.240
Hello World!
myweb-rs-lb-hfclf ✔️
➕ 확인 가능한 서비스 종류
- Selector 없는 서비스
서비스 자체만 만들고 서비스가 바라보는 것이 파드가 아닌 경우
IP와 Port만 가지고 있으면 다 가능
➜ 엔드포인트 직접 생성 / 접속포트 직접 지정
- Cluster IP 없는 서비스
헤드리스 서비스
statefulset과 함께 사용
cluster ip 사용 none?
- NodePort 없는 서비스
클러스터 내부에서 클러스터 외부의 특정 서비스에 접속하기 위해 DNS CNAME 설정
이름만 바라보게 만들어주기 때문에 replace로 externalName만 바꾸면 다른 파드를 바라보도록 만들 수 있음
externalIP 를 부여 받음 ➜ 서비스에 연결
➜ 쿠버네티스가 이 IP에 대해 보장 x (위험)
➜ NodePort 방법 구현과 LB 구성이 어려울 경우 사용 가능
🎈 ExternalName 실습 : 터미널에서 일기예보 확인
확인 방법
$ curl -s 'wttr.in/seoul?format=1'
weather-ext-svc.yaml
apiVersion: v1
kind: Service ✔️
metadata:
name: weather-ext-svc
spec:
type: ExternalName ✔️
externalName: wttr.in
서비스 생성
$ kubectl create -f weather-exy-svc.yaml
파드 생성
$ kubectl run nettool -it --image ghcr.io/c1t1d0s7/network-multitool --rm
일기예보 확인
# curl wttr.in
가상화
(하이퍼바이저)를 사용하는 구조에서 사용하는 네트워크
💡 핵심
물리적으로 떨어진 VM들이 논리적으로 연결 된 가상 네트워크에서 동작하도록 하기 위해 물리 네트워크 위에 가상 네트워크를 Overlay(Tunneling)하여 서로 다른 네트워크 대역 사이의 통신 가능하게 함
🎈 구성
VPC
를 여러 BM에 걸쳐서 논리적으로 생성VSW
(Virtual Switch) 생성(ex. Docker0 등의 브릿지)NIC
(Network Interface Card) 생성 후 연결SW
(SWitch) 에 연결Router
로 서로 다른 네트워크의 두 SW 연결Underlay Network
생성 (물리적 연결)Overlay(Tunneling) Network
생성🎈 Container에서의 Overlay(Tunneling) Network
동일 네트워크 대역을 사용하는 서로 떨어진 Dockder0(가상 브릿지)
들을 Calico 네트워크는 IPIP
or VxLAN
방식을 사용한 Overlay(Tunneling) Network로 연결
가정 : Node1의 컨테이너(SRC)에서 Node2의 컨테이너(DST)로 통신
➜ SRC(Source) IP == 10 / DST(Destination) IP == 11
Router와 NIC 사이에는 TUN0
라고 하는 컨테이너와의 연결을 위한 인터페이스 존재
TUN0는 IPIP 방식을 사용하여 터널링 구성 (Node1 Router ➜ Node2 Router)
➜ 아래 그림의 빨간색 부분
➕ IPIP : 원본 IP Header 위에 Outer IP Header를 Encapsulation(인캡슐레이션)하여 네트워크 통과하는 방식
➜ 원본 IP 패킷(빨강)에 Outer IP Header(초록)을 붙임
Node2로 들어오면서 Outer IP를 벗고 원본 IP 패킷에 대한 정보를 전달
➕ 인터페이스 확인 방법
$ ip a s
➜ cali (Network Interface Card)
➜ tun0 (Tunneling Interface)
➜ eth0 (NIC)
특징 : 컨테이너 수에 따라 개수 증가
칼리코 공식 유튜브 ➜ 네트워크 구조 설명 잘 되어있음
쿠버네티스에 네트워크를 제공하기 위한 인터페이스(NIC) ➜ 현재 Calico 사용