基于Bazel自定义Python工具链构建OCI Docker镜像的问题咨询
Bazel rules_oci构建Docker镜像问题解答
问题背景
正在使用Bazel的rules_oci仓库构建Docker镜像,已在WORKSPACE中注册自定义Python工具链,现有代码可构建包含该工具链、run_api_server.py及其依赖的镜像,需解决以下两个问题:
- 如何正确将Python工具链与
run_api_server设置为Docker镜像的入口点,使所有Bazel路径可直接使用? - 如何将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
相关产品推荐
相关产品推荐

