본문 바로가기

Kubernates

쿠버네티스 101

자료 출처 -  Mumshad Mannambeth 강의 from UDEMY

 

Worker 내부 기본적으로 Docker 컨테이너 인터페이스를 사용하지만

쿠버네티스의 Container Runtime Interface (CLI) 를 통해 다양한 인터페이스 호환이 가능함

 

Master Node - ETCD Cluster (1) / kube-apiserver (2) / kube-controller Manager (3) / kube-scheduler (4)

Workder Node - kubelet (5) / kube-proxy (6) 

 

ETCD Cluster (1)

key-value store 형식으로 독자적인 형태로 다양한 데이터 보관 :2379 \\

ETCD 를 직접 구성하기 VS Kubeadm 으로 구성하기 

 

kube-apiserver (2) 

가장 먼저 명령어를 관할 하는 부분 

 

cat /etc/kubernetes/manifests/kube-apiserver.yaml

OR

cat /etc/systemd/system/kube-apiserver.service

 

ps -aux | grep kube-apiserver 

 

kube-controller Manager (3)

실시간으로 자원을 모니터링하면서 조절하는 부분

 

cat /etc/kubernetes/manifests/kube-controller-manager.yaml

OR

cat /etc/systemd/system/kube-controller-manager.service

ps -aux | grep kube-controller-manager

 

kube-scheduler (4)

파드를 노드에 스케쥴링 결정 하는 부분 

 

cat /etc/kubernetes/manifests/kube-scheduler.yaml

 

ps -aux | grep kube-scheduler

 

kubelet (5) 

각 노드에서 자원 관리 / Pod

 

kubelet 설치위해 다운 받아도 직접 설정 필요함

 

ps -aux | grep kubelet

 

kube-proxy (6) 

각 노드에서 서비스로 통신하기위해 룰 설정

 

kubeadm 설치 시 deamoset 으로 설정됨

 

Pod

 

기본적으로 노드 내부에 파드 

파드 내부에 컨테이너

 

가용성을 높이기 위해선 파드 내부에 컨테이너 형식으로 노드안에 같은 파드를 여러개 생성 & 노드와 파드 함께 추가 생성

파드에 다수의 컨테이너가 위치하는 경우에는 각 개체들이 서로 같은 네트워크/스토리지 공유하며 파드가 죽으면 다 함께 운명을 맞이함 (컨테이너 종류는 다른편)

 

kubectl run nginx --image=nginx

nginx 이름을 가진 nginx 이미지를 가진 파드 생성

kubet get pods

파드 불러오기

kubectl describe pod pod-name

파드 자세히 불러오기 

kubectl create -f pod.yaml

kubectl apply -f pod.yaml

yaml 로 파일 생성하기 

kubectl delete pod pod-name

파드 삭제하기

 

yaml 기본 예시

apiVersion: v1 
kind: Pod
metadata: #파드 주관적인 정의 (파드 이름이나 레이블 등등)
  name: nginx
spec: #컨테이너 객관적인 정의 (컨테이너 구성 요소 이름이나 이미지 등등)
  containers:
  - name: nginx
    image: nginx:1.14.2
  - name: busybox #멀티 컨테이너의 경우 추가 방식

 

 

Replication Controller & Replica Set

 

파드 1개로 운용하거나 가용성을 위해 여러개를 운용할때 정해둔 개수만큼 꼭 돌아가게 하기 위해 조절해주는 역할

Label 로 모니터링할 아이들을 인식함

 

스케일링(파드 개수 늘리기)

kubectl replace -f rs.yaml

파일 자체 수정후 변경

kubectl scale --replicas=3 -f rs.yaml

kubectl scale --replicas=3 replicaset rs-name

명령어로 수정

 

pod 의 Label

metadata:
  name: label-demo
  labels:
    environment: production

 

Replicaset 의 Label 

Replication Controller 에선 필수가 아님 + apiversion 도 다름  

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend
  labels:
    app: guestbook
    tier: frontend
spec:
  # modify replicas according to your case
  replicas: 3
  selector:
    matchLabels:
      environment: production

 

Deployment

*yaml 파일은 Replicaset 과 큰 차이는 없음  / kind: Deployment 

한번에 수정 적용이나 업그레이드 할때 용이하게 사용되어 Replicaset 보다 더 큰범위에서 파드들을 적용시킴

 

Namespaces

리소스 사용에 구분을 지어 원활하게 관리하고자 하는 네임텍 같은 역할

기본적으론 Defalut Namespace 로 지정되어 있음

 

Namespace 별로 할당량을 미리 지정해놓고 싶을때 - Resource Quota 

apiVersion: v1
kind: ResourceQuota
metadata:
  name: disable-cross-namespace-affinity
  namespace: foo-ns
spec:
  hard:
    pods: "0"

 

개수 세기

# kubectl get pods | wc -l 

 

Service

자원과 통신하기 위해 필요한 구성요소

서비스는 다른 자원에 비해 비교적 유연하게 작동하기 때문에 파드/노드 범위에 상관없이 사용가능

 

Node Port - 노드 범위에서 접근 가능한 포트 (30000~32767) 노드 포트의 경우 selector 값에 파드 레이블 지정해서 파드도 같이 설정필요

#curl http://192.168.0.2:30008

ClusterIP - 노드 내부 구성요소의 포트 (기본값) (80)

Loadbalancer - 노드의 가용성을 높이기위해 통신을 할당 및 분배할때 필요한 포트/ 단일의 ip 주소로 접근 가능

노드포트에서 type 만 달라지지만 loadbalnace 역할이 작동하기 위해선 3rd party 기능 연동 사용 필요

 

Node Port 의 예시

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - port: 80
      # By default and for convenience, the `targetPort` is set to
      # the same value as the `port` field.
      targetPort: 80
      # Optional field
      # By default and for convenience, the Kubernetes control plane
      # will allocate a port from a range (default: 30000-32767)
      nodePort: 30007

 

Lables

자원별로 구별 가능쉽게 레이블링 하는 역할

 

Selector

레이블링 한 값을 찾아주는 역할 / 필터링

 

Taints&Tolerations

노드에 Taint + 파드에 Tolerations 설정

노드라는 갑옷에 Tolerations 값을 가진 파드만 무기로 접근 가능

 

Node Selector 

원하는 노드를 간략히 지정 가능

 

Node Affinity

Node Selector 와 비슷하나 조금 더 자세히 정의 가능

파드에 Node Affinity 설정으로 

갈고리로 원하는 노드에 부착

 

Node Affinity + Taints&Tolerations 함께 사용함으로 정확히 지정 설정 가능

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd            

 

 

Resource Requirement & Limits

 

LimitRange / CPU & Memory 

해당 kind 설정 이후 생성되는 자원에만 적용 가능

 

Resoucequota

 

 

DaemonSets

각 파드 생성마다 기본적으로 1개씩 갖게끔 하는 것

모니터링이나 로그 확인용으로 용이

kube-proxy & weave-net

* kube-scheduler 과는 상관 없음

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch

 

Static Pods

api server 에 상관없이 노드 범위에서 kubelet 이 독단적으로 파드 생성에 관여할 수 있음

/etc/kubernetes/manifests

yaml 파일로 static pod 생성

 

kubelet service 파일에 경로 확인 혹은

kubeconfig 파일 확인

 

* kube-scheduler 과는 상관 없음

 

ps -ef | grep /usr/bin/kubelet

--from-file

Multiple Schedulers

 

kubectl get events -o wide

kubectl logs customer-scheduler --name-space=kube-system

 

 

Monitoring

 

CPU&Memory 확인

#kubectl top node

#kubectl top pod

로그 확인

#kubectl logs -f pod-name (+container-name)

 

 

Rolling Updates

 

#kubectl rollout status deployment/my-deploy

#kubectl rollout history deployment/my-deploy

#kubectl rollout undo deployment/my-deploy

 

이미지 변경 방법

kubectl apply -f my-deploy.yaml

or

kubectl set image deployment/my-deploy ningx-name=nginx:1.7.1

 

 

Commands and Arguments

 

Docker 의 ENTRYPOINT ["sleep"] --- > K8S 의 command : ["sleep"]

Docker 의 CMD ["5"]  --- > args : ["5"]

 

Environmental variables

 

1) 기본형

spec:
  containers:
  - name: envar-demo-container
    image: gcr.io/google-samples/node-hello:1.0
    env:
    - name: DEMO_GREETING
      value: "Hello from the environment"

 

2) Configmap 형

 

configmap 우선 생성 후 pod 에 삽입

#kubeclt create configmap config-name --from-literal=key=value

or

#kubeclt create configmap config-name --from-file=filename

spec:
  containers:
    - name: test-container
      image: registry.k8s.io/busybox
      command: [ "/bin/sh", "-c", "env" ]
      env:
        # Define the environment variable
        - name: SPECIAL_LEVEL_KEY
          valueFrom:
            configMapKeyRef:
              # The ConfigMap containing the value you want to assign to SPECIAL_LEVEL_KEY
              name: special-config
              # Specify the key associated with the value
              key: special.how
spec:
  containers:
    - name: test-container
      image: registry.k8s.io/busybox
      command: [ "/bin/sh", "-c", "env" ]
      envFrom:
      - configMapRef:
          name: special-config

3) Secret 형

(Encrpytion 되지 않고 문자 변형만 되서 저장됨)

#kubeclt create screte generic secret-name --from-literal=key=value

or

#kubeclt create screte generic secret-name --from-file=filename

 

하지만 secret 는 변형되어 보관해야 안전하므로

echo -n '숨길문자' | base 64

echo -n '풀어낼문자' | base 64 --decode

 

k get secret

k describe secret

k get secret secret-name -o yaml

spec:
  containers:
  - name: envars-test-container
    image: nginx
    env:
    - name: SECRET_USERNAME
      valueFrom:
        secretKeyRef:
          name: backend-user
          key: backend-username
spec:
  containers:
  - name: envars-test-container
    image: nginx
    envFrom:
    - secretRef:
        name: test-secret

 

 

OS Upgrade

 

업그레이드 중 유용하게 사용될

kubectl drain node01

임시적으로 해당 노드의 파드를 다른곳에 위치시키고 사용 못하게 함

kubetl cordon node02

 임시적으로 해당 노드를 사용 못하게 함

kubectl uncordon02

  해당 노드를 다시 사용하게 함

 

업그레이드 하는 방법은 한단계씩 점진하여 하는것이 좋음

kubeadm 으로 하는경우

kubeadm upgrade plan

kubeadm updgrade apply

 

1.마스터 노드 업그레이드 -> 2.워커 노드 업그레이드

 

adm 툴 업그레이드

apt-get upgrade -y kubeadm=1.12.0-00

클러스터 업그레이드

kubeadm upgrade apply v1.12.0

 

kubectl drain controlplane 

kubelet 업그레이드

apt-get upgrade -y kubelet=1.12.0-00

systemctl restart kubelet

 

wokrder 노드 업그레이드 (각 노드)

kubectl drain node01 (마스터)

ap-get upgrade -y kubeadm=1.12.0-00

ap-get upgrade -y kubelet=1.12.0-00

kubeadm upgrade node config --kubelet-version v1.12.0

systemctl restart kubelet

kubectl uncordon node01 (마스터)

 

 

ETCD Back Up

ETCD Backup VS API kubectl Backup

 

Save - Restore 작업

 

( #export ETCDCTL_API=3 

#etcdctl version )

ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \
  --cacert=<trusted-ca-file> --cert=<cert-file> --key=<key-file> \
  snapshot save <backup-file-location>

 

service kube-apiserver stop

systemctl daemon-reload 

service etcd restart

service kube-apiserver start 

 

Security

 Who 누가 접근 & What 무엇을 관리 

 

누가 접근

User & Serviceaccount(kube로 생성가능)

 

가장 기본적으로 auth-file 생성해서 path 를 지정해서 가져오게끔 설정 하는 방법

롤 설정

curl -v -k https://localhost:6443/api/v1/pods -u "user1:password123"

 

TLS

 

Symmetric  Encryption - 같은키로 보내고 받아서 사용

Asymmetric Encryption - Private & Public Key 로 사용 

 

같은 키를 보내면 위험성이 크므로

해당 키를 Asymmetric 방식으로 전송하여 중요한 정보와 key 를 주고받음

 

하지만 이방식에서도 허점이 있으므로

Sertificate 을 통해 증명서로 안전한 key 라는것을 인증

CA(Certificate Authority)

CSR(Ceriticate Signing Request) 을 통해 CA 의 인증을 발급받음

 

Server Certificate - Kube API & ETCD & Kubelet 

Client Ceritificate - Admin & Kube Scheduler & Kube Controller Manager & Kube-Proxy 모두 ~ API 서버로 연결 & Kube API ( 연결 ~ ETCD & Kubelet )

 

CA

1. ca.key 키 생성

openssl genrsa -out ca.key 2048 

2. ca.csr (사인 리퀘스트)

openssl req -new -key ca.key -subj \ "/CN=KUBERNETES-CA" -out ca.csr

3. ca.crt (사인) 

openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt 

 

 

curl https://kube-apiserver:6443/api/v1/pods --key admin.key --cert admin.crt --cacert ca.crt

OR

kube-config 파일에 구성

 

모든 자원의 Certificate 생성에는 ca.crt 파일 복제본이 필요함

 

Adimin 

1. admin.key 키 생성 

openssl genrsa -out admin.key 2048 

 

2. admin.csr (사인 리퀘스트)

openssl req -new -key admin.key -subj \ "/CN=kube-admin" -out admin.csr

 

3. admin.crt (사인) 

openssl x509 -req -in admin.csr -CA ca.crt -CAkey ca.key -out admin.crt 

 

ETCD Cert -> etcd path 구성 변경 필요

 

API Server Cert

openssl genrsa -out apiserver.key 2048 

openssl req -new -key apiserver.key -subj \ "/CN=kube-apiserver" -out admin.csr #-config openssl.cnf

openssl x509 -req -in apiserver.csr -CA ca.crt -CAkey ca.key -out apiserver.crt 

 

Kubelet Node

kubelet-config 파일에 구성 (각 노드)

 

Cert 파일 자세히 확인 하는법

openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text -noout

 

서비스 로그 확인

journalctl -u etcd.service -l 

 

kubectl logs etcd-master

 

docker ps -a

dokcer logs #containerID

 

Run crictl ps -a command to identify the kube-api server container.

Run crictl logs container-id command to view the logs.

 

Certificates API

 (Controller manager 에 의해 관리됨)

 

openssl genrsa -out admin.key 2048 

openssl req -new -key jane.key -subj \ "/CN=jane" -out jane.csr

 

jane-csr.yaml

(cat jane.csr | base64)

 

kubectl get csr

kubectl certificate approve jane

 

base64 -w 0

공백 없이 생성

 

Kubeconfig

 

cirl https://hello:6443/api/v1/pods

--key admin.key

--cert admin.crt

--cacert ca.crt

 

k get pods

--server hello:6443

--client-key admin.key

--client-certificate admin.crt

--certificate-authority ca.crt

 

k get pods

--kubeconfig config

kubeconfig file 의 정보 (

--server hello:6443

--client-key admin.key

--client-certificate admin.crt

--certificate-authority ca.crt )

 

Kubeconfig file 에는 Cluster & Contexts & Users 

로 구성되어 있어 Cluster 에는 크게 목적 

Users 에는 사용자

Contect 는 어디 사용자가 무슨 목적으로 사용하지는지 연결 

* config file 은 따로 생성할 필요는 업슴

 

.kube/config

 

kubectl config view

 

특정 파일의 contecxt 이용

k config use-context --kubeconfig=/root/my-kube-config research

 

API Groups

 

/apis 아래 항목으로 각 자원 존재

 

curl https://kube-master:6443/version

curl https://kube-master:6443/api/vi/pods

 

curl http://localhost:8001 -k (kubeproxy 로 credential 사용 안해도 됨)

 

authority

 

ARBC - 유저당 추가해야함으로 관리하기 까다로움

RBAC - Rule 을 지정해서 유저를 넣어주기만 하면 됨으로 관리하기 수월함

Role 우선 생성 -> RoleBinding 생성 하여 유저를 추가

 

#kubectl auth can-i create nodes 형식으로 접근 재확인

or --as dev-user --namespace test

--authorization-mode=Node,RBAC,Webhook OR AlwaysAllow

 

Cluster Role 은 일반적인 Role 과 달리 노드 & PV 단계 범위에서 역할을 지정해주는것

 

Service Account

kubernets 의 자원이 아닌 제3자의 서비스가 권한을 갖는것

default SA 가 아닌 본인이 만든 SA 를 추가하려면 Pod 에 직접 추가 (serviceAccountName & automountServiceAccountToken: false)

 

Image Security

 

docker login private-image.io

docker run private-image.io/apps/internal-app

image: private-image.io/apps/internal-app

 

kubectl create secret docker-registry regcred 

--docker-server=

--docker-username=

--docer-password=

--docker-email=

 

imagePullSecrets:

-name : regcred

 

Security Context

Pod 범위 vs Container 범위

 

k exec ubuntu-sleeper -- whoami

* Capabilities 섹션은 container 범위 아래 에서만 사용 가능 

 

NetworkPolicy 

Ingress & Egress

 policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - ipBlock:
            cidr: 172.17.0.0/16
            except:
              - 172.17.1.0/24
        - namespaceSelector:
            matchLabels:
              project: myproject
        - podSelector:
            matchLabels:
              role: frontend
      ports:
        - protocol: TCP
          port: 6379

 

 

Volumes

Storage Drivers VS Volume Drivers 

 

Storage Drivers - Volume mount (기본 저장소에서) & Bind mount (지정 저장소에서)

 Volume Drivers - 보통 3rd party 볼륨에 마운트

 

CSI (Container Storage Interface)

 

파드가 생성되고 제거될때 보통 데이터도 함께 제거되므로

파드 파일 내에 Volume 지정 & 컨테이너에 해당 Volume 연결 해서 생성

*노드별로 모두 같은 path 에두면 관리하기에 어려우므로 3rd party 연결하여 사용

 

Persistent Volume 

으로 각각 파드에 정의하는대신 한번에 관리 할 수 있게끔 미리 볼륨을 생성 해 놓음

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv0003
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: slow
  mountOptions:
    - hard
    - nfsvers=4.1
  nfs:
    path: /tmp
    server: 172.17.0.2

 

이때 사용자가 PV 사용하기 위해 Persistent Volume Claim

1:1 관계로 PVC 라는 사용에의해 이를 만족시킬 수 있는 PV 를 찾는 과정 (Binding)

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 8Gi
  storageClassName: slow
  selector:
    matchLabels:
      release: "stable"

 

PVC 삭제후 PV 의 상태는 (Remain/Deleted/Recycle) 옵션을 선택할 수 있음

PVC 는 파드에 일반 볼륨을 넣는것 처럼 따로 넣어줘야함

 

Storage Class 를 pvc 에 사용한다면 자동으로 생성하므로 따로 pv 를 생성할 필요 없음

 

 

** kubeadm 설치

cat /etc/*-release

runtime 설치

kubeadm 설치

 

master 노드 initialize 

kubeadm init --apiserver-advertise-address=@ --pod-network-cidr=@

 

Networking

 

Switch 

같은 ip 주소 범위 내에서 서로 통신

#ip link 

(eth0 같은 스위치로 서로 접속)

 

Routing

다른 ip 주소간에 통신 가능하게 연결

#routing 

(routing table 확인 가능)

#ip route add default via 192.168.2.1

(원하는 목적지로 가기 위해 gateway add 해주는 설정)

 

echo 1 > /proc/sys/net/ipv4/ip_forward

/etc/sysctl.conf 의 net.ipv4.ip_forward=1 로 영구 변경 가능

 

DNS

cat >> etc/hosts

cat /etc/resolv.conf (dns 서버에 저장)

 

Network Namespaces

ip netns exec red ip link

ip -n red link

 

ip link add verth-red type veth peer name veth-blue

ip link set veth-red netns red / ip -n red link del veth-red

ip link set veth-blue netns blue

ip -n red addr add 192.168.15.1 dev veth-red

ip -n blue addr add 192.168.15.2 dev veth-blue

 

ip link add v-net-0 type bridge 

ip link set dev v-net-0 up

 

p link add verth-red type veth peer name veth-red-br

ip link set veth-red netns red

ip link set veth-red master v-net-0

ip -n red addr add 192.168.15.1 dev veth-red

ip -n red link set veth-red up

ip addr add 192.168.15.5/24 dev v-net-0 (master)

 

CNI (Container Network Interface)

 

Port - Kube-api(6443), kubelet(10250) kube-scheduler(10259)

kube-controller-manager(10257),etcd(2379),etcd client(2380)

nodeport services(30000-32767)

 

Pod Networking

 

net-script.sh 에 네트워크 연결 정의

 

#ps -aux | grep kubelet 으로 kubelet 의 cni 확인 가능

ls /opt/cni/bin

ls /etc/cni/net.d

 

CNI - DHCP / Host-local 기능

 

Service Networking

kube-proxy 가 iptable 생성 관리

#iptables -L -t nat 

# cat /var/log/kube-proxy.log

 

curl http://web-service.apps.svc.clister.local 

다른 namespace 에 있는 svc 에 접근

 

# cat /etc/coredns/Corefile -> kubectl get configmap -n kube-system

# cat /var/lib/kubelet/config.yaml 에서 dns 서버 주소 확인 가능

 

Ingress

 

프록시 & 로드밸런싱을 비롯한 다양한 역할을 수행해주는 역할

 

Nignx 와 같은 Ingress controller 설정 이후 Ingress Resources 설정 

 

1) Path 로 설정 

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-resource-backend
spec:
  defaultBackend:
    resource:
      apiGroup: k8s.example.com
      kind: StorageBucket
      name: static-assets
  rules:
    - http:
        paths:
          - path: /icons
            pathType: ImplementationSpecific
            backend:
              resource:
                apiGroup: k8s.example.com
                kind: StorageBucket
                name: icon-assets

 

2) Host 로 설정 

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-wildcard-host
spec:
  rules:
  - host: "foo.bar.com"
    http:
      paths:
      - pathType: Prefix
        path: "/bar"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: "*.foo.com"
    http:
      paths:
      - pathType: Prefix
        path: "/foo"
        backend:
          service:
            name: service2
            port:
              number: 80

 

Application Trouble Shooting

 

서비스 & 파드 연결성 및 정보 확인 - 보통 웹 페이지 서비스 에서 오류 확인 

 

Controlplan Trouble Shooting

 

서비스 상태 확인 - 보통 컨트롤 플레인 자원 작동 오류로 manifest 확인 혹은 로그 확인 필요

#service kube-apiserver status

#service kube-controller-manager status

#service kube-scheduler status

#service kubelet status

#service kube-proxy status

 

로그 확인

#kubectl logs kube-apiserver-master -n kube-system

#sudo journalctl -u kube-apiserver

 

Worker Node Trouble Shooting

 

노드 확인

#top

#df -h

 

#service kubelet status

#sudo journalctl -u kubelet

 

#openssl x509 -in /var/lib/kubelet/worker-1.crt -text