RTE images

The three published RTE images, and an RTE of your own with the collections and libraries your playbooks use

  1. The RTE images
  2. Build your own RTE
  3. The contract

The RTE images

The RTE is published in three layers, each built on the one before, with the same tags as the app (see Image tags):

Image What is in it Use it
ghcr.io/ansibleforms/ansibleforms-rte-base Node.js and the AnsibleForms server, git, ssh and sshpass. No python and no ansible, so it runs no playbook by itself To build an RTE with your own python and ansible versions
ghcr.io/ansibleforms/ansibleforms-rte-core The base, plus python 3.14, ansible-core and a few common libraries (jmespath, netaddr, requests, paramiko). No collections To build a smaller RTE with only the collections and libraries your playbooks use
ghcr.io/ansibleforms/ansibleforms-rte-full The core, plus the ansible package on the same ansible-core, and what the AnsibleForms 6.5 image had: the NetApp, AWS and community collections, pandas, pyvmomi, boto3, the mariadb client, ytt and a few os tools The default. Run it as it is: playbooks from 6.5 find what they used

Like the app image, every layer runs as the user node (uid 1000), and the playbooks run as that user too.


Build your own RTE

Build on ansibleforms-rte-core and add the collections and python libraries your playbooks use. This NetApp example is one of the Dockerfiles in examples/rte:

FROM ghcr.io/ansibleforms/ansibleforms-rte-core:7
RUN ansible-galaxy collection install netapp.ontap -p /usr/share/ansible/collections \
 && pip install --no-cache-dir netapp-lib netapp-ontap

The python environment and the collections folder belong to node, so these installs need no root. A layer that installs os packages switches to USER root for them and back to USER node at the end. To bring your own python and ansible, build on ansibleforms-rte-base (Dockerfile.own-ansible in the same folder).

Keep the image on the app’s release: :7 follows the app’s :7. Collections and roles can also be mounted instead of baked in, at /etc/ansible/collections and /etc/ansible/roles. Then no rebuild is needed per change, but what runs depends on that volume; python libraries always go into the image. Baking everything in is reproducible and starts fast, which makes it the way for production.


The contract

What the app and an RTE must share is their contract, a number both report. An RTE of an older release keeps working with a newer app as long as both speak the same contract; when a release changes it, its release notes say that RTEs must be updated. Each mode has its own:

Mode Contract On a mismatch
Outbound, Inbound 3, new in 7.3.0 The app closes the RTE’s socket with the code 4409 and logs RTE ‘<name>’ speaks contract <n>, this app (<release>) contract 3: refused. An outbound RTE logs the app speaks another contract (an upgrade in progress?): dialing again in 60 seconds. A job sent with another contract is refused
Database (deprecated) 2, since 7.0.0 The RTE refuses the app’s jobs

Test connection on the runner says which contract the RTE speaks and which one the app needs (see Test connection), and the Runners row of the Status page runs the same check.