Skip to main content

[React + Spring + Kube] KOSTA 3


쿠버네티스


미니 쿠베를 사용해본다.

kubectlminikube를 설치한다.

kubectl

minikube

시작하기


docker를 띄운 환경에서

minikube start --driver=docker

확인 명령어

  • 버전 확인
kubectl version
  • 클라이언트 버전 확인
kubectl version --client
  • minikube 상태 확인
minikube status
  • 클러스터 정보 확인
kubectl cluster-info
  • 노드 확인
kubectl get node
  • 도커 읽도록 설정
minikube docker-env

해서 나오는 마지막 줄인

@FOR /f "tokens=*" %i IN ('minikube -p minikube docker-env --shell cmd') DO @%i

를 넣는다.

  • 멈추기
minikube stop
  • 삭제하기
minikube delete

쿠버네티스 개념

클라우드 네이티브 앱으로 방법론은 데브옵스 구조는 MSA 인프라는 컨테이너이다.

쿠버네티스란

master와 node로 구성되는데 master는 설정 환경을 저장하고 node는 컴퓨터를 의미한다.

master는 Control Plane Node이고 node는 Worker Nodes이다.

master는 node들을 관리하는 역할을 하고 node는 실제 작업이 이루어진다.

Master 구성요소

master에는 api-server, controller, scheduler, etcd

  • api server

API 인터페이스를 제공하는 frontend 구성요소다. CRUD 요청을 api server를 통해서 하게 된다.

응답값은 etcd에 key value로 저장한다.

쿠버네티스의 저장소가 etcd라고 할 수 있다.

  • controller

desired state를 유지하기 위해서 변경사항 확인하는역할

desired state와 current state를 비교해서 desired state를 유지하기 위해 조치함.

  • scheduler

새로운 pod를 띄워야 한다고 했을 때 어떤 node에 띄울지 스케줄링하는 역할

Node 구성요소

node는 kubeletkube-proxy가 주요하다. 그리고 컨테이너 런타임도 있다.

  • kubelet

kubelete은 컨테이너가 pod에서 확실하게 동작하도록 관리한다.

  • kube-proxy

노드로 들어오는 트래픽을 라우팅, 로드밸런싱 한다. 노드와 마스터간 네트워크 통신 관리

이것들이 docker로 떠있음

쿠버네티스 명령어


상태 설정

kubectl apply -f 파일명

-f을 통해서 yaml 파일과 함께 사용한다.

목록 조회

kubectl get 타입

예시로 아래처럼

kubectl get pod

# 단축
kubectl get pods
kubectl get po

# 여러 개
kubectl get po,service
kubectl get po,svc

# pod, replicaset, deployment, job 모두 조회
kubectl get all

# 결과 포맷
kubectl get pod -o wide
kubectl get pod -o yaml
kubectl get pod -o json

# label 조회
kubectl get pod --show-labels

리스트 상태 보기

쿠버네티스 리소스의 상세한 상태 확인

kubectl describe 타입/이름 or 타입 이름
  • 예시
# pod로 이름 보고
kubectl get pod
# 자세한 정보 검색
kubectl describe pod/spring-abcd-1234

리소스 제거

kubectl delete 타입/이름 or 타입 이름
  • 예시
# pod로 이름 보고
kubectl get pod
# 제거
kubectl delete pod/spring-abcd-1234

# or 파일로 제거
kubectl delete -f pod.yaml

# 전체 삭제
kubectl delete all --all

로그 조회

kubectl logs POD이름
  • 예시
kubectl get pod

kubectl logs springboot-1234-1234

# 실시간 확인
kubectl logs -f springboot-1234-1234

명령어 전달

shell 접속하여 상태확인은 -it를 사용한다

kubectl exec [-it] POD이름 -- 명령어
  • 예시
kubectl get pod
kubectl exec -it springboot-1234-asdf -- bin/bash

설정 관리

현재 어떤 컨텍스트로 설정되어 있는지 확인하고 원하는 컨텍스트 지정

# 현재 컨텍스트 확인
kubectl config current-context
# 컨텍스트 설정
kubectl config use-context minikube

쿠버네티스 객체


모든 객체 정보는 etcd에 저장되고 yaml이나 json으로 관리된다.

pod : 가장 작은 배포 단위
deployment : pod의 replicaset을 생성하고 관리
service: pod에 대한 네트워크 엔드포인트 노출
volume: 데이터 저장하기 위한 디렉토리 또는 트리
namespace: 쿠버네티스 클러스터 내 가상 클러스터 생성
statefulset: 디스크 상태가 있는 앱 배포&관리
daemonSet : 모든 노드에서 실행되는 pod 배포&관리
job: 일시적인 작업 실행하고 완료까지 대기

pod

pod는 한개 또는 여러 컨테이너를 포함하고 있다. 즉 클러스터 안에 pod 그리고 pod안에 컨테이너가 있다.

  • 생성
kubectl run boot-kube --image bmsvega2k/springboot-kube:0.1

예시로 위처럼 pod 생성

  • yaml파일로 작성
apiVersion: v1
kind: Pod
metadata:
name: boot-kube
labels:
app: boot-kube
spec:
containers:
- name: bootapp
image: bmsvega2k/springboot-kube:0.1

version은 버전이고 kind는 종류, metadata에는 name과 label이 있고 spec은 상세 명세다.

지금은 컨테이너에대한 정보가 담겨있음.

yaml파일로는 아래처럼 pod 생성함.

kubectl apply -f ./k8s/boot-kube-pod.yml

ReplicaSet

pod를 단독으로 만들면 문제가 생겼을 때 복구 되지 않아서 pod를 정해진 수만큼 복제하고 관리

  • yaml 파일
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: boot-kube-rs
spec:
replicas: 1
selector:
matchLabels:
app: boot-kube
tier: app
template:
metadata:
labels:
app: boot-kube
tier: app
spec:
containers:
- name: boot-kube
image: bmsvega2k/springboot-kube:0.1

label을 체크해서 원하는 수의 pod가 없으면 새 pod를 생성한다고 한다.

spec.selector: label 체크 조건
spec.replicas: 원하는 pod 수
spec.template: pod 명세

  • 생성
kubectl apply -f ./k8s/boot-kube-rs.yml
  • 확인
kubectl get po,rs
  • 레이블 확인
kubectl get pod --show-labels
  • app- 로 app label 제거
kubectl label pod/boot-kube-rs-z48lp app-
  • app label 추가
kubectl label pod/boot-kube-rs-z48lp app=boot-kube

app label을 지우면 새로 pod를 하나 띄우고 다시 추가하면 띄었던거 내린다.

apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: boot-kube-rs
spec:
replicas: 4
selector:
matchLabels:
app: boot-kube
tier: app
template:
metadata:
labels:
app: boot-kube
tier: app
spec:
containers:
- name: boot-kube
image: bmsvega2k/springboot-kube:0.1

scale up도 할 수 있다.

Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
name: boot-kube-deploy
spec:
replicas: 4
selector:
matchLabels:
app: boot-kube
tier: app
template:
metadata:
labels:
app: boot-kube
tier: app
spec:
containers:
- name: boot-kube
image: bmsvega2k/springboot-kube:0.1

위처러 yaml 작성

apply -f 하고 ... 등ㅇ...

apiVersion: apps/v1
kind: Deployment
metadata:
name: boot-kube-deploy
spec:
replicas: 4
selector:
matchLabels:
app: boot-kube
tier: app
template:
metadata:
labels:
app: boot-kube
tier: app
spec:
containers:
- name: boot-kube
image: bmsvega2k/springboot-kube:0.2

이렇게 이미지 태그 변경하고 하면 pod 업데이트 된다.

debployment는 update를 위해서 사용하는 것이다.

yaml파일 없이도 아래처럼 할 수도 있다.

kubectl set image deployment/이미지 boot-kube=업데이트_이미지
  • 변경사항 확인
kubectl rollout history deploy
kubectl rollout history deploy --revision=1
  • 수동 deployment
kubectl set image deployment/boot-kube-deploy boot-kube=bmsvega2k/springboot-kube:0.3

Service

서비스가 pod와 통신한다.

  • db 서비스 yaml 예시
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
spec:
selector:
matchLabels:
app: mysql
tier: db
template:
metadata:
labels:
app: mysql
tier: db
spec:
containers:
- name: mysql
image: mariadb:10.4.16
env:
- name: MYSQL_ROOT_PASSWORD
value: maria
- name: MYSQL_DATABASE
value: boot_db
ports:
- containerPort: 3306
protocol: TCP

---
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
protocol: TCP
selector:
app: mysql
tier: db

한 파일 안에 deployment와 service가 들어가있다.

생성하려면 apply -f 하면 된다.

kubectl exec -it pod/이미지이름 -- bin/bash

이렇게 하면 pod에 들어갈 수 있고 vscode에서 plugin을 사용해서도 들어갈 수 있다.

  • spring boot service
docker build -t bmsvega2k/springboot-crud-k8s:0.1 .

spring boot를 도커 이미지로 만들고 진행

apiVersion: apps/v1
kind: Deployment
metadata:
name: boot-crud
spec:
selector:
matchLabels:
app: boot-crud
tier: app
template:
metadata:
labels:
app: boot-crud
tier: app
spec:
containers:
- name: boot-crud
image: bmsvega2k/springboot-crud-k8s:0.1
ports:
- containerPort: 8080
env:
- name: DB_HOST
value: "mysql"
- name: DB_NAME
value: "boot_db"
- name: DB_USERNAME
value: "root"
- name: DB_PASSWORD # Setting Database password from Secret
value: "maria"

중요한 부분은 여기 선언한 spec.containers.env 값들은 application.yml에서 활용될 수 있다.

db 들어가서 보면 다 잘 나옴


서비스는 Endpoint controller가 서비스와 pod를 감시하고 pod의 ip 수집한다. 그렇게 endpoint 생성된다.

kubectl get endpoints

하면 endpoint를 확인할 수 있다.

kubectl describe ep/엔드포인트이름

로 자세히 볼 수 있다.

kube-proxy는 endpoint 변화 감시하고 iptable 설정하고 core dns는 service 감시해서 서비스 이름과 ip를 core dns에 추가한다.

  • node port 생성

서비스의 기본 타입은 ClusterIP이다.

외부 접근을 하려면 NodePort로 만들어야 한다. port는 30000~40000을 사용한다.

apiVersion: v1
kind: Service
metadata:
name: boot-crud-np
spec:
type: NodePort
ports:
- port: 8080
protocol: TCP
targetPort: 8080
selector:
app: boot-crud
tier: app

위 yaml파일 처럼 type을 NodePort로 줘야한다.

minikube service boot-crud-np --url

이렇게 하면 url 나오는걸로 간단하게 해볼 수 있다 이후는 로드밸런서를 활용해서 해야함.

  • 로드밸런스

NodePort 단점은 노드가 사라지면 자동으로 다른 노드 접근이 어려움

그래서 로드밸런서가 필요함. 브라우저는 NodePort에 보내느게 아닌 Load Balancer에 보내서 일관성 유지 가능

apiVersion: v1
kind: Service
metadata:
name: boot-crud-lb
spec:
type: LoadBalancer
ports:
- port: 8080
protocol: TCP
targetPort: 8080
selector:
app: boot-crud
tier: app

근데 미니 쿠베는 원래 로드밸런서 못 만드는데 metalib을 사용해서 만들 수 있다.

metalib

근데 패스

ConfigMap과 Secrets

민감정보들을 하드코딩 하지 않고 사용하는 방법

vault라는 솔루션도 있다.

apiVersion: v1
kind: ConfigMap
metadata:
name: db-config
data:
host: mysql
dbName: boot_db

config Map은 이렇게 사용할 수 있다.

kubectl get cm

확인은 이렇게 가능

비슷한데 데이터를 Base64로 저장하는 Secrets도 있다.

apiVersion: v1
kind: Secret
metadata:
name: mysql-secrets
data:
username: cm9vdA==
password: bWFyaWE=

이런식이다. 확인은 아래처럼

kubectl get secret

그래서 deployment로 사용하면 아래와 같음.

apiVersion: apps/v1
kind: Deployment
metadata:
name: boot-crud
spec:
selector:
matchLabels:
app: boot-crud
tier: app
template:
metadata:
labels:
app: boot-crud
tier: app
spec:
containers:
- name: boot-crud
image: bmsvega2k/springboot-crud-k8s:0.1
ports:
- containerPort: 8080
env:
- name: DB_HOST
valueFrom :
configMapKeyRef :
name : db-config
key : host
- name: DB_NAME
valueFrom :
configMapKeyRef :
name : db-config
key : dbName
- name: DB_USERNAME
valueFrom :
secretKeyRef :
name : mysql-secrets
key : username
- name: DB_PASSWORD
valueFrom :
secretKeyRef :
name : mysql-secrets
key : password

config map의 값은 configMapKeyRef이고 secrets은 secretKeyRef로 사용한다.

minikube


dashboard

minikube dashboard

대시보드를 볼 수 있다.

삭제

minikube delete

gke


gke url

위에 들어가서 사용할 수 있음.

클러스터 생성

잘 생성하면된다.

google cloud cli 설치

gcloud cli url

gke-gcloud-auth-plugin 설치

yaml 파일 들

  • config map
apiVersion: v1
kind: ConfigMap
metadata:
name: bookmarker-config
data:
postgres_host: postgres-svc
postgres_port: "5432"
postgres_dbname: appdb
---
apiVersion: v1
kind: Secret
metadata:
name: bookmarker-secrets
type: Opaque
data:
postgres_username: cG9zdGdyZXM=
postgres_password: cG9zdGdyZXM=
kubectl apply -f 1-config.yaml
kubectl get secrets
kubectl get configmap
  • db
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres-deployment
spec:
selector:
matchLabels:
app: postgres-pod
template:
metadata:
labels:
app: postgres-pod
spec:
containers:
- name: postgres
image: "postgres:14-alpine"
ports:
- name: postgres
containerPort: 5432
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: bookmarker-secrets
key: postgres_username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: bookmarker-secrets
key: postgres_password
- name: POSTGRES_DB
valueFrom:
configMapKeyRef:
name: bookmarker-config
key: postgres_dbname
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
---
apiVersion: v1
kind: Service
metadata:
name: postgres-svc
labels:
app: postgres
spec:
type: ClusterIP
selector:
app: postgres-pod
ports:
- port: 5432
targetPort: 5432
kubectl apply -f 2-postgres-db.yaml
kubectl get deploy,svc,pod
kubectl exec -it pod/postgres-deployment-74cbc9c598-m7zjm bin/bash
  • backend
apiVersion: v1
kind: Service
metadata:
name: bookmarker-api-svc
spec:
type: NodePort
selector:
app: bookmarker-api-pod
ports:
- name: app-port-mapping
protocol: TCP
port: 8080
targetPort: 8080
nodePort: 30090
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: bookmarker-api-deployment
spec:
replicas: 1
selector:
matchLabels:
app: bookmarker-api-pod
template:
metadata:
labels:
app: bookmarker-api-pod
spec:
containers:
- name: bookmarker
image: bmsvega2k/springbootnextjs:1.1
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: prod
- name: DB_HOST
valueFrom:
configMapKeyRef:
key: postgres_host
name: bookmarker-config
- name: DB_PORT
valueFrom:
configMapKeyRef:
key: postgres_port
name: bookmarker-config
- name: DB_DATABASE
valueFrom:
configMapKeyRef:
key: postgres_dbname
name: bookmarker-config
- name: DB_USERNAME
valueFrom:
secretKeyRef:
key: postgres_username
name: bookmarker-secrets
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
key: postgres_password
name: bookmarker-secrets
kubectl apply -f 3-bookmarker-api.yaml
kubectl get deploy,svc
kubectl get pod
kubectl logs bookmarker-api-deployment-97f597cb5-rkmjw
kubectl exec -it postgres-deployment-74768df574-mtsh9 /bin/bash

psql -U postgres -W
\c appdb postgres
\dt
kubectl get service
kubectl get nodes -o wide

external ip가 배포 ip

  • backend load balance
apiVersion: v1
kind: Service
metadata:
name: bookmarker-api-svc
spec:
type: LoadBalancer
# type: NodePort
selector:
app: bookmarker-api-pod
ports:
- name: app-port-mapping
protocol: TCP
port: 8080
targetPort: 8080
nodePort: 30090

타입을 LoadBalancer로만 바꾸면 된다.

kubectl apply -f 3-bookmarker-api.yaml

kubectl get svc,deploy,pod

external-ip가 url

  • front
apiVersion: v1
kind: Service
metadata:
name: bookmarker-ui-svc
spec:
# type: LoadBalancer
type: NodePort
selector:
app: bookmarker-ui-pod
ports:
- name: app-port-mapping
protocol: TCP
port: 3000
targetPort: 3000
nodePort: 30080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: bookmarker-ui-deployment
spec:
replicas: 1
selector:
matchLabels:
app: bookmarker-ui-pod
template:
metadata:
labels:
app: bookmarker-ui-pod
spec:
containers:
- name: bookmarker-ui
image: bmsvega2k/springboonextjs:client0.2
ports:
- containerPort: 3000
env:
- name: NEXT_PUBLIC_CLIENT_API_BASE_URL
value: http://localhost:18080
- name: NEXT_PUBLIC_SERVER_API_BASE_URL
value: http://bookmarker-api-svc:8080

kubectl apply -f 4-bookmarker-ui.yaml
kubectl get svc,deploy,pod
kubectl get nodes -o wide

external-ip에 url

  • front load balance
apiVersion: v1
kind: Service
metadata:
name: bookmarker-ui-svc
spec:
type: LoadBalancer
# type: NodePort
selector:
app: bookmarker-ui-pod
ports:
- name: app-port-mapping
protocol: TCP
port: 3000
targetPort: 3000
nodePort: 30080
kubectl apply -f 4-bookmarker-ui.yaml
kubectl get svc,deploy,pod

external-ip가 배포 url