Kubernetes 기초
# 인증 토큰 생성
kubectl create token admin --namespace kubernetes-dashboard
1. 네임스페이스
Kubernetes를 시작하면 네 개의 초기 네임스페이스가 자동으로 생성됩니다.
- default: 새로운 클러스터에서 네임스페이스를 생성할 필요 없이 즉시 사용 가능한 기본 네임스페이스입니다.
- kube-node-lease: 각 노드와 연관된 Lease(임대) 객체를 포함합니다. 노드 임대를 통해 kubelet이 하트비트를 전송할 수 있어 컨트롤 플레인이 노드 장애를 감지할 수 있습니다.
- kube-public: 인증되지 않은 클라이언트를 포함한 모든 클라이언트가 읽을 수 있습니다. 클러스터 전체에서 표시되어야 하는 특정 리소스를 위해 예약되어 있으며, 클러스터 사용을 위한 것입니다.
- kube-system: Kubernetes 시스템이 생성한 객체에 사용됩니다.
주요 명령어
# 네임스페이스 조회
[root@k8s-master ~]# kubectl get ns
NAME STATUS AGE
default Active 46h
kube-node-lease Active 46h
kube-public Active 46h
kube-system Active 46h
kubernetes-dashboard Active 46h
# 특정 네임스페이스下的 파드 조회 (미지정 시 default)
kubectl get -n kube-system pod
# 네임스페이스 생성
kubectl create ns myproject
# 네임스페이스 삭제 (하위 리소스도 함께 삭제됨 - 주의 필요)
kubectl delete ns myproject
YAML을 사용한 생성
[root@k8s-master ~]# vim myproject.yaml
[root@k8s-master ~]# cat myproject.yaml
apiVersion: v1
kind: Namespace
metadata:
name: myproject
[root@k8s-master ~]# kubectl apply -f myproject.yaml
namespace/myproject created
YAML 파일 활용
# YAML 파일로 리소스 생성
# 차이점: create는 일회성 생성, apply는 수정 후 재적용 가능
kubectl create -f xxx.yaml
kubectl apply -f xxx.yaml
# YAML 파일로 리소스 삭제
kubectl delete -f xxx.yaml
# 리소스의 YAML 형식 정보 조회
kubectl get resource-name -o yaml
# 리소스의 YAML 파일을 직접 수정하고 적용
# 참고: 적용이 안 될 때는 delete 후 apply 사용
2. 파드
파드는 실행 중인 컨테이너 그룹입니다. 파드는 Kubernetes에서 가장 작은 배포 단위이며, 컨테이너화된 애플리케이션을 실행하는 리소스 객체입니다. 다른 리소스들은 모두 파드 기능을 지원하거나 확장하기 위해 사용됩니다.
참고사항:
각 파드에는 "Pause" 컨테이너라는 특수한 루트 컨테이너가 있습니다. 이 Pause 컨테이너의 이미지는 Kubernetes에 속하며, Kubernetes는 컨테이너를 직접 관리하지 않고 파드를 관리합니다.
애플리케이션 파드는 다중 프로세스 설계로, 하나의 파드에 여러 컨테이너가 있고 각 컨테이너가 플랫폼의 일부를 실행합니다.
파드 생성 및 사용
[root@k8s-master ~]# kubectl run webserver --image=nginx
pod/webserver created
[root@k8s-master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
webserver 0/1 ContainerCreating 0 18s
[root@k8s-master ~]# kubectl describe pod webserver
Name: webserver
Namespace: default
Priority: 0
Service Account: default
Node: k8s-node2/192.168.13.66
Start Time: Thu, 11 Apr 2024 15:18:52 +0800
Labels: run=webserver
Annotations: cni.projectcalico.org/containerID: 988a58cf1c04de31abadf12c9440fd8e19857be9a5bd79440b0893a70f153c2b
cni.projectcalico.org/podIP: 192.168.169.130/32
cni.projectcalico.org/podIPs: 192.168.169.130/32
Status: Running
IP: 192.168.169.130
IPs:
IP: 192.168.169.130
Containers:
webserver:
Container ID: docker://1a3ce0a1b4f470ba78c99bfae7f7558eb8c5aeebc180465011bd47bd36ecc173
Image: nginx
Image ID: docker-pullable://nginx@sha256:b72dad1d013c5e4c4fb817f884aa163287bf147482562f12c56368ca1c2a3705
Port: <none>
Host Port: <none>
State: Running
Started: Thu, 11 Apr 2024 15:20:46 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-qszgb (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
kube-api-access-qszgb:
Type: Projected
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 3m4s default-scheduler Successfully assigned default/webserver to k8s-node2
Normal Pulling 3m2s kubelet Pulling image "nginx"
Normal Pulled 70s kubelet Successfully pulled image "nginx" in 1m52.287s (1m52.287s including waiting)
Normal Created 70s kubelet Created container webserver
Normal Started 70s kubelet Started container webserver
# 대시보드에서도 상세 정보 확인 가능
# 로그 확인
kubectl logs webserver
YAML로 파드 생성
[root@k8s-master ~]# vim web-cre.yaml
[root@k8s-master ~]# cat web-cre.yaml
apiVersion: v1
kind: Pod
metadata:
name: webserver02
labels:
run: webserver02
spec:
containers:
- image: nginx
name: webserver02
[root@k8s-master ~]# kubectl apply -f web-cre.yaml
파드 내 애플리케이션 접근
# 파드 상세 정보 조회
# 기본적으로 default 네임스페이스의 파드 조회, -a 옵션으로 전체 조회
[root@k8s-master ~]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
webserver 1/1 Running 0 23m 192.168.169.130 k8s-node2 <none> <none>
webserver02 1/1 Running 0 9m2s 192.168.36.66 k8s-node1 <none> <none>
[root@k8s-master ~]# curl 192.168.169.130
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# IP와 포트로 파드 내 애플리케이션 접근
# 컨테이너 내부 접속 (docker 명령어와 유사)
kubectl exec -it webserver -- /bin/bash
하나의 파드에서 여러 컨테이너 실행
[root@k8s-master ~]# vim multi-container.yaml
[root@k8s-master ~]# kubectl apply -f multi-container.yaml
pod/multi-pod created
[root@k8s-master ~]# cat multi-container.yaml
apiVersion: v1
kind: Pod
metadata:
name: multi-pod
labels:
run: multi-pod
spec:
containers:
- image: nginx
name: nginx
- image: tomcat:8.5.92
name: tomcat
[root@k8s-master ~]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
webserver 1/1 Running 0 44m 192.168.169.130 k8s-node2 <none> <none>
webserver02 1/1 Running 0 29m 192.168.36.66 k8s-node1 <none> <none>
multi-pod 2/2 Running 2 (64s ago) 11m 192.168.169.131 k8s-node2 <none> <none>
# 192.168.169.131:80 (nginx) 및 192.168.169.131:8080 (tomcat) 접근 가능
파드는 작은 Linux 환경과 같습니다.
3. 디플로이먼트
여러 파드를 관리하기 위한 컨트롤러
서비스 오케스트레이션 문제를 해결하기 위해 Kubernetes 1.2 버전부터 디플로이먼트 컨트롤러가 도입되었습니다. 이 컨트롤러는 파드를 직접 관리하지 않고, 레플리카셋을 통해 간접적으로 관리합니다. 즉, 디플로이먼트가 레플리카셋을 관리하고 레플리카셋이 파드를 관리합니다.
디플로이먼트를 사용하면 파드에 다중 복제본, 자동 복구, 스케일링 등의 기능을 제공할 수 있습니다.
자동 복구 기능
# 디플로이먼트 생성
[root@k8s-master ~]# kubectl create deployment app-backend --image=nginx
deployment.apps/app-backend created
# 자동 복구 기능 확인
# app-backend 파드를 삭제하면 새 접미사의 파드가 자동 생성됨
[root@k8s-master ~]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
app-backend-5c48c5c8cd-mjvqn 1/1 Running 0 32s 192.168.36.67 k8s-node1 <none> <none>
[root@k8s-master ~]# kubectl delete pod app-backend-5c48c5c8cd-mjvqn
pod "app-backend-5c48c5c8cd-mjvqn" deleted
[root@k8s-master ~]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
app-backend-5c48c5c8cd-88tlv 1/1 Running 0 102s 192.168.36.68 k8s-node1 <none> <none>
# 디플로이먼트를 통해 삭제해야 함
[root@k8s-master ~]# kubectl get deploy -n default
NAME READY UP-TO-DATE AVAILABLE AGE
app-backend 1/1 1 1 6m29s
[root@k8s-master ~]# kubectl delete deploy app-backend -n default
deployment.apps "app-backend" deleted
다중 복제본 기능
[root@k8s-master ~]# kubectl create deployment replica-app --image=nginx --replicas=3
deployment.apps/replica-app created
[root@k8s-master ~]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
replica-app 3/3 3 3 20s
# 각 파드는 고유한 IP를 가짐
[root@k8s-master ~]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
replica-app-6cc66f8b5f-2d4gl 1/1 Running 0 111s 192.168.36.70 k8s-node1 <none> <none>
replica-app-6cc66f8b5f-7lzfj 1/1 Running 0 111s 192.168.36.69 k8s-node1 <none> <none>
replica-app-6cc66f8b5f-skd92 1/1 Running 0 111s 192.168.169.132 k8s-node2 <none> <none>
# 디플로이먼트와 파드의 매핑 방식
# 레이블의 해시 값을 통해 매핑
[root@k8s-master ~]# kubectl get replicaset --show-labels
NAME DESIRED CURRENT READY AGE LABELS
replica-app-6cc66f8b5f 3 3 3 5m8s app=replica-app,pod-template-hash=6cc66f8b5f
[root@k8s-master ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
replica-app-6cc66f8b5f-2d4gl 1/1 Running 0 5m15s app=replica-app,pod-template-hash=6cc66f8b5f
replica-app-6cc66f8b5f-7lzfj 1/1 Running 0 5m15s app=replica-app,pod-template-hash=6cc66f8b5f
replica-app-6cc66f8b5f-skd92 1/1 Running 0 5m15s app=replica-app,pod-template-hash=6cc66f8b5f
YAML으로 디플로이먼트 생성
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
run: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx-deployment
template:
metadata:
labels:
app: nginx-deployment
spec:
containers:
- image: nginx
name: nginx
# 사용 가능한 API 버전 목록
[root@k8s-master ~]# kubectl api-versions
admissionregistration.k8s.io/v1
apiextensions.k8s.io/v1
apiregistration.k8s.io/v1
apps/v1
authentication.k8s.io/v1
authorization.k8s.io/v1
autoscaling/v1
autoscaling/v2
batch/v1
certificates.k8s.io/v1
coordination.k8s.io/v1
crd.projectcalico.org/v1
discovery.k8s.io/v1
events.k8s.io/v1
flowcontrol.apiserver.k8s.io/v1beta2
flowcontrol.apiserver.k8s.io/v1beta3
networking.k8s.io/v1
node.k8s.io/v1
policy/v1
rbac.authorization.k8s.io/v1
scheduling.k8s.io/v1
storage.k8s.io/v1
v1
스케일링
[root@k8s-master ~]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 5h11m
[root@k8s-master ~]# kubectl scale deploy/nginx-deployment --replicas=5
deployment.apps/nginx-deployment scaled
[root@k8s-master ~]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/5 5 3 5h12m
자동 복구
worker 노드의 머신이 장애가 발생하면, 다른 머신에서 해당 서비스를 자동으로 시작합니다.
Kubernetes는 약 5분 동안 자동 장애 복구를 수행합니다.
롤링 업데이트 및 롤백
# 실시간 모니터링
kubectl get pod -w
# 업그레이드 또는_down그레이드
[root@k8s-master ~]# kubectl set image deployment/nginx-deployment nginx=nginx:1.19.2 --record
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/nginx-deployment image updated
[root@k8s-master ~]#
# 롤백
# kubectl rollout --help
# 배포 히스토리 확인
[root@k8s-master ~]# kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 <none>
2 kubectl set image deployment/nginx-deployment nginx=nginx:1.19.2 --record=true
3 kubectl set image deployment/nginx-deployment nginx=nginx:1.19.10 --record=true
# 특정 리비전 상세 정보
[root@k8s-master ~]# kubectl rollout history deployment/nginx-deployment --revision=2
deployment.apps/nginx-deployment with revision #2
Pod Template:
Labels: app=nginx-deployment
pod-template-hash=6fbbbfffd8
Annotations: kubernetes.io/change-cause: kubectl set image deployment/nginx-deployment nginx=nginx:1.19.2 --record=true
Containers:
nginx:
Image: nginx:1.19.2
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
# 이전 버전 또는 지정된 버전으로 롤백
[root@k8s-master ~]# kubectl rollout undo deployment/nginx-deployment --revision=2
[root@k8s-master ~]# kubectl rollout history deployment/nginx-deployment --to-revision=2
4. 서비스
지금까지 배포한 모든 애플리케이션은 브라우저에서 접근할 수 없습니다.
이전章节에서 설명한 바와 같이, 파드의 수명이 짧고 "생성 후 소멸"이라는 특성으로 인해 서비스 제공 파드의 IP 주소가频繁하게 변경됩니다. 서비스 접근 시 안정적인 IP 주소가 필요합니다. 이러한 요구 사항과 파드의 특성이 충돌하면서 서비스가 필요합니다.
서비스: 파드의 서비스 디스커버리 및 로드 밸런싱
# 3개의 nginx 생성 및 인덱스 파일 수정하여 구분
[root@k8s-master ~]# kubectl create deployment web-app --image=nginx --replicas=3
deployment.apps/web-app created
[root@k8s-master ~]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-app-5f989946d-76vll 1/1 Running 0 3m49s 192.168.36.76 k8s-node1 <none> <none>
web-app-5f989946d-pwxk2 1/1 Running 0 3m49s 192.168.169.144 k8s-node2 <none> <none>
web-app-5f989946d-tgk6q 1/1 Running 0 3m49s 192.168.169.145 k8s-node2 <none> <none>
[root@k8s-master ~]# curl 192.168.36.76
pod 111
[root@k8s-master ~]# curl 192.168.169.144
pod 222
[root@k8s-master ~]# curl 192.168.169.145
pod 333
서비스 노출 - kubectl expose
[root@k8s-master ~]# kubectl expose deploy web-app --port=80 --target-port=80
service/web-app exposed
[root@k8s-master ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d22h
web-app ClusterIP 10.96.31.78 <none> 80/TCP 44s
# 서비스 IP가 3개의 nginx에 매핑됨
[root@k8s-master ~]# curl 10.96.31.78
pod 222
[root@k8s-master ~]# curl 10.96.31.78
pod 222
[root@k8s-master ~]# curl 10.96.31.78
pod 222
[root@k8s-master ~]# curl 10.96.31.78
pod 333
[root@k8s-master ~]# curl 10.96.31.78
pod 111
[root@k8s-master ~]# curl 10.96.31.78
pod 333
[root@k8s-master ~]# curl 10.96.31.78
pod 333
로드 밸런싱 원리
레이블의 app 매개변수가 일치하는 파드를 찾아 로드 밸런싱을 수행합니다.
[root@k8s-master ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
web-app-5f989946d-76vll 1/1 Running 0 13m app=web-app,pod-template-hash=5f989946d
web-app-5f989946d-pwxk2 1/1 Running 0 13m app=web-app,pod-template-hash=5f989946d
web-app-5f989946d-tgk6q 1/1 Running 0 13m app=web-app,pod-template-hash=5f989946d
[root@k8s-master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d22h
web-app ClusterIP 10.96.31.78 <none> 80/TCP 5m36s
[root@k8s-master ~]# kubectl describe svc web-app
Name: web-app
Namespace: default
Labels: app=web-app
Annotations: <none>
Selector: app=web-app
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.96.31.78
IPs: 10.96.31.78
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 192.168.169.144:80,192.168.169.145:80,192.168.36.76:80
Session Affinity: None
Events: <none>
kubectl delete svc web-app
외부 노출
웹 서비스는 외부에 노출해야 하지만, Redis, SQL, MQ 등은 내부에서만 접근해야 합니다.
# type 기본값 - Kubernetes 내부 네트워크에서만 접근 가능 (ClusterIP)
# --type 옵션:
# ClusterIP, NodePort, LoadBalancer, ExternalName
# 기본값은 'ClusterIP'
# NodePort 타입으로 외부 노출
# 랜덤 IP가 할당됨 (다음章节에서 Ingress를 통해 통합 게이트웨이 설정)
[root@k8s-master ~]# kubectl expose deploy web-app --port=80 --target-port=80 --type=NodePort
service/web-app exposed
[root@k8s-master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d22h
web-app NodePort 10.96.50.186 <none> 80:31242/TCP 6s
# 컨테이너 접근용 도메인 (마이크로서비스에서 도메인으로 직접 접근 가능)
# curl web-app-default.svc
# 서비스 IP는 변경될 수 있지만 Kubernetes 도메인은 변경되지 않음