티스토리 뷰

728x90
반응형

쿠버네티스를 시작하기 전에

도커 스웜 모드와 비교해서 쿠버네티스만이 가지는 고유한 특징들을 살펴보자.

  1. 모든 리소스는 오브젝트 형태로 관리된다.
    도커 스웜 모드에서 컨테이너의 묶음을 표현하기 위해 서비스라는 것을 사용했는데 이것도 컨테이너 리소스의 집합을 정의한 것이기 때문에 일종의 오브젝트라고 볼 수 있다. 그러나 쿠버네티스는 이러한 개념을 더욱 폭넓고 세밀한 단위로 사용한다. 예를 들어 쿠버네티스에서는 컨테이너의 집합(Pods), 컨테이너의 집합을 관리하는 컨트롤러(Replica Set), 심지어 사용자(Service Account), 노드(Node)까지도 하나의 오브젝트로 사용할 수 있다. 쿠버네티스에서 사용할 수 있는 오브젝트는 kubectl api-resources 명령어를 사용해 확인할 수 있다. 특정 오브젝트의 간단한 설명을 보고 싶으면 kubectl explain '오브젝트' 명령어를 사용한다.

  2. 쿠버네티스는 명령어로도 사용할 수 있지만, YAML 파일을 더 많이 사용한다.
    YAML 파일로 컨테이너 리소스를 생성하거나 삭제할 수 있다. 쿠버네티스에서 YAML 파일의 용도는 컨테이너뿐만 아니라 거의 모든 리소스 오브젝트들에 사용될 수 있다는 것이 가장 큰 특징이다. 예를 들어 컨테이너 자체는 물론이고, 컨테이너의 설정값(ConfigMap), 비밀값(Secrets) 등도 모두 YAML 파일로 정의해 사용한다. 그리고 쿠버네티스에서 실제로 서비스를 배포할 때에도 kubectl 명령어가 아닌 여러 개의 YAML 파일을 정의해 쿠버네티스에 적용시키는 방식으로 동작한다.

  3. 쿠버네티스는 여러 개의 컴포넌트로 구성되어 있다.
    쿠버네티스 노드의 역할은 크게 마스터와 워커로 나뉘어 있다. 마스터 노드는 쿠버네티스가 제대로 동작할 수 있게 클러스터를 관리하는 역할을 담당하며, 워커 노드에는 애플리케이션 컨테이너가 생성된다. 쿠버네티스는 도커를 포함한 매우 많은 컴포넌트들이 실행된다. 마스터 노드에는 API 서버(kube-apiserver), 컨트롤러 매니저(kube-controller-manager), 스케줄러(kube-scheduler), DNS 서버(coreDNA) 등이 실행되며, 모든 노드에서는 오버레이 네트워크 구성을 위해 프락시(kube-proxy)와 네트워크 플러그인(calico, flannel 등)이 실행된다. 쿠버네티스 클러스터 구성을 위해 kubelet이라는 에이전트가 모든 노드에서 실행된다. kubelet은 컨테이너의 생성, 삭제뿐만 아니라 마스터와 워커 노드 간의 통신 역할을 함께 담당하는 매우 중요한 에이전트이다.



포드(Pod): 컨테이너를 다루는 기본 단위

컨테이너 애플리케이션을 구동하기 위해 반드시 알아야 할 몇가지 오브젝트들 : 포드(Pod), 레플리카셋(Replica Set), 서비스(Service), 디플로이먼트(Deployment)

이중에 포드를 먼저 배워보자.

포드 사용하기

쿠버네티스에서는 컨테이너 애플리케이션의 기본 단위를 포드(Pods)라고 부르며, 포드는 1개 이상의 컨테이너로 구성된 컨테이너의 집합이다. 1개의 포드에는 1개의 컨테이너가 존재할 수도 있고, 여러 개의 컨테이너가 존재할 수도 있다.

Nginx 컨테이너로 구성된 포드를 직접 생성해보자.

# vi nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-nginx-pod
spec:
  containers:
  - name: my-nginx-container
    image: nginx:latest
    ports:
    - containerPort: 80
      protocol: TCP

일반적으로 apiVersion, kind, metadata, spec 네 가지 항목으로 구성된다.

  • apiVersion : YAML 파일에서 정의한 오브젝트의 API 버전. 오브젝트의 종류 및 개발 성숙도에 따라 apiVersion이 달라질 수 있다.
  • kind : 이 리소스의 종류를 나타낸다.
  • metadata : 라벨, 주석, 이름 등과 같은 리소스의 부가 정보들.
  • spec : 리소스를 생성하기 위한 자세한 정보.

다음 명령어로 새로운 포드를 생성할 수 있다.

$ kubectl apply -f nginx-pod.yaml

특정 오브젝트의 목록을 확인하려면 아래의 명령어를 사용하면된다. 포드 1개가 출력될 것이다.

$ kubectl get pods

yaml파일에 포트를 정의하긴 했지만, 아직 외부에서 접근할 수 있도록 노출된 상태는 아니다. 따라서 포드의 Nginx 서버로 요청을 보내려면 포드 컨테이너의 내부 IP로 접근해야 한다.

kubectl describe 명령어를 사용하면 생성된 리소스의 자세한 정보를 얻을 수 있다. 이 명령어로 포드의 IP를 확인하자.

$ kubectl describe pods my-nginx-pod

Name:         my-nginx-pod
Namespace:    default
Priority:     0
Node:         minikube/192.168.49.2
Start Time:   Tue, 29 Jun 2021 01:18:40 +0900
Labels:       <none>
Annotations:  <none>
Status:       Running
IP:           172.17.0.2 #이거
IPs:
  IP:  172.17.0.2
...
...
...

이 IP는 외부에서 접근할 수 있는 IP가 아니기 때문에 클러스터 내부에서만 접근할 수 있다. docker run 명령어에서 -p 옵션 없이 컨테이너를 실행한 것과 비슷하다고 생각하면 이해가 쉽다.

쿠버네티스 외부 또는 내부에서 포드에 접근하려면 서비스라고 하는 쿠버네티스 오브젝트를 따로 생성해야 하지만, 지금은 서비스 오브젝트 없이 IP만으로 Nginx 포드에 접근해보자.

minikube로 작업을 하기 때문에 클러스터의 노드(1개의 마스터 노드, 여러 개의 워커 노드로 구성했을 때 워커노드를 의미)가 없으므로, 다음 명령어로 클러스터 내부에 테스트용 포드를 생성해 임시로 사용하자. 일반적으로 클러스터 내부에서는 포드의 IP로 접근할 수 있다.

kubectl run -i --tty --rm debug \
> --image=alicek106/ubuntu:curl --restart=Never bash


root@debug:/# curl 172.17.0.2(본인 nginx pod ip로)
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>


root@debug:/# exit
exit
pod "debug" deleted

이제 포드 컨테이너 내부로 직접 들어가보자. docker exec 명령어와 비슷하게 쿠버네티스에서도 kubectl exec 명령으로 포드의 컨테이너에 명령어를 전달할 수 있다.

kubectl exec -it my-nginx-pod bash


root@my-nginx-pod:/# ls /etc/nginx/
...
...
root@my-nginx-pod:/# exit

도커에서 docker logs 명령어를 사용했던 것처럼 쿠버네티스에서도 kubectl logs 명령어로 포드의 로그를 확인할 수 있다.

$ kubectl logs my-nginx-pod

쿠버네티스의 오브젝트는 kubectl delete -f 명령어로 삭제할 수 있다.

$ kubectl delete -f nginx-pod.yaml



포드 vs 도커 컨테이너

위의 기능들만 놓고 본다면 포드는 docker run으로 생성한 단일 nginx 컨테이너와 크게 다르지 않아 보이기도 하다. 포드는 컨테이너 IP 주소를 가지고 있어 쿠버네티스 클러스터 내부에서 접근할 수 있고, kubectl exec 명령어로 포드 컨테이너 내부로 들어갈 수도 있으며, kubectl logs 명령어로 포드의 로그를 확인할 수도 있다.

쿠버네티스가 포드를 사용하는 이유는 컨테이너 런타임의 인터페이스 제공 등 여러 가지가 있지만, 그 이유 중 하나는 여러 리눅스 네임스페이스(namespace)를 공유하는 여러 컨테이너들을 추상화된 집합으로 사용하기 위해서다.

kubectl get pods로 my-nginx-pod을 보면 READY에 1/1인 것을 볼 수 있다. Nginx 포드에는 1개의 컨테이너가 정의돼 있고, 이 컨테이너는 정상적으로 준비됐다는 뜻이다. 그러나 1/1이라는 항목에서 알 수 있듯이, 포드는 반드시 1개의 컨테이너로 구성해야 하는 것은 아니다. READY 항목은 포드의 컨테이너 개수에 따라 2/2도 될 수 있고, 3/3도 될 수 있다.

Nginx 포드에 새로운 우분투 컨테이너를 추가해보자.

# vi nginx-pod-ubuntu.yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-nginx-pod
spec:
  containers:
  - name: my-nginx-container
    image: nginx:latest
    ports:
    - containerPort: 80
      protocol: TCP

  - name: ubuntu-sidecar-container
    image: alicek106/rr-test:curl
    command: ["tail"]
    args: ["-f", "/dev/null"] # 컨테이너가 종료되지 않도록 유지합니다.

밑에쪽에 보이는 comamand와 args는 컨테이너 내부에서 가장 먼저 실행될 프로세스를 지정한다. YAML 파일에서 command를 설정하면 도커 컨테이너의 Entrypoint로, 포드에서 args를 설정하면 도커 컨테이너의 cmd(커맨드)로 치환된다고 이해하자.

kubectl apply -f 명령을 사용해 YAML 파일을 쿠버네티스에 적용하고 kubectl get pods로 보면 Nginx 포드에 2개의 컨테이너가 실행 중인 것을 확인할 수 있다.

이번에는 kubectl exec 명령어를 이용해 새롭게 추가된 우분투 컨테이너의 내부로 들어가보자. -c 옵션을 이용해 포드의 어떤 컨테이너에 대해 명령어를 수행할지 명시할 수 있다. 앞서 추가한 컨테이너에 배시 셀을 실행한다.

$ kubectl exec -it my-nginx-pod -c ubuntu-sidecar-container bash

ubuntu-sidecar-container 컨테이너 내부에서 로컬호스트로 HTTP 요청을 전송하면 Nginx 서버의 응답이 도착하는 것을 확인할 수 있다(curl localhost 명령어 사용).

우분투 컨테이너가 Nginx 서버를 실행하고 있지 않은데도, 우분투 컨테이너의 로컬호스트에서 Nginx 서버로 접근이 가능하다. 이는 포드 내의 컨테이너들이 네트워크 네임스페이스 등과 같은 리눅스 네임스페이스를 공유해 사용하기 때문이다.

네트워크 네임스페이스는 컨테이너의 고유한 네트워크 환경을 제공해주는 역할을 담당한다. 예를 들어 docker run 명령어로 docker0 브리지에 연결된 컨테이너가 생성됐다면, 그 컨테이너는 자기 자신만의 고유한 네트워크 네임스페이스를 가지게 된다.

도커 컨테이너에서 컨테이너 네트워크와 비슷하다. 컨테이너 네트워크 타입은(docker run --net ~) 네트워크 네임스페이스를 컨테이너 간에 공유해 사용할 수 있도록 설정하기 때문에 여러 개의 컨테이너가 동일한 네트워크 환경을 가지게 된다. 쿠버네티스의 포드 또한 이러한 리눅스 네임스페이스의 공유 개념을 사용한다.

image

포드가 공유하는 리눅스 네임스페이스에 네트워크 환경만 있는 것은 아니고 여러 개의 리눅스 네임스페이스를 공유할 수 있다.



완전한 애플리케이션으로서의 포드

하나의 포드는 하나의 완전한 애플리케이션이다. Nginx 컨테이너가 실행되기 위해 부가적인 기능을 필요로 하다면 설정 파일의 변경사항을 갱신해주는 설정 리로더 프로세스, 로그를 수집해주는 프로세스 등 Nginx 컨테이너와 함께 실행돼야 할 수 있다. 이런 경우 포드의 주 컨테이너를 Nginx로 하되, 기능 확장을 위한 추가 컨테이너를 함께 포드에 포함시킬 수 있다. 이렇게 포드에 정의된 부가적인 컨테이너를 사이드카 컨테이너라고 부르며, 사이드카 컨테이너는 포드 내의 다른 컨테이너와 네트워크 환경 등을 공유하게 된다. 때문에 포드에 포함된 컨테이너들은 모두 같은 워커 노드에서 함께 실행된다.

image

이러한 구조 및 원리에 따라 포드에 정의된 여러 개의 컨테이너는 하나의 완전한 애플리케이션으로서 동작하게 된다.

앞서 생성한 우분투 컨테이너의 네트워크를 실제로 확인해보면 Nginx 컨테이너가 아닌 Pause라는 이름의 컨테이너로부터 네트워크를 공유해 사용하고 있음을 알 수 있다. Pause 컨테이너는 네임스페이스를 공유하기 위해 포드별로 생성되는 컨테이너이다.

$ docker exec -it minikube /bin/bash
root@minikube:/# docker ps | grep nginx
root@minikube:/# docker inspect (ubuntu 컨테이너 id) | grep NetworkMode
# 컨테이너 id가 pause 컨테이너 id랑 같음.
root@minikube:/# exit





출처
시작하세요! 도커/쿠버네티스(용찬호 저, 위키북스)
example

728x90
반응형
댓글
반응형
250x250
글 보관함
최근에 달린 댓글
«   2024/05   »
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 30 31
Total
Today
Yesterday
링크