Docker: Gateway Restore & MQTT Module Install Challenges

Our goal is to have a combination of a dockerfile(s) and a docker-compose that will create a base image that contains the necessary MQTT modules installed along with restoring a Gateway backup on to the containers.

Where I am getting stuck is in two areas:

  1. MQTT Module Installing (MQTT module shows up in the Gateway, but is not installed and must be installed after container is running manually - except EULA and Cert.).
  2. Gateway back restore does not seem to work with the docker-compose I am using. The backup file mounts correctly and can be seen in the container in BASH, but the -r command does not seem to work or I have done this incorrectly.

Any suggestions out there?

Dockerfiles:

Transmitter Gateway

# Use the official Ignition image
FROM inductiveautomation/ignition:8.1.37

COPY MQTT-Transmission-signed.modl /usr/local/bin/ignition/user-lib/modules/

USER root

# Update the package list and install utilities
RUN apt-get update && apt-get install -y \
    iputils-ping \
    htop \
    nano \
	net-tools \
	traceroute \
    && apt-get clean && rm -rf /var/lib/apt/lists/*

# Expose required ports
EXPOSE 8088 1883

Engine/Distriburtor Gateway

# Use the official Ignition image
FROM inductiveautomation/ignition:8.1.37

COPY MQTT-Engine-signed.modl /usr/local/bin/ignition/user-lib/modules/
COPY MQTT-Distributor-signed.modl /usr/local/bin/ignition/user-lib/modules/

USER root

# Update the package list and install utilities
RUN apt-get update && apt-get install -y \
    iputils-ping \
    htop \
    nano \
	net-tools \
	traceroute \
    && apt-get clean && rm -rf /var/lib/apt/lists/*

# Expose required ports
EXPOSE 8088 1883

Docker Compose:

# Docker Compose Example for inductiveautomation/ignition
# Compose Spec: https://github.com/compose-spec/compose-spec/blob/master/spec.md
---  
services:
  sandbox_edge:
    build:
      context: .
      dockerfile: Dockerfile.edge
# Transmitter Container
    container_name: iX_SandBoxEdge
    environment:
      - ACCEPT_IGNITION_EULA=Y
      - GATEWAY_ADMIN_USERNAME=admin
    #  - GATEWAY_ADMIN_PASSWORD_FILE=/run/secrets/gateway-admin-password
      - GATEWAY_ADMIN_PASSWORD=password
      - IGNITION_EDITION=edge
      - TZ=America/Vancouver  # see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
    ports:
      - "9088:8088"  # Map HTTP port
      - "9883:1883"  # Map MQTT port
    networks:
      iX_Sandbox:
        ipv4_address: 192.168.1.100
    volumes:
      - edge-data:/usr/local/bin/ignition/data # Mounts the local folder 'edge-data' to '/app/files' in the container
      - ./:/app  # Mounts the directory with your backup file
    command: >
# This line does not seem to work???
        -r /<your Gateway backup filename goes here>.gwbk


  sandbox_cloud:
    build:
      context: .
      dockerfile: Dockerfile.cloud

# Engine/Distributor Container
    container_name: iX_SandBoxCloud
    environment:
        - ACCEPT_IGNITION_EULA=Y
        - GATEWAY_ADMIN_USERNAME=admin
        #  - GATEWAY_ADMIN_PASSWORD_FILE=/run/secrets/gateway-admin-password
        - GATEWAY_ADMIN_PASSWORD=password
        - IGNITION_EDITION=standard
        - TZ=America/Vancouver  # see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
    ports:
      - "7088:8088"  # Map HTTP port
      - "7883:1883"  # Map MQTT port
    networks:
      iX_Sandbox:
        ipv4_address: 192.168.1.101
    volumes:
        - cloud-data:/usr/local/bin/ignition/data # Mounts the local folder 'cloud-data' to '/app/files' in the container
        - ./:/app  # Mounts the directory with your backup file
    command: >
# This line does not seem to work???
        -r /<your Gateway backup filename goes here>.gwbk  
        
volumes:
  cloud-data:
  edge-data:
  
networks:
  iX_Sandbox:
    driver: bridge
    ipam:
      config:
        - subnet: 192.168.1.0/24
  

So I seem to have made more progress with the docker-compose.yml file where I can get the MQTT Installed and the Gateway backup restored. However, I still have a "house keeping" issue with containers.

When I run this docker-compose.yml I seem to get one extra container instantiated for each of the two service (edge, cloud). Even though, I think I have explicitly prevented this from happening in the docker-compose.yml.

I see this in the docker.desktop for windows:

Once again, I may be showing my ignorance of how to properly compose things with docker. Any help would be appreciated.

# v0.1  Initial BETA iX Sandbox environment
# Compose Spec: https://github.com/compose-spec/compose-spec/blob/master/spec.md
---  
services:
    sandbox_edge:
        build:  # Build base Image
          context: .
          dockerfile: Dockerfile.edge
        image: sandbox_edge_image:latest
        entrypoint: ["echo", "This service is for building only"]  # Prevent it from running as a real container

 
    edge: # Instantiate container
        image: sandbox_edge_image:latest # Use the built base image
        container_name: iXSandBoxEdge
        ports:
          - "9088:8088"  # Map HTTP port
          - "9883:1883"  # Map MQTT port
        networks:
          iXSandbox:
            ipv4_address: 192.168.1.100
        volumes:
          - edge-data:/usr/local/bin/ignition/data # Mounts the local folder 'edge-data' to '/app/files' in the container
          - ./:/app  # Mounts the directory with your backup file
        environment:
          - ACCEPT_IGNITION_EULA=Y
          - GATEWAY_ADMIN_USERNAME=admin
        #  - GATEWAY_ADMIN_PASSWORD_FILE=/run/secrets/gateway-admin-password
          - GATEWAY_ADMIN_PASSWORD=Cogentind
          - IGNITION_EDITION=edge
          - TZ=America/Vancouver  # see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
        depends_on:
          - sandbox_edge # Ensures the base image is built first          
        command:  >
            -r /<your Gateway backup filename goes here>.gwbk  

    sandbox_cloud:
        build:
          context: .
          dockerfile: Dockerfile.cloud
        image: sandbox_cloud_image:latest  
        entrypoint: ["echo", "This service is for building only"]  # Prevent it from running as a real container  


    cloud:
        image: sandbox_cloud_image:latest  # Use the built base image
        container_name: iXSandBoxCloud
        ports:
          - "7088:8088"  # Map HTTP port
          - "7883:1883"  # Map MQTT port
        networks:
          iXSandbox:
            ipv4_address: 192.168.1.101
        volumes:
            - cloud-data:/usr/local/bin/ignition/data # Mounts the local folder 'cloud-data' to '/app/files' in the container
            - ./:/app  # Mounts the directory with your backup file
        environment:
            - ACCEPT_IGNITION_EULA=Y
            - GATEWAY_ADMIN_USERNAME=admin
            #  - GATEWAY_ADMIN_PASSWORD_FILE=/run/secrets/gateway-admin-password
            - GATEWAY_ADMIN_PASSWORD=Cogentind
            - IGNITION_EDITION=standard
            - TZ=America/Vancouver  # see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
        depends_on:
            - sandbox_cloud # Ensures the base image is built first      
        command: >
            -r /<your Gateway backup filename goes here>.gwbk           
volumes:
  cloud-data:
  edge-data:
  
networks:
  iXSandbox:
    driver: bridge
    ipam:
      config:
        - subnet: 192.168.1.0/24
  

For containers borne from Compose, you can inspect them to find out details about their origin from container labels, e.g.:

The only "state" that is tracked by Docker Compose is that which is available by inspecting labels of containers. This means it is very easy to orphan things; for example, changing service names in your compose YAML. I'm guessing that is probably what happened here. It looks like your docker-compose.yaml is probably under a very generically named folder called docker. If this lack of specificity is intentional (perhaps it is a folder under an existing repo), you can also set the Compose "project" name via the top-level name element; make sure to make these types of changes with your stack "down", again, to prevent orphaning existing containers (then requiring manual cleanup).

As to other interests you've mentioned, you might find some inspiration from these two repos I maintain:

Ok, I will use the GitHub 'iiot' package you have created and modify it according to fit our needs. One thing I did notice right away with using the files on Windows Docker, is that all the *.sh (shell script) files need to be opened and saved as (UNIX LF). Otherwise, you get strange errors that will lead you astray.

May want to mention this in the ReadMe potentially as it could take people some time to debug this issue?

Example error:

 => CACHED [gateway-edge1 prep 4/8] COPY --chmod=0755 retrieve-modules.sh .                                                                                      0.0s
 => ERROR [gateway prep 5/8] RUN ./retrieve-modules.sh     -m "mqttdistributor mqttengine"                                                                       2.3s
 => CACHED [gateway-edge1 prep 4/8] COPY --chmod=0755 retrieve-modules.sh .                                                                                      0.0s
 => ERROR [gateway-edge1 prep 5/8] RUN ./retrieve-modules.sh     -m "mqtttransmission"                                                                           2.3s
------
 > [gateway prep 5/8] RUN ./retrieve-modules.sh     -m "mqttdistributor mqttengine":
0.351 /usr/bin/env: ‘bash\r’: No such file or directory
------
------
 > [gateway-edge1 prep 5/8] RUN ./retrieve-modules.sh     -m "mqtttransmission":
0.346 /usr/bin/env: ‘bash\r’: No such file or directory
------
failed to solve: process "/usr/bin/env -S bash -euo pipefail -O inherit_errexit -c ./retrieve-modules.sh     -m \"${SUPPLEMENTAL_MODULES:-}\"" did not complete successfully: exit code: 127

Ahhh, yes, good catch. I've put in .gitattributes files like over here before to ensure proper behavior (i.e. don't change shell scripts to CRLF on Windows). I'll update that for the future. Thanks!

1 Like

Also, noticed that the Github 'iiot' package changing the password in the iiot\secrets\gateway-admin-password folder does not seem to take even with the
build with --no-cache to force a rebuild. I changed the gw-init/gateway.env file too as per ReadMe. I also tried setting it directly and that didn't seem to take either:

  args:
    IGNITION_VERSION: ${IGNITION_VERSION:-latest}
    SUPPLEMENTAL_MODULES: "mqttdistributor mqttengine"
    BASE_GWBK_NAME: yourGateway.gwbk
    GATEWAY_ADMIN_USERNAME: admin
    GATEWAY_ADMIN_PASSWORD: yourpassword

In addition, replacing the BASE_GWBK_NAME: arg with a different gateway backup does not seem to load. (assuming the iiot\gw-build is where you need to store the GW backup).

Is there a trick I am over looking here to change the password and load a gateway backup?