You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Bazel自定义Python工具链构建OCI Docker镜像的问题咨询

Bazel rules_oci构建Docker镜像问题解答

问题背景

正在使用Bazel的rules_oci仓库构建Docker镜像,已在WORKSPACE中注册自定义Python工具链,现有代码可构建包含该工具链、run_api_server.py及其依赖的镜像,需解决以下两个问题:

  1. 如何正确将Python工具链与run_api_server设置为Docker镜像的入口点,使所有Bazel路径可直接使用?
  2. 如何将Bazel项目中的相关代码隔离到Docker镜像的/app目录下?

问题1:设置镜像入口点

Bazel生成的py_binary是一个自动封装的wrapper脚本,会自动加载runfiles中的Python解释器和依赖。只需在镜像构建规则中指定entrypoint,指向该脚本的路径即可。

修改py_image.bzl中的py_oci_image函数

在oci_image调用中添加entrypoint参数:

def py_oci_image(name, binary, tars = [], **kwargs):
    """
    Wrapper around oci_image that splits the py_binary into layers.
    Note you need to wrap the result of this rule in oci_tarball to produce
    an image that can be loaded by docker
    Args:
        name: name for the target
        binary: a py_binary target
        tars: extra docker layers, apart from `binary` dependencies
        kwargs: see oci_image docs
    """
    # 从binary标签中提取可执行文件名(如":run_api_server"提取为"run_api_server")
    binary_name = binary.split(":")[-1]
    oci_image(
        name = name,
        tars = tars + py_layers(name, binary),
        entrypoint = ["/{}".format(binary_name)],  # 设置入口点为py_binary可执行文件
        **kwargs
    )

镜像启动时会直接执行该wrapper脚本,自动调用Bazel打包的Python工具链并加载所有依赖。


问题2:将代码隔离到/app目录

通过修改tar规则的prefix参数,让所有项目文件、依赖和Python工具链都打包到镜像的/app目录下。

修改py_image.bzl中的py_layers函数

在tar规则中添加prefix="/app":

def py_layers(name, binary):
    """
    Create three layers for a py_binary target: interpreter, third-party dependencies, and application code.

    This allows a container image to have smaller uploads, since the application layer usually changes more
    than the other two.

    Args:
        name: prefix for generated targets, to ensure they are unique within the package
        binary: a py_binary target
    Returns:
        a list of labels for the layers, which are tar files
    """

    layers = ["interpreter", "packages", "app"]

    mtree_spec(
        name = name + ".mf",
        srcs = [binary],
    )

    native.genrule(
        name = name + ".interpreter_tar_manifest",
        srcs = [name + ".mf"],
        outs = [name + ".interpreter_tar_manifest.spec"],
        cmd = "grep '{}' $< >$@".format(PY_INTERPRETER_REGEX),
    )

    native.genrule(
        name = name + ".packages_tar_manifest",
        srcs = [name + ".mf"],
        outs = [name + ".packages_tar_manifest.spec"],
        cmd = "grep '{}' $< >$@".format(SITE_PACKAGES_REGEX),
    )

    native.genrule(
        name = name + ".app_tar_manifest",
        srcs = [name + ".mf"],
        outs = [name + ".app_tar_manifest.spec"],
        cmd = "grep -v '{}' $< | grep -v '{}' >$@".format(SITE_PACKAGES_REGEX, PY_INTERPRETER_REGEX),
    )

    result = []
    for layer in layers:
        layer_target = "{}.{}_layer".format(name, layer)
        result.append(layer_target)
        tar(
            name = layer_target,
            srcs = [binary],
            mtree = "{}.{}_tar_manifest".format(name, layer),
            prefix = "/app",  # 新增:将所有文件打包到/app目录下
        )

    return result

同步更新入口点路径

由于文件已移至/app目录,需修改py_oci_image中的entrypoint路径:

def py_oci_image(name, binary, tars = [], **kwargs):
    binary_name = binary.split(":")[-1]
    oci_image(
        name = name,
        tars = tars + py_layers(name, binary),
        entrypoint = ["/app/{}".format(binary_name)],  # 入口点改为/app下的可执行文件
        workdir = "/app",  # 可选:设置容器启动的工作目录为/app
        **kwargs
    )

验证步骤

修改完成后,重新构建镜像:

bazel build :run_api_server_docker

加载镜像并运行:

docker load -i bazel-bin/run_api_server_docker.tar
docker run my.repo/py_run_api_server_docker:latest

此时容器会以/app/run_api_server为入口启动,所有代码和依赖均位于/app目录下,且能正确调用Bazel打包的Python工具链。

内容的提问来源于stack exchange,提问作者niko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 03:20:04