쿠버네티스 기초
본문은 인프런의 대세는 쿠버네티스 [초급~중급] 강의를 정리한 글입니다.
모든 본문의 내용과 이미지의 출처는 강의자료에 있습니다.
Why Kubernetes?
VM vs Container
도커를 사용해서 컨테이너 이미지를 만든다.
- 컨테이너 이미지 : 한 서비스, 서비스가 돌아가는데 필요한 라이브러리가 같이 있다.
버전 차이에 따른 에러 문제를 해결할 수 있다.
다른 운영체제에 다른 라이브러리 버전이 설치되어 있어도 도커가 있으면 이미지를 가져와서 사용할 때, 서비스는 자신의 이미지에 있는 오픈스택 라이브러리를 사용하기 때문에 안정적인 서비스를 할 수 있다.
- 여러 컨테이너 간에 호스트 자원을 나눠서 사용할 수 있도록 해준다.
리눅스의 고유 기술인 namespace
와 cgroups
를 사용해서 격리하는 것이다.
-
namespace
: 커널에 대한 분리 -
cgroups
: 자원에 대한 분리
⇒ 도커와 같은 컨테이너 가상화 솔류션은 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만 확장할 수 있다.
- 쿠버네티스가 이를 쉽게 해준다.
Getting started Kubernetes
(시나리오) 도커 환경과 쿠버네티스 환경에서 앱을 실행
[리눅스]
- 리눅스 서버에서 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]
-
도커가 깔려있는 다른 서버에서 앞서 만든 Hello World 앱을 그대로 가져온다.
- 하지만 이 서버에는 Node.js가 깔려있지 않아서 앱을 실행할 수 없다.
-
도커를 이용해 컨테이너를 만든다.
- Docker Hub : 여러가지 컨테이너 이미지를 공개적으로 올릴 수 있는 곳이 있다.
-
Docker Hub에서 Node.js를 실행할 수 있는 컨테이너 이미지를 가져온다.
2-2) Docker Hub Site
https://hub.docker.com/
-
여기에 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
- 이 작업을 하기 위한
-
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
-
쿠버네티스를 사용해서 앱을 띄우기 위한 작업으로, 앞에서 만든 컨테이너 이미지를 다시 Docker Hub에 올린다.
2-4) Docker Image Push
docker login docker push kubetm/hello
[Kubernetes]
-
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
-
외부에서 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
- (Node는 PC와 같이 하나의 자원을 제공해주는 컴퓨터?라고 보면 될 듯?)
쿠버네티스는 서버 한 대는 Master로 쓰고, 다른 서버는 Node로 사용한다.
한 마스터에 여러 Node들이 연결된다. 이렇게 연결되면 이 환경이 하나의 Kubernetes Cluster
라는 개념에 묶이게 된다.
-
Master : 쿠버네티스의 전반적인 기능들을 컨트롤하는 역할
-
Node : 자원을 제공하는 역할
쿠버네티스 전체 자원을 늘리고 싶다면 Node들을 계속 추가하면 된다.
-
Namespace : 쿠버네티스 내의 네임스페이스는 쿠버네티스 오브젝트들을 독립된 공간을 분리되게 만들어 준다.
-
쿠버네티스 최소 배포 단위인 Pod(파드)들이 있고,
Pod들에게 외부로 부터 연결이 가능하도록 IP를 할당해주는 Service가 있다.
-
서로 다른 Namespace에 있는 Pod들 에게는 연결할 수 없다.
-
-
Pod안 에는 여러 Container가 있다.
- Container 하나다 하나의 앱이 동작하기 때문에 Pod에는 여러 앱들이 돌아갈 수 있다.
-
Pod에 문제가 생겨서 재생성이 되면 그 안의 데이터들이 날아간다.
- 그래서 Volume을 만들어서 Pod에 연결하면 데이터는 Volume에 별도로 저장할 수 있으니깐, Pod가 재생성돼서 데이터가 날아가는 문제를 해결할 수 있다.
- Namespace에
ResourceQuota(리소스쿼터)
와LimitRange
를 달아서, 한 네임스페이스에서 사용할 수 있는 자원의 양을 한정시킬 수 있다.- Pod의 갯수를 제한, CPU나 메모리 제한
- Pod 생성 시 컨테이너 안에 환경변수 값을 넣어준다거나 파일을 마운팅해줄 수 있다.
ConfigMap
이나Secret
을 통해서 세팅할 수 있다.
- Controller가 Pod들을 관리해주는 역할을 한다.
- 컨트롤러 종류가 다양하고, 각각의 사용 용도가 존재한다.
Controller 종류
-
Replication Controller, ReplicaSet
-
가장 기본적인 Controller
- Pod가 죽으면 강제해서 다시 살려준다.
- Pod의 갯수를 늘리거나 줄일 수 있다. (Scale - in-out)
-
- Deployment
- 배포 후에 Pod들을 새 버전으로 업그레이드 해준다.
- 업그레이드 중에 문제가 생기면 Rollback을 쉽게 해준다.
- DaemonSet
- 한 Node에 하나의 Pod만 유지하게 해준다.
- 이렇게 사용해야하는 모듈들이 존재한다. (추후에 다룸)
- CronJob
- Job : 어떤 특정 작업만하고 종료를 시켜야하는 작업을 할 때 Pod가 그렇게 동작하도록 해준다.
- 그러한 Job들을 주기적으로 실행해야할 때 CronJob을 사용한다.