Kubernetes
Libre WebUI는 helm/libre-webui 아래에 Helm 차트를 제공합니다.
Kubernetes의 Work
Work는 Kubernetes에서 네이티브로 실행됩니다. 어느 곳에도 Docker 데몬, CLI, 소켓이 관여하지 않습니다. 설치 시 활성화합니다.
helm install libre-webui ./helm/libre-webui --set work.enabled=true
그러면 백엔드가 WORK_RUNTIME_BACKEND=kubernetes로 전환되고 다음을 만듭니다.
- 전용 샌드박스 네임스페이스(
work.namespace, 기본값libre-webui-work). 실행 중인 샌드박스마다 Pod 하나, 작업 워크스페이스마다 PersistentVolumeClaim 하나(work.workspaceSize, 기본값5Gi)가 있습니다. 이는 실제 작업별 디스크 할당량이며, 이름 있는 Work 정책은 그 정책 아래 생성된 작업에 다른 크기를 지정할 수 있습니다. - 백엔드 ServiceAccount에 해당 네임스페이스의
pods(get/list/create/delete),pods/exec(get/create),persistentvolumeclaims(get/list/create/delete)만 허용하는 네임스페이스 범위 Role과 RoleBinding. secrets나 클러스터 범위 권한은 없습니다. 이 권한이 Docker 소켓을 완전히 대체합니다. 샌드박스 사양이 호스트 경로를 마운트하지 못하도록 애플리케이션이 아니라 API 서버가 강제합니다. - 모든 샌드박스 트래픽을 기본 거부하고, 미리보기 포트에는 백엔드만 들어오도록 허용하며, 네트워크 활성 샌드박스에는
work.networkPolicy.blockedEgressCidrs를 제외한 인터넷 송신을 허용하는 NetworkPolicies. 기본 제외 범위에는 사설 범위, 일부 관리형 클러스터가 Pod 및 Service CIDR에 사용하는 CGNAT 범위, 클라우드 메타데이터 링크 로컬 범위가 포함됩니다. 클러스터의 Pod 및 Service CIDR이 포함되는지 확인하세요. 샌드박스 DNS는kube-system에만 허용되며 node-local DNS를 쓰는 클러스터에는 별도 DNS 예외가 필요합니다.
샌드박스는 비 root, 읽기 전용 루트 파일시스템, 모든 capability 삭제, seccomp RuntimeDefault, ServiceAccount 토큰 없음으로 실행됩니다. 파일, 명령, git, 대화형 터미널은 API 서버의 exec 하위 리소스를 사용합니다. 미리보기는 서명된 동일 출처 프록시를 통해 샌드박스 Pod IP에서 제공되며, 백엔드가 클러스터 안에서 실행되어야 합니다(일반적인 차트 토폴로지). 이 백엔드는 호스트 폴더 워크스페이스를 지원하지 않습니다.
운영 시 두 가지를 주의하세요. NetworkPolicy 강제 적용에는 이를 구현하는 CNI(Calico, Cilium, 최근 kind 릴리스, 대부분의 관리형 클러스터 기본값)가 필요합니다. 샌드박스 격리가 활성화되었다고 보기 전에 클러스터에서 확인하세요. CI 종단 간 테스트는 사용한 클러스터의 적용 여부를 보고합니다. 또한 WebUI Pod에 노드의 컨테이너 런타임 소켓을 절대 마운트하지 마세요. Kubernetes 백엔드는 바로 그 필요를 없애기 위해 존재합니다.
설치
helm install libre-webui oci://ghcr.io/libre-webui/charts/libre-webui
기본 차트는 영구 스토리지와 번들 Ollama 서비스가 있는 Libre WebUI를 배포합니다. 0.14.1 전환은 검증된 다중 아키텍처 이미지 다이제스트로 고정되며, 이후 차트는 일치하는 의미 버전 appVersion 이미지를 기본값으로 사용합니다. 의도적으로 다른 이미지를 원할 때만 image.tag 또는 image.digest를 명시하세요. 비어 있지 않은 image.tag는 전환 다이제스트보다 우선합니다.
기본 solo 프로필은 의도적인 일시 중지에 replicaCount: 0, 정상 운영에 replicaCount: 1을 허용합니다. SQLite, 로컬 파일, 프로세스 로컬 조율은 여러 Pod 뒤에서 안전하지 않으므로 더 큰 값과 HorizontalPodAutoscaler를 거부합니다. 복제본이 0인 릴리스는 제어 영역 리소스는 프로비저닝하지만 Libre WebUI 트래픽을 제공하지 않습니다.
여러 복제본에는 완전한 team 프로필을 설정하세요. PostgreSQL/PGVector, S3 호환 Blob 스토리지, Redis, 별도의 영구 워커를 사용하며 차트는 공유 및 로컬 백엔드의 불완전한 혼합을 거부합니다. 다음과 같은 보호된 values 파일에서 시작하세요.
replicaCount: 3
env:
LIBRE_PLATFORM_MODE: team
DATABASE_BACKEND: postgres
DATABASE_SSL_MODE: verify-full
POSTGRES_MIGRATION_MODE: apply
POSTGRES_POOL_MAX: 10
POSTGRES_CONNECT_TIMEOUT_MS: 5000
POSTGRES_IDLE_TIMEOUT_MS: 30000
POSTGRES_STATEMENT_TIMEOUT_MS: 30000
POSTGRES_MIGRATION_LOCK_TIMEOUT_MS: 60000
OLLAMA_TIMEOUT: 300000
OLLAMA_LONG_OPERATION_TIMEOUT: 900000
OLLAMA_MAX_CONTEXT: 32768
BLOB_STORE_BACKEND: s3
VECTOR_STORE_BACKEND: pgvector
COORDINATION_BACKEND: redis
JOB_WORKER_MODE: external
STORAGE_ENCRYPTION_ACTIVE_KEY_ID: active
S3_BUCKET: libre-blobs
S3_REGION: us-east-1
S3_BLOB_PREFIX: libre/blobs
worker:
replicaCount: 1
secrets:
databaseUrl: postgresql://libre:replace-me@postgres.example/libre
redisUrl: rediss://redis.example:6379/0
jwtSecret: '<one-stable-high-entropy-secret-for-every-replica>'
encryptionKey: '<legacy-64-character-lowercase-hex-key>'
storageEncryptionKeys: '{"legacy":"<legacy-64-character-lowercase-hex-key>","active":"<active-64-character-lowercase-hex-key>"}'
s3AccessKeyId: replace-me
s3SecretAccessKey: replace-me
secrets.encryptionKey는 legacy 항목과 정확히 일치해야 하며 키 맵에는 STORAGE_ENCRYPTION_ACTIVE_KEY_ID도 있어야 합니다. secrets.jwtSecret은 모든 앱 및 워커 Pod가 공유하는 안정되고 엔트로피가 높은 값이어야 합니다. 차트는 team 모드에서 이 값이 없으면 거부하므로 세션이 Pod 로컬 생성 자료에 의존하지 않습니다. 관리형 PostgreSQL에는 검증된 TLS를 유지하고 databaseUrl에 드라이버 TLS 매개변수를 추가하지 마세요. 풀 제한은 모든 앱과 워커 Pod에 적용되므로 최소 (replicaCount + worker.replicaCount) * POSTGRES_POOL_MAX개의 데이터베이스 연결과 운영 여유를 확보하세요. 보호된 values 파일로 설치합니다.
helm upgrade --install libre-webui \
oci://ghcr.io/libre-webui/charts/libre-webui \
--values /absolute/path/to/libre-team-values.yaml
이 파일을 커밋하거나 프로덕션 시크릿을 --set으로 전달하지 마세요. 보호된 암호화 values 워크플로에 저장하세요. 모델 제공자와 Work 샌드박스 Pod는 독립적으로 확장합니다. work.enabled=true이면 외부 team 워커는 앱 Pod와 동일한 런타임 이미지, StorageClass, work.env 제한을 받습니다. 문서 임베딩, 영구 채팅, Work 실행에서 제공자 호출을 수행하므로 앱과 같은 Ollama 엔드포인트, 요청 타임아웃, 자동 채택 최대 문맥도 받습니다. 활성 team 애플리케이션(양수 replicaCount 또는 활성 자동 확장)에는 외부 워커가 하나 이상 필요하며, 설치 전 차트가 워커 0 구성을 거부합니다. 전체 일시 중지에는 replicaCount와 worker.replicaCount를 모두 0으로 설정합니다. 앱 수만 0으로 만드는 것은 의도적인 워커 전용 드레인 또는 복구 모드입니다. 웹 트래픽은 제공하지 않지만 워커는 대기 중인 영구 작업을 계속 처리합니다.
Team 업그레이드와 스키마 호환성
Libre는 혼합 버전 또는 무중단 데이터베이스 업그레이드가 아니라 정확한 스키마 버전 정책을 지원합니다. 애플리케이션과 외부 워커 Deployment는 각각 Recreate를 사용해 한 Deployment 안에서 이전 및 새 Pod가 겹치지 않게 합니다. Kubernetes는 두 Deployment를 하나의 업그레이드 경계로 조율하지 않습니다. 업그레이드 전에 새 ingress를 중지하고, 활성 영구 작업과 Work 작업을 완료 또는 취소하고, 두 이전 Deployment를 0으로 줄이고, 검증된 team 백업을 만들며, 모든 이전 앱과 워커 Pod가 종료되었는지 확인하세요. 그런 다음에만 POSTGRES_MIGRATION_MODE=apply로 릴리스를 업그레이드합니다. 새 프로세스 하나가 PostgreSQL advisory 리더 잠금을 보유하고 나머지 새 프로세스는 같은 마이그레이션 원장을 기다리고 검증합니다. 롤백에는 이전의 검증된 백업을 깨끗한 PostgreSQL/S3 대상으로 복원하세요. 정확히 지원하지 않는 스키마에 이전 바이너리를 절대 연결하지 마세요. 이 절차 중 의도적인 서비스 중단이 발생합니다.
로컬 접근
kubectl port-forward svc/libre-webui 8080:8080
http://localhost:8080을 엽니다.
외부 Ollama
기존 Ollama 엔드포인트 사용:
helm install libre-webui oci://ghcr.io/libre-webui/charts/libre-webui \
--set ollama.bundled.enabled=false \
--set ollama.external.enabled=true \
--set ollama.external.url=http://my-ollama:11434
시크릿
프로덕션에서는 안정된 JWT 시크릿과 암호화 키를 설정합니다. 기본적으로 차트는 비어 있지 않은 secrets.* 값에서 <release>-libre-webui-secrets를 만듭니다.
helm upgrade --install libre-webui \
oci://ghcr.io/libre-webui/charts/libre-webui \
--set-string secrets.jwtSecret="$(openssl rand -hex 64)" \
--set-string secrets.encryptionKey="$(openssl rand -hex 32)"
운영자가 관리하는 Secret에는 secrets.existingSecret을 설정합니다. 그러면 차트가 Secret을 렌더링하지 않고 애플리케이션과 워커 Pod가 이름 있는 객체를 참조합니다.
secrets:
existingSecret: libre-webui-runtime
릴리스 설치 전에 해당 Secret을 만드세요. jwt-secret과 encryption-key를 포함해야 합니다. Team 모드에는 database-url, redis-url, storage-encryption-keys도 필요합니다. 차트가 인식하는 선택적 키는 session-secret, s3-access-key-id, s3-secret-access-key, s3-session-token입니다. GitHub 및 Hugging Face OAuth도 해당하는 비어 있지 않은 secrets.githubClientId 또는 secrets.huggingfaceClientId 값으로 통합을 활성화하면 이름 있는 Secret의 *-client-id 및 *-client-secret 쌍을 읽을 수 있습니다. 차트는 의도적으로 Secret 값을 검증하거나 복사하지 않습니다. 필수 키가 없으면 Pod를 시작할 수 없습니다.
프로덕션 자동화에는 external-secrets 컨트롤러와 secrets.existingSecret을 사용하거나 암호화된 Helm values 워크플로를 통해 안정된 값을 제공하는 편이 좋습니다. 명령줄 --set 값은 프로세스 검사에 노출될 수 있고 Helm 릴리스 메타데이터에 보존됩니다. 제공자 자격 증명은 의도적인 차트 확장으로 추가하거나 WebUI에서 사용자별로 설정하세요.
애플리케이션 및 워커 NetworkPolicies
networkPolicy.enabled=true를 설정하면 애플리케이션과 team 모드의 외부 영구 워커에 대한 ingress 정책을 렌더링합니다.
networkPolicy:
enabled: true
애플리케이션은 HTTP 컨테이너 포트로만 ingress를 허용합니다. 워커는 ingress를 받지 않습니다. 이 정책은 egress를 제한하지 않습니다. 애플리케이션과 워커 프로세스는 설정된 PostgreSQL, Redis, S3, Ollama, 도구, 모델 제공자 엔드포인트에 계속 도달해야 하며, 해당 서비스의 위치는 운영자가 결정합니다.
이 설정은 Work 샌드박스 네임스페이스의 기본 거부 정책을 제어하고 Work 활성화 시 기본으로 켜지는 work.networkPolicy.enabled와 별개입니다. 두 설정 모두 NetworkPolicy를 실제로 강제하는 CNI가 필요합니다. 객체를 렌더링하는 것만으로 네트워크 격리가 증명되지는 않습니다.
영속성
Libre WebUI 데이터 PVC와 Ollama 모델 PVC를 영구 스토리지에 유지하세요. Libre WebUI 데이터 볼륨과 암호화 키를 함께 백업합니다.
Work 작업 워크스페이스는 Libre WebUI 데이터 PVC가 아니라 샌드박스 네임스페이스의 자체 PVC에 있습니다. 완전한 Work 복구에는 데이터베이스(작업 소유권, 리소스 이름, 실행)와 해당 PVC가 모두 필요합니다. 같은 정책으로 함께 백업하세요.
Ingress
공개 접근에는 HTTPS로 ingress를 설정하고 차트를 통해 정확한 브라우저 출처를 지정합니다.
helm upgrade libre-webui \
oci://ghcr.io/libre-webui/charts/libre-webui \
--reuse-values \
--set env.TRUST_PROXY=1 \
--set-string env.CORS_ORIGIN=https://your-domain.example
TRUST_PROXY는 불리언이 아니라 정확한 홉 수입니다. 안전한 차트 기본값 0은 전달된 클라이언트 주소를 무시합니다. ingress 프록시 하나가 Libre에 직접 연결할 때만 1을 사용하세요. 더 긴 고정 체인에서는 신뢰할 로드 밸런서 또는 프록시 홉을 모두 세고, 해당 체인 주변에서 Service에 직접 접근하지 못하게 하세요. 값이 너무 작으면 클라이언트가 프록시 주소 아래 묶여 공유 로그인 제한을 소진할 수 있고, 너무 크면 클라이언트가 제공한 주소를 신뢰할 수 있습니다. 차트는 무제한 true가 아닌 0~16만 허용하고 값을 HTTP 애플리케이션 Pod에만 보냅니다.
현재 차트는 BASE_URL 또는 OAuth 콜백 URL 값을 공개하지 않습니다. OAuth를 사용하는 배포는 차트를 확장하거나 Deployment를 패치해 해당 변수를 설정해야 하며 콜백 URL은 공개 도메인과 일치해야 합니다.
리소스 계획
클러스터 내부의 로컬 Ollama에는 실행할 모델에 충분한 메모리와 GPU 용량이 있는 노드에 Ollama Pod를 예약하세요. 클러스터에 전용 Ollama 또는 추론 서비스가 이미 있으면 외부 Ollama가 보통 더 간단합니다.