[K8s]3. 포드(pods)

[K8s]3. 포드(pods)


이 글은 쿠버네티스 인 액션 이라는 책과 검색을 통해서 공부한 것을 정리합니다.

포드 설명에 앞서서 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 를 사용해서 쿠버네티스의 리소스 정보를 찾을 수 있음.