diff --git a/README.md b/README.md index 806e037d1..e872da930 100644 --- a/README.md +++ b/README.md @@ -223,8 +223,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: diff --git a/container/incremental_load.sh.tpl b/container/incremental_load.sh.tpl index 438861b2a..3b616d289 100644 --- a/container/incremental_load.sh.tpl +++ b/container/incremental_load.sh.tpl @@ -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 diff --git a/container/layer_tools.bzl b/container/layer_tools.bzl index 1670d82ce..dcd093e87 100644 --- a/container/layer_tools.bzl +++ b/container/layer_tools.bzl @@ -220,18 +220,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: @@ -271,11 +274,6 @@ 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, @@ -283,7 +281,7 @@ def incremental_load( "%{docker_flags}": " ".join(toolchain_info.docker_flags), "%{docker_tool_path}": docker_path(toolchain_info), "%{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