Correctly handle platforms that include CPU variants (#1929)

* Correctly handle platforms that include CPU variants

Prior to this change, Kaniko would only select the platform-specific
image from a multi-platform image using the OS and architecture to
select the image. This leads to problems when there are two platforms
that are indistinguishable using only this information (e.g.,
linux/arm/v5 and linux/arm/v7).

This change more explicitly selects the right image from a
multi-platform image, taking CPU variant into account (v5 vs v7), using
containerd's CPU variant detection logic.

This also moves platform defaulting up as early as possible in execution
as it can go, so that malformed platform values are detected as soon as
possible.

* set platform in unit test
This commit is contained in:
Jason Hall 2022-02-10 12:12:23 -05:00 committed by GitHub
parent ef97636546
commit 3589382378
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 29 additions and 24 deletions

View File

@ -32,7 +32,9 @@ import (
"github.com/GoogleContainerTools/kaniko/pkg/logging"
"github.com/GoogleContainerTools/kaniko/pkg/timing"
"github.com/GoogleContainerTools/kaniko/pkg/util"
"github.com/containerd/containerd/platforms"
"github.com/genuinetools/bpfd/proc"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@ -223,6 +225,14 @@ func addKanikoOptionsFlags() {
if val, ok := os.LookupEnv("KANIKO_REGISTRY_MIRROR"); ok {
opts.RegistryMirrors.Set(val)
}
// Default the custom platform flag to our current platform, and validate it.
if opts.CustomPlatform == "" {
opts.CustomPlatform = platforms.DefaultString()
}
if _, err := v1.ParsePlatform(opts.CustomPlatform); err != nil {
logrus.Fatalf("Invalid platform %q: %v", opts.CustomPlatform, err)
}
}
// addHiddenFlags marks certain flags as hidden from the executor help text

View File

@ -24,7 +24,10 @@ import (
"github.com/GoogleContainerTools/kaniko/pkg/cache"
"github.com/GoogleContainerTools/kaniko/pkg/config"
"github.com/GoogleContainerTools/kaniko/pkg/logging"
"github.com/containerd/containerd/platforms"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@ -84,6 +87,14 @@ func addKanikoOptionsFlags() {
RootCmd.PersistentFlags().VarP(&opts.RegistriesCertificates, "registry-certificate", "", "Use the provided certificate for TLS communication with the given registry. Expected format is 'my.registry.url=/path/to/the/server/certificate'.")
RootCmd.PersistentFlags().VarP(&opts.RegistryMirrors, "registry-mirror", "", "Registry mirror to use as pull-through cache instead of docker.io. Set it repeatedly for multiple mirrors.")
RootCmd.PersistentFlags().StringVarP(&opts.CustomPlatform, "customPlatform", "", "", "Specify the build platform if different from the current host")
// Default the custom platform flag to our current platform, and validate it.
if opts.CustomPlatform == "" {
opts.CustomPlatform = platforms.DefaultString()
}
if _, err := v1.ParsePlatform(opts.CustomPlatform); err != nil {
logrus.Fatalf("Invalid platform %q: %v", opts.CustomPlatform, err)
}
}
// addHiddenFlags marks certain flags as hidden from the executor help text

View File

@ -33,6 +33,7 @@ import (
"github.com/GoogleContainerTools/kaniko/pkg/dockerfile"
"github.com/GoogleContainerTools/kaniko/pkg/util"
"github.com/GoogleContainerTools/kaniko/testutil"
"github.com/containerd/containerd/platforms"
"github.com/google/go-cmp/cmp"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
@ -371,6 +372,7 @@ COPY --from=second /bar /bat
ioutil.WriteFile(f.Name(), []byte(tt.args.dockerfile), 0755)
opts := &config.KanikoOptions{
DockerfilePath: f.Name(),
CustomPlatform: platforms.DefaultString(),
}
testStages, metaArgs, err := dockerfile.ParseStages(opts)
if err != nil {

View File

@ -17,7 +17,6 @@ limitations under the License.
package remote
import (
"runtime"
"strings"
"github.com/GoogleContainerTools/kaniko/pkg/config"
@ -129,28 +128,11 @@ func setNewRegistry(ref name.Reference, newReg name.Registry) name.Reference {
func remoteOptions(registryName string, opts config.RegistryOptions, customPlatform string) []remote.Option {
tr := util.MakeTransport(opts, registryName)
// on which v1.Platform is this currently running?
platform := currentPlatform(customPlatform)
return []remote.Option{remote.WithTransport(tr), remote.WithAuthFromKeychain(creds.GetKeychain()), remote.WithPlatform(platform)}
}
// CurrentPlatform returns the v1.Platform on which the code runs
func currentPlatform(customPlatform string) v1.Platform {
if customPlatform != "" {
customPlatformArray := strings.Split(customPlatform, "/")
imagePlatform := v1.Platform{}
imagePlatform.OS = customPlatformArray[0]
if len(customPlatformArray) > 1 {
imagePlatform.Architecture = customPlatformArray[1]
if len(customPlatformArray) > 2 {
imagePlatform.Variant = customPlatformArray[2]
}
}
return imagePlatform
}
return v1.Platform{
OS: runtime.GOOS,
Architecture: runtime.GOARCH,
// The platform value has previously been validated.
platform, err := v1.ParsePlatform(customPlatform)
if err != nil {
logrus.Fatalf("Invalid platform %q: %v", customPlatform, err)
}
return []remote.Option{remote.WithTransport(tr), remote.WithAuthFromKeychain(creds.GetKeychain()), remote.WithPlatform(*platform)}
}