[K8s]3. 포드(pods)
in etc on Kuberenetes
이 글은 쿠버네티스 인 액션 이라는 책과 검색을 통해서 공부한 것을 정리합니다.
포드 설명에 앞서서 minikube, kubectl을 설치합니다.
미니큐브 설치
설치:
$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-darwin-amd64 && chmod +x minikube
- 시작:
$ minikube start
- 정지:
$ minikube stop
- 삭제:
$ minikube delete
Kubectl 설치
설치:
$ curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl"
kubectl 바이너리를 실행 가능하게 만듭니다.
$ chmod +x ./kubectl
바이너리를 PATH로 옮깁니다.
$ sudo mv ./kubectl /usr/local/bin/kubectl
버전확인
$ kubectl version
클러스터 정보 확인
$ kubectl cluster-info
클러스터 노드 목록 확인
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
minikube Ready master 10m v1.10.0
kubectl로 클러스터와 상호작용
- 로컬 미니큐브로 실습하는 상황과는 조금 다르지만, 기본적인 상호작용 방법에 대해서 아래 그림을 참고한다.
각 노드들은 도커, kubelet, kube-proxy를 실행하고, 사용자는 쿠버네티스 클러스터 외부에서 kubectl 명령행 클라이언트를 이용해서 마스터 노드에 REST 호출해 상호작용을 함.
$ minikube start
를 하고 아래를 진행합니다.
포드
컨테이너의 공동의 배포된 그룹
일반적으로 포드는 단일 컨테이너만 포함한다.
플랫 인터 포드 네트워크
결론적으로 포드 간 통신은 항상 단순하다. 각 포드들은 자체 IP 주소를 가지며 포드 전용으로 설정된 네트워크를 통해서 다른 모든 포드에서 액세스할 수 있다.
컨테이너를 포드 전체에 적절하게 구성하기
- 다수의 포드로 멀티티어 애플리케이션 분할
- 각각 스케일링이 가능한 포드로 분할 하나의 포드에 두 개의 컨테이너를 넣지 않아야 할 이유는 스케일링이다.
쿠버네티스는 개별 컨테이너를 수평으로 확장할 수 없기 때문에 포드의 크기를 조정함.
하나의 pod - 하나의 컨테이너 권장
포드의 yaml 확인
$ kubectl get po [pod네임] -o yaml
- 메타 데이터 부분
- 포드와 관련된 이름, 네임스페이스 라벨, 기타 정보
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2019-10-02T11:28:48Z"
generateName: kubia-
labels:
run: kubia
name: kubia-45bfd
namespace: default
ownerReferences:
- apiVersion: v1
blockOwnerDeletion: true
controller: true
kind: ReplicationController
name: kubia
uid: cd374bf3-e507-11e9-8d6c-08002729ba79
resourceVersion: "30110"
selfLink: /api/v1/namespaces/default/pods/kubia-45bfd
uid: cd3914ae-e507-11e9-8d6c-08002729ba79
- Spec
- 포드의 컨테이너, 볼륨, 그 밖의 데이터 관련 내용 및 설명
spec:
containers:
- args:
- replicationcontoroller
- kubia
- created
image: kubia
imagePullPolicy: Always
name: kubia
ports:
- containerPort: 8080
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-hzlcg
readOnly: true
dnsPolicy: ClusterFirst
nodeName: minikube
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes:
- name: default-token-hzlcg
secret:
defaultMode: 420
secretName: default-token-hzlcg
- 상태
- 포드의 상태, 각 컨테이너의 설명 및 상태, 포드 내부의 IP 및 그 밖의 기본 정보 등 실행 중인 포드의 현재 정보가 있다.
status:
conditions:
- lastProbeTime: null
lastTransitionTime: "2019-10-02T11:28:48Z"
status: "True"
type: Initialized
- lastProbeTime: null
lastTransitionTime: "2019-10-02T11:28:48Z"
message: 'containers with unready status: [kubia]'
reason: ContainersNotReady
status: "False"
type: Ready
- lastProbeTime: null
lastTransitionTime: "2019-10-02T11:28:48Z"
status: "True"
type: PodScheduled
containerStatuses:
- image: kubia
imageID: ""
lastState: {}
name: kubia
ready: false
restartCount: 0
state:
waiting:
message: 'rpc error: code = Unknown desc = Error response from daemon: pull
access denied for kubia, repository does not exist or may require ''docker
login'''
reason: ErrImagePull
hostIP: 10.0.2.15
phase: Pending
podIP: 172.17.0.2
qosClass: BestEffort
startTime: "2019-10-02T11:28:48Z"
포드의 간단한 yaml 디스크립터 실습
apiVersion: v1 #쿠버네티스 API v1 버전을 따름
kind: Pod #pod에 대한 설명
metadata:
name: kubia-manual #포드 이름
spec:
contatiners:
- image: luksa/kubia #생설할 컨테이너 이미지
name:
ports:
- contatinerPort: 8080 #응답을 대기할 애플리케이션의 포트
protocol: TCP
포드 만들기
(실습) kubia-manual.yml 생성
apiVersion: v1
kind: Pod
metadata:
name: kubia-manual
spec:
containers:
- image: luksa/kubia
name: kubia
port:
- containerPort: 8080
protocol: TCP
$ minikube start
> $ kubectl create -f ./kubia-manual.yml
- 위 명령어로 컨테이너가 올라오는 중
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kubia-manual 0/1 ContainerCreating 0 42s
NAME READY STATUS RESTARTS AGE
kubia-manual 1/1 Running 0 1m
포드의 컨테이너 log 확인하기
$ kubectl logs kubia-manual
Kubia server starting...
- 현재의 셋팅 상태로는 서버 시작에 대한 단일 로그문만 확인할 수 있다.
- tip. 컨테이너 로그는 10MB 기준으로 자동 교체된다.
포트포워딩을 사용해서 외부에서 포드에 접근
- expose 명령을 사용해서 외부에서 포드에 접근하는 서비스가 가능함.
- 다른 방법으로 포트포워딩을 사용하자.
- 일시적으로 연결을 해주는 것 같다.
$ kubectl port-forward kubia-manual 8888:8080
Forwarding from 127.0.0.1:8888 -> 8080
Forwarding from [::1]:8888 -> 8080
curl로 포드에 http 요청보내기
$ curl localhost:8888
You've hit kubia-manual
라벨(Label)
라벨을 이용한 포드 구성
- 포드의 수가 증가하면서 포드를 하위 집합으로 분류해야한다.
- 포드들을 조직화하는 매커니즘이 없으면 아래처럼 이해할 수 없는 복잡한 모양이 된다.
- 키/밸류 쌍으로 구분짓는 값이다.
조직화하게 되면?
- 시스템을 다루는 모든 개발자 및 시스템 관리자가 원하는 포드를 쉽게 볼 수 있음
- 각 포드에서 개별적으로 작업하지 않고, 특정 그룹에 속한 모든 포드를 단일 작업으로 실행
포드를 만들 때 라벨 지정하기
1 apiVersion: v1
2 kind: Pod
3 metadata:
4 name: kubia-manual-v2
5 labels:
6 creation_method: manual #creation_method=manual 이라는 라벨
7 env: prod #env=prod 라는 라벨
8 spec:
9 containers:
10 - image: luksa/kubia
11 name: kubia
12 ports:
13 - containerPort: 8080
14 protocol: TCP
$ kubectl create -f kubia-manual-with-labels.yml
pod/kubia-manual-v2 created
포드 라벨 확인하기
$ kubectl get po --show-labels
NAME READY STATUS RESTARTS AGE LABELS
kubia-manual 1/1 Running 0 3h <none>
kubia-manual-v2 1/1 Running 0 38s creation_method=manual,env=prod
라벨을 수정해야 한다면?(key 입력 실수 등)
$ kubectl edit po [pod 네임] -o yaml
포드에 라벨 추가하기
$kubectl label po kubia-manual creation_method=manual
pod/kubia-manual labeled
➜ $ kubectl get po --show-labels
NAME READY STATUS RESTARTS AGE LABELS
kubia-manual 1/1 Running 0 3h creation_method=manual
kubia-manual-v2 1/1 Running 0 2m creation_method=manual,env=prod
기존 포드의 라벨을 변경하려면?
--overwrite 를 사용
➜ $ kubectl label po kubia-manual-v2 env=debug --overwrite
pod/kubia-manual-v2 labeled
➜ $ kubectl get po --show-labels
NAME READY STATUS RESTARTS AGE LABELS
kubia-manual 1/1 Running 0 3h creation_manual=manual
kubia-manual-v2 1/1 Running 0 6m creation_method=manual,env=debug
라벨은 라벨 셀렉터를 위해 존재한다?
- 라벨은 리소스만 구분하기위해 사용하는 것은 아님.
- 라벨 셀렉터 와 함께 사용되는 것이 중요.
- 라벨 셀렉터를 사용하면, 특정 라벨로 지정된 포드의 하위의 집합을 선택할 수 있다. 그리하여 해당 포드에서 작업을 수행할 수 있다. 쉽게 말해서 라벨 셀렉터는 특정 라벨을 포함하고 있는 여부에 따라서 리소스를 필터링할 수 있다.
- (1) 특정 키가 있는 라벨 포함
- (2) 특정 키와 값이 있는 라벨 포함
- (3) 특정 키가 있지만 지정한 값과 다른 값이 있는 라벨을 포함
라벨셀렉터 명령어
- 특정 label 선택
kubectl get pods -l creation_method=manual
- env 라는 key 값을 가진 label pod 선택
kubectl get pods -l env
- env label을 포함하지 않는 pod 선택
kubectl get pods -l '!env'
- 다중 선택
kubectl get pods -l env=prod,creation_method=manual
라벨은 포드 뿐만 아니라 쿠버네티스 객체에 모두 붙일 수 있다.
라벨을 노드에 붙이기
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
minikube Ready master 5h v1.10.0
$ kubectl label node minikube gpu=true
node/minikube labeled
$ kubectl get nodes -l gpu
NAME STATUS ROLES AGE VERSION
minikube Ready master 5h v1.10.0
아래와 같이 가정해보자.
GPU가 필요한 새 포드를 배포하려고 한다. 스케줄러에게 GPU를 제공하는 노드 중에서 하나만 선택하도록 요청하려면?
- kubia-gpu.yml 생성
1 apiVersion: v1
2 kind: Pod
3 metadata:
4 name: kubia-gpu #pod의 네임
5 spec:
6 nodeSelector: #스케줄러에게 gpu:true 라는 label를 가진 노드중에서 선택하도록 한다.
7 gpu: "true"
8 containers:
9 - image: luksa/kubia
10 name: kubia
$ kubectl create -f kubia-gpu.yml
pod/kubia-gpu created
- 멀티 클러스터 환경이었으면, kubia-gpu는 nodeSelector 에 의해서 gpu:”true”로 라벨이 붙은 node로 셀렉팅이 되어서 뜰 것이다.
중요한점. 노드가 죽은 상황일 때, 해당 pod는 난처한 상황이 발생할 수 있다. 이렇게 노드를 직접 지정해줄 때, 특정 기준을 충족하도록 논리적인 그룹을 생각해야한다.
네임스페이스(NameSpace)
- 라벨만 생각하면 객체는 여러 개의 라벨을 가지므로 객체 그룹은 겹칠 수 있다. 또한 라벨 셀렉터를 명시적으로 지정하지 않으면 항상 모든 객체가 표시된다.
- 그러므로 객체들을 서로 겹치지 않는 별개의 그룹으로 분리하려는 경우에 네임스페이스를 사용해 하나의 그룹을 만든다.
- 프로세스를 격리시키는데 사용됨.
- 아직까지는 감이 잘 안오므로 실습으로 해본다.
클러스터의 네임스페이스 보는 방법
$ kubectl get ns
NAME STATUS AGE
default Active 7h
kube-public Active 7h
kube-system Active 7h
특정 네임스페이스에 속한 pod 를 보자
$ kubectl get po --namespace kube-system #$ kubectl get po -n kube-system 도 가능
NAME READY STATUS RESTARTS AGE
coredns-c4cffd6dc-6tmt2 1/1 Running 0 7h
etcd-minikube 1/1 Running 0 7h
kube-addon-manager-minikube 1/1 Running 0 7h
kube-apiserver-minikube 1/1 Running 0 7h
kube-controller-manager-minikube 1/1 Running 0 7h
kube-dns-86f4d74b45-zmx96 3/3 Running 0 7h
kube-proxy-r45d8 1/1 Running 0 7h
kube-scheduler-minikube 1/1 Running 0 7h
kubernetes-dashboard-6f4cfc5d87-4rwcg 1/1 Running 0 7h
storage-provisioner 1/1 Running 0 7h
- NAME을 보면 쿠버네티스 클러스터 시스템과 관련이 있는 리소스로 보인다. 다만 여러 리소스들이 더 추가되고 섞여있을 때, 어디에 속해있는지 등등 관리하기가 어렵다.
- 네임스페이스를 사용해서 격리된 별개의 그룹으로 묶는 것이 좋아보인다.
- 추가적으로 특정 유저에게 네임스페이스별로 접근 권한 등을 줄 수 있고, 개별 사용자가 사용할 수 있는 컴퓨팅 리소스의 양을 제어할 수 있는 등 다양한 기능을 제공한다.
네임스페이스 만들기
불편하게 만드는 방법
$ vim custom-namespace.yml
1 apiVersion: v1
2 kind: Namespace
3 metadata:
4 name: custom-namespace
$ kubectl create -f custom-namespace.yml
namespace/custom-namespace created
편하게 만드는 방법
$ kubectl create namespace custom-namespace
// 위와 동일한 namespace를 만들 수 있다.
생성한 네임스페이스를 관리하는 방법(pod 에 어떻게 연결?)
(1) edit 명령어로 pod yaml에서 수정
(생략)
7 metadata:
8 creationTimestamp: "2019-10-07T02:15:28Z"
9 labels:
10 creation_method: manual
11 name: kubia-manual
12 namespace: custom-namespace #기본은 default 임.
(생략)
(2) 리소스를 만들 때 추가
$ kubectl create -f kubia-manual.yml -n custom-namespace
네임스페이스를 통한 격리
- 기본적으로 네임스페이스간 네트워크 통신을 할 수 없다. 겪리되어 있기 때문에
- 다만, 쿠버네티스와 배포되는 네트워킹 솔루션에 따라서 서로 통신할 수도 있다.
- 예) A 네임스페이스에 속한 pod가 B 네임스페이스의 pod의 IP 주소를 알 고 있으면, HTTP 요청과 같은 트래픽을 다른 pod 로 보내는 것을 막을 수는 없다.
포드 추가
포드 중지와 삭제
이름으로 삭제
$ kubectl delete po [pod 네임1 pod 네임2]
라벨 셀렉터로 삭제
$ kubectl delete po -l creation_method=manual
네임스페이스를 삭제 -> 포드삭제
$ kubectl delete ns custom-namespace
모든 pod 삭제
$ kubectl delete po --all
주의!
- 아무리 삭제해도 rc, 혹은 deployment replica 에 설정된 1이상의 값 때문에 계속 pod가 살아날 수 있다.
해결책: RC를 삭제하고 pod를 삭제한다. or 네임스페이스와 (거의) 모든 리소스를 삭제.
$ kubectl delete all --all
// delete 모든유형을 삭제, –all은 이름으로 지정하는 대신, 모든 리소스 인스턴스를 삭제하도록 지정.
요약
- 특정 컨테이너를 포드에 그룹화할지 여부를 결정하는 방법
- 라벨, 네임스페이스
- 포드는 물리적인 호스트와 유사함. 격리!
- yaml이나 json 을 통해서 포드를 만들거나 조회 할 수 있음.
- 포드는 라벨 및 라벨의 하위집합 요소인 라벨셀렉터를 사용할 수 있음.
- 라벨은 쿠버네티스의 모든 리소스에서 사용이 가능하다.
- 예를 들어서 노드 라벨 및 셀렉터를 사용해 특정 기능이 있는 노드에만 포드를 스케줄(해당 노드에서만 running 되도록) 할 수 있음.
- 네임스페이스를 사용
- kubectl explain xxx 를 사용해서 쿠버네티스의 리소스 정보를 찾을 수 있음.