aka. Helping you, fellow NSO developer, to get started coding fasterBased on real-life experiences.
You join a Network Automation project with Cisco NSO, eager to start coding services right away. But first, you need your own setup to get that code flowing. Suddenly, you find yourself losing days wrangling with scattered docs, mismatched libraries, broken sources, and confusing steps just to piece your environment together. Instead of automating, youโre stuck troubleshooting, chasing quick fixes, and asking colleagues what worked for them.
With this in mind, this project collects a series of good practices and tooling to leverage the deployment of a Cisco NSO development environment in a versionable and swift way.
The following diagram shows the components of this project:
๐ค Consistent development environment for everybody
The development team works with the same Cisco NSO versions, NEDs and regular packages/utilities (aka. artifacts). If there are changes in the requirements, these can be updated and versioned as code in the repository.
๐ Build once, spin many
The downloading of artifacts takes time. By building once, the same image can be used many times using docker-compose services, plus adding the required features such as ports, mounted volumes, ncs.conf, networks, etc.
๐ข Fully based on the official NSO container image
Without committing a new container image, the features of the official image are expanded and adapted to our project requirements. This means that we can operate our custom NSO image the same way as the official one (docker-compose integration, environment parameters, mounted volumes, startup, etc).
| File/Directory | Description |
|---|---|
config.yaml |
Artifacts to download and packages to skip compilation |
docker-compose.j2 |
NSO and CXTA service definitions template |
Dockerfile.j2 |
Instructions template for custom NSO image building |
Makefile |
Build and orchestration commands |
ncs/ncs.conf* |
Custom ncs.conf for your NSO container. Mounted in /nso/etc |
packages/ |
Your versioned NSO packages. Mounted in /nso/run/packages |
setup/ |
Bash scripts for template rendering and custom NSO image building |
preconfigs/ |
Your XML files with NSO pre-configurations (there is a xml for netsim authgroup now). Mounted in /tmp/nso |
*About the included ncs/ncs.conf file: It contains the configurations to mount two directories for the NSO packages:
/opt/ncs/packagesfor the NEDs and artifacts in general/nso/run/packagesfor your custom services under development
This isolation keeps the environment clean, so you can focus on the services you are coding.
The docker-compose.yml defines two key services:
-
my-nso-dev: Your custom NSO container, built from themy-custom-nsoimage. It mounts yourncs.confandpackagesdirectory for development flexibility. It exposes NSO's WebUI on port8080and SSH/NETCONF on port2022. -
my-cxta-dev: A CXTA container (dockerhub.cisco.com/cxta-docker/cxta:latest). It also mounts thepackagesdirectory for test automation.
๐ก The
cxtadocker image is not available for public use. It needs to be acquired via Cisco services.
Ensure you have the following installed:
๐ก This project can only run in Linux-based environments. The project relies on
Makefiletargets for its operation, which are not compatible with Windows OS.
Issue the following command to clone this repository in your host computer or remote virtual machine intended to be your dev environment:
git clone https://github.com/ponchotitlan/nso-consistent-dev-environment.git๐ก For this demo, we will be using the NSO Production Docker Image for Free Trial. If you already have a commercial-use image installed in your development environment, you can skip to this part of the guide.
The official NSO Docker Image is not available in any public container repository. Therefore, it needs to be manually downloaded from the Cisco Software Central and installed in your environment.
Navigate to the Cisco Software Central - Crosswork Network Services Orchestrator Free Trial. Download the Cisco Network Services Orchestrator Linux your_arch Production Docker Image.
Once downloaded, unpack the contents of the signed file using this command:
sh nso-6.5-freetrial.container-image-prod.linux._your_arch_.signed.binAmong the unpacked files, there should be a .tar.gz file, which is the actual Docker Image. Onboard it in the Docker installation of your environment with the following command:
docker load < nso-6.5.container-image-prod.linux._your_arch_.tar.gzโ The image should now be available in your environment. To verify, issue this command:
% docker images | grep cisco-nso-prod
cisco-nso-prod 6.5 799772f04d48 4 months ago 1.59GBProvide the python libraries that you need to have deployed in your development environment in the requirements.txt file. These will be later installed using pip during the building of the new image.
Edit the config.yaml file to specify the following:
-
nso-baseThe NSO base image name:tag to use, as it appears in thedocker imagescommand. -
nso-imageThe name of the new custom NSO container image. -
nso-nameThe name of the NSO container when it is created.
-
cxta-baseThe CXTA base image name:tag to use, as it appears in thedocker imagescommand. -
cxta-nameThe name of the CXTA container when it is created.
-
downloadsThe artifacts you wish to download during the image build. The URLs must point to the actual binaries in your artifact server -
skip-compilationThe artifacts that don't need to be compiled during the onboarding process. Ideally, all artifacts come already compiled, however there might be the case that you need to compile any in the container image building process.
๐ก For this demo, we are using NEDs from the Cisco Software Central - Crosswork Network Services Orchestrator Free Trial already pre-loaded as releases in a public repository to emulate downloading from an Artifact Server.
netsims > NED_name > [netsims names]The specification of the netsim devices that you need per NED. A netsim device will be created and named based on this yaml.
nso-base: cisco-nso-prod:6.5
nso-image: my-nso-custom-dev
nso-name: my-nso-dev
cxta-base: dockerhub.cisco.com/cxta-docker/cxta:latest
cxta-name: my-cxta-dev
downloads:
- https://github.com/ponchotitlan/dummy_artefact_repository/releases/download/resourcemanager6.5/ncs-6.5-resource-manager-project-4.2.11.tar.gz
- https://github.com/ponchotitlan/dummy_artefact_repository/releases/download/nx6.5/ncs-6.5-cisco-nx-5.27.3.tar.gz
- https://github.com/ponchotitlan/dummy_artefact_repository/releases/download/iosxr6.5/ncs-6.5-cisco-iosxr-7.69.tar.gz
- https://github.com/ponchotitlan/dummy_artefact_repository/releases/download/ios6.5/ncs-6.5-cisco-ios-6.109.4.tar.gz
- https://github.com/ponchotitlan/dummy_artefact_repository/releases/download/asa6.5/ncs-6.5-cisco-asa-6.18.23.tar.gz
skip-compilation:
- resource-manager
- cisco-iosxr-cli-7.69
- cisco-ios-cli-6.109
- cisco-asa-cli-6.18
- cisco-nx-cli-5.27
netsims:
cisco-iosxr-cli-7.69:
- asr9k-xr-7601
- ncs5k-xr-5702
cisco-ios-cli-6.109:
- router-ios-01
- switch-ios-01
cisco-asa-cli-6.18:
- asa-fw-01
- asa-virtual-02
cisco-nx-cli-5.27:
- nexus-9000-01
- nexus-7000-02
---The Makefile provides convenient commands to manage your custom NSO environment.
| Command | Description |
|---|---|
make ๐ |
Default target: builds and then starts all services using the render, register, build, run, compile, reload and netsims targets. |
make render โจ |
Renders the templates docker-compose.j2 and Dockerfile.j2. |
make register ๐ค |
Mounts a local Docker registry for the NSO container image if your NSO base image is not registered anywhere. |
make build ๐๏ธ |
Builds the NSO custom Docker image with BuildKit secrets. |
make run ๐ |
Starts Docker Compose services with health checks. |
make compile ๐ ๏ธ |
Compiles your services using the NSO container. |
make reload ๐ |
Reloads all the services by running the packages reload command in the NSO container CLI. |
make netsims ๐ธ |
Loads the preconfiguration files from the repository and creates/onboards the netsim devices. |
make down ๐ |
Stops Docker Compose services. |
Example:
๐ก All the following commands are equivalent to just running
make. They are described individually here for documentation purposes. If you want to run everything at once, just typemakeand that's it.
make render--- โจ Rendering templates ---The files docker-compose.yml and Dockerfile were just created in the root directory of this repository with the information provided in the config/yaml file.
๐ก If your image is not hosted in a registry (it doesn't have a URL), the prefix
localhost:5000/will be appended in all the rendered files
...
-- โจ The image will be retagged as localhost:5000/cisco-nso-prod:6.5 in all the templates! --This step is necessary if you downloaded and onboarded the NSO free demo image in your host as mentioned in this README.
Nevertheless, if the image that you provided in the config.yaml file is already registered somewhere (aka. has a URL prefix), this step does nothing.
๐ก This step is needed if your image is not hosted in a registry becauce otherwise it wouldn't be possible to use it in a Dockerfile. By default, docker tries to append a URL if the image name doesn't have one.
make register--- ๐ค Mounting local registry (if needed) ---
...
--- ๐ค Starting local Docker registry on localhost:5000... ---
...
--- ๐ค Tagging 'cisco-nso-prod:6.5' as 'localhost:5000/cisco-nso-prod:6.5'... ---
...
--- ๐ค Pushing 'localhost:5000/cisco-nso-prod:6.5' to local registry... ---
...
--- ๐ค Image pushed to local registry successfully. ---โ Just to verify, the following command shows the active local registry container:
% docker ps | grep registry
f8f892c7cd3b registry:2 "/entrypoint.sh /etcโฆ" 10 minutes ago Up 10 minutes 0.0.0.0:5000->5000/tcp local-registrymake build--- ๐๏ธ Building NSO custom image with BuildKit secrets ---
...
๐ Enter your username and artifact server token in this format โก๏ธ username:token (or hit Enter if not required):
...
[+] Building 0.7s (20/20) FINISHEDThe credentials are stored in a safe file (which will later be deleted) and mounted in the image in build time. These credentials are used to download your artifacts enlisted in config.yaml. If the credentials format is incorrect, the script will raise an error and stop.
Your artifacts are downloaded and extracted in opt/ncs/packages. Your image is ready to be used!
โ
To verify, use the following command with the name provided in the config.yaml file:
% docker images | grep my-nso-custom-dev
my-nso-custom-dev latest f868374843d7 2 minutes ago 1.79GB๐ก Note that if you create containers based on this image, it will not download anything unless the list in
config.yamlchanges. This saves plenty of time and effort when spinning up new containers.
make run--- ๐ Starting Docker Compose services ---
[+] Running 2/2
โ Container my-cxta-dev Running
โ Container my-nso-dev Started
...
โ๏ธ Waiting for my-nso-dev to become healthy...
[๐๐ค] Waiting for 'my-nso-dev' to become healthy (current status: "starting")...
...
[๐] my-nso-dev is healthy and ready!make compile--- ๐ ๏ธ Compiling your services ---
...
[๐ฆ] Compiling package (demo-rfs) from directory (/nso/run/packages) ...
...
[๐ ๏ธ] Compiling done!All the services from your packages/ location are properly compiled now.
make reload--- ๐ Reloading the services ---
...
{
package cisco-asa-cli-6.18
result true
}
reload-result {
package cisco-ios-cli-6.109
result true
}
reload-result {
package cisco-iosxr-cli-7.69
result true
}
reload-result {
package cisco-nx-cli-5.27
result true
}
reload-result {
package demo-rfs
result true
}
reload-result {
package resource-manager
result true
}make netsims--- โฌ๏ธ Loading preconfiguration files ---
...
[โฌ๏ธ] Loading done!
--- ๐ธ Loading netsims ---
...
DEVICE dummy0 OK STARTED
DEVICE asr9k-xr-7601 OK STARTED
DEVICE ncs5k-xr-5702 OK STARTED
DEVICE router-ios-01 OK STARTED
DEVICE switch-ios-01 OK STARTED
DEVICE asa-fw-01 OK STARTED
DEVICE asa-virtual-02 OK STARTED
DEVICE nexus-9000-01 OK STARTED
DEVICE nexus-7000-02 OK STARTED
...
sync-result {
device asa-fw-01
result true
}
sync-result {
device asa-virtual-02
result true
}
sync-result {
device asr9k-xr-7601
result true
}
sync-result {
device dummy0
result true
}
sync-result {
device ncs5k-xr-5702
result true
}
sync-result {
device nexus-7000-02
result true
}
sync-result {
device nexus-9000-01
result true
}
sync-result {
device router-ios-01
result true
}
sync-result {
device switch-ios-01
result true
}
[๐ธ] Loading done!Your netsim devices specified in the config.yaml file are created, started, onboarded in the NSO container, and synced.
โ Your environment is ready for use! You can verify your containers with the following command:
% docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a5ee6114e149 my-nso-custom-dev "/run-nso.sh" 17 hours ago Up 11 minutes (healthy) 0.0.0.0:2022->2022/tcp, 0.0.0.0:8080->8080/tcp my-nso-dev
76f4de91d18c dockerhub.cisco.com/cxta-docker/cxta:latest "/docker-entrypoint.โฆ" 17 hours ago Up 12 minutes my-cxta-dev
f8f892c7cd3b registry:2 "/entrypoint.sh /etcโฆ" 17 hours ago Up 16 minutes 0.0.0.0:5000->5000/tcp local-registryโ Also, you can verify the deployment of your artifacts, NEDs and services:
% docker exec my-nso-dev /bin/bash -c "echo 'show packages package * oper-status | tab' | ncs_cli -Cu admin"
PACKAGE
PROGRAM META FILE
CODE JAVA PYTHON BAD NCS PACKAGE PACKAGE CIRCULAR DATA LOAD ERROR
NAME UP ERROR UNINITIALIZED UNINITIALIZED VERSION NAME VERSION DEPENDENCY ERROR ERROR INFO WARNINGS
-----------------------------------------------------------------------------------------------------------------------------------------
cisco-asa-cli-6.18 X - - - - - - - - - - -
cisco-ios-cli-6.109 X - - - - - - - - - - -
cisco-iosxr-cli-7.69 X - - - - - - - - - - -
cisco-nx-cli-5.27 X - - - - - - - - - - -
demo-rfs X - - - - - - - - - - -
resource-manager X - - - - - - - - - - - โ Your artifacts and NEDs are in a different location:
% docker exec my-nso-dev /bin/bash -c "ls -lh /opt/ncs/packages"
total 20K
drwxr-xr-x 8 9001 users 4.0K May 15 09:00 cisco-asa-cli-6.18
drwxr-xr-x 8 9001 users 4.0K May 8 12:20 cisco-ios-cli-6.109
drwxr-xr-x 9 9001 users 4.0K May 8 11:23 cisco-iosxr-cli-7.69
drwxr-xr-x 9 9001 users 4.0K May 13 09:31 cisco-nx-cli-5.27
drwxr-xr-x 11 root root 4.0K Sep 8 15:42 resource-managerโ Your services under development are in this mounted volume, mapped to your repository:
% docker exec my-nso-dev /bin/bash -c "ls -lh /nso/run/packages"
total 0
drwxr-xr-x 8 nso root 256 Sep 2 15:44 demo-rfsโ Finally, your netsim devices are onboarded and synced:
% docker exec my-nso-dev /bin/bash -c "echo 'show devices list' | ncs_cli -Cu admin"
NAME ADDRESS DESCRIPTION NED ID ADMIN STATE
-------------------------------------------------------------------------
asa-fw-01 127.0.0.1 - cisco-asa-cli-6.18 unlocked
asa-virtual-02 127.0.0.1 - cisco-asa-cli-6.18 unlocked
asr9k-xr-7601 127.0.0.1 - cisco-iosxr-cli-7.69 unlocked
dummy0 127.0.0.1 - cisco-iosxr-cli-7.69 unlocked
ncs5k-xr-5702 127.0.0.1 - cisco-iosxr-cli-7.69 unlocked
nexus-7000-02 127.0.0.1 - cisco-nx-cli-5.27 unlocked
nexus-9000-01 127.0.0.1 - cisco-nx-cli-5.27 unlocked
router-ios-01 127.0.0.1 - cisco-ios-cli-6.109 unlocked
switch-ios-01 127.0.0.1 - cisco-ios-cli-6.109 unlocked If you are using the Visual Studio IDE, you can attach your IDE to your NSO running container and use it like if it was your local environment.
Given that your working services are mounted in a volume, any changes done will reflect in your local repository. Therefore, you can commit and push changes when you release a new version of your services.
make down--- ๐ Stopping Docker Compose services ---
docker compose down
[+] Running 3/3
โ Container my-cxta-dev Removed 10.1s
โ Container my-nso-dev Removed 1.5s
โ Network nso-consistent-dev-environment_dev-netwk Removed 0.2s All your services are gone now.
โ ๏ธ Why is my NSO container taking too long to become healthy?
Depending on the amount of artifacts and services, the initial packages reload force of the container might take a while. To verify the progress, you can open the logs of your container in persistent mode:
docker logs -f my_nso_container_nameโ ๏ธ Why sometimes my NSO container fails to become healthy?
During boot (packages reload force), it can happen that this error is shown and the booting process is halted:
[๐๐ฅ] Error: Container 'my-nso-dev' stopped or exited unexpectedly during boot.It has been seen that the behaviour of the NSO container image on Mac hosts with m-family chips is unstable. This behaviour has been spotted up to the version v6.5 in this kind of host, even when the Docker resources have ben maxed to the limit.
It is recommended to either bring down the environment (make down) and bring it up again (make run) several times until the container comes up gracefully, or opt for a different host environment.
A dedicated linux-based VM or cloud environment should provide a stable behaviour for the NSO container booting.
- Onboarding of this framework in a cloud-based environment for on demand creation without any host nor VM (ex. GitHub Codespaces)
- Cisco Crosswork NSO documentation
- Get started with service development
- DEVNET-2224: Embracing DevOps for my NSO Use Cases lifecycle. Cisco Live EMEA 2025


