마구잡

kubernetes AI - K8sGPT 활용 (with: Ollama-AI, Google Gemini) 본문

Kubernetes

kubernetes AI - K8sGPT 활용 (with: Ollama-AI, Google Gemini)

MAGUJOB 2025. 2. 24. 15:21
728x90

K8sGPT란?

K8sGPT는 Kubernetes 클러스터의 문제를 AI를 활용해 자동으로 분석하고 설명하는 오픈소스 도구이다.

존 Kubernetes 운영에서 발생하는 문제를 사람이 직접 로그와 이벤트를 분석하여 해결해야 했다면, K8sGPT는 이를 AI를 활용해 자동으로 진단하고 해결 방안을 제안한다.

 

 

로컬 LLM에서 K8sGPT로 쿠버네티스 AIOps 실행하기 (2) | 요즘IT

앞서 K8sGPT를 통한 쿠버네티스 AIOps의 가능성 1부에서는 K8sGPT에서 지난 1년간 보여준 변화를 소개했습니다. 이번 글에서는 공개된 AI 제공자를 사용하는 게 아닌 ‘나만의 AI 제공자를 사용하는 법

yozm.wishket.com

추가적으로 쿠버네티스 엠버서더 조훈 님의 글이 잘 정리되어있어 해당 글 링크 첨부드립니다.

 

( 공식 사이트에서 발췌한 내용을 기반으로 작성하였으나, 명확하지 않은 부분은 경험을 토대로 작성하였습니다.

이는 정확한 정보가 아닐 수 있음을 알려드립니다. )

공식 사이트

 

K8sGPT

Kubernetes SRE superpowers with AI

k8sgpt.ai

728x90

( 광고 클릭은 큰 힘이 됩니다! )

 


K8sGPT를 사용하는 이유

 

K8sGPT는 Kubernetes 클러스터의 문제를 AI로 자동 분석하고 설명하는 오픈소스 도구다.

기존에는 운영자가 직접 로그와 이벤트를 분석해야 했지만, K8sGPT는 이를 자동화해 엔지니어의 부담을 줄인다.

Kubernetes 클러스터 운영 중 CrashLoopBackOff, ImagePullBackOff, OOMKilled 같은 오류가 발생하면 빠른 원인 파악이 쉽지 않다. K8sGPT는 AI 기반 분석을 통해 이러한 문제를 신속하게 진단하고 해결책을 제시해 운영 효율성을 높인다.

출처: https://www.kerno.io/blog/k8sgpt

장점

  • Kubernetes 클러스터의 문제를 분석하여 원인과 해결책을 자연어(사람의 언어)로 제공
  • Pod, Deployment, Node 등의 상태를 점검하고 자동으로 이슈를 감지
  • DevOps 및 SRE 엔지니어의 운영 부담 감소 (비용 감소)
다만 실제 몇 번 사용해 본 입장으로 가독성이 그리 좋지 않으며 인과성을 확실하게 판단하기엔 무리가 있다.
이는 아래에서 자세하게 다룬다.

단점

  • AI가 제공하는 분석 결과가 항상 정확하지 않음
  • 외부 AI API를 사용할 시 추가적인 비용이 발생 (무료로 사용이 가능하긴 하나 프라이빗 클러스터에는 적합하지 않음)
  • 외부 AI를 사용 시 정보 노출 우려가 있음
  • 로컬 AI 사용시 모델 적합성들 판단해야 하며, 빠른 처리를 위해선 결국 GPU 카드가 필요함 (비용증가)
  • AI가 분석하지만, 해결책을 적용하려면 결국 Kubernetes 개념을 이해해야 함

 

K8sGPT Install

다양한 환경에서 설치를 지원하며 이는 공식 Docs에 친절히 설명되어 있다.

 

 

GitHub - k8sgpt-ai/k8sgpt: Giving Kubernetes Superpowers to everyone

Giving Kubernetes Superpowers to everyone. Contribute to k8sgpt-ai/k8sgpt development by creating an account on GitHub.

github.com

 

본 환경은 Redhat8에서 진행한다.

 

1. CLI 명령어로 설치

sudo rpm -ivh https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.48/k8sgpt_amd64.rpm
Retrieving https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.48/k8sgpt_amd64.rpm
Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
        file /usr/bin/k8sgpt from install of k8sgpt-0.3.48-1.x86_64 conflicts with file from package k8sgpt-0.3.37-1.x86_64

 

2. 설치 확인

k8sgpt
Kubernetes debugging powered by AI

Usage:
  k8sgpt [command]

Available Commands:
  analyze     This command will find problems within your Kubernetes cluster
  auth        Authenticate with your chosen backend
  cache       For working with the cache the results of an analysis
  completion  Generate the autocompletion script for the specified shell
  filters     Manage filters for analyzing Kubernetes resources
  generate    Generate Key for your chosen backend (opens browser)
  help        Help about any command
  integration Integrate another tool into K8sGPT
  serve       Runs k8sgpt as a server
  version     Print the version number of k8sgpt

Flags:
      --config string        Default config file (/root/.config/k8sgpt/k8sgpt.yaml)
  -h, --help                 help for k8sgpt
      --kubeconfig string    Path to a kubeconfig. Only required if out-of-cluster.
      --kubecontext string   Kubernetes context to use. Only required if out-of-cluster.

Use "k8sgpt [command] --help" for more information about a command.
위에서 보듯 K8sGPT 설치 자체는 간단하다.

 

3. K8sGPT 실행

k8sgpt analyze
AI Provider: AI not used; --explain not set

0: Service build/java-app-service()
- Error: Service has no endpoints, expected label app=java-app
... 중략
30: ValidatingWebhookConfgiguration /validation.webhook.serving.knative.dev()
- Error: Service webhook not found as mapped to by Validating Webhook validation.webhook.serving.knative.dev
아직 AI를 사용하지 않은 상태에서 클러스터의 문제점을 파악한다.
현재 본인의 클러스터는 테스트베드여서 아주 많은 문제점들이 나온다.

외부 AI 사용하기 - Gemini

K8sGPT의 메인 기능은 Kubernetes 클러스터의 문제를 AI로 자동 분석하고 설명하는 능력이다.

이때 필연적으로 사용되어야 하는 게 AI 모델이다, 이때 운영자는 두 가지 선택을 할 수 있다.

 

1. 퍼블릭한 AI API를 사용한다.

2. 로컬에서 사용하는 AI를 사용하거나 만든다

 

아래 사용가능한 AI 목록부터 확인해 본다.

k8sgpt auth list
Default: 
> openai
Active: 
> localai
> google
> googlevertexai
Unused: 
> openai
> azureopenai
> cohere
> amazonbedrock
> amazonsagemaker
> noopai
> huggingface
> oci
현재 auth list엔 여러 AI가 존재한다.
이번에는 Google의 Gemini를 사용해 본다.

 


Gemini API key 발급

K8sGPT의 메인 기능은 Kubernetes 클러스터의 문제를 AI로 자동 분석하고 설명하는 능력이다.

이때 필연적으로 사용되어야 하는 게 AI 모델이다.

 

K8sGPT의 기본 모델은 open-ai를 사용한다, 다만 무료로 거의 사용할 수 없기에 가장 만만한 Gemini를 사용한다.

 

Gemini Developer API 가격 책정  |  Gemini API  |  Google AI for Developers

Gemini Developer API 가격 책정

ai.google.dev


1. API key 발급 or 가져오기

https://aistudio.google.com/app/u/1/apikey

 

로그인 - Google 계정

이메일 또는 휴대전화

accounts.google.com

 

2. auth 등록

k8sgpt auth add --backend google --model gemini-1.5-flash  --password "발급받은 API"

 

2-1. 이미 google이 지정되어 등록이 안된다면 update 명령어로 수정이 가능하다.

k8sgpt auth update --backend google --model gemini-1.5-flash --password "발급받은 API"

 

3. Interactive 모드로 사용해 보기

k8sgpt analyze --explain --interactive  --backend=google
Interactive mode enabled [type exit to close.]
Input text: 한국말로 현재 클러스터의 문제를 설명해줄래?
현재 Kubernetes 클러스터에는 여러 가지 문제가 발생하고 있습니다.  주요 문제는 다음과 같습니다.

1. **저장소 클래스 누락:** `이름 가림` PersistentVolumeClaim은 "nfs-client-115"라는 저장소 클래스를 찾을 수 없습니다.  NFS 클라이언트를 설정하고 해당 저장소 클래스를 생성해야 합니다.

2. **Pod와 Service 매칭 문제:** `java-app-service` Service는 `app=java-app` 라벨을 가진 Pod를 찾을 수 없습니다.  Pod에 올바른 라벨이 지정되었는지, 그리고 Service의 selector가 Pod의 라벨과 일치하는지 확인해야 합니다.

... 중략

6. **MutatingWebhookConfiguration 및 ValidatingWebhookConfiguration 문제 (15개 이상):**  다수의 MutatingWebhookConfiguration과 ValidatingWebhookConfiguration이  `kserve`, `istio`, `knative`, `kubeflow` 등의 구성요소에 필요한 서비스를 찾을 수 없습니다.  이러한 서비스들이 올바르게 배포되고, Webhook 설정에서 서비스 이름과 네임스페이스가 정확한지 확인해야 합니다.  대부분 `kserve-webhook-server-service`, `istiod`, `eventing-webhook`, `domainmapping-webhook`, `katib-controller`, `admission-webhook-service`, `cache-server` 등의 서비스 관련 문제입니다.


요약하자면, 클러스터의 여러 구성 요소 (저장소, 서비스, Pod, Ingress, Webhook) 간의 설정 오류와  일부 구성 요소의 배포 또는 설정 문제로 인해 클러스터가 제대로 작동하지 않고 있습니다.  위에 제시된 각 문제에 대한 해결책을 따라 문제를 해결해야 합니다.  특히, 다수의 Webhook 관련 문제는 Knative, Istio, KServe, Kubefow 등의 설치 및 구성 상태를 점검해야 함을 시사합니다.
Input text: 해결 방법을 한국말로 알려줘
제공된 로그에는 Kubernetes 클러스터에서 다양한 구성 요소와 관련된 31개의 에러가 나타나고 있습니다.  각 에러와 해결 방법을 한국어로 요약하면 다음과 같습니다.  에러 메시지의 색상 코드는 생략했습니다.

**0. PersistentVolumeClaim (이름가림): StorageClass "nfs-client-115" 없음**

* **문제:**  PersistentVolumeClaim이 필요로 하는 StorageClass "nfs-client-115"가 존재하지 않습니다.
* **해결책:**
    1. 설정 파일에서 StorageClass 이름이 정확한지 확인합니다.
    2. "nfs-client-115" StorageClass가 없다면 생성합니다.
    3. Kubernetes 클러스터가 기본 저장소 제공자에 연결하는 데 필요한 드라이버와 권한을 가지고 있는지 확인합니다.


**1. Service (java-app-service): 엔드포인트 없음**

* **문제:** Service가 `app=java-app` 라벨을 가진 Pod를 찾을 수 없습니다.
* **해결책:**
    1. `kubectl describe svc <service-name>` 명령어로 Service의 선택자를 확인합니다.
    2. `kubectl get pods --show-labels` 명령어로 Pod 라벨을 확인합니다.
    3. Pod 라벨이 Service 선택자와 일치하는지 확인합니다.
    4. 필요하다면 Pod를 재시작합니다.

... 중략

전반적으로 이 문제들은 Kubernetes 구성 요소들의 상호 의존성 문제와 구성 오류로 인해 발생합니다.  각 에러 메시지에 제시된 명령어들을 사용하여 문제의 원인을 정확히 파악하고 해결해야 합니다.  특히, 8번부터 21번, 23번부터 30번까지의 에러들은  Knative, Istio, Kubeflow 등의 서비스들이 제대로 설치 및 구성되었는지 확인하는 것이 중요합니다.  필요하다면 해당 서비스들의 문서를 참고하여 문제 해결을 진행해야 합니다.

 

필터를 활용해 리소스를 지정하거나 네임스페이스를 지정할 수 있다.

k8sgpt analyze -e -f Pod  -b google -n open-webui -l Korean  
AI Provider: google

No problems detected

Ollama, Open Web-UI 사용

Google Gemini로 준수한 답변을 받아낼 수 있었다.

그러나 서두에서의 언급처럼 외부 AI를 사용하게 되면 정보유출 및 가격정책에 의한 제약사항이 생기기 마련이다.

이때 우리는 로컬 AI를 사용하여 문제를 해결할 수 있다.

Ollama란?

Ollama는 로컬에서 다양한 오픈소스 LLM을 손쉽게 실행할 수 있도록 지원하는 도구다. Llama 3, Mistral, Gemma 등 다양한 모델을 지원하며, 모델의 가중치, 설정, 데이터셋을 하나의 패키지로 관리할 수 있다.

  • 간편한 모델 실행 명령어 한 줄로 다양한 모델 실행 가능
  • 로컬 환경에서 동작 인터넷 연결 없이 오프라인 실행 가능
  • 빠른 모델 다운로드 및 관리 모델 실행과 관리가 쉽고 직관적
 

Ollama

Get up and running with large language models.

ollama.com

 

Open WebUI란?

Open WebUI는 웹 기반 인터페이스를 통해 로컬에서 LLM(대규모 언어 모델)을 실행하고 관리할 수 있도록 지원하는 오픈소스 플랫폼이다. 이를 통해 사용자는 복잡한 설정 없이도 웹 브라우저만으로 다양한 모델과 상호작용할 수 있다.

  • 웹 기반 인터페이스 브라우저에서 직접 모델과 상호작용 가능
  • 다양한 LLM 지원 여러 모델을 로컬에서 실행하고 관리 가능
  • 다중 사용자 지원 여러 사용자가 동시에 접속하여 활용 가능
 

Open WebUI

Open WebUI Community is currently undergoing a major revamp to improve user experience and performance ✨

openwebui.com


Ollama & Open WebUI Install

쿠버네티스 클러스터 환경에서 설치하기 위해 helm을 통한 설치로 진행한다.

Open WebUI 차트 내 Ollama가 내장되어 있어 따로 Ollama 차트를 받을 필요는 없다.

 

추가적으로 본 글에선 GPU자원을 사용할 예정이고 web-ui는 metal-lb를 통해 loadBalancer 형태의 서비스로 만들 예정이다.

 

1. helm repo 추가 및 tgz 다운로드

helm repo add open-webui https://helm.openwebui.com
helm repo update
helm pull open-webui/open-webui
-rw-r--r--. 1 root root 313362 Feb 24 00:11 open-webui-5.19.0.tgz

 

2. tgz 압축해제 및 values.yaml 수정 (기본으로 아무 수정 없이 설치해도 괜찮습니다.)

tar -zxvf open-webui-5.19.0.tgz
cd open-webui

ls -alth
total 56K
drwxr-xr-x. 4 root root  179 Feb 24 00:18 .
drwxr-xr-x. 4 root root   57 Feb 24 00:16 ..
-rw-r--r--. 1 root root 8.9K Feb 19 02:05 values.yaml
drwxr-xr-x. 6 root root   62 Feb 18 19:49 charts
drwxr-xr-x. 2 root root 4.0K Feb 18 19:49 templates
-rw-r--r--. 1 root root  464 Feb 18 12:48 Chart.lock
-rw-r--r--. 1 root root 1.2K Feb 18 12:48 Chart.yaml
-rw-r--r--. 1 root root  381 Feb 18 12:48 .helmignore
-rw-r--r--. 1 root root  11K Feb 18 12:48 README.md
-rw-r--r--. 1 root root  799 Feb 18 12:48 README.md.gotmpl
-rw-r--r--. 1 root root 9.0K Feb 18 12:48 values-gke-min.yaml
vim values.yaml

 

2-1. values.yaml 전문 (StorageClass, GPU, Redis는 필수는 아닙니다.)

더보기
nameOverride: ""
namespaceOverride: ""

ollama:
  enabled: true
  fullnameOverride: "open-webui-ollama"
  #gpu:
  #  enabled: true
  #  type: 'nvidia'
  #  number: 1
  #models:
  #  pull:
  #    - llama3
  #  run:
  #    - llama3
  #runtimeClassName: nvidia
  #persistentVolume:
  #  enabled: true
  #  volumeName: "example-pre-existing-pv-created-by-smb-csi"

pipelines:
  # -- Automatically install Pipelines chart to extend Open WebUI functionality using Pipelines: https://github.com/open-webui/pipelines
  enabled: true
  # -- This section can be used to pass required environment variables to your pipelines (e.g. Langfuse hostname)
  extraEnvVars: []

tika:
  # -- Automatically install Apache Tika to extend Open WebUI
  enabled: false

# -- A list of Ollama API endpoints. These can be added in lieu of automatically installing the Ollama Helm chart, or in addition to it.
ollamaUrls: []

# -- Disables taking Ollama Urls from `ollamaUrls`  list
ollamaUrlsFromExtraEnv: false

websocket:
  # -- Enables websocket support in Open WebUI with env `ENABLE_WEBSOCKET_SUPPORT`
  enabled: true
  # -- Specifies the websocket manager to use with env `WEBSOCKET_MANAGER`: redis (default)
  manager: redis
  # -- Specifies the URL of the Redis instance for websocket communication. Template with `redis://[:<password>@]<hostname>:<port>/<db>`
  url: redis://open-webui-redis:6379/0
  # -- Deploys a redis
  redis:
    # -- Enable redis installation
    enabled: true
    # -- Redis name
    name: open-webui-redis
    # -- Redis labels
    labels: {}
    # -- Redis annotations
    annotations: {}
    # -- Redis pod
    pods:
      # -- Redis pod annotations
      annotations: {}
    # -- Redis image
    image:
      repository: redis
      tag: 7.4.2-alpine3.21
      pullPolicy: IfNotPresent
    # -- Redis command (overrides default)
    command: []
    # -- Redis arguments (overrides default)
    args: []
    # -- Redis resources
    resources: {}
    # -- Redis service
    service:
      # -- Redis container/target port
      containerPort: 6379
      # -- Redis service type
      type: ClusterIP
      # -- Redis service labels
      labels: {}
      # -- Redis service annotations
      annotations: {}
      # -- Redis service port
      port: 6379
      # -- Redis service node port. Valid only when type is `NodePort`
      nodePort: ""

# -- Deploys a Redis cluster with subchart 'redis' from bitnami
redis-cluster:
  # -- Enable Redis installation
  enabled: false
  # -- Redis cluster name (recommended to be 'open-webui-redis')
  # - In this case, redis url will be 'redis://open-webui-redis-master:6379/0' or 'redis://[:<password>@]open-webui-redis-master:6379/0'
  fullnameOverride: open-webui-redis
  # -- Redis Authentication
  auth:
    # -- Enable Redis authentication (disabled by default). For your security, we strongly suggest that you switch to 'auth.enabled=true'
    enabled: false
  # -- Replica configuration for the Redis cluster
  replica:
    # -- Number of Redis replica instances
    replicaCount: 3

# -- Value of cluster domain
clusterDomain: cluster.local

annotations: {}
podAnnotations: {}
podLabels: {}
replicaCount: 1
# -- Strategy for updating the workload manager: deployment or statefulset
strategy: {}
# -- Open WebUI image tags can be found here: https://github.com/open-webui/open-webui
image:
  repository: ghcr.io/open-webui/open-webui
  tag: ""
  pullPolicy: "IfNotPresent"

serviceAccount:
  enable: true
  name: ""
  annotations: {}
  automountServiceAccountToken: false

# -- Configure imagePullSecrets to use private registry
# ref: <https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry>
imagePullSecrets: []
# imagePullSecrets:
# - name: myRegistryKeySecretName

# -- Probe for liveness of the Open WebUI container
# ref: <https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes>
livenessProbe: {}
# livenessProbe:
#   httpGet:
#     path: /health
#     port: http
#   failureThreshold: 1
#   periodSeconds: 10

# -- Probe for readiness of the Open WebUI container
# ref: <https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes>
readinessProbe: {}
# readinessProbe:
#   httpGet:
#     path: /health/db
#     port: http
#   failureThreshold: 1
#   periodSeconds: 10

# -- Probe for startup of the Open WebUI container
# ref: <https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes>
startupProbe: {}
# startupProbe:
#   httpGet:
#     path: /health
#     port: http
#   initialDelaySeconds: 30
#   periodSeconds: 5
#   failureThreshold: 20

resources: {}

copyAppData:
  resources: {}

managedCertificate:
  enabled: false
  name: "mydomain-chat-cert"  # You can override this name if needed
  domains:
    - chat.example.com # update to your real domain

ingress:
  enabled: false
  class: ""
  # -- Use appropriate annotations for your Ingress controller, e.g., for NGINX:  
  annotations: {}
  #   # Example for GKE Ingress
  #   kubernetes.io/ingress.class: "gce"
  #   kubernetes.io/ingress.global-static-ip-name: "open-webui-external-ip"   #  you need to create this address in GCP console
  #   # Force HTTP to redirect to HTTPS
  #   nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
  #   nginx.ingress.kubernetes.io/ssl-redirect: "true"
  #   nginx.ingress.kubernetes.io/permanent-redirect: "https://chat.example.com"
  #   networking.gke.io/managed-certificates: "mydomain-chat-cert"
  #   # nginx.ingress.kubernetes.io/rewrite-target: / 
  host: "chat.example.com"  # update to your real domain 
  additionalHosts: []
  tls: false
  existingSecret: ""
persistence:
  enabled: true
  size: 2Gi
  # -- Use existingClaim if you want to re-use an existing Open WebUI PVC instead of creating a new one
  existingClaim: ""
  # -- Subdirectory of Open WebUI PVC to mount. Useful if root directory is not empty.
  subPath: ""
  # -- If using multiple replicas, you must update accessModes to ReadWriteMany
  accessModes:
    - ReadWriteOnce
  storageClass: nfs-csi-115
  selector: {}
  annotations: {}

# -- Node labels for pod assignment.
nodeSelector: {}

# -- Tolerations for pod assignment
tolerations: []

# -- Affinity for pod assignment
affinity: {}

# -- Topology Spread Constraints for pod assignment
topologySpreadConstraints: []

# -- Service values to expose Open WebUI pods to cluster
service:
  type: LoadBalancer
  annotations: {}
  port: 80
  containerPort: 8080
  nodePort: ""
  labels: {}
  loadBalancerClass: ""

# -- OpenAI base API URL to use. Defaults to the Pipelines service endpoint when Pipelines are enabled, and "https://api.openai.com/v1" if Pipelines are not enabled and this value is blank
openaiBaseApiUrl: "https://api.openai.com/v1"

# -- OpenAI base API URLs to use. Overwrites the value in openaiBaseApiUrl if set
openaiBaseApiUrls: []
  # - "https://api.openai.com/v1"
  # - "https://api.company.openai.com/v1"

# -- Env vars added to the Open WebUI deployment. Most up-to-date environment variables can be found here: https://docs.openwebui.com/getting-started/env-configuration/
extraEnvVars:
  # -- Default API key value for Pipelines. Should be updated in a production deployment, or be changed to the required API key if not using Pipelines
  - name: OPENAI_API_KEY
    value: "0p3n-w3bu!"
  # valueFrom:
  #   secretKeyRef:
  #     name: pipelines-api-key
  #     key: api-key
  # - name: OPENAI_API_KEY
  #   valueFrom:
  #     secretKeyRef:
  #       name: openai-api-key
  #       key: api-key
  # - name: OLLAMA_DEBUG
  #   value: "1"

# -- Configure container volume mounts
# ref: <https://kubernetes.io/docs/tasks/configure-pod-container/configure-volume-storage/>
volumeMounts:
  initContainer: []
  # - name: ""
  #   mountPath: ""
  container: []
  # - name: ""
  #   mountPath: ""

# -- Configure pod volumes
# ref: <https://kubernetes.io/docs/tasks/configure-pod-container/configure-volume-storage/>
volumes: []
# - name: ""
#   configMap:
#     name: ""
# - name: ""
#   emptyDir: {}

# -- Configure pod security context
# ref: <https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-containe>
podSecurityContext:
  {}
  # fsGroupChangePolicy: Always
  # sysctls: []
  # supplementalGroups: []
  # fsGroup: 1001


# -- Configure container security context
# ref: <https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-containe>
containerSecurityContext:
  {}
  # runAsUser: 1001
  # runAsGroup: 1001
  # runAsNonRoot: true
  # privileged: false
  # allowPrivilegeEscalation: false
  # readOnlyRootFilesystem: false
  # capabilities:
  #   drop:
  #     - ALL
  # seccompProfile:
  #   type: "RuntimeDefault"

# -- Extra resources to deploy with Open WebUI
extraResources:
  []
  # - apiVersion: v1
  #   kind: ConfigMap
  #   metadata:
  #     name: example-configmap
  #   data:
    ##     example-key: example-value

3. GPU 자원 수정 (옵션)

vim charts/ollama/values.yaml

 

3-1. values.yaml 수정

더보기
# Default values for ollama-helm.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

# -- Number of replicas
replicaCount: 1

# Knative configuration
knative:
  # -- Enable Knative integration
  enabled: false
  # -- Knative service container concurrency
  containerConcurrency: 0
  # -- Knative service timeout seconds
  timeoutSeconds: 300
  # -- Knative service response start timeout seconds
  responseStartTimeoutSeconds: 300
  # -- Knative service idle timeout seconds
  idleTimeoutSeconds: 300

# Docker image
image:
  # -- Docker image registry
  repository: ollama/ollama

  # -- Docker pull policy
  pullPolicy: IfNotPresent

  # -- Docker image tag, overrides the image tag whose default is the chart appVersion.
  tag: ""

# -- Docker registry secret names as an array
imagePullSecrets: []

# -- String to partially override template  (will maintain the release name)
nameOverride: ""

# -- String to fully override template
fullnameOverride: ""

# -- String to fully override namespace
namespaceOverride: ""

# Ollama parameters
ollama:
  fullnameOverride: "open-webui-ollama"
  gpu:
    enabled: true
    type: 'nvidia'
    number: 1
    mig:
      enabled: false


  models:
    # -- List of models to pull at container startup
    # The more you add, the longer the container will take to start if models are not present
    # pull:
    #  - llama2
    #  - mistral
    pull: []

    # -- List of models to load in memory at container startup
    # run:
    #  - llama2
    #  - mistral
    run: []

    # -- List of models to create at container startup, there are two options
    # 1. Create a raw model
    # 2. Load a model from configMaps, configMaps must be created before and are loaded as volume in "/models" directory.
    # create:
    #  - name: llama3.1-ctx32768
    #    configMapRef: my-configmap
    #    configMapKeyRef: configmap-key
    #  - name: llama3.1-ctx32768
    #    template: |
    #      FROM llama3.1
    #      PARAMETER num_ctx 32768
    create: []

  # -- Add insecure flag for pulling at container startup
  insecure: false

  # -- Override ollama-data volume mount path, default: "/root/.ollama"
  mountPath: ""

# Service account
# ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
serviceAccount:
  # -- Specifies whether a service account should be created
  create: true

  # -- Automatically mount a ServiceAccount's API credentials?
  automount: true

  # -- Annotations to add to the service account
  annotations: {}

  # -- The name of the service account to use.
  # If not set and create is true, a name is generated using the fullname template
  name: ""

# -- Map of annotations to add to the pods
podAnnotations: {}

# -- Map of labels to add to the pods
podLabels: {}

# -- Pod Security Context
podSecurityContext: {}
  # fsGroup: 2000

# -- Container Security Context
securityContext: {}
  # capabilities:
  #  drop:
  #   - ALL
  # readOnlyRootFilesystem: true
  # runAsNonRoot: true
  # runAsUser: 1000

# -- Specify runtime class
runtimeClassName: ""

# Configure Service
service:

  # -- Service type
  type: ClusterIP

  # -- Service port
  port: 11434

  # -- Service node port when service type is 'NodePort'
  nodePort: 31434

  # -- Load Balancer IP address
  loadBalancerIP:

  # -- Annotations to add to the service
  annotations: {}

# Configure the ingress resource that allows you to access the
ingress:
  # -- Enable ingress controller resource
  enabled: false

  # -- IngressClass that will be used to implement the Ingress (Kubernetes 1.18+)
  className: ""

  # -- Additional annotations for the Ingress resource.
  annotations: {}
    # kubernetes.io/ingress.class: traefik
    # kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"

  # The list of hostnames to be covered with this ingress record.
  hosts:
    - host: ollama.local
      paths:
        - path: /
          pathType: Prefix

  # --  The tls configuration for hostnames to be covered with this ingress record.
  tls: []
  #  - secretName: chart-example-tls
  #    hosts:
  #      - chart-example.local

# Configure resource requests and limits
# ref: http://kubernetes.io/docs/user-guide/compute-resources/
resources:
  # -- Pod requests
  requests: {}
    # Memory request
    # memory: 4096Mi

    # CPU request
    # cpu: 2000m

  # -- Pod limit
  limits: {}
    # Memory limit
    # memory: 8192Mi

    # CPU limit
    # cpu: 4000m

# Configure extra options for liveness probe
# ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes
livenessProbe:
  # -- Enable livenessProbe
  enabled: true

  # -- Request path for livenessProbe
  path: /

  # -- Initial delay seconds for livenessProbe
  initialDelaySeconds: 60

  # -- Period seconds for livenessProbe
  periodSeconds: 10

  # -- Timeout seconds for livenessProbe
  timeoutSeconds: 5

  # -- Failure threshold for livenessProbe
  failureThreshold: 6

  # -- Success threshold for livenessProbe
  successThreshold: 1

# Configure extra options for readiness probe
# ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes
readinessProbe:
  # -- Enable readinessProbe
  enabled: true

  # -- Request path for readinessProbe
  path: /

  # -- Initial delay seconds for readinessProbe
  initialDelaySeconds: 30

  # -- Period seconds for readinessProbe
  periodSeconds: 5

  # -- Timeout seconds for readinessProbe
  timeoutSeconds: 3

  # -- Failure threshold for readinessProbe
  failureThreshold: 6

  # -- Success threshold for readinessProbe
  successThreshold: 1

# Configure autoscaling
autoscaling:
  # -- Enable autoscaling
  enabled: false

  # -- Number of minimum replicas
  minReplicas: 1

  # -- Number of maximum replicas
  maxReplicas: 100

  # -- CPU usage to target replica
  targetCPUUtilizationPercentage: 80

  # -- targetMemoryUtilizationPercentage: 80

# -- Additional volumes on the output Deployment definition.
volumes: []
# -- - name: foo
#   secret:
#     secretName: mysecret
#     optional: false

# -- Additional volumeMounts on the output Deployment definition.
volumeMounts: []
# -- - name: foo
#   mountPath: "/etc/foo"
#   readOnly: true

# -- Additional arguments on the output Deployment definition.
extraArgs: []

# -- Additional environments variables on the output Deployment definition.
# For extra OLLAMA env, please refer to https://github.com/ollama/ollama/blob/main/envconfig/config.go
extraEnv: []
#  - name: OLLAMA_DEBUG
#    value: "1"

# -- Additionl environment variables from external sources (like ConfigMap)
extraEnvFrom: []
#  - configMapRef:
#      name: my-env-configmap

# Enable persistence using Persistent Volume Claims
# ref: https://kubernetes.io/docs/concepts/storage/persistent-volumes/
persistentVolume:
  # -- Enable persistence using PVC
  enabled: true

  # -- Ollama server data Persistent Volume access modes
  # Must match those of existing PV or dynamic provisioner
  # Ref: http://kubernetes.io/docs/user-guide/persistent-volumes/
  accessModes:
    - ReadWriteOnce

  # -- Ollama server data Persistent Volume annotations
  annotations: {}

  # -- If you'd like to bring your own PVC for persisting Ollama state, pass the name of the
  # created + ready PVC here. If set, this Chart will not create the default PVC.
  # Requires server.persistentVolume.enabled: true
  existingClaim: ""

  # -- Ollama server data Persistent Volume size
  size: 30Gi

  # -- Ollama server data Persistent Volume Storage Class
  # If defined, storageClassName: <storageClass>
  # If set to "-", storageClassName: "", which disables dynamic provisioning
  # If undefined (the default) or set to null, no storageClassName spec is
  # set, choosing the default provisioner.  (gp2 on AWS, standard on
  # GKE, AWS & OpenStack)
  storageClass: nfs-csi

  # -- Ollama server data Persistent Volume Binding Mode
  # If defined, volumeMode: <volumeMode>
  # If empty (the default) or set to null, no volumeBindingMode spec is
  # set, choosing the default mode.
  volumeMode: ""

  # -- Subdirectory of Ollama server data Persistent Volume to mount
  # Useful if the volume's root directory is not empty
  subPath: ""

  # -- Pre-existing PV to attach this claim to
  # Useful if a CSI auto-provisions a PV for you and you want to always
  # reference the PV moving forward
  volumeName: ""

# -- Node labels for pod assignment.
nodeSelector: {}

# -- Tolerations for pod assignment
tolerations: []

# -- Affinity for pod assignment
affinity: {}

# -- Lifecycle for pod assignment (override ollama.models startup pull/run)
lifecycle: {}

# How to replace existing pods
updateStrategy:
  # -- Deployment strategy can be "Recreate" or "RollingUpdate". Default is Recreate
  type: "Recreate"

# -- Topology Spread Constraints for pod assignment
topologySpreadConstraints: {}

# -- Init containers to add to the pod
initContainers: []
# - name: startup-tool
#   image: alpine:3
#   command: [sh, -c]
#   args:
#     - echo init

# -- Use the host’s ipc namespace.
hostIPC: false

# -- Use the host’s pid namespace
hostPID: false

# -- Use the host's network namespace.
hostNetwork: false

# -- Extra K8s manifests to deploy
extraObjects: []
#  - apiVersion: v1
#    kind: PersistentVolume
#    metadata:
#      name: aws-efs
#    data:
#      key: "value"
#  - apiVersion: scheduling.k8s.io/v1
#    kind: PriorityClass
#    metadata:
#      name: high-priority
#    value: 1000000
#    globalDefault: false
#    description: "This priority class should be used for XYZ service pods only."

4. helm install

helm upgrade open-webui  --install -f values.yaml -n open-webui .
kubectl get pod,svc
NAME                                        READY   STATUS    RESTARTS   AGE
pod/open-webui-0                            1/1     Running   0          10m
pod/open-webui-ollama-668cd748c9-5hzs6      1/1     Running   0          4d22h
pod/open-webui-pipelines-78b44676f9-sllfx   1/1     Running   0          4d22h
pod/open-webui-redis-558f68d648-cb4kx       1/1     Running   0          10m

NAME                           TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)        AGE
service/open-webui             LoadBalancer   10.107.214.125   192.168.60.117   80:32410/TCP   4d22h
service/open-webui-ollama      ClusterIP      10.97.201.157    <none>           11434/TCP      4d22h
service/open-webui-pipelines   ClusterIP      10.110.26.156    <none>           9099/TCP       4d22h
service/open-webui-redis       ClusterIP      10.101.219.130   <none>           6379/TCP       10m

 

5. open webui 접속 (LoadBalancer가 아닐 시 NodePort로 접속)

 

5-1. 설정 -> 관리자 설정 -> 모델 -> 매니지 모델 -> 모델 다운로드 (옵션)

 

6. Open webui & Ollama 테스트

 

7. K8sGPT local-ai 연결

k8sgpt auth update --backend localai --baseurl http://Ollama-서비스-아이피:포트/v1 --model "다운 받은 모델"
k8sgpt auth update --backend localai --baseurl http://10.97.201.157:11434/v1 --model phi4

 

8. interactive 모드 모델 테스트

Input text: 안녕? 넌 한국말로 설명할 수 있어?

네, 물론입니다! 아래는 주어진 문서의 요약과 해결 방법을 한국어로 번역한 것입니다.

---

### 문제 요약

여러 개의 Validating Webhook 구성에서 서비스가 찾아지지 않는 오류가 발생하고 있습니다. 이 오류는 다양한 `kserve-webhook-server.validator`와 관련된 여러 유형의 리소스에 대해 반복적으로 나타납니다.

### 해결 방법

1. **서비스 존재 확인**:
   - 각 오류 메시지에서 언급된 서비스가 실제로 존재하는지 Kubernetes YAML 파일이나 다른 수단을 통해 확인합니다.
   
... 중략

7. **로그 검사**:
   - 문제가 지속되면 서비스와 웹훅의 로그를 확인하여 추가적인 오류 메시지나 단서를 찾습니다.

이러한 단계들을 통해 문제를 해결할 수 있기를 바랍니다. 추가적인 도움이 필요하면 언제든지 말씀해 주세요!

후기

이렇듯 local-ai를 연결하여 K8sGPT를 사용해 프라이빗 환경에서의 테스트가 정상적으로 종료되었다.

 


단점

로컬 모델이 가격적인 측면, 보안, 정보 유출 측면에서 유리해 보이긴 하나 이 또한 완벽하진 않다.

로컬 모델이 외부 AI만큼 빠르고 정확한 성능을 보여주기 위해선 GPU, RAM, SSD 등의 하드웨어적 자원이 충분히 받침 되어야 하며

AI 모델의 파인튜닝은 거의 필수적이다.

 

대규모 예산을 운용 가능한 회사는 문제없이 사용이 가능하지만, 작은 기업의 경우 하드웨어, AI 튜닝의 문제는 쉽게 해결하기 힘들다.

다만 작은 모델을 잘 튜닝하여 운영자에게 "도움" 정도를 줄 AI를 대시보드 상 녹여낸다면 꽤나 편리한 서비스가 될 것 같다.

 

잘못된 정보, 오류, 오타 등을 댓글로 알려주시면 감사하겠습니다.

728x90