Skip to content
This repository has been archived by the owner on Oct 2, 2023. It is now read-only.

Support for docker run args for docker image targets #1957

Merged
merged 6 commits into from
Dec 17, 2021
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
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,20 @@ You can load this into your local Docker client by running:
`bazel run my/image:helloworld`.

For the `lang_image` targets, this will also **run** the
container to maximize compatibility with `lang_binary` rules. You can suppress
this behavior by passing the single flag: `bazel run :foo -- --norun`
container using `docker run` to maximize compatibility with `lang_binary` rules.

Arguments to this command are forwarded to docker, meaning the command

```bash
bazel run my/image:helloworld -- -p 8080:80 -- arg0
```

performs the following steps:
* load the `my/image:helloworld` target into your local Docker client
* start a container using this image where `arg0` is passed to the image entrypoint
* port forward 8080 on the host to port 80 on the container, as per `docker run` documentation

You can suppress this behavior by passing the single flag: `bazel run :foo -- --norun`

Alternatively, you can build a `docker load` compatible bundle with:
`bazel build my/image:helloworld.tar`. This will produce the file:
Expand Down
34 changes: 32 additions & 2 deletions container/incremental_load.sh.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -242,11 +242,41 @@ function read_variables() {
# An optional "docker run" statement for invoking a loaded container.
# This is not executed if the single argument --norun is passed or
# no run_statements are generated (in which case, 'run' is 'False').
if [[ "a$*" != "a--norun" && "%{run}" == "True" ]]; then
if [[ "%{run}" == "True" ]]; then
docker_args=()
container_args=()

# Search remaining params looking for docker and container args.
#
# It is assumed that they will follow the pattern:
# [dockerargs...] -- [container args...]
#
# "--norun" is treated as a "virtual" additional parameter to
# "docker run", since it cannot conflict with any "docker run"
# arguments. If "--norun" needs to be passed to the container,
# it can be safely placed after "--".
while test $# -gt 0
do
case "$1" in
--norun) # norun as a "docker run" option means exit
exit
;;
--) # divider between docker and container args
shift
container_args=("$@")
break
;;
*) # potential "docker run" option
docker_args+=("$1")
shift
;;
esac
done

# Once we've loaded the images for all layers, we no longer need the temporary files on disk.
# We can clean up before we exec docker, since the exit handler will no longer run.
cleanup

# This generated and injected by docker_*.
exec %{run_statements}
exec %{run_statement} "${docker_args[@]}" "%{run_tag}" "${container_args[@]}"
fi
22 changes: 10 additions & 12 deletions container/layer_tools.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -216,18 +216,21 @@ def incremental_load(

toolchain_info = ctx.toolchains["@io_bazel_rules_docker//toolchains/docker:toolchain_type"].info

# Default to interactively launching the container,
# and cleaning up when it exits.

run_flags = run_flags or "-i --rm"

if len(images) > 1 and run:
fail("Bazel run does not currently support execution of " +
"multiple containers (only loading).")

# Default to interactively launching the container, and cleaning up when
# it exits. These template variables are unused if "run" is not set, so
# it is harmless to always define them as a function of the first image.
run_flags = run_flags or "-i --rm"
run_statement = "\"${DOCKER}\" ${DOCKER_FLAGS} run %s" % run_flags
run_tag = images.keys()[0]
if stamp:
run_tag = run_tag.replace("{", "${")

load_statements = []
tag_statements = []
run_statements = []

# TODO(mattmoor): Consider adding cleanup_statements.
for tag in images:
Expand Down Expand Up @@ -267,19 +270,14 @@ def incremental_load(
_get_runfile_path(ctx, image["config_digest"]),
),
)
if run:
# Args are embedded into the image, so omitted here.
run_statements.append(
"\"${DOCKER}\" ${DOCKER_FLAGS} run %s %s \"$@\"" % (run_flags, tag_reference),
)

ctx.actions.expand_template(
template = ctx.file.incremental_load_template,
substitutions = {
"%{docker_flags}": " ".join(toolchain_info.docker_flags),
"%{docker_tool_path}": toolchain_info.tool_path,
"%{load_statements}": "\n".join(load_statements),
"%{run_statements}": "\n".join(run_statements),
"%{run_statement}": run_statement,
"%{run}": str(run),
# If this rule involves stamp variables than load them as bash
# variables, and turn references to them into bash variable
Expand Down