MicroK8s для LLM та інших PoC з інтеграцією HTTPS.

pic

Це детальний покроковий посібник із розгортання Kubernetes кластера за допомогою microk8s на виділеній машині, спеціально призначеній для проектів proof-of-concept (PoC). Налаштування включає ключові компоненти, такі як:

  • Конфігурація HTTPS: Реалізована за допомогою Cert-Manager і Let’s Encrypt для реальної безпеки та надійності.
  • Мультидоменний Ingress: Підтримка кількох додатків або сервісів під одним контролером ingress.
  • Розгортання додатків: Гнучкі налаштування з використанням Docker-ізольованих додатків, що дозволяє підтримувати різні фреймворки та мови.
  • Автомасштабування: Налаштоване за допомогою Horizontal Pod Autoscalers (HPA) для ефективного оброблення змінних навантажень.

Відсутність роботи з helm chart не є помилкою, це частина стратегії навчання. Однак для розгортання додатків ви можете легко згенерувати простий шаблон helm, що покриває параметризацію.

1. Чому цей підхід?

A. Економія коштів

Використання MicroK8s є набагато дешевшою альтернативою гіпермасштабованим хмарним сервісам (AWS, GCP, Azure) при запуску PoC проектів. Ви уникаєте щомісячних або погодинних оплат за управлінські кластери Kubernetes в хмарі, при цьому все ще отримуєте повнофункціональне середовище Kubernetes на вашій локальній чи on-premise машині. Пристойну виділену машину на 128 ГБ з GPU можна орендувати за $150–200/місяць. В хмарі вам доведеться платити значно більше.

B. Реальне HTTPS для надійності

Налаштування HTTPS за допомогою Cert-Manager і Let’s Encrypt гарантує безпеку ваших проектів і підвищує їх привабливість для потенційних користувачів. Багато PoC проектів не отримують популярності через відсутність реальних стандартів розгортання, таких як HTTPS. Цей посібник гарантує, що ваш Kubernetes кластер буде максимально наближений до реального виробничого середовища, допомагаючи продемонструвати вашу роботу зацікавленим сторонам без компромісів у практиках.

C. Раннє виявлення перешкод

Розгортання додатків в реальному Kubernetes кластері на ранніх етапах життєвого циклу допомагає виявити потенційні проблеми, такі як:

  • Невідповідність конфігурацій
  • Проблеми з мережею
  • Обмеження в масштабуванні ресурсів

Цей проактивний підхід заощаджує час і забезпечує більш гладкий перехід від PoC до виробництва.

D. Гнучкість з фреймворками та мовами

Цей посібник використовує підхід з Docker-ізоляцією, що дозволяє розгортати додатки, написані на різних мовах і фреймворках. Чи то Streamlit, Chainlit, чи будь-яка інша технологія, Kubernetes дає можливість ефективно оркеструвати та керувати ними. Ви можете легко інтегрувати інструменти, написані на Python, JavaScript чи будь-якій іншій мові.

E. Демонстрація універсальності

З мультидоменним ingress і контейнеризованими розгортаннями ви можете одночасно запускати кілька незалежних PoC проектів на одному кластері. Наприклад:

  • Streamlit додаток для візуалізації даних
  • Chainlit чат-бот
  • API чи бекенд-сервіси, написані на Python, Node.js чи Go. Це робить таке налаштування ідеальним для

2. Налаштування Kubernetes кластера

Ці кроки автоматично виконуються за допомогою pulumi-скрипту. Тому ви можете одразу працювати з маніфестами.

  1. Встановіть microk8s:
sudo snap install microk8s --classic  
sudo snap install kubectl --classic
  1. Запустіть microk8s:
microk8s start  
microk8s status
  1. Увімкніть основні додатки (найкраще включати по черзі):
microk8s enable dns  
microk8s enable ingress  
microk8s enable storage
  1. Використовуйте metallb як вбудований балансувальник навантаження для microk8s

pic

3.

Розгортання контролера Ingress

Розгорніть контролер NGINX для обробки HTTP/HTTPS трафіку.

# ingress-nginx-controller.yaml  
# sync wave допомагає застосовувати маніфести в певному порядку  
# ingress-nginx-controller -> letsencrypt -> deployment/service -> ingress  
apiVersion: v1  
kind: Service  
metadata:  
 name: ingress-nginx-controller  
 namespace: ingress  
 annotations:  
 argocd.argoproj.io/sync-wave: "-1" # https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/  
spec:  
 type: LoadBalancer  
 ports:  
 - name: http  
 port: 80  
 targetPort: 80  
 protocol: TCP  
 - name: https  
 port: 443  
 targetPort: 443  
 protocol: TCP  
 selector:  
 name: nginx-ingress-microk8s

Застосуйте конфігурацію:

kubectl apply -f ingress-controller-service.yaml

4. Налаштування HTTPS з Cert-Manager

Cert-Manager автоматизує отримання сертифікатів за допомогою Let’s Encrypt.

  1. Встановіть Cert-Manager:
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.10.0/cert-manager.yamlconfigmap
  1. Створіть кластерний видавець і застосуйте його. Він відповідає за отримання https сертифікатів.
# cluster-issuer-lets-encrypt.yaml  
 apiVersion: cert-manager.io/v1  
 kind: ClusterIssuer  
 metadata:  
 name: letsencrypt-dev  
 namespace: default  
 annotations:  
 argocd.argoproj.io/sync-wave: "-1"   
 spec:  
 acme:  
 server: https://acme-v02.api.letsencrypt.org/directory  
 email: [email protected]  
 privateKeySecretRef:  
 name: letsencrypt-dev  
 solvers:  
 - http01:  
 ingress:  
 class: nginx
kubectl apply -f cluster-issuer-lets-encrypt.yaml

5. Розгортання додатку та сервісу

Ось приклад конфігурації для розгортання, включаючи сервіс, до якого звертається ingress. Дуже важливо не забути застосувати секрет з вашого "реєстру".

Для доступу до артефактного реєстру в Google Cloud ви отримуєте після створення секрету з обліковими даними сервісного акаунту, який ви налаштували. Якщо ваші образи публічні, цього робити не потрібно.

kubectl create secret docker-registry gcr-json-key \   
 --docker-server=europe-west3-docker.pkg.dev \  
 --docker-username=_json_key \  
 --docker-password="$(cat credentials.json)" \  
 [email protected]
# app101-deployment.yaml  
apiVersion: apps/v1  
kind: Deployment  
metadata:  
 name: app101-deployment  
 namespace: default  
spec:  
 replicas: 1  
 selector:  
 matchLabels:  
 app: app101  
 template:  
 metadata:  
 labels:  
 app: app101  
 spec:  
 containers:  
 - name: app101  
 image: your-docker-image:latest  
 ports:  
 - containerPort: 80  
 imagePullSecrets:  
 - name: gcr-json-key # Не потрібно, якщо ваші образи публічні.  
---  
apiVersion: v1  
kind: Service  
metadata:  
 name: app101-service  
 namespace: default  
spec:  
 selector:  
 app: app101  
 ports:  
 - protocol: TCP  
 port: 80  
 targetPort: 80  
 type: ClusterIP
kubectl apply -f app101-deplyoment.yaml

6. Додайте нові A records у реєстрації вашого домену

Я використовую AWS Route 53 для домену, але це завжди має бути схоже й на інших провайдерів. Просто додайте виділену IP-адресу з потрібним піддоменом.

pic

**6.

Конфігурація Ingress для кількох доменів

Налаштуйте правила ingress для кількох доменів:

# ingress.yaml  
apiVersion: networking.k8s.io/v1  
kind: Ingress  
metadata:  
 name: multi-domain-ingress  
 namespace: default  
 annotations:  
 kubernetes.io/ingress.class: "nginx"  
 cert-manager.io/cluster-issuer: "letsencrypt-dev"  
spec:  
 tls:  
 - hosts:  
 - landing-page.api101.net   
 - app101.api101.net  

 secretName: multi-domain-tls  
 rules:  
 - host: landing-page.api101.net  
 http:  
 paths:  
 - path: /  
 pathType: Prefix  
 backend:  
 service:  
 name: landing-page-service  
 port:  
 number: 80  
 - host: app101.api101.net  
 http:  
 paths:  
 - path: /  
 pathType: Prefix  
 backend:  
 service:  
 name: app101-service  
 port:  
 number: 8501
kubectl apply -f ingress.yaml

7. Використання Google Cloud

Відмінність при використанні хмари K8s кластеру в тому, що замість microk8s вам не потрібен ingress-nginx-controller! Ви можете почати в GCP з:

gcloud container clusters create my-cluster \  
 --region=europe-west3 \  
 --enable-autoscaling \  
 --min-nodes=1 --max-nodes=3
gcloud container clusters get-credentials my-cluster --region=europe-west3

8. ArgoCD

Я дуже рекомендую ArgoCD, і як тільки ви налаштуєте це, ви більше не захочете працювати без нього. Перевірте: https://argo-cd.readthedocs.io/en/stable/

Ось кілька порад, як почати:

kubectl create namespace argocd  
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml  
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "NodePort"}}'   
kubectl get svc -n argocd  
# Ось пароль для першого входу  
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

Тепер ви можете отримати доступ до GUI ArgoCD через IP та PORT.

kubectl get svc -n argocd
  • У налаштуваннях потрібно налаштувати ваш git репозиторій.
  • У розділі "Applications" налаштуйте ваш проєкт з репозиторію, зазначивши правильний шлях до маніфестів (infrastructure/manifests).

Якщо все буде працювати, це виглядатиме так, як на зображенні вгорі.

9. Ollama

Для ollama у нас є також конфігурація для деплойменту, сервісу та HPA, і для зручності все це в одному файлі.

  1. Працює без проблем з GPU від NVIDIA (microk8s enable nvidia)
  2. Для PV потрібно змінити NodeAffinity, якщо ви використовуєте інший StorageClass. Також переконайтеся, що на моделі достатньо місця!
    3.
    Стрес-тести у моєму списку завдань

URL хоста визначається в config-map (див. configmap)

Перевірте необхідні модифікації, які вам знадобляться.

# ollama-deplyoment.yaml  
apiVersion: apps/v1  
kind: Deployment  
metadata:  
 name: ollama-deployment  
 namespace: default  
 labels:  
 app: ollama  
 environment: production  
 annotations:  
 argocd.argoproj.io/sync-wave: "0"  
spec:  
 replicas: 2  
 selector:  
 matchLabels:  
 app: ollama  
 template:  
 metadata:  
 labels:  
 app: ollama  
 spec:  
 containers:  
 - name: ollama  
 image: ollama/ollama:latest  
 ports:  
 - containerPort: 11434  
 resources:  
 requests:  
 cpu: "500m"  
 memory: "1Gi"  
 #nvidia.com/gpu: 1  
 limits:  
 cpu: "650m"  
 memory: "2Gi"  
 #nvidia.com/gpu: 1  
 volumeMounts:  
 - name: ollama-data  
 mountPath: /root/.ollama  
 volumes:  
 - name: ollama-data  
 persistentVolumeClaim:  
 claimName: ollama-pvc  
---  
apiVersion: v1  
kind: PersistentVolumeClaim  
metadata:  
 name: ollama-pvc  
 namespace: default  
 annotations:  
 argocd.argoproj.io/sync-wave: "0"  
spec:  
 accessModes:  
 - ReadWriteOnce  
 storageClassName: "" # Залишити порожнім для ручного зв'язування  
 resources:  
 requests:  
 storage: 10Gi # Перевірте, скільки місця вам потрібно для моделей!  
---  
apiVersion: v1  
kind: PersistentVolume  
metadata:  
 name: ollama-pv  
 namespace: default  
 annotations:  
 argocd.argoproj.io/sync-wave: "0"  
spec:  
 capacity:  
 storage: 10Gi # Перевірте, скільки місця вам потрібно для моделей!  
 volumeMode: Filesystem  
 accessModes:  
 - ReadWriteOnce  
 persistentVolumeReclaimPolicy: Retain  
 storageClassName: "" # Відповідає PVC  
 local:  
 path: /home/ubuntu/.ollama # Змініть, якщо необхідно  
 nodeAffinity:  
 required:  
 nodeSelectorTerms:  
 - matchExpressions:  
 - key: kubernetes.io/hostname  
 operator: In  
 values:  
 - ip-172-31-16-98 # Вузол, де доступний PV, наприклад перевірте за допомогою "kubectl get nodes -o wide"  

---  
apiVersion: v1  
kind: Service  
metadata:  
 name: ollama-service  
 namespace: default  
 annotations:  
 argocd.argoproj.io/sync-wave: "0"  
spec:  
 selector:  
 app: ollama  
 type: NodePort  
 ports:  
 - protocol: TCP  
 port: 11434  
 targetPort: 11434  
 nodePort: 30000 # Опціонально, якщо ви хочете зробити сервіс доступним за межами кластера  
---  
apiVersion: autoscaling/v2  
kind: HorizontalPodAutoscaler  
metadata:  
 name: hpa-ollama  
 namespace: defaultconfigmap  
 annotations:  
 argocd.argoproj.io/sync-wave: "1"  
spec:  
 scaleTargetRef:  
 apiVersion: apps/v1  
 kind: Deployment  
 name: ollama-deployment  
 minReplicas: 2  
 maxReplicas: 5  
 metrics:  
 - type: Resource  
 resource:  
 name: cpu  
 target:  
 type: Utilization  
 averageUtilization: 65

Сервіс ollama-service не має моделей на початку, але за допомогою маніфесту Job це буде автоматично оброблено, коли сервіс буде готовий.

# ollama-init-job.yaml  
apiVersion: batch/v1  
kind: Job  
metadata:  
 name: ollama-init-job  
 namespace: default  
spec:  
 template:  
 spec:  
 containers:  
 - name: post-install  
 image: curlimages/curl:latest # Легкий образ curl  
 command: ["/bin/sh", "-c"]  
 args:  
 - |  
 echo "Очікування, поки сервіс стане доступним...";  
 while ! nc -z ollama-service 11434; do sleep 1; done;  
 echo "Сервіс доступний, відправляємо запити...";  
 curl http://ollama-service:11434/api/pull -d '{"model": "llama3.2:1b"}'  
 curl http://ollama-service:11434/api/pull -d '{"model": "llama3.2:3b"}'  
 echo "Запити виконано.";  
 restartPolicy: Never  
 backoffLimit: 4

10.

Додаток

Генерація Docker-образу автоматично обробляється за допомогою GitHub Actions (див. github-actions).

Для тестування підходу я використав EC2 інстанс, створений за допомогою Pulumi (див. ec2-build).

Перекладено з: MicroK8s for LLM- and other PoC’s with https integration.

Leave a Reply

Your email address will not be published. Required fields are marked *