최근에 진행하는 스터디도 없고 스스로 공부에 대한 목마름이 있던 찰나...! Google Study Jam 이라는 걸 발견하게 되었다. 구글에서 제공하는 스터디 플랫폼인 퀵랩을 활용해서 하나의 퀘스트를 완수하면 되는 프로젝트였고 이번 주제는 쿠버네티스 입문편이었다! 마침 회사에서도 쿠버네티스를 사용하고 있기 때문에 공부가 필요하기도 해서 너무 좋은 기회라고 생각했다.
개인으로 참여하거나 그룹으로 참여가 가능했고 나는 다같이 동기 부여도 하고 질문도 할 겸 대학교 동기들을 불러 모았다!무려 수료 기념품도 있어서 더 열심히 열정을 불태울 수 있었다.🔥 (수료한 대학교 동기들과 함께 이 모자 쓰고 인생 네컷 찍으러 가는 게 목표였다!)
대학 동기들과 이 과정을 관리하기 위한 노션 페이지도 만들었는데 언제나 그렇듯... 첫 1주차에는 관리가 잘 됐지만 그 이후로는 관리가 안 되어서 마지막 주에 다같이 몰아서 들었다...🥲 그래도 다들 수료 뱃지를 받았다는 거에 의의를 두기로 했다.
학습 내용에 대한 후기를 말하자면 일단 나에게 딱 알맞은 난이도라고 생각했다. 나는 쿠버네티스를 제대로 공부한 적은 없지만 회사에서 이미 사용중이기 때문에 어떤 상황때문에 필요하고 어떤 파일들이 어떤 역할을 하는지 대략적으로만 파악하고 있었다. (나의 추측..) 하지만 이번 기회에 확실히 쿠버네티스의 역할과 각 구성 요소들의 역할을 파악하면서 개념을 확립할 수 있어서 좋았다. 특히 회사에서 사용하고 있으면서도 정확히 이해가 되지 않아서 의문을 가지고 있었던 canary 배포에 대한 부분이나 deploy, service 의 차이에 대해서도 명확하게 정리를 해주어서 매우 만족스럽다.😸 내용도 그렇게 길지 않고 하나의 Lab에 대략 1시간정도 소요되어서 다음에도 Google Study Jam이 열린다면 참여할 의향이 매우 있다!
로컬(pwd)에 app.js 라는 애플리케이션 파일이 있다고 가정
# Dockerfile 이용해서 node:lts 이미지 실행하는데
FROM node:lts
# 컨테이너 안에서 working directory를 /app으로 설정하고
WORKDIR /app
# 로컬 파일들을 컨테이너의 /app 으로 복사한 다음에
ADD . /app
# 80번 포트를 외부에 공개해서
EXPOSE 80
# 어플리케이션 실행
CMD ["node", "app.js"]
# 위의 Dockerfile 이용해서 이미지 생성
docker build -t node-app:0.1 .
# my-app 이라는 이미지 이름으로 4000번 포트와 컨테이너의 80번 포트 포워딩 후 이미지 run
# 로컬에서 접속 시 4000번 포트로 접근해야 함
docker run -p 4000:80 --name my-app node-app:0.1
# 컨테이너의 working directory 에 접근
docker exec -it [container_id] bash
# 컨테이너 메타 데이터 확인
docker inspect [container_id]
# gcloud에서 클러스터 생성
gcloud container clusters create --machine-type=e2-medium --zone=assigned_at_lab_start lab-cluster
쿠버네티스를 이용해서 클러스터의 리소스를 관리할 수 있다.
deployment
: web 서버와 같은 stateless한 배포를 가능하게 함service
: 인터넷을 통해 어플리케이션에 접속할 때 rule이나 load balancing을 설정# hello-app:1.0 이미지 이용해서 deployment 생성
kubectl create deployment hello-server --image=gcr.io/google-samples/hello-app:1.0
# 외부로 노출할 포트와 LoadBalancer 설정해서 service 생성
kubectl expose deployment hello-server --type=LoadBalancer --port 8080
# hello-server 의 EXTERNAL-IP 확인 후 curl로 외부 접속 가능
kubectl get service
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: monolith
labels:
app: monolith
spec:
containers:
# monolith 라는 이름의 1개의 컨테이너로만 구성된 pod 이므로 모놀리식 구성
- name: monolith
image: kelseyhightower/monolith:1.0.0
args:
# 컨테이너가 시작할 때 전달되는 인수
- "-http=0.0.0.0:80"
- "-health=0.0.0.0:81"
- "-secret=secret"
ports:
# http 트래픽용 포트 80 개방
- name: http
containerPort: 80
- name: health
containerPort: 81
resources:
limits:
cpu: 0.2
memory: "10Mi"
# port forwarding
kubectl port-forward monolith 10080:80
# 로그 보기
kubectl logs monolith
# 실시간 로그 보기
kubectl logs -f monolith
# 대화형 shell 실행 후 ping 테스트
kubectl exec monolith --stdin --tty -c monolith /bin/sh
ping -c 3 google.com
엔드 포인트
가 필요# service.yaml
kind: Service
apiVersion: v1
metadata:
name: "monolith"
spec:
selector:
app: "monolith"
# secure: "enabled"가 있는 라벨이 지정된 pod를 찾아 노출
secure: "enabled"
ports:
# 외부의 31000 포트를 pod의 443 포트로 전달
- protocol: "TCP"
port: 443
targetPort: 443
nodePort: 31000
# NodePort 타입을 사용하여 외부에 IP 노출
type: NodePort
# pod에 secure=enabled 라벨 추가 후 확인
kubectl label pods secure-monolith 'secure=enabled'
kubectl get pods secure-monolith --show-labels
# 엔드포인트 확인 후 curl 명령으로 접속
kubectl describe services monolith | grep Endpoints
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: auth
spec:
selector:
matchlabels:
app: auth
# replica 본 1개
replicas: 1
template:
metadata:
labels:
app: auth
track: stable
spec:
containers:
- name: auth
image: "kelseyhightower/auth:2.0.0"
ports:
- name: http
containerPort: 80
- name: health
containerPort: 81
...
# replica 개수 설정
kubectl scale deployment hello --replicas=5
# deployment 파일 수정 후 저정하면 배포 시작됨
# 배포 history 확인
kubectl rollout history deployment/hello
# 배포 중지
kubectl rollout pause deployment/hello
# 배포 상태 확인
kubectl rollout status deployment/hello
# 배포 재개
kubectl rollout resume deployment/hello
# 배포 롤백 후 위의 history 명령어로 확인
kubectl rollout undo deployment/hello
Canary로 작은 규모의 일부 사용자에게만 변경 사항을 릴리즈하여 테스트한 후에 전체 배포를 진행하는 형식
# canary-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-canary
spec:
replicas: 1
selector:
matchLabels:
app: hello
template:
metadata:
labels:
app: hello
track: canary
# 2.0.0 버전을 사용하여 서비스 선택기의 버전과 일치시킵니다
version: 2.0.0
spec:
containers:
- name: hello
image: kelseyhightower/hello:2.0.0
ports:
- name: http
containerPort: 80
- name: health
containerPort: 81
이 때 한번 canary pod에 접속한 사용자는 계속 canary pod에 접속해야 변경 사항이 일관성 있게 적용되므로 이를 위해서 service 파일에 sessionAffinity 필드를 이용한다.
canary-service.yaml
kind: Service
apiVersion: v1
metadata:
name: "hello"
spec:
# 동일한 사용자에게 항상 동일한 버전을 제공하게 해줌
sessionAffinity: ClientIP
selector:
app: "hello"
ports:
- protocol: "TCP"
port: 80
targetPort: 80
최소한의 다운 타임을 위해서 배포를 모두 완료한 후에 부하 분산기를 수정하여 새 버전을 가리키도록 하는 배포. 큰 단점은 이를 사용하려면 클러스터에 최소 2배의 리소스가 필요하다는 것이다.
이 때는 blue용 deploy yaml 파일, green용 yaml 파일을 만들고
green용 yaml 파일을 수정하여 배포가 완료되면 서비스가 새 버전인 green을 가리키도록 한다.
# 배포가 완료된 green 서비스를 가리키도록 수정
kubectl apply -f services/hello-green.yaml
젠킨스를 이용한 CI/CD 환경을 구축하는 과정에 대한 장이었다. 이 부분은 git 저장소를 클러스터 위에 띄운 젠킨스와 연결하여 파이프라인 생성하여 master 브랜치에 push가 일어날 경우 배포가 발생하게 했다.