Skip to content

Latest commit

 

History

History
360 lines (272 loc) · 29.8 KB

File metadata and controls

360 lines (272 loc) · 29.8 KB

Public API for container image layer rules.

image_layer

load("@rules_img//img:layer.bzl", "image_layer")

image_layer(name, srcs, annotations, annotations_file, compress, create_parent_directories,
            default_metadata, estargz, file_metadata, history, include_runfiles, media_type,
            multi_file_layout, soci, symlinks, tree_artifact_handling)

Creates a container image layer from files, executables, and directories.

This rule packages files into a layer that can be used in container images. It supports:

  • Adding files at specific paths in the image
  • Setting file permissions and ownership
  • Creating symlinks
  • Including executables with their runfiles and any additional default outputs
  • Compression (gzip, zstd) and eStargz optimization

Example:

load("@rules_img//img:layer.bzl", "image_layer", "file_metadata")

# Simple layer with files
image_layer(
    name = "app_layer",
    srcs = {
        "/app/bin/server": "//cmd/server",
        "/app/config.json": ":config.json",
    },
)

# Layer with custom permissions
image_layer(
    name = "secure_layer",
    srcs = {
        "/etc/app/config": ":config",
        "/etc/app/secret": ":secret",
    },
    default_metadata = file_metadata(
        mode = "0644",
        uid = 1000,
        gid = 1000,
    ),
    file_metadata = {
        "/etc/app/secret": file_metadata(mode = "0600"),
    },
)

# Layer with symlinks
image_layer(
    name = "bin_layer",
    srcs = {
        "/usr/local/bin/app": "//cmd/app",
    },
    symlinks = {
        "/usr/bin/app": "/usr/local/bin/app",
    },
)

Output groups

  • mtree: a single mtree text file

ATTRIBUTES

Name Description Type Mandatory Default
name A unique name for this target. Name required
srcs Files to include in the layer. Keys are paths in the image (e.g., "/app/bin/server"), values are labels to files or executables.

When a value is an executable, the executable is placed at the path key and its runfiles tree is included (unless include_runfiles is set to False). Any additional default outputs of the target (the rest of DefaultInfo.files beyond the executable) are also copied, each placed at the same location relative to the executable that it has in the source tree.

When a value is a non-executable target that produces more than one default output, the path key is treated as a directory and the outputs are placed inside it according to multi_file_layout. A path key that ends with "/" is always treated as a directory, even when the target produces exactly one output.
Dictionary: String -> Label optional {}
annotations Annotations to add to the layer metadata as key-value pairs. Dictionary: String -> String optional {}
annotations_file File containing annotations for the layer, as JSON or newline-delimited text.

The file is parsed in one of the following formats, auto-detected from its contents:

- JSON object with string values: {"key": "value"} - JSON object with list values: {"key": ["value1", "value2"]} (the last value wins) - JSON array of KEY=VALUE strings: ["key=value"] - newline-delimited KEY=VALUE text (one per line; blank lines and # comments are ignored)

Values in JSON objects are used verbatim, so they can encode arbitrary strings including values that contain =, spaces, or newlines. The KEY=VALUE forms (JSON array and text) split on the first = and trim surrounding whitespace from the key and value.

Annotations from this file are merged with annotations specified via the annotations attribute, which take precedence for matching keys.

Example file content:
version=1.0.0
build.date=2024-01-15
source.url=https://github.com/...
Label optional None
compress Compression algorithm to use. If set to 'auto', uses the global default compression setting. String optional "auto"
create_parent_directories Whether to automatically create parent directory entries in the tar file for all files. If set to 'auto', uses the global default create_parent_directories setting. When enabled, parent directories will be created automatically for all files in the layer. String optional "auto"
default_metadata JSON-encoded default metadata to apply to all files in the layer. Can include fields like mode, uid, gid, uname, gname, mtime, and pax_records. String optional ""
estargz Whether to use estargz format. If set to 'auto', uses the global default estargz setting. When enabled, the layer will be optimized for lazy pulling and will be compatible with the estargz format. String optional "auto"
file_metadata Per-file metadata overrides as a dict mapping file paths to JSON-encoded metadata. The path should match the path in the image (the key in srcs attribute). Metadata specified here overrides any defaults from default_metadata. Dictionary: String -> String optional {}
history Overrides the created_by history entry recorded for this layer.

By default the layer records one entry, "bazel build ", so two layers with identical contents but different labels have different config digests. history = [] records no history entry, so identical contents give identical config digests regardless of label. A single-element list is recorded verbatim. The img tool records at most one history entry per layer, so longer lists are rejected.
List of strings optional ["<default bazel build history>"]
include_runfiles Whether to include runfiles for executable targets. When True (default), executables in srcs will include their runfiles tree. When False, only the executable file itself is included, without runfiles.

Either way, any additional default outputs of the target (the rest of DefaultInfo.files beyond the executable) are copied into the layer, placed relative to the executable.
Boolean optional True
media_type Override the layer media type. By default, the media type is auto-detected from the compression algorithm. String optional ""
multi_file_layout How to place a non-executable src that produces MORE THAN ONE default output.

- "package_relative" (default): treat the path key as a directory and place each file inside it, preserving its path relative to the producing target's package. - "flatten": place each file directly in the directory by basename (restores the older behavior).

A src that produces a single output is placed exactly at its path key, regardless of this setting. To opt out of that shortcut, end the path key with "/": it then always denotes a directory, and a single output is laid out inside it just like multiple outputs would be.
String optional "package_relative"
soci Whether to emit a SOCI ztoc (table of contents) for this layer. If set to 'auto', uses the global default //img/settings:soci setting. When enabled and the layer is gzip-compressed, a ztoc is produced in the layer action and recorded on the SingleLayerInfo provider, so images that build a SOCI Index Manifest v2 can reuse it instead of regenerating it. Non-gzip layers never emit a ztoc. String optional "auto"
symlinks Symlinks to create in the layer. Keys are symlink paths in the image, values are the targets they point to. Dictionary: String -> String optional {}
tree_artifact_handling How to handle duplicate tree artifacts (directories) in the layer. If set to 'full', each tree artifact is stored at its intended path (no deduplication). If set to 'deduplicate_symlink', duplicate tree artifacts are replaced with symlinks to the first occurrence. If set to 'auto', uses the global default from --@rules_img//img/settings:layer_tree_artifact_handling. String optional "auto"

layer_from_binary

load("@rules_img//img:layer.bzl", "layer_from_binary")

layer_from_binary(name, annotations, annotations_file, binary, compress, create_parent_directories,
                  default_metadata, estargz, include_runfiles, infer_working_dir, layer_budget,
                  media_type, path, runfiles_path, runfiles_shared_path, runfiles_sharing_mode, soci,
                  tree_artifact_handling)

Creates a container image layer from a *_binary target.

This rule packages a binary executable and its runfiles into a layer, and additionally provides image configuration (entrypoint, cmd, env, working_dir) via ImageLayerConfigInfo. When used as a layer in image_manifest, the configuration is automatically applied to the image with Dockerfile-like semantics.

The binary's args attribute becomes the image cmd, its env attribute (or RunEnvironmentInfo provider) becomes env, and the binary path becomes the entrypoint. When include_runfiles is True (default), the working directory is set to the runfiles root. Set infer_working_dir = False to leave the working directory unset, so the base image's working directory (or image_manifest's own working_dir attribute) applies instead.

In addition to the executable and its runfiles, any other default outputs of the binary target (the rest of DefaultInfo.files) are copied into the layer, each placed at the same location relative to the executable that it has in the source tree.

If the binary provides RunfilesGroupInfo (from rules_runfiles_group), the runfiles are split into separate layers based on the groups. This allows for better caching: stable layers (interpreter, stdlib) change infrequently and can be shared, while the application code layer changes with each build. Layers are emitted in the groups' rank order (lowest first), so foundational content ends up in the earliest, most cacheable layers. Any RunfilesGroupTransformInfo in the binary's aspect_hints is applied first, which lets users drop or re-shape groups per target.

Note that RunfilesGroupInfo emission is off by default in rules_runfiles_group. Build with --@rules_runfiles_group//runfiles_group:enabled=true to opt in; without it, group-aware binaries produce a single layer.

When the number of groups exceeds what is practical for a container image, use layer_budget to merge groups down to a maximum count. The merge algorithm respects group rank (only merges within the same rank), do_not_merge flags, merge affinity (groups sharing an affinity are preferred merge partners), and weight hints (lighter groups merge first).

Example:

load("@rules_img//img:layer.bzl", "layer_from_binary")
load("@rules_img//img:image.bzl", "image_manifest")

# Package a Go binary with its runfiles
layer_from_binary(
    name = "app_layer",
    binary = "//cmd/server",
)

# Use in an image - entrypoint, cmd, env, and working_dir are set automatically
image_manifest(
    name = "image",
    base = "@distroless_base",
    layers = [":app_layer"],
)

# Override the path inside the image
layer_from_binary(
    name = "custom_path_layer",
    binary = "//cmd/server",
    path = "/usr/local/bin/",
)

# Without runfiles (static binary)
layer_from_binary(
    name = "static_layer",
    binary = "//cmd/server",
    path = "/usr/local/bin/server",
    include_runfiles = False,
)

Output groups

  • mtree: one mtree text file per produced layer

ATTRIBUTES

Name Description Type Mandatory Default
name A unique name for this target. Name required
annotations Annotations to add to the layer metadata as key-value pairs. Dictionary: String -> String optional {}
annotations_file File containing annotations for the layer, as JSON or newline-delimited text.

The file is parsed in one of the following formats, auto-detected from its contents:

- JSON object with string values: {"key": "value"} - JSON object with list values: {"key": ["value1", "value2"]} (the last value wins) - JSON array of KEY=VALUE strings: ["key=value"] - newline-delimited KEY=VALUE text (one per line; blank lines and # comments are ignored)

Values in JSON objects are used verbatim, so they can encode arbitrary strings including values that contain =, spaces, or newlines. The KEY=VALUE forms (JSON array and text) split on the first = and trim surrounding whitespace from the key and value.

Annotations from this file are merged with annotations specified via the annotations attribute, which take precedence for matching keys.

Example file content:
version=1.0.0
build.date=2024-01-15
source.url=https://github.com/...
Label optional None
binary The *_binary target to package into the layer.

The binary's args and env attributes are extracted and provided as image configuration (cmd and env) via ImageLayerConfigInfo. The data attribute is used for $(location) expansion in args and env values.

If the binary provides RunfilesGroupInfo, the runfiles are split into separate layers per group.
Label required
compress Compression algorithm to use. If set to 'auto', uses the global default compression setting. String optional "auto"
create_parent_directories Whether to automatically create parent directory entries in the tar file for all files. If set to 'auto', uses the global default create_parent_directories setting. When enabled, parent directories will be created automatically for all files in the layer. String optional "auto"
default_metadata JSON-encoded default metadata to apply to all files in the layers. Can include fields like mode, uid, gid, uname, gname, mtime, and pax_records.

Accepts the same value as image_layer's attribute of the same name, so img/layer.bzl's file_metadata() builds it.
String optional ""
estargz Whether to use estargz format. If set to 'auto', uses the global default estargz setting. When enabled, the layer will be optimized for lazy pulling and will be compatible with the estargz format. String optional "auto"
include_runfiles Whether to include runfiles for executable targets. When True (default), executables in srcs will include their runfiles tree. When False, only the executable file itself is included, without runfiles.

Either way, any additional default outputs of the target (the rest of DefaultInfo.files beyond the executable) are copied into the layer, placed relative to the executable.
Boolean optional True
infer_working_dir Whether to infer the image's working directory from the binary's runfiles tree.

When True (default) and include_runfiles is True, ImageLayerConfigInfo.working_dir is set to the main workspace directory inside the runfiles tree (e.g. "/main/cmd/server/server/server.runfiles/_main"), which is the directory a binary launched through the runfiles convention expects to run in.

When False, ImageLayerConfigInfo.working_dir is None, which carries no opinion: image_manifest then keeps the base image's working directory, unless its own working_dir attribute is set explicitly.
Boolean optional True
layer_budget Maximum total number of layers produced by this rule. If set to a value > 0 and the binary provides RunfilesGroupInfo, groups are merged using the merge algorithm from rules_runfiles_group. The algorithm respects group rank (only merges within the same rank), do_not_merge flags, merge affinity (groups sharing an affinity are preferred merge partners), and weight hints (lighter groups merge first).

When the binary names an executable_group, the binary executable and supporting files are merged into that group's layer, and the full budget is available for runfiles groups. When no executable_group exists, one layer is reserved for a separate binary layer, and the remaining budget (layer_budget - 1) is used for groups; layer_budget=1 without an executable_group skips the grouped path entirely.

This is a target, not a hard cap: groups marked do_not_merge are never merged, and groups at different ranks never merge with each other, so a binary whose groups cannot be reduced far enough still produces more layers than the budget.

0 means no limit (all groups become separate layers, plus a binary layer unless an executable_group absorbs it).
Integer optional 0
media_type Override the layer media type. By default, the media type is auto-detected from the compression algorithm. String optional ""
path Optional path of the binary inside the image. If the path ends with a slash ("/"), the basename of the binary will be automatically appended. If unset, this defaults to the rlocationpath of the binary (e.g., "main/cmd/server/server/server"). String optional ""
runfiles_path Optional path of the runfiles directory of the binary inside the image. If unset, this defaults to the path of the binary with a .runfiles suffix (e.g., "main/cmd/server/server/server.runfiles"). Note: depending on the runfiles_sharing_mode, this may be a symlink to a shared runfiles directory. String optional ""
runfiles_shared_path Optional path of the shared runfiles directory inside the image. This is only used when runfiles sharing is enabled and has a global default. String optional ""
runfiles_sharing_mode How to process runfiles. Runfiles can either be placed next to the executable (in a directory with a .runfiles suffix, the runfiles_path attribute), or placed in a shared runfiles path. When sharing runfiles, there will be symlink added: {runfiles_path} -> {runfiles_shared_path}.

Possible settings:

* "auto": Share runfiles based on the global default and based on the presence of RunfilesGroupInfo. Globally, runfiles sharing can be set to "shared", "private", or "auto", where auto shares runfiles if RunfilesGroupInfo is provided. * "shared": Always share runfiles. * "private": Never share runfiles
String optional "auto"
soci Whether to emit a SOCI ztoc (table of contents) for this layer. If set to 'auto', uses the global default //img/settings:soci setting. When enabled and the layer is gzip-compressed, a ztoc is produced in the layer action and recorded on the SingleLayerInfo provider, so images that build a SOCI Index Manifest v2 can reuse it instead of regenerating it. Non-gzip layers never emit a ztoc. String optional "auto"
tree_artifact_handling How to handle duplicate tree artifacts (directories) in the layer. If set to 'full', each tree artifact is stored at its intended path (no deduplication). If set to 'deduplicate_symlink', duplicate tree artifacts are replaced with symlinks to the first occurrence. If set to 'auto', uses the global default from --@rules_img//img/settings:layer_tree_artifact_handling. String optional "auto"

layer_from_file

load("@rules_img//img:layer.bzl", "layer_from_file")

layer_from_file(name, src, annotations, base_name_annotations, diff_id, diff_id_annotations,
                media_type)

Creates a container image layer from an arbitrary file.

This rule uses any file as a container image layer blob, computing the necessary metadata (digest, size) without any tar-specific processing like compression or optimization.

This is useful for non-tar layer content such as Helm charts, WASM modules, or other OCI artifacts.

If you want to use an existing tar file as a layer, use layer_from_tar instead.

Example:

load("@rules_img//img:layer.bzl", "layer_from_file")

# Use an arbitrary artifact as a layer
layer_from_file(
    name = "artifact_layer",
    src = ":artifact.bin",
    media_type = "application/octet-stream",
    annotations = {
        "org.opencontainers.image.title": "artifact.bin",
    },
)

ATTRIBUTES

Name Description Type Mandatory Default
name A unique name for this target. Name required
src The file to use as a layer blob. Label required
annotations Annotations to add to the layer metadata as key-value pairs. Dictionary: String -> String optional {}
base_name_annotations List of annotations that are set to the basename of the file. List of strings optional []
diff_id If set, interprets the file as a (potentially compressed) tar file and calculates the diff_id. Warning: if you do this, you probably want to use layer_from_tar instead. Boolean optional False
diff_id_annotations List of annotations that are set to the diff_id of the file. Only works with tar files. List of strings optional []
media_type Layer media type. Defaults to "application/vnd.oci.image.layer.v1.tar" if not set. String optional "application/vnd.oci.image.layer.v1.tar"

layer_from_tar

load("@rules_img//img:layer.bzl", "layer_from_tar")

layer_from_tar(name, src, annotations, compress, estargz, media_type, optimize)

Creates a container image layer from an existing tar archive.

This rule converts tar files into container image layers, useful for incorporating pre-built artifacts, third-party distributions, or legacy build outputs.

The rule can:

  • Use tar files as-is or recompress them
  • Optimize tar contents by deduplicating files
  • Add annotations to the layer metadata

Example:

load("@rules_img//img:layer.bzl", "layer_from_tar")

# Use an existing tar file as a layer
layer_from_tar(
    name = "third_party_layer",
    src = "@third_party_lib//:lib.tar.gz",
)

# Optimize and recompress
layer_from_tar(
    name = "optimized_layer",
    src = "//legacy:build_output.tar",
    optimize = True,  # Deduplicate contents
    compress = "zstd",  # Use zstd compression
)

# Add metadata annotations
layer_from_tar(
    name = "annotated_layer",
    src = "//vendor:dependencies.tar.gz",
    annotations = {
        "org.opencontainers.image.title": "Vendor Dependencies",
        "org.opencontainers.image.version": "1.2.3",
    },
)

Output groups

  • mtree: a single mtree text file

ATTRIBUTES

Name Description Type Mandatory Default
name A unique name for this target. Name required
src The tar file to convert into a layer. Must be a valid tar file (optionally compressed). Label required
annotations Annotations to add to the layer metadata as key-value pairs. Dictionary: String -> String optional {}
compress Compression algorithm to use. If set to 'auto', it keeps the existing compression, unless the layer is being optimized. String optional "auto"
estargz Whether to use estargz format. If set to 'auto', uses the global default estargz setting. When enabled, the layer will be optimized for lazy pulling and will be compatible with the estargz format. String optional "auto"
media_type Override layer media type. Use e.g. "application/vnd.cncf.helm.chart.content.v1.tar" for Helm charts. String optional ""
optimize If set, rewrites the tar file to deduplicate it's contents. This is useful for reducing the size of the image, but will take extra time and space to store the optimized layer. Boolean optional False

file_metadata

load("@rules_img//img:layer.bzl", "file_metadata")

file_metadata(*, mode, uid, gid, uname, gname, mtime, pax_records)

Creates a JSON-encoded file metadata string for use with image_layer rules.

This function generates JSON metadata that can be used to customize file attributes in container image layers, such as permissions, ownership, and timestamps.

PARAMETERS

Name Description Default Value
mode File permission mode (e.g., "0755", "0644"). String format. None
uid User ID of the file owner. Integer. None
gid Group ID of the file owner. Integer. None
uname User name of the file owner. String. None
gname Group name of the file owner. String. None
mtime Modification time in RFC3339 format (e.g., "2023-01-01T00:00:00Z"). String. None
pax_records Dict of extended attributes to set via PAX records. None

RETURNS

JSON-encoded string containing the file metadata.