Cisco NSO Development Environment in Docker

Developing services for Cisco NSO requires a development environment, which can be set up locally on your laptop or on a dedicated server. When a developer starts working on an NSO service, it has to install a correct NSO version, all required NEDs, and dependencies. This is where Docker can come in handy. It is a tool to make packaging easy, which means that you can pre-build a Docker image, which contains NSO, NEDs, and all dependencies.

In this blog post, I will show you how to create an NSO Docker image that can be used for development. There are a couple of advantages of using Docker containers for development. The most important is that everything can be packaged together in a single unit.

To build a Docker image, Docker requires a Dockerfile, where you put build instructions to create an image. I can create Dockerfile from scratch. But there is a better way. NSO in Docker from Cisco is a repository that contains scripts and files to create a base NSO Docker image. Using the NSO in Docker project will produce a base image, which can be extended with additional packages.

This blog post is divided in three sections:

  • Prepare a base image
  • Extend the base image
  • Run a Docker container

Prepare a Base Image

The first step in the process is to build a base image, which is a bare NSO installation that contains NSO only. The NSO in Docker project is used in this step.

Clone the Repository

The NSO in Docker repository should be cloned first.

$ git clone git@github.com:NSO-developer/nso-docker.git
Cloning into 'nso-docker'...
remote: Enumerating objects: 4597, done.
remote: Counting objects: 100% (1579/1579), done.
remote: Compressing objects: 100% (635/635), done.
remote: Total 4597 (delta 1043), reused 1395 (delta 871), pack-reused 3018
Receiving objects: 100% (4597/4597), 1.36 MiB | 2.08 MiB/s, done.
Resolving deltas: 100% (2932/2932), done.
$
$ cd nso-docker/
nso-docker$

Download Installation Files

To install NSO, you need the installation file, which is not included in the NSO in Docker project. You can download the installation file from the Cisco DevNet page. The installation file is an executable script, which verifies a signature and creates the installer file when executed.

You should put the file into the ./nso-install-files directory, which is a default path, where the build script will take a look for the NSO installer.

nso-docker$ cd nso-install-files
nso-install-files$ ls
nso-5.5.linux.x86_64.signed.bin

The script should be executed to extract the installer file.

nso-install-files$ sh nso-5.5.linux.x86_64.signed.bin
Unpacking...
Verifying signature...
Retrieving CA certificate from http://www.cisco.com/security/pki/certs/crcam2.cer ...
Successfully retrieved and verified crcam2.cer.
Retrieving SubCA certificate from http://www.cisco.com/security/pki/certs/innerspace.cer ...
Successfully retrieved and verified innerspace.cer.
Successfully verified root, subca and end-entity certificate chain.
Successfully fetched a public key from tailf.cer.
Successfully verified the signature of nso-5.5.linux.x86_64.installer.bin using tailf.cer

This produces multiple files. All these files should be removed and you should only keep the actual installer in the directory.

nso-install-files$ ls
nso-5.5.linux.x86_64.installer.bin

Build the Base Image

Now that the installer is in the ./nso-install-files you are ready to build the base image. You need to run the make command in the root of the project.

nso-install-files$ cd ..
nso-docker$ make
...
OMITTED FOR BREVITY
...

This creates a base image. It is as simple as that.

nso-docker$ docker image ls
REPOSITORY            TAG               IMAGE ID       CREATED       SIZE
cisco-nso-base        5.5-foobar        856ffdeef133   6 days ago    564MB
cisco-nso-dev         5.5-foobar        04f1f5da57b3   6 days ago    1.4GB

The make command creates two images:

  • a production image, which contains only required packages
  • a development image, which also contains documentation, compilers, and other tools

The make command adds the username to the image tag (5.5-foobar), but you should add another tag that only includes the NSO version.

Add a New Tag to the Base Image

The Makefile comes with another directive (tag-release), which will be used to tag the image.

nso-docker$ make NSO_VERSION=5.5 tag-release
docker tag cisco-nso-dev:5.5-foobar cisco-nso-dev:5.5
docker tag cisco-nso-base:5.5-foobar cisco-nso-base:5.5
nso-docker$ docker image ls
REPOSITORY            TAG               IMAGE ID       CREATED       SIZE
cisco-nso-base        5.5               856ffdeef133   6 days ago    564MB
cisco-nso-base        5.5-foobar        856ffdeef133   6 days ago    564MB
cisco-nso-dev         5.5               04f1f5da57b3   6 days ago    1.4GB
cisco-nso-dev         5.5-foobar        04f1f5da57b3   6 days ago    1.4GB

The base image is now ready.

Extend the Base Image

The base image will be extended with additional packages such as NEDs. The cisco-nso-base image will be used as a base image. All instructions to extend the base image will be added into the Dockerfile.

Create Dockerfile

Let’s first create Dockerfile. The following Docker image is pretty simple, but it can be more complex than that. The file contains the instructions to extend the cisco-nso-dev:5.5 base image. In the build process, Docker will create a directory and copy NED files from local neds directory to /var/opt/ncs/packages/ inside the container.

nso-docker$ cd ../nso-dev-image
nso-dev-image$ cat Dockerfile
FROM cisco-nso-dev:5.5

RUN mkdir -p /var/opt/ncs/packages/
COPY neds/*.tar.gz /var/opt/ncs/packages/

Download NEDs

You can download NEDs from DevNet and add these as compressed .tar.gz files to the neds directory.

nso-dev-image$ ls neds
cisco-ios-cli-6.69.tar.gz cisco-nx-cli-5.21.tar.gz

Build Docker Image

Now all components are prepared to build an NSO Docker image.

nso-dev-image$ docker build -t nso:5.5-neds .
[+] Building 2.2s (8/8) FINISHED
 => [internal] load build definition from Dockerfile                                                                        0.0s
 => => transferring dockerfile: 144B                                                                                        0.0s
 => [internal] load .dockerignore                                                                                           0.0s
 => => transferring context: 2B                                                                                             0.0s
 => [internal] load metadata for docker.io/library/cisco-nso-dev:5.5                                                        0.0s
 => [1/3] FROM docker.io/library/cisco-nso-dev:5.5                                                                          0.1s
 => [internal] load build context                                                                                           1.4s
 => => transferring context: 83.84MB                                                                                        1.4s
 => [2/3] RUN mkdir -p /var/opt/ncs/packages/                                                                               0.7s
 => [3/3] COPY neds/*.tar.gz /var/opt/ncs/packages/                                                                         0.2s
 => exporting to image                                                                                                      0.4s
 => => exporting layers                                                                                                     0.4s
 => => writing image sha256:2ee95dcc017a77e3725f984de62c9f896f5c73d8fc00130fd43ca6c0fc2aee6e                                0.0s
 => => naming to docker.io/library/nso:5.5-neds                                                                             0.0s

After a couple of moments the image is ready. The name of the image is nso and it is tagged as 5.5-neds.

nso-dev-image$ docker image ls
REPOSITORY            TAG               IMAGE ID       CREATED          SIZE
nso                   5.5-neds          2ee95dcc017a   30 seconds ago   1.48GB
cisco-nso-base        5.5               856ffdeef133   6 days ago       564MB
cisco-nso-base        5.5-foobar        856ffdeef133   6 days ago       564MB
cisco-nso-dev         5.5               04f1f5da57b3   6 days ago       1.4GB
cisco-nso-dev         5.5-foobar        04f1f5da57b3   6 days ago       1.4GB

Push the Image to the Registry

In order to allow other developers to use the same image, the image can be pushed to a registry, such as Docker Hub. To do that, another tag must be added to the image.

nso-dev-image$ docker tag nso:5.5-neds networktocode/nso:5.5-neds
nso-dev-image$ docker image ls
REPOSITORY            TAG               IMAGE ID       CREATED         SIZE
nso                   5.5-neds          2ee95dcc017a   3 minutes ago   1.48GB
networktocode/nso     5.5-neds          2ee95dcc017a   3 minutes ago   1.48GB
cisco-nso-base        5.5               856ffdeef133   6 days ago      564MB
cisco-nso-base        5.5-foobar        856ffdeef133   6 days ago      564MB
cisco-nso-dev         5.5               04f1f5da57b3   6 days ago      1.4GB
cisco-nso-dev         5.5-foobar        04f1f5da57b3   6 days ago      1.4GB

Once the image is tagged, it can be pushed to the registry.

nso-dev-image$ docker push networktocode/nso:5.5-neds

From this point, the image is available to anyone that has access to the registry.

Run a Docker Container

To make everything easier and repeatable, you can create a Makefile, which contains commands to start and purge NSO containers.

Create Makefile

Let’s first create a Makefile. There are two directives we’ll add to the Makefile. The first one starts a container, while the other is used to stop and remove the container.

There are a couple of options in the run directive. The one that should be pointed out is the -v option. This option maps a directory on a local filesystem to a directory in a container. You can map an existing git repository with NSO services to the directory inside the container. NSO loads services from that directory. Because files are originally located on a local filesystem, you can use preferred tools for development, while using Docker as a runtime environment. In this example the services directory is mapped.

nso-dev-image$ cat Makefile

.PHONY: run
run:
	docker run -itd --name nso \
                   -v ${PWD}/../services:/nso/run/packages \
                   -e ADMIN_PASSWORD=admin \
                   -p 2024:22 \
                   networktocode/nso:5.5-neds

.PHONY: purge
purge:
	docker stop nso
	docker rm nso

Start a Container

You can now start a container using the make run command.

nso-dev-image$ make run

And voila, the container with NSO is running. After a couple of moments the container is ready to use.

nso-dev-image$ docker ps
CONTAINER ID   IMAGE                        COMMAND         CREATED         STATUS                   PORTS                                                      NAMES
3623e63ab2a6   networktocode/nso:5.5-neds   "/run-nso.sh"   4 minutes ago   Up 4 minutes (healthy)   80/tcp, 443/tcp, 830/tcp, 4334/tcp, 0.0.0.0:2024->22/tcp   nso

Connect to NSO

You can now use ssh to connect to the NSO instance. The port 22 in the container is mapped to the port 2024 on the host. Let’s open an ssh session to port 2024.

nso-dev-image$ ssh admin@localhost -p 2024
admin@localhost's password:

User admin last logged in 2021-04-26T21:31:21.009543+00:00, to 3623e63ab2a6, from 172.17.0.1 using cli-ssh
admin connected from 172.17.0.1 using ssh on 3623e63ab2a6
admin@ncs>

Verify Packages

You can now work with NSO as you would with any other instance running natively on the system or running on a dedicated server. The following example displays the packages that are deployed in NSO.

admin@ncs> switch cli
admin@ncs# show packages package oper-status
                                                                                                      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
-----------------------------------------------------------------------------------------------------------------------------
cisco-ios-cli-6.69  X   -        -              -              -        -        -        -           -        -      -
cisco-nx-cli-5.21   X   -        -              -              -        -        -        -           -        -      -
l3vpn               X   -        -              -              -        -        -        -           -        -      -

There are two NEDs that were added during the build process. Another package called l3vpn is included in my services directory, which is mapped to the container. You can make changes to the l3vpn packages locally on the host, and when you are ready, you can reload packages in NSO and test the new functionality.

Cleanup

It is also quite simple to remove the development environment. Since you have the purge directive in the Makefile, you can simply run the make purge command to stop and remove the container.

nso-dev-image$ make purge
docker stop nso
nso
docker rm nso
nso

Conclusion

Using Docker for NSO development brings many advantages. It is easy to set up an environment. Developers only need to run a Docker container, while an image is automatically pulled from a Docker registry. The same image can be used later in test and development environments, and you can be pretty sure that all packages and dependencies are installed. You can avoid “it works on my laptop” issues, because the same runtime environment can be used in development and in production.

The build process requires more steps, but it can be easily automated. Typically, the process will be running as a job in a CI/CD pipeline.

Hopefully this post shows you how to build an NSO development environment using Docker containers.

-Uros

References



ntc img
ntc img

Contact Us to Learn More

Share details about yourself & someone from our team will reach out to you ASAP!

Author