diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 908c8c3057..416372becd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -244,3 +244,22 @@ jobs: dev_tags: | docker.io/hashicorppreview/${{ env.repo }}:${{ env.version }} docker.io/hashicorppreview/${{ env.repo }}:${{ env.version }}-${{ github.sha }} + + build-docker-redhat: + name: Docker Build UBI Image for RedHat + needs: + - get-product-version + - build + runs-on: ubuntu-latest + env: + repo: ${{github.event.repository.name}} + version: ${{needs.get-product-version.outputs.product-version}} + + steps: + - uses: actions/checkout@v2 + - uses: hashicorp/actions-docker-build@v1 + with: + version: ${{env.version}} + target: ubi + arch: amd64 + redhat_tag: scan.connect.redhat.com/ospid-612d01d49f14588c41ebf67c/${{env.repo}}:${{env.version}}-ubi \ No newline at end of file diff --git a/.release/docker/docker-entrypoint-ubi.sh b/.release/docker/docker-entrypoint-ubi.sh new file mode 100755 index 0000000000..6ce389b274 --- /dev/null +++ b/.release/docker/docker-entrypoint-ubi.sh @@ -0,0 +1,82 @@ +#!/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. +CONSUL_BIND= +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 + +# 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. +CONSUL_CLIENT= +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 + +# 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. +CONSUL_DATA_DIR=/consul/data +CONSUL_CONFIG_DIR=/consul/config + +# 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 + +# NOTE: Unlike in the regular Consul Docker image, we don't have code here +# for changing data-dir directory ownership or using su-exec because OpenShift +# won't run this container as root and so we can't change data dir ownership, +# and there's no need to use su-exec. + +exec "$@" \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 5f80272c9c..762471eb5a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -188,6 +188,99 @@ COPY .release/docker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh RUN chmod +x /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"] + + +# Red Hat UBI-based image +# This target is used to build a Consul image for use on OpenShift. +FROM registry.access.redhat.com/ubi8/ubi-minimal:8.6 as ubi + +ARG PRODUCT_NAME +ARG PRODUCT_VERSION +ARG PRODUCT_REVISION +ARG BIN_NAME + +# PRODUCT_NAME and PRODUCT_VERSION are the name of the software on releases.hashicorp.com +# and the version to download. Example: PRODUCT_NAME=consul PRODUCT_VERSION=1.2.3. +ENV BIN_NAME=$BIN_NAME +ENV PRODUCT_VERSION=$PRODUCT_VERSION + +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." + +# Copy license for Red Hat certification. +COPY LICENSE /licenses/mozilla.txt + +# Set up certificates and base tools. +# dumb-init is downloaded directly from GitHub because there's no RPM package. +# Its shasum is hardcoded. If you upgrade the dumb-init verion you'll need to +# also update the shasum. +RUN set -eux && \ + microdnf install -y ca-certificates curl gnupg libcap openssl iputils jq iptables wget unzip tar && \ + wget -O /usr/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_x86_64 && \ + echo 'e874b55f3279ca41415d290c512a7ba9d08f98041b28ae7c2acb19a545f1c4df /usr/bin/dumb-init' > dumb-init-shasum && \ + sha256sum --check dumb-init-shasum && \ + chmod +x /usr/bin/dumb-init + +# Create a non-root user to run the software. On OpenShift, this +# will not matter since the container is run as a random user and group +# but this is kept for consistency with our other images. +RUN groupadd $BIN_NAME && \ + adduser --uid 100 --system -g $BIN_NAME $BIN_NAME +COPY dist/$TARGETOS/$TARGETARCH/$BIN_NAME /bin/ + +# The /consul/data dir is used by Consul to store state. The agent will be started +# with /consul/config as the configuration directory so you can add additional +# config files in that location. +# In addition, change the group of the /consul directory to 0 since OpenShift +# will always execute the container with group 0. +RUN mkdir -p /consul/data && \ + mkdir -p /consul/config && \ + chown -R consul /consul && \ + chgrp -R 0 /consul && chmod -R g+rwX /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 + +COPY .release/docker/docker-entrypoint-ubi.sh /usr/local/bin/docker-entrypoint.sh +RUN chmod +x /usr/local/bin/docker-entrypoint.sh +ENTRYPOINT ["docker-entrypoint.sh"] + +# OpenShift by default will run containers with a random user, however their +# scanner requires that containers set a non-root user. +USER 100 + # 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.