본문으로 건너뛰기

쿠버네티스 설치 (Helm)

PlantPulse 플랫폼을 쿠버네티스에서 운영하기 위한 Helm 차트가 있습니다.

아직 전체 스택이 검증되지 않았습니다

데이터레이크까지는 이 차트로 클린 설치해 확인했습니다(2026-09-09, 서비스 19/19, 특권 없음). 그러나 server · batch · warehouse · proxy 는 아직 실물로 재보지 않았습니다.

고객사 설치에는 원라인 설치 나 Docker 설치 를 쓰십시오.

무엇인가​

Docker Compose 구성을 쿠버네티스로 번역한 차트입니다. 대체한 것이 아닙니다.

정본은 여전히 compose 입니다. 둘이 어긋나면 compose 가 맞고 차트가 틀린 것입니다. 새 설정이 생기면 compose 에 먼저 들어가고 차트가 따라옵니다.

차트 위치plantpulse-platform-k8s 저장소의 charts/plantpulse-platform
이미지 레지스트리플랫폼은 docker.kopens.io/pp, 서드파티는 docker.kopens.io/proxy-dockerhub
실증 환경k3s v1.32.5+k3s1 · 단일 노드
다루는 compose 서비스10개 전부

시작하기 전에​

쿠버네티스 버전​

Oracle Linux 8.10 이면 k3s 는 v1.32 라인이어야 합니다

그 OS 는 cgroup v1 이고, k3s v1.36(쿠버네티스 1.36)은 cgroup v1 지원을 뺐습니다. 올리면 kubelet 이 이렇게 말하고 뜨지 않습니다.

kubelet is configured to not run on a host using cgroup v1

스토리지 — RWX 가 필요합니다​

TLS 자재를 담는 pp-security 볼륨에 여러 파드가 동시에 붙습니다. 그래서 ReadWriteMany 를 지원하는 프로비저너가 있어야 합니다 — NFS · CephFS · Longhorn RWX 등입니다.

k3s 기본 local-path 는 노드가 하나일 때만 동작합니다

local-path 는 RWO 이고 노드 로컬입니다. 단일 노드에서는 모든 파드가 그 노드에 앉으므로 동작하지만, 두 번째 노드가 붙는 날 조용히 깨집니다. 차트의 결함이 아니라 실제 제약이고, 고객사 설치 중에 발견하지 않도록 여기 적어 둡니다.

자원​

플랫폼 자원 요건은 쿠버네티스라고 줄지 않습니다. 시스템 요구사항 을 그대로 따릅니다 — 최소 16 vCPU · 128GB RAM · 1TB SSD 입니다.


클러스터가 없다면 — K3s → Rancher → Helm​

쿠버네티스를 이미 쓰고 계시면 이 절은 건너뛰고 설치로 가십시오. 없는 상태에서 시작한다면 K3s 로 클러스터를 만들고, Rancher 로 화면을 붙이고, 그 위에 PlantPulse 차트를 올리는 순서가 가장 짧습니다.

Rancher 는 우리 제품이 아닙니다

SUSE 의 오픈소스 쿠버네티스 관리 UI 입니다. 선택 사항이고, kubectl 만으로도 설치·운영이 전부 됩니다. 파드·로그·이벤트를 눈으로 보고 싶을 때 편해서 함께 적습니다.

1. K3s 설치​

한 대짜리 클러스터입니다. 설치 스크립트가 컨테이너 런타임 · kubelet · 기본 스토리지(local-path)까지 함께 올립니다.

# Oracle Linux 8.10 은 cgroup v1 이라 v1.32 라인을 고정합니다 (위 경고 참고)
curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.32.5+k3s1 sh -

sudo systemctl status k3s # active (running)
sudo k3s kubectl get nodes # STATUS = Ready

kubectl 을 일반 계정에서 쓰려면 kubeconfig 를 복사합니다.

mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown "$(id -u):$(id -g)" ~/.kube/config
kubectl get nodes
방화벽을 먼저 여십시오

K3s 는 6443(API) 을 씁니다. 다른 노드를 붙일 계획이면 노드 사이의 8472/udp(flannel VXLAN) · 10250(kubelet) 도 필요합니다. 플랫폼 자체가 쓰는 포트는 포트 구성에 있습니다.

2. Rancher 설치​

Rancher 는 인증서가 필요해 cert-manager 를 먼저 올립니다.

helm repo add rancher-stable https://releases.rancher.com/server-charts/stable
helm repo add jetstack https://charts.jetstack.io
helm repo update

# 1) cert-manager
helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --set crds.enabled=true

kubectl -n cert-manager rollout status deploy/cert-manager

# 2) Rancher — <호스트> 는 브라우저로 칠 주소입니다
helm install rancher rancher-stable/rancher --namespace cattle-system --create-namespace --set hostname=<호스트> --set bootstrapPassword=<초기비밀번호> --set replicas=1

kubectl -n cattle-system rollout status deploy/rancher

브라우저로 https://<호스트> 에 들어가 위에서 준 bootstrapPassword 로 처음 로그인하고, 바로 비밀번호를 바꾸십시오. 로그인하면 이 K3s 클러스터가 local 로 잡혀 있습니다.

사설망이면 호스트 이름부터 정하십시오

Rancher 는 hostname 으로 인증서를 만듭니다. IP 로 접속할 계획이면 그 IP 를 그대로 hostname 에 넣고, 브라우저가 자체서명 인증서를 경고하는 것을 받아들이십시오.

3. PlantPulse 설치​

여기서부터는 kubectl 로 하든 Rancher 화면에서 하든 같습니다. 아래 설치 절을 그대로 따르십시오. Rancher 를 쓰신다면 Apps → Charts → Repositories 에 차트 저장소를 등록해 화면에서 설치할 수도 있지만, 값 파일을 다루기에는 helm 명령이 낫습니다.

Rancher 가 실제로 도움이 되는 자리는 설치 뒤입니다 — 파드의 Init 단계가 어디서 기다리는지, 로그가 무엇을 말하는지, 이벤트가 무엇을 거절했는지를 한 화면에서 봅니다. 기동 순서를 읽을 때 특히 그렇습니다.


설치​

1. 비밀을 Secret 으로 만듭니다​

차트는 비밀번호를 한 줄도 갖고 있지 않습니다. values.yaml 에도 없고, 기본 설정에서는 차트가 Secret 을 만들지도 않습니다 — 이미 있는 것을 참조만 합니다.

정본은 compose 와 같은 사이드카 파일입니다. 바이트 단위로 그대로 씁니다.

kubectl -n plantpulse create secret generic plantpulse-platform-env \
--from-env-file=/etc/kopens/plantpulse-platform.env

2. 설치합니다​

helm install pp charts/plantpulse-platform -n plantpulse --create-namespace

기본 레지스트리(docker.kopens.io/pp · docker.kopens.io/pd)는 공개라 밖에서도 받을 수 있습니다. 그래서 평상시 설치에는 --set 이 필요 없습니다.

3. 사설 레지스트리로 미러링했다면​

helm install pp charts/plantpulse-platform -n plantpulse --create-namespace \
--set global.image.registry=<사설 레지스트리>/pp \
--set global.image.registryDatalake=<사설 레지스트리>/pd \
--set global.image.registryThirdParty=<사설 레지스트리>/proxy-dockerhub \
--set global.imagePullSecrets[0].name=<레지스트리 시크릿>
registryThirdParty 를 빠뜨리지 마세요

앞의 둘만 덮으면 기동 순서 대기용 busybox 를 못 받습니다. 그러면 의존하는 파드가 전부 Init:0/1 에서 영원히 서는데, 그 실패는 레지스트리 문제처럼 보이지 않습니다.


기동 순서 — 쿠버네티스가 지켜 주지 않습니다​

플랫폼에는 지켜야 할 순서가 있습니다.

certs → datalake → server → batch
→ warehouse · opcua · aasx · ha
server → proxy

compose 의 depends_on 에 해당하는 것이 쿠버네티스에는 없습니다. 흔히 대신 쓴다고 하는 셋은 전부 다른 일을 합니다.

흔히 쓰는 것실제로 하는 일
readinessProbe그 파드로 가는 트래픽을 막습니다. 남의 파드 기동은 못 늦춥니다
StatefulSet같은 StatefulSet 안의 파드 순서입니다. 다른 워크로드와는 무관합니다
Helm hook · --wait매니페스트 적용 순서입니다. 만들어진 것의 준비 상태가 아닙니다

그래서 차트는 쿠버네티스가 실제로 막아 주는 자리 — initContainer — 에 대기를 넣었습니다. 대기는 「파드가 떴나」가 아니라 「산출물이 있나」 를 봅니다.

Init:0/2 는 고장이 아닙니다

차트가 동작 중이라는 뜻입니다. 무엇을 기다리는지 물어보세요.

kubectl -n plantpulse logs <파드> -c wait-for-certs

기본 대기 한도는 1800초이고 5초마다 확인합니다. 한도를 넘기면 대기가 종료되고 kubelet 이 다시 띄웁니다 — 이유가 파드 이벤트에 남게 하려는 것입니다. 영원히 막혀 있으면 아무것도 남지 않습니다.

컨테이너 «안»의 순서는 차트가 건드리지 않습니다. 데이터레이크 내부의 기동 순서는 pd 가 컨테이너 안에서 강제합니다. 차트가 그것을 다시 구현하면 정본이 둘이 되어 갈라집니다.


프록시가 502 를 답한다면​

도커 네트워크는 컨테이너의 모든 포트를 전달하지만, 쿠버네티스 Service 는 «자기가 선언한 포트만» 전달합니다. compose 에서 되던 업스트림이 쿠버네티스에서 502 가 되는 경로가 여기입니다.

차트에 그것을 잡는 게이트가 있습니다 — 모든 프록시 업스트림이 «이 차트가 만드는 Service 의, 그 Service 가 선언한 포트» 를 가리키는지 검사합니다.

bash hack/run-gates.sh
게이트검사하는 것
gate-render.sh렌더 결과의 프록시 업스트림이 실재하는 Service · 포트인지
gate-no-plaintext-secrets.sh렌더 결과에 평문 비밀이 섞이지 않았는지
prove-gates-fail.sh게이트가 «실패해야 할 때 실제로 실패하는지» (게이트의 게이트)

설치 전에 돌려서 통과시키십시오. 502 의 대부분은 여기서 먼저 잡힙니다.


노드가 얼마나 커야 하나​

🔴 차트가 선언한 requests 의 합이 곧 노드 요구량입니다. 모자라면 파드가 뜨지 않고 Pending 으로 남습니다 — 「설치가 멈춘 것처럼 보이는」 첫 번째 원인입니다.

워크로드CPU 요청메모리 요청메모리 상한
datalake864 Gi64 Gi
server212 Gi16 Gi
batch16 Gi8 Gi
warehouse14 Gi8 Gi
opcua · aasx각 0.5각 2 Gi각 4 Gi
ha0.51 Gi4 Gi
proxy0.2256 Mi1 Gi
certs0.1256 Mi1 Gi
합(기본 구성)약 14약 92 Gi—
데이터레이크 하나가 대부분을 차지합니다

datalake 만으로 CPU 8 · 메모리 64 Gi 를 요청합니다(요청과 상한이 같습니다 — Guaranteed 로 잡아 둔 것입니다). 단일 노드에 올리려면 그 노드가 넉넉히 CPU 16 · 메모리 128 Gi 급이어야 합니다.

JVM 힙은 파드 한도와 «따로» 선언됩니다​

자바 앱 셋은 힙 크기를 차트가 직접 넘겨 줍니다. 파드 한도에서 유도하지 않습니다 — 유도하면 한도를 내렸을 때 힙이 조용히 줄어들고, 실제로는 이미지 안 리터럴이 이겨서 한도를 어느 방향으로 고쳐도 JVM 이 모르는 상태가 됩니다.

앱힙다이렉트넘어가는 변수
server8g4gPP_SERVER_HEAP · PP_SERVER_DIRECT
batch3g—PP_BATCH_HEAP
warehouse1g—PP_WAREHOUSE_HEAP

차트는 렌더할 때 아래를 단언합니다. 어기면 설치가 그 자리에서 실패합니다.

힙 + 다이렉트 + 여유(기본 2048Mi) ≤ limits.memory
힙 + 여유 ≤ requests.memory

🔴 힙만 키우고 파드 한도를 안 올리면 프리터치 중 OOMKill 이 납니다. -Xms=-Xmx 에 AlwaysPreTouch 라 힙은 기동 즉시 전부 상주하는데, 이때 로그에는 힙을 지목하는 줄이 남지 않습니다. 둘을 함께 올리십시오.


지금 어디까지 검증됐나​

실증 환경은 k3s v1.32.5+k3s1 · 단일 노드이고, 전부 실제 레지스트리 이미지입니다.

컴포넌트상태
plantpulse-certs✅ Ready. TLS 자재가 공유 볼륨에 실제로 생성됨
plantpulse-datalake✅ 이 차트로 클린 설치해 19/19 기동 (2026-09-09, 2026.09 이미지, PVC 삭제 후)
기동 순서 대기✅ 막히고 풀리는 것을 실물로 확인
server · batch · warehouse · proxy⬜ 띄워 본 기록이 아직 없습니다 — 다만 차트 쪽 결함은 계속 잡히고 있습니다(2026-09-09: 백업 볼륨 · JVM 힙 계약 · 프록시 업스트림)
opcua · aasx · ha⬜ 대기 상태까지만 확인
mirror-maker기본 꺼짐 (compose 의 mirror 프로파일 대응)

데이터레이크 파드는 이제 특권 없이 뜹니다 — 이미지에서 systemd 가 PID 1 에서 빠지면서 privileged · SYS_ADMIN · cgroup:host 가 모두 필요 없어졌습니다.

TOTAL SERVICES : 19 RUNNING / 0 STOPPED
/proc/1/comm : bash # systemd 아님
securityContext: (비어 있음) # privileged·SYS_ADMIN·cgroup 없음
남은 관문

server → batch → warehouse → proxy 순서가 실물로 지켜지는지는 아직 아무도 그 지점까지 가 보지 못했습니다.

「차트를 안 고치고 있다」는 뜻이 아닙니다. 2026-09-09 에 앱 티어 결함 셋을 잡았습니다 — 백업 볼륨이 서버에 안 붙던 것, JVM 힙이 쿠버네티스에서 설정 불가였던 것, 프록시 업스트림 일곱이 도커 모양 그대로였던 것. 다만 셋 다 렌더 대조와 코드로 찾은 것이고, 파드를 실제로 띄워 확인한 것은 아닙니다. 「고쳤다」와 「이 차트에서 뜬다」는 다른 사실입니다. 고객사 설치에는 원라인 설치 나 Docker 설치 를 쓰십시오.


막혔을 때​

증상먼저 볼 것
파드가 Init:0/1 에서 안 움직임busybox 를 못 받는 것일 수 있습니다 — registryThirdParty 확인
파드가 Init:0/2 에서 대기정상입니다. kubectl logs <파드> -c wait-for-certs 로 무엇을 기다리는지 봅니다
프록시 경로가 502bash hack/run-gates.sh — 업스트림이 실재하는 Service·포트를 가리키는지
두 번째 노드를 붙인 뒤 TLS 관련 오류pp-security 가 RWX 가 아닙니다
웨어하우스 콘솔의 목록이 항상 비어 있음Iceberg 관련 필수 설정이 비었습니다. 빈 값은 렌더가 실패하도록 되어 있으니 설치 로그를 봅니다

관련 문서​