Ollama 및 Open-WebUI를 사용하여 Gemma 배포

GDC 샌드박스 AI 최적화 SKU에 포함된 엔터프라이즈급 NVIDIA GPU를 사용하면 생성형 AI와 같은 까다로운 AI 학습 및 추론 애플리케이션을 개발하고 테스트할 수 있습니다.

Gemma는 Gemini 기술을 기반으로 하는 경량 대규모 언어 모델입니다. 이 튜토리얼 가이드에서는 GDC Sandbox에서 OllamaOpen-WebUI를 사용하여 Gemma를 배포하는 방법을 보여주며 목표는 다음과 같습니다.

  • GPU가 있는 AI 최적화 GDC Sandbox에 Gemma 모델을 사용하여 Ollama를 배포합니다.
  • Open-WebUI 인터페이스를 통해 비공개 엔드포인트에서 Ollama 서비스에 프롬프트를 보냅니다.

시작하기 전에

GDC Sandbox의 GPU는 org-infra 클러스터에 포함되어 있습니다.

  • 조직 인프라 클러스터에 대해 명령어를 실행하려면 클러스터 작업에 설명된 대로 org-1-infra 클러스터의 kubeconfig가 있어야 합니다.

    • gdcloud 명령줄로 구성 및 인증
    • 조직 인프라 클러스터의 kubeconfig 파일을 생성하고 경로를 환경 변수 KUBECONFIG에 할당합니다.
  • 사용자에게 sandbox-gpu-project 프로젝트에 sandbox-gpu-admin 역할이 할당되어 있는지 확인합니다. 기본적으로 역할은 platform-admin 사용자에게 할당됩니다. platform-admin로 로그인하고 다음 명령어를 실행하여 다른 사용자에게 역할을 할당할 수 있습니다.

    kubectl --kubeconfig ${KUBECONFIG} create rolebinding ${NAME} --role=sandbox-gpu-admin \
    --user=${USER} --namespace=sandbox-gpu-project
    
  • Artifact Registry 사용에 설명된 대로 Artifact Registry 저장소를 설정하고 Artifact Registry에 이미지를 푸시하고 가져올 수 있도록 로그인해야 합니다.

Ollama 및 Open-WebUI를 사용하여 Gemma 모델 배포

배포는 각각 특정 구성요소 또는 서비스를 정의하는 Kubernetes 구성 파일 (YAML 매니페스트)을 통해 오케스트레이션됩니다.

  1. Gemma가 미리 다운로드된 Dockerfile을 만듭니다.

     # Use an NVIDIA CUDA base image for GPU support
     FROM nvidia/cuda:12.3.1-cudnn8-devel-ubuntu22.04
    
     # Install Ollama
     # This uses Ollamas official installation script, which adds Ollama to /usr/local/bin
     RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates
     RUN curl -fsSL https://ollama.com/install.sh -o install.sh
     RUN chmod +x install.sh
     RUN ./install.sh && \
         rm -rf /var/lib/apt/lists/*
    
     # Set environment variables for Ollama (optional, but good practice)
     ENV OLLAMA_HOST="0.0.0.0"
     # ENV OLLAMA_MODELS="/usr/local/ollama/models" # Default is /root/.ollama
     # If you want to customize the model storage path within the container, set OLLAMA_MODELS
     # and then ensure you create and populate that directory. Default is usually fine for pre-downloaded.
    
     # --- Predownload Gemma Model ---
     # This step starts Ollama server in the background, pulls the model,
     # and then kills the server to allow the Docker build to continue.
     # This approach works around Docker''s RUN command limitations for services.
    
     RUN ollama serve & \
         sleep 5 && \
         # Give the Ollama server a moment to start up
         # Use --retry and --retry-connrefused to handle startup delays
         curl --retry 10 --retry-connrefused -s http://localhost:11434 || true && \
         echo "Attempting to pull gemma:7b..." && \
         ollama pull gemma:7b && \
         echo "Model pull complete. Cleaning up background Ollama process." && \
         pkill ollama || true # Gracefully kill the ollama serve process
    
     # Expose Ollama's default port
     EXPOSE 11434
    
     # Command to run Ollama server when the container starts
     CMD ["ollama", "serve"]
    
    
  1. Docker 이미지를 빌드하고 Artifact Registry 저장소에 업로드합니다.

    docker build -t ollama-gemma .
    docker tag ollama-gemma REGISTRY_REPOSITORY_URL/ollama-gemma:latest
    docker push REGISTRY_REPOSITORY_URL/ollama-gemma:latest
    

    다음을 바꿉니다.

    • REGISTRY_REPOSITORY_URL을 저장소 URL로 바꿉니다.
  2. Docker 사용자 인증 정보를 저장할 보안 비밀을 만듭니다.

    
    export SECRET=DOCKER_REGISTRY_SECRET
    export DOCKER_TEST_CONFIG=~/.docker/config.json 
    kubectl --kubeconfig ${KUBECONFIG}$ create secret docker-registry ${SECRET} --from-file=.dockerconfigjson=${DOCKER_TEST_CONFIG} -n sandbox-gpu-project
    

    다음을 바꿉니다.

    • DOCKER_REGISTRY_SECRET 보안 비밀 이름
  3. ollama-deployment.yaml 파일을 만들어 Ollama AI 엔진 배포를 정의합니다.

    Ollama 서버의 배포에는 GPU 하나가 필요합니다.

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        annotations:
          deployment.kubernetes.io/revision: "9"
        name: ollama
        namespace: sandbox-gpu-project
      spec:
        progressDeadlineSeconds: 600
        replicas: 1
        revisionHistoryLimit: 10
        selector:
          matchLabels:
            app: ollama
        strategy:
          rollingUpdate:
            maxSurge: 25%
            maxUnavailable: 25%
          type: RollingUpdate
        template:
          metadata:
            creationTimestamp: null
            labels:
              app: ollama
              egress.networking.gke.io/enabled: "true"
          spec:
            containers:
              - name: ollama
                image: REGISTRY_REPOSITORY_URL/ollama-gemma:latest
                imagePullPolicy: Always
                ports:
                  - containerPort: 11434
                    protocol: TCP
                resources:
                  limits:
                    nvidia.com/gpu-pod-NVIDIA_H100_80GB_HBM3: "1"
                  requests:
                    nvidia.com/gpu-pod-NVIDIA_H100_80GB_HBM3: "1"
                env:
                  - name: OLLAMA_HOST
                    value: 0.0.0.0
                  - name: OLLAMA_ORIGINS
                    value: http://localhost:8080,http://ollama-webui.ollama-llm.svc.cluster.local:8080,http://ollama-webui:8080
                securityContext:
                  seLinuxOptions:
                    type: unconfined_t
                terminationMessagePath: /dev/termination-log
                terminationMessagePolicy: File
            imagePullSecrets:
            - name: DOCKER_REGISTRY_SECRET
            dnsConfig:
              nameservers:
                - 8.8.8.8
            dnsPolicy: ClusterFirst
            restartPolicy: Always
            schedulerName: default-scheduler
            terminationGracePeriodSeconds: 30
    
    

    다음을 바꿉니다.

    • REGISTRY_REPOSITORY_URL: 저장소 URL입니다.
    • DOCKER_REGISTRY_SECRET: 보안 비밀의 이름입니다.
  4. Ollama 서버를 내부적으로 노출하는 ollama-service.yaml 파일을 만듭니다.

    apiVersion: v1
    kind: Service
    metadata:
      name: ollama
      namespace: sandbox-gpu-project
      annotations:
        metallb.universe.tf/ip-allocated-from-pool: lb-address-pool-0-ptleg
    spec:
      type: LoadBalancer
      selector:
        app: ollama
      ports:
        - port: 11434
          nodePort: 30450
      ipFamilyPolicy: SingleStack
      ipFamilies:
        - IPv4
      clusterIPs:
        - 10.1.122.216
      clusterIP: 10.1.122.216
    
  5. 매니페스트 적용

    kubectl --kubeconfig ${KUBECONFIG} apply -f ollama-deployment.yaml
    kubectl --kubeconfig ${KUBECONFIG} apply -f ollama-service.yaml
    
  6. ollama 포드가 실행 중인지 확인합니다.

    kubectl --kubeconfig ${KUBECONFIG} get deployments -n sandbox-gpu-project
    kubectl --kubeconfig ${KUBECONFIG} get service -n sandbox-gpu-project
    
  7. 출력에서 Ollama 서비스 OLLAMA_BASE_END_POINT의 외부 IP를 기록해 둡니다.

    kubectl --kubeconfig ${KUBECONFIG} get service ollama \
          -n sandbox-gpu-project -o jsonpath='{.status.loadBalancer.ingress[*].ip}'
    
  8. Open-WebUI 인터페이스를 배포할 openweb-ui-deployment.yaml 파일을 만듭니다.

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: ollama-webui
        namespace: sandbox-gpu-project
        labels:
          app: ollama-webui
        annotations:
          deployment.kubernetes.io/revision: "5"
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: ollama-webui
        strategy:
          type: RollingUpdate
          rollingUpdate:
            maxSurge: 25%
            maxUnavailable: 25%
        progressDeadlineSeconds: 600
        revisionHistoryLimit: 10
        template:
          metadata:
            labels:
              app: ollama-webui
            creationTimestamp: null
          spec:
            containers:
              - name: ollama-webui
                image: ghcr.io/open-webui/open-webui:main
                imagePullPolicy: IfNotPresent
                ports:
                  - name: http
                    containerPort: 8080
                    protocol: TCP
                env:
                  - name: OLLAMA_BASE_URL
                    value: OLLAMA_BASE_END_POINT
                  - name: PORT
                    value: "8080"
                terminationMessagePath: /dev/termination-log
                terminationMessagePolicy: File
            restartPolicy: Always
            dnsPolicy: ClusterFirst
            schedulerName: default-scheduler
            terminationGracePeriodSeconds: 30
    

    다음을 바꿉니다.

    • OLLAMA_BASE_END_POINT: Ollama 서비스의 외부 IP 주소입니다.
  9. ollama-webui-service.yaml 파일을 만들어 열린 webui 인터페이스를 외부에 노출합니다.

    apiVersion: v1
    kind: Service
    metadata:
      name: ollama-webui
      namespace: sandbox-gpu-project
      annotations:
        metallb.universe.tf/ip-allocated-from-pool: lb-address-pool-0-ptleg
    spec:
      type: LoadBalancer
      ipFamilyPolicy: SingleStack
      ipFamilies:
      - IPv4
      clusterIPs:
      - 10.1.104.52
      clusterIP: 10.1.104.52
      ports:
      - port: 80
        targetPort: 8080
        nodePort: 32351
      selector:
        app: ollama-webui
    
  10. 클러스터에 매니페스트 openweb-ui-deployment.yamlollama-webui-service.yaml을 적용합니다.

        kubectl --kubeconfig ${KUBECONFIG} apply -f openweb-ui-deployment.yaml
        kubectl --kubeconfig ${KUBECONFIG} apply -f ollama-webui-service.yaml
    
  11. 외부 IP 주소에서 인바운드 트래픽을 허용하는 프로젝트 네트워크 정책을 만듭니다.

    kubectl --kubeconfig ${KUBECONFIG} apply -f - <<EOF
    apiVersion: networking.global.gdc.goog/v1
    kind: ProjectNetworkPolicy
    metadata:
      namespace: sandbox-gpu-project
      name: allow-inbound-traffic-from-external
    spec:
      policyType: Ingress
      subject:
        subjectType: UserWorkload
      ingress:
      - from:
        - ipBlock:
            cidr: 0.0.0.0/0
    EOF
    
  12. 다음 명령어를 실행하여 Ollama 서비스의 외부 IP를 식별합니다. 이 값을 OPEN_WEB_UI_ENDPOINT로 대체하는 이후 단계에서 사용할 수 있도록 기록해 둡니다.

    kubectl --kubeconfig ${KUBECONFIG} get service -n sandbox-gpu-project
    
  13. Chrome을 열고 이전 단계에서 찾은 외부 IP 주소를 사용하여 URL을 입력합니다. 이제 Open Web UI 인터페이스를 통해 Gemma 모델과 상호작용할 수 있습니다.

    http://OPEN_WEB_UI_ENDPOINT/