Fix Kaniko registry auth and push target for Harbor builds.
Mount docker config as config.json (Kaniko requirement), push via harbor-registry internal URL, and wire harbor_registry_user credentials in Helm/GitOps values. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -125,6 +125,15 @@ spec:
|
|||||||
name: {{ include "cloudhost-platform.secretName" . }}
|
name: {{ include "cloudhost-platform.secretName" . }}
|
||||||
key: mizbansms-password
|
key: mizbansms-password
|
||||||
{{- end }}
|
{{- 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,6 +28,12 @@ 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:
|
||||||
|
|||||||
@@ -434,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}`);
|
||||||
|
|
||||||
@@ -534,7 +534,7 @@ export class BuildService {
|
|||||||
'--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',
|
||||||
@@ -544,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',
|
||||||
|
|||||||
@@ -35,13 +35,20 @@ export class RegistryService {
|
|||||||
return slash === -1 ? url : url.slice(0, slash);
|
return slash === -1 ? url : url.slice(0, slash);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Push target host:port (may differ from pull URL on Harbor setups). */
|
/** Push target host[:port][/project] — Kaniko destination (may differ from pull URL on Harbor). */
|
||||||
getRegistryPushHost(): string {
|
getRegistryPushUrl(): string {
|
||||||
const buildNs = this.getBuildNamespace();
|
const buildNs = this.getBuildNamespace();
|
||||||
const url = this.configService.get<string>('registry.url') || `registry.${buildNs}.svc.cluster.local:5000`;
|
const url =
|
||||||
const normalized = url.replace(/^https?:\/\//, '');
|
this.configService.get<string>('registry.url') ||
|
||||||
const slash = normalized.indexOf('/');
|
`registry.${buildNs}.svc.cluster.local:5000`;
|
||||||
return slash === -1 ? normalized : normalized.slice(0, slash);
|
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 } {
|
||||||
@@ -55,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('/');
|
||||||
@@ -72,10 +84,20 @@ 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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user