Skip to content

Docker Deployment

The RIC, the E2 emulator, the SDK base, and every xApp ship as Docker images built by a single script. A Docker Compose stack brings up a complete demo topology.

Building images

From the project root:

./build_docker.sh              # build everything: RIC + SDK base + emulator + all xApps
./build_docker.sh ric          # RIC server only            → airpuls-ric:latest
./build_docker.sh emulator     # E2 node emulator only       → airpuls-e2-emulator:latest
./build_docker.sh base         # xApp SDK base only          → airpuls-xapp-sdk:latest (+ airpuls/airpuls-xapp-sdk:latest)
./build_docker.sh kpm-monitor  # all languages of one xApp
./build_docker.sh kpm-monitor:go   # one xApp / language combo

xApp images are tagged <name>-<lang>:latest (e.g. kpm-monitor-python:latest). See SDK → Packaging for how xApp images are structured.

Running the RIC server alone

A licence is required

The RIC refuses to start without a valid licence for the deployment, so the commands below need one mounted. See Licensing for how to obtain it; a deployment managed by nrtric-ctrl already has one at conf/license.key, bound to the CA in conf/ric-tls/ca.crt.

docker run --rm \
  -v $(pwd)/conf/license.key:/etc/airpuls/license.key:ro \
  -v $(pwd)/conf/ric-tls/ca.crt:/etc/airpuls/tls/ca.crt:ro \
  -p 36421:36421/sctp \
  -p 36422:36422 \
  -p 9095:9095 \
  airpuls-ric:latest

The baked configuration reads the licence from /etc/airpuls/license.key and identifies the deployment by the certificate at /etc/airpuls/tls/ca.crt, so both mounts are needed. Without them the container exits reporting which one is missing.

Override the baked config by mounting your own:

docker run --rm \
  -v $(pwd)/nrtric.yml:/etc/airpuls/nrtric.yml:ro \
  -p 36421:36421/sctp -p 36422:36422 -p 9095:9095 \
  airpuls-ric:latest

Environment variables

The entrypoint (docker-entrypoint.sh) substitutes a small set of env vars into the baked nrtric.yml before exec'ing the server — the least-invasive way to adjust a container without a config mount:

Variable Values Default Meaning
RIC_BIND_ADDR IPv4 literal auto-detect SCTP bind address. Explicit is mandatory for --network host
RIC_BIND_INTERFACE interface name eth0 Interface to auto-discover the first IPv4 on, when RIC_BIND_ADDR is unset

Don't bind SCTP to 0.0.0.0 in a container

SCTP is multihomed — binding to 0.0.0.0 inside a container advertises every bridge IP to the peer, and if the peer picks an unreachable one the association drops silently. The entrypoint auto-discovers the container's eth0 IP by default; set RIC_BIND_ADDR explicitly for --network host:

docker run --network host -e RIC_BIND_ADDR=<host external IP> airpuls-ric:latest

Full-stack Compose demo

docker/compose/docker-compose.yml brings up the RIC together with an E2 emulator and a KPM monitor on a private bridge:

cd docker/compose
docker compose up -d
Service Image Role
airpuls-ric airpuls-ric:latest Near-RT RIC server
emu-gnb airpuls-e2-emulator:latest E2 node emulator (SCTP peer)
kpm-monitor kpm-monitor:latest KPM monitoring xApp

Startup order is enforced by health checks: the RIC comes up first and waits until its metrics endpoint answers, the emulator then connects over SCTP, and the xApp connects over the northbound IPC and subscribes.

docker compose logs -f              # all services
docker compose logs -f kpm-monitor  # the xApp only
docker compose restart kpm-monitor  # after editing docker/compose/xapp.yml
docker compose down                 # teardown

Build the emulator image

The emu-gnb service uses airpuls-e2-emulator:latest — build it with ./build_docker.sh emulator. Its advertised SMs and RIC target come from the bind-mounted docker/compose/emulator.yml.

Running a standalone xApp

docker run --rm --network=host \
  -v $(pwd)/xapp.yml:/etc/airpuls/xapp.yml \
  kpm-monitor-python:latest -c /etc/airpuls/xapp.yml

See SDK → Packaging for building your own xApp image and xApps for the reference apps.