컨테이너 개발 시대
가상화
•
실제가 아닌 하드웨어 환경을 의미
•
컴퓨터공학에서의 가상화란, 가짜 하드웨어 환경을 만들어내는 기술로, 실제 물리 장비인 Host와 가상머신인 Guest를 구분
호스트(Host) | 가상화 소프트웨어(== 하이퍼바이저)를 구동하는 물리 시스템 |
게스트(Guest) | 하이퍼바이저 위에 설치되는 가상 머신(VM) |
하이퍼바이저 가상화(소프트웨어)
•
한 대의 머신에서 다수의 운영체제를 동시에 실행하는 소프트웨어 ⇒ 하드외어를 가상화
•
VM Monitor와 같은 뜻
컨테이너 가상화(애플리케이션)
•
애플리케이션 구동에 필요한 모든 것을 패키징하고 격리된 환경에서 실행
•
컨테이너 기반의 가상화 ⇒ 애플리케이션 실행환경을 가상화
•
패키징 + 격리된 실행 ⇒ 서버 환경에 영향 X, 사람의 개입 X ⇒ 자동으로 배포
컨테이너란?
•
격리된 환경 + 제한된 리소스로 제어되는 프로세스
•
운영체제(커널) 위에 독립적으로 가상화된 공간
•
공유 자원을 프로세스별로 할당치만큼만 사용하도록 제한
•
의존성 라이브러리, 설정 등 실행에 필요한 모든 것들을 ‘이미지’로 모아 패키징 ⇒ ‘이미지’의 자원만으로 서버 환경에 의존하지 않는 것을 보장
VM과 컨테이너 비교
쿠버네티스란?
•
컨테이너화된 애플리케이션의 배포, 확장 등을 관리하는 것을 자동화하기 위한 플랫폼
•
컨테이너 오케스트레이션 엔진 ⇒ 설정/관리, 적절한 노드로 배치, 모니터링 등
⇒ 컨테이너 런타임(==도커)을 통해 컨테이너를 관리하는 플랫폼
•
서비스를 선언적으로 관리함으로써, 배포한 어플리케이션이 항상 의도한 대로 실행되도록 보장
쿠버네티스 표준 아키텍처 요약본
•
서비스 메시 Istio
◦
프록시를 통한 서비스 호출
◦
서비스의 트래픽을 네트워크단에서 통제, proxy단의 라우팅 서비스 가능
•
CD 미들웨어 ArgoCD
•
네트워크 구현체
◦
Calico 컨테이너 네트워크 인터페이스(CNI), 가장 쉽게 적용 가능
◦
Nginx Ingress Controller 인그레스는 클러스터 외부에서 HTTP(S)를 통해 접속할 수 있는 url을 노출하는 오브젝트
•
배포 간편화 도구 Helm
◦
쿠버네티스 패키지 매니저로서, Chart를 통해 쿠버네티스 클러스터에 컨테이너 어플리케이션을 손쉽게 배포 가능
•
컨테이너 관리 도구
◦
Docker 컨테이너 빌드 도구
◦
containerD 컨테이너 런타임(이미지를 기반으로 컨테이너를 생성하는 소프트웨어 프로그램)
•
매트릭 파이프라인
◦
Prometheus + Grafana 메트릭 수집 + 케트릭 시각화
쿠버네티스 구성요소
마스터 - 노드
•
마스터(컨트롤 플레인): 클러스터를 관리하고 클러스터의 기능을 실행
◦
API Server
▪
사용자 컨트롤 플레인
▪
쿠버네티스 API를 노출하는 컴포넌트
▪
컨트롤 플레인의 프론트엔드
▪
더 많은 인스턴스를 배포하여 병렬적(수평으로) 확장 가능
◦
Scheduler: 노드가 배정되지 않은, 새로 생성된 파드를 감지하고, 실행할 노드를 선택하는 컨트롤 플레인 컴포넌트
◦
Controller Manager: 컨트롤러 프로세스를 실행
▪
노드 컨트롤러: 노드가 다운되었을 때 대응
▪
잡 컨트롤러: 잡 오브젝트(일회성 작업)를 감시한 다음, 해당 작업을 완료할 때까지 동작하는 파드 생성
▪
엔드포인트슬라이스 컨트롤러: 서비스파드 연결고리를 제공하기 위해, 엔드포인트슬라이스 오브젝트를 채움
▪
서비스어카운트 컨트롤러: 새로운 네임스페이스에 대한 기본 서비스어카운트 생성
◦
Cloud Controller Manager
▪
클라우드별 컨트롤 로직을 포함
▪
클라우드 프로바이더 전용 컨트롤러만 실행(온프레미스 실행인 경우 클러스터에 존재하지 않음)
▪
논리적으로 독립적인 여러 컨트롤 루프를 단일 프로세스로 실행하는 단일 바이너리로 결합 ⇒ 수평으로 확장 가능
종류
•
노드: 동작중인 파드를 유지, 쿠버네티스 런타임 환경 제공, 모든 노드 상에서 동작
◦
kubelet: 클러스터의 각 노드에서 실행되는 Agent. 파드에서 컨테이너가 확실하게 동작하도록 관리
◦
kube-proxy
▪
클러스터의 각 노드에서 실행되는 네트워크 프록시, 쿠버네티스 서비스 개념의 구현부
▪
노드의 네트워크 규칙을 유지/관리.
쿠버네티스 YAML 작성하기
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 8090
YAML
복사
apiVersion
스크립트를 실행하기 위한 쿠버네티스 API 버전
kind
리소스의 종류 정의
•
Pod 컨테이너를 하나 이상 모아 놓은 것으로, 쿠버네티스 애플리케이션의 최소 단위
•
ReplicaSet ReplicationController, 쿠버네티스에 선언된 pod를 배포하기 위한 선언
•
Service 동적으로 생성된 pod(각각 다른 ip)들을 라벨과 라벨 셀렉터를 사용하여 하나의 서비스로 묶어주는 역할
•
Deployment 레클리카셋의 상위 개념. 레블리카셋을 생성하는 디플로이먼트를 정의할 수 있고, 배포 작업을 세분화 가능
[실습 1] minikube에서 쿠버네티스로 배포해 보기
Mac
1. homebrew 설치
> /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
> echo 'export PATH=/opt/homebrew/bin:$PATH' >> ~/.zshrc
> source ~/.zshrc
Bash
복사
2. kubectl 설치
> brew install kubernetes-cli
Bash
복사
3. minikube 설치
> brew install --cask minikube
Bash
복사
Window
0. 도커 데스크탑 설치
1. 미니쿠베 설치
2. 명령 프롬포트에서 미니쿠베 확인
> minikube version
Bash
복사
4. minikube 실행
> minikube start
😄 Darwin 12.3 (arm64) 의 minikube v1.31.2
🎉 minikube 1.32.0 이 사용가능합니다! 다음 경로에서 다운받으세요: https://github.com/kubernetes/minikube/releases/tag/v1.32.0
💡 해당 알림을 비활성화하려면 다음 명령어를 실행하세요. 'minikube config set WantUpdateNotification false'
✨ 기존 프로필에 기반하여 docker 드라이버를 사용하는 중
👍 minikube 클러스터의 minikube 컨트롤 플레인 노드를 시작하는 중
🚜 베이스 이미지를 다운받는 중 ...
🤷 docker "minikube" container is missing, will recreate.
🔥 Creating docker container (CPUs=2, Memory=4000MB) ...
🐳 쿠버네티스 v1.27.4 을 Docker 24.0.4 런타임으로 설치하는 중
▪ 인증서 및 키를 생성하는 중 ...
▪ 컨트롤 플레인이 부팅...
▪ RBAC 규칙을 구성하는 중 ...
🔗 Configuring bridge CNI (Container Networking Interface) ...
🔎 Kubernetes 구성 요소를 확인...
▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
▪ Using image docker.io/kubernetesui/dashboard:v2.7.0
▪ Using image docker.io/kubernetesui/metrics-scraper:v1.0.8
💡 Some dashboard features require the metrics-server addon. To enable all features please run:
minikube addons enable metrics-server
🌟 애드온 활성화 : storage-provisioner, default-storageclass, dashboard
🏄 끝났습니다! kubectl이 "minikube" 클러스터와 "default" 네임스페이스를 기본적으로 사용하도록 구성되었습니다.
Bash
복사
5. minikube 대시보드 확인하기
> minikube dashboard
Bash
복사
Deployment 올리기
0. git clone
> git clone https://github.com/sunnyineverywhere/boaz-k8s-scripts.git
Bash
복사
1. hello-deployment.yaml 파일 작성
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-k8s
labels:
app: hello-k8s
spec:
replicas: 1
selector:
matchLabels:
app: hello-k8s
template:
metadata:
labels:
app: hello-k8s
spec:
containers:
- name: hello-k8s
image: sunnyineverywhere/hell-minikube
ports:
- containerPort: 8080
YAML
복사
2. 명령어 실행
# kubectl apply -f {yaml file name}
> kubectl apply -f hello-deployment.yaml
=> deployment.apps/hello-k8s created
Bash
복사
3. 생성된 오브젝트 확인
> kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
hello-k8s 0/1 1 0 45s
Bash
복사
Service로 배포하기
1. hello-service.yaml
apiVersion: v1
kind: Service
metadata:
name: hello-k8s
namespace: default
labels:
app: hello-k8s
spec:
selector:
app: hello-k8s
ports:
- protocol: TCP
port: 8080
nodePort: 30090
type: NodePort
YAML
복사
8080 → 30090
2. service yaml 적용
> kubectl apply -f hello-service.yaml
Bash
복사
3. 적용된 서비스 확인
> kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-k8s NodePort 10.99.251.7 <none> 8080:30090/TCP 16s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5h11m
Bash
복사
> minikube service hello-k8s
|-----------|-----------|-------------|---------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|-----------|-------------|---------------------------|
| default | hello-k8s | 8080 | http://192.168.49.2:30090 |
|-----------|-----------|-------------|---------------------------|
🏃 Starting tunnel for service hello-k8s.
|-----------|-----------|-------------|------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|-----------|-------------|------------------------|
| default | hello-k8s | | http://127.0.0.1:50287 |
|-----------|-----------|-------------|------------------------|
🎉 Opening service default/hello-k8s in default browser...
❗ Because you are using a Docker driver on darwin, the terminal needs to be open to run it.
Bash
복사
4. 서비스 종료
> kubectl delete deploy --all
Bash
복사
Minikube
쿠버네티스를 운영환경에 설치하기 위해서, 최소 3대의 마스터 서버와 컨테이너 배포용 n개의 노드 서버가 필요합니다. 하지만 설치 과정이 복잡하고, 배포 환경에 따라 구축 방법이 다르기 때문에 처음 공부할 때로는 적합하지 않습니다.
따라서 하나의 서버(단일 프로세스)에 마스터와 노드를 설치하여 관리하는 방법을 학습용으로 많이 사용합니다.
minikube 는 로컬 쿠버네티스 클러스터를 빠르게 설정해주는 도구로, 쉽게 로컬에서 쿠버네티스 클러스터를 만들 수 있고 여러 클러스터를 관리하는 것도 가능합니다.
대시보드에 나와 있는 용어를 살펴보고 공부해 봅시다.
쿠버네티스 대시보드에 나온 오브젝트 살펴보기
오브젝트
쿠버네티스 오브젝트는 쿠버네티스 시스템에서 영속성을 가지는 오브젝트로, 쿠버네티스는 클러스터의 상태를 나타내기 위해 이 오브젝트를 이용합니다.
•
어떤 컨테이너화된 애플리케이션이 동작 중인지
•
그 애플리케이션이 이용할 수 있는 리소스
•
애플리케이션이 어떻게 동작하는지에 대한 정책
다른 말로 하면, 하나의 ‘의도를 담은 레코드’라고 볼 수 있는데, 오브젝트를 생성하게 되면 쿠버네티스 시스템은 그 오브젝트 생성을 보장하기 위해 지속적으로 작동할 것이고, 오브젝트를 생성함으로서 클러스터의 워크로드를 어떤 형태로 보이고자 하는지에 대해 시스템에 전합니다.
모든 쿠버네티스 오브젝트 동작(CRUD)에는 쿠버네티스 API를 이용해야 합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-k8s
labels:
app: hello-k8s
spec:
replicas: 1
selector:
matchLabels:
app: hello-k8s
template:
metadata:
labels:
app: hello-k8s
spec:
containers:
- name: hello-k8s
image: sunnyineverywhere/hell-minikube
ports:
- containerPort: 8080
YAML
복사
위에서 작성한 yaml 파일도 오브젝트를 생성하는 파일로 볼 수 있습니다.
•
쿠버네티스 API를 이용할 때, API 요청은 요청 내용 안에 JSON 형식으로 정보를 포함시킴
•
대부분의 경우 .yaml 파일로 kubectl에 제공하면, kubectl은 api 요청이 이루어질 때 JSON 형식으로 yaml을 변환해 요청
apiVersion 사용하고 있는 쿠버네티스 API 버전
kind 어떤 종류의 오브젝트를 생성하고자 하는지
metadata 이름, 문자열, UID, 선택적인 네임스페이스를 포함하여 오브젝트를 구분지어 줄 데이터
spec
오브젝트는 오브젝트를 생성할 때 리소스를 원하는 특징(의도한 상태)에 대한 설명을 제공해서 설정
오브젝트에 대해 어떤 상태를 의도하는가
status
쿠버네티스 시스템과 컴포넌트에 의해 제공되고 업데이트된 오브젝트의 현태 상태를 설명
크론잡
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello
spec:
schedule: "* * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox:1.28
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
YAML
복사
•
하나의 크론잡 오브젝트 == 크론탭 파일의 한 줄
•
모든 크론잡은 kube-controller-manager의 시간대를 기준으로 함
•
문법
항목 | 설명 | 상응 표현 |
@yearly (or @annually) | 매년 1월 1일 자정에 실행 | 0 0 1 1 * |
@monthly | 매월 1일 자정에 실행 | 0 0 1 * * |
@weekly | 매주 일요일 자정에 실행 | 0 0 * * 0 |
@daily (or @midnight) | 매일 자정에 실행 | 0 0 * * * |
@hourly | 매시 0분에 시작 | 0 * * * * |
데몬 셋
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
template:
metadata:
labels:
name: fluentd-elasticsearch
spec:
tolerations:
# 이 톨러레이션(toleration)은 데몬셋이 컨트롤 플레인 노드에서 실행될 수 있도록 만든다.
# 컨트롤 플레인 노드가 이 파드를 실행해서는 안 되는 경우, 이 톨러레이션을 제거한다.
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
containers:
- name: fluentd-elasticsearch
image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
YAML
복사
•
노드가 파드의 사본을 실행하도록 함
•
노드가 클러스터에 추가되면 파드도 추가
•
노드가 클러스에서 제거되면 파드가 가비지로 수집
•
데몬셋을 삭제하면 데몬셋이 생성한 파드들이 정리됨
•
대표적인 용도
◦
모든 노드에서 클러스터 스토리지 데몬 실행
◦
모든 노드에서 로그 수집 데몬 실행
◦
모든 노드에서 노드 모니터링 데몬 실행
디플로이먼트(Deployment)
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
YAML
복사
•
파드와 레플리카셋에 대한 선언적 업데이트 제공
•
디플로이먼트에서 의도하는 상태 를 설명하고, 디플로이먼트 컨트롤러(Controller)는 현재 상태에서 의도하는 상태로 비율을 조정하며 변경
> kubectl describe deployments
Name: hello-k8s
Namespace: default
CreationTimestamp: Wed, 22 Nov 2023 01:00:32 +0900
Labels: app=hello-k8s
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=hello-k8s
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=hello-k8s
Containers:
hello-k8s:
Image: sunnyinsummer/hell-minikube
Port: 8080/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: hello-k8s-758ccf9dc8 (1/1 replicas created)
Events: <none>
YAML
복사
잡(Job)
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: perl:5.34.0
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
backoffLimit: 4
YAML
복사
•
하나 이상의 파드를 생성하고, 지정된 수의 파드가 성공적으로 종료될 때까지 계속해서 파드의 실행을 재시도
•
여러 파드를 병렬로 실행 가능
파드(Pod)
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
YAML
복사
•
쿠버네티스에서 생성하고 관리할 수 있는, 배포 가능한 가장 작은 컴퓨터 단위
[실습 2] EC2 인스턴스로 쿠버네티스 클러스터 구축해 보기 과금주의
EC2 인스턴스 생성
공통 설정
1. 스왑 제거
> swapoff -a
> ip link
> sudo cat /sys/class/dmi/id/product_uuid
Bash
복사
> sudo apt update && sudo apt install -y apt-transport-https curl
> curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
OK
cat << EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
> deb http://apt.kubernetes.io/ kubernetes-xenial main
> EOF
> sudo apt-get update
Bash
복사
2. 쿠버네티스 설치
> sudo apt install -y kubelet=1.18.15-00 kubeadm=1.18.15-00 kubectl=1.18.15-00 docker.io
> kubectl version
Client Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.15", GitCommit:"73dd5c840662bb066a146d0871216333181f4b64", GitTreeState:"clean", BuildDate:"2021-01-13T13:22:41Z", GoVersion:"go1.13.15", Compiler:"gc", Platform:"linux/amd64"}
The connection to the server localhost:8080 was refused - did you specify the right host or port?
> kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.15", GitCommit:"73dd5c840662bb066a146d0871216333181f4b64", GitTreeState:"clean", BuildDate:"2021-01-13T13:20:05Z", GoVersion:"go1.13.15", Compiler:"gc", Platform:"linux/amd64"}
sudo apt-mark hold kubelet kubeadm kubectl docker.io
cat << EOF | sudo tee /etc/sysctl.d/k8s.conf
> net.bridge.bridge-nf-call-ip6tables = 1
> net.bridge.bridge-nf-call-ip6tables = 1
> net.ipv4.ip_forware = 1
> EOF
Bash
복사
3. 도커 설정
> sudo docker info |grep Cgroup
Cgroup Driver: cgroupfs
Cgroup Version: 1
Bash
복사
> sudo vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --exec-opt native.cgroupdriver=systemd
Bash
복사
> sudo systemctl daemon-reload
> sudo systemctl restart docker
Bash
복사
마스터
1. kubeadm init
> sudo kubeadm init --kubernetes-version=1.18.15 --pod-network-cidr=192.168.0.0/16 --apiserver-cert-extra-sans={10.1.1.10,13.125.131.247} --ignore-preflight-errors=NumCPU
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 172.31.14.110:6443 --token dr69f9.vlr5chhbs2po04jf \
--discovery-token-ca-cert-hash sha256:e2270bc7f371c072f1dce624768c3dd2fc34803d8b462e8b2ceacf0947e1d6fb
Bash
복사
> kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-172-31-14-110 NotReady master 62s v1.18.15
Bash
복사
2. Calico 설치
> kubectl apply -f https://docs.projectcalico.org/v3.11/manifests/calico.yaml
Bash
복사
노드 - 조인
> sudo kubeadm join 172.31.14.110:6443 --token dr69f9.vlr5chhbs2po04jf \
--discovery-token-ca-cert-hash sha256:e2270bc7f371c072f1dce624768c3dd2fc34803d8b462e8b2ceacf0947e1d6fb --ignore-preflight-errors=all
Bash
복사