Blog Post Running Universal Agents in Docker Containers

In this article we examine a sample dockerfile, entrypoint script, and the docker build and run commands needed to implement and use the image.


Stonebranch enjoys a full integration with Docker, meaning that Stonebranch and Docker products and solutions work seamlessly together. Below is an example use case for running the Stonebranch Universal Agent within a Docker container.

To operate successfully within a Docker container, there are several considerations to bear in mind when designing and implementing a Universal Agent Docker image. In this article, we examine a sample dockerfile, entrypoint script, and the docker build and run commands needed to implement and use the image.

Example Dockerfile and Entrypoint Script

Here is our example dockerfile:


#
# Dockerfile to build Universal Agent images
# - UA will run in console mode with any user
#
# Set the base image to redhat
FROM registry.access.redhat.com/ubi8/ubi
#
MAINTAINER "Colin Cocksedge "
#
# Install ua
ARG ua_version
ADD /install-files/sb-${ua_version}-linux-2.6-x86_64.tar.Z /tmp
RUN zcat /tmp/sb-${ua_version}-linux-2.6-x86_64.tar.Z | tar xvf - && \
sed -ri 's/\$UNV_DIR\/ubroker\/ubrokerd restart.*/
# Do Not Start Ubroker During Install/g'
./unvinst  && \
./unvinst --network_provider oms --oms_servers 7878@localhost --opscli yes
 --python yes --oms_port 7878 && \
rm unvinst *.rpm *.tar upimerge.sh upimerge.log usrmode.inc
 /tmp/sb-${ua_version}-linux-2.6-x86_64.tar.Z
EXPOSE 7887 7878
#
# Set Permissions for Arbitrary ID Support
RUN sed -ri 's/security.*/security NONE/g' /etc/universal/uags.conf && \
    sed -ri 's/security.*/security NONE/g' /etc/universal/udms.conf && \
    sed -ri 's/security.*/security NONE/g' /etc/universal/ucmds.conf && \
    sed -ri 's/security.*/security NONE/g' /etc/universal/uctls.conf && \
    sed -ri 's/security.*/security NONE/g' /etc/universal/uems.conf && \
    chgrp -R 0 /etc/universal && \
    chmod -R g=u /etc/universal && \
    chgrp -R 0 /opt/universal && \
    chmod -R g=u /opt/universal && \
    chgrp -R 0 /var/opt/universal && \
    chmod -R g=u /var/opt/universal && \
    chmod g=u /etc/passwd
#
# Add entrypoint script and because it's from Windows remove CRLF
COPY ./ua_entrypoint /
#
# Set Default userid
USER 10010
#
# Entry Point 
ENTRYPOINT [ "./ua_entrypoint" ]

Let’s break this down:


FROM registry.access.redhat.com/ubi8/ubi

Set the base image. In this example we are using a RedHat linux image, but you can choose a different base image based upon you own preferences.


ARG ua_version

Accept a build argument to specify the Universal Agent version to be installed within the Docker image. Add the Universal Agent installation file to the Docker image.

Add the Universal Agent installation file to the Docker image.


ADD /install-files/sb-${ua_version}-linux-2.6-x86_64.tar.Z /tmp

RUN zcat /tmp/sb-${ua_version}-linux-2.6-x86_64.tar.Z | tar xvf - && \
sed -ri 's/\$UNV_DIR\/ubroker\/ubrokerd restart.*/
# Do Not Start Ubroker During Install/g' ./unvinst
&& \
./unvinst --network_provider oms --oms_servers 7878@localhost
 --opscli yes --python yes --oms_port
7878 && \
rm unvinst *.rpm *.tar upimerge.sh upimerge.log usrmode.inc /tmp/sb-${ua_version}
-linux-2.6-
x86_64.tar.Z

The following runs several commands concatenated together, this is because each invocation of the RUN command adds a layer to the image, this method helps to minimize the image size.

RUN zcat /tmp/sb-${ua_version}-linux-2.6-x86_64.tar.Z | tar xvf - && \
sed -ri 's/\$UNV_DIR\/ubroker\/ubrokerd restart.*/
# Do Not Start Ubroker During Install/g' ./unvinst
 && \ 
./unvinst --network_provider oms --oms_servers 7878@localhost
 --opscli yes --python yes --oms_port
 7878 && \ 
rm unvinst *.rpm *.tar upimerge.sh upimerge.log usrmode.inc
 /tmp/sb-${ua_version}-linux-2.6-
x86_64.tar.Z
  1. The zcat command extracts the Universal Agent installation package.
  2. The sed command updates the unvinst script to prevent the ubroker from being started during the install.
  3. Run the Universal Agent Install script. You should review which options suit your needs.
  4. Remove the temporary installation files.
EXPOSE 7887 7878

Expose the Universal Agent ports. This is mostly documentational as depending on your requirements as the container ports would typically be mapped to the host system via the --publish option of the docker run command.

In some container orchestration environments (e.g. OpenShift) the Docker container's runtime User ID will be set to an arbitrary value by the environment. In order to support running the Universal Agent as any user the following commands are required.

  1. Set the security option for the ubroker components to none. This means that these components will inherit the ubroker user to execute workload, i.e. no identity switching will be performed.
  2. Set the group ownership of the installation files to gid 0 and set the group permissions for the installation files to match the user permissions. Arbitrary users assigned at container run time will belong to gid 0. This allows any user to start the Universal Broker.
RUN sed -ri 's/security.*/security NONE/g' /etc/universal/uags.conf && \
   sed -ri 's/security.*/security NONE/g' /etc/universal/udms.conf && \
   sed -ri 's/security.*/security NONE/g' /etc/universal/ucmds.conf && \
   sed -ri 's/security.*/security NONE/g' /etc/universal/uctls.conf && \
   sed -ri 's/security.*/security NONE/g' /etc/universal/uems.conf && \
   chgrp -R 0 /etc/universal && \
   chmod -R g=u /etc/universal && \
   chgrp -R 0 /opt/universal && \
   chmod -R g=u /opt/universal && \
   chgrp -R 0 /var/opt/universal && \
   chmod -R g=u /var/opt/universal && \
   chmod g=u /etc/passwd

Set the default user for containers run from this image. In the event that a user is not assigned or specified via the docker run command, this prevents the container from running as uid 0.

USER 10010

When the container is run an entrypoint script is provided to override the Universal Agent configuration, start the Universal Agent, and ensure it terminates cleanly when the container is stopped.

  1. Add the entrypoint script to the container.
  2. Define the entrypoint
“ COPY ./ua_entrypoint /
ENTRYPOINT [ "./ua_entrypoint" ]

Here is our example entrypoint script:


#!/bin/bash
# Handle Docker Stop and Terminate Ubroker Cleanly
shutdown() {
    kill -TERM "$ubroker"
    wait "$ubroker"
    exit 0
}
# Recognize Terminaton
trap 'shutdown' SIGINT SIGTERM
# Support Arbitrary User IDs
if ! whoami &> /dev/null; then
  if [ -w /etc/passwd ]; then
    echo "${USER_NAME:-default}:x:$(id -u):0:${USER_NAME:-default}
 user:${HOME}:/sbin/nologin" >> /etc/passwd
  fi
fi
# Set netname
if [ ! -z "$UAG_NETNAME" ]; then
  sed -ri "s/^netname.*/netname $UAG_NETNAME/g" /etc/universal/uags.conf
else
  sed -ri "s/^netname.*/netname $HOSTNAME/g" /etc/universal/uags.conf
fi
# Set oms_servers
if [ ! -z "$UAG_OMS_SERVERS" ]; then
  sed -ri "s/^oms_servers.*/oms_servers $UAG_OMS_SERVERS/g"
 /etc/universal/uags.conf
fi
# Set Agent Clusters
if [ ! -z "$UAG_AGENT_CLUSTERS" ]; then
  sed -ri "s/^agent_clusters.*/agent_clusters
 \"$UAG_OMS_SERVERS\"/g" /etc/universal/uags.conf
fi
# Set enable_ssl
if [ ! -z "$UAG_ENABLE_SSL" ]; then
  grep -q '^enable_ssl' /etc/universal/uags.conf && sed
 -i 's/^enable_ssl.*/enable_ssl yes/' /etc/universal/uags.conf
 || echo 'enable_ssl yes' >> /etc/universal/uags.conf
fi
# Run OMS Server
if [ ! -z "$OMS_AUTOSTART" ]; then
  sed -ri "s/^auto_start.*/auto_start yes/g" /etc/universal/comp/oms
  sed -ri "s/^restart.*/restart yes/g" /etc/universal/comp/oms
fi
# Start the Agent
/opt/universal/ubroker/bin/ubroker &
ubroker=$! 
wait "$ubroker"

Again, let’s break this down: The docker stop command attempts to stop a running container first by sending a SIGTERM signal to the root process (PID 1) in the container. If the process hasn't exited within the timeout period a SIGKILL signal will be sent. The following code implements a function to forward the sigterm to the ubroker process to ensure it is terminated cleanly.

# Handle Docker Stop and Terminate Ubroker Cleanly
shutdown() {
    kill -TERM "$ubroker"
    wait "$ubroker"
    exit 0
}
# Recognize Terminaton
trap 'shutdown' SIGINT SIGTERM

During startup the Universal Broker performs a check to confirm that the userid starting the ubroker daemon exists in the /etc/passwd. In order to allow the ubroker to run with an arbitrary user id we need to dynamically add the user id to the /etc/passwd file.

# Support Arbitrary User IDs
if ! whoami &> /dev/null; then
if ! whoami &> /dev/null; then
  if [ -w /etc/passwd ]; then
    echo "${USER_NAME:-default}:x:$(id -u):0:${USER_NAME:-default}
 user:${HOME}:/sbin/nologin" >> /etc/passwd
  fi
fi

Configuration overrides to the container will be specified using environment variables specified via the docker run command. Alternatively, you can mount a preconfigured configuration from the docker hosts file system via the docker run --env option.

# Set netname
if [ ! -z "$UAG_NETNAME" ]; then
  sed -ri "s/^netname.*/netname $UAG_NETNAME/g"
 /etc/universal/uags.conf
else
  sed -ri "s/^netname.*/netname $HOSTNAME/g" /etc/universal/uags.conf
fi
# Set oms_servers
if [ ! -z "$UAG_OMS_SERVERS" ]; then
  sed -ri "s/^oms_servers.*/oms_servers $UAG_OMS_SERVERS/g"
 /etc/universal/uags.conf
fi
# Set Agent Clusters
if [ ! -z "$UAG_AGENT_CLUSTERS" ]; then
  sed -ri "s/^agent_clusters.*/agent_clusters \"$UAG_OMS_SERVERS\"/g" 
/etc/universal/uags.conf
fi
# Set enable_ssl
if [ ! -z "$UAG_ENABLE_SSL" ]; then
  grep -q '^enable_ssl' /etc/universal/uags.conf && sed 
-i 's/^enable_ssl.*/enable_ssl yes/'
 /etc/universal/uags.conf || echo 'enable_ssl yes' >>
 /etc/universal/uags.conf
fi
# Run OMS Server
if [ ! -z "$OMS_AUTOSTART" ]; then
  sed -ri "s/^auto_start.*/auto_start yes/g" /etc/universal/comp/oms
  sed -ri "s/^restart.*/restart yes/g" /etc/universal/comp/oms

In order to avoid writing log files and to make the logs (unv and uag) accessible to docker you should run the ubroker in console mode.

# Start the Agent
/opt/universal/ubroker/bin/ubroker &
ubroker=$! 
wait "$ubroker"

Building the Image

The following command can be used to build and tag the Universal Agent docker image. This command expects the example dockerfile and ua_entrypoint script to be in the current directory (notice the that the “.” at the end of the command denotes the build context as the current directory), it also expects the Universal Agent installation package to be in the “install-files” subdirectory. Replace the “v.r.m.m” with the Universal Agent version being used for the image.

docker build -t ua-redhat:v.r.m.m --build-arg ua_version=v.r.m.m .

Running the Image

Docker Environment Variables

When you create a Universal Agent container, you can configure the Universal Agent by specifying the following environment variables:

Environment Variable

Description

Example

UAG_NETNAME

Set the Agent ID to be used when the Universal Agent registers/connects to a Universal Controller Instance.

Default=OPSAUTOCONF
UAG_NETNAME=UADKR001
UAG_OMS_SERVERS

Specifies one or more OMS server addresses.

Default=7878@localhost
UAG_OMS_SERVERS=7878@omsserver1,7878@omsserver2
UAG_AGENT_CLUSTERS

The list of Universal Controller Agent Clusters to join automatically.

Default='Opswise Default Linux/Unix Cluster, Opswise - Default Windows Cluster'
UAG_AGENT_CLUSTER='Agent Cluster 1,Agent Cluster 2'
UAG_ENABLE_SSL

Specifies whether the SSL protocol is used for network communication between UAG and OMS.

Default = no
UAG_ENABLE_SSL=yes
OMS_AUTOSTART

Specifies whether the Universal Broker starts an OMS server.

Default = no
OMS_AUTOSTART=yes

Docker Container Ports

The following ports may need to be mapped when running containers from the Universal Agent image.

Port

Description

7887 Universal Broker listening port
7878 OMS Server listening port


Universal Agent Logs

The Universal Agent image configures the Universal Broker service to start in console mode, which writes all log data (unv.log and agent.log) to stdout. To view the log of a specific container, run the following command:

docker logs ua-redhat:v.r.m.m

Persisting Configuration Changes

Docker containers are ephemeral, and any data or configuration changes are expected to be lost if the container is deleted. One method to persist a custom configuration or apply a license key is to bind-mount a host directory using the --mount option when creating the container.

Docker Run Examples

The following command can be used run the Universal Agent docker image, mapping port 7887 to the docker host port 9987 and mounting a local UDM manager configuration file.

docker run --detach --publish 9987:7887 --mount type=bind,src=/path-on
-host-machine/udm.conf,dst=/etc/universal/udm.conf --name udm-manager ua
-redhat:v.r.m.m

The above is just one of many possibilities for integrating Docker and Stonebranch Universal Agent. To learn more about our partnership and Docker integration capabilities see our solution section.

Start Your Automation Initiative Now

Schedule a Live Demo with a Stonebranch Solution Expert

Further Reading

Read the blog: Automation Trends 2024: Top Takeaways from the Annual Global State of IT Automation Report

Automation Trends 2024: Top Takeaways from the Annual Global State of IT Automation Report

The results are in! IT Ops, DevOps, DataOps, CloudOps, PlatformOps, and ITSM pros worldwide share their thoughts on automation and orchestration in the 2024…

Header Card Analyst Report: 2022 Global State of IT Automation Report

Stonebranch 2024 Global State of IT Automation Report

The results are in! New research reveals 2024's IT automation and orchestration benchmarks for IT Ops, DevOps, CloudOps, and DataOps teams.

Read the blog post: 6 Top Trends in Infrastructure and Operations (I&O) for 2024

6 Top Trends in Infrastructure and Operations (I&O) for 2024

2024's top trends in infrastructure and operations (I&O), including genAI, IT orchestration, MLOps, and self-service automation.

Watch the webinar now! Orchestration, Observability, and Control Over the Hybrid Data Pipeline

Orchestration, Observability, and Control Over the Hybrid Data Pipeline

Hybrid data pipelines involve multiple schedulers and real-time data issues — see how an orchestration layer can enhance observability and control.