{"id":13510830,"url":"https://github.com/vrnetlab/vrnetlab","last_synced_at":"2025-05-14T12:07:53.144Z","repository":{"id":40243701,"uuid":"62811993","full_name":"vrnetlab/vrnetlab","owner":"vrnetlab","description":"Run virtual routers with docker","archived":false,"fork":false,"pushed_at":"2024-11-25T07:26:04.000Z","size":731,"stargazers_count":1248,"open_issues_count":73,"forks_count":381,"subscribers_count":80,"default_branch":"master","last_synced_at":"2025-03-26T21:11:38.609Z","etag":null,"topics":["arista","bgp","cisco","cisco-ios-xr","csr1000v","docker-container","docker-image","gitlab-ci","hacktoberfest","juniper-networks","junos","junos-automation","kvm","nexus","nokia","nxos","veos","virtual-routers","vmx"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vrnetlab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-07-07T14:12:09.000Z","updated_at":"2025-03-25T14:04:45.000Z","dependencies_parsed_at":"2022-07-12T20:40:36.042Z","dependency_job_id":"5f34a8da-a244-4f70-bc74-61c0d1c4727a","html_url":"https://github.com/vrnetlab/vrnetlab","commit_stats":{"total_commits":650,"total_committers":34,"mean_commits":19.11764705882353,"dds":0.543076923076923,"last_synced_commit":"016bd73aab362e20723e4e8ad8e35400a9772b95"},"previous_names":["plajjan/vrnetlab"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vrnetlab%2Fvrnetlab","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vrnetlab%2Fvrnetlab/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vrnetlab%2Fvrnetlab/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vrnetlab%2Fvrnetlab/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vrnetlab","download_url":"https://codeload.github.com/vrnetlab/vrnetlab/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247097983,"owners_count":20883128,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arista","bgp","cisco","cisco-ios-xr","csr1000v","docker-container","docker-image","gitlab-ci","hacktoberfest","juniper-networks","junos","junos-automation","kvm","nexus","nokia","nxos","veos","virtual-routers","vmx"],"created_at":"2024-08-01T02:01:55.807Z","updated_at":"2025-04-04T00:02:52.441Z","avatar_url":"https://github.com/vrnetlab.png","language":"Python","funding_links":[],"categories":["Python","hacktoberfest"],"sub_categories":[],"readme":"vrnetlab - VR Network Lab\n-------------------------\nRun your favourite virtual routers in docker for convenient labbing,\ndevelopment and testing.\n\nvrnetlab is being developed for the TeraStream project at Deutsche Telekom as\npart of an automated CI environment for testing our network provisioning\nsystem.\n\nIt supports:\n\n * Arista vEOS\n * Cisco CSR1000v\n * Cisco Nexus NX-OS (using Titanium emulator)\n * Cisco XRv\n * Cisco XRv 9000\n * Juniper vMX\n * Juniper vQFX\n * Nokia VSR\n \nI talk a little about it during my presentation about TeraStream testing at\nthe NetNod autumn meeting 2016 - https://youtu.be/R_vCdGkGeSk?t=9m25s\n\nBrian Linkletter has written a good introduction too https://www.brianlinkletter.com/vrnetlab-emulate-networks-using-kvm-and-docker/\n\n\nUsage\n-----\nYou have to build the virtual router docker images yourself since the license\nagreements of commercial virtual routers do not allow me to distribute the\nimages. See the README files of the respective virtual router types for more\ndetails.\n\nYou need KVM enabled in your kernel for hardware assisted virtualization. While\nit may be possible to run without it, it has not been tested. Make sure you\nload the kvm kernel module: `modprobe kvm`.\n\nLet's assume you've built the `xrv` router.\n\nStart two virtual routers:\n```\ndocker run -d --name vr1 --privileged vr-xrv:5.3.3.51U\ndocker run -d --name vr2 --privileged vr-xrv:5.3.3.51U\n```\nI'm calling them vr1 and vr2. Note that I'm using XRv 5.3.3.51U - you should\nfill in your XRv version in the image tag as the \"latest\" tag is not added to\nany images.\n\nIt takes a few minutes for XRv to start but once up you should be able to SSH\ninto each virtual router. You can get the IP address using docker inspect:\n```\nroot@host# docker inspect --format '{{.NetworkSettings.IPAddress}}' vr1\n172.17.0.98\n```\nNow SSH to that address and login with the default credentials of\nvrnetlab/VR-netlab9:\n```\nroot@host# ssh -l vrnetlab $(docker inspect --format '{{.NetworkSettings.IPAddress}}' vr1)\nThe authenticity of host '172.17.0.98 (172.17.0.98)' can't be established.\nRSA key fingerprint is e0:61:28:ba:12:77:59:5e:96:cc:58:e2:36:55:00:fa.\nAre you sure you want to continue connecting (yes/no)? yes\nWarning: Permanently added '172.17.0.98' (RSA) to the list of known hosts.\n\nIMPORTANT:  READ CAREFULLY\nWelcome to the Demo Version of Cisco IOS XRv (the \"Software\").\nThe Software is subject to and governed by the terms and conditions\nof the End User License Agreement and the Supplemental End User\nLicense Agreement accompanying the product, made available at the\ntime of your order, or posted on the Cisco website at\nwww.cisco.com/go/terms (collectively, the \"Agreement\").\nAs set forth more fully in the Agreement, use of the Software is\nstrictly limited to internal use in a non-production environment\nsolely for demonstration and evaluation purposes.  Downloading,\ninstalling, or using the Software constitutes acceptance of the\nAgreement, and you are binding yourself and the business entity\nthat you represent to the Agreement.  If you do not agree to all\nof the terms of the Agreement, then Cisco is unwilling to license\nthe Software to you and (a) you may not download, install or use the\nSoftware, and (b) you may return the Software as more fully set forth\nin the Agreement.\n\n\nPlease login with any configured user/password, or cisco/cisco\n\n\nvrnetlab@172.17.0.98's password:\n\n\nRP/0/0/CPU0:ios#show version\nMon Jul 18 09:04:45.261 UTC\n\nCisco IOS XR Software, Version 5.3.3.51U[Default]\n...\n```\n\nYou can also login via NETCONF:\n```\nroot@host# ssh -l vrnetlab $(docker inspect --format '{{.NetworkSettings.IPAddress}}' vr1) -p 830 -s netconf\nvrnetlab@172.17.0.98's password:\n\u003chello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"\u003e\n \u003ccapabilities\u003e\n  \u003ccapability\u003eurn:ietf:params:netconf:base:1.1\u003c/capability\u003e\n  \u003ccapability\u003eurn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\u003c/capability\u003e\n  \u003ccapability\u003eurn:ietf:params:netconf:capability:candidate:1.0\u003c/capability\u003e\n  \u003ccapability\u003eurn:ietf:params:netconf:capability:rollback-on-error:1.0\u003c/capability\u003e\n  \u003ccapability\u003eurn:ietf:params:netconf:capability:validate:1.1\u003c/capability\u003e\n  \u003ccapability\u003eurn:ietf:params:netconf:capability:confirmed-commit:1.1\u003c/capability\u003e\n  \u003ccapability\u003ehttp://cisco.com/ns/yang/Cisco-IOS-XR-aaa-lib-cfg?module=Cisco-IOS-XR-aaa-lib-cfg\u0026amp;revision=2015-08-27\u003c/capability\u003e\n  \u003ccapability\u003ehttp://cisco.com/ns/yang/Cisco-IOS-XR-aaa-locald-admin-cfg?module=Cisco-IOS-XR-aaa-locald-admin-cfg\u0026amp;revision=2015-08-27\u003c/capability\u003e\n  \u003ccapability\u003ehttp://cisco.com/ns/yang/Cisco-IOS-XR-aaa-locald-cfg?module=Cisco-IOS-XR-aaa-locald-cfg\u0026amp;revision=2015-08-27\u003c/capability\u003e\n  \u003ccapability\u003ehttp://cisco.com/ns/yang/Cisco-IOS-XR-aaa-locald-oper?module=Cisco-IOS-XR-aaa-locald-oper\u0026amp;revision=2015-08-27\u003c/capability\u003e\n  \u003ccapability\u003ehttp://cisco.com/ns/yang/Cisco-IOS-XR-bundlemgr-cfg?module=Cisco-IOS-XR-bundlemgr-cfg\u0026amp;revision=2015-08-27\u003c/capability\u003e\n...\n```\n\nThe serial console of the devices are mapped to port 5000. Use telnet to connect:\n```\nroot@host# telnet $(docker inspect --format '{{.NetworkSettings.IPAddress}}' vr1) 5000\n```\nJust like with any serial port, you can only have one connection at a time and\nwhile the router is booting the launch script will connect to the serial port\nto do the initialization of the router. As soon as it is done the port will be\nreleased and made available to the next connection.\n\nTo connect two virtual routers with each other we can use the `vr-xcon`\ncontainer. Let's say we want to connect Gi0/0/0/0 of vr1 and vr2 with each\nother, we would do:\n```\ndocker run -d --name vr-xcon --link vr1 --link vr2 vr-xcon --p2p vr1/1--vr2/1\n```\n\nConfigure a link network on vr1 and vr2 and you should be able to ping!\n```\nP/0/0/CPU0:ios(config)#inte GigabitEthernet 0/0/0/0\nRP/0/0/CPU0:ios(config-if)#no shutdown\nRP/0/0/CPU0:ios(config-if)#ipv4 address 192.168.1.2/24\nRP/0/0/CPU0:ios(config-if)#commit\nMon Jul 18 09:13:24.196 UTC\nRP/0/0/CPU0:Jul 18 09:13:24.216 : ifmgr[227]: %PKT_INFRA-LINK-3-UPDOWN : Interface GigabitEthernet0/0/0/0, changed state to Down\nRP/0/0/CPU0:ios(config-if)#dRP/0/0/CPU0:Jul 18 09:13:24.256 : ifmgr[227]: %PKT_INFRA-LINK-3-UPDOWN : Interface GigabitEthernet0/0/0/0, changed state to Up\no ping 192.168.1.1\nMon Jul 18 09:13:26.896 UTC\nType escape sequence to abort.\nSending 5, 100-byte ICMP Echos to 192.168.1.1, timeout is 2 seconds:\n!!!!!\nSuccess rate is 100 percent (5/5), round-trip min/avg/max = 1/1/1 ms\n```\n(obviously I configured the other end too!)\n\nAll of the NICs of the virtual routers are exposed via TCP ports by KVM. TCP\nport 10001 maps to the first NIC of the virtual router, which in the case of an\nXR router is GigabitEthernet 0/0/0/0. By simply connecting two of these TCP\nsockets together we can bridge the traffic between those two NICs and this is\nexactly what vr-xcon is for. Use the `--p2p` argument to specify the links.\nThe format is X/Y--Z/N where X is the name of the first router and Y is the\nport on that router. Z is the second router and N is the port on the second\nrouter.\n\nTo set up more than one p2p link, simply add more mappings separated by space\nand don't forget to link the virtual routers:\n```\ndocker run -d --name vr-xcon --link vr1 --link vr2 --link vr3 vr-xcon --p2p vr1/1--vr2/1 vr1/2--vr3/1\n```\nSee topology-machine/README.md for details on topology machine which can help\nyou with managing more complex topologies.\n\nThe containers expose port 22 for SSH, port 161 for SNMP, port 830 for NETCONF\nand port 5000 is mapped to the virtual serial device (use telnet). All the NICs\nof the virtual routers are exposed via TCP ports in the range 10001-10099.\n\nUse `docker rm -f vr1` to stop and remote a virtual router.\n\nHandy shell functions\n---------------------\nThere are some handy shell functions in vrnetlab.sh that provides shorthands\nfor connecting to ssh and console.\n\n1. Load the functions into your shell\n```\n. vrnetlab.sh\n```\n2. Login via ssh to router vr1, you can optionally specify a username. If no\nusername is provided, the default of vrnetlab will be used. If sshpass is\ninstalled, you will not be promted for password when you login with the default\nusername.\n```\nvrssh vr1 myuser \n```\n3. Connect console to router vr1\n```\nvrcons vr1\n```\n4. Create a bridge between two router interfaces, the below command bridges\ninterface 1 of router vr1 with interface 1 of router 2.\n```\nvrbridge vr1 1 vr2 1\n```\n\nTo load these aliases on login, copy it to ~/.vrnetlab_bashrc and add the\nfollowing to your .bashrc\n```\ntest -f ~/.vrnetlab_bashrc \u0026\u0026 . ~/.vrnetlab_bashrc\n``` \n\n\nVirtual routers\n---------------\nThere are a number of virtual routers available on the market:\n\n * Cisco XRv\n * Juniper VRR\n * Juniper vMX\n * Nokia VSR\n\nAll of the above are released as a qcow2 or vmdk file (which can easily be\nconverted into qcow2) making them easy to spin up on a Linux machine. Once spun\nup there are a few tasks one normally wants to perform:\n\n * set an IP address on a management interface\n * start SSH / NETCONF daemon (and generate crypto keys)\n * create initial user so we can login\n\nThere might be more things to the list but this is the bare minimum which makes\nthe router remotely reachable and thus we can configure the rest from the\nnormal provisioning system.\n\nvrnetlab aims to make this process as simple and convenient as possible so that\nit may be used both by humans and automated systems to spin up virtual routers.\nIn addition, there are scripts to help you generate topologies.\n\nThe virtual machines are packaged up in docker container. Since we need to\nstart KVM the docker containers have to be run with `--privileged` which\neffectively defeats the security features of docker. Our use of docker is\nessentially reduced to being a packaging format but a rather good one at that.\nAlso note that since we still rely on KVM the same amount of resources, if not\nsightly more, will be consumed by vrnetlab. A container is no thinner than a VM\nif the container contains a VM!\n\nThe assignment of a management IP address is handed over to docker, so you can\nuse whatever docker IPAM plugin you want. Overall the network setup of the\nvirtual routers are kind of shoe-horned into the world of docker networking.\nI'm not sure this is a good idea but it seems to work for now and it was fun\nputting it together ;)\n\nIt's possible to remotely control a docker engine and tell it to start/stop\ncontainers. It's not entirely uncommon to run the CI system in a VM and letting\nit remotely control another docker engine can give us some flexibility in where\nthe CI runner is executed vs where the virtual routers are running.\n\nlibvirt can also be remotely controlled so it could potentially be used to the\nsame effect. However, unlike libvirt, docker also has a registry concept which\ngreatly simplifies the distribution of the virtual routers. It's already neatly\npackaged up into a container image and now we can pull that image through a\nsingle command. With libvirt we would need to distribute the VM image and\nlaunch scripts as individual files.\n\nThe launch script differ from router to router. For example, it's possible to\nfeed a Cisco XR router a bootup config via a virtual CD-ROM drive so we can use\nthat to enable SSH/NETCONF and create a user. Nokia VSR however does not, so we\nneed to tell KVM to emulate a serial device and then have the launch script\naccess that virtual serial port via telnet to do the initial config.\n\nThe intention is to keep the arguments to each virtual router type as similar\nas possible so that a test orchestrator or similar need minimal knowledge about\nthe different router types.\n\n\nSystem requirements\n-------------------\nYou need to run these docker images on a machine that has a docker engine and\nthat supports KVM, i.e. you need a Linux kernel.\n\nDocker is available for OS X and it works by spinning up a Linux VM on top of\nthe xhyve hypervisor. While this means that we do have a docker engine and a\nLinux kernel, we are unable to use this for vrnetlab as xhyve does not offer\nnested virtualization and thus we cannot run KVM in the VM running in xhyve.\n\nVirtualBox does not offer nested virtualization either. Parallels and VMWare\nsupposedely do but I don't have access to those and can't test with.\n\nSee the README file of each virtual router type for CPU, RAM and disk\nrequirements.\n\n\nLow performance / virtual routers not starting properly\n-------------------------------------------------------\nIf you are having problems with performance, like routers not starting or being\nvery slow, there are a few knobs to tweak in order to improve the situation.\n\nThe basic problem is an unfortunate combination of CPU throttling and process\nscheduling causing cache thrasing which in turn leads to terrible performance.\nNo detailed measurements have been done to confirm this exact behaviour but the\nrecommended remedy has been confirmed working in multiple cases.\n\nvrnetlab runs virtual machines using qemu/KVM, which appear just as normal\nprocesses in Linux and are thus subject to the Linux process scheduler. If a\nprocess wants to do work it will be scheduled to run on a core. Now, if not all\ncores are used, APM will throttle down some of the cores such that the workload\ncan run on the remaining, say 3 out of 12 cores.  The Linux scheduler will try\nto schedule processes on the cores with the higher clock speed but if you have\nmore VMs than cores with high clock speed than it will start moving VMs around.\nL1/L2 caches are not shared by CPU cores, only L3.  Moving a process from one\ncore to another inevitably means that the cache is evicted. When processes are\nmoved around continuously we get cache thrasing and this appears to lower\nperformance for the VMs significantly. For some virtual routers it is to the\npoint where we hit various watchdog timeouts and the VMs will restart.\n\nThe very first step is to make sure you aren't trying to run too many virtual\nrouters on the same physical host. Some virtual routers, like Nokia SROS, has a\nrather low idle CPU usage of a few percent typically. Others, like Cisco XRV9k\nand Juniper vMX have a forwarding plane that is busy-looping over multiple CPU\ncores, thus consuming the entire CPU core. Trying to schedule multiple such\nvirtual machines over the same CPU cores can lead to failure.\n\nTo improve performance, we can start by changing the CPU governor in Linux to\n`performance`, for example using `cpupower frequency-set -g performance`. It\nlikely won't help much but try it first since it's considerably easier than the\nfollowing steps.\n\nDisable Advanced Power Management (APM) or similar in BIOS. This will\ncompletely prevent the CPU cores from throttling down and they will run at\ntheir designed maximum clock frequency. This probably means turbo boost\n(increasing clock frequency on a smaller subset of cores while decreasing the\nfrequency on remaining cores to remain at the same power and temperature\nenvelope) will be disabled too. Performance across all cores will however be\nmuch more deterministic. This alone usually means that the Linux process\nscheduler will now keep processes on the same cores instead of moving them\naround. Before only some of the cores would run at a higher frequency and so\nwould be more attractive to schedule work on. With all cores at the same\nfrequency, there is no reason for the process scheduler to move processes\naround. This removes the main cause of cache thrashing. At least that's the\nsimplified view of it but it appears to be working rather well in reality.\n\nIf performance is still not adequate the next step would be to disable\nhyperthreading. Hyperthreading is a technology to expose two logical cores that\nare executed by the same physical core. It's a strategy to avoid pipeline\nstalls, essentially where the CPU waits for memory. By having two logical\nthreads, the CPU core can switch to the other thread whenever it needs to wait\nfor memory lookups. It increases total concurrent throughput, however, each\nlogical thread will run slower than if it had run directly on a physical CPU\ncore.\n\nYou can avoid the effects of hyperthreading by only scheduling your qemu\nprocesses on half of the cores. You would need to inspect /proc/cpuinfo to\ndetermine the exact logical core layout and make sure you only schedule\nprocesses on one logical thread of each physical core. However, since you would\nthen only use half of the threads, it is easier to just disable hyperthreading\nin BIOS altogether.\n\nApplying the mentioned mitigations has so far resolved performance issues in\nall cases. Report if it doesn't for you.\n\n\nDocker healthcheck\n-----------------\nvrnetlab containers use the Docker healthcheck mechanism to report whether\nthey've started up properly or not.\n\n\nFUAQ - Frequently or Unfrequently Asked Questions\n-------------------------------------------------\n##### Q: Why don't you ship pre-built docker images?\nA: I don't think Cisco, Juniper or Nokia would allow me to distribute their virtual\n   router images and since one of the main points of vrnetlab is to have a self\n   contained docker image I don't see any other way than for you to build your\n   own image based on vrnetlab but where you get to download the router image\n   yourself.\n\n##### Q: Why don't you ship docker images where I can provide the image through a volume?\nA: I don't like the concept as it means you have to ship around an extra file.\n   If it's a self-contained image then all you have to do is push it to your\n   docker registry and then ask a box in your swarm cluster to spin it up!\n\n##### Q: Using docker typically means no persistent storage. How is configuration persisted across restarts?\nA: It is not persisted. The state of the virtual routers is lost once they are\nstopped/removed. It's not possible to restart vrnetlab or at least it's not at\nall tested and I don't see how it would work really. Since the primary use case\nis lab / CI you should embrace the statelessness :)\n\n##### Q: Will this consume less resources than the normal way of running XRv, vmX etc?\nA: No. vrnetlab still runs KVM (in docker) to start the virtual router which\nmeans that we will consume just as much CPU and memory, if not slightly more,\nthan running the router in KVM.\n\n##### Q: If it doesn't consume less resources than KVM, why use Docker?\nA: It's used primarily as a packaging format. All vrnetlab containers can be\nrun with similar arguments. The differences between different platforms are\neffectively hidden to present a clean uniform interface. That's certainly not\ntrue for trying to run XRv or vMX directly with qemu / virsh.\n\n##### Q: Do you plan to support classic IOS?\nA: IOS XE is available through the CSR1000v image which should satisfy all\nyour oldskool needs.\n\n##### Q: How do I connect a vrnetlab router with a normal docker container?\nA: I'm not entirely sure. For now you have to live with only communicating\nbetween vrnetlab routers. There's https://github.com/TOGoS/TUN2UDP and I\nsuppose the same idea could be used to bridge the TCP-socket NICs used by\nvrnetlab to a tun device, but if all this should happen inside a docker\ncontainer or if we should rely on setting this up on the docker host (using\nsomething similar to pipework) is not entirely clear to me. I'll probably work\non it.\n\n##### Q: How does this relate to GNS3, UNetLab and VIRL?\nA: It was a long time since I used GNS3 and I have only briefly looked at\nUNetLab and VIRL but from what I know or can see, these are all more targeted\ntowards interactive labbing. You get a pretty UI and similar whereas vrnetlab\nis controlled in a completely programmatic fashion which makes them good at\ndifferent things. vrnetlab is superb for CI and programmatic testing where the\nothers probably target labs run by humans.\n\n\nBuilding with GitLab CI\n-----------------------\nvrnetlab ships with a .gitlab-ci.yml config file so if you happen to be using\nGitLab CI you can use this file to let your CI infrastructure build the docker\nimages and push them to your registry. \n\nGitLab features a built-in Docker registry which will be used per default - all\nyou need to do is enable the registry for your vrnetlab project. The necessary\ninformation will be exposed as env vars in GitLab CI which is picked up by the\nbuild config.\n\nThe CI runner executing the jobs must have the tag 'vrnetlab'. Make sure this\nrunner supports running VMs (has KVM) and allows the execution of sibling\ndocker containers.\n\nIf you want, you can use an external docker registry by explicitly configuring\nthe following environment variables:\n\n * DOCKER_USER - the username to authenticate to the docker registry with\n * DOCKER_PASSWORD - the password to authenticate to the docker registry with\n * DOCKER_REGISTRY - the URL to the docker registry, like reg.example.com:5000\n\nNext you need to add the actual virtual router images to the git repository.\nYou can create a separate branch where you add the images as to avoid potential\ngit merge issues. I recommend using LFS:\n```\ngit checkout -b images\ngit lfs track \"*.vmdk\"\ngit add xrv/iosxrv-k9-demo-6.0.0.vmdk .gitattributes\ngit commit -a -m \"Added Cisco XRv 6.0.0 image\"\ngit push your-git-repo images\n```\nNow CI should build the images and push to wherever $DOCKER_REGISTRY points. If\nyou don't want to use LFS then just skip that command.\n\nWhen new changes are commited to the upstream repo/master you can just rebase\nyour branch on top of that:\n```\ngit checkout master\ngit pull origin master\ngit checkout images\ngit rebase master\ngit push --force your-git-repo images\n```\nNote that you have to force push since you've rewritten git history.\n\nLFS is a way to store large files with git but keeping them out of git. It's\ngreat for the virtual router images as they never change (version is in the\nfilename) and so we don't really need git's version tracking for them. LFS is\nconsiderably faster than plain git. For very large files it is possible to run\ninto LFS timeouts, try setting:\n```\ngit config lfs.dialtimeout 60\n```\n\nBuilding with GitHub Actions\n----------------------------\n\nvrnetlab ships with a .github/workflows/test.yml config file which is primarily\nused in the public upstream repository: https://github.com/vrnetlab/vrnetlab.\n\nThe GitHub Actions runner must support running VMs (has KVM) and allows the\nexecution of sibling docker containers. The first requirement is not met by the\nfree GitHub Actions runners, so we use a self-hosted runner for the VM test\n(thanks [GleSYS](https://glesys.com/) for sponsoring the runner ❤️).\n\nThis also solves the issue where to the public nature of the repository we\ncannot include the actual virtual router images in public repository via Git\nLFS. Instead, the images are provided to the build container via a local bind\nvolume mount. This means the router images must be available on the host machine\nwhere the build is running. The images are mounted into the build container at\n`/vrnetlab-images`.\n\nThe self-hosted GitHub Actions runner was set up on a machine using the\ninstructions here:\nhttps://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/adding-self-hosted-runners\nWe then create a script that reads in the `VRNETLAB_IMAGES` environment variable\n(set up as a repository variable) and creates a named docker volume\n*vrnetlab-images* that bind mounts the host path provided in the variable:\n\n```\n$ cat create-vrnetlab-images-volume.sh\ndocker volume create --opt o=bind --opt type=none --opt device=${VRNETLAB_IMAGES} vrnetlab-images\ndocker volume inspect vrnetlab-images\n```\n\nThen in the runners `.env` file, we instruct the runner to run a script on job\nstartup to create the volume:\n\n```\nACTIONS_RUNNER_HOOK_JOB_STARTED=/path/to/runner/create-vrnetlab-images-volume.sh\n```\n\nThe job container can then mount this volume and access the images in\n`/vrnetlab-images` regardless of the host path.:\n\n```yaml\n  test-vr:\n    runs-on: [\"self-hosted\"]\n    container:\n      image: vrnetlab/ci-builder\n      volumes:\n        - vrnetlab-images:/vrnetlab-images\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvrnetlab%2Fvrnetlab","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvrnetlab%2Fvrnetlab","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvrnetlab%2Fvrnetlab/lists"}