Перейти к содержимому

Примеры развёртывания в Kubernetes

Здесь представлены готовые к продакшену манифесты Kubernetes для развёртывания NORA.

Окно терминала
# Deploy with default configuration
kubectl apply -k .
# Verify deployment
kubectl get pods -n nora-system
kubectl get svc -n nora-system

  • namespace.yaml — определение Namespace
  • pvc.yaml — PersistentVolumeClaim для хранилища
  • deployment.yaml — Deployment NORA
  • service.yaml — Service (ClusterIP)
  • ingress-nginx.yaml — Ingress для nginx
  • ingress-contour.yaml — HTTPProxy для Contour
  • configmap.yaml — конфигурация (необязательно)
  • secret.yaml — секреты (необязательно)
  • kustomization.yaml — оверлей Kustomize

apiVersion: v1
kind: Namespace
metadata:
name: nora-system
labels:
name: nora-system

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nora-storage
namespace: nora-system
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
storageClassName: fast-ssd # Adjust to your storage class

apiVersion: apps/v1
kind: Deployment
metadata:
name: nora
namespace: nora-system
labels:
app: nora
spec:
replicas: 1 # NORA does not support multi-replica yet
strategy:
type: Recreate # Required for RWO volumes
selector:
matchLabels:
app: nora
template:
metadata:
labels:
app: nora
spec:
containers:
- name: nora
image: ghcr.io/getnora-io/nora:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 4000
protocol: TCP
env:
# Storage
- name: NORA_STORAGE_PATH
value: /data
# Rate Limits (production values)
- name: NORA_RATE_LIMIT_UPLOAD_RPS
value: "2000"
- name: NORA_RATE_LIMIT_UPLOAD_BURST
value: "5000"
- name: NORA_RATE_LIMIT_GENERAL_RPS
value: "1000"
- name: NORA_RATE_LIMIT_GENERAL_BURST
value: "2000"
# Logging
- name: NORA_LOG_LEVEL
value: info
- name: NORA_LOG_FORMAT
value: json
# Metrics
- name: NORA_METRICS_ENABLED
value: "true"
volumeMounts:
- name: storage
mountPath: /data
resources:
requests:
cpu: 500m
memory: 256Mi
limits:
cpu: 2000m
memory: 1Gi
livenessProbe:
httpGet:
path: /health
port: 4000
initialDelaySeconds: 10
periodSeconds: 30
timeoutSeconds: 5
readinessProbe:
httpGet:
path: /health
port: 4000
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
capabilities:
drop:
- ALL
volumes:
- name: storage
persistentVolumeClaim:
claimName: nora-storage
# Optional: Specify node affinity for SSD nodes
# affinity:
# nodeAffinity:
# requiredDuringSchedulingIgnoredDuringExecution:
# nodeSelectorTerms:
# - matchExpressions:
# - key: storage-type
# operator: In
# values:
# - ssd

apiVersion: v1
kind: Service
metadata:
name: nora
namespace: nora-system
labels:
app: nora
spec:
type: ClusterIP
ports:
port: 4000
targetPort: 4000
- name: http
port: 4000
targetPort: 4000
protocol: TCP
selector:
app: nora

Для nginx Ingress Controller:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nora
namespace: nora-system
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/proxy-body-size: "0" # Unlimited upload size
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
spec:
ingressClassName: nginx
tls:
- hosts:
- nora.example.com
secretName: nora-tls
rules:
- host: nora.example.com
http:
paths:
# Docker Registry API
- path: /v2
pathType: Prefix
backend:
service:
name: nora
port:
number: 4000
# NORA API/UI
- path: /api
pathType: Prefix
backend:
service:
name: nora
port:
number: 4000
# Root (registry)
- path: /
pathType: Prefix
backend:
service:
name: nora
port:
number: 4000

Для Contour Ingress Controller (HTTPProxy):

apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
name: nora
namespace: nora-system
spec:
virtualhost:
fqdn: nora.example.com
tls:
secretName: nora-tls
routes:
# Docker Registry API
- conditions:
- prefix: /v2
services:
- name: nora
port: 4000
timeoutPolicy:
response: 10m # Large uploads need long timeout
# NORA API
- conditions:
- prefix: /api
services:
- name: nora
port: 4000
# Metrics (restricted)
- conditions:
- prefix: /metrics
services:
- name: nora
port: 4000
# Optional: IP allowlist
# ipAllowPolicy:
# - cidr: 10.0.0.0/8
# Default route (registry)
- conditions:
- prefix: /
services:
- name: nora
port: 4000

Для конфигурации на основе YAML:

apiVersion: v1
kind: ConfigMap
metadata:
name: nora-config
namespace: nora-system
data:
config.yaml: |
storage:
type: local
path: /data
rate_limits:
upload:
rps: 2000
burst: 5000
general:
rps: 1000
burst: 2000
logging:
level: info
format: json
metrics:
enabled: true

Монтирование в Deployment:

volumes:
- name: config
configMap:
name: nora-config
volumeMounts:
- name: config
mountPath: /etc/nora/config.yaml
subPath: config.yaml

Для учётных данных аутентификации:

apiVersion: v1
kind: Secret
metadata:
name: nora-auth
namespace: nora-system
type: Opaque
stringData:
username: admin
password: changeme

Ссылка в Deployment:

env:
- name: NORA_AUTH_TYPE
value: basic
- name: NORA_AUTH_USERNAME
valueFrom:
secretKeyRef:
name: nora-auth
key: username
- name: NORA_AUTH_PASSWORD
valueFrom:
secretKeyRef:
name: nora-auth
key: password

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: nora-system
resources:
- namespace.yaml
- pvc.yaml
- deployment.yaml
- service.yaml
- ingress-nginx.yaml # Or ingress-contour.yaml
# Optional
# - configmap.yaml
# - secret.yaml
commonLabels:
app.kubernetes.io/name: nora
app.kubernetes.io/component: registry
images:
- name: ghcr.io/getnora-io/nora
newTag: latest # Pin to specific version in production

Окно терминала
# Create namespace
kubectl apply -f namespace.yaml
# Deploy storage
kubectl apply -f pvc.yaml
# Deploy NORA
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
# Deploy ingress (choose one)
kubectl apply -f ingress-nginx.yaml
# OR
kubectl apply -f ingress-contour.yaml
# Wait for rollout
kubectl rollout status deployment/nora -n nora-system
Окно терминала
# Deploy everything
kubectl apply -k .
# Verify
kubectl get all -n nora-system
Окно терминала
helm install nora . -n nora-system --create-namespace

Окно терминала
# Check pod status
kubectl get pods -n nora-system
# Check logs
kubectl logs -n nora-system -l app=nora -f
# Check service
kubectl get svc -n nora-system
# Test from inside cluster
kubectl run -it --rm debug --image=curlimages/curl --restart=Never -- \
curl http://nora.nora-system.svc.cluster.local:4000/v2/
# Test from outside (after ingress)
curl https://nora.example.com/v2/

Окно терминала
docker login nora.example.com
docker tag myapp:latest nora.example.com/myapp:latest
docker push nora.example.com/myapp:latest
Окно терминала
# Create secret
kubectl create secret docker-registry nora-registry \
--docker-server=nora.example.com \
--docker-username=admin \
--docker-password=changeme \
-n default
# Use in pod
spec:
imagePullSecrets:
- name: nora-registry
containers:
- name: myapp
image: nora.example.com/myapp:latest

Плюсы:

  • Быстрое
  • Простое

Минусы:

  • Не масштабируется
  • Под привязан к конкретному узлу

Лучше всего подходит для: Однонодового кластера, разработки

Плюсы:

  • Общий доступ между узлами
  • Простое резервное копирование

Минусы:

  • Сетевая задержка
  • Единая точка отказа

Лучше всего подходит для: Небольших кластеров, локальной инфраструктуры

Плюсы:

  • Высокая доступность
  • Неограниченная ёмкость
  • PVC не требуется

Минусы:

  • Зависимость от сети
  • Стоимость

Конфигурация:

env:
- name: NORA_STORAGE_TYPE
value: s3
- name: NORA_S3_BUCKET
value: nora-registry
- name: NORA_S3_REGION
value: us-east-1
- name: NORA_S3_ENDPOINT
value: https://s3.amazonaws.com
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: s3-creds
key: access-key-id
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: s3-creds
key: secret-access-key

Лучше всего подходит для: Продакшена, мультирегиональных развёртываний


apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: nora
namespace: nora-system
spec:
selector:
matchLabels:
app: nora
endpoints:
- port: api
path: /metrics
interval: 30s

См. руководство по мониторингу для получения JSON дашборда.


Проблема: под застрял в состоянии Pending

Окно терминала
kubectl describe pod -n nora-system -l app=nora

Проверьте статус PVC и affinity узлов.

Проблема: CrashLoopBackOff

Окно терминала
kubectl logs -n nora-system -l app=nora --previous

Проверьте права доступа к томам и конфигурацию.

Проблема: 404 на /v2/

Проверьте конфигурацию Ingress и эндпоинты сервиса:

Окно терминала
kubectl get endpoints -n nora-system
kubectl describe ingress nora -n nora-system

  1. Включите аутентификацию (базовую или OIDC)
  2. Используйте NetworkPolicies для ограничения доступа
  3. Включите Pod Security Standards
  4. Регулярно выполняйте ротацию учётных данных
  5. Сканируйте образ NORA на уязвимости
  6. Используйте файловую систему только для чтения где возможно
  7. Ограничьте потребление ресурсов с помощью ResourceQuotas