HPA(Horizontal Pod Autoscaler)

# 간단하게 쓰고싶다면 스케일업이 유리, 보통은 스케일아웃 가장 많이 사용
- 기존 상위 리소스까지 전부 삭제
kubectl delete deploy,rs,pod,svc --all
root@master:~# cd mani/
root@master:~/mani# mkdir hpa
root@master:~/mani# cd hpa/
- 리소스를 제한할 파드 매니페스트
vi res.yml
apiVersion: v1 kind: Pod metadata: name: live-pod labels: app: live-nginx spec: containers: - name: nginx image: nginx:latest resources: requests: memory: "64Mi" cpu: "250m" limits: memory: "128Mi" cpu: "500m" |

# request: 최소자원, limits: 최대자원
pod(컨테이너)에 부여된 리소스에 임계값 정의를 통해, pod의 갯수를 늘리거나 줄이고 싶다.
오토스케일링을 위해선, 자원을 모니터링할 메트릭서버를 설치해야한다.
- 메트릭서버가 있는 깃허브
https://github.com/kubernetes-sigs/metrics-server
- 메트릭서버 매니페스트 다운로드
curl -Ls https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml -o metric.yml

root@master:~/mani/hpa# vi metric.yml

root@master:~/mani/hpa# kubectl apply -f metric.yml
root@master:~/mani/hpa# kubectl get pod -n kube-system

root@master:~/mani/hpa# kubectl apply -f res.yml
root@master:~/mani/hpa# kubectl top pod

# 메트릭서버가 설치되면 kubectl top pod 명령을 쓸 수 있다. 리소스의 자원 사용량을 조회 가능
- 리소스를 좀 낮춰서 deploy & svc 생성
apiVersion: v1 kind: Service metadata: name: svc-hpa spec: selector: app: hpa-nginx ports: - port: 80 targetPort: 80 --- apiVersion: apps/v1 kind: Deployment metadata: name: hpa-dep spec: replicas: 3 selector: matchLabels: app: hpa-nginx template: metadata: labels: app: hpa-nginx spec: containers: - image: 61.254.18.30:5000/nginx name: nginx-con resources: requests: cpu: 10m limits: cpu: 20m |
kubectl apply -f hpa-dep.yml
- cpu 사용량이 50% 이상일때, 스케일링을 할것이고, 최소1개-최대5개로 구성
→ kubectl autoscale deploy hpa-dep --min=1 --max=5 --cpu-percent=50
- 위 명령을 매니페스트로 정의
vi as.yml
apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: hpa-nginx spec: maxReplicas: 5 minReplicas: 1 scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: hpa-dep targetCPUUtilizationPercentage: 50 |
kubectl apply -f as.yml

- 부하 주기
→ i=1; while true; do sleep 0.001; echo $((i++)) `curl -s <svc의 ClusterIP>`;done
i=1; while true; do sleep 0.001; echo $((i++)) `curl -s 10.101.141.129`;done
- 다른 master에서 확인
watch kubectl top pod

kubectl get hpa

- 트래픽을 취소하면 파드가 삭제되는걸 확인 가능
kubectl get pod --watch

- 오토스케일러 삭제
kubectl delete hpa hpa-nginx
만약에 노드를 오토스케일링 하고 싶다면, AWS에는 카펜터(karpenter)를 통해 가능하다.
실습)
https://github.com/pcmin929/sb_code
이 스프링부트 앱을 여러분들의 쿠버네티스 클러스터에 배포하여 ilove.k8s.com 으로 접속했을때 앱이 뜨도록 해보세요. 또한 ilove.k8s.com/web 으로 접속했을때 readinessProbe를 통해 /healthz 경로로 헬스체크를 하는 간단한 httpd 웹서버를 띄워보세요. httpd 이미지는 61.254.18.30:5000/httpd로 올라가있는 상태, 위 두개의 앱은 오토스케일링 되어야한다.
- 기존 상위 리소스까지 전부 삭제
kubectl delete deploy,rs,pod,svc,ns --all
root@master:~/mani# git clone https://github.com/pcmin929/sb_code.git
root@master:~/mani# cd sb_code
- 이미지 pull
root@master:~/mani/sb_code# docker pull 61.254.18.30:5000/httpd
- Dockerfile 작성
root@master:~/mani/sb_code# vi Dockerfile
FROM openjdk:8-jdk-alpine
COPY target/springbootApp.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
- Maven Wrapper 실행
apt install -y maven
mvn clean package
- 빌드
docker build -t leeseohoo/springboot-app .
docker push leeseohoo/springboot-app
- 커스텀 httpd 이미지 생성
root@master:~/mani/sb_code# vi Dockerfile.httpd
FROM httpd
RUN echo "OK" > /usr/local/apache2/htdocs/healthz
docker build -t leeseohoo/httpd-healthz -f Dockerfile.httpd .
docker push leeseohoo/httpd-healthz
- Deployment 및 Service YML
1. springboot 앱
root@master:~/mani/sb_code# vi springboot.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: springboot-app
spec:
replicas: 1
selector:
matchLabels:
app: springboot
template:
metadata:
labels:
app: springboot
spec:
containers:
- name: springboot
image: leeseohoo/springboot-app
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: springboot-service
spec:
selector:
app: springboot
ports:
- port: 80
targetPort: 8080
root@master:~/mani/sb_code# kubectl apply -f springboot.yml
2. httpd 웹서버 (/healthz 응답 포함)
root@master:~/mani/sb_code# vi httpd.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpd-app
spec:
replicas: 1
selector:
matchLabels:
app: httpd
template:
metadata:
labels:
app: httpd
spec:
containers:
- name: httpd
image: leeseohoo/httpd-healthz
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 5
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: httpd-service
spec:
selector:
app: httpd
ports:
- port: 80
targetPort: 80
root@master:~/mani/sb_code# kubectl apply -f httpd.yml
- Ingress YML
root@master:~/mani/sb_code# vi ingress.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ilove-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2 # 정규표현식 기반 rewrite
spec:
ingressClassName: nginx
rules:
- host: ilove.k8s.com
http:
paths:
- path: /web(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: httpd-service
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: springboot-service
port:
number: 80
root@master:~/mani/sb_code# kubectl apply -f ingress.yml
oot@master:~/mani/sb_code# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.1/deploy/static/provider/baremetal/deploy.yaml
root@master:~/mani/sb_code# vi deploy.yaml

root@master:~/mani/sb_code# kubectl apply -f deploy.yaml
root@master:~/mani/sb_code# wget https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml
root@master:~/mani/sb_code# kubectl apply -f metallb-native.yaml
root@master:~/mani/sb_code# vi config-metal.yml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 211.183.3.200-211.183.3.240 # 원하는 대역대, 안겹치게 수정
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
root@master:~/mani/sb_code# kubectl apply -f config-metal.yml
- pod 확인
root@master:~/mani/sb_code# kubectl get pod -o wide

- ingress-controller external-IP 확인
root@master:~/mani/sb_code# kubectl get svc -n ingress-nginx

root@master:~/mani/sb_code# vi /etc/hosts
# 클러스터 ingress IP
211.183.3.200 ilove.k8s.com
- HPA
curl -Ls https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml -o metric.yml
root@master:~/mani/hpa# vi metric.yml

root@master:~/mani/hpa# kubectl apply -f metric.yml
cpu 사용량이 50% 이상일때, 스케일링을 할것이고, 최소1개-최대5개로 구성
→ kubectl autoscale deployment springboot-app --cpu-percent=50 --min=1 --max=5
→ kubectl autoscale deployment httpd-app --cpu-percent=50 --min=1 --max=5
- 위 명령을 매니페스트로 정의
1. springboot-hpa
root@master:~/mani/sb_code# vi springboot-hpa.yml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: springboot-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: springboot-app
minReplicas: 1
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
root@master:~/mani/sb_code# kubectl apply -f springboot-hpa.yml
2. httpd-hpa
root@master:~/mani/sb_code# vi httpd-hpa.yml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: httpd-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: httpd-app
minReplicas: 1
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
root@master:~/mani/sb_code# kubectl apply -f httpd-hpa.yml
- 결과 확인
curl ilove.k8s.com # → Spring Boot 페이지
curl ilove.k8s.com/web # → It works!
curl ilove.k8s.com/web/healthz # → OK


- HAproxy로 쓸 서버를 하나 clone

- IP를 211.183.3.50/24으로 설정
vi /etc/netplan/00-installer-config.yaml
netplan apply
- 호스트네임을 haproxy로 변경
# 각각 vm 이름과 동일하게 호스트네임 설정
hostnamectl set-hostname haproxy
su
apt update -y
apt install -y haproxy
- haproxy 설정파일 (/root에 백업)
cp /etc/haproxy/haproxy.cfg .
vi /etc/haproxy/haproxy.cfg
frontend kubernetes-master-lb bind 0.0.0.0:6443 option tcplog mode tcp default_backend kubernetes-master-nodes backend kubernetes-master-nodes mode tcp balance roundrobin option tcp-check option tcplog server k8s-master1 211.183.3.101:6443 check server k8s-master2 211.183.3.102:6443 check server k8s-master3 211.183.3.103:6443 check |

- 설정 반영
systemctl restart haproxy
- master와 worker1은 서스펜드 후, worker2만 종료

- 복제한 노드를 초기화
kubeadm reset --cri-socket unix:///run/containerd/containerd.sock
vi /etc/netplan/00-installer-config.yaml
netplan apply
hostnamectl set-hostname m1
- nfs 마운트해제
vi /etc/fstab
노드 구성 잘못한 경우, 초기화하고 싶은 경우
# kubeadm reset을 하게되면, 공통 설정은 다 들어있는 상태기 때문에 kubeadm init이 가능하다.
m1은 hostname m1에 IP는 211.183.3.101/24
m2은 hostname m2에 IP는 211.183.3.102/24
m3은 hostname m2에 IP는 211.183.3.103/24
m1
- 이니셜라이징
kubeadm config images pull --cri-socket unix:///run/containerd/containerd.sock --kubernetes-version v1.30.3
# m1에서 이미지를 pull
kubeadm init --pod-network-cidr=10.244.0.0/16 --upload-certs --kubernetes-version=v1.30.2 --cri-socket unix:///run/containerd/containerd.sock --ignore-preflight-errors=all --control-plane-endpoint=211.183.3.50
# --control-plane-endpoint=211.183.3.50
# kubectl을 통해 api요청을 할 주소 = haproxy의 주소

m2, m3
- m2, m3에서 마스터노드용 토큰 + --cri 옵션을 입력
kubeadm join 211.183.3.50:6443 --token 7bxl2u.7hhh8o4se1ar2gx8 \ --discovery-token-ca-cert-hash sha256:a6b74fb8d1dc94ad165cec275890ae564d7eaf6b9c22fb4eb6080a5a35a57e0e \ --control-plane --certificate-key a9471a19c262165d156eb33535225423308db5de627fd171c05b733adbcb9158 \ --cri-socket unix:///run/containerd/containerd.sock
haproxy 서버
스스로에게 kubectl명령을 치기 위해
kubectl 명령 설치 + 클러스터 m1의 config 파일 (/etc/kubernetes/admin.conf) 이 필요
- kubectl 명령 설치
apt-get install -y apt-transport-https ca-certificates curl
mkdir -p /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
apt-get update
apt-get install -y kubectl
apt-mark hold kubectl
mkdir -p ~/.kube
m1의 파일내용을 haproxy에 복사
- m1에서 config 파일의 내용을 복사
root@m1:~# cat /etc/kubernetes/admin.conf
- haproxy 서버에서 config 파일을 생성하여 위 admin.conf의 내용을 복붙
root@haproxy:~# vi ~/.kube/config
♨ 만약에 join했는데도 Not Ready가 뜬다면
→ CNI 설치해 해결 가능

m1을 서스펜드 후 바로 haproxy 서버에서 kubectl get nodes를 치면

# 잠깐동안 안되다가 다시 명령이 들어가는걸 확인 가능

# 1분정도후에 m1을 서스펜드 했기때문에 NotReady 상태가 된다.
# control plan의 HA를 구성할땐, 반드시 control plan의 갯수를 홀수개로 가져가야 한다.