Using Docker with the Akana Platform

Provides information about using Docker with the Akana Platform.

Valid in Version: 2020.2.0 and later

Table of Contents

Overview and Reference Information

Configuring and Customizing Akana within Docker

Appendix

Overview and Reference Information

Why Docker?

Akana promotes deployments utilizing Docker technology to enable rapid standup of an environments that utilize resources efficiently and integrate seamlessly into popular cloud infrastructure and management tools. Akana publishes a set of base images that can support several deployment types out of the box while allowing layers to be built upon them for customized deployments.

Deploying Akana with Docker makes some tasks much easier to automate. It can also simplify getting started because most of the environment needed to run the application is packaged together in the Docker container. For more information on how using containers can help with your organization's processes, see Why Develop with Docker (external link).

Available Docker Images

Published images correlate with common deployment segmentation of functionality. Most features can easily be combined or separated further as needed. The following Docker images are available:

  • API Gateway
  • Community Manager (Portal)
  • OAuth
  • Policy Manager
  • Envision
  • Lifecycle Manager

Security by Default

Our images are built with security enabled by default when possible. It is important to maintain these security features if customizing images for your organization.

  • Common hardening configurations are enabled by default. See Akana Platform Hardening Guide.
  • Industry best practices for Docker image hardening.
  • The Akana Administration Console is deployed on a separate port (9901). This allows network rules to block access to the Akana Administration Console.
  • TLS is enabled by default on standard port 9900 with external keystore feature installed by default. For more information, see Using the External Keystore Feature.

Inspecting Images

Our containers include metadata that define useful details about how the container runs and what you should consider configuring via environment variables and file volume mounts. You can easily inspect this information from the command line with the command shown below.

Code example: Inspect Akana Docker container

$> docker inspect {repository}/portal:<version>
[
  {
    "Id": "sha256:6d9d8e6....",
    "RepoTags": [
      "localhost/akana/docker/portal:2020.2.0.0"
    ],
...
"Env": [
        "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
        "CONTAINER_NAME=portal",
        "CONTAINER_KEY=portal",
        "CONTAINER_KEYSTORE_LOCATION=file:///opt/akana/etc/keystore",
        "CONTAINER_KEYSTORE_PASSWORD=",
        "CONTAINER_KEYSTORE_TYPE=jks",
        "CONTAINER_KEYSTORE_PROVIDER="
      ]
...
"Volumes": {
        "/opt/akana/etc/keystore": {},
        "/var/log/akana": {}
      },

It's a good idea to review this output. The above segment shows an example of the "Env" and "Volumes" sections. These sections are important, as well as the "Entrypoint" and "Healthcheck" sections, depending on your use cases. For example, the "Env" section provides information about configurations that you can set at container start time to change Akana behavior. Additionally, there might be some labels that will provide useful metadata about the image, such as when it was built. It is wise to inspect the images that you're using, because they will have the most up-to-date information about that image.

Getting Started

Docker is freely available, making it easy to get started anywhere it can run. These steps will set up a local Community Manager and API Gateway, to help you get familiar with running Akana with Docker as well as with basic concepts for proxying services.

There are three basic steps:

  1. Get your system environment ready
  2. Define and run your Akana test deployment
  3. Create your first proxied API

Get your system environment ready

  1. Install the Docker engine: see https://docs.docker.com/get-docker/.
  2. Obtain access to the Akana Docker registry or image downloads. For instructions, see To download the Docker images below.
    1. Load images from file using:
      docker load -i {path-to-download}
    2. Pull images from repository using:
      docker pull {repo}/{image-name}:{version-tag}
  3. Install Docker Compose: see https://docs.docker.com/compose/install/.
  4. Make sure that your current user has id 1000, or create a user with this id and give permissions to your working directory; for example, ./akana. We make use of Docker volumes to unburden the filesystem driver as well as separate the non-ephemeral data from the ephemeral container. This comes with the need to link the base operating system's access control with the Docker container's access control. When you use a common user identifier in both Linux operating systems, they look like the same user, and the Docker container can therefore access the files.

To download the Docker images

  1. Log in to the Support Center (https://library.roguewave.com).

    Note: If you don't have login credentials for the site, contact technical support to get access.

  2. Go to Product Downloads > Akana - Product Downloads > Akana 2020.2.x Product Downloads.
  3. Download the applicable version of the Docker ZIP file.

Define and run your Akana test deployment

  1. Define your environment in a local file: ./akana/.env.

    Code example: Basic Akana Configuration

    COMPOSE_PROJECT_NAME=akana-docker
    # Docker images to use
    AKANA_VERSION=2020.2.0
    AKANA_IMAGE_HOST=localhost
    # If you have a local cache for Docker images to avoid rate limit of Docker hub.
    THIRDPARTY_IMAGE_REGISTRY=
    # Host Config, where you are running docker compose. Use Public IP, or DNS name to autoconfigure TLS.
    HOST=localhost
    # Akana Administration Console User
    CONTAINER_ADMIN_NEW=admin
    CONTAINER_ADMIN_PASSWORD_NEW=Passw0rd!
    # Policy Manager Admin User
    PM_ADMIN=admin
    PM_PASSWORD=Passw0rd!
    #
    # Community Manager Tenant
    #
    TENANT_EMAIL=administrator@localhost
    TENANT_PASSWORD=Passw0rd!
    TENANT_THEME=hermosa
    TENANT_THEME_IMPL=hermosa
    TENANT_ID=t1
    TENANT_NAME=t1
    TENANT_HOST=localhost
    TENANT_CONSOLE_HOST=localhost
    TENANT_VHOSTS=localhost
  2. Use this sample compose script for a simple local deployment to define your Akana containers, and save it to a local file named ./akana/docker-compose.yml version: '3.8'.
  3. From the command line in the ./akana directory, run:
    docker-compose -d up
  4. In your browser, verify that Community Manager is running and you can log in using the credentials defined in your ./akana/.env file:
    https://localhost:9901/atmosphere

Create your first proxied API

Review how to create an API. See Adding an API.

Localhost Services: If you are proxying a service running on the same host, take notice of how Docker networking will affect your configuration. You will find that the common hostname (localhost) and loopback address (127.0.0.1) will not reference your service. This is because, within the context of the Akana Docker images, your service does not exist at the network's loopback address. Instead, you must use the external IP address for your host to allow the network traffic from Akana out of the Docker network and back to the host machine.

As a workaround, you can also use the DNS name host.docker.internal, which resolves to the internal IP address used by the host, to access services on the Docker host machine. For instructions, see https://docs.docker.com/docker-for-mac/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host.

SSH Tunneling: If you have firewall security, you can use SSH tunneling to circumvent the firewall.

Configuring and Customizing Akana within Docker

Configuration Overview

As you start getting deeper into your deployment plan, you'll want to understand the Akana configuration core concepts and automation framework.

Resources:

Configuring Akana Docker Images

Some common configurations can be done via Environment variables at the creation time of the container. More complex configuration can be done via recipes at the command line, or via the the Akana Administration Console, the browser-based user interface (UI). Recipes are recommended, to provide a consistent deployment experience. See Automation Reference Guide.

Rapid Startup Configuration

The fastest path to getting containers started is to use the Rapid Startup Environment Variable configuration to define everything that Akana needs to function. This way, as soon as you run the image, the container is ready to go. You can easily see what can be configured by these rapid startup configuration environment variables by inspecting the docker image. The 'docker inspect <image>' command outputs metadata about the image including pre-defined environment variables that Akana will observe at startup.

Container Identity and External Keystore

Each Akana container must have a unique identity and should use a unique key pair. Akana images define environment variables and a volume for the keystore file that should be defined during container creation that will give the Akana instance an identity and trust with other Akana instances in the deployment.

Notes:

  • Whether you're using JCEKS/PKCS12 or an HSM as a keystore, make sure you have keys defined for each container. See Simple external PKI setup for Akana.
  • Use the volume /opt/akana/etc/keystore to mount your keystore file (you can override the location using environment variable CONTAINER_KEYSTORE_LOCATION if necessary).
  • Specify the password to access the keystore CONATINER_KEYSTORE_PASSWORD as well as your container's CONTAINER_NAME and CONTAINER_ID as environment variables.
  • Run the container-identity-task.json recipe to select the key to be used for this container via its alias in the keystore (or HSM).

Specifying rapid startup configuration in Akana Docker container creation

$} docker run -d --name gateway \
  -p 9900:9900 \
  -e CONTAINER_NAME=gw1 \
  -e CONTAINER_ID=gw1 \
  -e CONTAINER_KEYSTORE_PASSWORD=changeit \
  -v ./<keystore-file>:/opt/akana/etc/keystore \
  {registry}/gateway:{version}
$} docker exec -w /opt/akana/bin \
  gateway \
  CONTAINER_IDENTITY_ACTION=assign.alias \
  CONTAINERALIAS=gateway-key \
  CONTAINERALIASPASSWORD=changeit \
  ./jython.sh -m akana.container --props container.properties --recipe ../recipes/tasks/container-identity-task.json

You can verify your changes by logging into the Akana Administration Console web UI and launching the Manage PKI task from the Configuration Tab. You should see your certificate details in the popup.

Recipe Configuration

In some cases it is not possible to use Rapid Startup Configuration exclusively, due to the type or complexity of a configuration. In these cases we recommend using the standard Akana automation framework. See Automation Reference Guide.

  • Akana Docker Containers come with a 'container.properties' file in the /opt/akana/bin folder that can be used for recipe execution.
  • As with other deployment models, there are useful recipes pre-defined in the /opt/akana/recipes folder.
  • You must set the working directory to /opt/akana/bin to run the jython scripts.

Running a recipe on an Akana Docker container

$> docker exec -w /opt/akana/bin <docker-container-name-or-id> ./jython.sh -m akana.container --props container.properties --recipe ../recipes/<name-of-recipe>.json

This method can be used to install a RDBMS driver on the fly using the db-driver.json recipe.

Persisting Container Configuration

Once you've configured your image ad hoc, you can persist that to a new image to allow you to redeploy without running all the configuration again. If you are looking to create pre-configured images, you may benefit more from reading Customizing Akana Docker Images.

$> docker container commit -m "What you changed" {container-id} {repo}/{new-image-name}:{version-tag}

Customizing Akana Docker Images

Often times the base images will need to be customized to meet your exact needs, especially in production. This can be to install addon features, remove unnecessary plugins, add your own agents, or to bake in your organization's/environment's configurations. Docker makes it easy to build upon existing images and there are a plethora of tools available to integrate a DevOps CI/CD pipeline to rapidly deliver your customized application based on Akana.

General Steps

  1. (Recommended) Set up version control (VCS) and a build tool project to consistently build your target image.
  2. Define a new multi-stage Dockerfile. See https://docs.docker.com/develop/develop-images/multistage-build/.
    1. FROM Akana image as stage1-image
    2. COPY any files needed to customize the image
    3. RUN any automation recipes (see Automation Examples)
    4. RUN any cleanup of unnecessary files after install
    5. FROM your base image
    6. COPY --from=stage1-image /opt/akana/ /opt/akana/
    7. Redefine any ENV, VOLUME, EXPOSE, and/or ENTRYPOINT properties.
  3. Automate the 'docker build' and 'docker push' commands to integrate the new image in your pipeline.

Example: Modifying Installed Features

Akana container images come with the most common features installed, but many are omitted to keep the size small and reduce the threat surface for most customers. You may need to add or remove features or individual OSGi bundles to meet your organization's individual needs. For example, most customers will need to install a proprietary database driver to be able to connect to their RDBMS. You can customize the Akana Docker Images to "bake" this into your organization's images.

Dockerfile : Adding JDBC Driver

FROM {repo}/portal:{version} AS build-instance
 
# Recopy recipes incase they've changed and we're doing an expidited build of just one image, without rebuilding the akana-base image
COPY ./my-jdbc-driver.jar /opt/akana/lib
WORKDIR /opt/akana/bin
# Start the Akana container instance
RUN CONTAINER_NAME=akana ./docker-start.sh akana -bg
# Install your JDBC Driver
RUN DB_DRIVER_LOCATION=file:///opt/akana/lib/my-jdbc-driver.jar \
    ./jython.sh -Dorg.slf4j.simplelogger.logFile=System.out \
    -Dorg.slf4j.simpleLogger.defaultLogLevel=info \
    -m akana.container \
    --recipe ../recipes/db-driver.json \
    --props container.properties \
    --name akana \
    --key akana \
    --home /opt/akana
 
# Clean up filesystem so downstream image is smaller
RUN rm /opt/akana/my-jdbc-driver.jar
 
#
# Step 2:
# - Use your organization's Docker base image, make sure JDK 1.8 is installed
FROM {repo}/{my-orgs-base-image}:latest
 
# Define environment variables so they can be seen by `Docker inspect {image}`
ENV CONTAINER_NAME=
ENV CONTAINER_KEY=
ENV CONTAINER_KEYSTORE_LOCATION=file:///opt/akana/etc/keystore
ENV CONTAINER_KEYSTORE_PASSWORD=
ENV CONTAINER_KEYSTORE_TYPE=jks
ENV CONTAINER_KEYSTORE_PROVIDER=
 
COPY --from=build-instance /opt/akana/ /opt/akana/
# Do some security hardening
RUN adduser -D -u 1001 akana && \
    chown akana:akana -R /opt/akana && \
    find / -perm +6000 -type f -exec chmod a-s {} \;
USER akana
 
HEALTHCHECK CMD bash /opt/akana/bin/admin-healthcheck.sh
 
# Redefine volumes
VOLUME /opt/akana/etc/keystore
VOLUME /var/log/akana
 
# Redefine ports
EXPOSE 9900
EXPOSE 9901
 
# Redefine entrypoint
ENTRYPOINT ["/bin/bash", "/opt/akana/bin/akana-entrypoint.sh", "akana"]

You can expand upon a multi-stage Docker build like this to modify just about anything, including:

  • Adding or modifying Linux monitoring tools
  • Adding third-party agent software
  • Running any customization recipe (see security note below)

Container Security Scanning: When adding open source software, it is recommended to use a component scanning tool to identify known vulnerabilities. You can then make an educated risk assessment and upgrade as appropriate.

Appendix

Simple external PKI setup for Akana

In general, a less secure deployment environment might use use software-based cryptography, such as JCEKS and PKCS12, and a more secure deployment environment might use HSM. You can leverage the external keystore feature in Akana by using the keytool command provided with the Java JDK. This setup can be replaced with a hardware security module (HSM) in the future, if needed, using the same configurations.

The example below uses software-based cryptography to illustrate configuring an external keystore. However, it's likely that a production environment would use an HSM rather than a keystore file.

The steps involved are:

  1. Create a private certificate authority (CA).
  2. Create keys for each of your Akana containers.
  3. Sign your container key's certificates with your private CA.
  4. (Optional) Install your private CA's public certificate's into your operating system's truststore.

Below is a script that performs steps 1-3 as an example. Just run the following:

./gen-pki.sh <hostname> <keystorePassword>

Generate private PKI

#!/bin/bash
 
# Clean
rm *.pem
rm *.jks
rm *.jceks
 
PWD=$2
 
# Create personal Certificate Authority
keytool -genkeypair -keystore root.jks -alias root -keyalg rsa -keysize 8192 -validity 1825 -storepass $PWD -keypass $PWD -dname "CN=Akana Root,OU=Akana,O=Perforce,L=Minneapolis,ST=Minnesota,C=US" -ext bc:c
keytool -genkeypair -keystore ca.jks -alias ca -keyalg rsa -keysize 4096 -storepass $PWD -keypass $PWD -dname "CN=Akana CA,OU=Akana,O=Perforce,L=Minneapolis,ST=Minnesota,C=US" -ext bc:c
 
keytool -keystore root.jks -alias root -storepass $PWD -keypass $PWD -exportcert -rfc > root.pem
keytool -storepass $PWD -keypass $PWD -keystore ca.jks -certreq -alias ca | keytool -storepass $PWD -keypass $PWD -keystore root.jks -gencert -validity 1825 -alias root -ext BC=0 -rfc > ca.pem
cat root.pem > cachain.pem
cat ca.pem >> cachain.pem
keytool -noprompt -importcert -keystore ca.jks -trustcacerts -storepass $PWD -keypass $PWD -file root.pem
keytool -noprompt -keystore ca.jks -storepass $PWD -keypass $PWD -importcert -alias ca -file cachain.pem
 
# Create Application Certificates Keystores
for containerName in "portal" "gateway" "policy-manager" "oauth" "envision" "lifecycle-manager"
do
    keytool -noprompt -importcert -trustcacerts -keystore $containerName.jceks -storetype jceks -storepass $PWD -alias "Akana Root" -file root.pem
    keytool -noprompt -importcert -trustcacerts -keystore $containerName.jceks -storetype jceks -storepass $PWD -alias "Akana CA" -file ca.pem
    keytool -genkeypair -keyalg rsa -keysize 2048 -keystore $containerName.jceks -storetype jceks -storepass $PWD -keypass $PWD -alias $containerName -dname "CN=$containerName,OU=Akana,O=Perforce,L=Minneapolis,ST=Minnesota,C=US"
    # Build Subject Alternative Names extensions
    SAN="dns:$containerName,dns:localhost,ip:127.0.0.1"
    if [[ "$1" != "" ]] ; then
        SAN="$SAN,dns:$1,dns:$containerName.$1"
    fi
    keytool -storepass $PWD -keypass $PWD -keystore $containerName.jceks -storetype jceks -certreq -alias $containerName | keytool -storepass $PWD -keypass $PWD -keystore ca.jks -gencert -validity 365 -alias ca -ext ku:c=dig,keyEncipherment -ext eku=serverAuth -ext san=$SAN -rfc > $containerName.pem
    cat root.pem ca.pem $containerName.pem > ${containerName}chain.pem
    keytool -noprompt -keystore $containerName.jceks -storetype jceks -storepass $PWD -keypass $PWD -importcert -alias $containerName -file ${containerName}chain.pem
done