// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: BUSL-1.1 package build import ( "context" "strings" "github.com/hashicorp/go-hclog" "github.com/hashicorp/consul/testing/deployer/sprawl/internal/runner" "github.com/hashicorp/consul/testing/deployer/topology" ) const dockerfileEnvoy = ` ARG CONSUL_IMAGE ARG ENVOY_IMAGE FROM ${CONSUL_IMAGE} FROM ${ENVOY_IMAGE} COPY --from=0 /bin/consul /bin/consul ` // FROM hashicorp/consul-dataplane:latest // COPY --from=busybox:uclibc /bin/sh /bin/sh // TODO: busybox:latest doesn't work, see https://hashicorp.slack.com/archives/C03EUN3QF1C/p1691784078972959 const dockerfileDataplane = ` ARG DATAPLANE_IMAGE FROM busybox:1.34 FROM ${DATAPLANE_IMAGE} COPY --from=0 /bin/busybox /bin/busybox USER 0:0 RUN ["busybox", "--install", "/bin", "-s"] USER 100:0 ENTRYPOINT [] ` const dockerfileDataplaneForTProxy = ` ARG DATAPLANE_IMAGE ARG CONSUL_IMAGE FROM ${CONSUL_IMAGE} AS consul FROM ${DATAPLANE_IMAGE} AS distroless FROM debian:bullseye-slim # undo the distroless aspect COPY --from=distroless /usr/local/bin/discover /usr/local/bin/ COPY --from=distroless /usr/local/bin/envoy /usr/local/bin/ COPY --from=distroless /usr/local/bin/consul-dataplane /usr/local/bin/ COPY --from=distroless /licenses/copyright.txt /licenses/ COPY --from=consul /bin/consul /bin/ # Install iptables and sudo, needed for tproxy. RUN apt update -y \ && apt install -y iptables sudo curl dnsutils RUN sed '/_apt/d' /etc/passwd > /etc/passwd.new \ && mv -f /etc/passwd.new /etc/passwd \ && adduser --uid=100 consul --no-create-home --disabled-password --system \ && adduser consul sudo \ && echo 'consul ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers COPY <<'EOF' /bin/tproxy-startup.sh #!/bin/sh set -ex # HACK: UID of consul in the consul-client container # This is conveniently also the UID of apt in the envoy container CONSUL_UID=100 ENVOY_UID=$(id -u) # - We allow 19000 so that the test can directly visit the envoy admin page. # - We allow 20000 so that envoy can receive mTLS traffic from other nodes. # - We (reluctantly) allow 8080 so that we can bypass envoy and talk to fortio # to do test assertions. sudo consul connect redirect-traffic \ -proxy-uid $ENVOY_UID \ -exclude-uid $CONSUL_UID \ -proxy-inbound-port=15001 \ -exclude-inbound-port=19000 \ -exclude-inbound-port=20000 \ -exclude-inbound-port=8080 exec "$@" EOF RUN chmod +x /bin/tproxy-startup.sh \ && chown 100:0 /bin/tproxy-startup.sh RUN echo 'consul ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers USER 100:0 ENTRYPOINT [] ` func DockerImages( logger hclog.Logger, run *runner.Runner, t *topology.Topology, ) error { built := make(map[string]struct{}) for _, c := range t.Clusters { for _, n := range c.Nodes { needsTproxy := n.NeedsTransparentProxy() joint := n.Images.EnvoyConsulImage() if _, ok := built[joint]; joint != "" && !ok { logger.Info("building envoy+consul image", "image", joint) logw := logger.Named("docker_envoy_consul").StandardWriter(&hclog.StandardLoggerOptions{ForceLevel: hclog.Debug}) err := run.DockerExecWithStderr(context.TODO(), []string{ "build", // provenance causes non-idempotent builds, which leads to spurious terraform replacements "--provenance=false", "--build-arg", "CONSUL_IMAGE=" + n.Images.Consul, "--build-arg", "ENVOY_IMAGE=" + n.Images.Envoy, "-t", joint, "-", }, logw, logw, strings.NewReader(dockerfileEnvoy)) if err != nil { return err } built[joint] = struct{}{} } cdp := n.Images.LocalDataplaneImage() if _, ok := built[cdp]; cdp != "" && !ok { logger.Info("building dataplane image", "image", cdp) logw := logger.Named("docker_dataplane").StandardWriter(&hclog.StandardLoggerOptions{ForceLevel: hclog.Debug}) err := run.DockerExecWithStderr(context.TODO(), []string{ "build", "--provenance=false", "--build-arg", "DATAPLANE_IMAGE=" + n.Images.Dataplane, "-t", cdp, "-", }, logw, logw, strings.NewReader(dockerfileDataplane)) if err != nil { return err } built[cdp] = struct{}{} } cdpTproxy := n.Images.LocalDataplaneTProxyImage() if _, ok := built[cdpTproxy]; cdpTproxy != "" && !ok && needsTproxy { logger.Info("building image", "image", cdpTproxy) logw := logger.Named("docker_dataplane_tproxy").StandardWriter(&hclog.StandardLoggerOptions{ForceLevel: hclog.Debug}) err := run.DockerExecWithStderr(context.TODO(), []string{ "build", "--build-arg", "DATAPLANE_IMAGE=" + n.Images.Dataplane, "--build-arg", "CONSUL_IMAGE=" + n.Images.Consul, "-t", cdpTproxy, "-", }, logw, logw, strings.NewReader(dockerfileDataplaneForTProxy)) if err != nil { return err } built[cdpTproxy] = struct{}{} } } } return nil }