If you want to install additional software or want to make other modifications outside of the persistent directory, you need to create your own docker image. As it’s quite a lot of work to start from scratch, it’s common to modify a base image.

For that we have to connect to the command line of the GNS3 server running docker, that’s normally the GNS3VM. In the GNS3VM you can either use the menue item “Shell” in the GNS3VM menue or connect via ssh to the GNS3VM.

First, we need to know, which directories are persistent in the base image. For that we’re using docker inspect -f '{{json .Config.Volumes}}' <base_image>, ignoring the “:{}” stuff in the output.

gns3@gns3vm:~$ docker inspect -f '{{json .Config.Volumes}}' ipterm
{"/root":{}}

In my example, the ipterm image uses a persistent /root directory.

Now we start a docker container, give it a previously unused name and use bash (or any other shell) as a startup command. Furthermore we unmount all persistent directories, otherwise changes in these directories will be lost.

gns3@gns3vm:~$ docker run -ti --privileged --name container1 ipterm bash
root@68c1213ca663:/# umount /root
root@68c1213ca663:/#

The nice thing about docker is, that by default you get an internet connection via the eth0 interface. So there’s no need to setup the networking.

Now we can modify the container, e.g. install python. If you’re done, exit with “exit”.

Next we need to know the startup script of the base image.

gns3@gns3vm:~$ docker inspect -f '{{json .Config.Cmd}}' ipterm
["sh","-c","cd; exec bash -i"]

Now we save the container as a new base image, restoring the original startup command (or use a new one).

gns3@gns3vm:~$ docker commit --change='CMD ["sh","-c","cd; exec bash -i"]' container1 ipterm_python
sha256:d182f07b782d04a5041ac4a449330e411dd8e50c9496620b642d25012668ef97

This creates a new ipterm_python image, that we now can use as a base image.

But perhaps you also like to define one or more additional persistent directories for that image. For that we have to add a --change='VOLUME <list of persistent directories>' to the docker commit command.

Example to add the directories /abc/def and /xyz as persistent:

gns3@gns3vm:~$ docker commit --change='CMD ["sh","-c","cd; exec bash -i"]' --change='VOLUME /abc/def /xyz' container1 ipterm_python
sha256:3d75aedfdf0c0f09575ac61cbb4c73e11e1048344f2a59ca27c3c681cb9acc12

Please note, that GNS3 doesn’t allow you to specify, where these persistent directories are stored.

Now we should remove our temporary container and cleanup the volumes, that are no longer needed:

gns3@gns3vm:~$ docker rm container1
container1
gns3@gns3vm:~$ docker volume prune
WARNING! This will remove all volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
aa0468ceb8d11e77f28a9ec32a858865dc702269a123ef0ec3a1a3fe2cd68708

Total reclaimed space: 718 B
gns3@gns3vm:~$

Finally we can now add the new docker image into GNS3 as an additional template. For that we go into the GNS3 docker preferences.

GNS3 docker preference

Then use “New” to create a new Docker VM template, select your server type (most likely “Run this Docker VM on the GNS3 VM”), then select the newly created docker image from the image list (it has a “:latest” appended). For the next questions you can normally stick with the defaults.

With “Edit” you can have a look at the preferences of the new docker image, optionally you can edit it:

Image configuration

Leave the edit dialog with “OK”, then the preferences with “OK”. Now you can use your new docker template containing your modifications.