|
# syntax=docker/dockerfile:1.4 |
|
# ^-- this line at the top indicates the "features" to consider in this Dockerfile. |
|
# ref: https://docs.docker.com/engine/reference/builder/#syntax |
|
|
|
# This argument is used to direct which image tag of the upstream Ignition image to use. |
|
ARG IGNITION_VERSION=${IGNITION_VERSION} |
|
# We label this first stage of our multi-stage build "prep" |
|
FROM inductiveautomation/ignition:${IGNITION_VERSION} as prep |
|
|
|
# Install some prerequisite packages--these are programs that our helper scripts |
|
# will be using. We're not worrying about cleaning up the package indexes here |
|
# because we're not in the final stage that will become the real image. |
|
RUN apt-get update && apt-get install -y wget ca-certificates jq zip unzip sqlite3 |
|
|
|
# These arguments have download links and file integrity checksums. We use indirection to reference these based on the |
|
# middle identifiers like `AZUREIOTINJECTOR` or `MQTTENGINE`. This way we can supply just those identifiers in the |
|
# `SUPPLEMENTAL_MODULES` arg when performing the build. |
|
ARG SUPPLEMENTAL_AZUREIOTINJECTOR_DOWNLOAD_URL="https://files.inductiveautomation.com/third-party/cirrus-link/4.0.11/Azure-Injector-signed.modl" |
|
ARG SUPPLEMENTAL_AZUREIOTINJECTOR_DOWNLOAD_SHA256="17babfcc28386262b5b67c5d7109dd4e0c346461d7a9add7f086fddd952574c0" |
|
ARG SUPPLEMENTAL_MQTTTRANSMISSION_DOWNLOAD_URL="https://files.inductiveautomation.com/third-party/cirrus-link/4.0.11/MQTT-Transmission-signed.modl" |
|
ARG SUPPLEMENTAL_MQTTTRANSMISSION_DOWNLOAD_SHA256="15e6b7f548dc909ffba1af44527e494e918192295835390f2e921a93f243ca07" |
|
ARG SUPPLEMENTAL_MQTTTRANSMISSIONNIGHTLY_DOWNLOAD_URL="https://ignition-modules-nightly.s3.amazonaws.com/Ignition8/MQTT-Transmission-signed.modl" |
|
ARG SUPPLEMENTAL_MQTTTRANSMISSIONNIGHTLY_DOWNLOAD_SHA256="notused" |
|
ARG SUPPLEMENTAL_MQTTENGINE_DOWNLOAD_URL="https://files.inductiveautomation.com/third-party/cirrus-link/4.0.11/MQTT-Engine-signed.modl" |
|
ARG SUPPLEMENTAL_MQTTENGINE_DOWNLOAD_SHA256="bebfdab4f423b5ffa40b3e4114781145dadd0eadb3500f48ca904365a838e0c9" |
|
ARG SUPPLEMENTAL_MQTTENGINENIGHTLY_DOWNLOAD_URL="https://ignition-modules-nightly.s3.amazonaws.com/Ignition8/MQTT-Engine-signed.modl" |
|
ARG SUPPLEMENTAL_MQTTENGINENIGHTLY_DOWNLOAD_SHA256="notused" |
|
ARG SUPPLEMENTAL_MQTTDISTRIBUTOR_DOWNLOAD_URL="https://files.inductiveautomation.com/third-party/cirrus-link/4.0.11/MQTT-Distributor-signed.modl" |
|
ARG SUPPLEMENTAL_MQTTDISTRIBUTOR_DOWNLOAD_SHA256="a27fdf7b2e9ca74e4eac571283aae0829cefbe4c19776506cd2b092d543175e2" |
|
ARG SUPPLEMENTAL_MQTTDISTRIBUTORNIGHTLY_DOWNLOAD_URL="https://ignition-modules-nightly.s3.amazonaws.com/Ignition8/MQTT-Distributor-signed.modl" |
|
ARG SUPPLEMENTAL_MQTTDISTRIBUTORNIGHTLY_DOWNLOAD_SHA256="notused" |
|
# This is the only argument that we expect to be supplied during the build, but there is handling for it |
|
# being omitted below (in the case of no supplemental modules desired). |
|
ARG SUPPLEMENTAL_MODULES |
|
|
|
# Set working directory for this prep image and |
|
WORKDIR /root |
|
# Configure shell to be bash since we're going to use some more advanced syntax below that `sh` (the default) |
|
# won't be able to accept. Also set default some options for bash that will help ensure that exits from |
|
# sub-shells bubble up and report an error (and thus break the build). |
|
SHELL [ "/usr/bin/env", "-S", "bash", "-euo", "pipefail", "-O", "inherit_errexit", "-c" ] |
|
|
|
# Retrieve all targeted modules and verify their integrity. This helper script contains a lot of the logic and |
|
# is designed to be used standalone. Note that `--chmod=0755` may not be supported by builders other than more |
|
# recent versions of BuildKit. If you run into errors here, just omit it, and then put a |
|
# `RUN chmod a+rx retrieve-modules.sh` statement after it to make sure it is executable. The `chmod` technique is |
|
# especially nice for final images since it only results in a single layer. |
|
COPY --chmod=0755 retrieve-modules.sh . |
|
# Run our `retrieve-modules.sh` helper script, and feed it our comma-delimited list of identifiers, defaulting to |
|
# a blank string. See Shell Parameter expansion in Bash user guide: https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html |
|
# This helper script will indirect to the ARG's listed above and download the modules from their respective location |
|
# as well as validate their file integrity. The image build will fail if a given downloaded module doesn't match |
|
# the prescribed SHA256 hash. |
|
RUN ./retrieve-modules.sh \ |
|
-m "${SUPPLEMENTAL_MODULES:-}" |
|
|
|
# Set CERTIFICATES/EULAS acceptance in gateway backup config db |
|
# First we'll copy this base gateway backup file from our build context... |
|
COPY base.gwbk . |
|
# Then we'll copy in our helper scripts: |
|
# - register-module.sh - used to auto-accept the Certificate and EULA for a given module in the SQLite Ignition DB |
|
# - register-password.sh - used to set the base admin username/password instead of relying on password reset. |
|
COPY --chmod=0755 register-module.sh register-password.sh ./ |
|
# We'll set a default for `GATEWAY_ADMIN_USERNAME`, which is consumed by the `register-password.sh` script. |
|
ARG GATEWAY_ADMIN_USERNAME="admin" |
|
# Okay, a lot to unpack here, let's go step by step. To start, we're using Docker build secrets here to make sure |
|
# that the secret we're bringing in (the password to be set) is treated safely (i.e. tmpfs mounted). See this |
|
# page for more information: https://docs.docker.com/develop/develop-images/build_enhancements/#new-docker-build-secret-information |
|
RUN --mount=type=secret,id=gateway-admin-password \ |
|
# First we'll extract the embedded SQLite Config DB from the gateway backup |
|
unzip -q base.gwbk db_backup_sqlite.idb && \ |
|
# Then we'll reconfigure our shell environment to allow nullglob... |
|
shopt -s nullglob; \ |
|
# ... so that when we invoke this for-loop and there are no modules, it just quietly skips onward |
|
for module in *.modl; do \ |
|
# Invoke our helper script and feed it the module filename and the config db. We'll run this |
|
# for each module that we downloaded above. |
|
./register-module.sh \ |
|
-f "${module}" \ |
|
-d db_backup_sqlite.idb; \ |
|
done; \ |
|
# Turn off the nullglob since we're done with it |
|
shopt -u nullglob && \ |
|
# Invoke our `register-password.sh` helper script, which will modify the first entry in the `default` |
|
# user source within the specified Ignition Config DB (from the GWBK). This particular invocation expects |
|
# there to be a file (our mounted secret) with the contents being the password. |
|
./register-password.sh \ |
|
-u "${GATEWAY_ADMIN_USERNAME}" \ |
|
-f /run/secrets/gateway-admin-password \ |
|
-d db_backup_sqlite.idb && \ |
|
# Finally, re-integrate the modified config db into the base gateway backup (zip file) |
|
zip -q -f base.gwbk db_backup_sqlite.idb || \ |
|
# This special handling accounts for the situation where the zip command above exits with |
|
# code 12 due to no action performed (the file is not changed). |
|
if [[ ${ZIP_EXIT_CODE:=$?} == 12 ]]; then \ |
|
echo "No changes to internal database needed during module registration."; \ |
|
else \ |
|
# if something else went wrong, then we exit with the associated code which will fail the build. |
|
echo "Unknown error (${ZIP_EXIT_CODE}) encountered during re-packaging of config db, exiting." && \ |
|
exit ${ZIP_EXIT_CODE}; \ |
|
fi |
|
|
|
# Final Image - the layers from this point forward will end up in the final image. |
|
# Note: we're starting with all of the layers from the upstream inductiveautomation/ignition image. |
|
FROM inductiveautomation/ignition:${IGNITION_VERSION} as final |
|
|
|
# Add supplemental packages, such as git if needed/desired |
|
# First we'll update the apt package index, since it isn't present in the upstream image. |
|
# These are intentionally purged during the image build because they'll be out-of-date and |
|
# we don't want to bake that in. |
|
RUN apt-get update && \ |
|
# We'll use noninteractive mode to make sure that `apt-get` doesn't try to prompt |
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ |
|
# Here is the list of packages we're installing... |
|
git && \ |
|
# ... and here we're wiping the cached package index back out now that we're done. |
|
rm -rf /var/lib/apt/lists/* |
|
# Notice that the above is a single `RUN` command to prevent accumulation of a ton of image layers |
|
|
|
# Embed modules and base gwbk from prep image as well as entrypoint shim |
|
# Notice that we're using `--from` here to copy not from our build context, but from the first |
|
# stage of our multi-stage build, the one we named `prep`. |
|
COPY --from=prep /root/*.modl ${IGNITION_INSTALL_LOCATION}/user-lib/modules/ |
|
COPY --from=prep /root/base.gwbk ${IGNITION_INSTALL_LOCATION}/base.gwbk |
|
COPY --chmod=0755 docker-entrypoint-shim.sh /usr/local/bin/ |
|
|
|
# Supplement other default environment variables--this is a way you can preload configuration into |
|
# your derived image. You can always override these when you run the container, such as you might do |
|
# with `IGNITION_EDITION=edge`, for example. |
|
ENV ACCEPT_IGNITION_EULA=Y \ |
|
IGNITION_EDITION=standard \ |
|
GATEWAY_MODULES_ENABLED=all |
|
|
|
# Target the entrypoint shim for any custom logic prior to gateway launch |
|
ENTRYPOINT [ "docker-entrypoint-shim.sh" ] |