쿠버네티스 오브젝트는 쿠버네티스 시스템에서 영속성을 가지는 오브젝트이다. 쿠버네티스는 클러스터의 상태를 나타내기 위해 이 오브젝트를 이용한다. 구체적으로 말하자면, 다음같이 기술할 수 있다.
오브젝트를 생성하게 되면, 쿠버네티스 시스템은 그 오브젝트 생성을 보장하기 위해 지속적으로 작동한다.
생성이든, 수정이든, 또는 삭제든 쿠버네티스 오브젝트를 동작시키려면, 쿠버네티스 API를 이용해야 한다. 예를 들어, kubectl 커맨드-라인 인터페이스를 이용할 때, CLI는 여러분 대신 필요한 쿠버네티스 API를 호출해 준다.
오브젝트를 생성하기 위해 (직접이든 또는 kubectl을 통해서든) 쿠버네티스 API를 이용할 때, API 요청은 요청 내용 안에 JSON 형식으로 정보를 포함시켜 줘야만 한다. 대부분의 경우 정보를 .yaml 파일로 kubectl에 제공한다. kubectl은 API 요청이 이루어질 때, JSON 형식으로 정보를 변환시켜 준다.
# 쿠버네티스 자료 git 클론
git clone https://github.com/c1t1d0s7/goorm-8th-k8s
# 디렉터리 변경
cd ./goorm-8th-k8s/manifests/03_workload_pod/01_pod
# 파드 생성하는 방법 2가지
kubectl create -f myapp-pod.yaml
kubectl apply -f myapp-pod.yaml
# 파드 내용 확인
kubectl get pods
# 상세정보 확인, IP 정보, 어떤 노드에 배치되어있는지 확인가능
kubectl get pods -o wide
# 해당되는 리소스를 yaml, json 형태로 보여줌
kubectl get pods -o yaml
kubectl get pods -o json
# 위 데이터보다 정제된 형태로 데이터를 보여줌
kubectl describe pod myapp-pod
# 로그 확인,
보통 명령들을 kubectl (서브 커맨드) (종류) (리스소 이름) 순으로 진행되는데
logs는 어플리케이션의 로그를 확인하기 떄문에 종류를 따로 지정해주지 않는다.
kubectl logs myapp-pod
#임시로 포트포워딩, 호스트 포트:컨테이너 포트 순, 컨테이너 포트는 바꿀 수 없다.
kubectl port-forward myapp-pod 8080:8080
임시 포트 포워딩, 왼쪽 작업을 종료하면 8080포트로 진입할 수 없다.
📢 명령어가 기억나지 않을때 참고하면 좋은 사이트: 명령어 모음집
💡 윈도우 터미널(Windows Terminal): 창(pane) 분할 단축키
Alt + Shift + D: 복제 및 분할(긴 축 기준)
Alt + Shift + +: 세로 분할
Alt + Shift + -: 가로 분할
Alt + Shift + 방향 키: 창(pane) 크기 조정
Alt + 방향 키: 창 간 이동
Ctrl + Shift + W 창 종료
레이블은 파드와 같은 오브젝트에 첨부된 키와 값의 쌍이다. 레이블은 오브젝트의 특성을 식별(identity)하는 데 사용되어 사용자에게 중요하지만, 코어 시스템에 직접적인 의미는 없다. 레이블은 오브젝트를 생성할 때에 붙이거나 생성 이후에 붙이거나 언제든지 수정이 가능하다. 오브젝트마다 키와 값으로 레이블을 정의할 수 있다. 오브젝트의 키는 고유한 값이어야 한다.
"metadata": {
"labels": {
"key1" : "value1",
"key2" : "value2"
}
}
레이블의 목적
이름과 UID와 다르게 레이블은 고유하지 않다. 일반적으로 우리는 많은 오브젝트에 같은 레이블을 가질 것으로 예상한다.
레이블 셀렉터를 통해 클라이언트와 사용자는 오브젝트를 식별할 수 있다. 레이블 셀렉터는 쿠버네티스 코어 그룹의 기본이다.
API는 현재 일치성 기준 과 집합성 기준 이라는 두 종류의 셀렉터를 지원한다. 레이블 셀렉터는 쉼표로 구분된 다양한 요구사항에 따라 만들 수 있다. 다양한 요구사항이 있는 경우 쉼표 기호가 AND(&&) 연산자로 구분되는 역할을 하도록 해야 한다.
일치성 기준 또는 불일치 기준 의 요구사항으로 레이블의 키와 값의 필터링을 허용한다. 일치하는 오브젝트는 추가 레이블을 가질 수 있지만, 레이블의 명시된 제약 조건을 모두 만족해야 한다.
=, ==, != 이 세 가지 연산자만 허용한다. 처음 두 개의 연산자의 일치성(그리고 동의어), 나머지는 불일치를 의미한다.
집합성 기준 레이블 요건에 따라 값 집합을 키로 필터링할 수 있다. in,notin과 exists(키 식별자만 해당)의 3개의 연산자를 지원한다.
environment in (production, qa)
tier notin (frontend, backend)
partition
'!partition' # !를 문자로 인식하기 위해
# 레이블을 확인할 수 있는 명령옵션
kubectl get pods --show-labels
# 메타 데이터 밑에 레이블이 존재해야하는데 없는것으로 보아 레이블이 없는것으로 확인가능
kubectl get pods -o ymal
# 해당 레이블 실습 공간으로 이동 후 yaml 내용확인
cd ../02_label
cat myapp-pod-label.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod-label
labels:
env: dev
tier: frontend
spec:
containers:
- name: myapp
image: ghcr.io/c1t1d0s7/go-myweb:alpine
ports:
- containerPort: 8080
protocol: TCP
# 파드 생성
kubectl create -f myapp-pod-label.yaml
# 레이블 확인
kubectl get pods --show-labels
# 레이블로 파드 내용 찾기
kubectl get pods -l env=dev
kubectl get pods -l tier=frontend
# 쿠베네티스의 모든 파드와 레이블 보기
kubectl get pods -A --show-labels
# kube-apiserver만 출력하는 방법: 뒤에 레이블로 설정하여 출력
kubectl get pods -A tier=control-plane, component=kube-apiserver
대부분의 리소스들은 업데이트가 안된다. 또한 기존에 존재하는 레이블을 변경하는 것은 --overwrite를 추가해주면 가능하다.
# 변경 불가능
kubectl replace -f myapp-pod-label.yaml
# vi로 yaml 파일 내용 수정 후
kubectl apply -f myapp-pod-label.yaml
kubectl get pods --show-labels
or
# vi로 yaml 파일 내용 수정 후 이미 만들어둔 파드를 제거한 후 새롭게 재생성
kubectl create -f myapp-pod-label.yaml
kubectl get pods --show-labels
# 명령형 커맨드
kubectl label pod myapp-pod-label version=0.1
# 레이블 수정
kubectl label pod myapp-pod-label version=0.2 --overwrite
kubectl get pods --show-labels
# 레이블 삭제
kubectl label pod myapp-pod-label version-
kubectl get pods --show-labels
쿠버네티스 어노테이션을 사용하여 임의의 비-식별 메타데이터를 오브젝트에 첨부할 수 있다. 레이블을 사용하여 오브젝트를 선택하고, 특정 조건을 만족하는 오브젝트 컬렉션을 찾을 수 있다. 반면에, 어노테이션은 오브젝트를 식별하고 선택하는데 사용되지 않는다.
cd ../03_annotation/
kubectl create -f myapp-pod-annotation.yaml
kubectl get pods
# 어노테이션 추가
kubectl annotate pod myapp-pod-annotation message=hello
kubectl describe pod myapp-pod-annotation | head -15
# 수정
kubectl annotate pod myapp-pod-annotation message=hello1 --overwrite
kubectl describe pod myapp-pod-annotation | head -15
# 삭제
kubectl annotate pod myapp-pod-annotation message-
kubectl describe pod myapp-pod-annotation | head -15
쿠버네티스에서, 네임스페이스는 단일 클러스터 내에서의 리소스 그룹 격리 메커니즘을 제공한다. 리소스의 이름은 네임스페이스 내에서 유일해야 하며, 네임스페이스 간에서 유일할 필요는 없다. 네임스페이스 기반 스코핑은 네임스페이스 기반 오브젝트 (예: 디플로이먼트, 서비스 등) 에만 적용 가능하며 클러스터 범위의 오브젝트 (예: 스토리지클래스, 노드, 퍼시스턴트볼륨 등) 에는 적용 불가능하다.
쿠버네티스는 처음에 네 개의 초기 네임스페이스를 갖는다.
kubectl get namespace(ns)
NAME STATUS AGE
default Active 1d
kube-node-lease Active 1d
kube-public Active 1d
kube-system Active 1d
# 모든 네임스페이스에 있는 파드의 목록을 볼
수 있다.
kubectl get pods -A
or
kubectl get pods --all-namespace
# not found
kubectl describe pod kube
-apiserver-kube-control1
# kube-system 네임스페이스에 있는 kube-apiserver-kube-control1이라고 하는 파드에 대한 상세정보를 보여달라는 명령
kubectl describe pod kube
-apiserver-kube-control1 -n kube-system
cd ../04_namespace/
kubectl create -f myapp-pod.yaml
# 네임스페이스를 지정하지 않았으므로 default 네임스페이스에 만들어짐
kubectl get pods
# 네임스페이스 확인
kubectl describe pod myapp-pod
# 메타데이터 밑에 네임스페이스가 있다.
kubectl get pod myapp=pod -o yaml | head -20
# 네임스페이스 설명
kubectl explain pod.metadata.namespace
kubectl -n kube-system de ## tab을 두번 클릭하면 사용가능한 것들이 보인다.
kubectl -n kube-system describe pod
kubectl -n kube-system describe pod kube
-apiserver-kube-control1
kubectl create -f myapp-pod.yaml -n kube-public
# 파드로는 조회가 안됨
kubectl get pods
# 네임스페이스까지 해서 조회
kubectl get pods -n kube-public
kubectl -n kube-public get pods myapp-pod -0 yaml | head -20
# 삭제도 마찬가지로 네임스페이스를 지정해줘야함
kubectl delete pods myapp-pod -n kube-public
or
kubectl delete -f myapp-pod.yaml -n kube-public
야물파일 내에서 네임스페이지가 지정할 수 있는데 이때는 외부 명령 커맨드로 네임스페이스로 지정이 불가능하다. 야물 파일의 네임스페이스가 우선순위가 높기 때문이다. 리소스를 만들때 중요한 이유가 없는 이상 야물 파일 내에서 네임스페이스를 지정해두지 않고 외부 명령으로 설정한다.
네임스페이스 자체도 지울 수 있는데 만약 지우게 되면 안에 있는 리소스들(오브젝트 등)도 자동으로 지워지게 되는데 일부 안지워지는 것들은 따로 지워준 다음에 네임스페이스를 지워야한다.
kubectl delete ns development
# 네임스페이스 부분이 비어있어 default로 설정이 되어있다.
kubectl config get-contexts
# 네임스페이스 지정하기
kubectl config set-context kubernetes-admin@cluster.local --namespace=kube-system
kubectl config get-contexts
or
# 밑 방법도 가능한데 다른 부분에서 나중에 문제가 생길수도 있다고 한다.
kubectl config set-context --current --namespace=kube-system
# 다시 원래 default 값으로 변환
kubectl config set-context kubernetes-admin@cluster.local --namespace=default
kubectl config get-contexts
kubectx + kubens: Power tools for kubectl 설치하기
# 파일 다운로드, https://github.com/ahmetb/kubectx/releases -> kubens 링크주소 복사
wget https://github.com/ahmetb/kubectx/releases/download/v0.9.4/kubens
# 지정 디렉터리에 실행 권한을 줘서 복사
sudo install kubens /usr/local/bin
# 현재 디렉터리의 있는 파일 삭제
rm kubens
# 실행, 현재 사용하는 네임스페이스에 하이라이트가 되어있음
kubens
# 네임스페이스 수정
kubens kube-system
kubens
개별 애플리케이션 컨테이너와 마찬가지로, 파드는 비교적 임시(계속 이어지는 것이 아닌) 엔티티로 간주된다. 파드가 생성되고, 고유 ID(UID)가 할당되고, 종료(재시작 정책에 따라) 또는 삭제될 때까지 남아있는 노드에 스케줄된다. 만약 노드가 종료되면, 해당 노드에 스케줄된 파드는 타임아웃 기간 후에 삭제되도록 스케줄된다.
UID로 정의된 특정 파드는 다른 노드로 절대 "다시 스케줄"되지 않는다. 즉 노드1에서 태어났으면 노드1에서 마감이 되어야 한다는 의미이다. 컨테이너는 마이그레이션의 개념이 존재하지 않기 때문에 이동이 불가능하다.
파드의 status 필드는 phase 필드를 포함하는 PodStatus 오브젝트로 정의된다. 파드의 phase는 파드가 라이프사이클 중 어느 단계에 해당하는지 표현하는 간단한 고수준의 요약이다.
전체 파드의 단계뿐 아니라, 쿠버네티스는 파드 내부의 각 컨테이너 상태를 추적한다. 컨테이너 라이프사이클 훅(hook)을 사용하여 컨테이너 라이프사이클의 특정 지점에서 실행할 이벤트를 트리거할 수 있다.
일단 스케줄러가 노드에 파드를 할당하면, kubelet은 컨테이너 런타임을 사용하여 해당 파드에 대한 컨테이너 생성을 시작한다. 표시될 수 있는 세 가지 컨테이너 상태는 Waiting, Running 그리고 Terminated 이다.
파드의 컨테이너 상태를 확인하려면, kubectl describe pod < name-of-pod> 를 사용할 수 있다. 출력 결과는 해당 파드 내의 각 컨테이너 상태가 표시된다.
Waiting
만약 컨테이너가 Running 또는 Terminated 상태가 아니면, Waiting 상태이다. Waiting 상태의 컨테이너는 시작을 완료하는 데 필요한 작업(예를 들어, 컨테이너 이미지 레지스트리에서 컨테이너 이미지 가져오거나, 시크릿(Secret) 데이터를 적용하는 작업)을 계속 실행하고 있는 중이다. kubectl 을 사용하여 컨테이너가 Waiting 인 파드를 쿼리하면, 컨테이너가 해당 상태에 있는 이유를 요약하는 Reason 필드도 표시된다.
Running
Running 상태는 컨테이너가 문제없이 실행되고 있음을 나타낸다. kubectl 을 사용하여 컨테이너가 Running 인 파드를 쿼리하면, 컨테이너가 Running 상태에 진입한 시기에 대한 정보도 볼 수 있다.
Terminated
Terminated 상태의 컨테이너는 실행을 시작한 다음 완료될 때까지 실행되었거나 어떤 이유로 실패했다. kubectl 을 사용하여 컨테이너가 Terminated 인 파드를 쿼리하면, 이유와 종료 코드 그리고 해당 컨테이너의 실행 기간에 대한 시작과 종료 시간이 표시된다.
파드의 spec 에는 restartPolicy 필드가 있다. 사용 가능한 값은 Always, OnFailure(비정상 종료일떄만 재시작), Never이다. 기본값은 Always이다.
restartPolicy는 파드의 모든 컨테이너에 적용된다. restartPolicy는 동일한 노드에서 kubelet에 의한 컨테이너 재시작만을 의미한다. 파드의 컨테이너가 종료된 후, kubelet은 5분으로 제한되는 지수 백오프 지연(10초, 20초, 40초, …)으로 컨테이너를 재시작한다. 컨테이너가 10분 동안 아무런 문제없이 실행되면, kubelet은 해당 컨테이너의 재시작 백오프 타이머를 재설정한다.
kubectl explain pod.spec.restartPolicy
프로브는 컨테이너에서 kubelet에 의해 주기적으로 수행되는 진단(diagnostic)이다. 진단을 수행하기 위해서, kubelet은 컨테이너 안에서 코드를 실행하거나, 또는 네트워크 요청을 전송한다.
프로브를 사용하여 컨테이너를 체크하는 방법에는 4가지가 있다. 각 프로브는 다음의 4가지 메커니즘 중 단 하나만을 정의해야 한다.
exec
컨테이너 내에서 지정된 명령어를 실행한다. 명령어가 상태 코드 0으로 종료되면 진단이 성공한 것으로 간주한다.
grpc
gRPC를 사용하여 원격 프로시저 호출을 수행한다. 체크 대상이 gRPC 헬스 체크를 구현해야 한다. 응답의 status 가 SERVING 이면 진단이 성공했다고 간주한다. gRPC 프로브는 알파 기능이며 GRPCContainerProbe 기능 게이트를 활성화해야 사용할 수 있다.
httpGet 일반적으로 많이 사용함
지정한 포트 및 경로에서 컨테이너의 IP주소에 대한 HTTP GET 요청을 수행한다. 응답의 상태 코드가 200 이상 400 미만이면 진단이 성공한 것으로 간주한다.
(100번대: infomation, {200번대: 성공, 300번대: 리다이렉션}, 400번대: 클라이언트 오류, 500번대: 서버 오류)
tcpSocket
지정된 포트에서 컨테이너의 IP주소에 대해 TCP 검사를 수행한다. 포트가 활성화되어 있다면 진단이 성공한 것으로 간주한다. 원격 시스템(컨테이너)가 연결을 연 이후 즉시 닫는다면, 이 또한 진단이 성공한 것으로 간주한다.
kubelet은 실행 중인 컨테이너들에 대해서 선택적으로 세 가지 종류의 프로브를 수행하고 그에 반응할 수 있다. 각 프로드에서 무엇을 체크할 것인지는 모두 위 체크 매커니즘과 같다는 것을 확인할 수 있다.
# 프로브 종류 확인, 컨테이너마다 이 프로브를 설정 가능하다.
kubectl explain pod.spec.containers | grep Probe
컨테이너가 동작 중인지 여부를 나타낸다. 즉 컨테이너에 있는 애플리케이션이 작동 중인지를 체크한다. 만약 활성 프로브(liveness probe)에 실패한다면, kubelet은 컨테이너를 죽이고, 해당 컨테이너는 재시작 정책의 대상이 된다. 만약 컨테이너가 활성 프로브를 제공하지 않는 경우, 기본 상태는 Success 이다.
# 포트가 필수적으로 필드에 필요
kubectl explain pod.spec.containers.livenessProbe.httpGet
cd ../05_lifecycle
kubectl create -f myapp-pod-liveness.yaml
kubectl get pods
# 포트 포워딩 실시
kubectl port-forward myapp-pod-liveness 8080:8080
# 다른 창에서 확인, -I 옵션으로 응답헤더를 확인하여 응답코드로 200이 오는것을 확인
curl localhost:8080/health -I
# 여기에서 Liveness 항목 확인 , 내가 설정한 위치로 되어있음
kubectl describe pod myapp-pod-liveness
period: 10초마다 한번씩 진단, timeout: 응답이 1초안에 안오면 실패한 것으로 간주, delay: 주기간격에 어느 일정 지연을 더할때 사용, 지금은 없음, success: 연속 1번 성공하면 성공으로 간주 , failure: 10초마다 프로브를 보내는데 실패를 한번 했다고 해서 오류 처리를 진행하면 안좋다. 그래서 연속으로 3번 실패를 하면 실패 처리, Threshold와 비슷한 의미
실패처리, 즉 연속 3번의 11초가 지나면, 즉 33초가 지나기 되면 실패처리를 하여 재시작을 함
일부로 오류를 발생시켜 재시작 하도록 설정, path뒤에 ?code=404를 붙여 코드를 설정해둠
kubectl create -f myapp-pod-liveness-404.yaml
# 리소스의 상태가 바뀌게 될떄마다 새로 생신하여 정보를 보여줌
kubectl get pods -w
# 실습 후 제거
kubectl delete -f myapp-pod-liveness.yaml -f myapp-pod-li
veness-404.yaml
Loopbackoff 이후 시간이 지날수록 재시작하는 타임간격이 늘어났다. 이는 어플리케이션을 시작하는 것은 리소스를 많이 잡아먹기 때문에 쿠버네티스가 판단하여 재시작 타임을 늘리는 것이다. 위에서 말한 컨테이너 재시작 정책과 관련있는 내용이다.
컨테이너가 요청을 처리할 준비가 되었는지 여부를 나타낸다. 웹서버나 어플리케이션 등이 응답할 준비가 되었는지를 의미한다.
만약 준비성 프로브(readiness probe)가 실패한다면, 엔드포인트 컨트롤러는 파드에 연관된 모든 서비스들의 엔드포인트에서 파드의 IP주소를 제거한다.(엔드포인트컨트롤러에서만!!) 준비성 프로브의 초기 지연 이전의 기본 상태는 Failure 이다. 만약 컨테이너가 준비성 프로브를 지원하지 않는다면, 기본 상태는 Success 이다.
cd ../05_readyness_probe
vi myapp-rs-readiness.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: myapp-rs-readiness
spec:
replicas: 3
selector:
matchLabels:
app: myapp-rs-readiness
template:
metadata:
labels:
app: myapp-rs-readiness
spec:
containers:
- name: myapp
image: ghcr.io/c1t1d0s7/go-myweb:alpine
readinessProbe:
exec:
command:
- ls
- /var/ready # 실제론 존재X, exec같은 경우 리턴코드가 0인 경우만 성공, 실패할 경우 엔드포인트에 등록하지 않음
ports:
- containerPort: 8080
kubectl create -f myapp-rs-readiness.yaml
kubectl create -f myapp-svc-readiness.yaml
# 현재 상태는 아무것도 ready되어 있지않다. 즉 엔드포인트에 등록되어있지 않다는 것이다.
kubectl get rs,pod,svc,ep
# 실행 안됨, readyness 서비스 실행시킨 것의 IP주소
curl 10.233.11.105
# kubectl exec 파드명 -- 실행하고 싶은 명령어
kubectl exec myapp-rs-readiness-cmkvl -- touch /var/ready
-> 이 명령을 실행하면 readynessprobe가 성립이 되어 readt 상태가 되고 엔드포인트에도 등록이 된다.
kubectl exec myapp-rs-readiness-cmkvl -- rm /var/ready
-> 삭제되었기 떄문에 파드가 ready상태에서 해제되고 엔드포인트에서도 제거된다.
# 실시간으로 바뀌는 것에 하이라이트표시
watch -n1 -d kubectl get pod,ep
컨테이너 내의 애플리케이션이 시작되었는지를 나타낸다. 초기 어플리케이션이 실행되는 시간이 오래걸리는 경우를 위해 만들어졌다. 스타트업 프로브(startup probe)가 주어진 경우, 성공할 때까지 다른 나머지 프로브는 활성화되지 않는다. 만약 스타트업 프로브가 실패하면, kubelet이 컨테이너를 죽이고, 컨테이너는 재시작 정책에 따라 처리된다. 컨테이너에 스타트업 프로브가 없는 경우, 기본 상태는 Success 이다.
각 probe는 다음 세 가지 결과 중 하나를 가진다.
cd ~
vi mydb-pod.yml
apiVersion: v1
kind: Pod
metadata:
name: mydb-pod
labels:
app.kubernetes.io/name: mysql
app.kubernetes.io/version: "5.7"
app.kubernetes.io/component: database
annotations:
app.kubernetes.io/managed-by: shin
spec:
containers:
- name: mydb
image: mysql:5.7
ports:
- containerPort: 3306
protocol: TCP
env:
- name: MYSQL_ROOT_PASSWORD
value: qwer1234
startupProbe:
exec:
command: ['mysqladmin', 'ping']
periodSeconds: 30
failureThreshold: 5
livenessProbe:
exec:
command: ['mysqladmin', 'ping']
periodSeconds: 10
failureThreshold: 3
# 파드 생성
kubectl create -f mydb-pod.yml
# startup 프로브와 liveness프로브를 길게 세팅해두었기 때문에 처음에 작동하는데 시간이 걸릴 수 있다.
kubectl get pods -w
# 포트 포워딩 실행
kubectl port-forward mydb-pod 3306:3306
# mysql설치
sudo apt install -y mysql-client
# 설치 확인
mtsql --version
# mysql 접속, 포트포워딩 걸어두었기 때문에 host는 자기자신, 사용자 root, password: qwer1234 실행
mysql -h 127.0.0.1 -u root -p