Post

[Kubernetes] 쿠버네티스로 컨테이너 시작하기

[쿠버네티스 입문:90가지 예제로 배우는 컨테이너 관리 자동화 표준] 책의 3장 쿠버네티스로 컨테이너 시작하기 단원을 공부하고 작성한 글입니다. 실습을 진행한 환경은 Window10 운영체제입니다.

3.1 kubectl

쿠버네티스 클러스터를 kubectl로 관리하는 방법을 알아보자

3.1.2 기본 사용법

kubectl의 기본 사용법

간단한 에코 서버를 동작시키는 kubectl 명령 예를 통해 kubectl의 기본 사용법을 알아본다.

Untitled

  • 일반적으로 애플리케이션의 개별 기능은 각각 파드로 따로 구현하는 것을 추천한다. 그래야 그 기능에 버그가 생겨도, 다른 파드에 영향 없이 해당 파드만 수정, 제거가 가능하다.

  • 각 파드(기능) 간의 통신은 파드의 private IP address를 통해 이루어진다.

  • 외부 사용자가 파드에 접근하기 위해서, Service라는 쿠버네티스 리소스를 통해 접근해야 한다.


echoserver라는 이름의 파드를 생성한다.

1
2
3
4
5
6
$ kubectl run echoserver --generator=run-pod/v1 --image="k8s.gcr.io/echoserver:1.10" --port=8080
error: unknown flag: --generator
See 'kubectl run --help' for usage.

$ kubectl run echoserver --image=k8s.gcr.io/echoserver:1.10 --port=8080
pod/echoserver created

파드에 접근할 때 필요한 서비스를 생성한다.

1
2
$ kubectl expose po echoserver --type=NodePort
service/echoserver exposed

kubectl get pods로 파드가 정상적으로 생성되었는지 확인한다.

1
2
3
$ kubectl get pods
NAME        READY      STATUS       RESTARTS        AGE
echoserver  1/1        Running      0               2m44s
  • NAME - 파드의 이름

  • READY

    • 0/1 현재 파드가 생성되었으나 사용할 준비가 되지 않았음
    • 1/1 파드가 생성되었고 사용할 준비가 끝났음
  • STATUS - 파드의 현재 상태

    • Running - 파드 실행됨
    • Terminating - (새로운 파드 생성 중) 컨테이너 생성 중
    • ContainerCreating - (새로운 파드 생성 중) 컨테이너 생성 중
  • RESTARTS - 해당 파드가 몇 번 재시작했는지 표시

  • AGE - 파드를 생성한 후 얼마나 시간이 지났는지 표시


kubectl get services로 서비스가 정상적으로 생성되었는지 확인한다.

1
2
3
4
5
6
7
$ kubectl expose po echoserver --type=NodePort
service/echoserver exposed

$ kubectl get services
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
echoserver   NodePort    10.103.207.36   <none>        8080:31205/TCP   3s
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP          26d

서버에 접근할 수 있도록 로컬 컴퓨터로 port-forwarding을 해준다. 서버의 8080 포트를 로컬 컴퓨터의 8080으로 forwarding한다.

1
2
3
4
5
$ kubectl port-forward svc/echoserver 8080:8080
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
Handling connection for 8080
Handling connection for 8080

localhost:8080로 확인할 수 있다.

Untitled

서버를 실행한 후 테스트

다른 shell을 실행한 후 curl http://localhost:8080을 입력한다. Minikube 또는 Kubernetes 클러스터 외부에서 클러스터 내의 서비스에 엑세스 하기 위한 명령어이다.

로컬 머신에서 localhost 주소와 8080 포트를 통해 클러스터 내의 서비스에 HTTP 요청을 보내는데, 이것은 클러스터 내의 서비스로 요청을 전달하고, 해당 서비스가 에코 서버 Pod에 연결되어 응답을 반환하는 방식이다.

만약 동작하지 않는다면, minikubeechoserver를 서비스한 후, minikube 내에서 접근한다.

1
2
$ minikube ssh
docker@minikube:/$ curl http://192.168.@@.@@:31663

Untitled

Untitled

서버 실행 중 로그 수집

kubectl logs -f echoserver으로 시간, HTTP 버전, 웹 브라우저와 운영체제 버전을 확인할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
$ kubectl logs -f echoserver
Generating self-signed cert
Generating a 2048 bit RSA private key
......+++
...........................................................................................................+++
writing new private key to '/certs/privateKey.key'
-----
Starting nginx
127.0.0.1 - - [30/Oct/2023:09:20:29 +0000] "GET / HTTP/1.1" 200 1072 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/@@@.@.@@@@.@@"
127.0.0.1 - - [30/Oct/2023:09:20:29 +0000] "GET /favicon.ico HTTP/1.1" 200 1010 "http://localhost:8080/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/@@@.@.@@@@.@@"
10.244.0.1 - - [30/Oct/2023:09:21:04 +0000] "GET / HTTP/1.1" 200 1074 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/@@@.@.@@@@.@@"
10.244.0.1 - - [30/Oct/2023:09:21:04 +0000] "GET /favicon.ico HTTP/1.1" 200 1013 "http://127.0.0.1:59950/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/@@@.@.@@@@.@@"
10.244.0.1 - - [30/Oct/2023:09:40:37 +0000] "GET / HTTP/1.1" 200 424 "-" "curl/7.@@.0"


실습한 파드와 서비스 삭제

shell에서 서버 로그 수집, 서버 실행을 중지한다.

  • 만약 앞서 minikube service echoserver를 통해 실행했다면, ctrl + ^C로 중지한 후 명령어를 통해 파드와 서비스를 삭제한다.
1
2
3
4
$ kubectl delete pod echoserver
pod "echoserver" deleted
$ kubectl delete service echoserver
service "echoserver" deleted

파드와 서비스 정보를 확인하는 명령으로 파드와 서비스가 정상적으로 삭제되었는지 확인한다.

  • Kubernetes 클러스터의 default namespace에서 리소스(예: Pod, 서비스 등)를 찾을 수 없다는 의미이므로, 정상적으로 삭제된 것이다!
1
2
3
4
5
$ kubectl get pods
No resources found in default namespace.
$ kubectl get services
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   6h48m


3.1.5 kubeconfig 환경 변수

kubectl은 기본적으로 $HOME/.kube/config 파일에서 클러스터, 인증, 컨텍스트 정보를 읽어 들인다. 이러한 클러스터 구성 정보를 kubeconfig라고 한다. docker desktop으로 쿠버네티스를 사용한다면 자동으로 kubeconfig가 설정된다.

클러스터에서 사용할 수 있는 자원들은 kubectl api-resources 명령으로 확인할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ kubectl api-resources
NAME                              SHORTNAMES   APIVERSION                             NAMESPACED   KIND
bindings                                       v1                                     true         Binding
componentstatuses                 cs           v1                                     false        ComponentStatus
configmaps                        cm           v1                                     true         ConfigMap
endpoints                         ep           v1                                     true         Endpoints
events                            ev           v1                                     true         Event
limitranges                       limits       v1                                     true         LimitRange
namespaces                        ns           v1                                     false        Namespace
nodes                             no           v1                                     false        Node
# 중략
csistoragecapacities                           storage.k8s.io/v1                      true         CSIStorageCapacity
storageclasses                    sc           storage.k8s.io/v1                      false        StorageClass
volumeattachments                              storage.k8s.io/v1                      false        VolumeAttachment

—kubeconfig 옵션으로 다른 설정 파일을 지정할 수 있다.

1
2
$ kubectl config use-context docker-desktop
Switched to context "docker-desktop".


3.1.7 다양한 사용 예

kubectl을 단순히 명령 실행에 사용하는 것뿐 아니라, shell script의 일부분으로 사용하여 클러스터의 많은 동작을 자동화할 수 있다.

쿠버네티스에서의 JSONPath 사용

JSONPath란?

JSONPath에 대한 글이 아니므로, 이 단원에서 필요한 JSONPath에 대한 내용은 다른 포스트에 작성하였다. 쿠버네티스에서는 클러스터 config 내용이나 node, resource 정보를 조회할 때 JSONPath 템플릿을 사용할 수 있다.

장점 1) kubectl get 기본 명령으로는 접근할 수 없는 정보를 알아볼 수 있다.

장점 2) 필요에 따라 출력 결과물을 원하는 조건에 따라 정렬시킬 수 있다.

⇒ 수십 개의 노드를 동시에 관리해야 하는 상용 환경에서도 꼭 필요한 정보만 걸러내어 확인할 수 있다!

실습

JSONPath를 이용해서 원하는 정보를 확인하자! echoserver, [자기이름]server 2개의 파드를 생성한다. 앞서 echoserver를 삭제했지만, 연습 삼아서 다시 만들어본다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ kubectl run echoserver --image=k8s.gcr.io/echoserver:1.10 --port=8080
pod/echoserver created

$ kubectl expose po echoserver --type=NodePort
service/echoserver exposed

$ kubectl get pods
NAME         READY   STATUS    RESTARTS   AGE
echoserver   1/1     Running   0          16s

$ kubectl run yunjinserver --image=k8s.gcr.io/echoserver:1.10 --port=8080
pod/yunjinserver created

$ kubectl expose po yunjinserver --type=NodePort
service/yunjinserver exposed

# pod, service 정상 생성 확인
$ kubectl get pods
NAME           READY   STATUS    RESTARTS   AGE
echoserver     1/1     Running   0          63s
yunjinserver   1/1     Running   0          17s
...

$ kubectl get services
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
echoserver     NodePort    10.106.213.33   <none>        8080:32760/TCP   76s
kubernetes     ClusterIP   10.96.0.1       <none>        443/TCP          26d
yunjinserver   NodePort    10.107.50.145   <none>        8080:32614/TCP   26s
...


3.2 디플로이먼트를 이용해 컨테이너 실행하기

쿠버네티스를 이용해서 컨테이너를 실행하는 방법은 다음과 같다.

방법 1) kubectl run 명령으로 직접 컨테이너를 실행한다.

방법 2) 어떻게 실행할 지 세부 내용을 담은 YAML 형식의 템플릿으로 컨테이너를 실행한다. → 버전 관리 시스템과 연동해서 자원 정의 변동 사항을 추적하기 쉽다.

Untitled

Untitled

servicepod의 논리적인 집합이며, 어떻게 접근할 지에 대한 정책을 내놓은 것이다. serviceLabel Selector를 통해 어떤 pod를 포함할 지 정의할 수 있다. 각 pod의 외부 IP로는 직접적인 접근이 불가능하지만, service는 가능하게 한다.

3.2.1 kubectl run으로 컨테이너 실행하기

쿠버네티스는 파드를 실행하는 여러 가지 컨트롤러를 제공하는데, kubectl run으로 파드를 실행시킬 때 기본 컨트롤러는 디플로이먼트이다.

디플로이먼트를 이용해 nginx 컨테이너를 실행하자.

(교재에 나온 명령어) kubectl run 디플로이먼트이름 —image 컨테이너이미지이름 —port=80을 하면 deployment.apps가 나오지 않고 pod가 생성된다.

1
2
$ kubectl run nginx-app --image nginx --port=80
pod/nginx-app created

디플로이먼트를 이용해 nginx를 실행하고, 디플로이먼트를 노출시키고, nginx를 실행하는 파드를 시작한다.

1
2
3
4
5
6
7
8
$ docker stop nginx-app
nginx-app

$ docker rm nginx-app
nginx-app

$ docker run -d --restart=always -e DOMAIN=cluster --name nginx-app -p 80:80 nginx
e070188344c507f20942944ab1178ac60fabae6c559ba26bf1e25a47e04d5987
1
2
3
$ docker ps
CONTAINER ID   IMAGE      COMMAND                   CREATED          STATUS          PORTS                  NAMES
677b69a6ec05   nginx     "/docker-entrypoint.…"   4 seconds ago    Up 4 seconds    0.0.0.0:80->80/tcp     nginx-app
1
2
$ kubectl create deployment --image=nginx nginx-app
deployment.apps/nginx-app created

사용자가 쿠버네티스 클러스터에 컨테이너를 실행하라고 명령하면, 지정된 컨테이너 이미지를 가져와 쿠버네티스 클러스터 안에서 실행한다.


nginx 컨테이너가 제대로 실행되는지 확인한다.

1
2
3
4
5
6
7
8
9
$ kubectl get pods
NAME                         READY   STATUS    RESTARTS   AGE
echoserver                   1/1     Running   0          38m
nginx-app-5c64488cdf-lhtg7   1/1     Running   0          68s <<
yunjinserver                 1/1     Running   0          37m

$ kubectl get deployments
NAME        READY   UP-TO-DATE   AVAILABLE   AGE
nginx-app   1/1     1            1           82s <<

디플로이먼트의 상태를 확인하는 항목 각각의 의미는 다음과 같다.

  • NAME - 클러스터에 배포한 디플로이먼트 이름

  • READY - 사용자가 최종 배포한 파드 개수와 디플로이먼트를 이용해 현재 클러스터에 실제로 동작시킨 파드 개수를 X/X 형태로 표시

  • UP-TO-DATE - 디플로이먼트 설정에 정의한 대로 동작 중인 신규 파드 개수

  • AVAILABLE - 서비스 가능한 파드 개수

  • AGE - 디플로이먼트를 생성한 후 지난 시간


디플로이먼트를 이용해서 실행 중인 파드 개수를 늘린다. READY의 출력 결과가 2/2 → 사용자가 최종 배포한 파드 개수와 실제로 동작하는 파드 개수가 각각 2개이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ kubectl scale deploy nginx-app --replicas=2
deployment.apps/nginx-app scaled

$ kubectl get pods
NAME                         READY   STATUS    RESTARTS   AGE
echoserver                   1/1     Running   0          51m
nginx-app                    1/1     Running   0          31m
nginx-app-5c64488cdf-lh67r   1/1     Running   0          26s <<
nginx-app-5c64488cdf-lhtg7   1/1     Running   0          14m <<
yunjinserver                 1/1     Running   0          50m

$ kubectl get deployments
NAME        READY   UP-TO-DATE   AVAILABLE   AGE
nginx-app   2/2     2            2           14m


원활한 실습을 위해 파드와 디플로이먼트를 삭제한다.

1
2
3
4
5
6
7
8
9
10
$ kubectl delete deployment nginx-app
deployment.apps "nginx-app" deleted

$ kubectl get deployments
No resources found in default namespace.

$ kubectl get pods
NAME           READY   STATUS    RESTARTS   AGE
echoserver     1/1     Running   0          56m
yunjinserver   1/1     Running   0          55m


디플로이먼트를 삭제하면, 파드도 함께 삭제된다. 아래 이미지와 같은 구조로 인해, 디플로이먼트를 삭제하면 파드도 함께 삭제된다. 디플로이먼트는 파드를 업데이트하기 위한 선언적 명세이다.

Untitled

3.2.2 템플릿으로 컨테이너 실행하기

✅ 디플로이먼트 설정이 담긴 템플릿(YAML 파일)로 컨테이너를 실행해보는 실습을 준비했다. 이 포스트의 내용, 교재의 3장 내용이 충분히 이해됐다면 실습은 어렵지 않을 것이다! (사실 나중에 내가 까먹을까봐, 이 실습을 통해 기억해내려고 만든 것이기도 하다!)

Deployment 설정이 담긴 템플릿으로 컨테이너 실행하기 실습


3.3 클러스터 외부에서 클러스터 안 앱에 접근하기

실행 중인 nginx 컨테이너에 접속하는 방법을 살펴보자. 쿠버네티스 내부에서 사용하는 네트워크는, 외부와 격리되어 있다! 쿠버네티스 내부에서 실행한 컨테이너를 외부에서 접근하려면, 쿠버네티스 서비스를 사용해야 한다.

서비스 하나에 모든 노드의 지정된 포트를 할당하는 NodePort를 설정한다.

  • YAML 파일을 저장한 경로에서 수행한다. nginx-app-deployment-perfect라는 서비스가 생성되어 있다.

  • 쿠버네티스 내부의 80번 포트가 30804라는 외부 포트와 연결되어 있고, Endpoint를 보면 서비스에 컨테이너 2개가 연결되어 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ kubectl expose deployment nginx-app-deployment-perfect  --type=NodePort
service/nginx-app-deployment-perfect exposed

$ kubectl get service
NAME                           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
echoserver                     NodePort    10.109.240.33    <none>        8080:31163/TCP   56m
kubernetes                     ClusterIP   10.96.0.1        <none>        443/TCP          26d
nginx-app-deployment-perfect   NodePort    10.96.155.121    <none>        **80:30804/TCP**     17s
yunjinserver                   NodePort    10.102.144.249   <none>        8080:32174/TCP   55m

$ kubectl describe service nginx-app-deployment-perfect
Name:                     nginx-app-deployment-perfect
Namespace:                default
Labels:                   app=nginx-app-deployment-perfect
Annotations:              <none>
Selector:                 app=nginx-app-hello
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.96.155.121
IPs:                      10.96.155.121
LoadBalancer Ingress:     localhost
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30804/TCP
**Endpoints:                10.1.0.59:80,10.1.0.60:80**
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>


localhost:30804로 접속하면 nginx의 기본 페이지를 확인할 수 있고, 이 화면을 만나면 클러스터 안의 앱에 접근한 것이다.

Untitled


사용하지 않을 컨테이너를 삭제한다.

1
2
3
4
5
6
7
8
9
10
11
$ kubectl delete deployment nginx-app
deployment.apps "nginx-app" deleted

$ kubectl get pods
NAME           READY   STATUS    RESTARTS   AGE
echoserver     1/1     Running   0          81m
nginx-app      1/1     Running   0          62m
yunjinserver   1/1     Running   0          81m

$ kubectl get deployments
No resources found in default namespace.


이미지 출처



This post is licensed under CC BY 4.0 by the author.