OS Upgrades

노드의 OS Upgrade를 위해서는 노드를 정지해야한다. 이때 도커 컨테이너의 라이브 마이그레이션에 해당하는 기능이 존재하지 않아 메인터넌스 등으로 노드를 정지하는 경우 파드를 정지해야 한다. 따라서 SIGTERM, SIGKILL 신호에 동작하는 애플리케이션을 만들고 terminationGracePeriodSeconds를 적절하게 설정해야한다.

 

즉, 각 파드에 정지 처리가 실행될 때 안전하게 정지하도록 preStop 설정 / gracefulPeriod 설정 / 애플리케이션 측에서 SIGTERM 신호 핸들링 등과 같은 적절한 준비를 해두어야 한다.

 

쿠버네티스 노드는 SchedulingEnabled(Default)와 SchedulingDisabled 중 하나의 상태를 가진다. 노드가 SchedulingDisabled 상태로 변경되도 이미 노드에서 실행되는 파드에는 영향을 주지 않는다.

 

노드의 OS Upgrade 절차는 아래와 같다.

참고) 테스트를 위해 kube-controller-manager의 --pod-eviction-timeout을 사용할 수 있다.

 

첫째, 파드축출(관련 포드들을 gracefully stop 시키고, 다른 노드에 띄운다.)

배출 처리에는 이후의 스케줄링 대상에서 제외하는 처리가 포함되어 있다.

kubectl drain node_name (--force --ignore-daemonsets --delete-local-data)

--force 옵션 : 단일 파드가 있으면 삭제 후에 재성성되지 않아도 되는 경우.

--delete-local-data 옵션 : 로컬 스토리지를 사용하고 있는 경우 데이터가 삭제해도 되는 경우.

--ignore-daemonsets 옵션 : 데몬셋이 관리하는 파드도 축출하고자 하는 경우.

 

둘째, 해당 노드를 스케줄링 대상에서 제외한다. 이미 노드에서 실행되는 파드에는 영향을 주지 않는다.

kubectl cordon node_name

셋째, OS Upgrade를 진행한다.

넷째, 해당 노드를 스케줄링 대상으로 복귀시킨다.

kubectl uncordon node_name

 


Cluster Upgrade

v1.11.3 : major.minor(features, funtionalites).patch(bug fix)

v1.11.0-alpha > v1.11.0-beta > v1.11.0

kube-apiserver, controller-manager, kube-scheduler, kubelet, kube-proxy, kubectl는 같은 버전의 패키지에 포함된다.

 

kubeadm으로 쿠버네티스 클러스터를 구성했다는 가정하에 master/controlplane components의 버전을 업그레이드 하는 과정을 살펴보겠다.

 

Automatic upgrade by providers(AWS EKS, ...)

# 어떤 버전으로 업그레이드 가능한지 볼수 있음
kubectl upgrade plan
# Upgrade
kubectl upgrade apply

 

Upgrade in a hard way(kubeadm)

Master 노드

첫째, master 노드의 파드를 축출한다.

kubectl drain master --ignore-daemonsets

둘째, kubeadm tool을 업그레이드 한다.

# Kubeadm installation
apt install kubeadm=1.xx.0-00 -y

# Check kubeadm version
kubeadm version

셋째, master components를 업그레이드 한다.

# Upgrade
kubeadm upgrade apply v1.xx.0

# Check if it is Upgraded
# not yet upgraded because kubelet is not upgraded
kubectl version --short
kubectl get nodes

넷째, kubelet을 업그레이드 한다.

# upgrade the kubelet on the master node
apt install kubelet=1.xx.0-00

# Recheck if it is Upgraded
kubectl get nodes

다섯째, master node를 스케줄링 대상으로 복귀시킨다.

# Mark the master/controlplane node as "Schedulable"
kubectl uncordon controlplane

 

Work 노드

첫째, work 노드의 파드를 축출한다.

# Drain the worker node of the workloads and mark it UnSchedulable
kubectl drain node-1 --ignore-daemonsets

둘째, kubeadm tool을 업그레이드 한다.

# Kubeadm installation
apt install kubeadm=1.xx.0-00 -y

# Check kubeadm version
kubeadm version

 

셋째, worker 노드를 업그레이드 한다.

kubeadm upgrade node

넷째, local kubelet configuration을 업그레이드 한다.

# upgrade the kubelet on the worker node
apt install kubelet=1.xx.0-00

# Recheck if it is Upgraded
kubectl get nodes

다섯째, worker 노드를 스케줄링 대상으로 복귀시킨다.

# Mark the worker node as "Schedulable"
kubectl uncordon worker_node

 


ETCD

ETCD is a distributed reliable key-value store that is Simple, Secure & Fast.

HA topology

- stacked etcd architecture : each control plane node creates a local etcd member

출처 : https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/ha-topology/

- external etcd architecture : etcd members run on separate hosts

출처 : https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/ha-topology/

# cat /etc/systemd/system/kube-apiserver.service
[Service]
ExecStart=/usr/local/bin/kube-apiserver \\
  --advertise-address=${INTERNAL_IP}
  --allow-privileged=true \\
  --apiserver-count=3 \\
  --etcd-cafile=/var/lib/kubernetes/ca.pem \\
  --etcd-certfile=/var/lib/kubernetes/kubernetes.pem \\
  --etcd-keyfile=/var/lib/kubernetes/kubernetes-key.pem \\
  --etcd-servers=https://10.240.0.10:2379,https://10.240.0.11:2379

ETCD options

--listen-client-urls(2379 포트)

--listen-peer-urls : 다른 노드에서 접근시 사용(2380 포트)

--cert-file=/etc/kubernetes/pki/etc/server.crt(ETCD server certificate)

--peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt(ETCD CA certificate)

ETCD read & write

  • READ : you can easily read data from any node
  • Write : only one of the instances is responsible for processing the writes. the two nodes elect a leader among them. Of the total instances one node becomes the leader and the other node becomes the followers. If the writes came into the leader node, then the leader processes the write. The leader makes sure that the other nodes are sent a copy of the data. A write in only considered complete, if the leader gets consent from other members in the cluster.

ETCD Leader Election(RAFT protocol)

  • Quorum = N/2 + 1 : If it can be written on the majority of the nodes in the cluster, a write will be successful.
  • Fault Tolerance : HA 구성을 위해서는 1 노드가 죽더라도 Quorum 2를 유지할 수 있게 적어도 3개 노드는 필요함(recommended).
  • Even or Odd : with even number of nodes there is possibility of the cluster faliling during a network segmentation. So need to choose the odd number.
[etcd.service]
ExecStart=/usr/local/bin/etcd \\
  --name ${ETCD_NAME}
  --cert-file=/etc/etcd/kubernetes.pem \\
  --key-file=/etc/etcd/kubernetes-key.pem \\
  --peer-cert-file=/etc/etcd/kubernetes.pem \\
  --peer-key-file=/etc/etcd/kubernetes-key.pem \\
  --trusted-ca-file=/etc/etcd/ca.pem \\
  --peer-trusted-ca-file=/etc/etcd/ca.pem \\
  --peer-client-cert-auth \\
  --client-cert-auth \\
  --initial-advertise-peer-urls https://${INTERNAL_IP}:2380 \\
  --listen-peer-urls https://${INTERNAL_IP}:2380 \\
  --listen-client-urls https://${INTERNAL_IP}:2379,https://127.0.0.1:2379 \\
  --advertise-client-urls https://${INTERNAL_IP}:2379 \\
  --initial-cluster-token etcd-cluster-0 \\
  --initial-cluster peer-1=https://${PEER1_IP}:2380,peer-2=https://${PEER2_IP}:2380 \\
  --initial-cluster-state new \\
  --data-dir=/var/lib/etcd

<initial-cluster>

ETCDCTL

  • GET/PUT
export ETCDCTL_API=3
etcdctl put name john
etcdctl get name
etcdctl get / --prefix --keys-only

 

ETCD Backup and Restore configuration

  • Git에 Resource configuration(yaml ...)을 저장
  • ETCD : 스냅샷 변경시 --data-dir 설정을 확인하자.
#etcd.service
ExecStart=/usr/local/bin/etcd \\
  --name ${ETCD_NAME} \\
  --cert-file=/etc/etcd/kubernetes.pem \\
  --key-file=/etc/etcd/kubernetes-key.pem \\
  --peer-cert-file=/etc/etcd/kubernetes.pem \\
  --peer-key-file=/etc/etcd/kubernetes-key.pem \\
  --trusted-ca-file=/etc/etcd/ca.pem \\
  --peer-trusted-ca-file=/etc/etcd/ca.pem \\
  --peer-client-cert-auth \\
  --client-cert-auth \\
  --initial-advertise-peer-urls https://${INTERNAL_IP}:
  --listen-peer-urls https:${INTERNAL_IP}:2380 \\
  --listen-client-urls https:${INTERNAL_IP}:2379,
  --adverties-client-urls https:${INTERNAL_IP}:2379 \\
  --initial-cluster-token etcd-cluster-0 \\
  --initial-cluster controller-0=https://${CONTROLLER0_ \\
  --initial-cluster-state new \\
  --data-dir=/var/lib/etcd

 

ETCD - SAVE

ETCDCTL_API=3 etcdctl snapshot save snapshot.db

# With TLS-Enabled
ETCDCTL_API=3 etcdctl \
		snapshot save snapshot.db \
        --endpoints=https://127.0.0.1:2379 \
        --cacert=/etc/etcd/ca.crt \
        --cert=/etc/etcd/etcd-server.crt \
        --key=/etc/etcd/etcd-server.key

ETCD - STATUS

ETCDCTL_API=3 etcdctl snapshot status snapshot.db

ETCD - RESTORE

# Stop kube-apiserver related to ETCD
service kube-apiserver stop

# Restore
ETCDCTL_API=3 etcdctl snapshot restore snapshot.db --data-dir /var/lib/etcd-from-backup

# Option1. change --data-dir (etcd.service)
ExecStart=/usr/local/bin/etcd \\
  --name ${ETCD_NAME} \\
  --cert-file=/etc/etcd/kubernetes.pem \\
  --key-file=/etc/etcd/kubernetes-key.pem \\
  --peer-cert-file=/etc/etcd/kubernetes.pem \\
  --peer-key-file=/etc/etcd/kubernetes-key.pem \\
  --trusted-ca-file=/etc/etcd/ca.pem \\
  --peer-trusted-ca-file=/etc/etcd/ca.pem \\
  --peer-client-cert-auth \\
  --client-cert-auth \\
  --initial-advertise-peer-urls https://${INTERNAL_IP}:
  --listen-peer-urls https:${INTERNAL_IP}:2380 \\
  --listen-client-urls https:${INTERNAL_IP}:2379,
  --adverties-client-urls https:${INTERNAL_IP}:2379 \\
  --initial-cluster-token etcd-cluster-0 \\
  --initial-cluster controller-0=https://${CONTROLLER0_ \\
  --initial-cluster-state new \\
  --data-dir=/var/lib/etcd-from-backup

# Option2. etcd volume 수정
# /etc/kubernetes/manifests/etcd.yaml(etcd pod - static pod)
volumes:
  - hostPath:
      path: /var/lib/etcd-from-backup
      type: DirectoryOrCreate
    name: etcd-data


# Reload daemon
systemctl daemon-reload

# Restart ETCD
service etcd restart

# Start the kube-apiserver
service kube-apiserver start

 

Note:

If any API servers are running in your cluster, you should not attempt to restore instances of etcd. Instead, follow these steps to restore etcd:

  • stop all API server instances
  • restore state in all etcd instances
  • restart all API server instances

We also recommend restarting any components (e.g. kube-scheduler, kube-controller-manager, kubelet) to ensure that they don't rely on some stale data. Note that in practice, the restore takes a bit of time. During the restoration, critical components will lose leader lock and restart themselves.

 

 

ETCD 디버깅

  • docker ps -a | grep etcd
  • docker logs xxx(위 명령어로 docker container id를 얻는다)
  • If the etcd pod is not getting Ready 1/1, then restart it by kubectl delete pod -n kube-system etcd-controlplane and wait 1 minute.

퀴즈

1. How many nodes can host workloads in this cluster?

>> Inspect the applications and taints set on the nodes.

>> taint 걸려있지 않는 노드의 수

 

2. How many applications are hosted on the cluster?

>> Count the number of deployments

 

3. You are tasked to upgrade the cluster. you can't provision new VMs and User's accessing the applications must not be impacted. What strategy would you use to upgrade the cluster?

>> Upgrade one node at a time while moving the workloads to the other

 


출처

- [강의] udemy - Certified Kubernetes Administrator 

- [책] 쿠버네티스 완벽 가이드(마사야 아오야마 지음, 박상욱 옮김)

- https://kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/#backing-up-an-etcd-cluster

- https://github.com/etcd-io/etcd/blob/master/Documentation/op-guide/recovery.md

- https://www.youtube.com/watch?v=qRPNuT080Hk

- https://v1-19.docs.kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade/

- https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api_changes.md

- https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md

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

 

 

 

Deployment Rollout and Versioning

Use kubectl rollout to inspect a rollout as it occurse, to pause and resume a rollout, to rollback an update, and to view an object's rollout history

 

디플로이먼트 업데이트 상태 확인

kubectl rollout status deployment nginx
--
Waiting for rollout to finish: 2 out of 3 newreplicas have been updated...
deployment "nginx" successfully rolled out

디플로이먼트 업데이트 히스토리 확인

kubectl rollout history deployment nginx (--revision 3)

디폴로이먼트 변경 롤백

- 명령어의 인수로 버전 번호를 지정할 수 있으며, 0으로 지정하거나 지정하지 않을 경우에는 바로 이전 버전으로 롤백하게 된다.

kubectl rollout undo deployment nginx (--to-revision 3)

- 실제 환경에서는 롤백 기능을 사용하는 경우가 많지 않다. CI/CD 파이프라인에서 롤백을 하는 경우 kubectl rollout 명령어보다 이전 매니페스트를 다시 kubectl apply 명령어로 실행하여 적용하는 것이 호환성 면에서 더 좋기 때문이다.

 

Note: A Deployment's revision is created when a Deployment's rollout is triggered. This means that the new revision is created if and only if the Deployment's Pod template (.spec.template) is changed, for example if you update the labels or container images of the template. Other updates, such as scaling the Deployment, do not create a Deployment revision, so that you can facilitate simultaneous manual- or auto-scaling. This means that when you roll back to an earlier revision, only the Deployment's Pod template part is rolled back.

출처
https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#rolling-back-a-deployment

 

디플로이먼트 업데이트 일시 중지

kubectl rollout pause deployment nginx

디플로이먼트 업데이트 일시 정지 해제

kubectl rollout resume deployment nginx

 

Deployment Update Strategy

- Recreate : 모든 파드를 한 번 삭제하고 다시 파드를 생성하기 때문에 다운타임이 발생하지만, 추가 리소스를 사용하지 않고 전환이 빠른 것이 장점이다. 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment-recreate
spec:
  strategy:
    type: Recreate
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: nginx
          image: nginx

- Rolling update(default) : 업데이트 중에 동시에 정지 가능한 최대 파드 수(maxUnavailable)와 업데이트 중에 동시에 생성할 수 있는 최대 파드 수(maxSurge)를 설정할 수 있다. 이 설정을 사용하여 추가 리소스를 사용하지 않도록 하거나 많은 리소스를 소비하지 않고 빠르게 전환하는 등 업데이트를 하면서 동작을 제어할 수 있다. maxUnavailable과 maxSurge를 모두 0으로 설정할 수는 없다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment-rollingupdate
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: nginx
          image: nginx

 


Kubernetes command & args

Definition에 기술된 command와 args는 Dockerfile에 있는 각각 Entrypoint와 CMD를 override 한다.

- command : override entrypoint instruction

- args : override cmd instruction

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-sleeper-pod
spec:
  containers:
    - name: ubuntu-sleeper
      image: ubuntu-sleeper
      command: ["sleep", "500"] #override entrypoint instruction
      args: ["10"] #override CMD instruction

(참고) 아래와 같은 형태도 가능

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-sleeper-pod
spec:
  containers:
    - name: ubuntu-sleeper
      image: ubuntu-sleeper
      command:
      - "sleep"
      - "1200"
      args: ["--color=green"]

 

예시) Dockerfile에서 실행될 명령 : --color green

FROM python:3.7-alpine

...

ENTRYPOINT ["python", "app.py"]

CMD ["--color", "red"]
apiVersion: v1
kind: Pod
metadata:
  name: webapp-green
  labels:
    name: webapp-green
spec:
  containers:
  - name: simple-webapp
    image: xxx
    command: ["--color", "green"]

 


Configuring Application

쿠버네티스에서 개별 컨테이너의 설정 내용은 환경 변수나 파일이 저장되어 있는 영역을 마운트 하여 전달하는 것이 일반적이다. 

쿠버네티스에서 환경 변수를 전달할 때는 파드 템플릿에 env 또는 envFrom을 지정한다. 다음과 같은 다섯 가지 정보를 환경 변수에 포함시킬 수 있다.

 

참고) envFrom

kubectl explain pods --recursive | grep envFrom -A3

         envFrom	<[]Object>
            configMapRef	<Object>
               name	<string>
               optional	<boolean>

 

정적 설정/파드 정보/컨테이너 정보

apiVersion: v1
kind: Pod
metadata:
  name: env-pod
spec:
  containers:
    - name: test-container
      image: k8s.gcr.io/busybox
      command: ["echo"]
      args: ["$(TESTENV)"]
      env:
      - name: color   # 정적 설정
        value: red
      - name: K8S_NODE # 파드 정보
        valueFrom:
          fieldRef:
            fieldPath: spec.nodeName
      - name: CPU_REQUESTS # 컨테이너 정보
        valueFrom:
          resourceFieldRef:
            containerName: nginx-container
            resource: requests.cpu
      - name: TESTENV
        value: "100"

 

시크릿 리소스 기밀 정보

apiVersion: v1
kind: Secret
metadata:
  name: db-auth
data:
  host: mysql
  username: root
  password: password

환경 변수로 전달

apiVersion: v1
kind: Pod
metadata:
  name: single-env
spec:
  containers:
    - name: secret-container
      image: nginx
      # Example 1
      env:
      - name: DB_USERNAME
        valueFrom:
          secretKeyRef:
            name: db-auth
            key: username
      # Example 2
      envFrom:
      - secretRef:
          name: db-auth

볼륨으로 마운트

apiVersion: v1
kind: Pod
metadata:
  name: single-volume
spec:
  containers:
    - name: secret-container
      image: nginx
      volumeMounts:
      - name: config-volume
        mountPath: /config
  volumes:
    # Example 1
    - name: config-volume
      secret:
        secretName: db-auth
        items:
        - key: username
          path: username.txt
    # Example 2
    - name: config-volume
      secret:
        secretName: sample-db-auth

 

컨피그맵 리소스 설정값

컨피그맵은 설정 정보 등을 키-밸류 값으로 저장할 수 있는 데이터 저장 리소스다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: sample-configmap
data:
  thread: "16"
  connection.max: "100"
  connection.min: "10"
  sample.properties: |
    property.1=value-1
    property.2=value-2
    property.3=value-3
  nginx.conf: |
    user nginx;
    worker_processes auto;
    error_log /var/log/nginx/error.log;
    pid /run/nginx.pid;

 

환경변수로 전달

apiVersion: v1
kind: Pod
metadata:
  name: sample-configmap-single-env
spec:
  containers:
    - name: configmap-container
      image: nginx:1.12
      # Example 1
      env:
        - name: CONNECTION_MAX
          valueFrom:
            configMapKeyRef:
              name: sample-configmap
              key: connection.max
      # Example 2
      envFrom:
      - configMapRef:
          name: sample-configmap

볼륨으로 마운트

apiVersion: v1
kind: Pod
metadata:
  name: sample-configmap-single-volume
spec:
  containers:
    - name: configmap-container
      image: nginx:1.12
      volumeMounts:
      - name: config-volume
        mountPath: /config
  volumes:
    # Example 1
    - name: config-volume
      configMap:
        name: sample-configmap
        items:
        - key: nginx.conf
          path: nginx-sample.conf
    
    # Example 2
    - name: config-volume
      configMap:
        name: sample-configmap

 

시크릿과 컨피그맵의 사용 구분

시크릿과 컨피그맵은 비슷한 리소스들이지만, 둘의 가장 큰 차이는 시크릿이 기밀 정보를 취급하기 위한 리소스라는 점에 있다. 시크릿 데이터는 쿠버네티스 마스터가 사용하는 분산 KVC(Key-Value Store)의 etcd에 저장된다. 실제 시크릿을 사용하는 파드가 있는 경우에만 etcd에서 쿠버네티스 노드에 데이터를 보낸다. 이때 쿠버네티스 노드상에 영구적으로 데이터가 남지 않도록 시크릿 데이터는 tmps 영역(메모리상에 구축된 임시 파일 시스템)에 저장되게 되어 있다.

 

 


멀티 컨테이너 파드 디자인 패턴

사이드카 패턴(Sidecar)

사이드카 패턴은 원래 사용하려고 했던 기본컨테이너의 기능을 확장하거나 강화하는 용도의 컨테이너를 추가하는 패턴입니다. 기본 컨테이너에는 원래 목적의 기능에만 충실하고 나머지 부가적인 공통 기능들은 사이드카 컨테이너를 추가해서 사용할 수 있습니다. 일반적인 웹서버의 예를 생각해 보면 다음 그림처럼 웹서버 컨테이너는 웹서버로서의 역할에 충실하고 자신의 로그는 포드의 파일로 남깁니다. 그러면 사이드카 역할인 로그수집 컨테이너가 파일시스템에 쌓이는 로그를 수집해서 외부의 로그수집 시스템으로 보내는 역할을 합니다.

 

이렇게 구성하게 되면 웹서버 컨테이너만 다른 역할을 하는 컨테이너로 변경하게 되면 로그수집 컨테이너는 그대로 사용할 수 있습니다. 그래서 이런 공통역할을 하는 컨테이너의 재사용성을 끌어 올릴 수 있습니다. 

 

앰배서더 패턴(Ambassador)

앰배서더 패턴은 포드내에 프록시 역할을 하는 컨테이너를 추가하는 패턴입니다. 포드내에서 외부 서버에 접근할때 내부의 프록시에 접근하도록 설정하고 실제로 외부로의 연결은 프록시에서 알아서 처리하는 방식입니다. 다음 그림과 같은 구조입니다.

웹서버 컨테이너는 캐시에 접근하기 위해서 localhost로만 접근하고 실제 외부 캐시중 어디로 접근할지는 프록시 컨테이너에서 처리합니다. 

이런 방식으로 포드의 트래픽을 보다 세밀하게 제어하는 것도 가능합니다. 트래픽을 세밀하게 제어하기 위한 서비스 메시(service mesh)용 오픈소스인 이스티오(istio)를 보면 다음처럼 포드마다 프록시를 추가해서 트래픽을 처리하도록 구성되어 있는걸 확인할 수 있습니다.

어댑터 패턴(Adapter)

어댑터 컨테이너는 포드 외부로 노출되는 정보를 표준화하는 역할을 합니다. 주로 포드의 모니터링 지표를 어댑터 컨테이너를 통해서 표준화된 형식으로 노출시키고, 외부의 모니터링 시스템에서 그 데이터를 주기적으로 가져가서 모니터링하는데 이용할 수 있습니다. 다음과 같은 구조입니다.



출처: https://arisu1000.tistory.com/27863 [아리수]

 


initContainers

초기화 컨테이너(Init Container)란 파드 내부에서 메인이 되는 컨테이너를 기동하기 전에 별도의 컨테이너를 기동하기 위한 기능을 말한다. 설정에 필요한 스크립트 등을 메인 컨테이너에 보관하지 않은 상태를 유지할 수 있다(보안을 유지하고 이미지 용량을 줄임).

 

사용 사례로는 저장소에서 파일 등을 가져오는 처리, 컨테이너 기동을 지연시키는 처리, 설정 파일을 동적으로 생성하는 처리, 서비스가 생성되어 있는지 확인하는 작업과 그 외 메인 컨테이너를 기동하기 전의 체크 작업 등이 있다.

 

apiVersion: v1
kind: Pod
metadata:
  name: sample-initcontainer
spec:
  initContainers:
    - name: output-1
      image: centos:6
      command: ['sh', '-c', 'sleep 20; echo 1st > /usr/share/nginx/html/index.html']
      volumeMounts:
      - name: html-volume
        mountPath: /usr/share/nginx/html/
    - name: output-2
      image: centos:6
      command: ['sh', '-c', 'sleep 10; echo 2nd >> /usr/share/nginx/html/index.html']
      volumeMounts:
      - name: html-volume
        mountPath: /usr/share/nginx/html/
  containers:
    - name: nginx-container
      image: nginx:1.12
      volumeMounts:
      - name: html-volume
        mountPath: /usr/share/nginx/html/
  volumes:
  - name: html-volume
    emptyDir: {}

출처

Kubernetes IO

https://kubernetes.io/docs/concepts/workloads/controllers/deployment/

 

- 쿠버네티스 완벽 가이드(마사야 아오야마 지음, 박상욱 옮김)

- https://github.com/MasayaAoyama/kubernetes-perfect-guide

- https://cloud.google.com/kubernetes-engine/docs/how-to/updating-apps

- https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/

- https://kubernetes.io/docs/concepts/workloads/pods/init-containers/

[멀티컨테이너 디자인패턴]

- https://gruuuuu.github.io/cloud/design-pattern/

- https://arisu1000.tistory.com/27863

- https://velog.io/@youngerjesus/%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4-%ED%8C%A8%ED%84%B4-%EC%82%AC%EC%9D%B4%EB%93%9C%EC%B9%B4

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

AWS EKS 살펴보기  (0) 2021.10.23
Kubernetes Cluster Maintenance  (0) 2021.10.16
CKA(Certified Kubernetes Administrator) 시험 비중  (0) 2021.09.11
Kubernetes TroubleShooting  (0) 2021.09.11
docker 리소스 제한  (0) 2021.09.05

CKA 시험비중

CKA 시험 비중에 대해서 linux foundation 사이트쪽에 디테일하게 정리되어있어 

각 항목에 대해서 어떤 내용이 있을지 간단하게 살펴보도록 하자.

 

1. Storage(10%)

- Understand storage classes, persistent volumes

- Understand volume mode, access modes and reclaim policies for volumes

- Understand persistent volume claims primitive

- Know how to configure applications with persistent storage

 

Kubernetes Storage

2. Troubleshooting(30%)

- Evaluate cluster and node logging

- Understand how to monitor applications

- Manage container stdout & stderr logs

- Troubleshoot application failure

- Troubleshoot cluster component failure

- Troubleshoot networking

 

Monitoring

Troubleshooting 

 

3. Workloads & Scheduling(15%)

- Understand deployments and how to perform rolling update and rollbacks

- Use ConfigMaps and Secrets to configure applications

- Know how to scale applications

- Understand the primitives used to create robust, self-healing, application deployments

- Understand how resource limits can affect Pod scheduling

- Awareness of manifest management and common templating tools

 

Deployments rolling update & rollbacks / configmaps & secrets 관련 내용

Workloads 관련 내용

Pod scheduling 관련 내용

Helm

4. Cluster Architecture, Installation & Configuration(25%)

- Manage role based access control (RBAC)

- Use Kubeadm to install a basic cluster

- Manage a highly-available Kubernetes cluster

- Provision underlying infrastructure to deploy a Kubernetes cluster

- Perform a version upgrade on a Kubernetes cluster using Kubeadm

- Implement etcd backup and restore

 

 

Security

Kubeadm 설치

Kubernetes Cluster Maintenance

Version upgrade on a kubernetes cluster & etcd backup and restore

 

5. Services & Networking(20%)

- Understand host networking configuration on the cluster nodes

- Understand connectivity between Pods

- Understand ClusterIP, NodePort, LoadBalancer service types and endpoints

- Know how to use Ingress controllers and Ingress resources

- Know how to configure and use CoreDNS

- Choose an appropriate container network interface plugin

 

Controlplane

Networking

Network policy 관련 내용

 

6. 기타 내용 

Kubernetes Container Images

도커 관련

AWS EKS

Jsonpath 관련 내용


CKA - Certified Kubernetes Administrator의 약자

- 유효기간 : 3년

- 강의 추천 : udemy(www.udemy.com/share/101WmEB0Ibd1tXRXg=/www.udemy.com/course/certified-kubernetes-administrator-with-practice-tests/)

- Kubernetes 공식 문서 오픈푹

- 총 3시간동안 24문제

- 74% 이상 점수 획득

 

오픈북

- https://kubernetes.io/blog/

- https://github.com/kubernetes/

- [추천] https://kubernetes.io/docs/ 

 

준비물

- 여권

 

응시료 할인

- ‘Linux Foundation Coupons’

 

참고

- [Kubernetes Korea Group] : www.facebook.com/groups/k8skr/

- [Github repo] : github.com/twajr/ckad-prep-notes

- [Github repo] : github.com/dgkanatsios/CKAD-exercises

- [Github repo] : github.com/kelseyhightower/kubernetes-the-hard-way

 

사용자 설정

alias k='kubectl'

 

자주쓰는 축약어

pod : po
replicationcontroller : rc
replicaset : rs
deployment : deploy
namespace : ns
service : svc
certificatesigningrequest : csr
ingress : ing
networkpolicies : netpol
node: no
persistentvolumeclaim : pvc
persistentvolume : pv
serviceaccount : sa
daemonset : ds

--namespace : -n
--selector : -l

 


 

출처

- https://github.com/MasayaAoyama/kubernetes-perfect-guide

- https://training.linuxfoundation.org/certification/certified-kubernetes-administrator-cka/

 

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

Kubernetes Cluster Maintenance  (0) 2021.10.16
Kubernetes Application Lifecycle Management  (0) 2021.09.11
Kubernetes TroubleShooting  (0) 2021.09.11
docker 리소스 제한  (0) 2021.09.05
docker 기본  (0) 2021.09.05

쿠버네티스에서 자주 발생하는 장애상황과 해결방법에 대해서 살펴보자.

 

- Application Failure

- Control Plane Failure

- Worker Node Failure

- Network Failure

 

Case 1) Application Failure

1. 서비스 target port를 잘못 지정한 경우

2. 서비스명을 잘못 지정한 경우

3. 환경설정이 잘못된 경우(예를 들면 데이터베이스 비밀번호)

4. 서비스의 selector 설정을 잘못 지정한 경우

 

<user> <--- <web-service> <-- <webapp-mysql> <-- <mysql-service> <-- <mysql>

 

What to do

# 유저가 서비스 이용을 할 수 있는지 확인
curl http://web-service-ip:port

# 서비스의 엔드포인트가 할당이 되었는지 확인
kubectl get ep

# 환경설정에 문제가 없는지 확인
kubectl describe po <pod_name>
kubectl logs -f <pod_name> (--previous)

 

Case 2) Control Plane Failure

출처 :&nbsp;&nbsp; https://v1-18.docs.kubernetes.io/docs/concepts/overview/components/

 

What to do

# controlplane pod 상태 검사
kubectl get po -n kube-system

# controlplane pod 로그 확인
k get po -n kube-system | grep control
k logs -f <pod_name> -n kube-system

etcd-kind-cluster-control-plane                       1/1     Running   0          28m
etcd-kind-cluster-control-plane2                      1/1     Running   0          27m
etcd-kind-cluster-control-plane3                      1/1     Running   0          27m
kube-apiserver-kind-cluster-control-plane             1/1     Running   0          28m
kube-apiserver-kind-cluster-control-plane2            1/1     Running   0          27m
kube-apiserver-kind-cluster-control-plane3            1/1     Running   1          27m
kube-controller-manager-kind-cluster-control-plane    1/1     Running   1          28m
kube-controller-manager-kind-cluster-control-plane2   1/1     Running   0          27m
kube-controller-manager-kind-cluster-control-plane3   1/1     Running   0          27m
kube-scheduler-kind-cluster-control-plane             1/1     Running   1          28m
kube-scheduler-kind-cluster-control-plane2            1/1     Running   0          26m
kube-scheduler-kind-cluster-control-plane3            1/1     Running   0          27m

 

만약 필수적으로 있어야하는 컴포넌트가 kube-system 네임스페이스의 pod 리스트에 나타나지 않는다면 manifest 파일을 확인해하자.

 

몇몇 컴포넌트들은 pod 이름에 실행중인 노드의 이름(static pod)이 붙는다.(kube-apiserver-kind-cluster-control-plane)

static pod의 manifest 파일의 위치는 보통 /etc/kubernetes/manifest 이다. manifest 파일을 열어보고 설정이 잘못되어있는지 확인한다.

root@controlplane:/etc/kubernetes/manifests# ls
etcd.yaml  kube-apiserver.yaml  kube-controller-manager.yaml  kube-scheduler.yaml

 

참고로 시스템 로그를 확인하고 싶다면 journalctl를 활용하자.

sudo journalctl -u kube-apiserver

 

Worker Node Failure

- kubelet

- kube-proxy

 

What todo

# 워커 노드 조회
k get no | grep worker

kind-cluster-worker           Ready    <none>   40m   v1.18.2
kind-cluster-worker2          Ready    <none>   40m   v1.18.2
kind-cluster-worker3          Ready    <none>   40m   v1.18.2

# 워커노드 상세 조회
k describe no kind-cluster-worker

kind-cluster-worker
Name:               kind-cluster-worker
Roles:              <none>
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/os=linux
                    kubernetes.io/arch=amd64
                    kubernetes.io/hostname=kind-cluster-worker
                    kubernetes.io/os=linux
Annotations:        kubeadm.alpha.kubernetes.io/cri-socket: unix:///run/containerd/containerd.sock
                    node.alpha.kubernetes.io/ttl: 0
                    volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp:  Sat, 11 Sep 2021 13:33:52 +0900
Taints:             <none>
Unschedulable:      false
Lease:
  HolderIdentity:  kind-cluster-worker
  AcquireTime:     <unset>
  RenewTime:       Sat, 11 Sep 2021 14:15:11 +0900
Conditions:
  Type             Status  LastHeartbeatTime                 LastTransitionTime                Reason                       Message
  ----             ------  -----------------                 ------------------                ------                       -------
  MemoryPressure   False   Sat, 11 Sep 2021 14:14:10 +0900   Sat, 11 Sep 2021 13:33:52 +0900   KubeletHasSufficientMemory   kubelet has sufficient memory available
  DiskPressure     False   Sat, 11 Sep 2021 14:14:10 +0900   Sat, 11 Sep 2021 13:33:52 +0900   KubeletHasNoDiskPressure     kubelet has no disk pressure
  PIDPressure      False   Sat, 11 Sep 2021 14:14:10 +0900   Sat, 11 Sep 2021 13:33:52 +0900   KubeletHasSufficientPID      kubelet has sufficient PID available
  Ready            True    Sat, 11 Sep 2021 14:14:10 +0900   Sat, 11 Sep 2021 13:34:12 +0900   KubeletReady                 kubelet is posting ready status
Addresses:
  InternalIP:  172.18.0.5
  Hostname:    kind-cluster-worker
Capacity:
  cpu:                6
  ephemeral-storage:  61255492Ki
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  memory:             2034968Ki
  pods:               110
Allocatable:
  cpu:                6
  ephemeral-storage:  61255492Ki
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  memory:             2034968Ki
  pods:               110
System Info:
  Machine ID:                 ec42c7f79c1042d7ab10c3d1374cce50
  System UUID:                28ec7417-523f-4269-b855-0868e56b2a17
  Boot ID:                    fbeca5f2-a9ad-45b8-a6a5-f50b368b90f9
  Kernel Version:             5.10.25-linuxkit
  OS Image:                   Ubuntu 20.04 LTS
  Operating System:           linux
  Architecture:               amd64
  Container Runtime Version:  containerd://1.3.3-14-g449e9269
  Kubelet Version:            v1.18.2
  Kube-Proxy Version:         v1.18.2
PodCIDR:                      10.244.4.0/24
PodCIDRs:                     10.244.4.0/24
ProviderID:                   kind://docker/kind-cluster/kind-cluster-worker
Non-terminated Pods:          (2 in total)
  Namespace                   Name                CPU Requests  CPU Limits  Memory Requests  Memory Limits  AGE
  ---------                   ----                ------------  ----------  ---------------  -------------  ---
  kube-system                 kindnet-8mspw       100m (1%)     100m (1%)   50Mi (2%)        50Mi (2%)      41m
  kube-system                 kube-proxy-rb6tg    0 (0%)        0 (0%)      0 (0%)           0 (0%)         41m
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests   Limits
  --------           --------   ------
  cpu                100m (1%)  100m (1%)
  memory             50Mi (2%)  50Mi (2%)
  ephemeral-storage  0 (0%)     0 (0%)
  hugepages-1Gi      0 (0%)     0 (0%)
  hugepages-2Mi      0 (0%)     0 (0%)
Events:
  Type    Reason                   Age                From        Message
  ----    ------                   ----               ----        -------
  Normal  NodeHasSufficientMemory  41m (x8 over 41m)  kubelet     Node kind-cluster-worker status is now: NodeHasSufficientMemory
  Normal  NodeHasNoDiskPressure    41m (x8 over 41m)  kubelet     Node kind-cluster-worker status is now: NodeHasNoDiskPressure
  Normal  Starting                 41m                kube-proxy  Starting kube-proxy.

워커 노드를 상세조회하면 Condition 항목이 있는데 이를 통해 OutOfDisk, MemoryPresure, DiskPresure, PIDPresure 상태를 살펴볼 수 있다.

 

예를들면 MemoryPresure 생태가 True이면 메모리가 부족하다는 이야기이다.

 

각 노드에 접속하여 top, df -h 등으로 보다 상세하게 노드의 상태를 검사할 수 있다.

 

가끔 상태가 Unknown인 경우가 있는데 이때는 kubelet 상태를 의심해보아야한다.

service kubelet status
sudo journalctl -u kubelet (-f)

보통 kubelet 설정 파일의 위치는 /var/lib/kubelet/config 이므로 파일을 열어 설정이 잘못되었는지 확인한다.

그 뒤 변경이 있으면 systemctl daemon-reload -> systemctl restart kubelet 을 실행하여 변경내용을 적용하자.

 

혹은 kubelet manifest 파일 내용이 잘못되었을지 모른다.

 

파일의 위치는 보통 /etc/kubernetes/kubelet.conf 이므로 잘못된 정보가 있는지 확인한다.

예를들면 kube-apiserver의 port가 잘못설정되어있을 수 있다.

 

참고) kubelet certificate 확인

openssl -x509 -in /var/lib/kubelet/worker-1.crt -text(right CA, right croup ...)


Certificate:
	Data: xxx
    Signature Algorithm: xxx
    	Issuer: xxx
        Validity
        	Not Before: xxx
            Not After : xxx
        Subject: xxx
        ...

 

Networking Failure

- CNI : kubelet configuration에서 cin-bin-dir, network-pluin 설정이 제대로 되어 있는지 확인.

- DNS

- Proxy

 

What to do for DNS failure

kubectl edit cm coredns -n kube-system

apiVersion: v1
data:
  Corefile: |
    .:53 {
        errors
        health {
           lameduck 5s
        }
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
           pods insecure
           fallthrough in-addr.arpa ip6.arpa
           ttl 30
        }
        prometheus :9153
        forward . /etc/resolv.conf
        cache 30
        loop
        reload
        loadbalance
    }
kind: ConfigMap
metadata:
  creationTimestamp: "2021-09-11T04:32:04Z"
  name: coredns
  namespace: kube-system
  resourceVersion: "247"
  selfLink: /api/v1/namespaces/kube-system/configmaps/coredns
  uid: 2f2d4f33-0ef1-4e37-b215-2e4034aac6f7

Port 53은 DNS resolution으로 사용되고 있다.

 

coreDNS 문제는 3가지로 나뉠 수 있다.

첫째, coredns pod가 pending 상태일 경우 : 네트워크 플러그인이 정상적으로 설치되었는지 확인하자.

둘째, coredns pod가 CrashLoopBackOff 또는 에러 상태일 경우 : 설치된 OS와 도커의 버전 및 권한 문제일 수 있다.

셋째, coredns와 관련된 pod가 모두 정상일 경우 : 서비스 엔드포인트, selector, port를 확인하자.

kubectl get ep kube-dns -n kube-system
NAME       ENDPOINTS                                                 AGE
kube-dns   10.244.0.3:53,10.244.0.4:53,10.244.0.3:9153 + 3 more...   72m

 

What to do for Proxy failure

kubeproxy is responsible for watching services and endpoint associated with each service. When the client is going to connect to the service using the virtual IP the kubeproxy is responsible for sending traffic to actual pods.

 

kube-proxy는 daemonset으로 배포된다.

k describe ds kube-proxy -n kube-system

Name:           kube-proxy
Selector:       k8s-app=kube-proxy
Node-Selector:  kubernetes.io/os=linux
Labels:         k8s-app=kube-proxy
Annotations:    deprecated.daemonset.template.generation: 1
Desired Number of Nodes Scheduled: 6
Current Number of Nodes Scheduled: 6
Number of Nodes Scheduled with Up-to-date Pods: 6
Number of Nodes Scheduled with Available Pods: 6
Number of Nodes Misscheduled: 0
Pods Status:  6 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:           k8s-app=kube-proxy
  Service Account:  kube-proxy
  Containers:
   kube-proxy:
    Image:      k8s.gcr.io/kube-proxy:v1.18.2
    Port:       <none>
    Host Port:  <none>
    Command:
      /usr/local/bin/kube-proxy
      --config=/var/lib/kube-proxy/config.conf
      --hostname-override=$(NODE_NAME)
    Environment:
      NODE_NAME:   (v1:spec.nodeName)
    Mounts:
      /lib/modules from lib-modules (ro)
      /run/xtables.lock from xtables-lock (rw)
      /var/lib/kube-proxy from kube-proxy (rw)
  Volumes:
   kube-proxy:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      kube-proxy
    Optional:  false
   xtables-lock:
    Type:          HostPath (bare host directory volume)
    Path:          /run/xtables.lock
    HostPathType:  FileOrCreate
   lib-modules:
    Type:               HostPath (bare host directory volume)
    Path:               /lib/modules
    HostPathType:       
  Priority Class Name:  system-node-critical
Events:                 <none>

 

kube-proxy pod 가 정상 상태가 아니거나 로그 확인 결과 문제점이 있는 경우가 있다.

k get po -n kube-system | grep kube-proxy
k logs <pod_name> -n kube-system

kube-proxy-4g89x                                      1/1     Running   0          83m
kube-proxy-6tp9m                                      1/1     Running   0          85m
kube-proxy-lvvh5                                      1/1     Running   0          84m
kube-proxy-r5vqz                                      1/1     Running   0          83m
kube-proxy-rb6tg                                      1/1     Running   0          83m
kube-proxy-t58hp                                      1/1     Running   0          83m

또는 컨테이너 내부에서 kube-proxy가 정상적으로 동작하고 있지 않은 경우가 있다.

# netstat -plan | grep kube-proxy
tcp        0      0 0.0.0.0:30081           0.0.0.0:*               LISTEN      1/kube-proxy
tcp        0      0 127.0.0.1:10249         0.0.0.0:*               LISTEN      1/kube-proxy
tcp        0      0 172.17.0.12:33706       172.17.0.12:6443        ESTABLISHED 1/kube-proxy
tcp6       0      0 :::10256                :::*

이때에는 kube-proxy damonset 정의가 올바르게 되어 있는지 확인해보자. 특히 kube-proxy binary 가 올바르게 작성되어있는지 확인하자.

 


출처

- https://kubernetes.io/docs/tasks/administer-cluster/dns-debugging-resolution/

- https://kubernetes.io/docs/tasks/debug-application-cluster/debug-service/

- https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/

- https://kind.sigs.k8s.io/docs/user/quick-start/

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

+ Recent posts