⭐ 가시다(gasida) 님이 진행하는 KANS(**K**ubernetes **A**dvanced **N**etworking **S**tudy)3기 실습 게시글입니다.
게시글 상 소스코드, 사진에서 ****굵게**** '''코드쉘''' 에 대한 부분이 들어가있을수도 있습니다.
⭐코드에서 실습 시 사용하는 변수가 들어갈 수 있습니다. 아래의 정보를 사용하고있습니다.
#route53 Domain: jjongguet.com
#AWS Secret Key: jjongkey
#Aws .pem Key: jjong-key.pem
실습환경
사전 준비
: AWS 계정, SSH 키 페어
구성
: VPC 1개(퍼블릭 서브넷 2개), EC2 인스턴스 4대 (Ubuntu 22.04 LTS, t3.medium - vCPU 2 , Mem 4)
- CloudFormation 스택 실행 시 파라미터를 기입하면, 해당 정보가 반영되어 배포됩니다.
- CloudFormation 에 EC2의 UserData 부분(Script 실행)으로 실습 환경에 필요한 기본 설정들이 자동으로 진행됩니다.
CloudFormation 스택 배포
← 실행하는 PC에 aws cli 설치되어 있고, aws configure 자격증명 설정 상태.
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/kans/**kans-6w.yaml**
aws cloudformation deploy --template-file **kans-6w.yaml** --stack-name **mylab** --parameter-overrides KeyName=jjongkey SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 --region ap-northeast-2
# CloudFormation 스택 배포 완료 후 작업용 EC2 IP 출력
aws cloudformation describe-stacks --stack-name **mylab** --query 'Stacks[*].**Outputs[0]**.OutputValue' --output text --region ap-northeast-2
# [모니터링] CloudFormation 스택 상태 : 생성 완료 확인
**while true; do
date
AWS_PAGER="" aws cloudformation list-stacks \
--stack-status-filter CREATE_IN_PROGRESS CREATE_COMPLETE CREATE_FAILED DELETE_IN_PROGRESS DELETE_FAILED \
--query "StackSummaries[*].{StackName:StackName, StackStatus:StackStatus}" \
--output table
sleep 1
done**
# EC2 SSH 접속 : 바로 접속하지 말고, 3~5분 정도 후에 접속 할 것
ssh -i *~/.ssh/jjong-key.pem* **ubuntu**@$(aws cloudformation describe-stacks --stack-name **mylab** --query 'Stacks[*].Outputs[0].OutputValue' --output text --region ap-northeast-2)
EC2 생성 수량 부족 실패 시
: 사용자 계정의 해당 리전에 EC2 최대 갯수 제한 일 경우, Service Quotas (EC2) 증설 요청으로 해결 - 링크 EC2 요청- Limit Type(EC2 Instances) ⇒ 서울 리전, All Standard (A, C, D, H, I, M, R, T, Z) Instances, New limit value(40 정도)
K3s: Lightweight Kubernetes
- 경량 쿠버네티스
- K8s 에서 ControlPlane, WorkerNode 라고 부르는 역할을 각각
K3s 에서 Server, Agent 라고 지칭한다.
설치옵션
# Install k3s-server
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC=" --disable=traefik" sh -s - **server** --token **kanstoken** --cluster-cidr "172.16.0.0/16" --service-cidr "10.10.200.0/24" --write-kubeconfig-mode 644
# Install k3s-agent
curl -sfL https://get.k3s.io | K3S_URL=https://192.168.10.10:6443 K3S_TOKEN=**kanstoken** sh -s -
k3s 기본 정보 확인 : k8s v1.30.x → 현재 ingress-nginx controller 이 1.30.x 까지 버전 호환 테스트 완료 임 (‘24.10.6 일 기준)
k3s 확인
# 노드 확인
**kubectl get node -owide**
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k3s-s Ready control-plane,master 23m v1.30.5+k3s1 192.168.10.10 <none> Ubuntu 22.04.5 LTS 6.8.0-1015-aws containerd://1.7.21-k3s2
k3s-w1 Ready <none> 23m v1.30.5+k3s1 192.168.10.101 <none> Ubuntu 22.04.5 LTS 6.8.0-1015-aws containerd://1.7.21-k3s2
k3s-w2 Ready <none> 23m v1.30.5+k3s1 192.168.10.102 <none> Ubuntu 22.04.5 LTS 6.8.0-1015-aws containerd://1.7.21-k3s2
k3s-w3 Ready <none> 23m v1.30.5+k3s1 192.168.10.103 <none> Ubuntu 22.04.5 LTS 6.8.0-1015-aws containerd://1.7.21-k3s2
# kubecolor alias 로 kc 설정 되어 있음
**kc** describe node k3s-s # Taints 없음
**kc** describe node k3s-w1
# 파드 확인
**kubectl get pod -n kube-system**
NAME READY STATUS RESTARTS AGE
coredns-7b98449c4-jmhgk 1/1 Running 0 21m
local-path-provisioner-6795b5f9d8-w6h8s 1/1 Running 0 21m
metrics-server-cdcc87586-m4ndt 1/1 Running 0 21m
#
kubectl top node
kubectl top pod -A --sort-by='cpu'
kubectl top pod -A --sort-by='memory'
kubectl get storageclass
# config 정보(위치) 확인
**kubectl get pod -v=6**
I1006 13:04:02.858105 4325 loader.go:395] Config loaded from file: **/etc/rancher/k3s/k3s.yaml**
I1006 13:04:02.872677 4325 round_trippers.go:553] GET https://127.0.0.1:6443/api/v1/namespaces/default/pods?limit=500 200 OK in 5 milliseconds
No resources found in default namespace.
**cat /etc/rancher/k3s/k3s.yaml**
export | grep KUBECONFIG
# 네트워크 정보 확인 : flannel CNI(vxlan mode), podCIDR
**ip -c addr**
ip -c route
**cat /run/flannel/subnet.env**
**kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}' ;echo**
kubectl describe node | grep -A3 Annotations
brctl show
# 서비스와 엔드포인트 확인
**kubectl get svc,ep -A**
# iptables 정보 확인
iptables -t **filter** -S
iptables -t **nat** -S
iptables -t **mangle** -S
# tcp listen 포트 정보 확인
ss -tnlp
kube-system 에 pod 가 많이 없는이유는 Server 에 다 들어가있기 때문이다(경량)
Ingress
0. Ingress 요약
Nginx 인그레스 컨트롤러
경우 : 외부에서 인그레스로 접속 시 Nginx 인그레스 컨트롤러 파드로 인입되고, 이후 애플리케이션 파드의 IP로 직접 통신
1. 인그레스(Ingress) 소개
인그레스 소개
: 클러스터 내부의 서비스(ClusterIP, NodePort, Loadbalancer)를 외부로 노출(HTTP/HTTPS) - Web Proxy 역할
- Make your HTTP (or HTTPS) network service available using a protocol-aware configuration mechanism, that understands web concepts like URIs, hostnames, paths, and more. The Ingress concept lets you map traffic to different backends based on rules you define via the Kubernetes API.
- An API object that manages external access to the services in a cluster, typically HTTP.
- Ingress may provide load balancing, SSL termination and name-based virtual hosting.
- Ingress is frozen. New features are being added to the Gateway API.
2. Nginx 인그레스 컨트롤러 설치
인그레스(Ingress) 소개
: 클러스터 내부의 HTTP/HTTPS 서비스를 외부로 노출(expose) - 링크
Ingress-Nginx 컨트롤러 생성 - ArtifactHub release
# Ingress-Nginx 컨트롤러 생성
cat <<EOT> ingress-nginx-values.yaml
**controller**:
service:
type: **NodePort**
nodePorts:
http: **30080**
https: **30443**
nodeSelector:
kubernetes.io/hostname: "**k3s-s**"
**metrics**:
enabled: true
**serviceMonitor**:
enabled: true
EOT
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
kubectl create ns ingress
**helm install ingress-nginx ingress-nginx/ingress-nginx -f ingress-nginx-values.yaml --namespace ingress --version 4.11.2**
# 확인
kubectl get all -n ingress
kc describe svc -n ingress ingress-nginx-controller
# externalTrafficPolicy 설정
**kubectl patch svc -n ingress ingress-nginx-controller -p '{"spec":{"externalTrafficPolicy": "Local"}}'**
# 기본 nginx conf 파일 확인
kc describe cm -n ingress ingress-nginx-controller
**kubectl exec deploy/ingress-nginx-controller -n ingress -it -- cat /etc/nginx/nginx.conf**
# 관련된 정보 확인 : 포드(Nginx 서버), 서비스, 디플로이먼트, 리플리카셋, 컨피그맵, 롤, 클러스터롤, 서비스 어카운트 등
kubectl get all,sa,cm,secret,roles -n ingress
kc describe clusterroles ingress-nginx
kubectl get pod,svc,ep -n ingress -o wide -l app.kubernetes.io/component=controller
# 버전 정보 확인
POD_NAMESPACE=ingress
POD_NAME=$(kubectl get pods -n $POD_NAMESPACE -l app.kubernetes.io/name=ingress-nginx --field-selector=status.phase=Running -o name)
kubectl exec $POD_NAME -n $POD_NAMESPACE -- /nginx-ingress-controller --version
ns ingress 의 service/ingress-nginx-controller 의 포트 30080, 30443 을 오픈했으며,
NodeIP 의 노드포트 30080, 30443 으로 연결하면 각각은 80, 443 으로 연결되고, Endpoint ingress-nginx-controller 를 사용중인 파드로 연결하게된다
3. 인그레스(Ingress) 실습 및 통신 흐름 확인
실습 구성도
- 컨트롤플레인 노드에 인그레스 컨트롤러(Nginx) 파드를 생성, NodePort 로 외부에 노출
- 인그레스 정책 설정 : Host/Path routing, 실습의 편리를 위해서 도메인 없이 IP로 접속 설정 가능
3.1 디플로이먼트와 서비스를 생성
생성 및 확인
# 모니터링
watch -d 'kubectl get ingress,svc,ep,pod -owide'
# 생성
**kubectl taint nodes k3s-s role=controlplane:NoSchedule**
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc1-pod.yaml
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc2-pod.yaml
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc3-pod.yaml
**kubectl apply -f svc1-pod.yaml,svc2-pod.yaml,svc3-pod.yaml**
# 확인 : svc1, svc3 은 ClusterIP 로 클러스터 외부에서는 접속할 수 없다 >> Ingress 는 연결 가능!
kubectl get pod,svc,ep
svc1-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy1-websrv
spec:
replicas: 1
selector:
matchLabels:
app: websrv
template:
metadata:
labels:
app: websrv
spec:
containers:
- name: pod-web
image: nginx
---
apiVersion: v1
kind: Service
metadata:
name: svc1-web
spec:
ports:
- name: web-port
port: 9001
targetPort: 80
selector:
app: websrv
type: ClusterIP
svc2-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy2-guestsrv
spec:
replicas: 2
selector:
matchLabels:
app: guestsrv
template:
metadata:
labels:
app: guestsrv
spec:
containers:
- name: pod-guest
image: gcr.io/google-samples/kubernetes-bootcamp:v1
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: svc2-guest
spec:
ports:
- name: guest-port
port: 9002
targetPort: 8080
selector:
app: guestsrv
type: NodePort
svc3-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy3-adminsrv
spec:
replicas: 3
selector:
matchLabels:
app: adminsrv
template:
metadata:
labels:
app: adminsrv
spec:
containers:
- name: pod-admin
image: k8s.gcr.io/echoserver:1.5
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: svc3-admin
spec:
ports:
- name: admin-port
port: 9003
targetPort: 8080
selector:
app: adminsrv
3.2 인그레스(정책) 생성 - 링크
ingress1.yaml
cat <<EOT> ingress1.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-1
annotations:
#nginx.ingress.kubernetes.io/upstream-hash-by: "true"
spec:
ingressClassName: **nginx**
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc1-web
port:
number: 80
- path: /guest
pathType: Prefix
backend:
service:
name: svc2-guest
port:
number: 8080
- path: /admin
pathType: Prefix
backend:
service:
name: svc3-admin
port:
number: 8080
EOT
spec.ingressClassName: nginx: nginx 이외에도 ingress 규칙을 만족하는 구현체면 사용할 수 있다.
spec.rules: ingress 설정파일에서는 룰(path)기반 라우팅을 정의한다.
위의 yaml 파일에서는 path(/, /guest, /admin) 에 매치가 될때 각각 svc1-web, svc2-guest, svc3-admin 으로 라우팅을 처리하라는 설정코드임
인그레스 생성 및 확인
# 모니터링
watch -d 'kubectl get ingress,svc,ep,pod -owide'
# 생성
kubectl apply -f ingress1.yaml
# 확인
kubectl get ingress
**kc describe ingress ingress-1**
...
Rules:
Host Path Backends
---- ---- --------
***
/ svc1-web:80 ()
/guest svc2-guest:8080 ()
/admin svc3-admin:8080 ()**
...
# 설정이 반영된 nginx conf 파일 확인
kubectl exec deploy/ingress-nginx-controller -n ingress -it -- cat /etc/nginx/nginx.conf
kubectl exec deploy/ingress-nginx-controller -n ingress -it -- **cat /etc/nginx/nginx.conf | grep 'location /' -A5**
location /guest/ {
set $namespace "default";
set $ingress_name "ingress-1";
set $service_name "svc2-guest";
set $service_port "8080";
--
location /admin/ {
set $namespace "default";
set $ingress_name "ingress-1";
set $service_name "svc3-admin";
set $service_port "8080";
--
location / {
set $namespace "default";
set $ingress_name "ingress-1";
set $service_name "svc1-web";
set $service_port "80";
--
...
Host: *: 어떠한 주소로 와도 전체에 대해
Path → Backends: 특정한 Path 에 충족이 될때, 특정한 Backend 로 보내주겠다는 뜻
⇒ 정확히는 매치되는 Backend 를 LabelSelect 로 갖고있는 Pod 에 보내준다.
3.3 인그레스를 통한 내부 접속
- Nginx 인그레스 컨트롤러를 통한 접속(HTTP 인입) 경로 : 인그레스 컨트롤러 파드에서 서비스 파드의 IP로 직접 연결 (아래 오른쪽 그림)
인그레스 접속 경로 : Ingress → 애플리케이션 서비스(Service) → 애플리케이션(Deploy, Pod 등)
인그레스 접속 경로(서비스 Bypass) : Ingress → 애플리케이션(Deploy, Pod 등)
인그레스(Nginx 인그레스 컨트롤러)를 통한 접속(HTTP 인입) 확인*** : HTTP 부하분산 & PATH 기반 라우팅, 애플리케이션 파드에 연결된 서비스는 Bypass
# (krew 플러그인 설치 시) 인그레스 정책 확인
**~~kubectl ingress-nginx ingresses~~**
INGRESS NAME HOST+PATH ADDRESSES TLS SERVICE SERVICE PORT ENDPOINTS
ingress-1 / 192.168.10.10 NO svc1-web 80 1
ingress-1 /guest 192.168.10.10 NO svc2-guest 8080 2
ingress-1 /admin 192.168.10.10 NO svc3-admin 8080 3
#
**kubectl get ingress**
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-1 nginx * 10.10.200.24 80 3m44s
**kubectl describe ingress ingress-1 | sed -n "5, \$p"**
Rules:
Host Path Backends
---- ---- --------
*** / svc1-web:80 ()
/guest svc2-guest:8080 ()
/admin svc3-admin:8080 ()**
# 접속 로그 확인 : kubetail 설치되어 있음 - 출력되는 nginx 의 로그의 IP 확인
**kubetail -n ingress -l app.kubernetes.io/component=controller**
-------------------------------
**# 자신의 집 PC에서 인그레스를 통한 접속 : 각각**
echo -e "Ingress1 **sv1-web** URL = http://$(curl -s ipinfo.io/ip):30080"
echo -e "Ingress1 **sv2-guest** URL = http://$(curl -s ipinfo.io/ip):30080/guest"
echo -e "Ingress1 **sv3-admin** URL = http://$(curl -s ipinfo.io/ip):30080/admin"
# svc1-web 접속
**MYIP=<EC2 공인 IP>**
**MYIP=13.125.137.47**
curl -s **$MYIP:30080**
# svvc2-guest 접속
curl -s **$MYIP:30080**/**guest**
curl -s **$MYIP:30080**/**guest**
for i in {1..100}; do curl -s **$MYIP:30080**/guest ; done | sort | uniq -c | sort -nr
# svc3-admin 접속 > 기본적으로 Nginx 는 라운드로빈 부하분산 알고리즘을 사용 >> Client_address 와 XFF 주소는 어떤 주소인가요?
curl -s **$MYIP:30080**/**admin**
curl -s **$MYIP:30080**/admin | egrep '(client_address|x-forwarded-for)'
for i in {1..100}; do curl -s **$MYIP:30080/**admin | grep Hostname ; done | sort | uniq -c | sort -nr
# (옵션) 디플로이먼트의 파드 갯수를 증가/감소 설정 후 접속 테스트 해보자
kubetail 명령어로 로그 걸어놓고 ingress ep url 로 직접 접근해보면
트래픽을 캡쳐 할 수 있다
sv2-guest EP 도 동일하게 접근됨
페이지가 다르게 뜨는것을 보아하니 다른 EP 로 접근했다는걸 확인가능하다
트래픽캡쳐도 동일
외부에서 접근하는것(우측상단) 도 동일
부하분산확인(service2에 deployment2)
부하분산확인(service3에 deployment3연결)
- 노드에서 아래 패킷 캡처 확인 : flannel vxlan, 파드 간 통신 시 IP 정보 확인
#
ngrep -tW byline -d ens5 '' udp port 8472 or tcp port 80
#
tcpdump -i ens5 udp port 8472 -nn
# vethY는 각자 k3s-s 의 가장 마지막 veth 를 지정
tcpdump -i ***vethY*** tcp port **8080** -nn
tcpdump -i ***vethY*** tcp port 8080 -w /tmp/ingress-nginx.pcap
# 자신의 PC에서 k3s-s EC2 공인 IP로 pcap 다운로드
scp ubuntu@***<k3s-s EC2 공인 IP>***:/tmp/ingress-nginx.pcap ~/Downloads
scp ubuntu@*43.202.1.177*:/tmp/ingress-nginx.pcap ~/Downloads
- Nginx 파드가 endpoint 정보 등을 모니터링 가능한 이유 : 클러스터롤과 롤(엔드포인트 list, watch)를 바인딩된 서비스 어카운트를 파드가 사용!
**# (옵션) Nginx 파드가 endpoint 정보 등을 모니터링 가능한 이유 : 클러스터롤과 롤(엔드포인트 list, watch)를 바인딩된 서비스 어카운트를 파드가 사용!**
kubectl describe clusterrole ingress -n ingress | egrep '(Verbs|endpoints)'
****[root@k8s-m:~/yaml (ctx-k8s:default)]# kubectl describe clusterrole ingress-nginx -n ingress-nginx | egrep '(Verbs|endpoints)'
Resources Non-Resource URLs Resource Names Verbs
**endpoints** [] [] [**list watch**]
kubectl describe roles ingress-nginx -n ingress | egrep '(Verbs|endpoints)'
[root@k8s-m:~/yaml (ctx-k8s:default)]# kubectl describe roles ingress-nginx -n ingress-nginx | egrep '(Verbs|endpoints)'
Resources Non-Resource URLs Resource Names Verbs
**endpoints** [] [] [**get list watch**]
- (심화) nginx ingress controller 이 endpoint ip(port) list 획득 코드 내용 - 링크
klog.V(3).Infof("Getting Endpoints for Service %q and port %v", svcKey, port.String())
ep, err := getServiceEndpoints(svcKey)
if err != nil {
klog.Warningf("Error obtaining Endpoints for Service %q: %v", svcKey, err)
return upsServers
}
- 외부 클라이언트(192.168.100.1) → 인그레스 접속 시(192.168.100.10:Port) : 각기 path 에 따른 연결⇒ 파드는 외부 클라이언트의 IP 획득을 위해서 X-Forwarded-For(XFF)를 참조를 해야 합니다!⇒ L4 장비는 4계층에 있는 정보까지만 이해하고 처리할 수 가 있다.
3.5 (옵션) Nginx 분산 알고리즘 변경
nginx 는 기본 RR 라운드 로빈 이지만, IP-Hash 나 Session Cookie 설정으로 대상 유지 가능 - 링크
# mypc
for i in {1..100}; do curl -s **$MYIP:30080**/admin | grep Hostname ; done | sort | uniq -c | sort -nr
while true; do curl -s --connect-timeout 1 **$MYIP:30080**/admin | grep Hostname ; date "+%Y-%m-%d %H:%M:%S" ; echo "--------------" ; sleep 1; done
# 아래 ingress 설정 중 **IP-Hash** 설정 > # 주석 제거
sed -i 's/#nginx.ingress/nginx.ingress/g' ingress1.yaml
kubectl apply -f ingress1.yaml
# 접속 확인
for i in {1..100}; do curl -s **$MYIP:30080**/admin | grep Hostname ; done | sort | uniq -c | sort -nr
while true; do curl -s --connect-timeout 1 **$MYIP:30080**/admin | grep Hostname ; date "+%Y-%m-%d %H:%M:%S" ; echo "--------------" ; sleep 1; done
# 다시 원복(라운드 로빈) > # 주석 추가
sed -i 's/nginx.ingress/#nginx.ingress/g' ingress1.yaml
kubectl apply -f ingress1.yaml
# 접속 확인
for i in {1..100}; do curl -s **$MYIP:30080**/admin | grep Hostname ; done | sort | uniq -c | sort -nr
while true; do curl -s --connect-timeout 1 **$MYIP:30080**/admin | grep Hostname ; date "+%Y-%m-%d %H:%M:%S" ; echo "--------------" ; sleep 1; done
- 다음 실습을 위해 오브젝트 삭제
kubectl delete deployments,svc,ingress --all
3.6 Host 기반 라우팅
ingress2.yaml
cat <<EOT> ingress2.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-2
spec:
ingressClassName: nginx
rules:
- host: kans.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc3-admin
port:
number: 8080
- host: "*.kans.com"
http:
paths:
- path: /echo
pathType: Prefix
backend:
service:
name: svc3-admin
port:
number: 8080
EOT
인그레스 생성 및 확인
# 터미널1
watch -d 'kubectl get ingresses,svc,ep,pod -owide'
# 도메인 변경
MYDOMAIN1=<각자 자신의 닉네임의 도메인> 예시) gasida.com
MYDOMAIN1=jjongguet.com
sed -i "s/kans.com/$MYDOMAIN1/g" ingress2.yaml
# 생성
kubectl apply -f ingress2.yaml,svc3-pod.yaml
# 확인
kubectl get ingress
kubectl describe ingress ingress-2
**kubectl describe ingress ingress-2 | sed -n "5, \$p"**
Rules:
Host Path Backends
---- ---- --------
kans.com / svc3-admin:8080 ()
*.kans.com /echo svc3-admin:8080 ()
...
describe 에서 Host 에 * 가 아닌, domain 이 있음을 확인
→ IP 로 접근불가하고, Host에 정의된 domain으로만 접근가능하게 설정함
인그레스(Nginx 인그레스 컨트롤러)를 통한 접속(HTTP 인입) 확인
# 로그 모니터링
kubetail -n ingress -l app.kubernetes.io/component=controller
# (옵션) ingress nginx 파드 vethY 에서 패킷 캡처 후 확인 해 볼 것
------------
# 자신의 PC 에서 접속 테스트
# svc3-admin 접속 > 결과 확인 : 왜 접속이 되지 않는가? HTTP 헤더에 Host 필드를 잘 확인해보자!
curl $MYIP:30080 -v
curl $MYIP:30080/echo -v
# mypc에서 접속을 위한 설정
## /etc/hosts 수정 : 도메인 이름으로 접속하기 위해서 변수 지정
## 윈도우 C:\Windows\System32\drivers\etc\hosts
## 맥 sudo vim /etc/hosts
MYDOMAIN1=**<각자 자신의 닉네임의 도메인>**
MYDOMAIN2=**<test.각자 자신의 닉네임의 도메인>**
MYDOMAIN1=jjongguet.com
MYDOMAIN2=test.jjongguet.com
echo $MYIP $MYDOMAIN1 $MYDOMAIN2
echo "$MYIP $MYDOMAIN1" | sudo tee -a /etc/hosts
echo "$MYIP $MYDOMAIN2" | sudo tee -a /etc/hosts
cat /etc/hosts | grep $MYDOMAIN1
~~~~# svc3-admin 접속 > 결과 확인
curl $MYDOMAIN1:30080 -v
curl $MYDOMAIN1:30080/admin
curl $MYDOMAIN1:30080/echo
curl $MYDOMAIN1:30080/echo/1
curl $MYDOMAIN2:30080 -v
curl $MYDOMAIN2:30080/admin
curl $MYDOMAIN2:30080/echo
curl $MYDOMAIN2:30080/echo/1
curl $MYDOMAIN2:30080/echo/1/2
## (옵션) /etc/hosts 파일 변경 없이 접속 방안
curl -H "host: $MYDOMAIN1" $MYIP:30080
IP로 접근불가능(404 not found)
이후 IP 정보 /etc/hosts 에 등록
MYDOMAIN1 으로 설정한 건 전부 접근완료
MYDOMAIN2 으로 설정한건 일부접근가능
- *.jjongguet.com 으로 설정한 호스트는 /echo 경로로 설정한것만 svc3-admin 으로 라우팅하기때문에
30080, 30080/admin 으로 통신한건 접근하지못함(404 not found)
- 오브젝트 삭제
kubectl delete deployments,svc,ingress --all
3.7 카나리 업그레이드
배포 자동화 지원(최소 중단, 무중단) - 롤링 업데이트, 카나리 업데이트, 블루/그린 업데이트 - 링크 링크2 하이커퍼넥스-블로그
롤링업데이트
카나리업데이트
블루그린업데이트
canary-svc1-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: dp-v1
spec:
replicas: 3
selector:
matchLabels:
app: svc-v1
template:
metadata:
labels:
app: svc-v1
spec:
containers:
- name: pod-v1
image: k8s.gcr.io/echoserver:1.5
ports:
- containerPort: 8080
terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Service
metadata:
name: svc-v1
spec:
ports:
- name: web-port
port: 9001
targetPort: 8080
selector:
app: svc-v1
canary-svc2-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: dp-v2
spec:
replicas: 3
selector:
matchLabels:
app: svc-v2
template:
metadata:
labels:
app: svc-v2
spec:
containers:
- name: pod-v2
image: k8s.gcr.io/echoserver:1.6
ports:
- containerPort: 8080
terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Service
metadata:
name: svc-v2
spec:
ports:
- name: web-port
port: 9001
targetPort: 8080
selector:
app: svc-v2
생성 및 확인
# 터미널1
watch -d 'kubectl get ingress,svc,ep,pod -owide'
# 생성
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/canary-svc1-pod.yaml
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/canary-svc2-pod.yaml
kubectl apply -f canary-svc1-pod.yaml,canary-svc2-pod.yaml
# 확인
kubectl get svc,ep,pod
# 파드 버전 확인: **1.13.0** vs **1.13.1**
for pod in $(kubectl get pod -o wide -l app=**svc-v1** |awk 'NR>1 {print $6}'); do curl -s $pod:8080 | egrep '(Hostname|nginx)'; done
Hostname: dp-v1-cdd8dc687-gcgsz
server_version=**nginx: 1.13.0** - lua: 10008
for pod in $(kubectl get pod -o wide -l app=**svc-v2** |awk 'NR>1 {print $6}'); do curl -s $pod:8080 | egrep '(Hostname|nginx)'; done
Hostname: dp-v2-785f69bd6-hh624
server_version=**nginx: 1.13.1** - lua: 10008
canary-ingress1.yaml
cat <<EOT> canary-ingress1.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-canary-v1
spec:
ingressClassName: nginx
rules:
- host: kans.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc-v1
port:
number: 8080
EOT
canary-ingress2.yaml
cat <<EOT> canary-ingress2.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-canary-v2
annotations:
**nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"**
spec:
ingressClassName: nginx
rules:
- host: kans.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc-v2
port:
number: 8080
EOT
첫번째 Ingress, 두번째 Ingress의 차이점: 두번째 ingress 에 weight10이 부여되어있음
→ 첫번째 Ingress 에는 svc1(1.13.0), 두번째 Ingress 에는 svc2(1.13.1) 이 연결되어있는데
두번째 Ingress 에 설정된 weight 10 설정 ⇒ 두번째 Ingress 로는 전체 100%중 10%의 트래픽만 처리하겠다는 뜻
카나리 업그레이드 확인
# 터미널1
watch -d 'kubectl get ingress,svc,ep'
# 도메인 변경
MYDOMAIN1=<각자 자신의 닉네임의 도메인> 예시) gasida.com
MYDOMAIN1=jjongguet.com
sed -i "s/kans.com/$MYDOMAIN1/g" canary-ingress1.yaml
sed -i "s/kans.com/$MYDOMAIN1/g" canary-ingress2.yaml
# 생성
kubectl apply -f canary-ingress1.yaml,canary-ingress2.yaml
# 로그 모니터링
kubetail -n ingress -l app.kubernetes.io/component=controller
# 접속 테스트
curl -s $MYDOMAIN1:30080
curl -s $MYDOMAIN1:30080 | grep nginx
# 접속 시 v1 v2 버전별 비율이 어떻게 되나요? 왜 이렇게 되나요?
for i in {1..100}; do curl -s $MYDOMAIN1:30080 | grep nginx ; done | sort | uniq -c | sort -nr
for i in {1..1000}; do curl -s $MYDOMAIN1:30080 | grep nginx ; done | sort | uniq -c | sort -nr
while true; do curl -s --connect-timeout 1 $MYDOMAIN1:30080 | grep Hostname ; echo "--------------" ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; done
# 비율 조정 >> 개발 배포 버전 전략에 유용하다!
kubectl annotate --overwrite ingress ingress-canary-v2 nginx.ingress.kubernetes.io/canary-weight=**50**
# 접속 테스트
for i in {1..100}; do curl -s $MYDOMAIN1:30080 | grep nginx ; done | sort | uniq -c | sort -nr
for i in {1..1000}; do curl -s $MYDOMAIN1:30080 | grep nginx ; done | sort | uniq -c | sort -nr
# (옵션) 비율 조정 << 어떻게 비율이 조정될까요?
kubectl annotate --overwrite ingress ingress-canary-v2 nginx.ingress.kubernetes.io/canary-weight=100
for i in {1..100}; do curl -s $MYDOMAIN1:30080 | grep nginx ; done | sort | uniq -c | sort -nr
# (옵션) 비율 조정 << 어떻게 비율이 조정될까요?
kubectl annotate --overwrite ingress ingress-canary-v2 nginx.ingress.kubernetes.io/canary-weight=0
for i in {1..100}; do curl -s $MYDOMAIN1:30080 | grep nginx ; done | sort | uniq -c | sort -nr
ingress2 weight10
ingress2 weight50
- 오브젝트 삭제
kubectl delete deployments,svc,ingress --all
3.8 HTTPS 처리 (TLS 종료) - 링크
Ingress 에서 HTTPS 를 입력받고 HTTP로 바꿔서, 내부망에는 HTTP통신만 하게 만드는 처리기법
svc-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-https
labels:
app: https
spec:
containers:
- name: container
image: k8s.gcr.io/echoserver:1.6
terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Service
metadata:
name: svc-https
spec:
selector:
app: https
ports:
- port: 8080
ssl-termination-ingress.yaml
cat <<EOT> ssl-termination-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: https
spec:
ingressClassName: nginx
**tls**:
- hosts:
- kans.com
**secretName**: secret-https
rules:
- host: kans.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc-https
port:
number: 8080
EOT
생성 확인 및 secret 생성 후 접속 확인
# 서비스와 파드 생성
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc-pod.yaml
kubectl apply -f svc-pod.yaml
# 도메인 변경
MYDOMAIN1=<각자 자신의 닉네임의 도메인> 예시) gasida.com
MYDOMAIN1=jjongguet.com
echo $MYDOMAIN1
sed -i "s/kans.com/$MYDOMAIN1/g" ssl-termination-ingress.yaml
# 인그레스 생성
kubectl apply -f ssl-termination-ingress.yaml
# 인증서 생성
# openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=dkos.com/O=dkos.com"mkdir key && cd key
MYDOMAIN1=jjongguet.com
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=$MYDOMAIN1/O=$MYDOMAIN1"
tree
# Secret 생성
kubectl create secret tls secret-https --key tls.key --cert tls.crt
# Secret 확인
kubectl get secrets secret-https
kubectl get secrets secret-https -o yaml
-------------------
# 자신의 PC 에서 접속 확인 : PC 웹브라우저
# 접속 확인 : -k 는 https 접속 시 : 접속 포트 정보 확인
curl -Lk https://$MYDOMAIN1:**30443**
## (옵션) /etc/hosts 파일 변경 없이 접속 방안
curl -Lk -H "host: $MYDOMAIN1" https://$MYDOMAIN1:30443
ingress controller 로 30443 → 443 으로 HTTPS 통신 진행
웹에서도 접근가능
- 오브젝트 삭제
kubectl delete pod,svc,ingress --all
- Nginx 인그레스 컨트롤러 삭제
helm uninstall -n ingress ingress-nginx
Chrome 에서 사설인증서 제공 https 사이트 접속 시thisisunsafe
입력 - 링크
INGRESS 실습종료(추후 Gateway 실습을 위해 제거)
실습 환경 삭제
: 모든 실습 완료 후에는 꼭 삭제 확인 해주시기 바랍니다.
- /etc/hosts 에 추가한 내용 삭제
# CloudFormation 스택 삭제
**aws cloudformation delete-stack --stack-name mylab**
# [모니터링] CloudFormation 스택 상태 : 삭제 확인
**while true; do
date
AWS_PAGER="" aws cloudformation list-stacks \
--stack-status-filter CREATE_IN_PROGRESS CREATE_COMPLETE CREATE_FAILED DELETE_IN_PROGRESS DELETE_FAILED \
--query "StackSummaries[*].{StackName:StackName, StackStatus:StackStatus}" \
--output table
sleep 1
done**