3 minute read

An air-gapped environment is a network physically isolated from unsecured networks. It means that when you install Digital.ai Release in such environment, Release does not have access to the internet.

Tip: see the official documentation on how to install Release on an Air-gapped Environment

Release does not need internet access to work. Without internet access, problems occur for container type plugins, based on docker images; they are by default configured to fetch images from docker.io.

Hopefully Digital.ai will provide soon a solution to configure these plugins using a custom registry URL. In the current Release version, version 23.3.4, the container type plugins cannot be used in an air-gapped environment without customization.

In this article I will show you a way to customize container type plugins so that you can use them in an air-gapped environment.
This is not without drawbacks: by using custom plugins, you’ll have to maintain the plugin definitions up to date with new versions and you’ll have to pull/push new images. This is a temporary solution until Digital.ai provides a way to manage custom image registry.

There are 3 steps:

  1. use a custom images registry
  2. pull the images from docker.io and push them in your local registry
  3. define new plugins based on your local registry images

Step 1: Custom registry

For this article, I’m going to use a simple local registry based on docker. Run the command:

docker run -d -p 5050:5000 --name registry registry

The command starts a local registry based on the registryimage. You can add an entry in your /etc/hosts file to refer to this local registry like:

127.0.0.1 container-registry

You can optionally install a UI for the registy. Run the command:

docker run -d \
  -p 8080:80 \
  -e REGISTRY_HOST=host.docker.internal \
  -e REGISTRY_PORT=5050 \
  -e REGISTRY_PROTOCOL=http \
  -e REGISTRY_ALLOW_DELETE=true \
  --name registry-ui \
  parabuzzle/craneoperator

You can access your local registry UI at http://container-registry:8080. It’s empty for now.

Step 2: Pull images

For the demo, I’m going to use the ‘Terraform Container’ plugin.

The definition of the plugin is available in the type-definition.xml file stored in the zip file of the plugin. Here is an extract:

<type type="containerTerraform.BaseTask" extends="xlrelease.ContainerTask" virtual="true">
  <property name="image" required="true" hidden="true" default="docker.io/xebialabs/release-terraform-integration:23.3.1" transient="true"/>
  <property name="iconLocation" default="release-terraform-integration.png" hidden="true"/>
  <property name="taskColor" hidden="true" default="#667385"/>
</type>

As we can see, the plugin uses the docker.io/xebialabs/release-terraform-integration:23.3.1 image from docker.io.

Let’s pull this image locally:

docker pull xebialabs/release-terraform-integration:23.3.1

Now let’s push this image in our registry. To do this we first need to add our registry’s location to the repository name. Run the command:

docker tag xebialabs/release-terraform-integration:23.3.1 container-registry:5050/mycompany/release-terraform-integration:23.3.1

Warning: Be aware that in a real scenario, the URL must be set with a DNS name, resolved by the k8s server running the Release Remote runner!

then push the image:

docker push container-registry:5050/mycompany/release-terraform-integration:23.3.1

Refresh the registry ui to confirm:

Step 3: Define a custom plugin

Add the definition of a new plugin in the ext/synthetic.xml file. The definition below is a coy of the default definition with a modified image property and custom labels (set as (MyCompany Registry) to differenciate from the default ones):

Warning: Like for the previous warning, the URL must be set with a DNS name, resolved by the k8s server running the Release Remote runner!

<type type="mycompanyContainerTerraform.BaseTask" extends="xlrelease.ContainerTask" virtual="true">
  <property name="iconLocation" default="release-terraform-integration.png" hidden="true"/>
  <property name="taskColor" hidden="true" default="#667385"/>
  <property name="image" required="true" hidden="true" default="container-registry:5050/mycompany/release-terraform-integration:23.3.1" transient="true"/>
</type>

<type type="mycompanyContainerTerraform.Apply" extends="mycompanyContainerTerraform.BaseTask" label="Terraform: Apply (MyCompany Registry)"  description="The task is to execute terraform module for the apply command">
  <property category="input" name="terraformClientVersion" readonly="true" required="false" kind="string" default="1.5.0" description="The installed terraform client version"/>
  <property category="input" name="gitUrl" label="Git URL" kind="string" description="Git repository URL"/>
  <property category="input" name="branch" required="false" kind="string" description="Git branch"/>
  <property category="input" name="gitDirPath" required="false" kind="string" label="Git directory path"/>
  <property category="input" name="gitToken" required="false" kind="string" password="true" description="Personal token for connecting to git"/>
  <property name="environmentVariables" category="input" required="false" size="large" password="true" label="Environment Variables"  description="Pass terraform environment variables the following format: {'VAR1': 'value1', 'VAR2': 'value2'}"/>
  <property name="outputVariables" category="output" kind="map_string_string" description="Return variable and values for a Terraform module"/>
</type>

<type type="mycompanyContainerTerraform.Destroy" extends="mycompanyContainerTerraform.BaseTask" label="Terraform: Destroy (MyCompany Registry)"  description="The task is to execute terraform module for the destroy command">
  <property category="input" name="terraformClientVersion" readonly="true" required="false" kind="string" default="1.5.0" description="The installed terraform client version"/>
  <property category="input" name="gitUrl" label="Git URL" kind="string" description="Git repository URL"/>
  <property category="input" name="branch" required="false" kind="string" description="Git branch"/>
  <property category="input" name="gitDirPath" required="false" kind="string" label="Git directory path"/>
  <property category="input" name="gitToken" required="false" kind="string" password="true" description="Personal token for connecting to git"/>
  <property name="environmentVariables" category="input" size="large" required="false" password="true" label="Environment Variables"  description="Pass terraform environment variables the following format: {'VAR1': 'value1', 'VAR2': 'value2'}"/>
</type>

Restart your Release instance after modifying the synthetic.xml file. You should now have new tasks using the new image stored in your images registry.