Clean-up bazel wrapper.

The bazel server was being started as the wrong user, leading to issues
where the container would suddenly exit during a build.

We can also simplify the waiting logic by starting the container in two
separate steps: those that must complete first, then the asynchronous bit.

PiperOrigin-RevId: 323391161
This commit is contained in:
Adin Scannell 2020-07-27 10:38:24 -07:00 committed by gVisor bot
parent 77552f1c77
commit d0fd97541a
2 changed files with 57 additions and 24 deletions

View File

@ -643,7 +643,9 @@ func TestExec(t *testing.T) {
if err != nil {
t.Fatalf("error creating temporary directory: %v", err)
}
cmd := fmt.Sprintf("ln -s /bin/true %q/symlink && sleep 100", dir)
// Note that some shells may exec the final command in a sequence as
// an optimization. We avoid this here by adding the exit 0.
cmd := fmt.Sprintf("ln -s /bin/true %q/symlink && sleep 100 && exit 0", dir)
spec := testutil.NewSpecWithArgs("sh", "-c", cmd)
_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)

View File

@ -15,6 +15,7 @@
# limitations under the License.
# See base Makefile.
SHELL=/bin/bash -o pipefail
BRANCH_NAME := $(shell (git branch --show-current 2>/dev/null || \
git rev-parse --abbrev-ref HEAD 2>/dev/null) | \
xargs -n 1 basename 2>/dev/null)
@ -22,8 +23,11 @@ BRANCH_NAME := $(shell (git branch --show-current 2>/dev/null || \
# Bazel container configuration (see below).
USER ?= gvisor
HASH ?= $(shell readlink -m $(CURDIR) | md5sum | cut -c1-8)
BUILDER_BASE := gvisor.dev/images/default
BUILDER_IMAGE := gvisor.dev/images/builder
BUILDER_NAME ?= gvisor-builder-$(HASH)
DOCKER_NAME ?= gvisor-bazel-$(HASH)
DOCKER_PRIVILEGED ?= --privileged --network host
DOCKER_PRIVILEGED ?= --privileged
BAZEL_CACHE := $(shell readlink -m ~/.cache/bazel/)
GCLOUD_CONFIG := $(shell readlink -m ~/.config/gcloud/)
DOCKER_SOCKET := /var/run/docker.sock
@ -32,17 +36,25 @@ DOCKER_SOCKET := /var/run/docker.sock
OPTIONS += --test_output=errors --keep_going --verbose_failures=true
BAZEL := bazel $(STARTUP_OPTIONS)
# Non-configurable.
# Basic options.
UID := $(shell id -u ${USER})
GID := $(shell id -g ${USER})
USERADD_OPTIONS :=
FULL_DOCKER_RUN_OPTIONS := $(DOCKER_RUN_OPTIONS)
FULL_DOCKER_RUN_OPTIONS += --user $(UID):$(GID)
FULL_DOCKER_RUN_OPTIONS += --entrypoint ""
FULL_DOCKER_RUN_OPTIONS += --init
FULL_DOCKER_RUN_OPTIONS += -v "$(BAZEL_CACHE):$(BAZEL_CACHE)"
FULL_DOCKER_RUN_OPTIONS += -v "$(GCLOUD_CONFIG):$(GCLOUD_CONFIG)"
FULL_DOCKER_RUN_OPTIONS += -v "/tmp:/tmp"
FULL_DOCKER_EXEC_OPTIONS := --user $(UID):$(GID)
FULL_DOCKER_EXEC_OPTIONS += -i
# Add docker passthrough options.
ifneq ($(DOCKER_PRIVILEGED),)
FULL_DOCKER_RUN_OPTIONS += -v "$(DOCKER_SOCKET):$(DOCKER_SOCKET)"
FULL_DOCKER_RUN_OPTIONS += $(DOCKER_PRIVILEGED)
FULL_DOCKER_EXEC_OPTIONS += $(DOCKER_PRIVILEGED)
DOCKER_GROUP := $(shell stat -c '%g' $(DOCKER_SOCKET))
ifneq ($(GID),$(DOCKER_GROUP))
USERADD_OPTIONS += --groups $(DOCKER_GROUP)
@ -50,7 +62,30 @@ GROUPADD_DOCKER += groupadd --gid $(DOCKER_GROUP) --non-unique docker-$(HASH) &&
FULL_DOCKER_RUN_OPTIONS += --group-add $(DOCKER_GROUP)
endif
endif
SHELL=/bin/bash -o pipefail
# Add KVM passthrough options.
ifneq (,$(wildcard /dev/kvm))
FULL_DOCKER_RUN_OPTIONS += --device=/dev/kvm
KVM_GROUP := $(shell stat -c '%g' /dev/kvm)
ifneq ($(GID),$(KVM_GROUP))
USERADD_OPTIONS += --groups $(KVM_GROUP)
GROUPADD_DOCKER += groupadd --gid $(KVM_GROUP) --non-unique kvm-$(HASH) &&
FULL_DOCKER_RUN_OPTIONS += --group-add $(KVM_GROUP)
endif
endif
bazel-image: load-default
@if docker ps --all | grep $(BUILDER_NAME); then docker rm -f $(BUILDER_NAME); fi
docker run --user 0:0 --entrypoint "" --name $(BUILDER_NAME) \
$(BUILDER_BASE) \
sh -c "groupadd --gid $(GID) --non-unique $(USER) && \
$(GROUPADD_DOCKER) \
useradd --uid $(UID) --non-unique --no-create-home \
--gid $(GID) $(USERADD_OPTIONS) -d $(HOME) $(USER) && \
if [[ -e /dev/kvm ]]; then chmod a+rw /dev/kvm; fi"
docker commit $(BUILDER_NAME) $(BUILDER_IMAGE)
@docker rm -f $(BUILDER_NAME)
.PHONY: bazel-image
##
## Bazel helpers.
@ -65,41 +100,37 @@ SHELL=/bin/bash -o pipefail
## GCLOUD_CONFIG - The gcloud config directory (detect: detected).
## DOCKER_SOCKET - The Docker socket (default: detected).
##
bazel-server-start: load-default ## Starts the bazel server.
bazel-server-start: bazel-image ## Starts the bazel server.
@mkdir -p $(BAZEL_CACHE)
@mkdir -p $(GCLOUD_CONFIG)
@if docker ps --all | grep $(DOCKER_NAME); then docker rm -f $(DOCKER_NAME); fi
docker run -d --rm \
--init \
--name $(DOCKER_NAME) \
--user 0:0 $(DOCKER_GROUP_OPTIONS) \
# This command runs a bazel server, and the container sticks around
# until the bazel server exits. This should ensure that it does not
# exit in the middle of running a build, but also it won't stick around
# forever. The build commands wrap around an appropriate exec into the
# container in order to perform work via the bazel client.
docker run -d --rm --name $(DOCKER_NAME) \
-v "$(CURDIR):$(CURDIR)" \
--workdir "$(CURDIR)" \
--entrypoint "" \
$(FULL_DOCKER_RUN_OPTIONS) \
gvisor.dev/images/default \
sh -c "groupadd --gid $(GID) --non-unique $(USER) && \
$(GROUPADD_DOCKER) \
useradd --uid $(UID) --non-unique --no-create-home --gid $(GID) $(USERADD_OPTIONS) -d $(HOME) $(USER) && \
$(BAZEL) version && \
exec tail --pid=\$$($(BAZEL) info server_pid) -f /dev/null"
@while :; do if docker logs $(DOCKER_NAME) 2>/dev/null | grep "Build label:" >/dev/null; then break; fi; \
if ! docker ps | grep $(DOCKER_NAME); then docker logs $(DOCKER_NAME); exit 1; else sleep 1; fi; done
$(BUILDER_IMAGE) \
sh -c "tail -f --pid=\$$($(BAZEL) info server_pid)"
.PHONY: bazel-server-start
bazel-shutdown: ## Shuts down a running bazel server.
@docker exec --user $(UID):$(GID) $(DOCKER_NAME) $(BAZEL) shutdown; rc=$$?; docker kill $(DOCKER_NAME) || [[ $$rc -ne 0 ]]
@docker exec $(FULL_DOCKER_EXEC_OPTIONS) $(DOCKER_NAME) $(BAZEL) shutdown; \
rc=$$?; docker kill $(DOCKER_NAME) || [[ $$rc -ne 0 ]]
.PHONY: bazel-shutdown
bazel-alias: ## Emits an alias that can be used within the shell.
@echo "alias bazel='docker exec --user $(UID):$(GID) -i $(DOCKER_NAME) bazel'"
@echo "alias bazel='docker exec $(FULL_DOCKER_EXEC_OPTIONS) $(DOCKER_NAME) bazel'"
.PHONY: bazel-alias
bazel-server: ## Ensures that the server exists. Used as an internal target.
@docker exec $(DOCKER_NAME) true || $(MAKE) bazel-server-start
@docker exec $(FULL_DOCKER_EXEC_OPTIONS) $(DOCKER_NAME) true || $(MAKE) bazel-server-start
.PHONY: bazel-server
build_cmd = docker exec --user $(UID):$(GID) -i $(DOCKER_NAME) sh -o pipefail -c '$(BAZEL) build $(OPTIONS) $(TARGETS)'
build_cmd = docker exec $(FULL_DOCKER_EXEC_OPTIONS) $(DOCKER_NAME) sh -o pipefail -c '$(BAZEL) build $(OPTIONS) $(TARGETS)'
build_paths = $(build_cmd) 2>&1 \
| tee /proc/self/fd/2 \
@ -126,9 +157,9 @@ sudo: bazel-server
.PHONY: sudo
test: bazel-server
@docker exec --user $(UID):$(GID) -i $(DOCKER_NAME) $(BAZEL) test $(OPTIONS) $(TARGETS)
@docker exec $(FULL_DOCKER_EXEC_OPTIONS) $(DOCKER_NAME) $(BAZEL) test $(OPTIONS) $(TARGETS)
.PHONY: test
query: bazel-server
@docker exec --user $(UID):$(GID) -i $(DOCKER_NAME) $(BAZEL) query $(OPTIONS) '$(TARGETS)'
@docker exec $(FULL_DOCKER_EXEC_OPTIONS) $(DOCKER_NAME) $(BAZEL) query $(OPTIONS) '$(TARGETS)'
.PHONY: query