Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support Bazel platform mappings #9300

Merged
merged 6 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 36 additions & 1 deletion docs-v2/content/en/schemas/v4beta10.json
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,14 @@
"[\"-flag\", \"--otherflag\"]"
]
},
"platforms": {
"items": {
"$ref": "#/definitions/BazelPlatformMapping"
},
"type": "array",
"description": "configure the --platforms flag for `bazel build` based on the configured skaffold target platform.",
"x-intellij-html-description": "configure the --platforms flag for <code>bazel build</code> based on the configured skaffold target platform."
},
"target": {
"type": "string",
"description": "`bazel build` target to run.",
Expand All @@ -705,13 +713,40 @@
},
"preferredOrder": [
"target",
"args"
"args",
"platforms"
],
"additionalProperties": false,
"type": "object",
"description": "describes an artifact built with [Bazel](https://bazel.build/).",
"x-intellij-html-description": "describes an artifact built with <a href=\"https://bazel.build/\">Bazel</a>."
},
"BazelPlatformMapping": {
"required": [
"platform",
"target"
],
"properties": {
"platform": {
"type": "string",
"description": "skaffold platform.",
"x-intellij-html-description": "skaffold platform."
},
"target": {
"type": "string",
"description": "bazel platform target to be passed to bazel's `--platforms` flag.",
"x-intellij-html-description": "bazel platform target to be passed to bazel's <code>--platforms</code> flag."
}
},
"preferredOrder": [
"platform",
"target"
],
"additionalProperties": false,
"type": "object",
"description": "relates a skaffold platform (like 'linux/amd64') to a workspace-specific bazel platform target (e.g. '//platforms:linux_amd64').",
"x-intellij-html-description": "relates a skaffold platform (like 'linux/amd64') to a workspace-specific bazel platform target (e.g. '//platforms:linux_amd64')."
},
"BuildConfig": {
"type": "object",
"anyOf": [
Expand Down
15 changes: 2 additions & 13 deletions examples/bazel/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
load("@aspect_bazel_lib//lib:transitions.bzl", "platform_transition_filegroup")
load("@rules_go//go:def.bzl", "go_binary", "go_library")
load("@rules_oci//oci:defs.bzl", "oci_image", "oci_tarball")
load("@rules_pkg//:pkg.bzl", "pkg_tar")
Expand Down Expand Up @@ -31,18 +30,8 @@ oci_image(
tars = [":app_layer"],
)

# This is the target that should be released to the target platform
platform_transition_filegroup(
name = "transitioned_image",
srcs = [":image"],
target_platform = select({
"@platforms//cpu:arm64": "@rules_go//go/toolchain:linux_arm64",
"@platforms//cpu:x86_64": "@rules_go//go/toolchain:linux_amd64",
}),
)

# $ bazel build :tarball
# $ docker load --input $(bazel cquery --output=files :tarball)
# $ bazel build :skaffold-example.tar
# $ docker load --input $(bazel cquery --output=files :skaffold-example.tar)
# $ docker run --rm gcr.io/example:latest

oci_tarball(
Expand Down
1 change: 0 additions & 1 deletion examples/bazel/MODULE.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
bazel_dep(name = "aspect_bazel_lib", version = "1.31.1")
bazel_dep(name = "gazelle", version = "0.31.0")
bazel_dep(name = "platforms", version = "0.0.5")
bazel_dep(name = "rules_oci", version = "1.2.0")
Expand Down
2 changes: 1 addition & 1 deletion examples/bazel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ build:
- image: skaffold-bazel
context: .
bazel:
target: //:skaffold_example.tar
target: //:skaffold-example.tar
```

1. make sure the `context` contains the bazel files (`WORKSPACE`, `BUILD`)
Expand Down
15 changes: 2 additions & 13 deletions integration/examples/bazel/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
load("@aspect_bazel_lib//lib:transitions.bzl", "platform_transition_filegroup")
load("@rules_go//go:def.bzl", "go_binary", "go_library")
load("@rules_oci//oci:defs.bzl", "oci_image", "oci_tarball")
load("@rules_pkg//:pkg.bzl", "pkg_tar")
Expand Down Expand Up @@ -31,18 +30,8 @@ oci_image(
tars = [":app_layer"],
)

# This is the target that should be released to the target platform
platform_transition_filegroup(
name = "transitioned_image",
srcs = [":image"],
target_platform = select({
"@platforms//cpu:arm64": "@rules_go//go/toolchain:linux_arm64",
"@platforms//cpu:x86_64": "@rules_go//go/toolchain:linux_amd64",
}),
)

# $ bazel build :tarball
# $ docker load --input $(bazel cquery --output=files :tarball)
# $ bazel build :skaffold-example.tar
# $ docker load --input $(bazel cquery --output=files :skaffold-example.tar)
# $ docker run --rm gcr.io/example:latest

oci_tarball(
Expand Down
1 change: 0 additions & 1 deletion integration/examples/bazel/MODULE.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
bazel_dep(name = "aspect_bazel_lib", version = "1.31.1")
bazel_dep(name = "gazelle", version = "0.31.0")
bazel_dep(name = "platforms", version = "0.0.5")
bazel_dep(name = "rules_oci", version = "1.2.0")
Expand Down
2 changes: 1 addition & 1 deletion integration/examples/bazel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ build:
- image: skaffold-bazel
context: .
bazel:
target: //:skaffold_example.tar
target: //:skaffold-example.tar
```

1. make sure the `context` contains the bazel files (`WORKSPACE`, `BUILD`)
Expand Down
5 changes: 5 additions & 0 deletions integration/examples/bazel/skaffold.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ build:
- image: skaffold-bazel
bazel:
target: //:skaffold-example.tar
platforms:
- platform: linux/amd64
target: "@rules_go//go/toolchain:linux_amd64"
- platform: linux/arm64
target: "@rules_go//go/toolchain:linux_arm64"
deploy:
kubectl: {}
manifests:
Expand Down
14 changes: 12 additions & 2 deletions pkg/skaffold/build/bazel/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (b *Builder) Build(ctx context.Context, out io.Writer, artifact *latest.Art

a := artifact.ArtifactType.BazelArtifact

tarPath, err := b.buildTar(ctx, out, artifact.Workspace, a)
tarPath, err := b.buildTar(ctx, out, artifact.Workspace, a, matcher)
if err != nil {
return "", err
}
Expand All @@ -58,7 +58,7 @@ func (b *Builder) Build(ctx context.Context, out io.Writer, artifact *latest.Art

func (b *Builder) SupportedPlatforms() platform.Matcher { return platform.All }

func (b *Builder) buildTar(ctx context.Context, out io.Writer, workspace string, a *latest.BazelArtifact) (string, error) {
func (b *Builder) buildTar(ctx context.Context, out io.Writer, workspace string, a *latest.BazelArtifact, matcher platform.Matcher) (string, error) {
if !strings.HasSuffix(a.BuildTarget, ".tar") {
return "", errors.New("the bazel build target should end with .tar, see https://github.com/bazelbuild/rules_docker#using-with-docker-locally")
}
Expand All @@ -67,6 +67,16 @@ func (b *Builder) buildTar(ctx context.Context, out io.Writer, workspace string,
args = append(args, a.BuildArgs...)
args = append(args, a.BuildTarget)

platformMappings := a.PlatformMappings
for _, mapping := range platformMappings {
m, err := platform.Parse([]string{mapping.Platform})
if err == nil {
if matcher.Intersect(m).IsNotEmpty() {
args = append(args, fmt.Sprintf("--platforms=%s", mapping.BazelPlatformTarget))
}
}
}

if output.IsColorable(out) {
args = append(args, "--color=yes")
} else {
Expand Down
33 changes: 33 additions & 0 deletions pkg/skaffold/build/bazel/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
"path/filepath"
"testing"

specs "github.com/opencontainers/image-spec/specs-go/v1"

"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/docker"
"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/platform"
"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/schema/latest"
Expand Down Expand Up @@ -77,6 +79,37 @@ func TestBazelTarPathPrependExecutionRoot(t *testing.T) {
})
}

func TestBazelAddPlatforms(t *testing.T) {
testutil.Run(t, "", func(t *testutil.T) {
t.Override(&util.DefaultExecCommand, testutil.CmdRun("bazel build //:app.tar --platforms=//platforms:linux-x86_64 --color=no").AndRunOut(
"bazel cquery //:app.tar --output starlark --starlark:expr target.files.to_list()[0].path",
"app.tar").AndRunOut("bazel info execution_root", ".."))
testutil.CreateFakeImageTar("bazel:app", "../app.tar")

artifact := &latest.Artifact{
Workspace: "..",
ArtifactType: latest.ArtifactType{
BazelArtifact: &latest.BazelArtifact{
BuildTarget: "//:app.tar",
PlatformMappings: []latest.BazelPlatformMapping{
{
Platform: "linux/amd64",
BazelPlatformTarget: "//platforms:linux-x86_64",
},
},
},
},
}

testPlatform := platform.Matcher{Platforms: []specs.Platform{{Architecture: "amd64", OS: "linux"}}}

builder := NewArtifactBuilder(fakeLocalDaemon(), &mockConfig{}, false)
_, err := builder.Build(context.Background(), io.Discard, artifact, "img:tag", testPlatform)

t.CheckNoError(err)
})
}

func TestBuildBazelFailInvalidTarget(t *testing.T) {
testutil.Run(t, "", func(t *testutil.T) {
artifact := &latest.Artifact{
Expand Down
14 changes: 14 additions & 0 deletions pkg/skaffold/schema/latest/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,16 @@ type TaggerComponent struct {
Component TagPolicy `yaml:",inline" yamltags:"skipTrim"`
}

// BazelPlatformMapping relates a skaffold platform (like 'linux/amd64')
// to a workspace-specific bazel platform target (e.g. '//platforms:linux_amd64').
type BazelPlatformMapping struct {
// Platform is the skaffold platform.
Platform string `yaml:"platform" yamltags:"required"`

// BazelPlatformTarget is the bazel platform target to be passed to bazel's `--platforms` flag.
BazelPlatformTarget string `yaml:"target" yamltags:"required"`
}

// BuildType contains the specific implementation and parameters needed
// for the build step. Only one field should be populated.
type BuildType struct {
Expand Down Expand Up @@ -1597,6 +1607,10 @@ type BazelArtifact struct {
// BuildArgs are additional args to pass to `bazel build`.
// For example: `["-flag", "--otherflag"]`.
BuildArgs []string `yaml:"args,omitempty"`

// PlatformMappings configure the --platforms flag for `bazel build`
// based on the configured skaffold target platform.
PlatformMappings []BazelPlatformMapping `yaml:"platforms,omitempty"`
}

// KoArtifact builds images using [ko](https://github.com/google/ko).
Expand Down