fix(pipeline): update buildx create command to specify platforms for multi-arch images

Signed-off-by: 孙振宇 <>
This commit is contained in:
孙振宇 2025-02-10 04:00:49 +08:00
parent 6bf7687dd5
commit 0ff368f502

View File

@ -58,14 +58,9 @@ class ImageBuilder {
if (builderType == ImageBuilderTypes.DOCKER_IN_DOCKER && architectures.size() > 1) { if (builderType == ImageBuilderTypes.DOCKER_IN_DOCKER && architectures.size() > 1) {
steps.log.warn("ImageBuilder", "If you want to build multi-arch images and using Docker in Docker (DIND) as builder, system will using buildx to replace build command.") steps.log.warn("ImageBuilder", "If you want to build multi-arch images and using Docker in Docker (DIND) as builder, system will using buildx to replace build command.")
steps.log.info("ImageBuilder", "Creating buildx builder with name: multiarch-builder-${name}") steps.log.info("ImageBuilder", "Creating buildx builder with name: multiarch-builder-${name}")
steps.sh "docker buildx create --use --name multiarch-builder-${name}" steps.sh "docker buildx create --use --name multiarch-builder-${name} --platform ${architectures.join(",")}"
steps.log.info("ImageBuilder", "Inspecting buildx builder with name: multiarch-builder-${name}") steps.log.info("ImageBuilder", "Inspecting buildx builder with name: multiarch-builder-${name}")
steps.sh "docker buildx inspect --bootstrap" steps.sh "docker buildx inspect --bootstrap"
steps.log.info("ImageBuilder", "Register clean up hook for buildx builder deletion for builder named: multiarch-builder-${name}")
def context = steps.$build()
context.cleanup {
steps.sh "docker buildx rm multiarch-builder-${name} || true"
}
this.buildxBuilderName = "multiarch-builder-${name}" this.buildxBuilderName = "multiarch-builder-${name}"
} }
} }
@ -78,63 +73,78 @@ class ImageBuilder {
} }
def build() { def build() {
steps.log.info("ImageBuilder", "Building image with ${builderType.builder}") try {
steps.log.info("ImageBuilder", "Workspace sets to: ${workspace}") steps.log.info("ImageBuilder", "Building image with ${builderType.builder}")
steps.log.info("ImageBuilder", "Using dockerfile at: ${dockerfile}, context root sets to: ${contextRoot}") steps.log.info("ImageBuilder", "Workspace sets to: ${workspace}")
steps.log.info("ImageBuilder", "Using dockerfile at: ${dockerfile}, context root sets to: ${contextRoot}")
if (architectures == null || architectures.isEmpty()) { if (architectures == null || architectures.isEmpty()) {
steps.log.warn("ImageBuilder", "No architectures specified, using default amd64") steps.log.warn("ImageBuilder", "No architectures specified, using default amd64")
architectures = ['linux/amd64'] architectures = ['linux/amd64']
} }
steps.withCredentials([steps.usernamePassword(credentialsId: registryCredentialsId, passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME')]) {
steps.log.info("ImageBuilder", "Authentication to ${registry}")
switch(builderType) {
case ImageBuilderTypes.DOCKER_IN_DOCKER:
steps.sh "docker login -u ${steps.env.DOCKER_USERNAME} -p ${steps.env.DOCKER_PASSWORD} ${registry}"
break
case ImageBuilderTypes.KANIKO:
def auth = "${steps.env.DOCKER_USERNAME}:${steps.env.DOCKER_PASSWORD}".bytes.encodeBase64().toString()
steps.writeFile file: '/kaniko/.docker/config.json', text: """{
"auths": {
"${registry}": {
"auth": "${auth}"
}
}
}"""
break
default:
steps.error("Unsupported builder type: ${builderType.builder}")
}
}
steps.withCredentials([steps.usernamePassword(credentialsId: registryCredentialsId, passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME')]) {
steps.log.info("ImageBuilder", "Authentication to ${registry}")
switch(builderType) { switch(builderType) {
case ImageBuilderTypes.DOCKER_IN_DOCKER: case ImageBuilderTypes.DOCKER_IN_DOCKER:
steps.sh "docker login -u ${steps.env.DOCKER_USERNAME} -p ${steps.env.DOCKER_PASSWORD} ${registry}" steps.dir(workspace) {
break if (buildxBuilderName != null && !buildxBuilderName.isEmpty() && architectures.size() > 1) {
case ImageBuilderTypes.KANIKO: steps.log.info("ImageBuilder", "Building image ${registry}/${repository}/${name} with architectures: ${architectures} using buildx builder: ${buildxBuilderName}, tag sets to ${version}")
def auth = "${steps.env.DOCKER_USERNAME}:${steps.env.DOCKER_PASSWORD}".bytes.encodeBase64().toString() steps.sh "docker buildx build --builder ${buildxBuilderName} --platform ${architectures.join(",")} -t ${registry}/${repository}/${name}:${version} -f ${dockerfile} --push ${contextRoot}"
steps.writeFile file: '/kaniko/.docker/config.json', text: """{ } else {
"auths": { architectures.each { architecture ->
"${registry}": { def archTag = architecture.split("/")[1]
"auth": "${auth}" steps.log.info("ImageBuilder", "Building image ${registry}/${repository}/${name} with architectures: ${architectures}, tag sets to ${version}")
steps.sh "docker build -t ${registry}/${repository}/${name}:${version}-${archTag} --platform ${architecture} -f ${dockerfile} ${contextRoot}"
steps.sh "docker push ${registry}/${repository}/${name}:${version}-${archTag}"
} }
} }
}""" }
break
case ImageBuilderTypes.KANIKO:
steps.dir(workspace) {
architectures.each { architecture ->
def archTag = architecture.split("/")[1]
steps.log.info("ImageBuilder", "Building image ${registry}/${repository}/${name} with architectures: ${architectures}, tag sets to ${version}-${archTag}")
steps.sh "/kaniko/executor --log-format text --context ${contextRoot} --dockerfile ${dockerfile} --destination ${registry}/${repository}/${name}:${version}-${archTag} --custom-platform ${architecture}"
}
}
break break
default: default:
steps.error("Unsupported builder type: ${builderType.builder}") steps.error("Unsupported builder type: ${builderType.builder}")
} }
} } catch (Exception e) {
steps.log.error("ImageBuilder", "Failed to build image: ${e.message}")
switch(builderType) { throw e
case ImageBuilderTypes.DOCKER_IN_DOCKER: } finally {
steps.dir(workspace) { if (buildxBuilderName != null && !buildxBuilderName.isEmpty() && architectures.size() > 1) {
if (buildxBuilderName != null && !buildxBuilderName.isEmpty() && architectures.size() > 1) { try {
steps.log.info("ImageBuilder", "Building image ${registry}/${repository}/${name} with architectures: ${architectures} using buildx builder: ${buildxBuilderName}, tag sets to ${version}") steps.log.info("ImageBuilder", "Cleaning up buildx builder: ${buildxBuilderName}")
steps.sh "docker buildx build --builder ${buildxBuilderName} --platform ${architectures.join(",")} -t ${registry}/${repository}/${name}:${version} -f ${dockerfile} --push ${contextRoot}" steps.sh "docker buildx rm ${buildxBuilderName} || true"
} else { } catch (Exception e) {
architectures.each { architecture -> steps.log.warn("ImageBuilder", "Failed to cleanup buildx builder: ${e.message}")
def archTag = architecture.split("/")[1]
steps.log.info("ImageBuilder", "Building image ${registry}/${repository}/${name} with architectures: ${architectures}, tag sets to ${version}")
steps.sh "docker build -t ${registry}/${repository}/${name}:${version}-${archTag} --platform ${architecture} -f ${dockerfile} ${contextRoot}"
steps.sh "docker push ${registry}/${repository}/${name}:${version}-${archTag}"
}
}
} }
break }
case ImageBuilderTypes.KANIKO:
steps.dir(workspace) {
architectures.each { architecture ->
def archTag = architecture.split("/")[1]
steps.log.info("ImageBuilder", "Building image ${registry}/${repository}/${name} with architectures: ${architectures}, tag sets to ${version}-${archTag}")
steps.sh "/kaniko/executor --log-format text --context ${contextRoot} --dockerfile ${dockerfile} --destination ${registry}/${repository}/${name}:${version}-${archTag} --custom-platform ${architecture}"
}
}
break
default:
steps.error("Unsupported builder type: ${builderType.builder}")
} }
} }
} }