Kubectl를 이용하여 쿠버네티스 리소스를 조회하려고 할때 원하고자 하는 형태로 컨솔창에 출력하고 싶을 경우가 있다.

이런 경우를 위해 JSONPATH를 활용해보자.

 

원하는 결과를 출력하기 전에 우선 소스가되는 데이터 부터 확인해보자. 너무 길어서 일부만 캡쳐하는걸로..

kubectl get no -o json
controlplane $ kubectl get no -o json | head -n 20
{
    "apiVersion": "v1",
    "items": [
        {
            "apiVersion": "v1",
            "kind": "Node",
            "metadata": {
                "annotations": {
                    "flannel.alpha.coreos.com/backend-data": "null",
                    "flannel.alpha.coreos.com/backend-type": "host-gw",
                    "flannel.alpha.coreos.com/kube-subnet-manager": "true",
                    "flannel.alpha.coreos.com/public-ip": "172.17.0.13",
                    "kubeadm.alpha.kubernetes.io/cri-socket": "/var/run/dockershim.sock",
                    "node.alpha.kubernetes.io/ttl": "0",
                    "volumes.kubernetes.io/controller-managed-attach-detach": "true"
                },
                "creationTimestamp": "2021-08-08T06:14:24Z",
                "labels": {
                    "beta.kubernetes.io/arch": "amd64",
                    "beta.kubernetes.io/os": "linux",

 

먼저, JSONPATH를 연습해보도록 하자.

 

Before

{
  "firstName": "John",
  "lastName" : "doe",
  "age"      : 26,
   "address1"  : {
      "streetAddress": "naist street",
      "city"         : "Nara",
      "postalCode"   : "630-0192"
 	 },
   "address2"  : {
      "streetAddress": "naist street",
      "city"         : "Seoul",
      "postalCode"   : "640-0112"
  },
  "phoneNumbers": [
      {
        "type": "iPhone",
        "number": "0123-4567-8888"
      },
      {
        "type": "home",
        "number": "0123-4567-8910"
      },
      {
        "type"  : "home2",
        "number": "0123-1111-3333"
   	  },
      {
        "type"  : "home3",
        "number": "0123-1771-6633"
      }
  ]
}

After($)

[
  {
    "firstName": "John",
    "lastName": "doe",
    "age": 26,
    "address1"  : {
      "streetAddress": "naist street",
      "city"         : "Nara",
      "postalCode"   : "630-0192"
 	 },
  	"address2"  : {
      "streetAddress": "naist street",
      "city"         : "Seoul",
      "postalCode"   : "640-0112"
  	},
    "phoneNumbers": [
      {
        "type": "iPhone",
        "number": "0123-4567-8888"
      },
      {
        "type": "home",
        "number": "0123-4567-8910"
      },
      {
        "type"  : "home2",
        "number": "0123-1111-3333"
   	  },
      {
        "type"  : "home3",
        "number": "0123-1771-6633"
      }
    ]
  }
]

After($.firstName)

[
  "John"
]

 

결과가 List로 나온다는 것에 유의하자.

 

After($.phoneNumbers[0,2])

- 인덱스 번호를 콤마(,)로 구분하여 원하는 정보만 출력할 수 있다.

[
  {
    "type": "iPhone",
    "number": "0123-4567-8888"
  },
  {
    "type": "home2",
    "number": "0123-1111-3333"
  }
]

 

After($.phoneNumbers[?(@.type == 'iPhone')])

- 리스트에서 조건을 주어 해당하는 요소만 출력할 수 있다.

- @ : List Element

[
  {
    "type": "iPhone",
    "number": "0123-4567-8888"
  }
]

 

After($.phoneNumbers[*]), $.phoneNumbers[*].type

- 리스트의 모든 요소를 출력하고자 할때

[
  {
    "type": "iPhone",
    "number": "0123-4567-8888"
  },
  {
    "type": "home",
    "number": "0123-4567-8910"
  },
  {
    "type": "home2",
    "number": "0123-1111-3333"
  },
  {
  	"type"  : "home3",
  	"number": "0123-1771-6633"
  }
]
[
  "iPhone",
  "home",
  "home2",
  "home3"
]

- 리스트가 아니더라도 * 를 사용할 수 있음($.*.city)

[
  "Nara",
  "Seoul"
]

After($.phoneNumbers[0:2], $.phoneNumbers[0:4:2])

- start:end or start:end:step

[
  {
    "type": "iPhone",
    "number": "0123-4567-8888"
  },
  {
    "type": "home",
    "number": "0123-4567-8910"
  }
]
[
  {
    "type": "iPhone",
    "number": "0123-4567-8888"
  },
  {
    "type": "home2",
    "number": "0123-1111-3333"
  }
]

After($.phoneNumbers[-1:])

- last element

[
  {
    "type": "home3",
    "number": "0123-1771-6633"
  }
]




위의 명령어들에 어느 정도 익숙해졌다면 이제 쿠버네티스에서 JSONPATH를 이용하는 방법을 알아보자.

 

Root element를 $로 표현하지만 kubectl를 이용할 때는 생략해도 좋다.

 

kubectl get nodes -o=jsonpath='{write jsonpath}'

 

당연한 이야기지만 jsonpath를 작성할 때에 필터링 할 Json data 구조를 알고 있어야한다.

 

- 노드 이름

kubectl get nodes -o=jsonpath='{.items[*].metadata.name}'
> controlplane node01

 

- 노드 아키텍쳐

kubectl get nodes -o=jsonpath='{.items[*].status.nodeInfo.architecture}'
> amd64 amd64

- 노드 cpu capacity

kubectl get nodes -o=jsonpath='{.items[*].status.capacity.cpu}'
> 48 48

- 노드 이름 + cpu capacity

kubectl get nodes -o=jsonpath='{.items[*].metadata.name} {.items[*].status.capacity.cpu}'
> controlplane node01 48 48
kubectl get nodes -o=jsonpath='{.items[*].metadata.name} {"\n"} {.items[*].status.capacity.cpu}'
> controlplane node01 
  48 48

 

좀 더 출력을 커스터마이징 하기 위해서는 rage ~ end를 사용하자.

 

- [Range] : 노드 이름 + capacity with 출력 형태 변경

kubectl get nodes -o=jsonpath='{range .items[*]}{.metadataname} {"\t"} {.status.capacity.cpu} {"\n"} {end}'
> controlplane     48 
 node01          48

 

- [Range + Custom Colum] : 노드 이름 + capacity with 출력 형태 변경

kubectl get nodes -o=jsonpath='{range .items[*]}{.metadata.name} {"\t"} {.status.capacity.cpu} {"\n"} {end}' -o custom-columns=NODE:.metadata.name,CPU:.status.capacity.cpu
> NODE CPU 
 controlplane     48 
 node01          48

 

리소스에 문제가 있는 리소스를 효과적으로 분별하기 위해서 정렬 기능도 제공한다.

 

- [Sort] : 정렬 기준을 정하여 리소스 출력

kubectl get nodes --sort-by=.medatadata.name
kubectl get nodes --sort-by=.status.capacity.cpu

 

- yaml 포맷 파일에 jsonpath 적용하기

# /root/my-kube-config
contexts:
- context:
    cluster: kubernetes-on-aws
    user: aws-user
  name: aws-user@kubernetes-on-aws
- context:
    cluster: test-cluster-1
    user: dev-user
  name: research
- context:
    cluster: development
    user: test-user
  name: test-user@development
- context:
    cluster: production
    user: test-user
  name: test-user@production
  
# get the user names from the file
k config view --kubeconfig=/root/my-kube-config -o=jsonpath='{.users.*.name}'

 

쿠버네티스 시스템 장애시에 문제 파악을 보다 효과적으로 하기 위해서 jsonpath를 잘 알아두면 좋을 것 같다.

 


출처

- https://jsonpath.com/

'클라우드 컴퓨팅 > 쿠버네티스' 카테고리의 다른 글

Kubernetes Pod Scheduling  (0) 2021.08.13
Kubernetes Workloads  (0) 2021.08.08
Kubernetes Network Model & Policy  (0) 2021.07.08
Kubeadm Swap Disable  (0) 2021.07.04
Kubernetes Components  (0) 2021.07.03

쿠버네티스 클러스터 구성 중에 CNI(Container Network Interface)를 설치하지 않으면 포드간에 통신이 되지 않는다.

CNI는 쿠버네티스 네트워크 모델 구현체라고 할 수 이다.  

 

네트워크 모델의 여러 기능중에서 개인적으로 중요하다고 생각하는 부분만 살펴보겠다.

Kubernetes Networking Model

- Every Pod gets its own IP address.

- pods on a node can communicate with all pods on all nodes without NAT

- containers within a Pod must coordinate port usage

communication between containers in a Pod
- shared volumes
- Inter-process communications(IPC)
- Inter-container network communication

 

위의 네트워크 모델을 구현하는 여러가지 플러그인(Calico, WeaveNet ...)들이 존재하고, 각 플러그인 마다 장단점이 존재한다고 한다.

 

예를들면 GKE, EKS or AKS 등과 같은 대형 클라우드 업체에서 제공하는 쿠버네티스 서비스는 그들 자신의 Contaer Network Interface(CNI)를 가지고 있기 때문에 별도의 작업이 필요 없다. 이러한 대형 클라우드 업체들은 Calico를 기반으로 쿠버네티스 네트워크 모델을 구현한다고 한다.

 

AWS EKS 공식 문서를 한편 살펴보자. 

https://docs.aws.amazon.com/eks/latest/userguide/calico.html

 

Project Calico
 is a network policy engine for Kubernetes. With Calico network policy enforcement, you can implement network segmentation and tenant isolation.

 

정말 사용하고 있다! 나는 개인 On-Prem network 및 테스트에 적합하다고 하는 WeaveNet을 사용했다.

 

플러그인들을 크게 특징/타입으로 나누어 보자면 아래와 같다. 

- Cloud : Pod traffic is routed in cloud virtual network

- Overlay(ex. VXLAN) : Pod traffic is encapsulated and uses underlay for reachability

- Routing Config(ex. BGP) : Pod traffic is routed in underlay network

 

Calico는 Router Config에 해당하고, WeaveNet은 Overlay 타입/특징이라 할 수 있다.

 

이처럼 플러그인들은 각기 다른 멋진 특색을 가지고 있기 때문에 시스템에 가장 적합한 플러그인을 선택해야한다.

 

이제 Network Policy에 대해서 살펴보자.

 

보통은 인바운드 규칙을 만들고, 시스템으로 들어오는 트래픽을 제어한다. 

지금까지의 경험으로는 일부 기관을 제외하고는 아웃바운드는 모두 오픈했다.

 

Network Policy

Ingress

인그레스는 인바운드 방향의 트래픽 룰을 설정한다. 설정 범위는 podSelector로 지정한다.

- ipBlock : 특정 IP 대역으로부터 들어오는 트래픽만 허용.

- podSelector : 특정 파드로부터 들어오는 트래픽만 허용.

- namespaceSelector : 특정 네임스페이스로 부터 들어오는 트래픽만 허용.

- Protocol & Port : 특정 프로토콜 및 포트로부터 들어오는 트래픽만 허용.

 

Egress

이그레스는 아웃바운드 방향의 트래픽 룰을 설정한다. 설정 범위는 podSelector로 지정한다.

- ipBlock : 특정 IP 대역으로 나가는 트래픽만 허용.

- podSelector : 특정 파드로 나가는 통신 허가

- namespaceSelector : 특정 네임스페이스상에 있는 파드로 나가는 통신 허가.

- Protocol & Port : 특정 프로토콜 및 포트로 나가는 트래픽만 허용.

 

네트워크 정책예제

- kubectl get networkpolicy

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: sample-networkpolicy
  namespace: default # 네트워크 정책을 생성할 네임스페이스 지정
spec:
  podSelector:
    # 설정할 대상 파드를 여기에 기입
    # 레이블 셀렉터이므로 여러 파드를 대상으로 할 수 있음
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
      # Ingress 룰을 기입
    ports:
      # 허가할 수신 포트 번호와 프로토콜 기입
  egress:
  - to:
      # Egress 룰을 기입
    ports:
      # 허가할 목적지 포트 번호와 프로토콜 기입
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-policy
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          name: api-pod
      namespaceSelector:
        matchLabels:
          name: prod
    - namespaceSelector:
        matchLabels:
          name: na
    - ipBlock:
          cidr: 192.168.5.10/32
    ports:
    - protocol: TCP
      port: 3306
  egress:
  - to:
    - ipBlock:
          cidr: 192.168.5.10/32
    ports:
    - protocol: TCP
      port: 80
  - to:
    - podSelector:
         matchLabels:
           name: mysql
    ports:
    - protocol: TCP
      port: 3306

 

참고로, EKS 에서 Calico를 설치하고 NetworkPolicy의 ipBlock을 이용하여 클러스터 밖에서 접속하는 특정 트래픽만 허용하는 방화벽 설정(화이트리스트)을 하였지만 정상적으로 동작하지 않았다. 그 이유는 클러스터 내부로 트래픽이 들어올 시 Source 주소가 변경되기 때문이다(SNAT). 만약 로드밸런서로 클러스터 밖에서 트래픽이 들어올 수 있도록 허용해놓은 상황이라면 NetworkPolicy가 아닌 로드밸런서 방화벽 설정을 살펴봐야한다.

NetworkPolicies are an application-centric construct which allow you to specify how a pod is allowed to communicate with various network "entities" (we use the word "entity" here to avoid overloading the more common terms such as "endpoints" and "services", which have specific Kubernetes connotations) over the network.

출처 : https://kubernetes.io/docs/concepts/services-networking/network-policies/

https://github.com/projectcalico/calico/issues/2088
https://docs.aws.amazon.com/quickstart/latest/vpc/images/quickstart-vpc-design-fullscreen.png

 

 

참고

1. NAT란

모든 IP 패킷에는 Source IP와 Destination IP가 있다.

NAT란, Network Address Translation, 즉 IP 패킷 헤더의 IP 주소를 변경하는 기능 혹은 절차를 뜻한다. 1:1 NAT 혹은 1:다 NAT가 있다.

  • PREROUTING : DNAT을 이용하여 패킷이 생길 때 사용됨
  • POSTROUTING : SNAT을 이용하여 패킷이 나갈 때 사용됨

2. SNAT

  • 내부 -> 외부
  • 패킷의 Source 주소를 변경하는 것으로  Source NAT, SNAT, 혹은 IP 마스커레이드라고 한다.
  • 인터넷으로 나가는 패킷의 Source IP를 G/W의 Public IP로 바꾼다.

3. DNAT

  • 외부 -> 내부
  • Destination IP 주소를 변경하여 내부에 접근할 수 있도록 패킷을 변경한다.
  • 대표적인 것은 Load Balancer이다. 

출처

Networkpolicy with Calico on EKS

https://docs.projectcalico.org/getting-started/kubernetes/managed-public-cloud/eks

https://docs.projectcalico.org/about/about-kubernetes-services

https://docs.aws.amazon.com/eks/latest/userguide/calico.html

https://docs.aws.amazon.com/eks/latest/userguide/alternate-cni-plugins.html

https://github.com/projectcalico/calico/issues/2088

 

기타

- https://github.com/kubernetes/community/blob/master/contributors/design-proposals/network/networking.md

- https://www.slideshare.net/CodeOps/kubernetes-networking-sreenivas-makam-google-cc18

- https://ssup2.github.io/theory_analysis/Kubernetes_Calico_Plugin/

- https://itnext.io/benchmark-results-of-kubernetes-network-plugins-cni-over-10gbit-s-network-updated-april-2019-4a9886efe9c4

- https://bcho.tistory.com/1353?category=731548 

- https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing

- https://docs.aws.amazon.com/eks/latest/userguide/calico.html

- https://www.mirantis.com/blog/multi-container-pods-and-container-communication-in-kubernetes/

- https://kubedex.com/kubernetes-network-plugins/

- https://kubernetes.io/docs/concepts/cluster-administration/networking/

- https://thenordicweb.com/Kubernetes-Network-Cilium-1d4371f562ea4acdb5e679e376a7c992

 

 

'클라우드 컴퓨팅 > 쿠버네티스' 카테고리의 다른 글

Kubernetes Workloads  (0) 2021.08.08
Kubernetes JSONPATH 사용법  (0) 2021.08.08
Kubeadm Swap Disable  (0) 2021.07.04
Kubernetes Components  (0) 2021.07.03
Kubeadm Infrastructure With Raspberry Pi  (0) 2021.06.20

Kubeadm 설치를 하며 아래 에러를 본적이 있다.

[init] Using Kubernetes version: v1.21.2
[preflight] Running pre-flight checks
	[WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/
	[WARNING SystemVerification]: missing optional cgroups: hugetlb
error execution phase preflight: [preflight] Some fatal errors occurred:
	[ERROR Mem]: the system RAM (924 MB) is less than the minimum 1700 MB
	[ERROR Swap]: running with swap on is not supported. Please disable swap
[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
To see the stack trace of this error execute with --v=5 or higher

 

최소 권장 메모리보다 적은 메모리 사양을 지니고 있다는 에러는 그렇다 치고, 왜 swap을 disable 하도록 하는 것일까?

 

물리적 메모리(RAM) 사용량이 가득 차게될 경우 하드 디스크 상에 위치하는 스왑 공간을 사용하여 시스템 장애에 대비할 수 있지 않은가?

 

역시나 이 부분에 대해서 여러사람들이 코멘트를 남긴 기록들이 존재한다.

 

특히, 눈에 들어왔던 부분은 이 부분이다.

 

srevenant commented on 3 Apr 2018

Not supporting swap as a default? I was surprised to hear this -- I thought Kubernetes was ready for the prime time? Swap is one of those features.

This is not really optional in most open use cases -- it is how the Unix ecosystem is designed to run, with the VMM switching out inactive pages.

If the choice is no swap or no memory limits, I'll choose to keep swap any day, and just spin up more hosts when I start paging, and I will still come out saving money.

Can somebody clarify -- is the problem with memory eviction only a problem if you are using memory limits in the pod definition, but otherwise, it is okay?

It'd be nice to work in a world where I have control over the way an application memory works so I don't have to worry about poor memory usage, but most applications have plenty of inactive memory space.

I honestly think this recent move to run servers without swap is driven by the PaaS providers trying to coerce people into larger memory instances--while disregarding ~40 years of memory management design. The reality is that the kernel is really good about knowing what memory pages are active or not--let it do its job.

 

결론은 srevenant씨에 따르면 기술적인 문제라기 보다는 비지니스 적인 이유라는 것이다. 좋아요를 210개 넘게 받았다..

 

그래도 쿠버네티스 측의 입장을 한번 들어보아야 하지 않을까?

 

역시내 개인적으로 눈에 들어왔던 내용을 살펴보자.

Swap Memory: The QoS proposal assumes that swap memory is disabled. If swap is enabled, then resource guarantees (for pods that specify resource requirements) will not hold. For example, suppose 2 guaranteed pods have reached their memory limit. They can start allocating memory on swap space. Eventually, if there isn’t enough swap space, processes in the pods might get killed. TODO: ensure that swap space is disabled on our cluster setups scripts.

 

또 다른 내용이다.

Adding swap slows down jobs and introducing more bandwidth to disk and isolation issues. We don't manage disk io yet, and it is hard to manage too. Without better disk io management, simply enabling swap for container/pod is bad solution.
Disabling swap is a good approach. When you have multiple containers and multiple machines they could be scheduled on, it is better to kill one container, than to have all the containers on a machine operate at an unpredictable, probably slow, rate.

 

결론은 본인들이 정의해 놓은 QoS 전략에 맞지 않고, 지원하려면 고려해야될 것들이 너무 많다.. 차라리 문제가 되는 컨테이너는 죽이고, 다른 컨테이너들은 살리겠다는 접근인 것 같다.

 

이외에 많은 쿠버네티스 엔지니어들이 여러 다양한 코멘트를 남겨놓았다. 

 

이 괜찮은 시스템을 만드는데 얼마나 많은 고생을 했을까? 그들이 남긴 코멘트에 마음이 기울었고, 현재 나는 빙산의 일각을 이해하는 입장이기 때문에 아직은 엔지니어 말에 동의해야겠다.

 

다음 포스팅에서는 Network Policy(weave container network)에 대해서 살펴보겠다.

출처

- https://github.com/kubernetes/kubernetes/issues/7294#issuecomment-215637455

- https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/proposals/resource-qos.md

- https://www.evernote.com/shard/s360/client/snv?noteGuid=caa3d18e-4bda-4516-9ec9-1180999015e2&noteKey=46fa507ba5b78edc&sn=https%3A%2F%2Fwww.evernote.com%2Fshard%2Fs360%2Fsh%2Fcaa3d18e-4bda-4516-9ec9-1180999015e2%2F46fa507ba5b78edc&title=191120%2Bwhy%2Bk8s%2Bdisable%2Bswap%253F 

- https://github.com/kubernetes/kubernetes/issues/53533

Master Node with Control Plane Components

- Master Node : Manage, Plan, Schedule, Monitor Nodes with control plane components

- 클러스트 전반에 걸친 중요한 결정을 내린다. 예를들면 스케줄링, 이벤트 감지 및 대응 등이 있다.

- Control Plane Component 들은 같은 머신에 위치시키는 것을 추천하고, 유저 컨테이너를 이 머신에서 실행시키지 말라고 한다.

- 아래는 Control Plane Component 들이다. 살펴보도록 하자.

Name Description
kube-apiserver orchestrating all operations within the cluster
- 외부에서 모니터링할 수 있도록 REST API 제공
- worker node와의 커뮤니케이션 수단 제공
kube-controller-manager HA를 유지하는데 도움을 주는 역할
- node-controller
- replication-controller
...
etcd-cluster - configuration storage with key-value format
kube-scheduler - identifies the right node to place a container based on the container's resource requirement, worker node's capacity or any other policies
container runtime engine - docker, rkt ...

 

Worker Nodes

- Host Application as Containers

Name Description
kube-proxy worker node 사이의 container들의 커뮤니케이션 수단 제공 
kubelet master node와 컨테이너 상태 등에 대해서 커뮤니케이션 및 container를 제어하는 역할
- listens for instructions from the kube-apiserver
- deploys or destroys containers on the nodes
- kube-api server periodically fetches status reports from the kubelet
container runtime engine - docker, rkt ...

 

다음 포스팅에서는 kubeadm 설치를 하며 swap을 disable 해야하는 이유에 대해서 살펴보겠다.


출처

- https://v1-18.docs.kubernetes.io/docs/concepts/overview/components/

- https://kubernetes.io/docs/concepts/overview/components/

+ Recent posts