쿠버네티스 기초

4 minute read

본문은 인프런의 대세는 쿠버네티스 [초급~중급] 강의를 정리한 글입니다.

모든 본문의 내용과 이미지의 출처는 강의자료에 있습니다.

Why Kubernetes?

image-20210404174500663

VM vs Container

image-20210404174649276

도커를 사용해서 컨테이너 이미지를 만든다.

  • 컨테이너 이미지 : 한 서비스, 서비스가 돌아가는데 필요한 라이브러리가 같이 있다.

버전 차이에 따른 에러 문제를 해결할 수 있다.

다른 운영체제에 다른 라이브러리 버전이 설치되어 있어도 도커가 있으면 이미지를 가져와서 사용할 때, 서비스는 자신의 이미지에 있는 오픈스택 라이브러리를 사용하기 때문에 안정적인 서비스를 할 수 있다.

image-20210404175043617

  • 여러 컨테이너 간에 호스트 자원을 나눠서 사용할 수 있도록 해준다.

리눅스의 고유 기술인 namespacecgroups를 사용해서 격리하는 것이다.

  • namespace : 커널에 대한 분리

  • cgroups : 자원에 대한 분리

image-20210404175126006

도커와 같은 컨테이너 가상화 솔류션은 OS에서 제공하는 자원격리 기술을 이용해서 컨테이너 단위로 서비스를 분리할 수 있게 해주고, 이 것을 사용하면 컨테이너 가상화가 깔려 있는 OS에서는 개발환경에 대한 걱정 없이 배포가 가능하게 된다.

구조적 차이

VM

  • 각각의 OS를 띄워야하는 구조
  • Host OS가 리눅스인 환경에서 윈도우 OS를 설치해서 사용할 수 있다.
  • 보안적으로 한 Guest OS가 뚫려도 다른 Guest OS나 Host OS와 완벽히 분리되어 있기 때문에 각각의 VM끼리 피해가 가지 않다.

Container

  • 한 OS를 공유
  • Host OS가 리눅스인 환경에서 윈도우용 컨테이너를 사용할 수 없다.
  • 한 컨테이너가 뚫려서 OS에 접근하게 되면 다른 컨테이너도 위협이 될 수 있다.

시스템 개발 사상 차이

VM

  • 한 서비스를 만들 때, 한개의 언어로 사용해서 여러 모듈들이 한 서비스로 돌아간다.
  • A와 B 모듈은 괜찮은데 C 모듈의 부하가 가는 상황이라면 하나의 서비스를 더 띄운다.
    • 자원 사용과 성능 입장에서 Guest OS가 2 개 사용된다.
    • A와 B는 사실 필요 없지만 같은 패키지로 존재해서 따라 올라가게 되는 것이다.

Container

  • 컨테이너를 얘기할 때는 Micro Service가 따라온다.
  • 한 서비스를 만들 때 모듈별로 쪼개서 각각의 컨테이너에 담는 것을 권장한다.
  • 그리고 각 모듈에 맞는 최적화된 언어를 사용하면 더 좋다.
  • 여기서 쿠버네티스는 여러 컨테이너들을 한 Pod(파드)로 묶을 수 있고, 하나의 컨테이너도 한 Pod에 담을 수 있다.
  • 이 한 Pod가 하나의 배포 단위이다.

  • 내가 필요한 Pod만 확장할 수 있다.
  • 쿠버네티스가 이를 쉽게 해준다.

image-20210404180115077

Getting started Kubernetes

image-20210404181049317

(시나리오) 도커 환경과 쿠버네티스 환경에서 앱을 실행

[리눅스]

image-20210408205457727

  1. 리눅스 서버에서 Hello World라는 앱을 만들어서 실행
    • 리눅스에는 Node.js를 실행할 수 있는 패키지가 깔려있다.

1-1) Hello.Js

var http = require('http');
var content = function(req, resp) {
 resp.end("Hello Kubernetes!" + "\n");
 resp.writeHead(200);
}
var w = http.createServer(content);
w.listen(8000);
node hello.js

[Docker]

image-20210408205417324

  1. 도커가 깔려있는 다른 서버에서 앞서 만든 Hello World 앱을 그대로 가져온다.

    • 하지만 이 서버에는 Node.js가 깔려있지 않아서 앱을 실행할 수 없다.
  2. 도커를 이용해 컨테이너를 만든다.

    • Docker Hub : 여러가지 컨테이너 이미지를 공개적으로 올릴 수 있는 곳이 있다.
  3. Docker Hub에서 Node.js를 실행할 수 있는 컨테이너 이미지를 가져온다.

    2-2) Docker Hub Site

    https://hub.docker.com/
    
  4. 여기에 Hello World 앱을 합쳐서 하나의 컨테이너 이미지로 만든다.

    • 이 작업을 하기 위한 Dockerfile 이 필요

    2-1) Dockerfile

    • FROM node:slim : nodejs의 slime 버전을 가져온다.
    • EXPOSE 8000 : 8000번 포트를 오픈시켜 놓는다.
    • COPY hello.js . : hello.js 파일을 현재 위치(.)에 복사해온다.
    • CMD node hello.js : 컨테이너를 구동시킬 때 실행시킬 명령어 “hello.js를 node로 실행해라”
    FROM node:slim
    EXPOSE 8000
    COPY hello.js .
    CMD node hello.js
    
  5. Dockerfile 내용에 따라 컨테이너 이미지가 만들어지면 도커로 이 컨테이너를 구동시켜서 외부에서 이 서비스에 접근할 수 있도록 오픈 시킨다.

    2-3) Docker Container Run

    docker build -t kubetm/hello .
    -t : 레파지토리/이미지명:버전
       
    docker images
    docker run -d -p 8100:8000 kubetm/hello # (내부)8000번 포트에서 서비스
    -d : 백그라운드 모드
    -p : 포트변경
       
    docker ps
    docker exec -it c403442e8a59 /bin/bash
    
  6. 쿠버네티스를 사용해서 앱을 띄우기 위한 작업으로, 앞에서 만든 컨테이너 이미지를 다시 Docker Hub에 올린다.

    2-4) Docker Image Push

    docker login
    docker push kubetm/hello
    

[Kubernetes]

Getting started Hello World on Kubernetes

  1. Pod와 Pod내의 Container를 만들 때, Docker Hub로 부터 컨테이너 이미지를 가져와서 Pod을 구동시킨다.

    3-1) Pod

    apiVersion: v1 # 버전
    kind: Pod # 오브젝트 종류 - Pod를 만들겠다.
    metadata:
      name: hello-pod # 이 Pod의 이름
      labels:
        app: hello # service 오브젝트의 selector 값과 같은 서비스에 연결된다.
    spec:
      containers: # Pod안에 Container를 만들겠다.
      - name: hello-container # Container의 이름을 지정
        image: kubetm/hello # 가져오려는 이미지 - 레파지토리/이미지명:버전 
        ports:
        - containerPort: 8000 # 이 컨테이너의 포트는 8000번으로 open
    
  2. 외부에서 Pod에 접근할 수 있는 Service 오브젝트를 생성

    • Service는 Pod를 외부에 노출시켜서 외부에서 접근해서 사용할 수 있게 해준다.
    • Service의 spec:selector: 에 지정한 app: hello 는 Pod의 labels: 에 지정한 app: hello 와 매칭되어서 Pod-Service가 연결된다.

    3-2) Service

    apiVersion: v1 # 버전
    kind: Service # 오브젝트 종류 - Service를 만들겠다.
    metadata:
      name: hello-svc # 이 Service의 이름
    spec:
      selector:
        app: hello # 여기 지정한 selector 값과 같은 label이 붙은 pod와 연결
      ports:
        - port: 8200 # 외부로 open 시키는 포트
          targetPort: 8000 # container의 포트
      externalIPs:
      - 192.168.0.30 # 외부에서 접근할 수 있는 IP
    

실습 자료 출처

쿠버네티스 기능 Overview

image-20210404181102992

  • (Node는 PC와 같이 하나의 자원을 제공해주는 컴퓨터?라고 보면 될 듯?)

쿠버네티스는 서버 한 대는 Master로 쓰고, 다른 서버는 Node로 사용한다.

한 마스터에 여러 Node들이 연결된다. 이렇게 연결되면 이 환경이 하나의 Kubernetes Cluster라는 개념에 묶이게 된다.

  • Master : 쿠버네티스의 전반적인 기능들을 컨트롤하는 역할

  • Node : 자원을 제공하는 역할

쿠버네티스 전체 자원을 늘리고 싶다면 Node들을 계속 추가하면 된다.

  • Namespace : 쿠버네티스 내의 네임스페이스는 쿠버네티스 오브젝트들을 독립된 공간을 분리되게 만들어 준다.

    • 쿠버네티스 최소 배포 단위인 Pod(파드)들이 있고,

      Pod들에게 외부로 부터 연결이 가능하도록 IP를 할당해주는 Service가 있다.

    • 서로 다른 Namespace에 있는 Pod들 에게는 연결할 수 없다.

      image-20210404182937417

  • Pod안 에는 여러 Container가 있다.

    • Container 하나다 하나의 앱이 동작하기 때문에 Pod에는 여러 앱들이 돌아갈 수 있다.
  • Pod에 문제가 생겨서 재생성이 되면 그 안의 데이터들이 날아간다.

    • 그래서 Volume을 만들어서 Pod에 연결하면 데이터는 Volume에 별도로 저장할 수 있으니깐, Pod가 재생성돼서 데이터가 날아가는 문제를 해결할 수 있다.
  • Namespace에 ResourceQuota(리소스쿼터)LimitRange를 달아서, 한 네임스페이스에서 사용할 수 있는 자원의 양을 한정시킬 수 있다.
    • Pod의 갯수를 제한, CPU나 메모리 제한
  • Pod 생성 시 컨테이너 안에 환경변수 값을 넣어준다거나 파일을 마운팅해줄 수 있다.
    • ConfigMap이나 Secret 을 통해서 세팅할 수 있다.
  • ControllerPod들을 관리해주는 역할을 한다.
    • 컨트롤러 종류가 다양하고, 각각의 사용 용도가 존재한다.

Controller 종류

  1. Replication Controller, ReplicaSet

    • 가장 기본적인 Controller

    • Pod가 죽으면 강제해서 다시 살려준다.
    • Pod의 갯수를 늘리거나 줄일 수 있다. (Scale - in-out)
  2. Deployment
    • 배포 후에 Pod들을 새 버전으로 업그레이드 해준다.
    • 업그레이드 중에 문제가 생기면 Rollback을 쉽게 해준다.
  3. DaemonSet
    • 한 Node에 하나의 Pod만 유지하게 해준다.
    • 이렇게 사용해야하는 모듈들이 존재한다. (추후에 다룸)
  4. CronJob
    • Job : 어떤 특정 작업만하고 종료를 시켜야하는 작업을 할 때 Pod가 그렇게 동작하도록 해준다.
    • 그러한 Job들을 주기적으로 실행해야할 때 CronJob을 사용한다.