# PersistentVolumeClaim for YouMusic data (music, cache, etc.) apiVersion: v1 kind: PersistentVolume metadata: name: youmusic-data-pv spec: capacity: storage: 100Gi accessModes: - ReadWriteMany nfs: server: 192.168.1.5 path: "/fs/1000/nfs/k8s/you-music" --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: "youmusic-data-pvc" spec: storageClassName: "" volumeName: youmusic-data-pv accessModes: - ReadWriteMany resources: requests: storage: 100Gi --- # PersistentVolume for YouMusic database (local hostPath for better performance) apiVersion: v1 kind: PersistentVolume metadata: name: youmusic-db-pv spec: capacity: storage: 2Gi accessModes: - ReadWriteOnce hostPath: path: "/mnt/k8s/you-music-db" type: DirectoryOrCreate --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: "youmusic-db-pvc" spec: storageClassName: "" volumeName: youmusic-db-pv accessModes: - ReadWriteOnce resources: requests: storage: 2Gi --- # Deployment apiVersion: apps/v1 kind: Deployment metadata: name: youmusic labels: app: youmusic spec: selector: matchLabels: app: youmusic replicas: 1 # Single replica due to SQLite (ReadWriteOnce) strategy: type: Recreate # Prevent multiple pods accessing SQLite simultaneously template: metadata: labels: app: youmusic spec: volumes: - name: data persistentVolumeClaim: claimName: youmusic-data-pvc - name: db persistentVolumeClaim: claimName: youmusic-db-pvc # Init container to run database migrations initContainers: - name: youmusic-migrations image: "ghcr.io/wahyd4/you-music:{{IMAGE_VERSION}}" imagePullPolicy: Always workingDir: /app/backend command: - /bin/bash - -c - | echo "🔄 Running database migrations..." alembic upgrade head echo "✅ Migrations complete!" env: - name: PYTHONUNBUFFERED value: "1" - name: PYTHONPATH value: "/app/backend" - name: DATABASE_URL value: "sqlite+aiosqlite:////app/db/youmusic.db" - name: MUSIC_DIR value: "/app/data/music" - name: UPLOAD_DIR value: "/app/data/uploads" - name: TEMP_DIR value: "/app/data/temp" - name: BASE_DIR value: "/app" volumeMounts: - name: data mountPath: /app/data - name: db mountPath: /app/db containers: - name: youmusic image: "ghcr.io/wahyd4/you-music:{{IMAGE_VERSION}}" # Auto-updated by CI imagePullPolicy: Always workingDir: /app/backend command: - /bin/bash - -c - | echo "🚀 Starting YouMusic application..." exec uvicorn main:app --host 0.0.0.0 --port 8000 volumeMounts: - name: data mountPath: /app/data - name: db mountPath: /app/db env: - name: PYTHONUNBUFFERED value: "1" - name: PYTHONPATH value: "/app/backend" - name: DATABASE_URL value: "sqlite+aiosqlite:////app/db/youmusic.db" - name: MUSIC_DIR value: "/app/data/music" - name: LOCAL_MUSIC_DIR value: "/app/data/local-music" - name: UPLOAD_DIR value: "/app/data/uploads" - name: TEMP_DIR value: "/app/data/temp" - name: BASE_DIR value: "/app" - name: FFMPEG_LOCATION value: "/usr/bin/ffmpeg" # Optional: Set proxy if needed # - name: PROXY # value: "http://proxy:port" ports: - containerPort: 8000 name: http protocol: TCP livenessProbe: httpGet: path: / port: http initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3 readinessProbe: httpGet: path: / port: http initialDelaySeconds: 5 periodSeconds: 5 timeoutSeconds: 3 resources: requests: cpu: 200m memory: 512Mi limits: cpu: 2000m memory: 2048Mi # If using private registry, add imagePullSecrets imagePullSecrets: - name: github-image-pull-secret --- # Service apiVersion: v1 kind: Service metadata: name: youmusic labels: app: youmusic spec: type: ClusterIP ports: - port: 80 targetPort: http protocol: TCP name: web selector: app: youmusic --- # Ingress for main app apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: youmusic-ingress annotations: kubernetes.io/ingress.class: "nginx" kubernetes.io/tls-acme: "true" cert-manager.io/cluster-issuer: "letsencrypt-prod" # Increase upload size for large music files nginx.ingress.kubernetes.io/proxy-body-size: 500m nginx.ingress.kubernetes.io/proxy-read-timeout: "600" nginx.ingress.kubernetes.io/proxy-send-timeout: "600" # Optional: Enable authentication nginx.ingress.kubernetes.io/auth-url: "https://pass.junv.cc/oauth2/auth" nginx.ingress.kubernetes.io/auth-signin: "https://pass.junv.cc/oauth2/start?rd=https://$host$escaped_request_uri" spec: ingressClassName: nginx tls: - hosts: - music.junv.cc # Update with your domain secretName: youmusic-tls rules: - host: music.junv.cc # Update with your domain http: paths: - path: / pathType: Prefix backend: service: name: youmusic port: number: 80 --- # Ingress for public share links (no authentication) apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: youmusic-share-ingress annotations: kubernetes.io/ingress.class: "nginx" kubernetes.io/tls-acme: "true" cert-manager.io/cluster-issuer: "letsencrypt-prod" nginx.ingress.kubernetes.io/proxy-body-size: 100m nginx.ingress.kubernetes.io/proxy-read-timeout: "300" spec: ingressClassName: nginx tls: - hosts: - music.junv.cc # Update with your domain secretName: youmusic-tls rules: - host: music.junv.cc # Update with your domain http: paths: - path: /share pathType: Prefix backend: service: name: youmusic port: number: 80 --- # Ingress for public API v1 (no authentication - API key based) apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: youmusic-api-v1-ingress annotations: kubernetes.io/ingress.class: "nginx" kubernetes.io/tls-acme: "true" cert-manager.io/cluster-issuer: "letsencrypt-prod" nginx.ingress.kubernetes.io/proxy-body-size: 100m nginx.ingress.kubernetes.io/proxy-read-timeout: "300" spec: ingressClassName: nginx tls: - hosts: - music.junv.cc # Update with your domain secretName: youmusic-tls rules: - host: music.junv.cc # Update with your domain http: paths: - path: /api/v1 pathType: Prefix backend: service: name: youmusic port: number: 80