From 059a669b4fbee95d47ec5738e611ca20b3759ec6 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Thu, 27 Jul 2023 12:39:26 -0700 Subject: [PATCH 1/2] WIP: py interpreter --- oci_python_image/MODULE.bazel | 12 +++++++++++- oci_python_image/interpreter_as_layer/BUILD.bazel | 14 ++++++++++++++ .../{hello_world => use_python_base}/BUILD.bazel | 0 .../{hello_world => use_python_base}/__init__.py | 0 .../{hello_world => use_python_base}/__main__.py | 0 .../{hello_world => use_python_base}/app.py | 0 .../{hello_world => use_python_base}/test.yaml | 0 7 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 oci_python_image/interpreter_as_layer/BUILD.bazel rename oci_python_image/{hello_world => use_python_base}/BUILD.bazel (100%) rename oci_python_image/{hello_world => use_python_base}/__init__.py (100%) rename oci_python_image/{hello_world => use_python_base}/__main__.py (100%) rename oci_python_image/{hello_world => use_python_base}/app.py (100%) rename oci_python_image/{hello_world => use_python_base}/test.yaml (100%) diff --git a/oci_python_image/MODULE.bazel b/oci_python_image/MODULE.bazel index 44e86f54..70974890 100644 --- a/oci_python_image/MODULE.bazel +++ b/oci_python_image/MODULE.bazel @@ -27,4 +27,14 @@ oci.pull( image = "python", ) -use_repo(oci, "distroless_python") \ No newline at end of file +oci.pull( + name = "distroless_base", + digest = "sha256:ccaef5ee2f1850270d453fdf700a5392534f8d1a8ca2acda391fbb6a06b81c86", + image = "gcr.io/distroless/base", + platforms = [ + "linux/amd64", + "linux/arm64", + ], +) + +use_repo(oci, "distroless_base", "distroless_python") \ No newline at end of file diff --git a/oci_python_image/interpreter_as_layer/BUILD.bazel b/oci_python_image/interpreter_as_layer/BUILD.bazel new file mode 100644 index 00000000..281e8daa --- /dev/null +++ b/oci_python_image/interpreter_as_layer/BUILD.bazel @@ -0,0 +1,14 @@ +pkg_tar( + name = "interpreter", + srcs = ["@rules_python//python:current_py_toolchain"], + extension = "tar.gz", + package_dir = "/opt/python", + strip_prefix = ".", +) + +oci_image( + name = "image", + base = "@distroless_base", + entrypoint = ["/opt/hello_world/hello_world_bin"], + tars = [":hello_world_layer"], +) diff --git a/oci_python_image/hello_world/BUILD.bazel b/oci_python_image/use_python_base/BUILD.bazel similarity index 100% rename from oci_python_image/hello_world/BUILD.bazel rename to oci_python_image/use_python_base/BUILD.bazel diff --git a/oci_python_image/hello_world/__init__.py b/oci_python_image/use_python_base/__init__.py similarity index 100% rename from oci_python_image/hello_world/__init__.py rename to oci_python_image/use_python_base/__init__.py diff --git a/oci_python_image/hello_world/__main__.py b/oci_python_image/use_python_base/__main__.py similarity index 100% rename from oci_python_image/hello_world/__main__.py rename to oci_python_image/use_python_base/__main__.py diff --git a/oci_python_image/hello_world/app.py b/oci_python_image/use_python_base/app.py similarity index 100% rename from oci_python_image/hello_world/app.py rename to oci_python_image/use_python_base/app.py diff --git a/oci_python_image/hello_world/test.yaml b/oci_python_image/use_python_base/test.yaml similarity index 100% rename from oci_python_image/hello_world/test.yaml rename to oci_python_image/use_python_base/test.yaml From 0efc30c645026359e21d50688152cb1984cba2d3 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Tue, 1 Aug 2023 08:10:27 -0700 Subject: [PATCH 2/2] chore: docs --- oci_python_image/MODULE.bazel | 5 +-- oci_python_image/README.md | 9 +++++ .../interpreter_as_layer/BUILD.bazel | 31 +++++++++++++--- .../current_py_toolchain.bzl | 35 +++++++++++++++++++ oci_python_image/use_python_base/BUILD.bazel | 2 +- 5 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 oci_python_image/README.md create mode 100644 oci_python_image/interpreter_as_layer/current_py_toolchain.bzl diff --git a/oci_python_image/MODULE.bazel b/oci_python_image/MODULE.bazel index 70974890..426e670b 100644 --- a/oci_python_image/MODULE.bazel +++ b/oci_python_image/MODULE.bazel @@ -22,8 +22,9 @@ register_toolchains( oci = use_extension("@rules_oci//oci:extensions.bzl", "oci") oci.pull( - name = "distroless_python", + name = "docker_python", digest = "sha256:b48e216f7c4adcf24fecd7016f3b8ead76866a19571819f67f47c1ccaf899717", + # Shorthand for https://hub.docker.com/_/python image = "python", ) @@ -37,4 +38,4 @@ oci.pull( ], ) -use_repo(oci, "distroless_base", "distroless_python") \ No newline at end of file +use_repo(oci, "distroless_base", "docker_python") \ No newline at end of file diff --git a/oci_python_image/README.md b/oci_python_image/README.md new file mode 100644 index 00000000..276c574b --- /dev/null +++ b/oci_python_image/README.md @@ -0,0 +1,9 @@ +# Example of Python plus rules_oci + +There are a couple ways to treat the interpreter: + +1. Choose a base image which includes it. This is the typical approach outside Bazel, and is + recommended when migrating from a Dockerfile or similar build system to avoid changing + multiple things at the same time. In `/MODULE.bazel` we use `oci.pull` to pull https://hub.docker.com/_/python and then in `use_python_base/BUILD.bazel` we choose that as the base image. Then, the Bazel-built Python application just falls through to the "system interpreter". +2. Propagate Bazel's "toolchain resolution" so that the same interpreter used by `bazel run` + will also be used when the Python application runs in a container. This avoids version skew in the Python version used. In `/MODULE.bazel` we use `oci.pull` to pull the Distroless base image (which is tiny). Then the `interpreter_as_layer/BUILD.bazel` file shows how we get that interpreter as a layer in the image. diff --git a/oci_python_image/interpreter_as_layer/BUILD.bazel b/oci_python_image/interpreter_as_layer/BUILD.bazel index 281e8daa..3364a2ad 100644 --- a/oci_python_image/interpreter_as_layer/BUILD.bazel +++ b/oci_python_image/interpreter_as_layer/BUILD.bazel @@ -1,14 +1,35 @@ +load(":current_py_toolchain.bzl", "current_py_toolchain") +load("@rules_oci//oci:defs.bzl", "oci_image") +load("@rules_pkg//pkg:pkg.bzl", "pkg_tar") + +current_py_toolchain( + name = "current_py_toolchain_runfiles", +) + pkg_tar( - name = "interpreter", - srcs = ["@rules_python//python:current_py_toolchain"], + name = "py_interpreter_toolchain", + # If we just used @rules_python//python:current_py_toolchain then we would end up with platform + # specific paths here. The current_py_toolchain_runfiles remaps the paths to be platform independent + srcs = [":current_py_toolchain_runfiles"], extension = "tar.gz", package_dir = "/opt/python", strip_prefix = ".", ) +pkg_tar( + name = "python_aliases", + symlinks = { + "/usr/bin/python": "/usr/bin/fake_python", + "/usr/bin/python3": "/usr/bin/fake_python", + }, +) + oci_image( - name = "image", + name = "py_base", base = "@distroless_base", - entrypoint = ["/opt/hello_world/hello_world_bin"], - tars = [":hello_world_layer"], + tars = [ + ":python_aliases", + ":py_interpreter_toolchain", + ], + visibility = ["//visibility:public"], ) diff --git a/oci_python_image/interpreter_as_layer/current_py_toolchain.bzl b/oci_python_image/interpreter_as_layer/current_py_toolchain.bzl new file mode 100644 index 00000000..2055e152 --- /dev/null +++ b/oci_python_image/interpreter_as_layer/current_py_toolchain.bzl @@ -0,0 +1,35 @@ +load("@rules_pkg//:providers.bzl", "PackageFilegroupInfo", "PackageFilesInfo") + +def _strip_platform_specific(path): + parts = path.split("/") + return "/".join(parts[2:]) + +def _current_py_toolchain_impl(ctx): + default = ctx.toolchains["@rules_python//python:toolchain_type"].py3_runtime + file_map = {} + + files = depset(transitive = [default.files]) + + for file in files.to_list(): + file_map[_strip_platform_specific(file.path)] = file + + files = depset([], transitive = [files]) + + return [ + PackageFilegroupInfo( + pkg_dirs = [], + pkg_files = [ + [PackageFilesInfo( + dest_src_map = file_map, + attributes = {}, + ), ctx.label], + ], + ), + DefaultInfo(files = files), + ] + +current_py_toolchain = rule( + implementation = _current_py_toolchain_impl, + attrs = {}, + toolchains = ["@rules_python//python:toolchain_type"], +) diff --git a/oci_python_image/use_python_base/BUILD.bazel b/oci_python_image/use_python_base/BUILD.bazel index 6b5d7bb4..d73cfd49 100644 --- a/oci_python_image/use_python_base/BUILD.bazel +++ b/oci_python_image/use_python_base/BUILD.bazel @@ -31,7 +31,7 @@ py_image_layer( oci_image( name = "image", - base = "@distroless_python", + base = "@docker_python", entrypoint = ["/opt/hello_world/hello_world_bin"], tars = [":hello_world_layer"], )