
k8s에 어플리케이션 띄워보는 방식으로 가면서 리소스에 대해 좀 더 세세하게 알아보는 과정 거쳐볼 예정.
그 이후엔 실제 ci/cd는 보통 어떻게 하는지만 정리할 것이다.
orbstack v 1.7.5

Orbstack은 MacOS에서 Docker 컨테이너, 쿠버네티스, 각종 Linux 배포본을 빠르고 간편하게 실행하는 Docker Desktop 대체제다
유명한 docker desktop 대신 왜 orbstack을 쓰냐? 이제 다 알겠지만... docker desktop은 유료화가 됐고... 회사에서 쓰다보니 익숙해졌고... CPU랑 메모리 사용량이 도커 데스크탑보다 낮음. 그리고 도커 데스크탑의 기능을 대부분 대체할 수 있다보니 사용하게 됐다.
차이점이나 장점 등 자세한 내용은 아래 링크를 참고하면 좋겠네..
https://jonnung.dev/docker/2023/11/20/orbstack-alternative-docker-desktop/
어쨌든,
orbstack에서 가벼운 싱글 노드 쿠버네티스 클러스터를 띄우는 걸 지원해주기 때문에 메뉴에서 kubernetes를 눌러 turn on 해주면 위의 캡쳐처럼 돌아감. (나는 이미 띄워놔서 캡처는 생략 함)
docker ps
쿠버네티스가 올라간 것을 확인할 수 있음

테스트로 이미 orbstack에서 알려주는 example 명령어를 사용해보자.
kubectl run nginx --image=nginx
kubectl expose pod nginx --type=NodePort --port=80
를 입력하면
nginx 이미지로 된 pod가 생성되고, service 는 Nodeport로 설정해서 port를 통해 외부에서 접근할 수 있도록 설정해 줌.
지금 pod와 service를 말했는데 이젠 게시물에서 언급한 리소스임.
그러면


다음과 같이 orbstak에서 확인할 수 있음. port는 80 -> 32700으로 설정됐으므로
localhost:37200으로 들어가보면

다음과 같이 쿠버네티스로 띄운 nginx에 NortPort설정을 통해 접근할 수 있다.
신기하죵?
그럼 실제 어플리케이션을 올려보겠다.
이 때 kubectl로 리소스 매니패스트 파일을 사용하여 pod를 올려보려고 한다.
서비스는 총 2가지이고, spring boot로 정말 간단하게 만든 서버 2대를 올릴 예정이다.
애플리케이션 간단 소개
공통
- java 21
- spring boot 3.3.4
- maven

띄울 애플리케이션이 있어야 하는데... 막상 올릴 서비스는 없어서 k8s에 올려서 테스트 해볼 정도의 서비스 2개를 만들었다.
🎧 kwangya-service ( 그 에스파 광야 맞다 .. )
👩👩👧👧 🖤 aespa-service ( 그 에스파가 맞다 .. )
로 정말 대~충 통신만 우선 할 수 있게 간단한 REST API 서버를 만들어놨다.
이제
k8s에서 이 서비스들이 어떻게 통신할 거냐면

이런 식으로
1. 외부에서 kwangya-service 와 aespa-service 를 둘 다 각각 호출할 수 있도록
2. 외부에서 kwangya-service를 호출하면 kwangya-service 내부에서 aespa-service를 호출할 수 있도록
처리해볼 예정이다.
mvn clean compile package -Dmaven.test.skip=true
2.각 서비스에 dockerfile 생성
FROM openjdk:17-ea-11-jdk-slim
VOLUME /tmp
COPY target/{패키징된 jar 파일} app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
target 폴더를 들어가보면 패키징된 jar 파일을 확인할 수 있음. 그 파일의 이름을 넣어주면 된다.
(kwangya-service-0.0.1-SNAPSHOT.ja | aespa-service-0.0.1-SNAPSHOT.jar)
잘 실행되는지 알고 싶으면 java -jar kwangya-service-0.0.1-SNAPSHOT.jar 로 띄워보면 됨.
docker build --tag kwanya-service:1.0 .
docker build --tag aespa-service:1.0 .

그럼 각자 이런식으로 도커 이미지가 만들어진다.

그럼 이제 k8에 올리기 위한 준비를 한다.
필요 리소스 매니패스트 파일
쿠버네티스 공식 문서에서 설명하는 deployment
디플로이먼트(Deployment) 는 파드와 레플리카셋(ReplicaSet)에 대한 선언적 업데이트를 제공한다.
디플로이먼트에서 의도하는 상태 를 설명하고, 디플로이먼트 컨트롤러(Controller)는 현재 상태에서 의도하는 상태로 비율을 조정하며 변경한다. 새 레플리카셋을 생성하는 디플로이먼트를 정의하거나 기존 디플로이먼트를 제거하고, 모든 리소스를 새 디플로이먼트에 적용할 수 있다.
https://kubernetes.io/ko/docs/concepts/workloads/controllers/deployment/
kangya-deployment.yaml
apiVersion: apps/v1
kind: Deployment # 리소스 종류 - deployment
metadata:
name: kwangya-deployment # deployment 이름
spec:
selector: # 파드 생성 spe
matchLabels:
app: kwangya-service-app
replicas: 1 # 복제 수
template:
metadata:
labels:
app: kwangya-service-app # 파드 레벨 = selector 이름과 동일
spec:
containers:
- name: kwangya-service # 컨테이너 이름
image: kwangya-service:1.0 # 컨테이너 이미지
imagePullPolicy: Always # 이미지 항상 pull 함
ports:
- containerPort: 8090 # 컨테이너가 사용하는 포트
protocol: TCP # TCP 통신
resources:
requests:
cpu: 500m # 컨테이너에서 요청하는 CPU
memory: 1000Mi # 컨테이너에서 요청하는 메모리
env:
- name: AESPA-SERVICE-URL # 환경 변수 이름
valueFrom:
configMapKeyRef:
name: kwangya-configmap # 참조하는 configmap 이름
key: aespa-service-url # configmap에서 가져올 키
---
apiVersion: v1
kind: Service # 리소스 종류 - service
metadata:
name: kwangya-service # service 이름
spec:
type: NodePort # 외부에서 접근 가능하게 함
selector:
app: kwangya-service-app
ports:
- protocol: TCP
port: 8090 # 서비스에서 사용할 포트
targetPort: 8090 # 파드에서 사용하는 포트
nodePort: 30000 # 외부에서 접근할 수 있도록 하는 포트
kwangya-service 와 비슷하지만, 우선 환경변수 설정 따로 안함.
그리고 포트가 다름 8091, 30001
aespa-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: aespa-deployment
spec:
selector:
matchLabels:
app: aespa-service-app
replicas: 1
template:
metadata:
labels:
app: aespa-service-app
spec:
containers:
- name: aespa-service
image: aespa-service:k8s_v1.0
imagePullPolicy: Always
ports:
- containerPort: 8091
protocol: TCP
resources:
requests:
cpu: 500m
memory: 1000Mi
---
apiVersion: v1
kind: Service
metadata:
name: aespa-service
spec:
type: NodePort
selector:
app: aespa-service-app
ports:
- protocol: TCP
port: 8091
targetPort: 8091
nodePort: 30001
여기서 중요한 건 service 리소스인데,
kwangya-service 8090은 k8s 내부에서 사용하는 포트이고, nodeport의 30000은 k8s 외부에서 서비스를 호출할 때 사용하는 포트이다.
ports:
- protocol: TCP
port: 8090
targetPort: 8090
nodePort: 30000
aespa-service 도 똑같이 8091은 k8s 내부에서 사용하는 포트이고, nodeport의 30001은 k8s 외부에서 서비스를 호출할 때 사용하는 포트이다.
ports:
- protocol: TCP
port: 8091
targetPort: 8091
nodePort: 30001
쿠버네티스 공식 문서에서 설명하는 configmap
configmap은 키-값 쌍으로 기밀이 아닌 데이터를 저장하는 데 사용하는 API 오브젝트이다. 파드는 볼륨에서 환경 변수, 커맨드-라인 인수 또는 구성 파일로 configmap을 사용할 수 있다.
configmap을 사용하면 컨테이너 이미지에서 환경별 구성을 분리하여, 애플리케이션을 쉽게 이식할 수 있다.즉, 환경 변수, 커맨드-라인 인수 또는 구성파일을 설정할 수 있다.
https://kubernetes.io/ko/docs/concepts/configuration/configmap/
apiVersion: v1
kind: ConfigMap
metadata:
name: kwangya-configmap # kwangya-service 용이 아닌 전체 config로 사용할 수 있음.
data:
aespa-service-url: "http://aespa-service:8091"
⭐️ 중요한 내용
kwangya-service에서 aespa-service로 rest api를 호출할 때, kwangya-service는 aespa-service의 서버를 알아야 한다.그리고, k8s에서는 aespa-service 는 8091 번호로 port를 설정해놨다.
쿠버네티스 클러스터 안에서는 파드끼리 통신이 가능하기 때문에 30001으로 외부로 나가서 호출하는 게 아닌 "http://aespa-service:8091" 로 호출할 수 있도록 설정해놓는 작업을 한다.
kubectl apply -f configmap.ymlkubectl apply -f kwangya-deployment.ymlkubectl apply -f aespa-deployment.yml(이 때, kubectl도 설치해놔야 한다. 나는 맥이라서 brew install kubectl 로 설치 함.)
하지만 에러가 난다...
이유는 이미지를 이미지 레지스트리(docker hub 이나 프라이빗 레지스트리) 에 안올렸기 때문인데... dokcer hub에 올리기 싫어서(ㅋㅋㅋ) 노선을 틀어 minikube를 이용해서 쿠버네티스 클러스터 올릴 예정이다.
minikube는 로컬 환경에서 쿠버네티스 클러스터 쉽게 띄울 수 있는 도구.
Minikube를 사용하면 로컬 컴퓨터에서 단일 노드 Kubernetes 클러스터를 실행하여 애플리케이션 개발, 테스트 및 배포를 쉽게 할 수 있으며, 단일 머신에서 다중 노드 Kubernetes 환경을 시뮬레이션하여 다양한 Kubernetes 기능 및 구성을 실험할 수 있습니다.
https://www.itmaya.co.kr/wboard/view.php?wb=tech&idx=52
나는 mac이므로 brew를 이용해서 설치한다.
brew install minikube
이러면 간단하게 설치 완료
minikube start
minikube start # minikube 실행
kubectl cluster-info # minikube랑 연결 잘 됐는지 확인
minikube status # minikube 잘 떴는지 확인

로그를 보면 CPUs 2, memory=8100MB 인데 이건 옵션으로 변경할 수 있다. 보통 minikube는 local에서 테스트할 때 보통 사용하므로 필요에 따라 설정을 바꾸면 된다.
minikube dashboard : minikube를 대시보드로 보고 싶을 때 사용

그럼 자동으로 minikube addons enable metrics-server 가 애드온되면서 대시보드가 활성화된다.

로그에 있는 url 복사에서 브라우저 들어가면 됨.
+) 중지 / 삭제할 때는 아래와 같이 하면 된다.
minikube stop # minikube 중지
minikube delete # minikube 삭제
이제 minikube 쿠버네티스 클러스터가 만들어졌으니 다시 deployment와 configmap 실행.
이 때, 로컬에 있는 이미지를 사용해야 하므로 기존 이미지는 지우고 다시 빌드할 것이다.
configmap 실행
kubectl apply -f configmap.yml

대시보드에서 컨피그 맵 메뉴 들어가면 kwangya-configmap 생성 확인 가능.
eval $(minikube docker-env)
docker build --tag aespa-service:1.0 .
eval $(minikube docker-env)
docker build --tag kwangya-service:1.0 .
(...)
spec:
containers:
- name: kwangya-service
image: kwangya-service:1.0
imagePullPolicy: Never
ports:
- containerPort: 8090
protocol: TCP
(...)
Always를 Never로 변경
https://stackoverflow.com/questions/42564058/how-can-i-use-local-docker-images-with-minikube
kubectl apply -f kwangya-deployment.ymlkubectl apply -f aespa-deployment.yml

이렇게 하면 로컬 이미지를 pull해서 k8s에 생성된 파드를 확인할 수 있다~
명령어로 확인하려면
kubectl get pods

Running으로 정상적으로 실행 됨.

kubectl get services 로 서비스 설정 잘 되어있는지 확인한다.
minikube에 올라가있기 때문에 minikube url 확인
minikube ip

따라서,
앞서 얘기한
🎧 kwangya-service
- [GET] / : 서비스명 가져오기 (kwangya-service)
- [GET] /{group}/member : 특정 그룹의 모든 멤버 목록 가져오기
이 때, group으로 aespa를 넣어 호출하면 openfeign을 통해 aespa-servcie와 통신하여 모든 멤버 데이터를 가져올 수 있게 함.
👩👩👧👧 🖤 aespa-service
- [GET] /member : 에스파 모든 멤버 목록 가져오기
- [GET] /member/{id} : id로 에스파 멤버 가져오기
로 호출을 시도해본다.
curl --silent --location --request GET 'http://192.168.67.2:30000/'

외부에서 각각 서비스에 호출 성공
이 때, kwangya-service 를 거쳐 내부적으로 aespa-service를 호출하여 aespa 모든 멤버 목록을 가져오는 흐름이다.
그런데 안된다.... 하

원인 : configmap에 포트 잘못 설정했음. 하하


8091로 변경하고 다시 설정

pods 다 죽이고 다시 실행.

호출 완료 ~~~
이렇게 k8s위에 테스트 완성 ...
다음 게시물은 그럼 실제로는 어떻게 ci/cd 구성하는지 정리해 볼 예정이다.