diff --git a/AUDIT-STATUS.fa.md b/AUDIT-STATUS.fa.md index 7d2348d..5c756ab 100644 --- a/AUDIT-STATUS.fa.md +++ b/AUDIT-STATUS.fa.md @@ -16,7 +16,7 @@ | دسته | تعداد | ✅ | ⚠️ | 🔜 | |------|-------|----|----|-----| | بلاکرهای پروداکشن | 8 | 8 | 0 | 0 | -| بیلد و Kaniko | 10 | 8 | 1 | 1 | +| بیلد و Kaniko | 10 | 9 | 0 | 1 | | دیپلوی و پیش‌نمایش | 6 | 6 | 0 | 0 | | دیتابیس / سرویس اختیاری | 9 | 8 | 0 | 1 | | Migration / اسکیما | 4 | 4 | 0 | 0 | @@ -57,7 +57,7 @@ | Zip slip در unzip | ✅ | اعتبارسنجی مسیر قبل و بعد از extract | | state بیلد در حافظه | ✅ | Redis session + startup recovery | | دیپلوی هم‌زمان بدون قفل | ✅ | in-flight guard در `triggerDeployment` | -| Base image بدون آینه | ⚠️ | `BASE_IMAGE_REGISTRY` اضافه شده؛ باید در env پروداکشن ست شود | +| Base image بدون آینه | ✅ | `build.images` در Helm values + پیش‌فرض Harbor در configuration | | zip bomb (۱۰GiB) | 🔜 | سقف آپلود موجود؛ محدودیت تعداد entry در archive پیشنهاد می‌شود | --- @@ -157,7 +157,8 @@ |--------|---------|-------| | `CLUSTER_DEPLOY_FALLBACK_ENABLED` | `false` | fallback بین کلاستر | | `CLUSTER_DEPLOY_FALLBACK_ATTEMPTS` | `3` | فقط وقتی fallback فعال | -| `BASE_IMAGE_REGISTRY` | — | آینه base imageهای بیلد | +| `BASE_IMAGE_REGISTRY` | `registry.abrban.com/proxy-dockerhub/library` | آینه base imageهای بیلد (یا از `build` در Helm values) | +| `KANIKO_IMAGE` | `registry.abrban.com/proxy-gcr/...` | Kaniko executor (یا `build.images.kaniko` در values) | | `BUILD_PVC_STORAGE_CLASS` | — | StorageClass برای PVC بیلد | | `BILLING_WALLET_HMAC_SECRET` | — | اجباری در production | | `PAYMENT_GATEWAY_*` | — | اجباری برای charge واقعی | diff --git a/README.md b/README.md index 544df53..4f4dcc8 100644 --- a/README.md +++ b/README.md @@ -287,7 +287,10 @@ curl -s -o /dev/null -w '%{http_code}\n' https:// | `MIZBANSMS_USERNAME` / `MIZBANSMS_PASSWORD` / `MIZBANSMS_FROM` | OTP SMS credentials (required or OTP send 503s) | — | | `REGISTRY_URL` / `REGISTRY_PULL_URL` | In-cluster registry (push / pull) | `registry.cloudhost-builds.svc.cluster.local:5000` | | `BUILD_NAMESPACE` / `BUILD_SERVICE_ACCOUNT` | Build Jobs namespace + SA | `cloudhost-builds` / `kaniko-builder` | -| `KANIKO_IMAGE` | Kaniko executor image | `gcr.io/kaniko-project/executor:v1.23.2` | +| `KANIKO_IMAGE` | Kaniko executor image | `registry.abrban.com/proxy-gcr/kaniko-project/executor:v1.23.2` | +| `BUILD_ALPINE_IMAGE` | Alpine image for build init/helper pods | `registry.abrban.com/proxy-dockerhub/library/alpine:3.19` | +| `BUILD_ALPINE_GIT_IMAGE` | Git-clone init container image | `registry.abrban.com/proxy-dockerhub/alpine/git:2.43.0` | +| `BASE_IMAGE_REGISTRY` | Harbor prefix for Docker Hub images in generated Dockerfiles | `registry.abrban.com/proxy-dockerhub/library` | | `UPLOAD_DIR` | Disk path for uploaded source archives | `./uploads` | | `INGRESS_CLASS` | Ingress controller for app Ingress objects | `traefik` | | `PLATFORM_DOMAIN` / `PREVIEW_BASE_DOMAIN` | Base domain for app subdomains / previews | `apps.cloudhost.local` / — | diff --git a/backend/.env.example b/backend/.env.example index 72b5f66..791797d 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -75,6 +75,11 @@ REGISTRY_PASSWORD=registry_secret # Build BUILD_NAMESPACE=cloudhost-builds BUILD_SERVICE_ACCOUNT=kaniko-builder +# Kaniko job images — defaults pull from Harbor proxy-cache when unset. +# KANIKO_IMAGE=registry.abrban.com/proxy-gcr/kaniko-project/executor:v1.23.2 +# BUILD_ALPINE_IMAGE=registry.abrban.com/proxy-dockerhub/library/alpine:3.19 +# BUILD_ALPINE_GIT_IMAGE=registry.abrban.com/proxy-dockerhub/alpine/git:2.43.0 +# BASE_IMAGE_REGISTRY=registry.abrban.com/proxy-dockerhub/library # Platform # Public URL(s) of the frontend — used for CORS and to derive the platform/preview diff --git a/backend/helm/cloudhost-platform/templates/_helpers.tpl b/backend/helm/cloudhost-platform/templates/_helpers.tpl index 0ad79c7..f0539af 100644 --- a/backend/helm/cloudhost-platform/templates/_helpers.tpl +++ b/backend/helm/cloudhost-platform/templates/_helpers.tpl @@ -113,3 +113,14 @@ PLATFORM_DOMAIN / preview domain from the first entry only. The panel host {{- define "cloudhost-platform.frontendImage" -}} {{- printf "%s:%s" .Values.images.frontend.repository .Values.images.frontend.tag }} {{- end }} + +{{- define "cloudhost-platform.buildEnv" -}} +- name: KANIKO_IMAGE + value: {{ .Values.build.images.kaniko | quote }} +- name: BUILD_ALPINE_IMAGE + value: {{ .Values.build.images.alpine | quote }} +- name: BUILD_ALPINE_GIT_IMAGE + value: {{ .Values.build.images.alpineGit | quote }} +- name: BASE_IMAGE_REGISTRY + value: {{ .Values.build.baseImageRegistry | quote }} +{{- end }} diff --git a/backend/helm/cloudhost-platform/templates/backend-deployment.yaml b/backend/helm/cloudhost-platform/templates/backend-deployment.yaml index 802d35c..7186cb1 100644 --- a/backend/helm/cloudhost-platform/templates/backend-deployment.yaml +++ b/backend/helm/cloudhost-platform/templates/backend-deployment.yaml @@ -100,6 +100,7 @@ spec: key: cluster-kubeconfig-key - name: FRONTEND_URL value: {{ include "cloudhost-platform.corsOrigins" . | quote }} + {{- include "cloudhost-platform.buildEnv" . | nindent 12 }} {{- range $key, $val := .Values.backend.env }} - name: {{ $key }} value: {{ $val | quote }} diff --git a/backend/helm/cloudhost-platform/values-production.example.yaml b/backend/helm/cloudhost-platform/values-production.example.yaml index 764641c..8812c38 100644 --- a/backend/helm/cloudhost-platform/values-production.example.yaml +++ b/backend/helm/cloudhost-platform/values-production.example.yaml @@ -22,6 +22,14 @@ images: tag: "1.0.0" pullPolicy: Always +# Build job images — override for clusters without Harbor proxy-cache. +build: + images: + kaniko: registry.example.com/proxy-gcr/kaniko-project/executor:v1.23.2 + alpine: registry.example.com/proxy-dockerhub/library/alpine:3.19 + alpineGit: registry.example.com/proxy-dockerhub/alpine/git:2.43.0 + baseImageRegistry: registry.example.com/proxy-dockerhub/library + postgres: password: "CHANGE_ME_STRONG_POSTGRES_PASSWORD" # Pull secret for the mirrored postgres image @@ -58,8 +66,6 @@ backend: PLATFORM_DOMAIN: apps.example.com REGISTRY_URL: registry.cloudhost-builds.svc.cluster.local:5000 REGISTRY_PULL_URL: registry.cloudhost-builds.svc.cluster.local:5000 - # Mirror prefix for base images in generated Dockerfiles + managed services - BASE_IMAGE_REGISTRY: registry.example.com/mirror # Elastic log-stack credentials (must match the logging namespace Secret) ELASTIC_PASSWORD: "CHANGE_ME_ELASTIC_PASSWORD" FLUENTBIT_PASSWORD: "CHANGE_ME_FLUENTBIT_PASSWORD" diff --git a/backend/helm/cloudhost-platform/values.yaml b/backend/helm/cloudhost-platform/values.yaml index 7ae047a..5358d57 100644 --- a/backend/helm/cloudhost-platform/values.yaml +++ b/backend/helm/cloudhost-platform/values.yaml @@ -28,6 +28,16 @@ images: tag: "1.0.0" pullPolicy: IfNotPresent +# Kaniko job images — defaults pull from Harbor proxy-cache. +# Override any line for a different registry/tag. +build: + images: + kaniko: registry.abrban.com/proxy-gcr/kaniko-project/executor:v1.23.2 + alpine: registry.abrban.com/proxy-dockerhub/library/alpine:3.19 + alpineGit: registry.abrban.com/proxy-dockerhub/alpine/git:2.43.0 + # Prefix for Docker Hub images in generated user-app Dockerfiles (node, php, …) + baseImageRegistry: registry.abrban.com/proxy-dockerhub/library + postgres: enabled: true database: cloudhost diff --git a/backend/src/build/build.service.ts b/backend/src/build/build.service.ts index 57fb611..06d60d8 100644 --- a/backend/src/build/build.service.ts +++ b/backend/src/build/build.service.ts @@ -56,12 +56,6 @@ export class BuildService { private readonly logger = new Logger(BuildService.name); private readonly progressMap = new Map(); private readonly activeBuilds = new Map(); - /** - * Kaniko executor image. Pinned (not `:latest`) so it can be cached on the node - * with imagePullPolicy=IfNotPresent — avoids re-pulling the ~250MB image on every build. - */ - private readonly kanikoImage = process.env.KANIKO_IMAGE || 'gcr.io/kaniko-project/executor:v1.23.2'; - constructor( private configService: ConfigService, private clustersService: ClustersService, @@ -85,6 +79,18 @@ export class BuildService { return `${prefix}/${image}`; } + /** Kaniko executor — pinned (not :latest) for node-level caching. */ + private getKanikoImage(): string { + return this.configService.get('build.images.kaniko')!; + } + + /** Init/helper container image — explicit Harbor ref or baseImage() fallback. */ + private resolveBuildImage(kind: 'alpine' | 'alpineGit', dockerHubFallback: string): string { + const explicit = this.configService.get(`build.images.${kind}`); + if (explicit) return explicit; + return this.baseImage(dockerHubFallback); + } + /** * Git branch names come from users and end up in a shell command — accept * only conservative ref characters and reject anything option-like. @@ -548,7 +554,7 @@ export class BuildService { // Add init container that unzips the source code from PVC initContainers.push({ name: 'unzip-source', - image: this.baseImage('alpine:3.19'), + image: this.resolveBuildImage('alpine', 'alpine:3.19'), imagePullPolicy: 'IfNotPresent', command: [ 'sh', @@ -628,7 +634,7 @@ export class BuildService { // Clone git repo into /workspace/source, then copy our generated Dockerfile initContainers.push({ name: 'git-clone', - image: this.baseImage('alpine/git:2.43.0'), + image: this.resolveBuildImage('alpineGit', 'alpine/git:2.43.0'), imagePullPolicy: 'IfNotPresent', env: [ { name: 'GIT_URL', value: app.gitUrl! }, @@ -679,7 +685,7 @@ export class BuildService { // add an init container that creates empty source dir + copies Dockerfile initContainers.push({ name: 'prepare-workspace', - image: this.baseImage('alpine:3.19'), + image: this.resolveBuildImage('alpine', 'alpine:3.19'), imagePullPolicy: 'IfNotPresent', command: [ 'sh', @@ -715,7 +721,7 @@ export class BuildService { containers: [ { name: 'kaniko', - image: this.kanikoImage, + image: this.getKanikoImage(), imagePullPolicy: 'IfNotPresent', args: kanikoArgs, volumeMounts: kanikoVolumeMounts, @@ -950,7 +956,7 @@ export class BuildService { containers: [ { name: 'helper', - image: this.baseImage('alpine:3.19'), + image: this.resolveBuildImage('alpine', 'alpine:3.19'), imagePullPolicy: 'IfNotPresent', command: ['sh', '-c', 'sleep 3600'], volumeMounts: [{ name: 'source', mountPath: '/data' }], diff --git a/backend/src/config/configuration.ts b/backend/src/config/configuration.ts index 27f9ed2..c2d8496 100644 --- a/backend/src/config/configuration.ts +++ b/backend/src/config/configuration.ts @@ -135,12 +135,21 @@ export default () => ({ namespace: process.env.BUILD_NAMESPACE || 'cloudhost-builds', serviceAccount: process.env.BUILD_SERVICE_ACCOUNT || 'kaniko-builder', /** - * Optional registry prefix for Docker Hub base images used in generated - * Dockerfiles and managed-service charts (e.g. "mirror.example.com" makes - * `node:20-alpine` → `mirror.example.com/node:20-alpine`). Useful when - * cluster nodes cannot reach docker.io directly. + * Registry prefix for Docker Hub base images used in generated Dockerfiles + * and managed-service charts (e.g. `node:20-alpine` → + * `registry.abrban.com/proxy-dockerhub/library/node:20-alpine`). */ - baseImageRegistry: (process.env.BASE_IMAGE_REGISTRY || '').trim().replace(/\/+$/, ''), + baseImageRegistry: (process.env.BASE_IMAGE_REGISTRY || 'registry.abrban.com/proxy-dockerhub/library') + .trim() + .replace(/\/+$/, ''), + /** Full image refs for Kaniko jobs — override via Helm values or env. */ + images: { + kaniko: + process.env.KANIKO_IMAGE || + 'registry.abrban.com/proxy-gcr/kaniko-project/executor:v1.23.2', + alpine: (process.env.BUILD_ALPINE_IMAGE || 'registry.abrban.com/proxy-dockerhub/library/alpine:3.19').trim(), + alpineGit: (process.env.BUILD_ALPINE_GIT_IMAGE || 'registry.abrban.com/proxy-dockerhub/alpine/git:2.43.0').trim(), + }, /** Kaniko build container resources — tune for large images. */ kaniko: { cpuRequest: process.env.KANIKO_CPU_REQUEST || '500m', diff --git a/gitops/platform/values-abrban.example.yaml b/gitops/platform/values-abrban.example.yaml index 6adff0a..ed53318 100644 --- a/gitops/platform/values-abrban.example.yaml +++ b/gitops/platform/values-abrban.example.yaml @@ -28,6 +28,14 @@ images: tag: "1.0.0" # ← CI overwrites on each deploy pullPolicy: IfNotPresent +# Kaniko job images — Harbor proxy-cache (first pull is slow, no manual seed needed). +build: + images: + kaniko: registry.abrban.com/proxy-gcr/kaniko-project/executor:v1.23.2 + alpine: registry.abrban.com/proxy-dockerhub/library/alpine:3.19 + alpineGit: registry.abrban.com/proxy-dockerhub/alpine/git:2.43.0 + baseImageRegistry: registry.abrban.com/proxy-dockerhub/library + postgres: enabled: true database: cloudhost @@ -98,8 +106,6 @@ backend: PLATFORM_STORAGE_PROVISIONER: rancher.io/local-path ELASTICSEARCH_HOST: elasticsearch.logging.svc.cluster.local ELASTICSEARCH_AUTO_PORT_FORWARD: "false" - # Mirror prefix for user-app Dockerfiles and managed DB/Redis/RabbitMQ charts - BASE_IMAGE_REGISTRY: registry.abrban.com/proxy-dockerhub/library # Must match elasticsearch-credentials Secret in logging namespace (not in Helm chart) ELASTIC_PASSWORD: "CHANGE_VIA_SEALEDSECRET_OR_KUBECTL" FLUENTBIT_PASSWORD: "CHANGE_VIA_SEALEDSECRET_OR_KUBECTL"