From f1a24835a9fec4143ede026c8519891152d07304 Mon Sep 17 00:00:00 2001 From: shashank381 <58882644+shashank381@users.noreply.github.com> Date: Tue, 9 Apr 2024 14:36:48 -0700 Subject: [PATCH] feat: podman multiarch support (#1157) * feat: use podman for building custom images if executable is found Signed-off-by: Soumil Paranjpay * feat: add support for multiarch with podman Signed-off-by: shashank381 * feat: allow providing container runtime for multi arch scripts Signed-off-by: shashank381 --------- Signed-off-by: shashank381 Co-authored-by: Soumil Paranjpay --- .../templates/pushimages.sh | 2 +- .../buildandpushimages_multiarch.bat | 33 +++++++++++++++++-- .../templates/buildandpushimages_multiarch.sh | 27 +++++++++++++-- .../templates/buildimages.sh | 2 +- common/utils.go | 12 +++++++ .../containerimagespushscripttransformer.go | 5 ++- .../dockerfilebuildscripttransformer.go | 2 ++ 7 files changed, 75 insertions(+), 8 deletions(-) diff --git a/assets/built-in/transformers/containerimagespushscript/templates/pushimages.sh b/assets/built-in/transformers/containerimagespushscript/templates/pushimages.sh index 963376653..62258ed2b 100755 --- a/assets/built-in/transformers/containerimagespushscript/templates/pushimages.sh +++ b/assets/built-in/transformers/containerimagespushscript/templates/pushimages.sh @@ -21,7 +21,7 @@ REGISTRY_URL={{ .RegistryURL }} REGISTRY_NAMESPACE={{ .RegistryNamespace }} -CONTAINER_RUNTIME=docker +CONTAINER_RUNTIME={{ .ContainerRuntime }} if [ "$#" -gt 1 ]; then REGISTRY_URL=$1 REGISTRY_NAMESPACE=$2 diff --git a/assets/built-in/transformers/dockerfile/dockerimagebuildscript/templates/buildandpushimages_multiarch.bat b/assets/built-in/transformers/dockerfile/dockerimagebuildscript/templates/buildandpushimages_multiarch.bat index 8bdfc30d4..4cc385a5a 100755 --- a/assets/built-in/transformers/dockerfile/dockerimagebuildscript/templates/buildandpushimages_multiarch.bat +++ b/assets/built-in/transformers/dockerfile/dockerimagebuildscript/templates/buildandpushimages_multiarch.bat @@ -17,6 +17,8 @@ :: 1) buildandpush_multiarchimages.bat :: 2) buildandpush_multiarchimages.bat index.docker.io your_registry_namespace :: 3) buildandpush_multiarchimages.bat quay.io your_quay_username linux/amd64,linux/arm64,linux/s390x +:: 4) ./buildandpush_multiarchimages.bat docker +:: 5) ./buildandpush_multiarchimages.bat podman quay.io your_quay_username linux/amd64,linux/arm64,linux/s390x @echo off for /F "delims=" %%i in ("%cd%") do set basename="%%~ni" @@ -29,6 +31,12 @@ if not %basename% == "scripts" ( REM go to the parent directory so that all the relative paths will be correct cd {{ .RelParentOfSourceDir }} +SET CONTAINER_RUNTIME={{ .ContainerRuntime }} +IF "%1"!="" ( + SET CONTAINER_RUNTIME=%1% + shift +) + IF "%3"=="" GOTO DEFAULT_PLATFORMS SET PLATFORMS=%3% GOTO REGISTRY @@ -42,22 +50,41 @@ GOTO REGISTRY IF "%1"=="" GOTO DEFAULT_REGISTRY SET REGISTRY_URL=%1 SET REGISTRY_NAMESPACE=%2 - GOTO MAIN + GOTO DOCKER_CONTAINER_RUNTIME :DEFAULT_REGISTRY SET REGISTRY_URL={{ .RegistryURL }} SET REGISTRY_NAMESPACE={{ .RegistryNamespace }} + GOTO DOCKER_CONTAINER_RUNTIME + +:DOCKER_CONTAINER_RUNTIME + IF NOT "%CONTAINER_RUNTIME%" == "docker" GOTO PODMAN_CONTAINER_RUNTIME + GOTO MAIN + +:PODMAN_CONTAINER_RUNTIME + IF NOT "%CONTAINER_RUNTIME%" == "podman" GOTO UNSUPPORTED_BUILD_SYSTEM GOTO MAIN +:UNSUPPORTED_BUILD_SYSTEM + echo 'Unsupported build system passed as an argument for pushing the images.' + GOTO SKIP + :MAIN :: Uncomment the below line if you want to enable login before pushing :: docker login %REGISTRY_URL% {{- range $dockerfile := .DockerfilesConfig }} - echo "building and pushing image {{ $dockerfile.ImageName }}" pushd {{ $dockerfile.ContextWindows }} -docker buildx build --platform ${PLATFORMS} -f {{ $dockerfile.DockerfileName }} --push --tag ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/{{ $dockerfile.ImageName }} . +IF "%CONTAINER_RUNTIME%" == "docker" ( + docker buildx build --platform ${PLATFORMS} -f {{ $dockerfile.DockerfileName }} --push --tag ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/{{ $dockerfile.ImageName }} . +) ELSE ( + podman manifest create ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/{{ $dockerfile.ImageName }} + podman build --platform ${PLATFORMS} -f {{ $dockerfile.DockerfileName }} --manifest ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/{{ $dockerfile.ImageName }} . + podman manifest push ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/{{ $dockerfile.ImageName }} +) popd {{- end }} echo "done" + +:SKIP diff --git a/assets/built-in/transformers/dockerfile/dockerimagebuildscript/templates/buildandpushimages_multiarch.sh b/assets/built-in/transformers/dockerfile/dockerimagebuildscript/templates/buildandpushimages_multiarch.sh index a3ff94007..1821974f4 100755 --- a/assets/built-in/transformers/dockerfile/dockerimagebuildscript/templates/buildandpushimages_multiarch.sh +++ b/assets/built-in/transformers/dockerfile/dockerimagebuildscript/templates/buildandpushimages_multiarch.sh @@ -18,6 +18,8 @@ # 1) ./buildandpush_multiarchimages.sh # 2) ./buildandpush_multiarchimages.sh index.docker.io your_registry_namespace # 3) ./buildandpush_multiarchimages.sh quay.io your_quay_username linux/amd64,linux/arm64,linux/s390x +# 4) ./buildandpush_multiarchimages.sh docker +# 5) ./buildandpush_multiarchimages.sh podman quay.io your_quay_username linux/amd64,linux/arm64,linux/s390x if [[ "$(basename "$PWD")" != 'scripts' ]] ; then echo 'please run this script from the "scripts" directory' @@ -29,6 +31,13 @@ cd {{ .RelParentOfSourceDir }} # go to the parent directory so that all the rela REGISTRY_URL={{ .RegistryURL }} REGISTRY_NAMESPACE={{ .RegistryNamespace }} PLATFORMS="linux/amd64,linux/arm64,linux/s390x,linux/ppc64le" +CONTAINER_RUNTIME={{ .ContainerRuntime }} + +if [ "$#" -gt 0 ] && [[ "$1" == "docker" || "$1" == "podman" ]]; then + CONTAINER_RUNTIME=$1 + shift; +fi + if [ "$#" -gt 1 ]; then REGISTRY_URL=$1 REGISTRY_NAMESPACE=$2 @@ -36,13 +45,27 @@ fi if [ "$#" -eq 3 ]; then PLATFORMS=$3 fi + +if [ "${CONTAINER_RUNTIME}" != "docker" ] && [ "${CONTAINER_RUNTIME}" != "podman" ]; then + echo 'Unsupported container runtime passed as an argument for building the images: '"${CONTAINER_RUNTIME}" + exit 1 +fi + + # Uncomment the below line if you want to enable login before pushing # docker login ${REGISTRY_URL} {{- range $dockerfile := .DockerfilesConfig }} - echo 'building and pushing image {{ $dockerfile.ImageName }}' cd {{ $dockerfile.ContextUnix }} -docker buildx build --platform ${PLATFORMS} -f {{ $dockerfile.DockerfileName }} --push --tag ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/{{ $dockerfile.ImageName }} . +if [ "${CONTAINER_RUNTIME}" == "docker" ] +then + docker buildx build --platform ${PLATFORMS} -f {{ $dockerfile.DockerfileName }} --push --tag ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/{{ $dockerfile.ImageName }} . +else + podman manifest create ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/{{ $dockerfile.ImageName }} + podman build --platform ${PLATFORMS} -f {{ $dockerfile.DockerfileName }} --manifest ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/{{ $dockerfile.ImageName }} . + podman manifest push ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/{{ $dockerfile.ImageName }} +fi + cd - {{- end }} diff --git a/assets/built-in/transformers/dockerfile/dockerimagebuildscript/templates/buildimages.sh b/assets/built-in/transformers/dockerfile/dockerimagebuildscript/templates/buildimages.sh index 28f99e058..d719b80d7 100755 --- a/assets/built-in/transformers/dockerfile/dockerimagebuildscript/templates/buildimages.sh +++ b/assets/built-in/transformers/dockerfile/dockerimagebuildscript/templates/buildimages.sh @@ -22,7 +22,7 @@ if [[ "$(basename "$PWD")" != 'scripts' ]] ; then echo 'please run this script from the "scripts" directory' exit 1 fi -CONTAINER_RUNTIME=docker +CONTAINER_RUNTIME={{ .ContainerRuntime }} if [ "$#" -eq 1 ]; then CONTAINER_RUNTIME=$1 fi diff --git a/common/utils.go b/common/utils.go index cd13fba7b..1a67f9d1f 100644 --- a/common/utils.go +++ b/common/utils.go @@ -32,6 +32,7 @@ import ( "math/rand" "net/url" "os" + "os/exec" "path/filepath" "reflect" "regexp" @@ -1593,3 +1594,14 @@ func IsHTTPURL(str string) bool { return regex.MatchString(str) } + +// GetDefaultContainerRuntime returns the preferred container runtime of the host +func GetDefaultContainerRuntime() string { + _, err := exec.LookPath("podman") + if err == nil { + logrus.Info("Podman executable found in the directories named by the PATH environment variable. Using Podman as the container runtime.") + return "podman" + } + logrus.Info("Couldn't find Podman executable in the directories named by the PATH environment variable. Using Docker as the container runtime.") + return "docker" +} diff --git a/transformer/containerimage/containerimagespushscripttransformer.go b/transformer/containerimage/containerimagespushscripttransformer.go index 92ee738fd..cc59d6d06 100644 --- a/transformer/containerimage/containerimagespushscripttransformer.go +++ b/transformer/containerimage/containerimagespushscripttransformer.go @@ -46,6 +46,7 @@ type DockerfileImagePushScriptConfig struct { // ImagePushTemplateConfig represents template config used by ImagePush script type ImagePushTemplateConfig struct { + ContainerRuntime string RegistryURL string RegistryNamespace string Images []string @@ -79,7 +80,9 @@ func (t *ContainerImagesPushScript) DirectoryDetect(dir string) (services map[st // Transform transforms the artifacts func (t *ContainerImagesPushScript) Transform(newArtifacts []transformertypes.Artifact, alreadySeenArtifacts []transformertypes.Artifact) ([]transformertypes.PathMapping, []transformertypes.Artifact, error) { pathMappings := []transformertypes.PathMapping{} - ipt := ImagePushTemplateConfig{} + ipt := ImagePushTemplateConfig{ + ContainerRuntime: common.GetDefaultContainerRuntime(), + } for _, a := range newArtifacts { if a.Type != artifacts.NewImagesArtifactType { continue diff --git a/transformer/dockerfile/dockerfilebuildscripttransformer.go b/transformer/dockerfile/dockerfilebuildscripttransformer.go index c9f1a3a42..5e7aae1bd 100644 --- a/transformer/dockerfile/dockerfilebuildscripttransformer.go +++ b/transformer/dockerfile/dockerfilebuildscripttransformer.go @@ -48,6 +48,7 @@ type DockerfileImageBuildScriptConfig struct { // DockerfileImageBuildScriptTemplateConfig represents the data used to fill the build script generator template type DockerfileImageBuildScriptTemplateConfig struct { + ContainerRuntime string RelParentOfSourceDir string DockerfilesConfig []DockerfileImageBuildConfig RegistryURL string @@ -177,6 +178,7 @@ func (t *DockerfileImageBuildScript) Transform(newArtifacts []transformertypes.A RegistryURL: commonqa.ImageRegistry(), RegistryNamespace: commonqa.ImageRegistryNamespace(), DockerfilesConfig: dockerfilesImageBuildConfig, + ContainerRuntime: common.GetDefaultContainerRuntime(), } pathMappings = append(pathMappings, transformertypes.PathMapping{ Type: transformertypes.TemplatePathMappingType,