From 451042fc469a29b0f2cdd0161dbb39f0f11d5003 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Sep 2025 22:18:05 +0000 Subject: [PATCH 1/2] Initial plan From 35fa0810f8b11d3fda08196fed0ebc55d150ac3b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Sep 2025 22:30:03 +0000 Subject: [PATCH 2/2] Complete Kubernetes native deployment for FinalRip microservices Co-authored-by: Tohrusky <65994850+Tohrusky@users.noreply.github.com> --- deploy/k8s/COMPARISON.md | 338 ++++++++++++++++ deploy/k8s/README.md | 360 ++++++++++++++++++ deploy/k8s/base/asynqmon.yaml | 66 ++++ deploy/k8s/base/configmap.yaml | 46 +++ deploy/k8s/base/consul.yaml | 103 +++++ deploy/k8s/base/dashboard.yaml | 58 +++ deploy/k8s/base/ingress.yaml | 55 +++ deploy/k8s/base/kustomization.yaml | 35 ++ deploy/k8s/base/minio.yaml | 100 +++++ deploy/k8s/base/mongodb.yaml | 94 +++++ deploy/k8s/base/namespace.yaml | 7 + deploy/k8s/base/redis.yaml | 92 +++++ deploy/k8s/base/secrets.yaml | 16 + deploy/k8s/base/server.yaml | 78 ++++ deploy/k8s/base/worker-encode.yaml | 71 ++++ deploy/k8s/base/workers.yaml | 127 ++++++ deploy/k8s/deploy.sh | 93 +++++ deploy/k8s/helm/finalrip/.helmignore | 23 ++ deploy/k8s/helm/finalrip/Chart.yaml | 38 ++ deploy/k8s/helm/finalrip/templates/NOTES.txt | 22 ++ .../k8s/helm/finalrip/templates/_helpers.tpl | 62 +++ .../helm/finalrip/templates/deployment.yaml | 78 ++++ deploy/k8s/helm/finalrip/templates/hpa.yaml | 32 ++ .../k8s/helm/finalrip/templates/ingress.yaml | 43 +++ .../k8s/helm/finalrip/templates/service.yaml | 15 + .../finalrip/templates/serviceaccount.yaml | 13 + .../templates/tests/test-connection.yaml | 15 + deploy/k8s/helm/finalrip/values.yaml | 291 ++++++++++++++ .../overlays/development/kustomization.yaml | 28 ++ .../patches/development-patches.yaml | 48 +++ .../overlays/production/kustomization.yaml | 34 ++ .../patches/production-patches.yaml | 76 ++++ deploy/k8s/undeploy.sh | 56 +++ 33 files changed, 2613 insertions(+) create mode 100644 deploy/k8s/COMPARISON.md create mode 100644 deploy/k8s/README.md create mode 100644 deploy/k8s/base/asynqmon.yaml create mode 100644 deploy/k8s/base/configmap.yaml create mode 100644 deploy/k8s/base/consul.yaml create mode 100644 deploy/k8s/base/dashboard.yaml create mode 100644 deploy/k8s/base/ingress.yaml create mode 100644 deploy/k8s/base/kustomization.yaml create mode 100644 deploy/k8s/base/minio.yaml create mode 100644 deploy/k8s/base/mongodb.yaml create mode 100644 deploy/k8s/base/namespace.yaml create mode 100644 deploy/k8s/base/redis.yaml create mode 100644 deploy/k8s/base/secrets.yaml create mode 100644 deploy/k8s/base/server.yaml create mode 100644 deploy/k8s/base/worker-encode.yaml create mode 100644 deploy/k8s/base/workers.yaml create mode 100755 deploy/k8s/deploy.sh create mode 100644 deploy/k8s/helm/finalrip/.helmignore create mode 100644 deploy/k8s/helm/finalrip/Chart.yaml create mode 100644 deploy/k8s/helm/finalrip/templates/NOTES.txt create mode 100644 deploy/k8s/helm/finalrip/templates/_helpers.tpl create mode 100644 deploy/k8s/helm/finalrip/templates/deployment.yaml create mode 100644 deploy/k8s/helm/finalrip/templates/hpa.yaml create mode 100644 deploy/k8s/helm/finalrip/templates/ingress.yaml create mode 100644 deploy/k8s/helm/finalrip/templates/service.yaml create mode 100644 deploy/k8s/helm/finalrip/templates/serviceaccount.yaml create mode 100644 deploy/k8s/helm/finalrip/templates/tests/test-connection.yaml create mode 100644 deploy/k8s/helm/finalrip/values.yaml create mode 100644 deploy/k8s/overlays/development/kustomization.yaml create mode 100644 deploy/k8s/overlays/development/patches/development-patches.yaml create mode 100644 deploy/k8s/overlays/production/kustomization.yaml create mode 100644 deploy/k8s/overlays/production/patches/production-patches.yaml create mode 100755 deploy/k8s/undeploy.sh diff --git a/deploy/k8s/COMPARISON.md b/deploy/k8s/COMPARISON.md new file mode 100644 index 0000000..b68106b --- /dev/null +++ b/deploy/k8s/COMPARISON.md @@ -0,0 +1,338 @@ +# FinalRip 微服务启动方式对比:Docker Compose vs Kubernetes + +## 当前微服务架构分析 + +### 现有 Docker Compose 部署方式 + +#### 1. 快速部署(单机模式) +```bash +# 使用 lite 版本的 docker-compose +docker-compose -f deploy/docker-compose/lite/docker-compose.yml up -d +``` + +**特点:** +- 所有服务运行在单一主机上 +- 简单易用,适合开发和测试 +- 资源共享,性能受限于单机 + +#### 2. 分布式部署(多阶段) +```bash +# 第一步:基础服务 +docker-compose -f deploy/docker-compose/docker-compose-base.yml up -d + +# 第二步:核心服务 +docker-compose -f deploy/docker-compose/docker-compose-server.yml up -d + +# 第三步:编码工作节点(可多主机) +docker-compose -f deploy/docker-compose/docker-compose-encode.yml up -d +``` + +**特点:** +- 支持多主机分布式部署 +- 可以根据需要在不同主机部署编码节点 +- 手动管理节点,扩展性有限 + +### 服务组件分析 + +| 组件 | 功能 | 端口 | 依赖 | +|------|------|------|------| +| **finalrip-server** | API 服务器,任务调度 | 8848 | MongoDB, Redis, Consul | +| **finalrip-dashboard** | Web 前端界面 | 8989(80) | Server | +| **worker-cut** | 视频切割工作节点 | - | MongoDB, Redis, MinIO | +| **worker-merge** | 视频合并工作节点 | - | MongoDB, Redis, MinIO | +| **worker-encode** | 视频编码工作节点(GPU加速)| - | MongoDB, Redis, MinIO | +| **mongodb** | 数据库 | 27017 | - | +| **redis** | 队列系统 | 6379 | - | +| **minio** | 对象存储 | 9000, 9001 | - | +| **consul** | 配置管理 | 8500 | - | +| **asynqmon** | 队列监控 | 8080 | Redis | + +## Kubernetes 原生部署方案 + +### 优势对比 + +| 特性 | Docker Compose | Kubernetes | +|------|----------------|------------| +| **扩展性** | 手动扩展,有限 | 自动/手动扩展,无限制 | +| **高可用** | 单点故障 | 多副本,故障自恢复 | +| **负载均衡** | 简单轮询 | 智能负载均衡 | +| **服务发现** | 容器名称 | DNS + Service | +| **配置管理** | 环境变量/文件挂载 | ConfigMap + Secret | +| **存储管理** | 本地卷/NFS | 持久卷 + 存储类 | +| **网络隔离** | Docker 网络 | Network Policy | +| **监控** | 外部工具 | 原生监控支持 | +| **CI/CD** | 手动或简单脚本 | 成熟的 GitOps | + +### 1. 基础部署(Kustomize) + +```bash +# 开发环境 +kubectl apply -k deploy/k8s/overlays/development + +# 生产环境 +kubectl apply -k deploy/k8s/overlays/production +``` + +**特点:** +- 声明式配置 +- 环境差异化管理 +- 版本控制友好 + +### 2. Helm 部署 + +```bash +# 默认配置安装 +helm install finalrip deploy/k8s/helm/finalrip + +# 自定义配置安装 +helm install finalrip deploy/k8s/helm/finalrip -f custom-values.yaml + +# 升级 +helm upgrade finalrip deploy/k8s/helm/finalrip +``` + +**特点:** +- 参数化配置 +- 版本管理 +- 依赖管理 + +### 3. 快速部署脚本 + +```bash +# 一键部署 +./deploy/k8s/deploy.sh development + +# 一键清理 +./deploy/k8s/undeploy.sh +``` + +## 核心改进点 + +### 1. 配置管理改进 + +**Docker Compose 方式:** +```yaml +environment: + - FINALRIP_REMOTE_CONFIG_HOST=consul:8500 + - FINALRIP_DB_HOST=mongodb + - FINALRIP_REDIS_HOST=redis +``` + +**Kubernetes 方式:** +```yaml +# ConfigMap 集中管理 +apiVersion: v1 +kind: ConfigMap +metadata: + name: finalrip-config +data: + finalrip.yml: | + server: + port: 8848 + db: + host: mongodb + +# Secret 安全管理 +apiVersion: v1 +kind: Secret +metadata: + name: finalrip-secrets +data: + mongodb-password: MTIzNDU2 +``` + +### 2. 服务发现改进 + +**Docker Compose:** 依赖容器名称 +**Kubernetes:** 使用 Service + DNS + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: mongodb +spec: + selector: + app.kubernetes.io/name: mongodb + ports: + - port: 27017 +``` + +### 3. 存储管理改进 + +**Docker Compose:** 本地卷挂载 +```yaml +volumes: + - ./data/mongodb:/data/db +``` + +**Kubernetes:** 持久卷声明 +```yaml +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mongodb-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +``` + +### 4. 扩展性改进 + +**Docker Compose:** 手动扩展 +```bash +docker-compose scale worker-encode=3 +``` + +**Kubernetes:** 自动扩展 +```yaml +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: worker-encode-hpa +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: finalrip-worker-encode + minReplicas: 1 + maxReplicas: 10 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 +``` + +## 迁移路径 + +### 1. 渐进式迁移 + +```bash +# 阶段1:部署基础服务到 K8s +kubectl apply -f deploy/k8s/base/mongodb.yaml +kubectl apply -f deploy/k8s/base/redis.yaml +kubectl apply -f deploy/k8s/base/minio.yaml + +# 阶段2:迁移应用服务 +kubectl apply -f deploy/k8s/base/server.yaml +kubectl apply -f deploy/k8s/base/dashboard.yaml + +# 阶段3:迁移工作节点 +kubectl apply -f deploy/k8s/base/workers.yaml +``` + +### 2. 数据迁移 + +```bash +# 导出 Docker 卷数据 +docker run --rm -v finalrip_mongodb:/source -v $(pwd):/backup alpine tar czf /backup/mongodb.tar.gz -C /source . + +# 导入到 K8s PV +kubectl cp mongodb.tar.gz finalrip/mongodb-pod:/tmp/ +kubectl exec -it mongodb-pod -n finalrip -- tar xzf /tmp/mongodb.tar.gz -C /data/db +``` + +### 3. 配置迁移 + +```bash +# 从 Consul 导出配置 +docker exec finalrip-consul consul kv export > config-export.json + +# 创建 K8s ConfigMap +kubectl create configmap finalrip-config --from-file=finalrip.yml=./conf/finalrip.yml -n finalrip +``` + +## 运维优势 + +### 1. 监控和日志 + +**K8s 原生支持:** +```bash +# 查看所有 Pod 状态 +kubectl get pods -n finalrip + +# 查看服务日志 +kubectl logs -l app.kubernetes.io/name=finalrip-server -n finalrip + +# 实时监控资源 +kubectl top pods -n finalrip +``` + +### 2. 滚动更新 + +```bash +# 零停机更新 +kubectl set image deployment/finalrip-server server=lychee0/finalrip:server-v2 -n finalrip + +# 回滚 +kubectl rollout undo deployment/finalrip-server -n finalrip +``` + +### 3. 健康检查 + +```yaml +livenessProbe: + httpGet: + path: /ping + port: 8848 + initialDelaySeconds: 30 + periodSeconds: 10 +readinessProbe: + httpGet: + path: /ping + port: 8848 + initialDelaySeconds: 10 + periodSeconds: 5 +``` + +## 成本效益 + +### 资源利用率 +- **Docker Compose:** 静态资源分配 +- **Kubernetes:** 动态资源调度,提高利用率 + +### 维护成本 +- **Docker Compose:** 手动运维,容易出错 +- **Kubernetes:** 自动化运维,降低人工成本 + +### 扩展成本 +- **Docker Compose:** 需要手动添加节点 +- **Kubernetes:** 弹性扩展,按需付费 + +## 推荐部署策略 + +### 开发环境 +```bash +# 使用 Kustomize 开发覆盖层 +kubectl apply -k deploy/k8s/overlays/development +``` + +### 测试环境 +```bash +# 使用 Helm 进行参数化部署 +helm install finalrip-test deploy/k8s/helm/finalrip -f test-values.yaml +``` + +### 生产环境 +```bash +# 使用 Helm + GitOps +helm install finalrip-prod deploy/k8s/helm/finalrip -f production-values.yaml +``` + +## 总结 + +从 Docker Compose 迁移到 Kubernetes 原生部署,FinalRip 将获得: + +1. **更强的扩展性**:支持大规模分布式部署 +2. **更高的可用性**:故障自恢复和负载均衡 +3. **更好的运维体验**:声明式配置和自动化管理 +4. **更强的安全性**:网络隔离和访问控制 +5. **更好的可观测性**:原生监控和日志管理 + +这种转换不仅提供了更现代的部署方式,还为后续的云原生化发展奠定了基础。 \ No newline at end of file diff --git a/deploy/k8s/README.md b/deploy/k8s/README.md new file mode 100644 index 0000000..4e14ff9 --- /dev/null +++ b/deploy/k8s/README.md @@ -0,0 +1,360 @@ +# FinalRip Kubernetes Native Deployment + +This directory contains Kubernetes-native deployment configurations for FinalRip, a distributed video processing system. + +## Architecture Overview + +FinalRip consists of the following components: + +### Core Services +- **Server**: API server that handles requests and orchestrates tasks +- **Dashboard**: Web frontend for user interaction +- **Worker-Cut**: Cuts videos into clips for parallel processing +- **Worker-Merge**: Merges processed clips back into final video +- **Worker-Encode**: Processes video clips (GPU-accelerated) + +### Infrastructure Services +- **MongoDB**: Database for task and metadata storage +- **Redis**: Queue system for task distribution (via Asynq) +- **MinIO**: Object storage for video files +- **Consul**: Configuration management and service discovery +- **AsynqMon**: Queue monitoring interface + +## Deployment Options + +### 1. Quick Deployment with Kustomize + +For development environments: +```bash +# Apply base configuration +kubectl apply -k deploy/k8s/overlays/development + +# Or for production +kubectl apply -k deploy/k8s/overlays/production +``` + +### 2. Helm Chart Deployment + +```bash +# Install with default values +helm install finalrip deploy/k8s/helm/finalrip + +# Install with custom values +helm install finalrip deploy/k8s/helm/finalrip -f custom-values.yaml + +# Upgrade existing deployment +helm upgrade finalrip deploy/k8s/helm/finalrip +``` + +### 3. Manual Deployment + +```bash +# Apply each component individually +kubectl apply -f deploy/k8s/base/namespace.yaml +kubectl apply -f deploy/k8s/base/configmap.yaml +kubectl apply -f deploy/k8s/base/secrets.yaml +kubectl apply -f deploy/k8s/base/mongodb.yaml +kubectl apply -f deploy/k8s/base/redis.yaml +kubectl apply -f deploy/k8s/base/minio.yaml +kubectl apply -f deploy/k8s/base/consul.yaml +kubectl apply -f deploy/k8s/base/asynqmon.yaml +kubectl apply -f deploy/k8s/base/server.yaml +kubectl apply -f deploy/k8s/base/dashboard.yaml +kubectl apply -f deploy/k8s/base/workers.yaml +kubectl apply -f deploy/k8s/base/worker-encode.yaml +kubectl apply -f deploy/k8s/base/ingress.yaml +``` + +## Prerequisites + +### Required Kubernetes Features +- **Persistent Volumes**: For data storage +- **LoadBalancer/Ingress**: For external access +- **GPU Support** (optional): For encode workers + - NVIDIA Device Plugin + - GPU nodes with appropriate labels + +### Required Resources +- **Minimum**: 4 CPU cores, 8GB RAM, 100GB storage +- **Recommended**: 8 CPU cores, 16GB RAM, 500GB storage +- **GPU**: NVIDIA GPU for video encoding acceleration + +## Configuration + +### Environment-Specific Configurations + +#### Development +- Single replicas for all services +- Reduced resource requirements +- Debug logging enabled +- Local storage + +#### Production +- Multiple replicas for high availability +- Increased resource limits +- Production logging levels +- Persistent storage with proper backup +- SSL/TLS termination +- Resource monitoring + +### Custom Configuration + +1. **Via ConfigMap** (for application config): + ```yaml + apiVersion: v1 + kind: ConfigMap + metadata: + name: finalrip-config + data: + finalrip.yml: | + # Your custom configuration + ``` + +2. **Via Environment Variables**: + ```yaml + env: + - name: FINALRIP_DB_HOST + value: "your-mongodb-host" + - name: FINALRIP_REDIS_HOST + value: "your-redis-host" + ``` + +3. **Via Helm Values**: + ```yaml + # custom-values.yaml + server: + replicaCount: 3 + workers: + encode: + replicaCount: 5 + ``` + +## Storage Considerations + +### Persistent Volumes +- **MongoDB**: Requires persistent storage for database +- **Redis**: Optional persistence for queue durability +- **MinIO**: Primary storage for video files +- **Consul**: Configuration data persistence + +### Storage Classes +Configure appropriate storage classes based on your infrastructure: +- **Fast SSD**: For databases and active processing +- **Object Storage**: For video file storage +- **Network Storage**: For shared access across nodes + +## Networking + +### Service Discovery +All services use Kubernetes DNS for internal communication: +- `mongodb.finalrip.svc.cluster.local` +- `redis.finalrip.svc.cluster.local` +- `minio.finalrip.svc.cluster.local` +- `consul.finalrip.svc.cluster.local` + +### External Access +Configure ingress based on your environment: +- **Development**: NodePort or port-forward +- **Production**: Ingress with SSL/TLS + +### Required Ports +- **8848**: API Server +- **80**: Dashboard +- **8080**: Asynq Monitor +- **9000/9001**: MinIO API/Console +- **8500**: Consul UI + +## GPU Support + +For GPU-accelerated encoding: + +1. **Install NVIDIA Device Plugin**: + ```bash + kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/main/nvidia-device-plugin.yml + ``` + +2. **Label GPU Nodes**: + ```bash + kubectl label nodes accelerator=nvidia-tesla-gpu + ``` + +3. **Configure Worker-Encode**: + ```yaml + workers: + encode: + resources: + requests: + nvidia.com/gpu: 1 + limits: + nvidia.com/gpu: 1 + ``` + +## Scaling + +### Manual Scaling +```bash +# Scale server replicas +kubectl scale deployment finalrip-server --replicas=3 -n finalrip + +# Scale encode workers +kubectl scale deployment finalrip-worker-encode --replicas=5 -n finalrip +``` + +### Horizontal Pod Autoscaler +```yaml +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: finalrip-server-hpa +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: finalrip-server + minReplicas: 1 + maxReplicas: 10 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 +``` + +## Monitoring and Observability + +### Built-in Monitoring +- **AsynqMon**: Queue monitoring at `/asynq` +- **Consul UI**: Configuration management at `/consul` +- **MinIO Console**: Storage management at `/minio` + +### Additional Monitoring +Consider integrating with: +- **Prometheus**: Metrics collection +- **Grafana**: Visualization +- **ELK Stack**: Log aggregation +- **Jaeger**: Distributed tracing + +## Troubleshooting + +### Common Issues + +1. **Pod Startup Failures**: + ```bash + kubectl logs -n finalrip + kubectl describe pod -n finalrip + ``` + +2. **Storage Issues**: + ```bash + kubectl get pvc -n finalrip + kubectl describe pvc -n finalrip + ``` + +3. **Service Connectivity**: + ```bash + kubectl get svc -n finalrip + kubectl exec -it -n finalrip -- nslookup mongodb + ``` + +4. **GPU Issues**: + ```bash + kubectl get nodes -o yaml | grep nvidia + kubectl describe node + ``` + +### Health Checks +All services include health checks: +- **Liveness Probes**: Restart unhealthy containers +- **Readiness Probes**: Remove unhealthy pods from service + +## Security Considerations + +### Secrets Management +- Database passwords +- Object storage credentials +- API tokens + +### Network Policies +Implement network policies to restrict inter-pod communication: +```yaml +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: finalrip-network-policy +spec: + podSelector: + matchLabels: + app.kubernetes.io/part-of: finalrip + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchLabels: + app.kubernetes.io/part-of: finalrip +``` + +### RBAC +Configure Role-Based Access Control for service accounts. + +## Migration from Docker Compose + +### Key Differences + +1. **Service Discovery**: DNS-based instead of container names +2. **Configuration**: ConfigMaps/Secrets instead of environment files +3. **Storage**: Persistent Volumes instead of bind mounts +4. **Networking**: Services and Ingress instead of Docker networks +5. **Scaling**: Native Kubernetes scaling instead of Docker Compose scale + +### Migration Steps + +1. **Export existing data** from Docker Compose volumes +2. **Create PVCs** and import data +3. **Update configuration** for Kubernetes DNS +4. **Deploy services** using provided manifests +5. **Configure ingress** for external access +6. **Test functionality** and performance + +## Performance Tuning + +### Resource Allocation +- **CPU**: Adjust based on workload +- **Memory**: Monitor usage and adjust limits +- **GPU**: Optimize for video processing workloads + +### Storage Performance +- Use appropriate storage classes +- Consider local storage for temporary processing +- Implement storage tiering for different data types + +### Network Optimization +- Use appropriate service types +- Configure ingress for optimal routing +- Consider service mesh for advanced traffic management + +## Backup and Recovery + +### Database Backup +```bash +# MongoDB backup +kubectl exec -it mongodb-pod -n finalrip -- mongodump --out /backup + +# Copy backup from pod +kubectl cp finalrip/mongodb-pod:/backup ./mongodb-backup +``` + +### Configuration Backup +```bash +# Export current configuration +kubectl get configmap finalrip-config -n finalrip -o yaml > config-backup.yaml +kubectl get secret finalrip-secrets -n finalrip -o yaml > secrets-backup.yaml +``` + +### Disaster Recovery +1. **Regular backups** of persistent data +2. **Configuration versioning** in Git +3. **Infrastructure as Code** for cluster recreation +4. **Multi-region deployment** for high availability \ No newline at end of file diff --git a/deploy/k8s/base/asynqmon.yaml b/deploy/k8s/base/asynqmon.yaml new file mode 100644 index 0000000..e8ab912 --- /dev/null +++ b/deploy/k8s/base/asynqmon.yaml @@ -0,0 +1,66 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: asynqmon + namespace: finalrip + labels: + app.kubernetes.io/name: asynqmon + app.kubernetes.io/component: monitor +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: asynqmon + template: + metadata: + labels: + app.kubernetes.io/name: asynqmon + app.kubernetes.io/component: monitor + spec: + containers: + - name: asynqmon + image: hibiken/asynqmon:latest + ports: + - containerPort: 8080 + env: + - name: REDIS_ADDR + value: "redis:6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: finalrip-secrets + key: redis-password + resources: + requests: + memory: "128Mi" + cpu: "50m" + limits: + memory: "256Mi" + cpu: "100m" + livenessProbe: + httpGet: + path: / + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 5 +--- +apiVersion: v1 +kind: Service +metadata: + name: asynqmon + namespace: finalrip + labels: + app.kubernetes.io/name: asynqmon + app.kubernetes.io/component: monitor +spec: + selector: + app.kubernetes.io/name: asynqmon + ports: + - port: 8080 + targetPort: 8080 \ No newline at end of file diff --git a/deploy/k8s/base/configmap.yaml b/deploy/k8s/base/configmap.yaml new file mode 100644 index 0000000..945c26c --- /dev/null +++ b/deploy/k8s/base/configmap.yaml @@ -0,0 +1,46 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: finalrip-config + namespace: finalrip + labels: + app.kubernetes.io/name: finalrip + app.kubernetes.io/component: config +data: + finalrip.yml: | + server: + token: 114514 + name: EutropicAI-FinalRip + port: 8848 + mode: prod + + log: + level: debug + mode: + - console + - file + + db: + type: mongodb + host: mongodb + port: 27017 + username: root + password: 123456 + database: finalrip + ssl: false + + redis: + host: redis + port: 6379 + password: 123456 + poolSize: 1000 + + oss: + type: minio # minio, cos + endpoint: minio:9000 + accessKey: homo + secretKey: homo114514 + region: local + bucket: finalrip + ssl: false + hostnameImmutable: true \ No newline at end of file diff --git a/deploy/k8s/base/consul.yaml b/deploy/k8s/base/consul.yaml new file mode 100644 index 0000000..458c5f6 --- /dev/null +++ b/deploy/k8s/base/consul.yaml @@ -0,0 +1,103 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: consul-pvc + namespace: finalrip + labels: + app.kubernetes.io/name: consul + app.kubernetes.io/component: config +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: consul + namespace: finalrip + labels: + app.kubernetes.io/name: consul + app.kubernetes.io/component: config +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: consul + template: + metadata: + labels: + app.kubernetes.io/name: consul + app.kubernetes.io/component: config + spec: + containers: + - name: consul + image: consul:1.15 + ports: + - containerPort: 8500 + name: ui + - containerPort: 8300 + name: rpc + - containerPort: 8301 + name: serflan + - containerPort: 8302 + name: serfwan + command: + - consul + - agent + - -server + - -bootstrap + - -data-dir + - /consul + - -ui + - -bind + - 0.0.0.0 + - -client + - 0.0.0.0 + volumeMounts: + - name: consul-storage + mountPath: /consul + resources: + requests: + memory: "256Mi" + cpu: "100m" + limits: + memory: "512Mi" + cpu: "250m" + livenessProbe: + httpGet: + path: /v1/status/leader + port: 8500 + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /v1/status/leader + port: 8500 + initialDelaySeconds: 5 + periodSeconds: 5 + volumes: + - name: consul-storage + persistentVolumeClaim: + claimName: consul-pvc +--- +apiVersion: v1 +kind: Service +metadata: + name: consul + namespace: finalrip + labels: + app.kubernetes.io/name: consul + app.kubernetes.io/component: config +spec: + selector: + app.kubernetes.io/name: consul + ports: + - port: 8500 + targetPort: 8500 + name: ui + - port: 8300 + targetPort: 8300 + name: rpc \ No newline at end of file diff --git a/deploy/k8s/base/dashboard.yaml b/deploy/k8s/base/dashboard.yaml new file mode 100644 index 0000000..6778694 --- /dev/null +++ b/deploy/k8s/base/dashboard.yaml @@ -0,0 +1,58 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: finalrip-dashboard + namespace: finalrip + labels: + app.kubernetes.io/name: finalrip-dashboard + app.kubernetes.io/component: frontend +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: finalrip-dashboard + template: + metadata: + labels: + app.kubernetes.io/name: finalrip-dashboard + app.kubernetes.io/component: frontend + spec: + containers: + - name: dashboard + image: lychee0/finalrip:dashboard-dev + ports: + - containerPort: 80 + resources: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "256Mi" + cpu: "200m" + livenessProbe: + httpGet: + path: / + port: 80 + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: 80 + initialDelaySeconds: 5 + periodSeconds: 5 +--- +apiVersion: v1 +kind: Service +metadata: + name: finalrip-dashboard + namespace: finalrip + labels: + app.kubernetes.io/name: finalrip-dashboard + app.kubernetes.io/component: frontend +spec: + selector: + app.kubernetes.io/name: finalrip-dashboard + ports: + - port: 80 + targetPort: 80 \ No newline at end of file diff --git a/deploy/k8s/base/ingress.yaml b/deploy/k8s/base/ingress.yaml new file mode 100644 index 0000000..3d78bc5 --- /dev/null +++ b/deploy/k8s/base/ingress.yaml @@ -0,0 +1,55 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: finalrip-ingress + namespace: finalrip + labels: + app.kubernetes.io/name: finalrip + app.kubernetes.io/component: ingress + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / + nginx.ingress.kubernetes.io/ssl-redirect: "false" + nginx.ingress.kubernetes.io/proxy-body-size: "100m" + nginx.ingress.kubernetes.io/proxy-read-timeout: "600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "600" +spec: + ingressClassName: nginx # Adjust based on your ingress controller + rules: + - host: finalrip.local # Change to your domain + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: finalrip-dashboard + port: + number: 80 + - path: /api + pathType: Prefix + backend: + service: + name: finalrip-server + port: + number: 8848 + - path: /asynq + pathType: Prefix + backend: + service: + name: asynqmon + port: + number: 8080 + - path: /minio + pathType: Prefix + backend: + service: + name: minio + port: + number: 9001 + - path: /consul + pathType: Prefix + backend: + service: + name: consul + port: + number: 8500 \ No newline at end of file diff --git a/deploy/k8s/base/kustomization.yaml b/deploy/k8s/base/kustomization.yaml new file mode 100644 index 0000000..6dd321b --- /dev/null +++ b/deploy/k8s/base/kustomization.yaml @@ -0,0 +1,35 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +metadata: + name: finalrip-base + +resources: +- namespace.yaml +- configmap.yaml +- secrets.yaml +- mongodb.yaml +- redis.yaml +- minio.yaml +- consul.yaml +- asynqmon.yaml +- server.yaml +- dashboard.yaml +- workers.yaml +- worker-encode.yaml +- ingress.yaml + +commonLabels: + app.kubernetes.io/part-of: finalrip + +images: +- name: lychee0/finalrip:server-dev + newTag: latest +- name: lychee0/finalrip:dashboard-dev + newTag: latest +- name: lychee0/finalrip:worker-cut-dev + newTag: latest +- name: lychee0/finalrip:worker-merge-dev + newTag: latest +- name: lychee0/finalrip:worker-encode-cuda-dev + newTag: latest \ No newline at end of file diff --git a/deploy/k8s/base/minio.yaml b/deploy/k8s/base/minio.yaml new file mode 100644 index 0000000..5cf488c --- /dev/null +++ b/deploy/k8s/base/minio.yaml @@ -0,0 +1,100 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: minio-pvc + namespace: finalrip + labels: + app.kubernetes.io/name: minio + app.kubernetes.io/component: storage +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: minio + namespace: finalrip + labels: + app.kubernetes.io/name: minio + app.kubernetes.io/component: storage +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: minio + template: + metadata: + labels: + app.kubernetes.io/name: minio + app.kubernetes.io/component: storage + spec: + containers: + - name: minio + image: bitnami/minio:2024.7.13 + ports: + - containerPort: 9000 + name: api + - containerPort: 9001 + name: console + env: + - name: MINIO_ROOT_USER + valueFrom: + secretKeyRef: + name: finalrip-secrets + key: minio-access-key + - name: MINIO_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: finalrip-secrets + key: minio-secret-key + - name: MINIO_DEFAULT_BUCKETS + value: "finalrip:public" + volumeMounts: + - name: minio-storage + mountPath: /bitnami/minio/data + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "1Gi" + cpu: "500m" + livenessProbe: + httpGet: + path: /minio/health/live + port: 9000 + initialDelaySeconds: 60 + periodSeconds: 20 + readinessProbe: + httpGet: + path: /minio/health/ready + port: 9000 + initialDelaySeconds: 10 + periodSeconds: 5 + volumes: + - name: minio-storage + persistentVolumeClaim: + claimName: minio-pvc +--- +apiVersion: v1 +kind: Service +metadata: + name: minio + namespace: finalrip + labels: + app.kubernetes.io/name: minio + app.kubernetes.io/component: storage +spec: + selector: + app.kubernetes.io/name: minio + ports: + - port: 9000 + targetPort: 9000 + name: api + - port: 9001 + targetPort: 9001 + name: console \ No newline at end of file diff --git a/deploy/k8s/base/mongodb.yaml b/deploy/k8s/base/mongodb.yaml new file mode 100644 index 0000000..9729987 --- /dev/null +++ b/deploy/k8s/base/mongodb.yaml @@ -0,0 +1,94 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mongodb-pvc + namespace: finalrip + labels: + app.kubernetes.io/name: mongodb + app.kubernetes.io/component: database +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mongodb + namespace: finalrip + labels: + app.kubernetes.io/name: mongodb + app.kubernetes.io/component: database +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: mongodb + template: + metadata: + labels: + app.kubernetes.io/name: mongodb + app.kubernetes.io/component: database + spec: + containers: + - name: mongodb + image: mongo:8.0.0-rc13-jammy + ports: + - containerPort: 27017 + env: + - name: MONGO_INITDB_ROOT_USERNAME + value: "root" + - name: MONGO_INITDB_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: finalrip-secrets + key: mongodb-root-password + - name: MONGO_INITDB_DATABASE + value: "finalrip" + volumeMounts: + - name: mongodb-storage + mountPath: /data/db + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "1Gi" + cpu: "500m" + livenessProbe: + exec: + command: + - mongosh + - --eval + - "db.adminCommand('ping')" + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + exec: + command: + - mongosh + - --eval + - "db.adminCommand('ping')" + initialDelaySeconds: 5 + periodSeconds: 5 + volumes: + - name: mongodb-storage + persistentVolumeClaim: + claimName: mongodb-pvc +--- +apiVersion: v1 +kind: Service +metadata: + name: mongodb + namespace: finalrip + labels: + app.kubernetes.io/name: mongodb + app.kubernetes.io/component: database +spec: + selector: + app.kubernetes.io/name: mongodb + ports: + - port: 27017 + targetPort: 27017 \ No newline at end of file diff --git a/deploy/k8s/base/namespace.yaml b/deploy/k8s/base/namespace.yaml new file mode 100644 index 0000000..1f918b1 --- /dev/null +++ b/deploy/k8s/base/namespace.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: finalrip + labels: + app.kubernetes.io/name: finalrip + app.kubernetes.io/part-of: finalrip \ No newline at end of file diff --git a/deploy/k8s/base/redis.yaml b/deploy/k8s/base/redis.yaml new file mode 100644 index 0000000..d3ef46f --- /dev/null +++ b/deploy/k8s/base/redis.yaml @@ -0,0 +1,92 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: redis-pvc + namespace: finalrip + labels: + app.kubernetes.io/name: redis + app.kubernetes.io/component: cache +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: redis + namespace: finalrip + labels: + app.kubernetes.io/name: redis + app.kubernetes.io/component: cache +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: redis + template: + metadata: + labels: + app.kubernetes.io/name: redis + app.kubernetes.io/component: cache + spec: + containers: + - name: redis + image: redis:7.2.5 + ports: + - containerPort: 6379 + command: + - redis-server + - --requirepass + - $(REDIS_PASSWORD) + env: + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: finalrip-secrets + key: redis-password + volumeMounts: + - name: redis-storage + mountPath: /data + resources: + requests: + memory: "256Mi" + cpu: "100m" + limits: + memory: "512Mi" + cpu: "250m" + livenessProbe: + exec: + command: + - redis-cli + - ping + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + exec: + command: + - redis-cli + - ping + initialDelaySeconds: 5 + periodSeconds: 5 + volumes: + - name: redis-storage + persistentVolumeClaim: + claimName: redis-pvc +--- +apiVersion: v1 +kind: Service +metadata: + name: redis + namespace: finalrip + labels: + app.kubernetes.io/name: redis + app.kubernetes.io/component: cache +spec: + selector: + app.kubernetes.io/name: redis + ports: + - port: 6379 + targetPort: 6379 \ No newline at end of file diff --git a/deploy/k8s/base/secrets.yaml b/deploy/k8s/base/secrets.yaml new file mode 100644 index 0000000..6e48c14 --- /dev/null +++ b/deploy/k8s/base/secrets.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Secret +metadata: + name: finalrip-secrets + namespace: finalrip + labels: + app.kubernetes.io/name: finalrip + app.kubernetes.io/component: config +type: Opaque +data: + # Base64 encoded values + mongodb-root-password: MTIzNDU2 # 123456 + redis-password: MTIzNDU2 # 123456 + minio-access-key: aG9tbw== # homo + minio-secret-key: aG9tbzExNDUxNA== # homo114514 + server-token: MTE0NTE0 # 114514 \ No newline at end of file diff --git a/deploy/k8s/base/server.yaml b/deploy/k8s/base/server.yaml new file mode 100644 index 0000000..d8ee301 --- /dev/null +++ b/deploy/k8s/base/server.yaml @@ -0,0 +1,78 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: finalrip-server + namespace: finalrip + labels: + app.kubernetes.io/name: finalrip-server + app.kubernetes.io/component: server +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: finalrip-server + template: + metadata: + labels: + app.kubernetes.io/name: finalrip-server + app.kubernetes.io/component: server + spec: + containers: + - name: server + image: lychee0/finalrip:server-dev + ports: + - containerPort: 8848 + env: + - name: FINALRIP_REMOTE_CONFIG_HOST + value: "consul:8500" + - name: FINALRIP_DB_HOST + value: "mongodb" + - name: FINALRIP_REDIS_HOST + value: "redis" + - name: FINALRIP_OSS_ENDPOINT + value: "minio:9000" + - name: TZ + value: "Asia/Shanghai" + command: ["/app/server", "server"] + volumeMounts: + - name: config + mountPath: /app/conf + readOnly: true + resources: + requests: + memory: "256Mi" + cpu: "250m" + limits: + memory: "512Mi" + cpu: "500m" + livenessProbe: + httpGet: + path: /ping + port: 8848 + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /ping + port: 8848 + initialDelaySeconds: 10 + periodSeconds: 5 + volumes: + - name: config + configMap: + name: finalrip-config +--- +apiVersion: v1 +kind: Service +metadata: + name: finalrip-server + namespace: finalrip + labels: + app.kubernetes.io/name: finalrip-server + app.kubernetes.io/component: server +spec: + selector: + app.kubernetes.io/name: finalrip-server + ports: + - port: 8848 + targetPort: 8848 \ No newline at end of file diff --git a/deploy/k8s/base/worker-encode.yaml b/deploy/k8s/base/worker-encode.yaml new file mode 100644 index 0000000..7aee99d --- /dev/null +++ b/deploy/k8s/base/worker-encode.yaml @@ -0,0 +1,71 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: finalrip-worker-encode + namespace: finalrip + labels: + app.kubernetes.io/name: finalrip-worker-encode + app.kubernetes.io/component: worker +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: finalrip-worker-encode + template: + metadata: + labels: + app.kubernetes.io/name: finalrip-worker-encode + app.kubernetes.io/component: worker + spec: + containers: + - name: worker-encode + image: lychee0/finalrip:worker-encode-cuda-dev + env: + - name: FINALRIP_REMOTE_CONFIG_HOST + value: "consul:8500" + - name: FINALRIP_DB_HOST + value: "mongodb" + - name: FINALRIP_REDIS_HOST + value: "redis" + - name: FINALRIP_OSS_ENDPOINT + value: "minio:9000" + - name: TZ + value: "Asia/Shanghai" + command: ["/app/worker", "encode"] + volumeMounts: + - name: config + mountPath: /app/conf + readOnly: true + resources: + requests: + memory: "1Gi" + cpu: "500m" + nvidia.com/gpu: 1 + limits: + memory: "4Gi" + cpu: "2" + nvidia.com/gpu: 1 + livenessProbe: + exec: + command: + - pgrep + - worker + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + exec: + command: + - pgrep + - worker + initialDelaySeconds: 10 + periodSeconds: 5 + volumes: + - name: config + configMap: + name: finalrip-config + nodeSelector: + accelerator: nvidia-tesla-gpu # Adjust based on your GPU nodes + tolerations: + - key: nvidia.com/gpu + operator: Exists + effect: NoSchedule \ No newline at end of file diff --git a/deploy/k8s/base/workers.yaml b/deploy/k8s/base/workers.yaml new file mode 100644 index 0000000..44c012e --- /dev/null +++ b/deploy/k8s/base/workers.yaml @@ -0,0 +1,127 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: finalrip-worker-cut + namespace: finalrip + labels: + app.kubernetes.io/name: finalrip-worker-cut + app.kubernetes.io/component: worker +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: finalrip-worker-cut + template: + metadata: + labels: + app.kubernetes.io/name: finalrip-worker-cut + app.kubernetes.io/component: worker + spec: + containers: + - name: worker-cut + image: lychee0/finalrip:worker-cut-dev + env: + - name: FINALRIP_REMOTE_CONFIG_HOST + value: "consul:8500" + - name: FINALRIP_DB_HOST + value: "mongodb" + - name: FINALRIP_REDIS_HOST + value: "redis" + - name: FINALRIP_OSS_ENDPOINT + value: "minio:9000" + - name: TZ + value: "Asia/Shanghai" + command: ["/app/worker", "cut"] + volumeMounts: + - name: config + mountPath: /app/conf + readOnly: true + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "1Gi" + cpu: "500m" + livenessProbe: + exec: + command: + - pgrep + - worker + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + exec: + command: + - pgrep + - worker + initialDelaySeconds: 10 + periodSeconds: 5 + volumes: + - name: config + configMap: + name: finalrip-config +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: finalrip-worker-merge + namespace: finalrip + labels: + app.kubernetes.io/name: finalrip-worker-merge + app.kubernetes.io/component: worker +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: finalrip-worker-merge + template: + metadata: + labels: + app.kubernetes.io/name: finalrip-worker-merge + app.kubernetes.io/component: worker + spec: + containers: + - name: worker-merge + image: lychee0/finalrip:worker-merge-dev + env: + - name: FINALRIP_REMOTE_CONFIG_HOST + value: "consul:8500" + - name: FINALRIP_DB_HOST + value: "mongodb" + - name: FINALRIP_REDIS_HOST + value: "redis" + - name: FINALRIP_OSS_ENDPOINT + value: "minio:9000" + - name: TZ + value: "Asia/Shanghai" + command: ["/app/worker", "merge"] + volumeMounts: + - name: config + mountPath: /app/conf + readOnly: true + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "1Gi" + cpu: "500m" + livenessProbe: + exec: + command: + - pgrep + - worker + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + exec: + command: + - pgrep + - worker + initialDelaySeconds: 10 + periodSeconds: 5 + volumes: + - name: config + configMap: + name: finalrip-config \ No newline at end of file diff --git a/deploy/k8s/deploy.sh b/deploy/k8s/deploy.sh new file mode 100755 index 0000000..bf7863d --- /dev/null +++ b/deploy/k8s/deploy.sh @@ -0,0 +1,93 @@ +#!/bin/bash + +# Quick deployment script for FinalRip on Kubernetes +# Usage: ./deploy.sh [development|production] + +set -e + +ENVIRONMENT=${1:-development} +NAMESPACE="finalrip" + +echo "🚀 Deploying FinalRip to Kubernetes in $ENVIRONMENT mode..." + +# Check if kubectl is available +if ! command -v kubectl &> /dev/null; then + echo "❌ kubectl is not installed or not in PATH" + exit 1 +fi + +# Check if cluster is accessible +if ! kubectl cluster-info &> /dev/null; then + echo "❌ Cannot connect to Kubernetes cluster" + exit 1 +fi + +echo "✅ Kubernetes cluster is accessible" + +# Create namespace if it doesn't exist +kubectl create namespace $NAMESPACE --dry-run=client -o yaml | kubectl apply -f - + +echo "📦 Deploying infrastructure services..." + +# Deploy infrastructure first +kubectl apply -f deploy/k8s/base/namespace.yaml +kubectl apply -f deploy/k8s/base/configmap.yaml +kubectl apply -f deploy/k8s/base/secrets.yaml + +echo "🗄️ Deploying data services..." +kubectl apply -f deploy/k8s/base/mongodb.yaml +kubectl apply -f deploy/k8s/base/redis.yaml +kubectl apply -f deploy/k8s/base/minio.yaml +kubectl apply -f deploy/k8s/base/consul.yaml + +echo "⏳ Waiting for data services to be ready..." +kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=mongodb -n $NAMESPACE --timeout=300s +kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=redis -n $NAMESPACE --timeout=300s +kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=minio -n $NAMESPACE --timeout=300s +kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=consul -n $NAMESPACE --timeout=300s + +echo "🔧 Deploying application services..." +kubectl apply -f deploy/k8s/base/asynqmon.yaml +kubectl apply -f deploy/k8s/base/server.yaml +kubectl apply -f deploy/k8s/base/dashboard.yaml +kubectl apply -f deploy/k8s/base/workers.yaml + +if [ "$ENVIRONMENT" = "production" ]; then + echo "🎬 Deploying GPU-enabled encode workers..." + kubectl apply -f deploy/k8s/base/worker-encode.yaml +fi + +echo "🌐 Configuring network access..." +if [ "$ENVIRONMENT" = "development" ]; then + kubectl apply -f deploy/k8s/base/ingress.yaml + + # Port forward for local access + echo "🔗 Setting up port forwarding for local access..." + echo "Dashboard will be available at: http://localhost:8989" + echo "API will be available at: http://localhost:8848" + echo "Asynq Monitor will be available at: http://localhost:8080" + echo "" + echo "To access services, run:" + echo "kubectl port-forward svc/finalrip-dashboard 8989:80 -n $NAMESPACE &" + echo "kubectl port-forward svc/finalrip-server 8848:8848 -n $NAMESPACE &" + echo "kubectl port-forward svc/asynqmon 8080:8080 -n $NAMESPACE &" +fi + +echo "⏳ Waiting for application services to be ready..." +kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=finalrip-server -n $NAMESPACE --timeout=300s +kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=finalrip-dashboard -n $NAMESPACE --timeout=300s + +echo "✅ FinalRip deployment complete!" +echo "" +echo "📊 Deployment status:" +kubectl get pods -n $NAMESPACE + +echo "" +echo "🔧 To check service status:" +echo "kubectl get svc -n $NAMESPACE" +echo "" +echo "📝 To view logs:" +echo "kubectl logs -l app.kubernetes.io/name=finalrip-server -n $NAMESPACE" +echo "" +echo "🗑️ To uninstall:" +echo "./undeploy.sh" \ No newline at end of file diff --git a/deploy/k8s/helm/finalrip/.helmignore b/deploy/k8s/helm/finalrip/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/deploy/k8s/helm/finalrip/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/deploy/k8s/helm/finalrip/Chart.yaml b/deploy/k8s/helm/finalrip/Chart.yaml new file mode 100644 index 0000000..8a6a0d5 --- /dev/null +++ b/deploy/k8s/helm/finalrip/Chart.yaml @@ -0,0 +1,38 @@ +apiVersion: v2 +name: finalrip +description: A distributed video processing system for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.0.0" + +maintainers: +- name: EutropicAI + email: contact@eutropicai.com + +keywords: +- video-processing +- distributed +- finalrip +- kubernetes + +home: https://github.com/EutropicAI/FinalRip +sources: +- https://github.com/EutropicAI/FinalRip diff --git a/deploy/k8s/helm/finalrip/templates/NOTES.txt b/deploy/k8s/helm/finalrip/templates/NOTES.txt new file mode 100644 index 0000000..3e862ca --- /dev/null +++ b/deploy/k8s/helm/finalrip/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "finalrip.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "finalrip.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "finalrip.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "finalrip.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/deploy/k8s/helm/finalrip/templates/_helpers.tpl b/deploy/k8s/helm/finalrip/templates/_helpers.tpl new file mode 100644 index 0000000..b0e86f2 --- /dev/null +++ b/deploy/k8s/helm/finalrip/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "finalrip.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "finalrip.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "finalrip.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "finalrip.labels" -}} +helm.sh/chart: {{ include "finalrip.chart" . }} +{{ include "finalrip.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "finalrip.selectorLabels" -}} +app.kubernetes.io/name: {{ include "finalrip.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "finalrip.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "finalrip.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/deploy/k8s/helm/finalrip/templates/deployment.yaml b/deploy/k8s/helm/finalrip/templates/deployment.yaml new file mode 100644 index 0000000..a98ab2c --- /dev/null +++ b/deploy/k8s/helm/finalrip/templates/deployment.yaml @@ -0,0 +1,78 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "finalrip.fullname" . }} + labels: + {{- include "finalrip.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "finalrip.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "finalrip.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "finalrip.serviceAccountName" . }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.port }} + protocol: TCP + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/deploy/k8s/helm/finalrip/templates/hpa.yaml b/deploy/k8s/helm/finalrip/templates/hpa.yaml new file mode 100644 index 0000000..8412426 --- /dev/null +++ b/deploy/k8s/helm/finalrip/templates/hpa.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "finalrip.fullname" . }} + labels: + {{- include "finalrip.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "finalrip.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/deploy/k8s/helm/finalrip/templates/ingress.yaml b/deploy/k8s/helm/finalrip/templates/ingress.yaml new file mode 100644 index 0000000..2751b65 --- /dev/null +++ b/deploy/k8s/helm/finalrip/templates/ingress.yaml @@ -0,0 +1,43 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "finalrip.fullname" . }} + labels: + {{- include "finalrip.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- with .Values.ingress.className }} + ingressClassName: {{ . }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- with .pathType }} + pathType: {{ . }} + {{- end }} + backend: + service: + name: {{ include "finalrip.fullname" $ }} + port: + number: {{ $.Values.service.port }} + {{- end }} + {{- end }} +{{- end }} diff --git a/deploy/k8s/helm/finalrip/templates/service.yaml b/deploy/k8s/helm/finalrip/templates/service.yaml new file mode 100644 index 0000000..609e8fe --- /dev/null +++ b/deploy/k8s/helm/finalrip/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "finalrip.fullname" . }} + labels: + {{- include "finalrip.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "finalrip.selectorLabels" . | nindent 4 }} diff --git a/deploy/k8s/helm/finalrip/templates/serviceaccount.yaml b/deploy/k8s/helm/finalrip/templates/serviceaccount.yaml new file mode 100644 index 0000000..b3491f5 --- /dev/null +++ b/deploy/k8s/helm/finalrip/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "finalrip.serviceAccountName" . }} + labels: + {{- include "finalrip.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/deploy/k8s/helm/finalrip/templates/tests/test-connection.yaml b/deploy/k8s/helm/finalrip/templates/tests/test-connection.yaml new file mode 100644 index 0000000..2375695 --- /dev/null +++ b/deploy/k8s/helm/finalrip/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "finalrip.fullname" . }}-test-connection" + labels: + {{- include "finalrip.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "finalrip.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/deploy/k8s/helm/finalrip/values.yaml b/deploy/k8s/helm/finalrip/values.yaml new file mode 100644 index 0000000..973eb9f --- /dev/null +++ b/deploy/k8s/helm/finalrip/values.yaml @@ -0,0 +1,291 @@ +# Default values for finalrip. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Global settings +global: + namespace: finalrip + imageRegistry: lychee0 + +# Application components +server: + enabled: true + replicaCount: 1 + image: + repository: finalrip + tag: server-dev + pullPolicy: IfNotPresent + service: + type: ClusterIP + port: 8848 + resources: + requests: + memory: "256Mi" + cpu: "250m" + limits: + memory: "512Mi" + cpu: "500m" + +dashboard: + enabled: true + replicaCount: 1 + image: + repository: finalrip + tag: dashboard-dev + pullPolicy: IfNotPresent + service: + type: ClusterIP + port: 80 + resources: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "256Mi" + cpu: "200m" + +workers: + cut: + enabled: true + replicaCount: 1 + image: + repository: finalrip + tag: worker-cut-dev + pullPolicy: IfNotPresent + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "1Gi" + cpu: "500m" + + merge: + enabled: true + replicaCount: 1 + image: + repository: finalrip + tag: worker-merge-dev + pullPolicy: IfNotPresent + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "1Gi" + cpu: "500m" + + encode: + enabled: true + replicaCount: 1 + image: + repository: finalrip + tag: worker-encode-cuda-dev + pullPolicy: IfNotPresent + resources: + requests: + memory: "1Gi" + cpu: "500m" + nvidia.com/gpu: 1 + limits: + memory: "4Gi" + cpu: "2" + nvidia.com/gpu: 1 + nodeSelector: + accelerator: nvidia-tesla-gpu + tolerations: + - key: nvidia.com/gpu + operator: Exists + effect: NoSchedule + +# Infrastructure components +mongodb: + enabled: true + image: + repository: mongo + tag: "8.0.0-rc13-jammy" + pullPolicy: IfNotPresent + persistence: + enabled: true + storageClass: "" + size: 10Gi + auth: + rootUsername: root + rootPassword: 123456 + database: finalrip + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "1Gi" + cpu: "500m" + +redis: + enabled: true + image: + repository: redis + tag: "7.2.5" + pullPolicy: IfNotPresent + persistence: + enabled: true + storageClass: "" + size: 5Gi + auth: + password: 123456 + resources: + requests: + memory: "256Mi" + cpu: "100m" + limits: + memory: "512Mi" + cpu: "250m" + +minio: + enabled: true + image: + repository: bitnami/minio + tag: "2024.7.13" + pullPolicy: IfNotPresent + persistence: + enabled: true + storageClass: "" + size: 50Gi + auth: + rootUser: homo + rootPassword: homo114514 + defaultBuckets: "finalrip:public" + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "1Gi" + cpu: "500m" + +consul: + enabled: true + image: + repository: consul + tag: "1.15" + pullPolicy: IfNotPresent + persistence: + enabled: true + storageClass: "" + size: 5Gi + resources: + requests: + memory: "256Mi" + cpu: "100m" + limits: + memory: "512Mi" + cpu: "250m" + +asynqmon: + enabled: true + image: + repository: hibiken/asynqmon + tag: latest + pullPolicy: IfNotPresent + resources: + requests: + memory: "128Mi" + cpu: "50m" + limits: + memory: "256Mi" + cpu: "100m" + +# Ingress configuration +ingress: + enabled: false + className: "nginx" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: finalrip.local + paths: + - path: / + pathType: Prefix + service: dashboard + - path: /api + pathType: Prefix + service: server + - path: /asynq + pathType: Prefix + service: asynqmon + - path: /minio + pathType: Prefix + service: minio + - path: /consul + pathType: Prefix + service: consul + tls: [] + # - secretName: finalrip-tls + # hosts: + # - finalrip.local + +# Service configuration +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# Application configuration +config: + finalrip: + server: + token: 114514 + name: EutropicAI-FinalRip + port: 8848 + mode: prod + log: + level: debug + mode: + - console + - file + db: + type: mongodb + host: mongodb + port: 27017 + username: root + password: 123456 + database: finalrip + ssl: false + redis: + host: redis + port: 6379 + password: 123456 + poolSize: 1000 + oss: + type: minio + endpoint: minio:9000 + accessKey: homo + secretKey: homo114514 + region: local + bucket: finalrip + ssl: false + hostnameImmutable: true \ No newline at end of file diff --git a/deploy/k8s/overlays/development/kustomization.yaml b/deploy/k8s/overlays/development/kustomization.yaml new file mode 100644 index 0000000..5d3f0fd --- /dev/null +++ b/deploy/k8s/overlays/development/kustomization.yaml @@ -0,0 +1,28 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +metadata: + name: finalrip-development + +namespace: finalrip + +resources: +- ../../base + +patchesStrategicMerge: +- patches/development-patches.yaml + +images: +- name: lychee0/finalrip:server-dev + newTag: dev +- name: lychee0/finalrip:dashboard-dev + newTag: dev +- name: lychee0/finalrip:worker-cut-dev + newTag: dev +- name: lychee0/finalrip:worker-merge-dev + newTag: dev +- name: lychee0/finalrip:worker-encode-cuda-dev + newTag: dev + +commonLabels: + environment: development \ No newline at end of file diff --git a/deploy/k8s/overlays/development/patches/development-patches.yaml b/deploy/k8s/overlays/development/patches/development-patches.yaml new file mode 100644 index 0000000..d772ccb --- /dev/null +++ b/deploy/k8s/overlays/development/patches/development-patches.yaml @@ -0,0 +1,48 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: finalrip-server + namespace: finalrip +spec: + template: + spec: + containers: + - name: server + env: + - name: FINALRIP_LOG_LEVEL + value: "debug" + resources: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "256Mi" + cpu: "250m" +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: finalrip-worker-encode + namespace: finalrip +spec: + replicas: 1 # Single replica for development + template: + spec: + containers: + - name: worker-encode + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "2Gi" + cpu: "1" +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: finalrip-ingress + namespace: finalrip +spec: + rules: + - host: finalrip-dev.local \ No newline at end of file diff --git a/deploy/k8s/overlays/production/kustomization.yaml b/deploy/k8s/overlays/production/kustomization.yaml new file mode 100644 index 0000000..9d3c083 --- /dev/null +++ b/deploy/k8s/overlays/production/kustomization.yaml @@ -0,0 +1,34 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +metadata: + name: finalrip-production + +namespace: finalrip + +resources: +- ../../base + +patchesStrategicMerge: +- patches/production-patches.yaml + +images: +- name: lychee0/finalrip:server-dev + newTag: latest +- name: lychee0/finalrip:dashboard-dev + newTag: latest +- name: lychee0/finalrip:worker-cut-dev + newTag: latest +- name: lychee0/finalrip:worker-merge-dev + newTag: latest +- name: lychee0/finalrip:worker-encode-cuda-dev + newTag: latest + +commonLabels: + environment: production + +replicas: +- name: finalrip-server + count: 2 +- name: finalrip-worker-encode + count: 3 \ No newline at end of file diff --git a/deploy/k8s/overlays/production/patches/production-patches.yaml b/deploy/k8s/overlays/production/patches/production-patches.yaml new file mode 100644 index 0000000..342de63 --- /dev/null +++ b/deploy/k8s/overlays/production/patches/production-patches.yaml @@ -0,0 +1,76 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: finalrip-server + namespace: finalrip +spec: + template: + spec: + containers: + - name: server + env: + - name: FINALRIP_LOG_LEVEL + value: "info" + resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1" +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: finalrip-worker-encode + namespace: finalrip +spec: + template: + spec: + containers: + - name: worker-encode + resources: + requests: + memory: "2Gi" + cpu: "1" + nvidia.com/gpu: 1 + limits: + memory: "8Gi" + cpu: "4" + nvidia.com/gpu: 1 +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mongodb-pvc + namespace: finalrip +spec: + resources: + requests: + storage: 100Gi +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: minio-pvc + namespace: finalrip +spec: + resources: + requests: + storage: 500Gi +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: finalrip-ingress + namespace: finalrip + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + nginx.ingress.kubernetes.io/ssl-redirect: "true" +spec: + tls: + - hosts: + - finalrip.yourdomain.com + secretName: finalrip-tls + rules: + - host: finalrip.yourdomain.com \ No newline at end of file diff --git a/deploy/k8s/undeploy.sh b/deploy/k8s/undeploy.sh new file mode 100755 index 0000000..af96a73 --- /dev/null +++ b/deploy/k8s/undeploy.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# Uninstall script for FinalRip Kubernetes deployment +# Usage: ./undeploy.sh + +set -e + +NAMESPACE="finalrip" + +echo "🗑️ Removing FinalRip from Kubernetes..." + +# Check if kubectl is available +if ! command -v kubectl &> /dev/null; then + echo "❌ kubectl is not installed or not in PATH" + exit 1 +fi + +# Check if namespace exists +if ! kubectl get namespace $NAMESPACE &> /dev/null; then + echo "ℹ️ Namespace $NAMESPACE does not exist, nothing to remove" + exit 0 +fi + +echo "🔧 Removing application services..." +kubectl delete -f deploy/k8s/base/ingress.yaml --ignore-not-found=true +kubectl delete -f deploy/k8s/base/worker-encode.yaml --ignore-not-found=true +kubectl delete -f deploy/k8s/base/workers.yaml --ignore-not-found=true +kubectl delete -f deploy/k8s/base/dashboard.yaml --ignore-not-found=true +kubectl delete -f deploy/k8s/base/server.yaml --ignore-not-found=true +kubectl delete -f deploy/k8s/base/asynqmon.yaml --ignore-not-found=true + +echo "🗄️ Removing data services..." +kubectl delete -f deploy/k8s/base/consul.yaml --ignore-not-found=true +kubectl delete -f deploy/k8s/base/minio.yaml --ignore-not-found=true +kubectl delete -f deploy/k8s/base/redis.yaml --ignore-not-found=true +kubectl delete -f deploy/k8s/base/mongodb.yaml --ignore-not-found=true + +echo "📦 Removing configuration..." +kubectl delete -f deploy/k8s/base/secrets.yaml --ignore-not-found=true +kubectl delete -f deploy/k8s/base/configmap.yaml --ignore-not-found=true + +echo "⚠️ Persistent data will be preserved. To remove data volumes:" +echo "kubectl delete pvc --all -n $NAMESPACE" +echo "" + +read -p "Do you want to remove persistent data as well? (y/N): " -n 1 -r +echo +if [[ $REPLY =~ ^[Yy]$ ]]; then + echo "🗄️ Removing persistent volumes..." + kubectl delete pvc --all -n $NAMESPACE --ignore-not-found=true +fi + +echo "🗑️ Removing namespace..." +kubectl delete namespace $NAMESPACE --ignore-not-found=true + +echo "✅ FinalRip has been removed from Kubernetes" \ No newline at end of file