From 4f45ee316ff537466c7ab4cb7b733462fdc60828 Mon Sep 17 00:00:00 2001 From: David Herberth Date: Fri, 20 Sep 2024 11:18:36 +0200 Subject: [PATCH] ref(docker): Support multi-arch images through docker buildkit --- src/targets/docker.ts | 48 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/src/targets/docker.ts b/src/targets/docker.ts index ca12abd6..4a51f2dd 100644 --- a/src/targets/docker.ts +++ b/src/targets/docker.ts @@ -86,7 +86,7 @@ export class DockerTarget extends BaseTarget { * Pushes the the source image into local * @param revision Image tag, usually the git revision */ - public async pull(revision: string): Promise { + async pull(revision: string): Promise { this.logger.debug('Pulling source image...'); const sourceImage = renderTemplateSafe(this.dockerConfig.sourceTemplate, { ...this.dockerConfig, @@ -105,7 +105,7 @@ export class DockerTarget extends BaseTarget { * @param sourceRevision The tag/revision for the source image * @param version The release version for the target image */ - public async push(sourceRevision: string, version: string): Promise { + async push(sourceRevision: string, version: string): Promise { const sourceImage = renderTemplateSafe(this.dockerConfig.sourceTemplate, { ...this.dockerConfig, revision: sourceRevision, @@ -124,6 +124,40 @@ export class DockerTarget extends BaseTarget { ); } + /** + * Checks whether Docker BuildKit is installed. + */ + async hasBuildKit(): Promise { + return spawnProcess(DOCKER_BIN, ['buildx', 'version']).then(() => true).catch(() => false); + } + + /** + * Copies an existing local or remote docker image to a new destination. + * + * Requires BuildKit / `docker buildx` to be installed. + * + * @param sourceRevision The tag/revision for the source image + * @param version The release version for the target image + */ + async copy(sourceRevision: string, version: string): Promise { + const sourceImage = renderTemplateSafe(this.dockerConfig.sourceTemplate, { + ...this.dockerConfig, + revision: sourceRevision, + }); + const targetImage = renderTemplateSafe(this.dockerConfig.targetTemplate, { + ...this.dockerConfig, + version, + }); + + this.logger.debug(`Copying image from ${sourceImage} to ${targetImage}...`); + return spawnProcess( + DOCKER_BIN, + ['buildx', 'imagetools', 'create', '--tag', targetImage, sourceImage], + {}, + { showStdout: true } + ); + } + /** * Pushes a source image to Docker Hub * @@ -132,8 +166,14 @@ export class DockerTarget extends BaseTarget { */ public async publish(version: string, revision: string): Promise { await this.login(); - await this.pull(revision); - await this.push(revision, version); + + if (await this.hasBuildKit()) { + await this.copy(revision, version); + } else { + // Fall back to slow/old pull and push method. + await this.pull(revision); + await this.push(revision, version); + } this.logger.info('Docker release complete'); }