Це детальний покроковий посібник із розгортання 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-скрипту. Тому ви можете одразу працювати з маніфестами.
- Встановіть microk8s:
sudo snap install microk8s --classic
sudo snap install kubectl --classic
- Запустіть microk8s:
microk8s start
microk8s status
- Увімкніть основні додатки (найкраще включати по черзі):
microk8s enable dns
microk8s enable ingress
microk8s enable storage
- Використовуйте metallb як вбудований балансувальник навантаження для microk8s
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.
- Встановіть Cert-Manager:
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.10.0/cert-manager.yamlconfigmap
- Створіть кластерний видавець і застосуйте його. Він відповідає за отримання 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-адресу з потрібним піддоменом.
**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, і для зручності все це в одному файлі.
- Працює без проблем з GPU від NVIDIA (microk8s enable nvidia)
- Для 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.