일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- FTP
- KUBECTL
- aws saa
- docker
- linux
- NAT
- vyos
- aws cloud
- DNS
- aws SAA-c03
- 쿠버네티스
- aws cloud shcool 8
- EC2
- aws cloud school
- SAA-C03
- vmware
- EC2 인스턴스
- Ebs
- 네트워크
- ALB
- AWS
- aws iam
- load balancer
- AWS 자격증
- IAM
- Troubleshooting
- Firewall
- GNS3
- tftp
- Kubernetes
- Today
- Total
나의 공부기록
[Kubernetes] 10. HPA(Horizontal Pod AutoScaler) & Control Plane 3중화(HAProxy) 본문
[Kubernetes] 10. HPA(Horizontal Pod AutoScaler) & Control Plane 3중화(HAProxy)
나의 개발자 2025. 4. 19. 17:35HPA(Horizontal Pod Autoscaler)
- 간단하게 쓰고 싶다면 Scale Up이 유리하고, 보통은 Scale Out이 많이 쓰임
HPA 실습
1. 디렉토리 생성
root@master-250410:~# cd mani/
root@master-250410:~/mani# mkdir hpa
root@master-250410:~/mani# cd hpa
2. 리소스 제한 manifest file 정의
root@master-250410:~/mani/hpa# vi res.yml
apiVersion: v1
kind: Pod
metadata:
name: live-pod
labels:
app: live-nginx
spec:
containers:
- name: nginx
image: 61.254.18.30:5000/nginx
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"

- request : 최소 자원 / limits : 최대 자원
- Pod(컨테이너)에 부여된 리소스에 임계값 정의를 통해, Pod의 갯수를 늘리거나 줄이고 싶음
- AutoScaling을 위해, 자원을 모니터링할 메트릭서버를 설치해야 함
💡Metrics Server
✅ 헷갈렸던 부분 : Metrics Server도 CNI 플러그인 같은 역할을 해서, control-plane과 data-plane에 설치가 돼야 하는 것인 줄 알았음
➡️ 하지만, Metrics Server는 Control Plane에 설치된다기보다, 쿠버네티스 클러스터 안에 배포되는 Deployment
✅ 스케줄링되는 노드가 어디든 Pod 형태로 돌아감 ➡️ Worker Node에도 배포될 수 있음
✅ 역할 : kubelet으로부터 메트릭을 수집해서 API Server에 제공
3. 메트릭스 서버 설치 파일 다운로드
root@master-250410:~/mani/hpa# curl -Ls https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml -o metric.yml
root@master-250410:~/mani/hpa# ls
metric.yml res.yml
4. 메트릭스 서버 설치 파일 수정
- kubelet-insecure-tls
- 목적 : metrics-server가 각 노드의 kubelet에 매트릭 데이터를 요청할 대, TLS 인증서 검증을 무시하는 옵션
➡️ kubelet은 보안상 HTTPS로 메트릭을 제공
➡️ 대부분의 kubelete은 자체 서명된 인증서(self-signed cert)를 사용
➡️ metrics-server는 kubelet과 통신할 때, 인증서 유효성 검사를 진행
👉 kubelet이 self-signed 인증서를 사용하면 "신뢰할 수 없는 인증서"라고 에러가 나서 메트릭을 가져올 수 없음 - 그래서 인증서 검증을 생략해서 통신 에러 방지❗
- 목적 : metrics-server가 각 노드의 kubelet에 매트릭 데이터를 요청할 대, TLS 인증서 검증을 무시하는 옵션
- --kubelet-preferred-address-types=InternalIP
- 목적 : kubelet과 통신할 때, 어떤 IP 주소를 우선 사용해야 하는지를 정함
➡️ 쿠버네티스 노드는 여러 종류의 주소를 가지고 있음(ExternalIP, hostname 등...)
➡️ 실습이나 클라우드 환경에서는 노드의 hostname이 외부에서 해석되지 않을 수 있기 때문
➡️ metrics-server가 hostname을 먼저 사용하려고 시도하다가, 노드에 접근하지 못해서 메트릭 수집 실패❗
👉 노드의 InternalIP를 우선 사용하도록 설정해서 오류 방지❗
- 목적 : kubelet과 통신할 때, 어떤 IP 주소를 우선 사용해야 하는지를 정함

5. 메트리스 서버 설치
root@master-250410:~/mani/hpa# kubectl apply -f metric.yml
serviceaccount/metrics-server unchanged
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader unchanged
clusterrole.rbac.authorization.k8s.io/system:metrics-server unchanged
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader unchanged
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator unchanged
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server unchanged
service/metrics-server unchanged
deployment.apps/metrics-server created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
6. 메트릭스 서버 설치 확인

💡 리소스 제한 설정 이유
1️⃣ Pod가 자원을 과도하게 사용하는 것 방지
- 컨테이너는 "호스트 OS 자원을 공유"하는 구조 ➡️ Pod에 리소스 제한을 주지 않으면, 프로세스가 무한정 CPU, 메모리를 쓸 수 있음
- 만약 하나의 Pod가 과도하게 메모리를 먹으면, 노드 전체가 OOM(Out Of Memory) 크래시 날 수도 있음
- 제한을 설정해서 과도한 자원 점유 방지
➡️ 다른 Pod들이 정상적으로 살아남을 수 있도록 보호
2️⃣ 자원의 공정한 분배
- 쿠버네티스는 여러 Pod를 한 노드에 여러 개 띄워서 자원을 나눠 사용
- 제한을 걸어주면:
- 특정 Pod가 CPU, 메모리를 독점하지 않음
- 모든 Pod가 균등하게 자원을 쓰도록 보장 가능
- 다같이 먹는 피자를 인원수대로 잘라주는 것 같은 개념
3️⃣ 스케줄링 최적화
- Pod에 requests 값을 설정해두면
- 쿠버네티스 스케줄러가 "이 Pod는 최소 얼마 자원이 필요하다"를 인식하고
- 적절한 노드에 배치할 수 있음
- 요청한 자원이 없는 노드에는 배포하지 않아서 과부화로 인한 충돌을 미리 방지
4️⃣ 예측 가능한 성능 보장
- 리소스를 제한해두면, 시스템은 예측 가능한 자원 범위 내에서만 동작
- 부하가 갑자기 몰려도, 다른 Pod 성능에 미치는 영향을 최소화 가능
- 안정성 있는 서비스 운영이 가능
7. 리소스 제한 pod 설치
7-1. Pod - manifest file 정의
root@master-250410:~/mani/hpa# vi res.yml
apiVersion: v1
kind: Pod
metadata:
name: live-pod
labels:
app: live-nginx
spec:
containers:
- name: nginx
image: 61.254.18.30:5000/nginx
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
7-2. Pod 생성
root@master-250410:~/mani/hpa# kubectl apply -f res.yml
pod/live-pod created
8. 리소스 자원 사용량 조회
kubectl top pod
- 메트릭스 서버가 설치되면 kubectl top pod 명령을 쓸 수 있음
➡️ 리소스의 자원 사용량 조회 가능

9. Pod 배포 설정 - Service + Deployment
- 부하를 줘서 AutoScaling 되는 것을 확인하고자 함
- 리소스를 낮춰서 Deploy & SVC 생성
root@master-250410:~/mani/hpa# vi hpa-deploy.yml
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 # Pod 개수 : 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
💡 HPA를 왜 Deployment로 구현하는가?
- HPA는 Pod의 수를 자동으로 늘리고 줄이는 기능
➡️ Pod 개수를 관리하려면 기준이 필요한데, 이때 기준이 Deployment
왜 Deployment로 구현해야 할까?
1️⃣ Deployment는 ReplicaSet을 관리하는 상위 객체
- Deployment는 Pod의 수(Replicas)를 선언하는 컨트롤러
- Pod를 직접 관리하지 않고, 항상 ReplicaSet을 통해 Pod 개수를 관리함
- HPA는 Deployment.spec.replicas 값을 자동으로 수정해서 Pod를 늘리거나 줄임
✅ 여기서 질문! - Pod의 수 ➡️ 즉, ReplicaSet으로 Pod의 수를 선언하면 되는 거 아니야?
ReplicaSet은 단순히 Pod 개수 유지를 하는 역할로, HPA 대상 스케일링이 가능하지만, Pod 복제만 담당
➡️ 이중화, 복제, 전략적 배포(노드의 리소스에 따라 Pod 배포) 불가능
2️⃣ HPA는 Pod가 아니라 Controller를 대상으로 함
- HPA는 Pod가 아니라 Deployment를 감시하고 스케일링함
- Pod가 직접 생성된 경우 (kind:Pod)에는 HPA가 사용할 수 없음
- Deployment, StatefulSet, ReplicaSet 같은 컨트롤러가 관리하는 자원만 스케일링 가능
3️⃣ Deployment의 목적 = 자동 복제 + 롤링 업데이트
- Deployment는 Pod 개수를 유지하려고 노력함
- HPA는 그 값을 동적으로 수정하는 역할을 함
- Deployment : Pod 배포, 버전 관리, 고가용성 유지, replicas 선언
- HPA : CPU/메모리 등 리소스 사용량을 기반으로 replicas 수 자동 수정
만약 Pod만 사용하면?
- Kind: Pod로 직접 배포된 Pod는 HPA가 컨트롤할 수 있는 방법 ❌
- Pod는 스스로 복제하거나 갯수 유지를 할 수 없음
- Deployment가 있어야 kubectl scale도 되고, HPA도 자동으로 컨트롤 가능
10. Pod 배포
root@master-250410:~/mani/hpa# kubectl apply -f hpa-deploy.yml
service/svc-hpa created
deployment.apps/hpa-dep created

11. 명령어로 PHA 배포
- CPU 사용량이 50 % 이상일 때, 스케일링을 할 것이고, 최소 1 ~ 최대 5개로 구성
root@master-250410:~/mani/hpa# kubectl autoscale deploy hpa-dep --min=1 --max=5 --cpu-percent=50
12. manifest file로 PHA 정의 - Pod 개수 자동조절 정책
root@master-250410:~/mani/hpa# 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
13. HPA 생성
root@master-250410:~/mani/hpa# kubectl apply -f as.yml
horizontalpodautoscaler.autoscaling/hpa-nginx created

14. 부하 테스트
- 부하를 줄 ClusterIP

- 부하 부여
i=1; while true; do sleep 0.001; echo $((i++)) `curl -s <svc의 ClusterIP>`;done
15. 부하테스트 결과 확인
- Pod 개수가 최대 개수(max replicas)로 늘어난 것을 확인 가능


16. 부하 중단
- Pod 개수 : 5 ➡️ 1 수정 (Min Replicas)

17. hpa 상태 확인
kubectl get hpa


18. HPA 삭제

- hpa에서 최소 1개의 Pod라고 정의했기 때문에, 1개만 남았음
➡️ spec.replicas=3 자체가 spec.replicas=1로 변경된 걸 확인 가능
👉 Deployment이 replicas = 1로 변경되어 HPA가 삭제되어도 Pod는 1개로 유지됨을 의미 - kubectl delete hpa hpa-nginx ➡️ 오토스케일러 삭제

- 만약에 노드를 오토스케일링하고 싶다면, AWS에는 카펜터(karpenter)를 통해 가능하다.
실습 - 01
문제
https://github.com/pcmin929/sb_code 이 스프링부트 앱을 여러분들의 쿠버네티스 클러스에 배포하여
ilove.k8s.com 으로 접속했을 때 앱이 뜨도록 해보세요.
또한, ilove.k8s.com/web 으로 접속했을 때, readinessProbe를 통해
/healthz 경로로 헬스체크를 하는 간단한 httpd 웹서버를 띄워보세요.
위 두 개의 앱은 오토스케일링 되어야 한다.
풀이
1. sb_code 소스코드 다운로드
root@master-250410:~/mani/hpa# mkdir exam01
root@master-250410:~/mani/hpa# cd exam01/
root@master-250410:~/mani/hpa/exam01# git clone https://github.com/pcmin929/sb_code
Cloning into 'sb_code'...
remote: Enumerating objects: 531, done.
remote: Counting objects: 100% (352/352), done.
remote: Compressing objects: 100% (96/96), done.
remote: Total 531 (delta 170), reused 298 (delta 151), pack-reused 179 (from 1)
Receiving objects: 100% (531/531), 35.92 MiB | 9.07 MiB/s, done.
Resolving deltas: 100% (215/215), done.
2. 이미지 정의 & 빌드 & Push
root@master-250410:~/mani/hpa/exam01# vi Dockerfile
FROM openjdk:8
RUN apt update -y && apt install -y maven
WORKDIR /
COPY sb_code sb_code
RUN cd sb_code && mvn clean package
WORKDIR /sb_code/target
CMD ["java","-jar","springbootApp.jar"]
root@master-250410:~/mani/hpa/exam01# docker build -t etoile0320/spring:1 .
[+] Building 1.1s (10/10) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 227B 0.0s
=> [internal] load metadata for docker.io/library/openjdk:8 1.1s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/6] FROM docker.io/library/openjdk:8@sha256:86e863cc57215cfb181bd319736d0baf6 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 5.41kB 0.0s
=> CACHED [2/6] RUN apt update -y && apt install -y maven 0.0s
=> CACHED [3/6] COPY sb_code sb_code 0.0s
=> CACHED [4/6] RUN cd sb_code && mvn clean package 0.0s
=> CACHED [5/6] WORKDIR /sb_code/target 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:982d6b1b28163235a15ec2e20d08452a12b747f435166feb5ef529e 0.0s
=> => naming to docker.io/etoile0320/spring:1 0.0s
root@master-250410:~/mani/hpa/exam01# docker push etoile0320/spring:1
The push refers to repository [docker.io/etoile0320/spring]
5f70bf18a086: Mounted from etoile0320/mynginx
e555f105c919: Pushed
258fa15dce80: Pushed
5b357aae65d8: Pushed
6b5aaff44254: Mounted from library/openjdk
53a0b163e995: Mounted from library/openjdk
b626401ef603: Mounted from library/openjdk
9b55156abf26: Mounted from library/openjdk
293d5db30c9f: Mounted from library/openjdk
03127cdb479b: Mounted from library/openjdk
9c742cd6c7a5: Mounted from library/openjdk
1: digest: sha256:5d2e896da6f7f9a777a89da72d65ffed30b5aebaad988c5c18e388a6f2948957 size: 2638
3. Spring - Pod
3-1. Spring - Pod 정의
root@master-250410:~/mani/hpa/exam01# vi spring-dep.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hpa-spring-dep
spec:
replicas: 3
selector:
matchLabels:
app: hpa-spring
template:
metadata:
labels:
app: hpa-spring
spec:
containers:
- image: 61.254.18.30:5000/bo-spring:1
name: spring-con
readinessProbe:
httpGet:
path: /
port: 8085
initialDelaySeconds: 3
periodSeconds: 5
resources:
requests:
cpu: 100m
limits:
cpu: 200m
3-2. Spring - Pod 배포
root@master-250410:~/mani/hpa/exam01# kubectl apply -f spring-dep.yml
3-3. Spring - Pod 정상 작동 확인

4. Spring - Service
4-1. Spring - Service 정의
root@master-250410:~/mani/hpa/exam01# vi spring-svc.yml
apiVersion: v1
kind: Service
metadata:
name: svc-spring-hpa
spec:
selector:
app: hpa-spring
ports:
- port: 80
targetPort: 8085
4-2. Spring Service 배포
root@master-250410:~/mani/hpa/exam01# kubectl apply -f spring-svc.yml
4-3. Spring - Service 정상 작동 확인

5. Spring - HPA
5-1. Spring - HPA 정의
root@master-250410:~/mani/hpa/exam01# vi spring-as.yml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: hpa-spring-sa
spec:
maxReplicas: 5
minReplicas: 1
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: hpa-spring-dep
targetCPUUtilizationPercentage: 50
5-2. Spring - HPA 배포
root@master-250410:~/mani/hpa/exam01# kubectl apply -f spring-as.yml
5-3. Spring - HPA 정상 작동 확인

6. nginx - Pod
6-1. nginx - Pod 정의
root@master-250410:~/mani/hpa/exam01# vi nginx-dep.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: index
data:
index.html: |
i love k8s:)
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hpa-nginx-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
volumeMounts:
- name: vol-index
mountPath: /usr/share/nginx/html/healthz
readinessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 3
periodSeconds: 5
resources:
requests:
cpu: 100m
6-2. nginx - Pod 배포
root@master-250410:~/mani/hpa/exam01# kubectl apply -f nginx-dep.yml
6-3. nginx - Pod 작동 확인

7. nginx - Service
7-1. nginx - Service 정의
root@master-250410:~/mani/hpa/exam01# vi nginx-svc.yml
apiVersion: v1
kind: Service
metadata:
name: svc-nginx-hpa
spec:
selector:
app: hpa-nginx
ports:
- port: 80
targetPort: 80
7-2. nginx - Service 배포
root@master-250410:~/mani/hpa/exam01# kubectl apply -f nginx-svc.yml
7-3. nginx - Service 정상 작동 확인


8. nginx - HPA
8-1. nginx - HPA 정의
root@master-250410:~/mani/hpa/exam01# vi nginx-as.yml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: hpa-nginx-sa
spec:
maxReplicas: 5
minReplicas: 1
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: hpa-nginx-dep
targetCPUUtilizationPercentage: 50
8-2. nginx - HPA 배포
root@master-250410:~/mani/hpa/exam01# kubectl apply -f nginx-as.yml
8-3. nginx - HPA 정상 작동 확인


9. ingress
9-1. ingress 정의
root@master-250410:~/mani/hpa/exam01# vi ingress.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: ilove.k8s.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc-spring-hpa
port:
number: 80 #서비스의 포트
- path: /web
pathType: Prefix
backend:
service:
name: svc-nginx-hpa
port:
number: 80 #서비스의 포트
:
9-2. ingress 배포
root@master-250410:~/mani/hpa/exam01# kubectl apply -f ingress.yml
9-3. ingress 생성 확인

10. 작은 DNS 수정
root@master-250410:~/mani/hpa/exam01# vi /etc/hosts
127.0.0.1 localhost
127.0.1.1 ubuntu-tem
# kubectl get svc -n ingress-nginx에서 나왔던 주소
# ingress-controller 주소
211.183.3.150 ilove.k8s.com
11. 결과 확인


control plane 삼중화
- etcd를 동기화하기 위해서, 메인 etcd를 선출
➡️ 홀수 개 만큼 control plane이 존재해야 동률이 나오지 ❌
➡️ Contorl Plane은 홀수 개로 구성되어야 함
HAproxy 실습
1. HAproxy 서버 생성 - haproxy
- 기존 우분투 템플릿 복제
- IP : 211.183.3.50/24
- 호스트명 수정

2. haproxy 패키지 설치 - haproxy
root@haproxy:~# apt update -y
root@haproxy:~# apt install -y haproxy
3. haproxy 설정 - haproxy
3-1. haproxy 설정 파일 백업
root@haproxy:~# cp /etc/haproxy/haproxy.cfg .
3-2. haproxy 설정파일 수정 - 타겟 그룹 & 주소 설정
root@haproxy:~# 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

4. m1 생성 & 설정 - m1
4-1. Worker2 노드 복제
- master / worker1 노드 ➡️ suspend, worker2 노드 ➡️ shut down


4-2. IP 설정

4-3. 호스트 네임 설정
root@m1-250418:~# hostnamectl set-hostname m1-250418
4-4. fstab 마운트 해제
root@m1-250418:~# vi /etc/fstab
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>
# / was on /dev/ubuntu-vg/ubuntu-lv during curtin installation
/dev/disk/by-id/dm-uuid-LVM-FbCcNiwxfzYCT4sOGiAUnUv9tzOJziSZZFLADjshFr2WZanOkLoQpew9zAZmxLoj / ext4 defaults 0 1
# /boot was on /dev/sda2 during curtin installation
/dev/disk/by-uuid/ac919480-e104-499d-ae25-8ce7c4a5965e /boot ext4 defaults 0 1
#/swap.img none swap sw 0 0
# 211.183.3.100:/shared /shared nfs defaults 0 0
4-5. 클러스터 초기화 - kubeadm reset
- 기존 클러스터(worker2에서 포함되어 있던 클러스터)에서 탈퇴
root@m1-250418:~# kubeadm reset --cri-socket unix:///run/containerd/containerd.sock
# 원본
kubeadm reset --cri-socket unix:///run/containerd/containerd.sock
5. m2, m3 생성 ➡️ m1 복제 후 IP & 호스트명 수정 - m2, m3
- m2 : 211.183.3.102/24
- m3 : 211.183.3.103/24

6. haproxy 재시작 - haproxy
- 설정 파일(haproxy.cfg)을 바꾸거나 환경을 수정 ➡️ 변경사항 반영을 위해 haproxy 재시작
root@haproxy:~# systemctl restart haproxy
7. kubeadm 초기화 - m1
- contorl-plane-endpoint=211.183.3.50
➡️ haproxy의 주소
root@m1-250418:~# 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
# 원본
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
- 클러스터 초기화 ➡️ 2개의 토큰 생성

💡왜 m1에서만 kuubeadm 초기화를 진행하는가?

- 해당 명령어는 쿠버네티스 클러스터의 "초기 설정"으로, /etc/kubernetes 안에 인증서, 설정 파일이 생성됨
➡️ etcd 클러스터의 첫 멤버(m1)가 생성됨 ➡️ Control Plane 구성요소가 기동됨
👉 초기화용 Token, Certificate Key를 생성함 - 초기화를 통해 생성한 Token을 가지고, 다른 Control Plane(m2, m3)를 클러스터에 Join함
8. 마스터용 토큰 ➡️ m2와 m3에 실행
- 마스터용 토큰 + --cri 옵션 입력
- --cri 옵션 : --cri-socket unix:///run/containerd/containerd.sock
root@m3-250418:~# kubeadm join 211.183.3.50:6443 --token 38c2k5.mjfc8sh6slx1mar2 --discovery-token-ca-cert-hash sha256:4cbdafa947854b1826d7a53a169ed55b280ac79a81444f600c9d5e97f33f2b3c --control-plane --certificate-key 99997a7109e61bedf3d8b96eb3d060d0d9c91037cfbba2043d354e31717ddcea --cri-socket unix:///run/containerd/containerd.sock

✅ haproxy 서버에서 스스로에게 kubectl명령을 치기 위해 kubectl 명령어 설치 + 클러스터의 config 파일 필요
- 클러스터의 config 파일 ➡️ m1의 config 파일(/etc/kubernetes/amdin.conf)
9. 패키지 다운로드 - haproxy
- HTTPS 기반 저장소에서 안전하게 패키지를 다운로드하고 curl을 사용하기 위한 패키지 설치
root@haproxy:~# apt-get install -y apt-transport-https ca-certificates curl
10. GPG Key(무결성 검증) 생성 - haproxy
10-1. GPG Key 저장 디렉토리 생성
root@haproxy:~# mkdir -p /etc/apt/keyrings
10-2. GPG Key 공개키 다운로드 & 바이너리로 변환 ➡️ 저장
root@haproxy:~# curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
11. Kubernetes 저장소 패키지 설치 - haproxy
- GPG Key로 서명된 것만 Kubernetes 저장소 패키지에서 다운로드
root@haproxy:~# 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
deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /
12. APT 저장소 목록 업데이트
root@haproxy:~# apt-get update
13. kubectl 명령어 설치 - haproxy
13-1. kubectl 명령어 설치
root@haproxy:~# apt-get install -y kubect
13-2. kubectl 업그레이드 제외
root@haproxy:~# apt-mark hold kubectl
14. 클러스터의 config 파일 설정 - haproxy
14-1. m1의 config 파일 복사

14-2. 설정 파일 생성
root@haproxy:~# mkdir -p $HOME/.kube
root@haproxy:~# vi ~/.kube/config
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCVENDQWUyZ0F3SUJBZ0lJZjY0M2ZkLzhjaHN3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TlRBME1UZ3dPREk1TUROYUZ3MHpOVEEwTVRZd09ETTBNRE5hTUJVeApFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLCkFvSUJBUURDTWt0T2pBNjJvVklkWEFseGRZK3RXUmN5ODRxY0VMeVk5dm5DWm1ISzZJTjVjM2VZOTdSVkc3THAKV2tMUDhtMzlrd0xpSldzWVJzY3gwK3ZnMkt1RlZTcGJkZjRhVDgydHBKRldSWmNLOThUS251M2QzQUl1cEd6YQp2SlhBZmRtcHNkNm5FaXN4dkJXS08zUXBLWkMycHlEakFUb2JoeVl4dEFkWVJrT2ticlRpREM4SE5LdnBWSGQrCnJaRDFseFVicmRLTkxtUXhKdWpHRVdWZXArN3EzZ1VPWmFPMS9CZXBHbUd4RktyMHU5QjUreEd2Z2dEanJBNGgKL3Z0UTIxN0xUNGN1S05HeU9ldG9kWEdWd0hGalNGdjZrdXNkS1pKZk4vQTBnVVlLOG1ydVFrSzRVN0NZTEJ5MgpEbWgzWms3RWkzdTBEVXl1cVBuSEVkbU9OTktiQWdNQkFBR2pXVEJYTUE0R0ExVWREd0VCL3dRRUF3SUNwREFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUIwR0ExVWREZ1FXQkJTZllBcW53YitQMlFzU3hVODd0Q2R5dDhiQVdEQVYKQmdOVkhSRUVEakFNZ2dwcmRXSmxjbTVsZEdWek1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQUdEbTNZMGVWYQpuaUM0VzE2RUkyci9OWU5PYlhZckd4dVJxVkhEeDlvSTRKMnVwc1E5UjNkRTZxeFZ5dWcrSjY3N0JPTU5SQ0wvCjFoaDV4ZzlWZzhRYWUvb0hLR05SbExweTZEMUJXZGQwNXVFc2VtdlRUVUxCa2N2aDFxaXg5cmJNWW9uQ1pRK3YKVnV5N1doTFM4OEJGNTBmOG01MW5LWUNIcEh3cFVGRTdwWVM3b243UHlvbEtoZzlVS3prbHpmcmdKc3cyeDluOQo1c3pHY0tpV2NxTVI5dnN5TmhHM0lmaWRxbnZqWEZJZ0lneHE0MWdEQTFueWFJdFdqbytIWFovcEgvVFFrbkJNCnpxYVZCeGt4R0pCbTZnZ3dib2RCZDVXSTVFSTZpMXE0eWlhdXRuTkk3MzVJQkUxYWc3bnlYeFpyMVdSOXovL2oKa1RIMGtqbms4M0dZCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
server: https://211.183.3.50:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLVENDQWhHZ0F3SUJBZ0lJVEhRN3NSem9mVGt3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TlRBME1UZ3dPREk1TUROYUZ3MHlOakEwTVRnd09ETTBNRFJhTUR3eApIekFkQmdOVkJBb1RGbXQxWW1WaFpHMDZZMngxYzNSbGNpMWhaRzFwYm5NeEdUQVhCZ05WQkFNVEVHdDFZbVZ5CmJtVjBaWE10WVdSdGFXNHdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDY2Z4dUQKTzFFSjZjWmxuYUFTdVNCbmhZaUkwTnl1QjBEVFF4aHZLdk01ZVU1d2tUM09RK0c2aWFHZUhtSEQ5MThxY0R5YwpreFJzdFk1UnB6UjNWS09WN1Jvby8zNHhoUVhaOXJJM3FEWjJZUFJ2eDI2YklycFNwd01aZEpyVGNIRU1maHNHCkNyLzJMUUZYeTZnMVk1N2RScjl1MkhtNmxYQXdQZUdMemNvUm50UDBrWEkvTFErQ3Vac01rV2NjbmtXUndmOWQKMVpuSkhsS3FvNi80M2ZsVzBaYUVPcWlxZlJuc0ovWWorMjFPSGhZLytDK0l3dmlUSnFFSHlHVGdRUkpDMHY4MQp1N2JXOXRzVmxOcTJveXlzQUJnRXQrWktiSGUwMXRSY0VjSU1UeU14cTVTVEhwME96Nyt4YlhvM1N2TUE1aFRHCmE2L1YyZU1jdHdqejljQ0JBZ01CQUFHalZqQlVNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUsKQmdnckJnRUZCUWNEQWpBTUJnTlZIUk1CQWY4RUFqQUFNQjhHQTFVZEl3UVlNQmFBRko5Z0NxZkJ2NC9aQ3hMRgpUenUwSjNLM3hzQllNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUJZNnJNUVBOVjBSb2I4bzMxSnB5NnFwMUQ0Cm9WeXRHcnVabWVsbncwUWM2N241aURFQUFHU3MzTUtTOXVlekRxM1Z5THl5OGsyTFYzWXFVanprcGoxVE1ZOEQKa3NwTlhtOXZBelVCbHlXYTk0b3JvajV0UDl1Nk9mRFQ3V2RuMTJ5b3NQeFgxWU11MXYrVDF4L29udy9xbUxyYQpHRTRrRU5XaCs5N1BhYS82Q3BtT3MzeEpkamJJd2NVM1hNaEtjZkxaMVNaNUY0SGpUNEhIaTIrcG9YcEtXc053CjlYNjdid3JMWTVIT3UvVGttaHNFTkorUlN0cDNiNGNmZ2YxWkE0VWIyTVdkQ3dOaWptZDNLcWltNXBrS0JRalgKei91enFPR293RmFwQks0R3Y5K09sY1VsWnVvM3FaaEl1RnVkU21GczNWWE15WEhZUDhLQ3U1N256QldXCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBbkg4Ymd6dFJDZW5HWloyZ0Vya2daNFdJaU5EY3JnZEEwME1ZYnlyek9YbE9jSkU5CnprUGh1b21obmg1aHcvZGZLbkE4bkpNVWJMV09VYWMwZDFTamxlMGFLUDkrTVlVRjJmYXlONmcyZG1EMGI4ZHUKbXlLNlVxY0RHWFNhMDNCeERINGJCZ3EvOWkwQlY4dW9OV09lM1VhL2J0aDV1cFZ3TUQzaGk4M0tFWjdUOUpGeQpQeTBQZ3JtYkRKRm5ISjVGa2NIL1hkV1p5UjVTcXFPditOMzVWdEdXaERxb3FuMFo3Q2YySS90dFRoNFdQL2d2CmlNTDRreWFoQjhoazRFRVNRdEwvTmJ1MjF2YmJGWlRhdHFNc3JBQVlCTGZtU214M3ROYlVYQkhDREU4ak1hdVUKa3g2ZERzKy9zVzE2TjByekFPWVV4bXV2MWRuakhMY0k4L1hBZ1FJREFRQUJBb0lCQUVHaVZZbWVjUWgxVVU0QQo0OGUyZU02eUJHZE5JYUNqVGg3TWZ3end1SDJjVUxlSlVxQ1ZlN0JlVkxnYUNlckVidGMvcDB3THEzOUVUZUlVCi9ENG44MHZIMnpiaW9LeG9HK0lrUXU1dzBCYXA1eHFTUytNb2wzaGVyMEFYMVc5a015V0lKaEZNcE9HOFVsbmUKQWpnU0Jlakw2VEcxL0tleVVSRUtndk85WlVncDZ0Yk8rc2FLZmZhclh6WUFZMW5xTzd1QUVlMWJNaEJRdUs5ZwpjY0taT1RhUkxkbGNlUVFCVEM0b04zU3RoR2lzT2VkWGVFd0d4SDB4WExIcGFnOEwxcjdHRWtvSzNFUnRtUkEvCmlyaThYSHd1eER5Z1F0NzUydXhYME9xZ1YwRDA2UkdsQTI3cGpBcGlreGJHcUNoWHdaaEVVUmtSczdTWlFiNHAKQy81SUhJRUNnWUVBeXNKUlFVT1MzMEJ6N1hyOWJxTVc4RWwrSk9vYTFWNVczcW1GRkM4Vjc1VHFWN0xHanRzZAplanBuK1h0NFJGcFhsMUNncWNSV0dHbTU0N0xsZkduaUZLT3Foa25aa2FKOEFETmdUajBxSmNZU1crb0JDNVdNCk4yOVZPQVlQNnFjM0gxRjRDejh4RE9vVEVzKzNYd1A3N0NBRmx1VnJHSlNKaEpsVG1xemE3d2tDZ1lFQXhaYjQKNDNWOWJEWGtGcnBJZjFGTCtGVXRCV210eFVLSk9qaHU1dDNhVlExcWpFUllrTXlUa3h0cnhsNXdqemRqVEZQYwowMUdtZkhlSUxkNDZKRVdDK3phSm14Q2JQdHltMXZSaFZ0ZkdTSHNwYnJzT2U4bDljMnZWeThiSk51TUlyekJ5CjByMTdXUlNzbXNOVS9kVjdZVUozMUNzQXFIdWcwYU03L3B4MHE3a0NnWUVBeDBkTXpUUTQraXRDeFRtSU5HRWUKZm5QOUF4TUQ1SW1nSDUvRktCMVBGZlhxak44c3YrTWppYW8xM3NJM1poYlUxK2Rxd1BBekhqTnJmQnVyNlNlNApDRWtEcEpDWXdjWk0wWFd0UmJoZjRGaFlXdllXcU9nR3M4VThvSjkwclZCRG9RaFZUOWgvd1EyZVNYTFY2eERqClhTUHIybThKWDFNK0JaRWMxbnpsZ09FQ2dZRUFnMFh6WTROS2FkdEFCNDJKM3ZTUEtaVEZUWVJSaSszUnFCbVkKTE5BV1gwMkRqVjlYREJTdXN4eVR0UDVIZ0E4SGJNMkd0K3JXVm5rL3cyR1NkVWl0WmVOczl0WElucklRTWwyNApVZThYY0U1TFQ2TDlVMmFoYjA2a2d6YzF0YjZPcFgzbHUzZGgvT1FNYk9IN2xJMEI1TE01VTMraWQwMXpvZlAyClJ3bUJSaGtDZ1lCQVByYTlkRTVIRy9IVjI5UXhNQ0ZyRm1hWG03MWNEM0RQamEzOTFKQW9tTThUK0hoQ3c4K2gKcXpBUGs0Rno2ZGVuOHJxSDVYZmdoMllGbXkyMm8yNm0xZnY2SDBLOW9JL21jaGhEd3Z3MlBuTmhqM0RobWZPYwpaVmMrWW05Y3BUc2ZqbjMrbFdvR3hibksrT3dZME1EZy96ZDhtRWYrdDZzakYzdlF3N2RtbWc9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
root@haproxy:~# sudo chown $(id -u):$(id -g) $HOME/.kube/config
15. 마스터용 클러스터에 포함된 거 확인 - haproxy
root@haproxy:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
m1-250418 Ready control-plane 11m v1.30.11
m2-250418 Ready control-plane 6m46s v1.30.11
m3-250418 Ready control-plane 5m55s v1.30.11
16. m1 노드 Spuspend

17. 마스터용 클러스터 확인 - m1 노드 비활성화(Suspend)
- 일정 시간이 지나면, 메인 Control Plane을 선출

👉 Control Plane의 HAproxy 구성할 때는 반드시 Control Plane의 개수를 홀수개로 가져가야 한다.
'CS > Kubernetes' 카테고리의 다른 글
[Kubernetes] 12. Helm(헬름) & Chart(차트) (2) | 2025.04.22 |
---|---|
[Kubernetes] 11. Node Selector, Node Affinity, Taints & Tolerations (0) | 2025.04.22 |
[Kubernetes] 08. Container Health Check(컨테이너 헬스체크) - livenessProbe, readinessProbe (1) | 2025.04.17 |
[Kubernetes] 07. 자율과제 - Dynamic Provisioner (0) | 2025.04.17 |
[Kubernetes] 06. RBAC, Dynamic Provisioner (0) | 2025.04.16 |