From 6f7a3eab376cd20c76be86ca2b8cf25bbca28670 Mon Sep 17 00:00:00 2001 From: 99 Date: Wed, 20 Oct 2021 15:25:55 -0700 Subject: [PATCH] Add Dockerfile --- .release/docker/docker-entrypoint.sh | 114 +++++++++++++++++++++++++++ Dockerfile | 67 ++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 .release/docker/docker-entrypoint.sh create mode 100644 Dockerfile diff --git a/.release/docker/docker-entrypoint.sh b/.release/docker/docker-entrypoint.sh new file mode 100644 index 0000000000..fe91711c6e --- /dev/null +++ b/.release/docker/docker-entrypoint.sh @@ -0,0 +1,114 @@ +#!/usr/bin/dumb-init /bin/sh +set -e + +# Note above that we run dumb-init as PID 1 in order to reap zombie processes +# as well as forward signals to all processes in its session. Normally, sh +# wouldn't do either of these functions so we'd leak zombies as well as do +# unclean termination of all our sub-processes. +# As of docker 1.13, using docker run --init achieves the same outcome. + +# You can set CONSUL_BIND_INTERFACE to the name of the interface you'd like to +# bind to and this will look up the IP and pass the proper -bind= option along +# to Consul. +if [ -z "$CONSUL_BIND" ]; then + if [ -n "$CONSUL_BIND_INTERFACE" ]; then + CONSUL_BIND_ADDRESS=$(ip -o -4 addr list $CONSUL_BIND_INTERFACE | head -n1 | awk '{print $4}' | cut -d/ -f1) + if [ -z "$CONSUL_BIND_ADDRESS" ]; then + echo "Could not find IP for interface '$CONSUL_BIND_INTERFACE', exiting" + exit 1 + fi + + CONSUL_BIND="-bind=$CONSUL_BIND_ADDRESS" + echo "==> Found address '$CONSUL_BIND_ADDRESS' for interface '$CONSUL_BIND_INTERFACE', setting bind option..." + fi +fi + +# You can set CONSUL_CLIENT_INTERFACE to the name of the interface you'd like to +# bind client intefaces (HTTP, DNS, and RPC) to and this will look up the IP and +# pass the proper -client= option along to Consul. +if [ -z "$CONSUL_CLIENT" ]; then + if [ -n "$CONSUL_CLIENT_INTERFACE" ]; then + CONSUL_CLIENT_ADDRESS=$(ip -o -4 addr list $CONSUL_CLIENT_INTERFACE | head -n1 | awk '{print $4}' | cut -d/ -f1) + if [ -z "$CONSUL_CLIENT_ADDRESS" ]; then + echo "Could not find IP for interface '$CONSUL_CLIENT_INTERFACE', exiting" + exit 1 + fi + + CONSUL_CLIENT="-client=$CONSUL_CLIENT_ADDRESS" + echo "==> Found address '$CONSUL_CLIENT_ADDRESS' for interface '$CONSUL_CLIENT_INTERFACE', setting client option..." + fi +fi + +# CONSUL_DATA_DIR is exposed as a volume for possible persistent storage. The +# CONSUL_CONFIG_DIR isn't exposed as a volume but you can compose additional +# config files in there if you use this image as a base, or use CONSUL_LOCAL_CONFIG +# below. +if [ -z "$CONSUL_DATA_DIR" ]; then + CONSUL_DATA_DIR=/consul/data +fi + +if [ -z "$CONSUL_CONFIG_DIR" ]; then + CONSUL_CONFIG_DIR=/consul/config +fi + +# You can also set the CONSUL_LOCAL_CONFIG environemnt variable to pass some +# Consul configuration JSON without having to bind any volumes. +if [ -n "$CONSUL_LOCAL_CONFIG" ]; then + echo "$CONSUL_LOCAL_CONFIG" > "$CONSUL_CONFIG_DIR/local.json" +fi + +# If the user is trying to run Consul directly with some arguments, then +# pass them to Consul. +if [ "${1:0:1}" = '-' ]; then + set -- consul "$@" +fi + +# Look for Consul subcommands. +if [ "$1" = 'agent' ]; then + shift + set -- consul agent \ + -data-dir="$CONSUL_DATA_DIR" \ + -config-dir="$CONSUL_CONFIG_DIR" \ + $CONSUL_BIND \ + $CONSUL_CLIENT \ + "$@" +elif [ "$1" = 'version' ]; then + # This needs a special case because there's no help output. + set -- consul "$@" +elif consul --help "$1" 2>&1 | grep -q "consul $1"; then + # We can't use the return code to check for the existence of a subcommand, so + # we have to use grep to look for a pattern in the help output. + set -- consul "$@" +fi + +# If we are running Consul, make sure it executes as the proper user. +if [ "$1" = 'consul' -a -z "${CONSUL_DISABLE_PERM_MGMT+x}" ]; then + # Allow to setup user and group via envrironment + if [ -z "$CONSUL_UID" ]; then + CONSUL_UID="$(id -u consul)" + fi + + if [ -z "$CONSUL_GID" ]; then + CONSUL_GID="$(id -g consul)" + fi + + # If the data or config dirs are bind mounted then chown them. + # Note: This checks for root ownership as that's the most common case. + if [ "$(stat -c %u "$CONSUL_DATA_DIR")" != "${CONSUL_UID}" ]; then + chown ${CONSUL_UID}:${CONSUL_GID} "$CONSUL_DATA_DIR" + fi + if [ "$(stat -c %u "$CONSUL_CONFIG_DIR")" != "${CONSUL_UID}" ]; then + chown ${CONSUL_UID}:${CONSUL_GID} "$CONSUL_CONFIG_DIR" + fi + + # If requested, set the capability to bind to privileged ports before + # we drop to the non-root user. Note that this doesn't work with all + # storage drivers (it won't work with AUFS). + if [ ! -z ${CONSUL_ALLOW_PRIVILEGED_PORTS+x} ]; then + setcap "cap_net_bind_service=+ep" /bin/consul + fi + + set -- su-exec ${CONSUL_UID}:${CONSUL_GID} "$@" +fi + +exec "$@" diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..6df3022117 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,67 @@ +# This Dockerfile creates a production release image for the project using crt release flow. +FROM alpine:3.13 as default + +ARG VERSION +ARG BIN_NAME + +# PRODUCT_NAME and PRODUCT_VERSION are the name of the software in releases.hashicorp.com +# and the version to download. Example: PRODUCT_NAME=consul PRODUCT_VERSION=1.2.3. +ENV BIN_NAME=$BIN_NAME +ENV VERSION=$VERSION +#ARG CONSUL_VERSION=$VERSION +#ARG PRODUCT_VERSION +ARG PRODUCT_REVISION +ARG PRODUCT_NAME=$BIN_NAME +# TARGETOS and TARGETARCH are set automatically when --platform is provided. +ARG TARGETOS TARGETARCH + +LABEL org.opencontainers.image.authors="Consul Team " \ + org.opencontainers.image.url="https://www.consul.io/" \ + org.opencontainers.image.documentation="https://www.consul.io/docs" \ + org.opencontainers.image.source="https://github.com/hashicorp/consul" \ + org.opencontainers.image.version=$VERSION \ + org.opencontainers.image.vendor="HashiCorp" \ + org.opencontainers.image.title="consul" \ + org.opencontainers.image.description="Consul is a datacenter runtime that provides service discovery, configuration, and orchestration." + +# Create a consul user and group first so the IDs get set the same way, even as +# the rest of this may change over time. +RUN addgroup $BIN_NAME && \ + adduser -S -G $BIN_NAME $BIN_NAME +COPY dist/$TARGETOS/$TARGETARCH/$BIN_NAME /bin/ + + +RUN mkdir -p /consul/data && \ + mkdir -p /consul/config && \ + chown -R consul:consul /consul + +# set up nsswitch.conf for Go's "netgo" implementation which is used by Consul, +# otherwise DNS supercedes the container's hosts file, which we don't want. +#RUN test -e /etc/nsswitch.conf || echo 'hosts: files dns' > /etc/nsswitch.conf + +# Expose the consul data directory as a volume since there's mutable state in there. +VOLUME /consul/data + +# Server RPC is used for communication between Consul clients and servers for internal +# request forwarding. +EXPOSE 8300 + +# Serf LAN and WAN (WAN is used only by Consul servers) are used for gossip between +# Consul agents. LAN is within the datacenter and WAN is between just the Consul +# servers in all datacenters. +EXPOSE 8301 8301/udp 8302 8302/udp + +# HTTP and DNS (both TCP and UDP) are the primary interfaces that applications +# use to interact with Consul. +EXPOSE 8500 8600 8600/udp + +# Consul doesn't need root privileges so we run it as the consul user from the +# entry point script. The entry point script also uses dumb-init as the top-level +# process to reap any zombie processes created by Consul sub-processes. +COPY .release/docker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh +ENTRYPOINT ["docker-entrypoint.sh"] + +# By default you'll get an insecure single-node development server that stores +# everything in RAM, exposes a web UI and HTTP endpoints, and bootstraps itself. +# Don't use this configuration for production. +CMD ["agent", "-dev", "-client", "0.0.0.0"]