Running Service in Docker

Using the pre-built Service image

Note

Pre-built images are currently available for Cisco internal users only. We hope to be able to provide Docker images externally for download at some point in the future.

Pre-built RADKit Service Docker images for Linux x86_64 and aarch64 can be found in this repository, with the latest tag pointing to the latest stable external release. You need to be connected to the Cisco network in order to access the repository and pull images.

Warning

If you use these pre-built images, remember to replace radkit-service:latest with containers.cisco.com/radkit/radkit-service:latest in the docker run commands in the following sections.

Building your own Service image

Extracting the wheels

The sample Dockerfile below assumes that the RADKit wheels for the target platform have been extracted from the .tgz files found in the downloads area into a directory called wheels/ relative to the current directory; for instance (Python 3.11, x86_64, GNU libc):

$ mkdir -p wheels/
$ tar zxvf cisco_radkit_1.6.0_pip_linux.tgz -C wheels/ '*cp311-none-manylinux1_x86_64*'
x cisco_radkit_service-1.6.0-cp311-none-manylinux1_x86_64.whl
x cisco_radkit_genie-1.6.0-cp311-none-manylinux1_x86_64.whl
x cisco_radkit_common-1.6.0-cp311-none-manylinux1_x86_64.whl
x cisco_radkit_client-1.6.0-cp311-none-manylinux1_x86_64.whl
$ rm -f wheels/cisco_radkit_{client,genie}

Make sure to only include the wheels you need, in order to save space in the final image. Only cisco_radkit_service and cisco_radkit_common are required for RADKit Service.

Dockerfile

Here is a sample Dockerfile that can be used to build a RADKit Service container image. This example is based on the official Python image from Docker. It relies on a startup script, start.sh, that is shown below.

ARG PYTHON_VERSION=3.11
FROM docker.io/python:${PYTHON_VERSION}-slim
WORKDIR /
ENV RADKIT_DIRECTORY="/radkit"

COPY wheels/ wheels/
COPY start.sh start.sh

RUN apt update && apt upgrade -y && python3 -m pip install -U pip
RUN python3 -m pip install -f wheels/ cisco_radkit_service
RUN chmod +x start.sh
RUN mkdir ${RADKIT_DIRECTORY}

VOLUME ${RADKIT_DIRECTORY}
EXPOSE 8081

# This must be ENTRYPOINT, not CMD, so that there is proper signal handling. Also,
# ENTRYPOINT must be written in the "exec form" (JSON array), not the shell form.
ENTRYPOINT [ "/start.sh" ]

Note

On some platforms such as aarch64, some dependencies may have to be built from source. If that is the case for your target platform, use the following RUN command for pip install ... cisco_radkit_service instead of the one shown in the example above:

RUN apt install gcc -y \
    && python3 -m pip install -f wheels/ cisco_radkit_service \
    && apt remove gcc -y \
    && apt autoremove -y \
    && apt clean \
    && rm -rf /var/lib/apt/lists/*

Startup script

The start.sh script should be copied verbatim from this document:

#!/bin/bash
ARGS=""
RUN_ARGS=""
[ "${RADKIT_SERVICE_CLI_DEBUG}" == 1 ] && ARGS="${ARGS} --debug"
[ "${RADKIT_SERVICE_CLI_TRACE}" == 1 ] && ARGS="${ARGS} --trace"
[ "${RADKIT_SERVICE_CLI_TRACEBACKS}" == 1 ] && ARGS="${ARGS} --tracebacks"
[ -n "${RADKIT_SERVICE_CLI_DOMAIN}" ] && ARGS="${ARGS} --domain ${RADKIT_SERVICE_CLI_DOMAIN}"
[ -n "${RADKIT_SERVICE_CLI_SETTINGS_FILE}" ] && ARGS="${ARGS} --settings-file ${RADKIT_SERVICE_CLI_SETTINGS_FILE}"
[ "${RADKIT_SERVICE_CLI_NO_HEADLESS}" != 1 ] && RUN_ARGS="${RUN_ARGS} --headless"
[ "${RADKIT_SERVICE_CLI_RUN_FORCE}" == 1 ] && RUN_ARGS="${RUN_ARGS} --force"
exec radkit-service ${ARGS} run ${RUN_ARGS}

Build the image

To build the image:

$ docker build . -t radkit-service:latest

Things to know

Ports and volumes

When running in a container, the Service will listen on port 8081 internally and store all its data under /radkit. These can be remapped to a specific port and directory on the host machine as needed, using Docker’s -p / ports and -v / volumes parameters.

Warning

Make sure to mount RADKit’s data directory outside of your container, otherwise all data including certificates, database, logs … will be lost when the container is removed.

Bootstrapping

The Service container must first be bootstrapped, which requires the creation of a superadmin user, before it can be enrolled and have devices added to its database. Below are the most common ways to bootstrap and run the Service; if none of these work for your specific use case, please reach out to the RADKit development team.

Running behind a proxy

If you are running this container behind a proxy, you may have to pass additional environment variables to docker run using the -e option (see Proxy settings), for instance:

-e RADKIT_CLOUD_CLIENT_PROXY_URL=http://proxy.esl.cisco.com:80/

IPv6 support

Docker containers do not have IPv6 enabled by default. To configure an IPv6 network for your RADKit Service container, please refer to this article.

Docker run interactive

The first option to bootstrap and run RADKit Service in a container involves entering the superadmin password interactively at startup. First run the radkit-service bootstrap command in an interactive container (make sure to replace /tmp/radkit with your own local RADKit Service data directory):

$ docker run --rm -it --entrypoint radkit-service -v /tmp/radkit:/radkit \
    radkit-service:latest bootstrap

19:48:35.290Z INFO  | internal | RADKit Service [version='1.6.4']
Set up the superadmin user. You'll be asked to provide a superadmin password.
Keep this password securely stored, as it will be impossible to recover it!
Superadmin password (for new setup): *********
Confirm: *********
19:48:41.582Z INFO  | internal | Creating new database file. [path=PosixPath('/radkit/service/service-db.json.encrypted')]
...
19:48:41.664Z INFO  | internal | Creating administrator [admin_name='superadmin']
19:48:41.673Z INFO  | internal | Database closed. [path=PosixPath('/radkit/service/service-db.json.encrypted')]

Bootstrapping is complete. The next step is to enroll with the RADKit Certificate Authority.
You can now start the Service with 'radkit-service run' and log on to the WebUI as 'superadmin'.
Alternatively, you can enroll through the CLI (see documentation for details).

Once this is done, you can run the container normally (it starts radkit-service run by default) and enter the password interactively on startup:

$ docker run --rm -it -p 8081:8081 -e RADKIT_SERVICE_CLI_NO_HEADLESS=1 \
    -v /tmp/radkit:/radkit radkit-service:latest

19:50:35.030Z INFO  | internal | RADKit Service [version='1.6.4']
...
Superadmin password: *********   [correct]
19:50:38.067Z INFO  | internal | Opening database. [path=PosixPath('/radkit/service/service-db.json.encrypted')]
...
19:50:38.552Z INFO  | internal | Running on https://0.0.0.0:8081 (CTRL + C to quit)

Note the addition of -p 8081:8081 to allow access to the container’s WebUI and API from the host, as well as -e RADKIT_SERVICE_CLI_NO_HEADLESS=1 to allow for interactive password input.

Docker run non-interactive

If entering the superadmin password interactively is not an option, you can store it in an environment variable as described in Storing the superadmin password (note that this is not recommended; only do it if you understand the risks !)

In this case, as the password is readily available, the Service will automatically bootstrap itself and start up.

First store the password in an environment variable, for example (on Linux or macOS):

# !! Please do NOT copy-paste the 'MyPassW0rd!' example in your actual setup !!
% export RADKIT_SERVICE_SUPERADMIN_PASSWORD_BASE64=$( echo -n 'MyPassW0rd!' | base64 )

Then run the container:

  • without -it (non-interactive);

  • with -p 8081:8081 (to allow access to the container’s WebUI from the host);

  • with -e RADKIT_SERVICE_SUPERADMIN_PASSWORD_BASE64 (to publish the value of the environment variable into the container);

  • making sure to replace /tmp/radkit with your own local RADKit Service data directory.

% docker run --rm -p 8081:8081 -e RADKIT_SERVICE_SUPERADMIN_PASSWORD_BASE64 \
    -v /tmp/radkit:/radkit radkit-service:latest

20:00:27.399Z INFO  | internal | RADKit Service [version='1.6.4']
...
20:00:27.419Z WARNI | internal | Loading superadmin password from environment ($RADKIT_SERVICE_SUPERADMIN_PASSWORD_BASE64)
20:00:29.155Z INFO  | internal | Creating new database file. [path=PosixPath('/radkit/service/service-db.json.encrypted')]
...
20:00:29.772Z INFO  | internal | Running on https://0.0.0.0:8081 (CTRL + C to quit)

Note

The interactive and non-interactive methods described in this and the previous section can be combined, i.e. you can do an interactive bootstrap and then pass the superadmin password non-interactively, or do a non-interactive bootstrap then suppress the environment variable in later runs and provide the password interactively. You can also switch between the interactive and non-interactive way of running the Service as you see fit.

Docker Compose

To use Docker Compose to manage the Service, copy-paste the following YAML content into your docker-compose.yml:

services:
  radkit-service:
    container_name: radkit-service
    image: containers.cisco.com/radkit/radkit-service:latest
    environment:
    # Set variables here, or pass them with '-e', or don't pass them at all
    # Make sure you do NOT enclose the value in double quotes !
    - RADKIT_SERVICE_SUPERADMIN_PASSWORD_BASE64=...
    - RADKIT_CLOUD_CLIENT_PROXY_URL=...
    ports:
    # Set the host RADKit port here (syntax: "<host-port>:8081")
    - "8081:8081"
    volumes:
    # Set the host RADKit directory here, or pass RADKIT_DIRECTORY when calling Compose
    - "${RADKIT_DIRECTORY}:/radkit"
    # To get help on available CLI options, please use:
    #   docker compose run radkit-service bash -c "radkit-service --help"
    #   docker compose run radkit-service bash -c "radkit-service run --help"
    command: radkit-service run --headless

In this file, you can specify static parameters such as:

See the previous sections about docker run for an explanation of the different parameters.

Warning

Starting with RADKit 1.4, the --no-cli-app CLI argument to radkit-service run has been deprecated in favor of --headless with better support for headless mode. Please make sure you update your Compose file, as --no-cli-app will be removed in a future release.

Once the docker-compose.yml file is created and tuned according to your needs, start the container with docker compose up. The instructions for interactive and non-interactive bootstrap from the previous sections still apply; the difference is only in the way you run the container.

docker compose up
[+] Running 2/2
 ⠿ Network docker_default    Created                                                                                                                                                                                                                       0.0s
 ⠿ Container radkit-service  Created                                                                                                                                                                                                                       0.0s
Attaching to radkit-service
radkit-service  | 20:21:18.610Z INFO  | internal | RADKit Service [version='1.6.4']
...
radkit-service  | 20:21:18.635Z WARNI | internal | Loading superadmin password from environment ($RADKIT_SERVICE_SUPERADMIN_PASSWORD_BASE64)
...
radkit-service  | 20:21:19.134Z INFO  | internal | Running on https://0.0.0.0:8081 (CTRL + C to quit)

Passing CLI arguments through the environment

In very specific scenarios (such as CML integration) it may not be possible to provide any CLI arguments to the RADKit Service entry point when starting it. In such cases it is still possible to force a few select CLI options by way of an environment variable, thanks to the start.sh script:

  • RADKIT_SERVICE_CLI_DEBUG=1 for --debug

  • RADKIT_SERVICE_CLI_TRACE=1 for --trace

  • RADKIT_SERVICE_CLI_TRACEBACKS=1 for --tracebacks

  • RADKIT_SERVICE_CLI_DOMAIN=... for --domain ...

  • RADKIT_SERVICE_CLI_SETTINGS_FILE=... for --settings-file ...

  • RADKIT_SERVICE_CLI_NO_HEADLESS=1 to turn off run --headless

  • RADKIT_SERVICE_CLI_RUN_FORCE=1 for run --force (added in RADKit 1.6.0)