brunch

매거진 Programming

You can make anything
by writing

C.S.Lewis

by sokoban Apr 07. 2020

Kubenetes 기본 사용하기 #1

#kubectl #docker-desktop


Kubernetes에 대해서 ?

  클라우드라는 말이 나온지도 꽤나 되어 가지만 막상 클라우드에서 사용하는 기술적인 부분에 대해서는 가상 머신 (Virtual Machine) 이외에는 큰 변화 없이 시간이 흘러 갔다. 하지만 Docker가 나오고 여기에 Kubernetes가 나오면서 어찌 보면 누구나 쉽게 클라우드와 같은 환경을 쉽게 구축할 수 있게 되었다. 

  CI/CD를 이용하여 지속적인 빌드,배포에 핵심적인 것이 이러한 클라우드 인프라이며 현재 시점에서 가장 쉽게 접근 하고 구축할수 있는 것이 Kubernetes 라는데에 이견은 없다.


  본 글에서는 kubernetes의 기본적인 구성에 대해서 알아보고 Mac OS 환경하에서 Docker-Desktop에 포함된 Kubernetes를 통해서 기본적인 사용법을 따라가보고자 한다. 본 글은 아래의 서적과 Kubernetes공식 사이트 두가지 외에 여러가지 정보를 기반으로 기본 구성과 사용법에 대해서 적어 보았다.


https://kubernetes.io/ko/docs/home/

http://www.yes24.com/Product/Goods/85578606?Acode=101



  


Kubernetes Object


Namespace 

  : 하나의 물리 클러스터 안에서 여러개의 가상 클러스터를 사용 할 수 있으며 이러한 가상 클러스터는 Namespace 기반으로 나누어서 사용할 수 있다. 즉 클러스터에서 여러개의 앱을 사용하거나 여러명의 사용자가 사용해야 할때 유용하게 사용할 수 있다.


#kubectl get namespace

NAME                   STATUS   AGE

default                Active   22d

docker                 Active   22d

kube-node-lease        Active   22d

kube-public            Active   22d

kube-system            Active   22d

kubernetes-dashboard   Active   21d

기본적으로 위와 같은 namespace가 정의 되어 있을 것이다.


#kubectl config current-context

docker-desktop


네임 스페이스 변경 하기

kubectl config set-context docker-desktop --namespace=kube-system


쉬운방법 (kubens 사용하기)



Kubernetes 용어 정리


Deployment : Pod의 설치를 관리하는 기본 요소로서, 실행시의 기본 컨트롤러, Deployment 삭제시 하부의 Pod도 모두 삭제됨

Service : Pod 에서 실행중인 프로세스를 위한 신원(identity)을 제공하여 서비스 찾기를 통해서 Pod 에 고유한 IP주소와 Pod 집합에 대한 단일 DNS명을 부여하여 외부에서 접근할 수 있게 해준다. 타입는 ClusterIP, NodePort, LoadBalancer ,ExteralName 등이 있다.

Pod : 실제로 도커 인스턴스가 떠 있는 단위를 Pod이라고 지칭한다.


Kubernetes 노드 구성

Master  : 노드들의 상태를 관리하고 제어, 1대만 구성할수 있으나 고가용성 서비스라면 3대 이상으로 구성 장애가 발생하면 남은 서버중 한대가 마스터의 역할을 함

Node (Worker) : Kubelet, kube-proxy, docker 등의 프로세스가 동작하며 마스터 노드의 명령을 받아 사용자가 선언한 Pod나 Job을 실행함, 실제 docker 컨테이너가 동작하는 것은 노드에서 동작함


노드별 구성 요소


Master Node 구성 요소


kube-scheduler : 클러스터 내에서 발생하는 파드의 생성에 대한 노드의 자원 할당을 선택하는 컴포넌트, 정해놓은 조건에 맞게 빈 노드에 파드를 할당한다. 할당은 affinity, anti-affinity ,데이터 지역성 등 다양한 요소를 고려한다.


kube-controller-manager : 토드 컨트롤러외에 아래의 다수의 컨트롤러를 복잡성을 줄이기 위해서 하나로 구성한 컴포넌트로서 각 컨트롤러는 다음과 같다.

- 노드 컨트롤러 : 노드의 중지에 대한 대응

- 레플리케이션 컨트롤러 : 전체 레플리케이션 컨트롤러 객체에 대한 파드 숫자 유지

- 엔드포인트 컨트롤러 : 서비스와 파드 연결

- 서비스 어카운트 & 토큰 컨트롤러 : 신슈 name space에 대한 기본적인 관리


cloud-controller-manager : 클라우드 사업자와 컨트롤러들을 연결하여 관리하는 역할을 함

- 노드 컨트롤러 : 노드 중지이후 클라우드 상에서 삭제되었는지 판별하기 위함

- 라우트 컨트롤러 : 클라우드 서비스 상의 네트워크 라우팅 관리

- 서비스 컨트롤러 : 클라우드 제공사업자 서비스의 로드밸런서를 생성, 업데이트 삭제

- 볼륨 컨트롤러 : 클라우드 서비스상의 볼륨을 노드와 연결하거나 마운트


kube-apiserver : 쿠버네티스상에서 이루어지는 모든 요청은 이를 통해서 각 컴포넌트에 전달되고 실행된다. 외부에서 클라우드를 관리할 수 있는 핵심 API, 수평 확장이 가능하므로 요청이 많은 경우 확장 할 수 있다.


etcd : key- value 저장소로서 모든 클러스터의 데이터를 저장하는 저장소이다. (https://etcd.io)


Worker Node


kubelet : 프로세스로서 실행 가능하며 도커를 관리한다. kube-apiserver와 통신하면서 파드의 생성, 관리, 삭제를 담당함, 


kube-proxy : 개별 노드에서 실행되는 네트워크 프록시로서 파드가 외부와 통신할 수 있게 해주는등 네트워크 규칙을 관리.


컨테이너 런타임 : 클러스터에서 컨테이너의 실행을 담당하는 것으로서 대표적으로는 Docker가 있으며 containerd와 같은 다른 런타임도 지원 합니다.  CRI (Container Runtime Interface)를 만족하는 모든 소프트웨어를 지원


 

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


Kubernetes Docker-desktop 기반 사용법 정리

 본 정리는 기본적으로 Mac상에서 Docker-desktop 설치시의 환경에서 테스트 되었으며 최초 Docker-Desktop에 설치된 환경을 가정하여 Step-By-Step으로 따라가게 되어 있습니다.


사용 엔진 버전

Docker Engine : v19.03.5

Kubernetes : v1.15.5


 가장 많이 사용되는 명령어인 kubectl 명령어에 대한 전반적인 치트 시트는 아래와 같다.

https://kubernetes.io/ko/docs/reference/kubectl/cheatsheet/


0. MAC 상에서의 기본적인 kubernetes 설치


 Mac에서는 kubernetes를 테스트 하기 위해서 별도로 여러가지 컴포넌트의 설치 없이 간단하게 Docker Desktop만 다운받은 다음 설치 하고 아래의 설정만 하면 된다.


  기본 설치 상태에서는 "Enable Kubernetes" 부분이 빠져 있을 것이다. 이것을 체크 하고 적용하면 간단하게 설치가 완료 된다.


1. kubernetes 대시보드의 실행


아래의 명령어를 통해서 Docker-desktop 환경에서 kubernetes UI인 대시보드를 로컬에 실행 할 수 있다.


#kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml

namespace/kubernetes-dashboard created

serviceaccount/kubernetes-dashboard created

service/kubernetes-dashboard created

secret/kubernetes-dashboard-certs created

secret/kubernetes-dashboard-csrf created

secret/kubernetes-dashboard-key-holder created.........


접근을 위해서 아래와 같이 해준다.

#kubectl proxy

Starting to serve on 127.0.0.1:8001

이제 아래의 주소를 통해서 접속이 가능하게 됩니다.

http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/


그러면 아래와 같은 인증 화면이 나온다. 

이제 인증을 위한 Token 값을 가져 와 보자.


#kubectl get serviceaccount

NAME      SECRETS   AGE

default   1         22h

#kubectl get serviceaccount default -o yaml

apiVersion: v1

kind: ServiceAccount

metadata:

  creationTimestamp: "2020-03-31T15:22:25Z"

  name: default

  uid: c7abfb9a-e716-4b8c-bf62-9b8b323c0da0

secrets:

- name: default-token-ja26m


위의 secret을 이용하여 아래의 명령어를 치면 token을 구할 수 있다.


#kubectl describe secret default-token-ja26m

Name:         default-token-ja26m

Namespace:    default

Labels:       <none>

Annotations:  kubernetes.io/service-account.name: default

.......

token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tajJqNm0iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImM3YWJmYjlhLWU3MTYtNGI4Yy1iZjYyLTliOGIzMjNjMGRhMCIsInN1YYWNjb3VudD


  이제 구한 토큰을 통해서 접속이 가능하다.


#kubectl get services --v=7

I0401 23:24:19.119767   51293 loader.go:359] Config loaded from file:  /Users/sokoban/.kube/config

I0401 23:24:19.135067   51293 round_trippers.go:416] GET https://kubernetes.docker.internal:6443/api/v1/namespaces/default/services?limit=500

I0401 23:24:19.135093   51293 round_trippers.go:423] Request Headers:

I0401 23:24:19.135102   51293 round_trippers.go:426]     Accept: application/json;as=Table;v=v1beta1;g=meta.k8s.io, application/json

I0401 23:24:19.135110   51293 round_trippers.go:426]     User-Agent: kubectl/v1.15.5 (darwin/amd64) kubernetes/20c265f

I0401 23:24:19.194940   51293 round_trippers.go:441] Response Status: 200 OK in 59 milliseconds

I0401 23:24:19.199984   51293 get.go:564] no kind "Table" is registered for version "meta.k8s.io/v1beta1" in scheme "k8s.io/kubernetes/pkg/api/legacyscheme/scheme.go:30"

NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE

kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   23h


  초기 대시보드가 구현된 상태에서 조회를 해보면 Services에 kubernetes가 등록 된 것을 알 수 있다.

 거기에 --v=7 옵션을 주게 되면 디버그용 출력 (kubectl용) 이 가능하므로 실제적으로 정보 조회를 하기 위한 Rest API호출문도 볼수 있다.


% 공인 IP로 kubernetes 마스터를 열어두지는 않겠지만 만약 공인 IP상에서 마스터 노드가 열려 있고 외부에서 토큰이 유출 되었거나 공격자가 내부에 침투하여 토큰을 탈취하였다면 kubernetes 서비스를 모두 파악하고 영향을 줄수도 있다. 유출된 토큰의 클러스터만 영향을 받을 수 있으나 만약 공격자가 자원 고갈 공격을 할 경우를 대비해서 쿼터를 주는것도 좋은 방법이다.


  상세한 인증 방법은 아래의 방안을 참고하면 된다.

https://kubernetes.io/docs/reference/access-authn-authz/authentication/


DashBoard 상에서의 API 조회


kubernetes를 컨트롤 하기 위한 방법으로 API 서버가 제공되고 이는 kube-apiserver를 통해서 제공된다. 다만 api-server는 각각의 버전에 맞는 정확한 버전을 적어주는것이 중요하며 버전 변경이 빠른 편이기 때문에 본인이 사용하고자 하는 API 버전에 대해서 체크 해 보아야 한다.


아래는 대시보드가 실행된 이후 http://127.0.0.1:8001/를 통해서 kubenetes API로 접속 하였을때 제공되는 API 목록이다.


{   "paths": [     "/api",     "/api/v1",     "/apis",     "/apis/",     "/apis/admissionregistration.k8s.io",     "/apis/admissionregistration.k8s.io/v1beta1",     "/apis/apiextensions.k8s.io",     "/apis/apiextensions.k8s.io/v1beta1",     "/apis/apiregistration.k8s.io",     "/apis/apiregistration.k8s.io/v1",     "/apis/apiregistration.k8s.io/v1beta1",     "/apis/apps",     "/apis/apps/v1",     "/apis/apps/v1beta1",     "/apis/apps/v1beta2",     "/apis/authentication.k8s.io",     "/apis/authentication.k8s.io/v1",     "/apis/authentication.k8s.io/v1beta1",     "/apis/authorization.k8s.io",     "/apis/authorization.k8s.io/v1",     "/apis/authorization.k8s.io/v1beta1",     "/apis/autoscaling",     "/apis/autoscaling/v1",     "/apis/autoscaling/v2beta1",     "/apis/autoscaling/v2beta2",     "/apis/batch",     "/apis/batch/v1",     "/apis/batch/v1beta1",     "/apis/certificates.k8s.io",     "/apis/certificates.k8s.io/v1beta1",     "/apis/compose.docker.com",     "/apis/compose.docker.com/v1alpha3",     "/apis/compose.docker.com/v1beta1",     "/apis/compose.docker.com/v1beta2",     "/apis/coordination.k8s.io",     "/apis/coordination.k8s.io/v1",     "/apis/coordination.k8s.io/v1beta1",     "/apis/events.k8s.io",     "/apis/events.k8s.io/v1beta1",     "/apis/extensions",     "/apis/extensions/v1beta1",     "/apis/networking.k8s.io",     "/apis/networking.k8s.io/v1",     "/apis/networking.k8s.io/v1beta1",     "/apis/node.k8s.io",     "/apis/node.k8s.io/v1beta1",     "/apis/policy",     "/apis/policy/v1beta1",     "/apis/rbac.authorization.k8s.io",     "/apis/rbac.authorization.k8s.io/v1",     "/apis/rbac.authorization.k8s.io/v1beta1",     "/apis/scheduling.k8s.io",     "/apis/scheduling.k8s.io/v1",     "/apis/scheduling.k8s.io/v1beta1",     "/apis/storage.k8s.io",     "/apis/storage.k8s.io/v1",     "/apis/storage.k8s.io/v1beta1",     "/healthz",     "/healthz/autoregister-completion",     "/healthz/etcd",     "/healthz/log",     "/healthz/ping",     "/healthz/poststarthook/apiservice-openapi-controller",     "/healthz/poststarthook/apiservice-registration-controller",     "/healthz/poststarthook/apiservice-status-available-controller",     "/healthz/poststarthook/bootstrap-controller",     "/healthz/poststarthook/ca-registration",     "/healthz/poststarthook/crd-informer-synced",     "/healthz/poststarthook/generic-apiserver-start-informers",     "/healthz/poststarthook/kube-apiserver-autoregistration",     "/healthz/poststarthook/rbac/bootstrap-roles",     "/healthz/poststarthook/scheduling/bootstrap-system-priority-classes",     "/healthz/poststarthook/start-apiextensions-controllers",     "/healthz/poststarthook/start-apiextensions-informers",     "/healthz/poststarthook/start-kube-aggregator-informers",     "/healthz/poststarthook/start-kube-apiserver-admission-initializer",     "/logs",     "/metrics",     "/openapi/v2",     "/version"   ] }


Kubernetes의 경우 대시보드나 API가 외부에 클러스터 정보가 노출될 경우 위험할 수 있으므로 노출되는지에 대해서 모니터링 하는것도 중요하다.



CLI상에서도 apiVersion에 대한 조회가 가능하며 아래의 명령어를 사용하여 조회 할수 있다. 

#kubectl api-versions

admissionregistration.k8s.io/v1beta1

apiextensions.k8s.io/v1beta1

apiregistration.k8s.io/v1

apiregistration.k8s.io/v1beta1

apps/v1

apps/v1beta1

apps/v1beta2

authentication.k8s.io/v1

authentication.k8s.io/v1beta1

authorization.k8s.io/v1

authorization.k8s.io/v1beta1

autoscaling/v1

autoscaling/v2beta1

autoscaling/v2beta2

batch/v1

batch/v1beta1


1. Kubernetes 템플릿

  Kubernetes에서는 yaml 형식의 템플릿을 통해서 현재 배포하는 인스턴스나 앱의 상태를 기술 할수 있다. 

간단하게 어떻게 구성되는지 알아 보자.


Ex.

apiVersion: apps/v1beta2

kind: Deployment

metadata:

  name: dvwa-sample

  namespace: default

spec:

  selector:

    matchLabels:

      app: dvwa-sample-app

  replicas: 1

  template:

    metadata:

      labels:

        app: dvwa-sample-app

    spec:

      containers:

      - name: dvwa-sample

        image: vulnerables/web-dvwa

        imagePullPolicy: IfNotPresent

        resources:

          requests:

            cpu: 500m

            memory: 200Mi

        ports:

        - containerPort: 80


apiVersion : Kubernetes의 API 버전을 명시합니다. 위의 설명에서와 같이 버전별로 상이 할 수 있으므로 본인이 Deploy하고자 하는 버전에 맞게 변경하는것이 필요합니다.

kind : Pod, Deployment, Service 등의 유형을 명시합니다.

metadata : 해당 객체의 이름이나 namespace등을 명시합니다.

spec : 어떠한 컨테이너를 이용할 것인지 그리고 어떻게 구동할 것인지 등을 설정합니다.


 위의 각각의 항목에 대한 상세한 설명은 아래의 명령어를 통해서 조회 할수 있다. 
(예를 들어 pods에 대한 템플릿과 metadata 그리고 전체 옵션을 보고 싶다면 아래와 같이 할수 있다.)

#kubectl explain pods

#kubectl explain pods.metadata

#kubectl explain pods --recursive


2. kubectl 접근 설정(config) 변경


  Client에서 주로 kubectl을 이용하여 kubernetes의 대부분의 기능을 사용할 수 있다. 물론 대시보드를 사용해도 되지만 CLI 환경에서 하는게 더 편할 때도 있다.


현재의 설정 조회 하기 : 설정 파일은 $Home/.kube/config 파일에 저장되어 있다.

#kubectl config view


(1). Kubernetes context 변경

: PC에 Kubectl을 설치해 놓고 사용한다면 로컬에서 사용해야 할때와 서버에 연결해서 사용해야 할때 두가지가 발생될 수 있다. 이때 사용하고자 하는 context를 변경하는 방법을 알아 본다.


- context:

    cluster: docker-desktop

    user: docker-desktop

  name: docker-desktop

- context:

    cluster: minikube

    user: minikube

  name: minikube

- context:

    cluster: kub-test-cluster

    user: sokoban

  name: kub-test-context


위와 같이 3가지 context가 등록 되어 있다. ( 아래와 같이 Mac일 경우 UI를 통한 조회 변경도 가능하다.)

docker-desktop은 현재 docker에서 제공하는 kubernetes 환경이며 minikube는 kubernetes 클러스터를 PC에 단독 구성할때.. 그리고 kub-test-cluster는 실제 구축된 리얼 환경이다. 본인이 사용하고자 하는 환경에 맞게 구성을 변경하면 된다.


CLI 환경에서 context를 변경하고자 한다면 아래와 같은 명령어를 사용하자.

#kubectl config use-context minikube



#kubectl describe services Sample-service


3. Pod 사용하기

  Pod는 kubernetes에서 사용하는 관리 단위로서 여러개의 컨테이너를 하나의 Pod로 묶어서 관리한다. 한개의 Pod에는 다수의 컨테이너가 들어가며 해당 Pod에 있는 컨테이너들은 Pod가 할당 받은 하나의 IP를 공유하여 사용하게 되며 접속은 개별 부여된 Port를 통해서 통신을 진행한다. 내부 통신은 127.0.0.1로 서로 통신이 가능하다.


#kubectl get pods

NAME                           READY   STATUS    RESTARTS   AGE

dvwa-sample-75c6f6dc7d-wbcfq   1/1     Running   0          8s


#kubectl describe pods

kubectl describe pod dvwa-sample-75c6f6dc7d-wbcfq

Name:         dvwa-sample-75c6f6dc7d-wbcfq

Namespace:    default

Priority:     0

Node:         docker-desktop/192.168.65.3

Start Time:   Thu, 14 May 2020 14:38:11 +0900

Labels:       app=dvwa-sample-app

              pod-template-hash=75c6f6dc7d

Annotations:  <none>

Status:       Running

IP:           10.1.0.8

IPs:

  IP:           10.1.0.8

Controlled By:  ReplicaSet/dvwa-sample-75c6f6dc7d

Containers:

  dvwa-sample:

    Container ID:   docker://

    Image:          vulnerables/web-dvwa

    Image ID:       docker-pullable://vulnerables/web-dvwa@sha256:

    Port:           80/TCP

    Host Port:      0/TCP

    State:          Running

      Started:      Thu, 14 May 2020 14:38:13 +0900

    Ready:          True

    Restart Count:  0

    Requests:

      cpu:        500m

      memory:     200Mi

    Environment:  <none>

    Mounts:

      /var/run/secrets/kubernetes.io/serviceaccount from default-token-g4dnw (ro)

Conditions:

  Type              Status

  Initialized       True 

  Ready             True 

  ContainersReady   True 

  PodScheduled      True 

Volumes:

  default-token-g4dnw:

    Type:        Secret (a volume populated by a Secret)

    SecretName:  default-token-g4dnw

    Optional:    false

QoS Class:       Burstable

Node-Selectors:  <none>

Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s

                 node.kubernetes.io/unreachable:NoExecute for 300s


4. 로그 검색하기

  #kubectl logs -f <pod anme>



5. 서비스 노출 하기

  처음 kubernetes를 이용하여 도커 컨테이너를 실행하게 되면 내부에만 IP를 할당 받은 상태가 된다. 여기에 외부에서 접근 할 수 있는 여러가지 방법을 제공하고 있고 아래와 같은 구성도를 통해서 접근하게 된다.


  


Cluster IP

https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-wha


















NodePort

https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-wha



















Load Balancer 


https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-wha


















Ingress










6. 기본 사용


디플로이먼트의 변경 이력 찾아 보기

kubectl rollout history deploy


데몬셋 조회 하기

kubectl get daemonset -n kube-system



https://kubernetes.io/ko/docs/concepts/services-networking/service/#loadbalancer


7. ConfigMap


https://kubernetes.io/ko/docs/concepts/configuration/configmap/

  



참고 사이트


https://kubernetes.io/ko/docs/concepts/configuration/organize-cluster-access-kubeconfig/

https://arisu1000.tistory.com/category/Kubernetes

  지금 이 글을 쓰는 시점에 같은 층에서 근무하시는 분의 블로그이다. "쿠버네티스 입문"이라는 책을 서술 하신 만큼 보아야할 정보가 많이 있다.


https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0






브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari