쿠버네티스는 가장 기본적인 구성단위가 되는 오브젝트와, 이 기본 오브젝트를 생성하고 관리하는 추가적인 기능을 가진 컨트롤러(Controller)로 이루어진다. 컨트롤러는 다양한 형태의 워크로드를 지원하고, 다양한 시나리오에 맞게 Pod를 운영할 수 있도록 지원한다.

 

기본 오브젝트 

쿠버네티스에 의해서 배포 및 관리되는 가장 기본적인 오브젝트는 컨테이너화되어 배포되는 애플리케이션의 워크로드를 기술하는 오브젝트로 Pod, Service, Volume, Namespace 4가지가 있다.

 

# Pod

- Pod는 쿠버네티스에서 가장 기본적은 배포 단위로, 하나 이상의 컨테이너를 포함하는 단위이다. Pod 안의 컨테이너들은 IP와 Port를 공유하고, 디스크 볼륨을 공유하는 특징을 갖는다.

- 실행중인 포드의 환경설정, service account, resource limit을 수정할 수 없다.

- Pod는 재시작하면 기록이 모두 지워지기 때문에 --restart=Never 로 실행한다.

 

참고) 애플리케이션 배포시에 항상 함께 사용하는 프로그램을 같이 배포할 수 있는데 이런 경우에 Pod가 유용하게 활용될 수 있다.

 

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
    type: front-end
spec:
  containers:
    - name: nginx-container
      image: nginx
      ports:
        - containerPort: 8080
# 포드 생성
kubectl run nginx --image=nginx --labels=tier=db --port=8080 (container port)
kubectl run httpd --image=httpd:alpine --port 80 --expose --dry-run-client -o yaml (cluster ip)

# 포드 이미지
kubectl describe pod pod_name | grep -i image

# 포드의 노드 이름
kubectl get pods -o wide --show-labels
kubectl get pods --selector app=App1
kubectl get pods -l env=dev,bu=finance,tier=frontend --no-headers | wc -l
kubectl get all 

# 특정 포드 조회
kubectl get pods webapp

# 포드 삭제
kubectl delete pod webapp

# 포드 YAML 및 실행
kubectl run redis --image=redis --dry-run=client -o yaml > pod.yaml
kubectl run mosquito --image nginx --restart=Never
kubectl apply -f pod.yaml

# 포드 Config 수정
kubectl edit pod redis

kubectl explain pod --recursive | less

 

# Service & Service Type

- 지정된 IP로 생성 가능(Pod의 경우에 지정되는 IP가 랜덤하게 지정이 되고, 리스타트 때마다 변함)

- 여러 Pod에 같은 애플리케이션을 운용할 경우 이 Pod 간의 LB를 지원

- 고유한 DNS 이름을 가질 수 있음

ClusterIP

Exposes the Service on a cluster-internal IP. Choosing this value makes the Service only reachable from within the cluster. This is the default ServiceType.

apiVersion: v1
kind: Service
metadata:
  name: back-end
spec:
  type: ClusterIP
  ports:
    - protocol: TCP
    - targetPort: 80 #default(same as port)
      port: 80
  selector: #labels
    app: myapp
    type: back-end
# Create a Service named redis-service of type ClusterIP to expose pod redis on port 6379
kubectl expose pod redis --name redis-service --port=6379 --target-port 6379
kubectl expose pod redis --port=6379 --name redis-service --dry-run=client -o yaml
kubectl create service clusterip redis --tcp=6379:6379 --dry-run=client -o yaml

LoadBalancer

Exposes the Service externally using a cloud provider's load balancer. NodePort and ClusterIP Services, to which the external load balancer routes, are automatically created.

 

apiVersion: v1
kind: Service
metadata:
  name: back-end
spec:
  type: LoadBalancer
  ports:
    - targetPort: 80 #default(same as port)
      port: 80
      nodePort: 30008 #range(30000 ~ 32767)
  selector: #labels
    app: myapp
    type: back-end

 

참고) AWS EKS lb

apiVersion: v1
kind: Service
metadata:
  name: web-service
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
    service.beta.kubernetes.io/aws-load-balancer-ssl-cert: xxx
    service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https"
  namespace: default
spec:
  ports:
  - name: http
    port: 80
    targetPort: 80
  - name: https
    port: 443
    targetPort: 80
  selector:
    run: web-app
  type: LoadBalancer

 

NodePort

Exposes the Service on each Node's IP at a static port (the NodePort). A ClusterIP Service, to which the NodePort Service routes, is automatically created. You'll be able to contact the NodePort Service, from outside the cluster, by requesting :<NodeIP>:<NodePort>

apiVersion: v1
kind: Service
metadata:
  name: hello-node-svc
spec:
  selector:
    app: hello-node
  type: NodePort
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: 8080
      nodePort: 30036

출처 : ttps://bcho.tistory.com/1262

# service 생성
kubectl expose deploy simple-webapp-deployment --name=webapp-service --target-port=8080 --type=NodePort --port=8080 --dry-run=client -o yaml > test.yaml

# Create a Service named nginx of type NodePort to expose pod nginx port 80 on port 30080 on the nodes
kubectl expose pod nginx --port=80 --name nginx-service --type=NodePort --dry-run=client -o yaml (recommended)
kubectl create service nodeport nginx --tcp=80:80 --node-port=30080 --dry-run=client -o yaml

# Namespace

네임스페이스는 쿠버네티스 클러스터내의 논리적인 분리단위라고 할 수 있다.

- 네임스페이스별로 리소스를 나눠서 관리할 수 있다.(Pod, Service)

- 사용자별로 네임스페이스별 접근 권한을 다르게 운영할 수 있다.

- 네임스페이스별로 리소스의 할당량을 지정할 수 있다.

 

네임스페이스는 논리적인 분리이기 때문에 분리 정책을 적용하지 않는 이상 네임스페이스간의 통신이 가능하다.

apiVersion: v1
kind: Namespace
metadata:
  name: dev
# namespace 생성
kubectl create namespace dev

# default namespace 변경
kubectl config set-context $(kubectl config current-context) --namespace=dev

# namespace 카운트
k get ns --no-headers | wc -l

# namespace 포드 생성
k run redis -n xxx --image=redis --dry-run=client -o yaml > test.yaml

# pod namespace 조회
k get pods --all-namespaces | grep blue

# fqdn(fully qualified domain name)
serviceName.ns.svc.cluster.local

 

컨트롤러

# Replicaset(Previous name : Replication Controller)

- High Availability

- Load Balancing & Scaling

- Self-healing

 

Kubernetes supports self-healing applications through ReplicaSets and Replication Controllers. The replication controller helps in ensuring that a POD is re-created automatically when the application within the POD crashes. It helps in ensuring enough replicas of the application are running at all times.

 

Kubernetes provides additional support to check the health of applications running within PODs and take necessary actions through Liveness and Readiness Probes.

 

apiVersion: v1
kind: ReplicationController
metadata:
  name: myapp-rc
  labels:
    app: myapp
    type: front-end
  annotations:
    buildversion: 1.34
spec: Pod 영역
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: simple-webapp
  labels:
    app: myapp1
    type: front-end
spec:
  replicas: 3
  selector:
    matchLabels: #important!
      app: myapp
  template:
    metadata:
      labels:
        app: myapp #important!
        type: front-end
    spec:
      containers:
        - name: simple-webapp
          image: simple-webapp
# replicaset의 개수
kubectl get replicasets.apps

# replicaset 이미지
kubectl describe replicasets.apps new-replica-set

# replicaset 삭제
kubectl delete replicasets.apps replicaset-1

# replicaset 수정
kubectl edit replicasets.apps replicaset-1

# replicaset replica 수정
kubectl scale replicaset --replicas=5 new-replica-set

 

# Deployment Controller

Deployment is an object which can own ReplicaSets and update them and their Pods via declarative, server-side rolling updates. While ReplicaSets can be used independently, today they're mainly used by Deployments as a mechanism to orchestrate Pod creation, deletion and updates. When you use Deployments you don't have to worry about managing the ReplicaSets that they create. Deployments own and manage their ReplicaSets. As such, it is recommended to use Deployments when you want ReplicaSets.

 

With Deployments you can easily edit any field/property of the POD template.

# deploy의 개수
kubectl get deployments.apps

# deploy 이미지
kubectl describe deployments.apps new-deploy | grep -i image

kubectl create deployment httpd-frontend --image=xxxx

kubectl scale deploy httpd-frontend --replicas=3 

kubectl get deployments.apps httpd-frontend

kubectl create deploy --image=nginx nginx --dry-run=client -o yaml > test.ayml

kubectl create deploy --image=nginx nginx --replicas=4

 

참고) rolling updates

롤링 업데이트 방식은 Pod를 하나씩 업그레이드 해가는 방식이다.

출처 : https://bcho.tistory.com/1256

롤링 업데이트 실패시 수동으로 롤백해주어야한다.

# you can rollback to a specific revision by specifying it with --to-revision
kubectl rollout undo deployment.v1.apps/nginx-deployment --to-revision=2

 

고급 컨트롤러

# DaemonSets

출처 : https://bcho.tistory.com/1257

Pod가 각각의 노드에서 하나씩만 돌게 하는 형태로 Pod를 관리하는 컨트롤러. 모니터링 용도(예를들면 fluentd로 많이 사용된다.)로 많이 쓰임.

- kube-proxy

- network

DaemonSets은 특정 노드에만 Pod를 배포할 수 있도록, node selector를 이용해서 특정 노드만을 선택할 수 있게 지원한다.

 

apiVersion: apps/v1
kind: DaemonSet
metadata:
	name: monitoring-daemon
spec:
	selector:
    	matchLabels:
        	app: monitoring-agent
    template:
    	metadata:
        	labels:
            	app: monitoring-agent
        spec:
        	containers:
            - name: monitoring-agent
              image: monitoring-agent
kubectl get ds --all-namespaces
kubectl -n kube-system describe ds weave-net | grep -i image
# DaemonSet 생성시 deploy로 생성하고, 필요없는 부분 삭제
# Deploy -> DaemonSet 변경 / replicas, strategy 제거
kubectl create deploy elasticsearch --image=xxx --dry-run -o yaml > elastic.yaml

 

# StatefulSet

데이터베이스와 같이 상태를 가지는 애플리케이션을 관리하기 위한 컨트롤러.

 

기존 컨트롤러는 아래와 같은 문제점이 있음.

- Pod의 이름이 불규칙적이다.

마스터/슬레이브 구조를 가지는 데이터베이스 등에서 마스터 서버의 이름을 특정 이름으로 지정할 수가 없다.

- Stateless Pod들은 기동이 될때 병렬로 동시에 기동된다.

데이터베이스의 경우에는 마스터 노드가 기동된 다음 스레이브 노드가 순차적으로 기동되어야하는 순차성을 가지고 있는 경우가 있음.

- 볼륨 마운트

맨 처음 생성된 Pod가 PVC와 PV에 연결이 되기 때문에 뒤에 생성되는 Pod들은 PVC를 얻지 못해서 디스크를 사용할 수 없음.

출처 : https://bcho.tistory.com/1306

Statefulset은 앞서 설명한 stateless 애플리케이션이 관리하는 컨트롤러로 할 수 없는 기능을 제공한다. 대표적인 기능들은 아래와 같다.

- Pod 이름에 대한 규칙성을 부여

생성된 Pod들은 {Pod name}-{num} 식으로 이름이 정해진다. 예를들면 cassandra-0, cassandra-1 … 가 된다.

- 배포시 순차적인 기동과 업데이트

동시에 모든 Pod를 생성하지 않고, 0, 1, 2 … 순서대로 하나씩 Pod를 생성한다. 이러한 순차기동은 데이터베이스에서 마스터 노드가 기동된 후에, 슬레이브 노드가 기동되어야 하는 조건등에 유용하게 사용될 수 있다.

- 개별 Pod에 대한 디스크 볼륨 관리

Pod 마다 각각 PVC와 PV를 생성하여 관리할 수 있도록한다.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: cassandra
  labels:
    app: cassandra
spec:
  serviceName: cassandra
  replicas: 3
  selector:
    matchLabels:
      app: cassandra
  template:
    metadata:
      labels:
        app: cassandra
    spec:
      terminationGracePeriodSeconds: 1800
      containers:
      - name: cassandra
        image: gcr.io/google-samples/cassandra:v13
        imagePullPolicy: Always
        ports:
        - containerPort: 7000
          name: intra-node
        - containerPort: 7001
          name: tls-intra-node
        - containerPort: 7199
          name: jmx
        - containerPort: 9042
          name: cql
        resources:
          limits:
            cpu: "500m"
            memory: 1Gi
          requests:
            cpu: "500m"
            memory: 1Gi
        securityContext:
          capabilities:
            add:
              - IPC_LOCK
        lifecycle:
          preStop:
            exec:
              command: 
              - /bin/sh
              - -c
              - nodetool drain
        env:
          - name: MAX_HEAP_SIZE
            value: 512M
          - name: HEAP_NEWSIZE
            value: 100M
          - name: CASSANDRA_SEEDS
            value: "cassandra-0.cassandra.default.svc.cluster.local"
          - name: CASSANDRA_CLUSTER_NAME
            value: "K8Demo"
          - name: CASSANDRA_DC
            value: "DC1-K8Demo"
          - name: CASSANDRA_RACK
            value: "Rack1-K8Demo"
          - name: POD_IP
            valueFrom:
              fieldRef:
                fieldPath: status.podIP
        readinessProbe:
          exec:
            command:
            - /bin/bash
            - -c
            - /ready-probe.sh
          initialDelaySeconds: 15
          timeoutSeconds: 5
        # These volume mounts are persistent. They are like inline claims,
        # but not exactly because the names need to match exactly one of
        # the stateful pod volumes.
        volumeMounts:
        - name: cassandra-data
          mountPath: /cassandra_data
  # These are converted to volume claims by the controller
  # and mounted at the paths mentioned above.
  # do not use these in production until ssd GCEPersistentDisk or other ssd pd
  volumeClaimTemplates:
  - metadata:
      name: cassandra-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: fast
      resources:
        requests:
          storage: 1Gi
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: fast
provisioner: k8s.io/minikube-hostpath
parameters:
  type: pd-ssd

 

이때, PVC의 이름은 {StatefulSet}-{Pod name}으로 생성된다.

 

Static Pods

- kube-apiserver와 kube-sceduler 등 클러스터에서 지원하는 기능(control plane) 없이 Pod를 관리하고 싶은 경우

- 노드명이 suffix로 붙음(kubectl get pods --all-namespaces | grep "\-master")

- manifests 폴더에 있는 yaml 파일들이 static pod 정의(해당 위치에있는 yaml 파일들은 자동으로 만들어짐)

Static pods DaemonSets
Created by the Kubelet Created by Kube-API server(DaemonSet Controller)
Deploy Control plane components as static pods deploy monitoring agents, logging agents on nodes
lgnored by the kube-scheduler

- how to kill delete static pod

root@controlplane:~# kubectl get pods --all-namespaces -o wide  | grep static-greenbox
default       static-greenbox-node01                 1/1     Running   0          19s     10.244.1.2   node01       <none>           <none>
root@controlplane:~#

root@controlplane:~# ssh node01(172.17.0.41) 

root@node01:~# ps -ef |  grep /usr/bin/kubelet   (ps -ef | grep kubelet | grep "\--config")
root       752   654  0 00:30 pts/0    00:00:00 grep --color=auto /usr/bin/kubelet
root     28567     1  0 00:22 ?        00:00:11 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.2
root@node01:~# grep -i staticpod /var/lib/kubelet/config.yaml
staticPodPath: /etc/just-to-mess-with-you
root@node01:~# 

root@node01:/etc/just-to-mess-with-you# ls
greenbox.yaml
root@node01:/etc/just-to-mess-with-you# rm -rf greenbox.yaml 
root@node01:/etc/just-to-mess-with-you#

# Exit out of node01
root@controlplane:~# kubectl get pods --all-namespaces -o wide  | grep static-greenbox
root@controlplane:~#

참고) static pod 실행시 --restart=Never를 잊지말자.

 

 

다음 포스팅에서는 쿠버네티스 스케줄러에 대해서 살펴보도록 하겠습니다.

 


출처

- https://kubernetes.io/docs/tutorials/stateful-application/cassandra/

- https://bcho.tistory.com/1306

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

- https://www.weave.works/blog/optimizing-cluster-resources-for-kubernetes-team-development

- https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/

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

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

- https://kubernetes.io/docs/reference/command-line-tools-reference/kube-controller-manager/

 

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

docker 기본  (0) 2021.09.05
Kubernetes Pod Scheduling  (0) 2021.08.13
Kubernetes JSONPATH 사용법  (0) 2021.08.08
Kubernetes Network Model & Policy  (0) 2021.07.08
Kubeadm Swap Disable  (0) 2021.07.04

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

개발 환경이 변경되거나 솔루션을 판매할때 플랫폼에 필요한 시스템 데이터를 세팅해야 될 경우가 있다. 이를 위해 필요한 내용에 대해서 간단히 살펴보겠다.

 

Contents

- Workbench를 활용하여 MySQL 5.7에 저장된 데이터를 export & import 하는 방법

- 마스터 유저생성 및 권한할당

- 스카마 이름을 변경하는 방법

 

How to Export 

  1. Data Export to Self-Contained File
  2. Advanced Options → set-gtid-purged → OFF 설정

 

3. Export!

4. View를 사용한다면 xxx.sql을 열고, DEFINER의 계정을 확인하자. Import 하고자하는 계정으로 설정!

/*!50013 DEFINER=admin@% SQL SECURITY DEFINER */

 

Import

  1. Import from Self-Contained File
  2. Default Target Schema : 데이터베이스가 생성되어 있지않다면 생성하자.
  3. Import!

 

 


마스터 유저 생성 및 권한 할당

mysql> SHOW GRANTS for master_username; # 권한 확인

 

mysql> CREATE USER 'new_master_user'@'%' IDENTIFIED BY 'password'; # 새로운 마스터 유저 생성, 외부에서의 접근을 허용

mysql> GRANT ALL PRIVILEGES ON schema_name.* TO 'new_master_user'@'%' IDENTIFIED BY 'password'; # 모든 원격지에서의 schema_name 스키마의 모든 테이블에 대해서 new_aster_user 유저에게 모든 권한을 부여

 


스키마 이름 변경

RENAMTE TABLE Statement

RENAME TABLE
    tbl_name TO new_tbl_name
    [, tbl_name2 TO new_tbl_name2] ...

 

todos -> self_todolist 예시

RENAME TABLE todos.company TO self_todolist.company,
			 todos.todo TO self_todolist.todo,
             todos.todo_has_ref TO self_todolist.todo_has_ref,
             todos.user TO self_todolist.user,
             todos.user_auth TO self_todolist.user_auth,
             todos.user_grp TO self_todolist.user_grp,
             todos.user_role TO self_todolist.user_role,
             todos.user_role_has_user_auth TO self_todolist.user_role_has_user_auth

출처

- https://dev.mysql.com/doc/refman/5.6/en/rename-table.html

- https://www.quora.com/How-can-I-rename-a-schema-with-MySQL-Workbench-using-MySQL-5-6

- https://nickjoit.tistory.com/144

- https://aws.amazon.com/ko/premiumsupport/knowledge-center/duplicate-master-user-mysql/

쿠버네티스 클러스터 구성 중에 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

+ Recent posts