Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 54ab2f2f05 | |||
| 214b617be0 | |||
| 2679c9d66e | |||
| 1ec4d07939 | |||
| 3d773a4a62 | |||
| b2ecdad53b | |||
| a2fe61b1f6 |
@@ -159,7 +159,7 @@ jobs:
|
|||||||
mountPath: /workspace
|
mountPath: /workspace
|
||||||
containers:
|
containers:
|
||||||
- name: kaniko
|
- name: kaniko
|
||||||
image: ${PULL_REGISTRY}/${PROJECT}/kaniko-executor:v1.27.6-debug
|
image: ${PULL_REGISTRY}/${PROJECT}/kaniko-executor:v1.23.2
|
||||||
# Base image (node:24-alpine) is seeded in Harbor abrban/ — avoids
|
# Base image (node:24-alpine) is seeded in Harbor abrban/ — avoids
|
||||||
# flaky direct pulls from docker.io through the egress proxy.
|
# flaky direct pulls from docker.io through the egress proxy.
|
||||||
envFrom:
|
envFrom:
|
||||||
@@ -224,7 +224,7 @@ jobs:
|
|||||||
mountPath: /workspace
|
mountPath: /workspace
|
||||||
containers:
|
containers:
|
||||||
- name: kaniko
|
- name: kaniko
|
||||||
image: ${PULL_REGISTRY}/${PROJECT}/kaniko-executor:v1.27.6-debug
|
image: ${PULL_REGISTRY}/${PROJECT}/kaniko-executor:v1.23.2
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: registry-egress-proxy
|
name: registry-egress-proxy
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
{{- $auth := printf "elastic:%s" .Values.elasticPassword | b64enc }}
|
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: StatefulSet
|
kind: StatefulSet
|
||||||
metadata:
|
metadata:
|
||||||
@@ -74,22 +73,20 @@ spec:
|
|||||||
- name: es-data
|
- name: es-data
|
||||||
mountPath: /usr/share/elasticsearch/data
|
mountPath: /usr/share/elasticsearch/data
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
exec:
|
||||||
path: /_cluster/health?local=true
|
command:
|
||||||
port: 9200
|
- sh
|
||||||
httpHeaders:
|
- -c
|
||||||
- name: Authorization
|
- curl -sf -u "elastic:${ELASTIC_PASSWORD}" http://127.0.0.1:9200/_cluster/health?local=true
|
||||||
value: Basic {{ $auth }}
|
|
||||||
initialDelaySeconds: 30
|
initialDelaySeconds: 30
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
timeoutSeconds: 5
|
timeoutSeconds: 5
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
httpGet:
|
exec:
|
||||||
path: /_cluster/health?local=true
|
command:
|
||||||
port: 9200
|
- sh
|
||||||
httpHeaders:
|
- -c
|
||||||
- name: Authorization
|
- curl -sf -u "elastic:${ELASTIC_PASSWORD}" http://127.0.0.1:9200/_cluster/health?local=true
|
||||||
value: Basic {{ $auth }}
|
|
||||||
initialDelaySeconds: 60
|
initialDelaySeconds: 60
|
||||||
periodSeconds: 30
|
periodSeconds: 30
|
||||||
timeoutSeconds: 10
|
timeoutSeconds: 10
|
||||||
|
|||||||
@@ -123,4 +123,8 @@ PLATFORM_DOMAIN / preview domain from the first entry only. The panel host
|
|||||||
value: {{ .Values.build.images.alpineGit | quote }}
|
value: {{ .Values.build.images.alpineGit | quote }}
|
||||||
- name: BASE_IMAGE_REGISTRY
|
- name: BASE_IMAGE_REGISTRY
|
||||||
value: {{ .Values.build.baseImageRegistry | quote }}
|
value: {{ .Values.build.baseImageRegistry | quote }}
|
||||||
|
{{- if .Values.build.egressProxySecret }}
|
||||||
|
- name: BUILD_EGRESS_PROXY_SECRET
|
||||||
|
value: {{ .Values.build.egressProxySecret | quote }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -98,8 +98,42 @@ spec:
|
|||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: {{ include "cloudhost-platform.secretName" . }}
|
name: {{ include "cloudhost-platform.secretName" . }}
|
||||||
key: cluster-kubeconfig-key
|
key: cluster-kubeconfig-key
|
||||||
|
- name: ELASTIC_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "cloudhost-platform.secretName" . }}
|
||||||
|
key: elastic-password
|
||||||
- name: FRONTEND_URL
|
- name: FRONTEND_URL
|
||||||
value: {{ include "cloudhost-platform.corsOrigins" . | quote }}
|
value: {{ include "cloudhost-platform.corsOrigins" . | quote }}
|
||||||
|
{{- if .Values.backend.sms.enabled }}
|
||||||
|
- name: SMS_PROVIDER
|
||||||
|
value: {{ .Values.backend.sms.provider | default "mizbansms" | quote }}
|
||||||
|
- name: MIZBANSMS_FROM
|
||||||
|
value: {{ .Values.backend.sms.from | default "5000467254" | quote }}
|
||||||
|
- name: MIZBANSMS_API
|
||||||
|
value: {{ .Values.backend.sms.api | default "2016" | quote }}
|
||||||
|
- name: MIZBANSMS_USERTYPE
|
||||||
|
value: {{ .Values.backend.sms.userType | default "2" | quote }}
|
||||||
|
- name: MIZBANSMS_USERNAME
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "cloudhost-platform.secretName" . }}
|
||||||
|
key: mizbansms-username
|
||||||
|
- name: MIZBANSMS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "cloudhost-platform.secretName" . }}
|
||||||
|
key: mizbansms-password
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.registry.credentialsSecret }}
|
||||||
|
- name: REGISTRY_USERNAME
|
||||||
|
value: {{ .Values.registry.username | default "harbor_registry_user" | quote }}
|
||||||
|
- name: REGISTRY_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ .Values.registry.credentialsSecret | quote }}
|
||||||
|
key: {{ .Values.registry.credentialsPasswordKey | default "REGISTRY_CREDENTIAL_PASSWORD" | quote }}
|
||||||
|
{{- end }}
|
||||||
{{- include "cloudhost-platform.buildEnv" . | nindent 12 }}
|
{{- include "cloudhost-platform.buildEnv" . | nindent 12 }}
|
||||||
{{- range $key, $val := .Values.backend.env }}
|
{{- range $key, $val := .Values.backend.env }}
|
||||||
- name: {{ $key }}
|
- name: {{ $key }}
|
||||||
|
|||||||
@@ -28,15 +28,25 @@ images:
|
|||||||
tag: "1.0.0"
|
tag: "1.0.0"
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
# Kaniko push credentials — harbor_registry_user for harbor-registry:5000 (Harbor production).
|
||||||
|
registry:
|
||||||
|
credentialsSecret: ""
|
||||||
|
credentialsPasswordKey: REGISTRY_CREDENTIAL_PASSWORD
|
||||||
|
username: harbor_registry_user
|
||||||
|
|
||||||
# Kaniko job images — defaults pull from Harbor proxy-cache.
|
# Kaniko job images — defaults pull from Harbor proxy-cache.
|
||||||
# Override any line for a different registry/tag.
|
# Override any line for a different registry/tag.
|
||||||
build:
|
build:
|
||||||
images:
|
images:
|
||||||
kaniko: registry.abrban.com/proxy-gcr/kaniko-project/executor:v1.23.2
|
# Seeded into abrban/ via gitops/jobs/seed-ci-images.yaml — avoid flaky proxy-gcr pulls.
|
||||||
alpine: registry.abrban.com/proxy-dockerhub/library/alpine:3.19
|
kaniko: registry.abrban.com/abrban/kaniko-executor:v1.27.6-debug
|
||||||
alpineGit: registry.abrban.com/proxy-dockerhub/alpine/git:2.43.0
|
alpine: registry.abrban.com/abrban/alpine:3.19
|
||||||
# Prefix for Docker Hub images in generated user-app Dockerfiles (node, php, …)
|
alpineGit: registry.abrban.com/abrban/alpine-git:2.43.0
|
||||||
baseImageRegistry: registry.abrban.com/proxy-dockerhub/library
|
# Seeded base images (gitops/jobs/seed-ci-images.yaml) — proxy-dockerhub cache can be corrupt on first pull.
|
||||||
|
baseImageRegistry: registry.abrban.com/abrban
|
||||||
|
# Secret with HTTP_PROXY/HTTPS_PROXY for Kaniko build jobs (npm, apk, git clone).
|
||||||
|
# Set to registry-egress-proxy in production; leave empty when nodes have direct egress.
|
||||||
|
egressProxySecret: ""
|
||||||
|
|
||||||
postgres:
|
postgres:
|
||||||
enabled: true
|
enabled: true
|
||||||
@@ -89,6 +99,13 @@ backend:
|
|||||||
cpu: "2"
|
cpu: "2"
|
||||||
memory: 2Gi
|
memory: 2Gi
|
||||||
extraEnv: {}
|
extraEnv: {}
|
||||||
|
# OTP SMS — credentials live in the platform Secret (mizbansms-username/password).
|
||||||
|
sms:
|
||||||
|
enabled: false
|
||||||
|
provider: mizbansms
|
||||||
|
from: "5000467254"
|
||||||
|
api: "2016"
|
||||||
|
userType: "2"
|
||||||
env:
|
env:
|
||||||
NODE_ENV: production
|
NODE_ENV: production
|
||||||
PORT: "4000"
|
PORT: "4000"
|
||||||
@@ -124,7 +141,7 @@ secrets:
|
|||||||
# Use a pre-created Secret instead of chart-managed one. Required for GitOps
|
# Use a pre-created Secret instead of chart-managed one. Required for GitOps
|
||||||
# (Argo CD renders with `helm template`, so lookup/randAlphaNum regenerate on
|
# (Argo CD renders with `helm template`, so lookup/randAlphaNum regenerate on
|
||||||
# every sync). Secret must contain keys: postgres-password, jwt-secret,
|
# every sync). Secret must contain keys: postgres-password, jwt-secret,
|
||||||
# jwt-refresh-secret, cluster-kubeconfig-key.
|
# jwt-refresh-secret, cluster-kubeconfig-key, redis-password, elastic-password.
|
||||||
existingSecret: ""
|
existingSecret: ""
|
||||||
jwtSecret: ""
|
jwtSecret: ""
|
||||||
jwtRefreshSecret: ""
|
jwtRefreshSecret: ""
|
||||||
|
|||||||
@@ -181,24 +181,20 @@ spec:
|
|||||||
- name: data
|
- name: data
|
||||||
mountPath: /usr/share/elasticsearch/data
|
mountPath: /usr/share/elasticsearch/data
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
exec:
|
||||||
path: /_cluster/health?local=true
|
command:
|
||||||
port: 9200
|
- sh
|
||||||
scheme: HTTP
|
- -c
|
||||||
httpHeaders:
|
- curl -sf -u "elastic:${ELASTIC_PASSWORD}" http://127.0.0.1:9200/_cluster/health?local=true
|
||||||
- name: Authorization
|
|
||||||
value: "Basic ZWxhc3RpYzpDbG91ZEhvc3QyMDI0IVNlY3VyZQ=="
|
|
||||||
initialDelaySeconds: 30
|
initialDelaySeconds: 30
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
timeoutSeconds: 5
|
timeoutSeconds: 5
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
httpGet:
|
exec:
|
||||||
path: /_cluster/health?local=true
|
command:
|
||||||
port: 9200
|
- sh
|
||||||
scheme: HTTP
|
- -c
|
||||||
httpHeaders:
|
- curl -sf -u "elastic:${ELASTIC_PASSWORD}" http://127.0.0.1:9200/_cluster/health?local=true
|
||||||
- name: Authorization
|
|
||||||
value: "Basic ZWxhc3RpYzpDbG91ZEhvc3QyMDI0IVNlY3VyZQ=="
|
|
||||||
initialDelaySeconds: 60
|
initialDelaySeconds: 60
|
||||||
periodSeconds: 30
|
periodSeconds: 30
|
||||||
timeoutSeconds: 10
|
timeoutSeconds: 10
|
||||||
|
|||||||
@@ -137,4 +137,29 @@ describe('BuildService', () => {
|
|||||||
expect(dockerfile).toContain('dotnet publish "$CSPROJ"');
|
expect(dockerfile).toContain('dotnet publish "$CSPROJ"');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('egressProxyEnvFrom', () => {
|
||||||
|
it('returns secretRef when BUILD_EGRESS_PROXY_SECRET is set', () => {
|
||||||
|
const config = (service as any).configService as { get: jest.Mock };
|
||||||
|
config.get.mockImplementation((key: string) => {
|
||||||
|
if (key === 'build.egressProxySecret') return 'registry-egress-proxy';
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect((service as any).egressProxyEnvFrom()).toEqual([
|
||||||
|
{ secretRef: { name: 'registry-egress-proxy' } },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns undefined when egress proxy is disabled', () => {
|
||||||
|
const config = (service as any).configService as { get: jest.Mock };
|
||||||
|
config.get.mockImplementation((key: string) => {
|
||||||
|
if (key === 'build.egressProxySecret') return '';
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect((service as any).egressProxyEnvFrom()).toBeUndefined();
|
||||||
|
expect((service as any).withEgressProxy({ name: 'kaniko' })).toEqual({ name: 'kaniko' });
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -91,6 +91,22 @@ export class BuildService {
|
|||||||
return this.baseImage(dockerHubFallback);
|
return this.baseImage(dockerHubFallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Egress HTTP(S) proxy for build pods on restricted networks (Iran).
|
||||||
|
* Kaniko forwards these env vars into Dockerfile RUN steps (npm, apk, composer, pip).
|
||||||
|
*/
|
||||||
|
private egressProxyEnvFrom(): k8s.V1EnvFromSource[] | undefined {
|
||||||
|
const secretName = this.configService.get<string>('build.egressProxySecret');
|
||||||
|
if (!secretName?.trim()) return undefined;
|
||||||
|
return [{ secretRef: { name: secretName.trim() } }];
|
||||||
|
}
|
||||||
|
|
||||||
|
private withEgressProxy<T extends Record<string, unknown>>(container: T): T {
|
||||||
|
const envFrom = this.egressProxyEnvFrom();
|
||||||
|
if (!envFrom) return container;
|
||||||
|
return { ...container, envFrom };
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Git branch names come from users and end up in a shell command — accept
|
* Git branch names come from users and end up in a shell command — accept
|
||||||
* only conservative ref characters and reject anything option-like.
|
* only conservative ref characters and reject anything option-like.
|
||||||
@@ -418,10 +434,10 @@ export class BuildService {
|
|||||||
* Returns { imageUri, buildLog } — the full image URI and the build logs.
|
* Returns { imageUri, buildLog } — the full image URI and the build logs.
|
||||||
*/
|
*/
|
||||||
async buildImage(app: Application, deploymentId?: string): Promise<{ imageUri: string; buildLog: string }> {
|
async buildImage(app: Application, deploymentId?: string): Promise<{ imageUri: string; buildLog: string }> {
|
||||||
const registryUrl = this.registryService.getRegistryUrl();
|
const registryPushUrl = this.registryService.getRegistryPushUrl();
|
||||||
const buildNamespace = this.registryService.getBuildNamespace();
|
const buildNamespace = this.registryService.getBuildNamespace();
|
||||||
const tag = `${Date.now()}`;
|
const tag = `${Date.now()}`;
|
||||||
const imageUri = this.registryService.buildImageReference(app.userId, app.name, tag);
|
const imageUri = this.registryService.buildPushImageReference(app.userId, app.name, tag);
|
||||||
|
|
||||||
this.logger.log(`Starting image build for ${app.name} → ${imageUri}`);
|
this.logger.log(`Starting image build for ${app.name} → ${imageUri}`);
|
||||||
|
|
||||||
@@ -514,11 +530,11 @@ export class BuildService {
|
|||||||
// Build the Kaniko Job spec
|
// Build the Kaniko Job spec
|
||||||
// Always use dir context — init containers prepare /workspace/source
|
// Always use dir context — init containers prepare /workspace/source
|
||||||
const kanikoArgs = [
|
const kanikoArgs = [
|
||||||
'--dockerfile=/workspace/Dockerfile',
|
'--dockerfile=Dockerfile',
|
||||||
'--context=dir:///workspace/source',
|
'--context=dir:///workspace/source',
|
||||||
`--destination=${imageUri}`,
|
`--destination=${imageUri}`,
|
||||||
'--cache=true',
|
'--cache=true',
|
||||||
`--cache-repo=${registryUrl}/${app.userId}/cache`,
|
`--cache-repo=${registryPushUrl}/${app.userId}/cache`,
|
||||||
'--insecure',
|
'--insecure',
|
||||||
'--skip-tls-verify',
|
'--skip-tls-verify',
|
||||||
'--single-snapshot',
|
'--single-snapshot',
|
||||||
@@ -528,7 +544,10 @@ export class BuildService {
|
|||||||
const volumes: any[] = [
|
const volumes: any[] = [
|
||||||
{
|
{
|
||||||
name: 'docker-config',
|
name: 'docker-config',
|
||||||
secret: { secretName: 'registry-credentials' },
|
secret: {
|
||||||
|
secretName: 'registry-credentials',
|
||||||
|
items: [{ key: '.dockerconfigjson', path: 'config.json' }],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'dockerfile',
|
name: 'dockerfile',
|
||||||
@@ -552,7 +571,7 @@ export class BuildService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add init container that unzips the source code from PVC
|
// Add init container that unzips the source code from PVC
|
||||||
initContainers.push({
|
initContainers.push(this.withEgressProxy({
|
||||||
name: 'unzip-source',
|
name: 'unzip-source',
|
||||||
image: this.resolveBuildImage('alpine', 'alpine:3.19'),
|
image: this.resolveBuildImage('alpine', 'alpine:3.19'),
|
||||||
imagePullPolicy: 'IfNotPresent',
|
imagePullPolicy: 'IfNotPresent',
|
||||||
@@ -564,7 +583,6 @@ export class BuildService {
|
|||||||
reject_unsafe_path() {
|
reject_unsafe_path() {
|
||||||
case "$1" in ..|../*|*/../*|/*) echo "ERROR: unsafe archive path: $1" && exit 1;; esac
|
case "$1" in ..|../*|*/../*|/*) echo "ERROR: unsafe archive path: $1" && exit 1;; esac
|
||||||
} &&
|
} &&
|
||||||
cp /workspace/Dockerfile /workspace-out/Dockerfile &&
|
|
||||||
mkdir -p /tmp/extract &&
|
mkdir -p /tmp/extract &&
|
||||||
cd /tmp/extract &&
|
cd /tmp/extract &&
|
||||||
if tar tzf /source-pvc/source.zip >/dev/null 2>&1; then
|
if tar tzf /source-pvc/source.zip >/dev/null 2>&1; then
|
||||||
@@ -594,6 +612,7 @@ export class BuildService {
|
|||||||
cp -a /tmp/extract/. /workspace-out/source/
|
cp -a /tmp/extract/. /workspace-out/source/
|
||||||
fi &&
|
fi &&
|
||||||
rm -rf /tmp/extract &&
|
rm -rf /tmp/extract &&
|
||||||
|
cp /dockerfile/Dockerfile /workspace-out/source/Dockerfile &&
|
||||||
echo "--- Final workspace contents ---" &&
|
echo "--- Final workspace contents ---" &&
|
||||||
ls -la /workspace-out/source/
|
ls -la /workspace-out/source/
|
||||||
`,
|
`,
|
||||||
@@ -602,12 +621,12 @@ export class BuildService {
|
|||||||
{ name: 'workspace', mountPath: '/workspace-out' },
|
{ name: 'workspace', mountPath: '/workspace-out' },
|
||||||
{
|
{
|
||||||
name: 'dockerfile',
|
name: 'dockerfile',
|
||||||
mountPath: '/workspace/Dockerfile',
|
mountPath: '/dockerfile/Dockerfile',
|
||||||
subPath: 'Dockerfile',
|
subPath: 'Dockerfile',
|
||||||
},
|
},
|
||||||
{ name: 'source-pvc', mountPath: '/source-pvc' },
|
{ name: 'source-pvc', mountPath: '/source-pvc' },
|
||||||
],
|
],
|
||||||
});
|
}));
|
||||||
} else if (hasGitUrl) {
|
} else if (hasGitUrl) {
|
||||||
// Validate user-controlled values before they get anywhere near a shell.
|
// Validate user-controlled values before they get anywhere near a shell.
|
||||||
this.assertSafeGitUrl(app.gitUrl!);
|
this.assertSafeGitUrl(app.gitUrl!);
|
||||||
@@ -632,7 +651,7 @@ export class BuildService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clone git repo into /workspace/source, then copy our generated Dockerfile
|
// Clone git repo into /workspace/source, then copy our generated Dockerfile
|
||||||
initContainers.push({
|
initContainers.push(this.withEgressProxy({
|
||||||
name: 'git-clone',
|
name: 'git-clone',
|
||||||
image: this.resolveBuildImage('alpineGit', 'alpine/git:2.43.0'),
|
image: this.resolveBuildImage('alpineGit', 'alpine/git:2.43.0'),
|
||||||
imagePullPolicy: 'IfNotPresent',
|
imagePullPolicy: 'IfNotPresent',
|
||||||
@@ -661,7 +680,7 @@ export class BuildService {
|
|||||||
fi
|
fi
|
||||||
echo ">>> Cloning branch '$GIT_BRANCH' from $GIT_URL"
|
echo ">>> Cloning branch '$GIT_BRANCH' from $GIT_URL"
|
||||||
git clone --depth 1 --branch "$GIT_BRANCH" "$GIT_URL" /workspace-out/source
|
git clone --depth 1 --branch "$GIT_BRANCH" "$GIT_URL" /workspace-out/source
|
||||||
cp /dockerfile/Dockerfile /workspace-out/Dockerfile
|
cp /dockerfile/Dockerfile /workspace-out/source/Dockerfile
|
||||||
echo ">>> Workspace contents:"
|
echo ">>> Workspace contents:"
|
||||||
ls -la /workspace-out/source/
|
ls -la /workspace-out/source/
|
||||||
`,
|
`,
|
||||||
@@ -670,7 +689,7 @@ export class BuildService {
|
|||||||
{ name: 'workspace', mountPath: '/workspace-out' },
|
{ name: 'workspace', mountPath: '/workspace-out' },
|
||||||
{ name: 'dockerfile', mountPath: '/dockerfile' },
|
{ name: 'dockerfile', mountPath: '/dockerfile' },
|
||||||
],
|
],
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kaniko container volume mounts
|
// Kaniko container volume mounts
|
||||||
@@ -692,7 +711,7 @@ export class BuildService {
|
|||||||
'-c',
|
'-c',
|
||||||
`
|
`
|
||||||
mkdir -p /workspace-out/source &&
|
mkdir -p /workspace-out/source &&
|
||||||
cp /dockerfile/Dockerfile /workspace-out/Dockerfile &&
|
cp /dockerfile/Dockerfile /workspace-out/source/Dockerfile &&
|
||||||
echo ">>> Prepared empty workspace for fresh install" &&
|
echo ">>> Prepared empty workspace for fresh install" &&
|
||||||
ls -la /workspace-out/
|
ls -la /workspace-out/
|
||||||
`,
|
`,
|
||||||
@@ -719,7 +738,7 @@ export class BuildService {
|
|||||||
serviceAccountName: this.configService.get<string>('build.serviceAccount'),
|
serviceAccountName: this.configService.get<string>('build.serviceAccount'),
|
||||||
initContainers: initContainers.length > 0 ? initContainers : undefined,
|
initContainers: initContainers.length > 0 ? initContainers : undefined,
|
||||||
containers: [
|
containers: [
|
||||||
{
|
this.withEgressProxy({
|
||||||
name: 'kaniko',
|
name: 'kaniko',
|
||||||
image: this.getKanikoImage(),
|
image: this.getKanikoImage(),
|
||||||
imagePullPolicy: 'IfNotPresent',
|
imagePullPolicy: 'IfNotPresent',
|
||||||
@@ -735,7 +754,7 @@ export class BuildService {
|
|||||||
memory: this.configService.get<string>('build.kaniko.memoryLimit') || '4Gi',
|
memory: this.configService.get<string>('build.kaniko.memoryLimit') || '4Gi',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
],
|
],
|
||||||
restartPolicy: 'Never',
|
restartPolicy: 'Never',
|
||||||
volumes,
|
volumes,
|
||||||
@@ -1118,25 +1137,27 @@ export class BuildService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Ensure registry-credentials secret (docker config for Kaniko to push)
|
// 3. Ensure registry-credentials secret (docker config for Kaniko push/pull)
|
||||||
const registrySecretName = 'registry-credentials';
|
const registrySecretName = 'registry-credentials';
|
||||||
|
const registrySecretBody = {
|
||||||
|
metadata: { name: registrySecretName, namespace },
|
||||||
|
type: 'kubernetes.io/dockerconfigjson',
|
||||||
|
data: {
|
||||||
|
'.dockerconfigjson': Buffer.from(this.registryService.buildDockerConfigJson()).toString('base64'),
|
||||||
|
},
|
||||||
|
};
|
||||||
try {
|
try {
|
||||||
await coreApi.readNamespacedSecret({
|
await coreApi.replaceNamespacedSecret({
|
||||||
name: registrySecretName,
|
name: registrySecretName,
|
||||||
namespace,
|
namespace,
|
||||||
|
body: registrySecretBody,
|
||||||
});
|
});
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (err.code === 404 || err.body?.code === 404) {
|
if (err.code === 404 || err.body?.code === 404) {
|
||||||
this.logger.log(`Secret "${registrySecretName}" not found in "${namespace}" — creating it`);
|
this.logger.log(`Secret "${registrySecretName}" not found in "${namespace}" — creating it`);
|
||||||
await coreApi.createNamespacedSecret({
|
await coreApi.createNamespacedSecret({
|
||||||
namespace,
|
namespace,
|
||||||
body: {
|
body: registrySecretBody,
|
||||||
metadata: { name: registrySecretName, namespace },
|
|
||||||
type: 'kubernetes.io/dockerconfigjson',
|
|
||||||
data: {
|
|
||||||
'.dockerconfigjson': Buffer.from(this.registryService.buildDockerConfigJson()).toString('base64'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw err;
|
throw err;
|
||||||
|
|||||||
@@ -139,17 +139,23 @@ export default () => ({
|
|||||||
* and managed-service charts (e.g. `node:20-alpine` →
|
* and managed-service charts (e.g. `node:20-alpine` →
|
||||||
* `registry.abrban.com/proxy-dockerhub/library/node:20-alpine`).
|
* `registry.abrban.com/proxy-dockerhub/library/node:20-alpine`).
|
||||||
*/
|
*/
|
||||||
baseImageRegistry: (process.env.BASE_IMAGE_REGISTRY || 'registry.abrban.com/proxy-dockerhub/library')
|
baseImageRegistry: (process.env.BASE_IMAGE_REGISTRY || 'registry.abrban.com/abrban')
|
||||||
.trim()
|
.trim()
|
||||||
.replace(/\/+$/, ''),
|
.replace(/\/+$/, ''),
|
||||||
/** Full image refs for Kaniko jobs — override via Helm values or env. */
|
/** Full image refs for Kaniko jobs — override via Helm values or env. */
|
||||||
images: {
|
images: {
|
||||||
kaniko:
|
kaniko:
|
||||||
process.env.KANIKO_IMAGE ||
|
process.env.KANIKO_IMAGE ||
|
||||||
'registry.abrban.com/proxy-gcr/kaniko-project/executor:v1.23.2',
|
'registry.abrban.com/abrban/kaniko-executor:v1.27.6-debug',
|
||||||
alpine: (process.env.BUILD_ALPINE_IMAGE || 'registry.abrban.com/proxy-dockerhub/library/alpine:3.19').trim(),
|
alpine: (process.env.BUILD_ALPINE_IMAGE || 'registry.abrban.com/abrban/alpine:3.19').trim(),
|
||||||
alpineGit: (process.env.BUILD_ALPINE_GIT_IMAGE || 'registry.abrban.com/proxy-dockerhub/alpine/git:2.43.0').trim(),
|
alpineGit: (process.env.BUILD_ALPINE_GIT_IMAGE || 'registry.abrban.com/abrban/alpine-git:2.43.0').trim(),
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Secret name with HTTP_PROXY / HTTPS_PROXY / NO_PROXY for build pods
|
||||||
|
* (Kaniko RUN steps: npm, apk, composer, pip; init containers: apk, git clone).
|
||||||
|
* Empty = disabled (clusters with direct egress).
|
||||||
|
*/
|
||||||
|
egressProxySecret: (process.env.BUILD_EGRESS_PROXY_SECRET || '').trim(),
|
||||||
/** Kaniko build container resources — tune for large images. */
|
/** Kaniko build container resources — tune for large images. */
|
||||||
kaniko: {
|
kaniko: {
|
||||||
cpuRequest: process.env.KANIKO_CPU_REQUEST || '500m',
|
cpuRequest: process.env.KANIKO_CPU_REQUEST || '500m',
|
||||||
|
|||||||
@@ -28,6 +28,29 @@ export class RegistryService {
|
|||||||
return url.replace(/^https?:\/\//, '');
|
return url.replace(/^https?:\/\//, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Docker auth key — hostname[:port] only, no repository path prefix. */
|
||||||
|
getRegistryHost(): string {
|
||||||
|
const url = this.getRegistryUrl();
|
||||||
|
const slash = url.indexOf('/');
|
||||||
|
return slash === -1 ? url : url.slice(0, slash);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Push target host[:port][/project] — Kaniko destination (may differ from pull URL on Harbor). */
|
||||||
|
getRegistryPushUrl(): string {
|
||||||
|
const buildNs = this.getBuildNamespace();
|
||||||
|
const url =
|
||||||
|
this.configService.get<string>('registry.url') ||
|
||||||
|
`registry.${buildNs}.svc.cluster.local:5000`;
|
||||||
|
return url.replace(/^https?:\/\//, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Push target host:port only, no repository path prefix. */
|
||||||
|
getRegistryPushHost(): string {
|
||||||
|
const url = this.getRegistryPushUrl();
|
||||||
|
const slash = url.indexOf('/');
|
||||||
|
return slash === -1 ? url : url.slice(0, slash);
|
||||||
|
}
|
||||||
|
|
||||||
getRegistryCredentials(): { username: string; password: string } {
|
getRegistryCredentials(): { username: string; password: string } {
|
||||||
return {
|
return {
|
||||||
username: this.configService.get<string>('registry.username') || 'admin',
|
username: this.configService.get<string>('registry.username') || 'admin',
|
||||||
@@ -39,6 +62,11 @@ export class RegistryService {
|
|||||||
return `${this.getRegistryUrl()}/${userId}/${appName}:${tag}`;
|
return `${this.getRegistryUrl()}/${userId}/${appName}:${tag}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Kaniko push target — uses registry.url (in-cluster harbor-registry on Harbor setups). */
|
||||||
|
buildPushImageReference(userId: string, appName: string, tag: string): string {
|
||||||
|
return `${this.getRegistryPushUrl()}/${userId}/${appName}:${tag}`;
|
||||||
|
}
|
||||||
|
|
||||||
parseImageReference(imageRef: string): ParsedImageReference {
|
parseImageReference(imageRef: string): ParsedImageReference {
|
||||||
const normalized = imageRef.replace(/^https?:\/\//, '');
|
const normalized = imageRef.replace(/^https?:\/\//, '');
|
||||||
const slashIdx = normalized.indexOf('/');
|
const slashIdx = normalized.indexOf('/');
|
||||||
@@ -56,24 +84,35 @@ export class RegistryService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Re-point any stored image (e.g. legacy external host) to the in-cluster registry. */
|
/** Re-point any stored image (e.g. push host) to the pull registry URL for kubelet. */
|
||||||
normalizeImageReference(imageRef: string): string {
|
normalizeImageReference(imageRef: string): string {
|
||||||
const { repository, tag } = this.parseImageReference(imageRef);
|
const { repository, tag } = this.parseImageReference(imageRef);
|
||||||
return `${this.getRegistryUrl()}/${repository}:${tag}`;
|
const pullBase = this.getRegistryUrl().replace(/\/$/, '');
|
||||||
|
const slash = pullBase.indexOf('/');
|
||||||
|
const pullPath = slash === -1 ? '' : pullBase.slice(slash + 1);
|
||||||
|
let repo = repository;
|
||||||
|
if (pullPath && (repo === pullPath || repo.startsWith(`${pullPath}/`))) {
|
||||||
|
repo = repo === pullPath ? '' : repo.slice(pullPath.length + 1);
|
||||||
|
}
|
||||||
|
if (!repo) {
|
||||||
|
throw new Error(`Invalid image reference after normalization: ${imageRef}`);
|
||||||
|
}
|
||||||
|
return `${pullBase}/${repo}:${tag}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
buildDockerConfigJson(): string {
|
buildDockerConfigJson(): string {
|
||||||
const { username, password } = this.getRegistryCredentials();
|
const { username, password } = this.getRegistryCredentials();
|
||||||
const auth = username && password ? Buffer.from(`${username}:${password}`).toString('base64') : '';
|
const auth = username && password ? Buffer.from(`${username}:${password}`).toString('base64') : '';
|
||||||
const host = this.getRegistryUrl();
|
const pullHost = this.getRegistryHost();
|
||||||
return JSON.stringify({
|
const pushHost = this.getRegistryPushHost();
|
||||||
auths: {
|
const auths: Record<string, { auth: string }> = {
|
||||||
[host]: { auth },
|
[pullHost]: { auth },
|
||||||
[`registry.${this.getBuildNamespace()}.svc.cluster.local:5000`]: {
|
[`registry.${this.getBuildNamespace()}.svc.cluster.local:5000`]: { auth },
|
||||||
auth,
|
};
|
||||||
},
|
if (pushHost !== pullHost) {
|
||||||
},
|
auths[pushHost] = { auth };
|
||||||
});
|
}
|
||||||
|
return JSON.stringify({ auths });
|
||||||
}
|
}
|
||||||
|
|
||||||
async ensureRegistryPullSecret(coreApi: k8s.CoreV1Api, namespace: string): Promise<void> {
|
async ensureRegistryPullSecret(coreApi: k8s.CoreV1Api, namespace: string): Promise<void> {
|
||||||
|
|||||||
@@ -0,0 +1,124 @@
|
|||||||
|
# registry.abrban.com — Traefik path split
|
||||||
|
#
|
||||||
|
# Proxy-cache projects (proxy-dockerhub, proxy-gcr, …) MUST hit harbor-core so
|
||||||
|
# Harbor can pull upstream on demand. harbor-registry only stores blobs; it does
|
||||||
|
# not run proxy-cache logic → 404 for uncached proxy paths.
|
||||||
|
#
|
||||||
|
# Direct pushes (abrban/, rook/) stay on harbor-registry where Kaniko/skopeo
|
||||||
|
# wrote the blobs.
|
||||||
|
#
|
||||||
|
# Apply: kubectl apply -f gitops/harbor/registry-ingress.yaml
|
||||||
|
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: registry
|
||||||
|
namespace: cloudhost
|
||||||
|
annotations:
|
||||||
|
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||||
|
traefik.ingress.kubernetes.io/router.middlewares: cloudhost-long-timeout@kubernetescrd
|
||||||
|
spec:
|
||||||
|
ingressClassName: traefik
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- registry.abrban.com
|
||||||
|
secretName: abrban-wildcard-tls
|
||||||
|
rules:
|
||||||
|
- host: registry.abrban.com
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
# ── Proxy-cache (harbor-core serves v2 + on-demand upstream pull) ──
|
||||||
|
- path: /v2/proxy-dockerhub/
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: harbor-core
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
- path: /v2/proxy-gcr/
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: harbor-core
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
- path: /v2/proxy-quay/
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: harbor-core
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
- path: /v2/proxy-k8s/
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: harbor-core
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
- path: /v2/proxy-gitea/
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: harbor-core
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
# ── abrban/rook project images (served by harbor-core; required for k3s mirror pulls) ──
|
||||||
|
- path: /v2/abrban/
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: harbor-core
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
- path: /v2/rook/
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: harbor-core
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
# ── Legacy registry (platform images pre-Harbor) ──
|
||||||
|
- path: /v2/
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: registry
|
||||||
|
port:
|
||||||
|
number: 5000
|
||||||
|
# ── Harbor UI / API ──
|
||||||
|
- path: /api/
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: harbor-core
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
- path: /service/
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: harbor-core
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
- path: /c/
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: harbor-core
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
- path: /chartrepo/
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: harbor-core
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: harbor-portal
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
@@ -31,7 +31,7 @@ spec:
|
|||||||
mountPath: /workspace
|
mountPath: /workspace
|
||||||
containers:
|
containers:
|
||||||
- name: kaniko
|
- name: kaniko
|
||||||
image: registry.abrban.com/proxy-gcr/kaniko-project/executor:v1.23.2
|
image: registry.abrban.com/abrban/kaniko-executor:v1.23.2
|
||||||
env:
|
env:
|
||||||
- name: IMAGE_TAG
|
- name: IMAGE_TAG
|
||||||
value: bootstrap
|
value: bootstrap
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
# kubectl -n cloudhost wait --for=condition=complete job/seed-ci-images --timeout=15m
|
# kubectl -n cloudhost wait --for=condition=complete job/seed-ci-images --timeout=15m
|
||||||
#
|
#
|
||||||
# Images copied (see RUNBOOK-CICD.fa.md):
|
# Images copied (see RUNBOOK-CICD.fa.md):
|
||||||
# abrban/act-runner, abrban/alpine-git, abrban/node, abrban/kaniko-executor
|
# abrban/act-runner, abrban/alpine, abrban/alpine-git, abrban/node, abrban/kaniko-executor
|
||||||
apiVersion: batch/v1
|
apiVersion: batch/v1
|
||||||
kind: Job
|
kind: Job
|
||||||
metadata:
|
metadata:
|
||||||
@@ -39,6 +39,9 @@ spec:
|
|||||||
skopeo copy --dest-tls-verify=false --dest-creds="${CREDS}" \
|
skopeo copy --dest-tls-verify=false --dest-creds="${CREDS}" \
|
||||||
docker://docker.io/gitea/act_runner:0.2.11 \
|
docker://docker.io/gitea/act_runner:0.2.11 \
|
||||||
"${DEST}/act-runner:0.2.11"
|
"${DEST}/act-runner:0.2.11"
|
||||||
|
skopeo copy --dest-tls-verify=false --dest-creds="${CREDS}" \
|
||||||
|
docker://docker.io/library/alpine:3.19 \
|
||||||
|
"${DEST}/alpine:3.19"
|
||||||
skopeo copy --dest-tls-verify=false --dest-creds="${CREDS}" \
|
skopeo copy --dest-tls-verify=false --dest-creds="${CREDS}" \
|
||||||
docker://docker.io/alpine/git:2.43.0 \
|
docker://docker.io/alpine/git:2.43.0 \
|
||||||
"${DEST}/alpine-git:2.43.0"
|
"${DEST}/alpine-git:2.43.0"
|
||||||
@@ -46,6 +49,14 @@ spec:
|
|||||||
docker://docker.io/library/node:24-alpine \
|
docker://docker.io/library/node:24-alpine \
|
||||||
"${DEST}/node:24-alpine"
|
"${DEST}/node:24-alpine"
|
||||||
skopeo copy --dest-tls-verify=false --dest-creds="${CREDS}" \
|
skopeo copy --dest-tls-verify=false --dest-creds="${CREDS}" \
|
||||||
docker://gcr.io/kaniko-project/executor:v1.27.6-debug \
|
docker://docker.io/library/node:20-alpine \
|
||||||
|
"${DEST}/node:20-alpine"
|
||||||
|
# Tag present in Harbor abrban/ — seed via proxy-gcr (see seed-ci-images.yaml).
|
||||||
|
skopeo copy --dest-tls-verify=false --dest-creds="${CREDS}" \
|
||||||
|
docker://registry.abrban.com/proxy-gcr/kaniko-project/executor:v1.23.2 \
|
||||||
|
"${DEST}/kaniko-executor:v1.23.2"
|
||||||
|
# Alias for CI/configs that reference the debug tag name.
|
||||||
|
skopeo copy --dest-tls-verify=false --dest-creds="${CREDS}" \
|
||||||
|
docker://harbor-registry.cloudhost.svc.cluster.local:5000/abrban/kaniko-executor:v1.23.2 \
|
||||||
"${DEST}/kaniko-executor:v1.27.6-debug"
|
"${DEST}/kaniko-executor:v1.27.6-debug"
|
||||||
echo SEED_OK
|
echo SEED_OK
|
||||||
|
|||||||
@@ -11,6 +11,11 @@
|
|||||||
namespace: cloudhost
|
namespace: cloudhost
|
||||||
createNamespace: false
|
createNamespace: false
|
||||||
|
|
||||||
|
registry:
|
||||||
|
credentialsSecret: harbor-core
|
||||||
|
credentialsPasswordKey: REGISTRY_CREDENTIAL_PASSWORD
|
||||||
|
username: harbor_registry_user
|
||||||
|
|
||||||
global:
|
global:
|
||||||
storageClass: local-path
|
storageClass: local-path
|
||||||
|
|
||||||
@@ -31,10 +36,12 @@ images:
|
|||||||
# Kaniko job images — Harbor proxy-cache (first pull is slow, no manual seed needed).
|
# Kaniko job images — Harbor proxy-cache (first pull is slow, no manual seed needed).
|
||||||
build:
|
build:
|
||||||
images:
|
images:
|
||||||
kaniko: registry.abrban.com/proxy-gcr/kaniko-project/executor:v1.23.2
|
kaniko: registry.abrban.com/abrban/kaniko-executor:v1.27.6-debug
|
||||||
alpine: registry.abrban.com/proxy-dockerhub/library/alpine:3.19
|
alpine: registry.abrban.com/abrban/alpine:3.19
|
||||||
alpineGit: registry.abrban.com/proxy-dockerhub/alpine/git:2.43.0
|
alpineGit: registry.abrban.com/abrban/alpine-git:2.43.0
|
||||||
baseImageRegistry: registry.abrban.com/proxy-dockerhub/library
|
baseImageRegistry: registry.abrban.com/abrban
|
||||||
|
# Kaniko + init containers (npm/apk/composer/pip/git clone) on restricted egress.
|
||||||
|
egressProxySecret: registry-egress-proxy
|
||||||
|
|
||||||
postgres:
|
postgres:
|
||||||
enabled: true
|
enabled: true
|
||||||
@@ -112,6 +119,13 @@ backend:
|
|||||||
KIBANA_SYSTEM_PASSWORD: "CHANGE_VIA_SEALEDSECRET_OR_KUBECTL"
|
KIBANA_SYSTEM_PASSWORD: "CHANGE_VIA_SEALEDSECRET_OR_KUBECTL"
|
||||||
# Swagger disabled in production unless explicitly enabled
|
# Swagger disabled in production unless explicitly enabled
|
||||||
# SWAGGER_ENABLED: "true"
|
# SWAGGER_ENABLED: "true"
|
||||||
|
# OTP SMS — username/password in abrban-platform-secrets (SealedSecret).
|
||||||
|
sms:
|
||||||
|
enabled: true
|
||||||
|
provider: mizbansms
|
||||||
|
from: "5000467254"
|
||||||
|
api: "2016"
|
||||||
|
userType: "2"
|
||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
# Real SealedSecret lives in cloud-host-gitops/sealed-secrets/ — never commit plaintext passwords.
|
# Real SealedSecret lives in cloud-host-gitops/sealed-secrets/ — never commit plaintext passwords.
|
||||||
#
|
#
|
||||||
# Required keys (must match backend Deployment + validate-production-config):
|
# Required keys (must match backend Deployment + validate-production-config):
|
||||||
# postgres-password, jwt-secret, jwt-refresh-secret, cluster-kubeconfig-key, redis-password
|
# postgres-password, jwt-secret, jwt-refresh-secret, cluster-kubeconfig-key,
|
||||||
|
# redis-password, elastic-password (must match elasticsearch-credentials in logging),
|
||||||
|
# mizbansms-username, mizbansms-password (OTP SMS — required when backend.sms.enabled)
|
||||||
#
|
#
|
||||||
# Generate (replace CHANGE_ME_* with strong random values):
|
# Generate (replace CHANGE_ME_* with strong random values):
|
||||||
#
|
#
|
||||||
@@ -13,6 +15,9 @@
|
|||||||
# --from-literal=jwt-refresh-secret='CHANGE_ME_REFRESH_32CHARS_MIN' \
|
# --from-literal=jwt-refresh-secret='CHANGE_ME_REFRESH_32CHARS_MIN' \
|
||||||
# --from-literal=cluster-kubeconfig-key='0123456789abcdef0123456789abcdef' \
|
# --from-literal=cluster-kubeconfig-key='0123456789abcdef0123456789abcdef' \
|
||||||
# --from-literal=redis-password='CHANGE_ME_REDIS' \
|
# --from-literal=redis-password='CHANGE_ME_REDIS' \
|
||||||
|
# --from-literal=elastic-password='CHANGE_ME_ELASTIC' \
|
||||||
|
# --from-literal=mizbansms-username='CHANGE_ME_SMS_USER' \
|
||||||
|
# --from-literal=mizbansms-password='CHANGE_ME_SMS_PASS' \
|
||||||
# --dry-run=client -o json \
|
# --dry-run=client -o json \
|
||||||
# | kubeseal \
|
# | kubeseal \
|
||||||
# --controller-name=sealed-secrets-controller \
|
# --controller-name=sealed-secrets-controller \
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ spec:
|
|||||||
mountPath: /workspace
|
mountPath: /workspace
|
||||||
containers:
|
containers:
|
||||||
- name: kaniko
|
- name: kaniko
|
||||||
image: registry.abrban.com/proxy-gcr/kaniko-project/executor:v1.23.2
|
image: registry.abrban.com/abrban/kaniko-executor:v1.23.2
|
||||||
command:
|
command:
|
||||||
- sh
|
- sh
|
||||||
- -ec
|
- -ec
|
||||||
|
|||||||
Reference in New Issue
Block a user