전체 목차
- 쿠버네티스 클러스터 #1 Ubuntu OS 설치 및 설정
- 쿠버네티스 클러스터 #2 시스템 설정
- 쿠버네티스 클러스터 #3 쿠버네티스 설치 및 설정
- 쿠버네티스 클러스터 #4 로컬 Docker Disktop 설치 및 설정
- 쿠버네티스 클러스터 #5 Spring boot 어플리케이션 배포
- 쿠버네티스 클러스터 #6 node 및 pod 설정 점검
- 쿠버네티스 클러스터 #7 안전한 시작, 종료 스크립트
- 쿠버네티스 클러스터 #8 Spring boot 로그 확인
- 쿠버네티스 클러스터 #9 CI/CD 적용
이번 챕터에서는 간단한 Spring boot 어플리케이션을 작성하고 이전에 생성한 원격 쿠버네티스 환경에 배포해 보도록 하겠습니다.
(침고 : 맨 첫번째 챕터에서 언급한 대로 이 프로젝트에서는 마스터(제온, amd64)와 워커(라즈베리파이, arm64) 노드의 CPU 아키텍쳐가 다르기 때문에 빌드 스크립트가 조금더 복잡합니다.)
1. Hello Kebernetes Spring boot 프로젝트 생성
1.1. 프로젝트 기본 속성
일반적인 Spring boot 프로젝트를 생성합니다.
여기서는 Java 21, Gradle 프로젝트로 생성하였고
의존성은 spring-boot-starter-webmvc 만을 주입하였습니다.
implementation 'org.springframework.boot:spring-boot-starter-webmvc'org.springframework.boot:spring-boot-starter-webmvc
1.2. HelloController.java
현재 실행되는 Pod Name을 출력하는 간단한 소스입니다.
@RestController
public class HelloController {
@GetMapping("/")
public String hello() {
String podName = System.getenv("HOSTNAME");
if (podName == null || podName.isEmpty()) {
try {
podName = java.net.InetAddress.getLocalHost().getHostName();
} catch (java.net.UnknownHostException e) {
podName = "unknown";
}
}
return "Hello from Spring Boot on Hybrid K8s!!! (Running on " + podName + ")";
}
}
1.3. deployment.yaml
프로젝트 최상위에 deployment.yaml 를 생성합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-kubernetes-api
spec:
replicas: 1
selector:
matchLabels:
app: hello-kubernetes-api
template:
metadata:
labels:
app: hello-kubernetes-api
spec:
containers:
- name: hello-kubernetes-api
image: basscraft/hello-kubernetes-api:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: hello-kubernetes-api-service
spec:
selector:
app: hello-kubernetes-api
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: NodePort
1.4. 프로잭트 구조

1.5. 로컬 실행 화면 확인
에러 없이 정상적으로 실행 되면 브라우저에서 http://localhost:8080 으로 접속시 아래와 같은 화면이 나와야 합니다.

2. 빌드
일반적인 경우 (동일한 플랫폼) 아래와 같이 빌드 하고 나서 PUSH를 하면 됩니다.
$ docker build -t <Docker Hub 계정>/hello-kubernetes-api:latest .
현재 로컬 환경의 CPU 아키텍처로 빌드 됩니다.
$ docker push <Docker Hub 계정>/hello-kubernetes-api:latest
빌드된 이미지를 도커 허브로 전송합니다.
여기서는 Master (Xeon/amd64), Worker node (라즈베리파이 / arm64)로 서로 상이합니다.
Java의 경우 JVM에서 실행되기 때문에 플랫폼 독립적이지만 그래도 다른 아키텍처를 지정해서 빌드하는 것을 해보겠습니다.
PS C:\Users\user\Projects\k8sTest\HelloKubernates\api\HelloKubernetesApi> docker buildx build --platform linux/amd64,linux/arm64 -t basscraft/hello-kubernetes-api:latest --push .
buildx 엔진을 사용해서 멀티 아키텍처를 지원하도록 합니다.
--platform linux/amd64,linux/arm64 : 마스터와 워커의 바이너리를 플랫폼별로 각각 빌드합니다.
-t <Docker Hub 계정>/hello-kubernetes-api:latest : 저장될 도커 계정에 앱 이름을 태깅합니다.
--push : 멀티 아키텍처 이미지는 Docker 엔진에 한번에 담을 수가 없기 때문에 빌드와 동시에 push를 해야 합니다.
이렇게 빌드 하면 마스터노드(Xeon)가 이미지를 다운로드 하면 amd64 버전을, 워커노드(라즈베리파이)가 이미지를 다운로드 하면 arm64로 인식하여 자동으로 선택 다운드 됩니다.
3. 배포
3.1. 컨텍스트 확인
프로젝트 디렉토리에서 현재 선택된 컨텍스트를 확인합니다.
(배포하려는 타겟과 맞지 않으면 변경합니다.)
PS C:\Users\user\Projects\k8sTest\HelloKubernates\api\HelloKubernetesApi> kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* docker-desktop docker-desktop docker-desktop
kubernetes-admin@kubernetes kubernetes kubernetes-admin
PS C:\Users\user\Projects\k8sTest\HelloKubernates\api\HelloKubernetesApi> kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".
PS C:\Users\user\Projects\k8sTest\HelloKubernates\api\HelloKubernetesApi> kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
master Ready control-plane 45h v1.30.14 192.168.2.100 <none> Ubuntu 24.04.3 LTS 6.8.0-90-generic containerd://1.7.28
node1 Ready <none> 44h v1.30.14 192.168.2.101 <none> Ubuntu 24.04.3 LTS 6.8.0-1044-raspi containerd://1.7.28
node2 Ready <none> 44h v1.30.14 192.168.2.102 <none> Ubuntu 24.04.3 LTS 6.8.0-1044-raspi containerd://1.7.28
node3 Ready <none> 44h v1.30.14 192.168.2.103 <none> Ubuntu 24.04.3 LTS 6.8.0-1044-raspi containerd://1.7.28
PS C:\Users\user\Projects\k8sTest\HelloKubernates\api\HelloKubernetesApi>
3.2. 배포 deployment.yaml 적용
PS C:\Users\user\Projects\k8sTest\HelloKubernates\api\HelloKubernetesApi> kubectl apply -f deployment.yaml
deployment.apps/hello-kubernetes-api created
service/hello-kubernetes-api-service created
PS C:\Users\user\Projects\k8sTest\HelloKubernates\api\HelloKubernetesApi>
배포 상태 확인
PS C:\Users\user\Projects\k8sTest\HelloKubernates\api\HelloKubernetesApi> kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
hello-kubernetes-api-78dd74b6cd-l5pkn 0/1 ContainerCreating 0 2m33s <none> node3 <none> <none>
nginx-bf5d5cf98-bgn9c 1/1 Running 0 45h 10.244.1.3 node1 <none> <none>
PS C:\Users\user\Projects\k8sTest\HelloKubernates\api\HelloKubernetesApi>
배포후 즉시 확인해 보면 상태가 ContainerCreating 입니다.
1~2분 후에 확인해보면 Running 상태로 변경 됩니다.
PS C:\Users\user\Projects\k8sTest\HelloKubernates\api\HelloKubernetesApi> kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
hello-kubernetes-api-78dd74b6cd-l5pkn 1/1 Running 0 4m20s 10.244.2.3 node3 <none> <none>
nginx-bf5d5cf98-bgn9c 1/1 Running 0 45h 10.244.1.3 node1 <none> <none>
PS C:\Users\user\Projects\k8sTest\HelloKubernates\api\HelloKubernetesApi>
hello-kubernetes-api 애플리케이션이 정상 적으로 배포 되었습니다.
3.3. 서비스 포트 확인
어떤 포트에서 실행되는지 확인해야 합니다.
PS C:\Users\user\Projects\k8sTest\HelloKubernates\api\HelloKubernetesApi> kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-kubernetes-api-service NodePort 10.105.75.244 <none> 80:32311/TCP 9m33s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 46h
nginx NodePort 10.102.162.252 <none> 80:31098/TCP 45h
PS C:\Users\user\Projects\k8sTest\HelloKubernates\api\HelloKubernetesApi>
리스트 중 hello-kubernetes-api-service 항목의 PORT 에 80:32311 이 서비스 포트입니다.
브라우저에서 확인해 봅니다.
http://192.168.2.100:32311/
http://192.168.2.101:32311/
http://192.168.2.102:32311/
http://192.168.2.103:32311/

4. 서비스 안전한 종료
실제 서버의 경우 항상 켜놓기 때문에 매번 종료 할 필요가 없지만
환경상 안전을 위해(전력 사용, 서버 소음) 때문에 매번 서비스를 내리고 있습니다.
아래 순서를 지켜서 종료 하는 것을 권장합니다.
4.1. 워커 노드 격리 (마스터 노드에서 실행)
# 각 워커 노드에 대해 순차적으로 실행
$ kubectl drain node1 --ignore-daemonsets --delete-emptydir-data
$ kubectl drain node2 --ignore-daemonsets --delete-emptydir-data
$ kubectl drain node3 --ignore-daemonsets --delete-emptydir-data
node/node1 drained 라는 메시지가 나오면 정상 격리가 된 것입니다.
4.2. 워커노드 OS 종료 (각각 워커 노드에서 실행)
$ sudo shutdown -h now
4.3. 마트서 노드 OS 종료 (마스터 노드에서 실행)
마스터 노드는 etcd 같은 중요한 데이터베이스를 담고 있으므로, 반드시 워커노드 들이 모두 종료 된 후에 마지막으로 꺼야 합니다.
$ sudo shutdown -h now
끝.
'UNIX-Networking' 카테고리의 다른 글
| 쿠버네티스 클러스터 #7 안전한 시작, 종료 스크립트 (0) | 2026.01.20 |
|---|---|
| 쿠버네티스 클러스터 #6 node 및 pod 설정 점검 (0) | 2026.01.20 |
| 쿠버네티스 클러스터 #4 로컬 Docker Disktop 설치 및 설정 (1) | 2026.01.19 |
| 쿠버네티스 클러스터 #3 - 쿠버네티스 설치 및 설정 (0) | 2025.12.19 |
| 쿠버네티스 클러스터 #2 - 시스템 설정 (0) | 2025.12.18 |
