backend/kubernetes docs

k8s 문서 - 튜토리얼; 쿠버네티스 기초 학습

seul chan 2020. 5. 13. 21:52

https://kubernetes.io/ko/docs/tutorials/kubernetes-basics/

Tutorial: 쿠버네티스 기초 학습

Assumming that minikube is successfully installed

Deploying app

Create deployment using kubernetes

  • pod는 isolated, private network 되어있기 때문에 proxy를 통해 debug, interact 가능하다.
$ minikube start

$ kube kubectl create deployment kubernetes-bootcamp --image=gcr.io/google-samples/kubernetes-bootcamp:v1

# starting proxy
echo -e "\n\n\n\e[92mStarting Proxy. After starting it will not output a response. Please click the first Terminal Tab\n"; 
kubectl proxy

curl localhost:8001

# set POD_NAME
export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
echo Name of the Pod: $POD_NAME

Anylize app

kubernetes pod

  • Pod is abstract concept

kubernetes node

  • Each node can have one or more pods
  • Each node is controlled by master node

kubectl get - 자원을 나열한다
kubectl describe - 자원에 대해 상세한 정보를 보여준다.
kubectl logs - 파드 내 컨테이너의 로그들을 출력한다
kubectl exec - 파드 내 컨테이너에 대한 명령을 실행한다.

$ kubectl get pods
NAME                                   READY   STATUS    RESTARTS   AGE
kubernetes-bootcamp-69fbc6f4cf-pzqcg   1/1     Running   0          6m26s


$ kubectl describe pods
Name:         kubernetes-bootcamp-69fbc6f4cf-pzqcg
Namespace:    default
Priority:     0
...

# or just simply "kubectl proxy"
$ echo -e "\n\n\n\e[92mStarting Proxy. After starting it will not output a response. Please click the first Terminal Tab\n"; kubectl proxy
Starting Proxy. After starting it will not output a response. Please click the first Terminal Tab

Starting to serve on 127.0.0.1:8001

# or just get pod name from "kubectl get pods"
$ export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
echo Name of the Pod: $POD_NAME
Name of the Pod: kubernetes-bootcamp-69fbc6f4cf-pzqcg

$ curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME/proxy/

$ kubectl logs $POD_NAME
Kubernetes Bootcamp App Started At: 2020-05-07T15:28:48.194Z | Running On:  kubernetes-bootcamp-69fbc6f4cf-pzqcg

# Executing command on the container
$ kubectl exec $POD_NAME -- env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=kubernetes-bootcamp-69fbc6f4cf-pzqcg
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
NPM_CONFIG_LOGLEVEL=info
NODE_VERSION=6.3.1
HOME=/root

$ kubectl exec -ti $POD_NAME -- bash
root@kubernetes-bootcamp-69fbc6f4cf-pzqcg:/#

$ cat server.js

$ curl localhost:8080

$ exit

https://kubernetes.io/ko/docs/tutorials/kubernetes-basics/expose/expose-intro/

앱 외부로 노출하기

쿠버네티스에서 서비스는 하나의 논리적인 파드 셋과 그 파드들에 접근할 수 있는 정책을 정의하는 추상적 개념이다.

각 pod들은 ip를 가지지만, 이는 서비스를 통해야만 클러스터 외부로 노출이 가능하다. ServiceSpec에서 type을 지정하여 다양한 방식으로 노출 가능.

  • ClusterIP (기본값) - 클러스터 내에서 내부 IP 에 대해 서비스를 노출해준다. 이 방식은 오직 클러스터 내에서만 서비스가 접근될 수 있도록 해준다.
  • NodePort - NAT가 이용되는 클러스터 내에서 각각 선택된 노드들의 동일한 포트에 서비스를 노출시켜준다. :를 이용하여 클러스터 외부로부터 서비스가 접근할 수 있도록 해준다. ClusterIP의 상위 집합이다.
  • LoadBalancer - (지원 가능한 경우) 기존 클라우드에서 외부용 로드밸런서를 생성하고 서비스에 고정된 공인 IP를 할당해준다. NodePort의 상위 집합이다.
  • ExternalName - 이름으로 CNAME 레코드를 반환함으로써 임의의 이름(스펙에서 externalName으로 명시)을 이용하여 서비스를 노출시켜준다. 프록시는 사용되지 않는다. 이 방식은 kube-dns 버전 1.7 이상에서 지원 가능하다.
# 서비스 보는 명령어
$ kubectl get services
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   17d

kubernetes 서비스는 minikube가 뜰 때 자동으로 생성되는 service이다.

새로 서비스를 만드려면 expose 명령어를 사용하면 된다. (minikube는 아직 loadBalancer 옵션을 제공해주지 않는다.)

$ kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080
service/kubernetes-bootcamp exposed

$ kubectl get services
NAME                  TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
kubernetes            ClusterIP   10.96.0.1       <none>        443/TCP          17d
kubernetes-bootcamp   NodePort    10.105.237.31   <none>        8080:31552/TCP   4s

describe 명령어를 사용하여 더 상세한 service의 상태를 확인 가능하다.

$ kubectl describe services/kubernetes-bootcamp
Name:                     kubernetes-bootcamp
Namespace:                default
Labels:                   app=kubernetes-bootcamp
Annotations:              <none>
Selector:                 app=kubernetes-bootcamp
Type:                     NodePort
IP:                       10.105.237.31
Port:                     <unset>  8080/TCP
TargetPort:               8080/TCP
NodePort:                 <unset>  31552/TCP
Endpoints:                172.17.0.4:8080
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

현재 배정되어 있는 node port를 $NODE_PORT 환경변수에 지정해보자.

$ export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')
echo NODE_PORT=$NODE_PORT
NODE_PORT=31552

이제 minikube ip와 NODE_PORT를 사용하여 외부에서 접속이 가능하다.

$ curl $(minikube ip):$NODE_PORT

Using labels

$ kubectl describe deployments

$ kubectl get pods -l run=kubernetes-bootcamp
$ kubectl get services -l run=kubernetes-bootcamp

# POD_NAME 설정, 그냥 kubectl get pods에서 보고 해도 상관없다.
$ export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
echo Name of the Pod: $POD_NAME

# 이미 app에 label이 등록되어 있다면 --overwrite 가능
$ kubectl label pod $POD_NAME app=v1

Delete services with label

$ kubectl delete service -l run=kubernetes-bootcamp
service "kubernetes-bootcamp" deleted

$ kubectl get services
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   18d

service가 죽었기 때문에 외부 접속이 안된다.

$ curl $(minikube ip):$NODE_PORT
curl: (7) Failed to connect to 192.168.64.4 port 31552: Connection refused

여전히 클러스터에서는 잘 떠있는 것을 볼 수 있음

$ kubectl exec -ti $POD_NAME -- curl localhost:8080
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-69fbc6f4cf-pzqcg | v=1

앱 스케일링하기

$ kubectl get rs
NAME                             DESIRED   CURRENT   READY   AGE
kubernetes-bootcamp-69fbc6f4cf   1         1         1       2d21h

$ kubectl scale deployments/kubernetes-bootcamp --replicas=4
deployment.apps/kubernetes-bootcamp scaled

$ kubectl get rs
NAME                             DESIRED   CURRENT   READY   AGE
kubernetes-bootcamp-69fbc6f4cf   4         4         4       2d23h

$ kube kubectl get deployments
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
kubernetes-bootcamp   4/4     4            4           2d23h

$ kubectl get pods -o wide
                                   READY   STATUS    RESTARTS   AGE     IP           NODE   NOMINATED NODE   READINESS GATES
kubernetes-bootcamp-69fbc6f4cf-7hp7h   1/1     Running   0          94m     172.17.0.6   m01    <none>           <none>
kubernetes-bootcamp-69fbc6f4cf-f4g8n   1/1     Running   0          94m     172.17.0.7   m01    <none>           <none>
kubernetes-bootcamp-69fbc6f4cf-mxfvx   1/1     Running   0          94m     172.17.0.5   m01    <none>           <none>
kubernetes-bootcamp-69fbc6f4cf-pzqcg   1/1     Running   0          2d23h   172.17.0.4   m01    <none>           <none>

$ kubectl describe deployments/kubernetes-bootcamp 

$ export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')
echo NODE_PORT=$NODE_PORT

$ curl $(minikube ip):$NODE_PORT
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-69fbc6f4cf-pzqcg | v=1

$ curl $(minikube ip):$NODE_PORT
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-69fbc6f4cf-7hp7h | v=1

$ curl $(minikube ip):$NODE_PORT
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-69fbc6f4cf-f4g8n | v=1

curl을 해보면 할 때마다 로드밸런싱이 되는 것을 볼 수 있다!!

이제 scale down 해보자.

$ kubectl scale deployments/kubernetes-bootcamp --replicas=2
deployment.apps/kubernetes-bootcamp scaled

$ kubectl get deployments/kubernetes-bootcamp
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
kubernetes-bootcamp   2/2     2            2           2d23h

$ kubectl get pods -o wide
NAME                                   READY   STATUS    RESTARTS   AGE     IP           NODE   NOMINATED NODE   READINESS GATES
kubernetes-bootcamp-69fbc6f4cf-mxfvx   1/1     Running   0          102m    172.17.0.5   m01    <none>           <none>
kubernetes-bootcamp-69fbc6f4cf-pzqcg   1/1     Running   0          2d23h   172.17.0.4   m01    <none>           <none>

앱 업데이트하기

"롤링 업데이트"는 파드 인스턴스를 점진적으로 새로운 것으로 업데이트하여 디플로이먼트 업데이트가 서비스 중단 없이 이루어질 수 있도록 해준다

$ kubectl get deployments
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
kubernetes-bootcamp   2/2     2            2           2d23h

$ kubectl describe deployments/kubernetes-bootcamp
...
Pod Template:
  Labels:  app=kubernetes-bootcamp
  Containers:
   kubernetes-bootcamp:
    Image:        gcr.io/google-samples/kubernetes-bootcamp:v1
    Port:         <none>
    Host Port:    <none>
...

위에서 gcr.io/google-samples/kubernetes-bootcamp:v1 이미지를 롤링 업데이트로 배포시켜보자.

$ kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=jocatalin/kubernetes-bootcamp:v2
deployment.apps/kubernetes-bootcamp image updated

# 바로 pods를 확인하면 기존 pod가 제거되는 것을 볼 수 있다.
$ kubectl get pods
NAME                                   READY   STATUS        RESTARTS   AGE
kubernetes-bootcamp-69fbc6f4cf-mxfvx   1/1     Terminating   0          108m
kubernetes-bootcamp-69fbc6f4cf-pzqcg   1/1     Terminating   0          2d23h
kubernetes-bootcamp-b4d9f565-jw76c     1/1     Running       0          9s
kubernetes-bootcamp-b4d9f565-mbg26     1/1     Running       0          3s

# 조금 시간이 지나면 업데이트 된 pod들만 남아있다.
$ kubectl get pods
NAME                                 READY   STATUS    RESTARTS   AGE
kubernetes-bootcamp-b4d9f565-jw76c   1/1     Running   0          49s
kubernetes-bootcamp-b4d9f565-mbg26   1/1     Running   0          43s

# 다시 describe deployments를 확인하여 이미지가 업데이트 된 것을 볼 수 있다.
$ kubectl descirbe deployments/kubernetes-bootcamp
...
Pod Template:
  Labels:  app=kubernetes-bootcamp
  Containers:
   kubernetes-bootcamp:
    Image:        jocatalin/kubernetes-bootcamp:v2
...

이제 업데이트가 정상적으로 되었는지 확인해보자

$ export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')
$ echo NODE_PORT=$NODE_PORT
NODE_PORT=30486

$ curl $(minikube ip):$NODE_PORT
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-b4d9f565-jw76c | v=2

v=2를 반환하여 업데이트가 잘 되었음을 볼 수 있다.

# rollout 명령어로도 업데이트를 할 수 있다.
$ kubectl rollout status deployments/kubernetes-bootcamp
deployment "kubernetes-bootcamp" successfully rolled out

이제 v10으로 업데이트를 해보자.

$ kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=gcr.io/google-samples/kubernetes-bootcamp:v10
deployment.apps/kubernetes-bootcamp image updated

$ kubectl get deployments
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
kubernetes-bootcamp   2/2     1            2           2d23h

$ kubectl get pods
NAME                                   READY   STATUS         RESTARTS   AGE
kubernetes-bootcamp-6b4c55d8fc-fgtwh   0/1     ErrImagePull   0          70s
kubernetes-bootcamp-b4d9f565-jw76c     1/1     Running        0          8m50s
kubernetes-bootcamp-b4d9f565-mbg26     1/1     Running        0          8m44s

뭔가 잘못된 것을 볼 수 있다. ErrImagePull status 를 볼 수 있다. 상세한 내용 확인을 위해 describe를 사용해보자.

$ kubectl describe pods
...
Events:
  Type     Reason     Age                  From               Message
  ----     ------     ----                 ----               -------
  Normal   Scheduled  <unknown>            default-scheduler  Successfully assigned default/kubernetes-bootcamp-6b4c55d8fc-fgtwh to m01
  Normal   Pulling    55s (x4 over 2m23s)  kubelet, m01       Pulling image "gcr.io/google-samples/kubernetes-bootcamp:v10"
  Warning  Failed     53s (x4 over 2m21s)  kubelet, m01       Failed to pull image "gcr.io/google-samples/kubernetes-bootcamp:v10": rpc error: code = Unknown desc = Error response from daemon: manifest for gcr.io/google-samples/kubernetes-bootcamp:v10 not found: manifest unknown: Failed to fetch "v10" from request "/v2/google-samples/kubernetes-bootcamp/manifests/v10".
  Warning  Failed     53s (x4 over 2m21s)  kubelet, m01       Error: ErrImagePull
  Normal   BackOff    27s (x6 over 2m21s)  kubelet, m01       Back-off pulling image "gcr.io/google-samples/kubernetes-bootcamp:v10"
  Warning  Failed     12s (x7 over 2m21s)  kubelet, m01       Error: ImagePullBackOff
...

레파지토리에 v10 이미지가 없어서 생긴 에러였다. rollout 명령어를 사용해서 이전 버전으로 롤백해보자.

$ kubectl rollout undo deployments/kubernetes-bootcamp
deployment.apps/kubernetes-bootcamp rolled back

$ kubectl get pods
NAME                                 READY   STATUS    RESTARTS   AGE
kubernetes-bootcamp-b4d9f565-jw76c   1/1     Running   0          12m
kubernetes-bootcamp-b4d9f565-mbg26   1/1     Running   0          12m

$ kubectl describe pods
...
Containers:
  kubernetes-bootcamp:
    Container ID:   docker://4f726cfe7a828f0fc3f8e6e4a400bcaf763e26fc522490c09da40113e53f84c5
    Image:          jocatalin/kubernetes-bootcamp:v2
    Image ID:       docker-pullable://jocatalin/kubernetes-bootcamp@sha256:fb1a3ced00cecfc1f83f18ab5cd14199e30adc1b49aa4244f5d65ad3f5feb2a5
Port:           <none>
... 

이미지를 확인해보면 다시 v2인 것을 볼 수 있다.