Volume dependent file install - Ignition 8.3, MQTT Transmission/Engine, Third Party Modules

I am currently working on a project that spins up several Inductive Automation Ignition 8.3.6 containers and makes use of the third party MQTT Transmission and MQTT Engine modules.

In previous version of Ignition the modules would be installed in /usr-lib but in 8.3 they are installed in */ignition/data/var/ignition/modl

I need to mount the volume to
/usr/local/bin/ignition/data

and the module need to be installed in
/usr/local/bin/ignition/data/var/ignition/modl/MQTTmodule.modl

Bellow is a screenshot of the /var/ignition directory.

When using a bind mount

- type: bind
        source: ./gw-build/MQTT-Transmission-signed.modl
        target: ${IGN_DATA}/var/ignition/modl/MQTT-Transmission-signed

the file mount as a directory and obfuscates the volume directories in Red but provides the path in Yellow. This leads to Ignition recognizing that a module is installed when hitting the Ignition gateway webpage and prompts me if i would like to use this module. It then fails to load the gateway web UI as those directories in red are require for the normal operation of Ignition.

Many Ignition forms and solution for this include running a docker build like this:

ARG IGNITION_VERSION 
ARG MODULE
FROM inductiveautomation/ignition:${IGNITION_VERSION}
ARG MODULE

# for Ignition 8.1
COPY MQTT-Transmission-signed.modl /usr/local/bin/ignition/user-lib/modules/
# for Ignition 8.3
COPY ./MQTT-${MODULE}-signed.modl /usr/local/bin/ignition/data/var/ignition/modl/

However, in Ignition 8.3 the modules are not installed in /user-lib, and when it tries to copy the file it fails because the volume is not mounted and the */ignition/data/ directory does not exist.

As mentioned above, I have tried using a single file mount but, the file is seen as a directory even though the file exists in the host machine and the other required directories are obfuscated. However, I have discovered that If I exclude the .modl extension then it is mounted as a file and does not obfuscate the requisite directory but then Ignition does not see it as a module file.

I need to build an image based on Ignition, include the module file in a directory that does not depend on the volume mount then connect the volume mounted directory to the image stored file.

One thought was to symlink the file after the volume is mounted but it does not seem like you can create a symlink inside of docker compose.

How can I build an image that is not dependent on a volume but then gives a volume directory access to an image file?
OR
Can anyone tell me why the Ignition .modl extension is causing the binding error that obfuscates the /var/ingition/ directory to only have the /var/ignition/modl/ directory?

That folder structure is really strange to me, unusual on Linux, but I see it is mentioned in the documentation. Just in case someone else also finds it strange:

File extensions should not matter as long as your path is correct. And I’m not sure what volumes you mean. I see no volume definition in the image:

Can you explain what that means? Do the files in the red fodlers change?

Also where did you create the screenshot? I assume it is on the host and not in a container through the file browser of Docker Desktop.

If that is on the host, that probably means there is indeed another bind mount and you mount one folderover another. What you see on the host is not always what you have in the container. When you do something like this:

volumes:
  - type: bind
    source: ./hostpath/a
    target: /path/a
  - type: bind
    source: ./hostpath/b
    target: /path/a/b

If the sourcs are folders, then Docker needs to create a folder named “b” under ./hostpath/a/, because the source path has to exists before you bind mount something else onto it.

If for example ./hostpath/b is a file, tthen Docker needs to create a file at ./hostpath/a/b. But you will see the right folders and files when you check it inside the container.

You can always pre-create the required files/folders in the image before running the COPY instruction, but the COPY instruction also creates that automatically. I assume you mean the problem would be that then you want to mount a folder from the host into the container and that overrides the file you copied into the image. If that is the case, you need to decide wheter you copy files or use a bind mount.

Alternatively, you can also give a custom path to an actual local volume which has “type: volume”.

For example (I copied it from one of my blogposts)

volumes:
  docroot:
    driver: local
    driver_opts:
      type: none
      device: ./docroot
      o: bind

services:
  httpd:
    image: httpd:2.4
    volumes:
      - type: volume
        source: docroot
        target: /usr/local/apache2/htdocs

Then you can use an image with files copied into it and still have a local folder populated with the data in the container. Then you can have problems with permissions it is not always a good idea if you also want to edit files outside the container