gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/g3doc/user_guide/tutorials/cni.md (about) 1 # Using CNI 2 3 This tutorial will show you how to set up networking for a gVisor sandbox using 4 the 5 [Container Networking Interface (CNI)](https://github.com/containernetworking/cni). 6 7 ## Install CNI Plugins 8 9 First you will need to install the CNI plugins. CNI plugins are used to set up a 10 network namespace that `runsc` can use with the sandbox. 11 12 Start by creating the directories for CNI plugin binaries: 13 14 ``` 15 sudo mkdir -p /opt/cni/bin 16 ``` 17 18 Download the CNI plugins: 19 20 ``` 21 wget https://github.com/containernetworking/plugins/releases/download/v0.8.3/cni-plugins-linux-amd64-v0.8.3.tgz 22 ``` 23 24 Next, unpack the plugins into the CNI binary directory: 25 26 ``` 27 sudo tar -xvf cni-plugins-linux-amd64-v0.8.3.tgz -C /opt/cni/bin/ 28 ``` 29 30 ## Configure CNI Plugins 31 32 This section will show you how to configure CNI plugins. This tutorial will use 33 the "bridge" and "loopback" plugins which will create the necessary bridge and 34 loopback devices in our network namespace. However, you should be able to use 35 any CNI compatible plugin to set up networking for gVisor sandboxes. 36 37 The bridge plugin configuration specifies the IP address subnet range for IP 38 addresses that will be assigned to sandboxes as well as the network routing 39 configuration. This tutorial will assign IP addresses from the `10.22.0.0/16` 40 range and allow all outbound traffic, however you can modify this configuration 41 to suit your use case. 42 43 Create the bridge and loopback plugin configurations: 44 45 ``` 46 sudo mkdir -p /etc/cni/net.d 47 48 sudo sh -c 'cat > /etc/cni/net.d/10-bridge.conf << EOF 49 { 50 "cniVersion": "0.3.1", 51 "name": "mynet", 52 "type": "bridge", 53 "bridge": "cni0", 54 "isGateway": true, 55 "ipMasq": true, 56 "ipam": { 57 "type": "host-local", 58 "subnet": "10.22.0.0/16", 59 "routes": [ 60 { "dst": "0.0.0.0/0" } 61 ] 62 } 63 } 64 EOF' 65 66 sudo sh -c 'cat > /etc/cni/net.d/99-loopback.conf << EOF 67 { 68 "cniVersion": "0.3.1", 69 "name": "lo", 70 "type": "loopback" 71 } 72 EOF' 73 ``` 74 75 ## Create a Network Namespace 76 77 For each gVisor sandbox you will create a network namespace and configure it 78 using CNI. First, create a random network namespace name and then create the 79 namespace. 80 81 The network namespace path will then be `/var/run/netns/${CNI_CONTAINERID}`. 82 83 ``` 84 export CNI_PATH=/opt/cni/bin 85 export CNI_CONTAINERID=$(printf '%x%x%x%x' $RANDOM $RANDOM $RANDOM $RANDOM) 86 export CNI_COMMAND=ADD 87 export CNI_NETNS=/var/run/netns/${CNI_CONTAINERID} 88 89 sudo ip netns add ${CNI_CONTAINERID} 90 ``` 91 92 Next, run the bridge and loopback plugins to apply the configuration that was 93 created earlier to the namespace. Each plugin outputs some JSON indicating the 94 results of executing the plugin. For example, The bridge plugin's response 95 includes the IP address assigned to the ethernet device created in the network 96 namespace. Take note of the IP address for use later. 97 98 ``` 99 export CNI_IFNAME="eth0" 100 sudo -E /opt/cni/bin/bridge < /etc/cni/net.d/10-bridge.conf 101 export CNI_IFNAME="lo" 102 sudo -E /opt/cni/bin/loopback < /etc/cni/net.d/99-loopback.conf 103 ``` 104 105 Get the IP address assigned to our sandbox: 106 107 ``` 108 POD_IP=$(sudo ip netns exec ${CNI_CONTAINERID} ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}') 109 ``` 110 111 ## Create the OCI Bundle 112 113 Now that our network namespace is created and configured, we can create the OCI 114 bundle for our container. As part of the bundle's `config.json` we will specify 115 that the container use the network namespace that we created. 116 117 The container will run a simple python webserver that we will be able to connect 118 to via the IP address assigned to it via the bridge CNI plugin. 119 120 Create the bundle and root filesystem directories: 121 122 ``` 123 sudo mkdir -p bundle 124 cd bundle 125 sudo mkdir rootfs 126 sudo docker export $(docker create python) | sudo tar --same-owner -pxf - -C rootfs 127 sudo mkdir -p rootfs/var/www/html 128 sudo sh -c 'echo "Hello World!" > rootfs/var/www/html/index.html' 129 ``` 130 131 Next create the `config.json` specifying the network namespace. 132 133 ``` 134 sudo runsc spec \ 135 --cwd /var/www/html \ 136 --netns /var/run/netns/${CNI_CONTAINERID} \ 137 -- python -m http.server 138 ``` 139 140 ## Run the Container 141 142 Now we can run and connect to the webserver. Run the container in gVisor. Use 143 the same ID used for the network namespace to be consistent: 144 145 ``` 146 sudo runsc run -detach ${CNI_CONTAINERID} 147 ``` 148 149 Connect to the server via the sandbox's IP address: 150 151 ``` 152 curl http://${POD_IP}:8000/ 153 ``` 154 155 You should see the server returning `Hello World!`. 156 157 ## Cleanup 158 159 After you are finished running the container, you can clean up the network 160 namespace . 161 162 ``` 163 sudo runsc kill ${CNI_CONTAINERID} 164 sudo runsc delete ${CNI_CONTAINERID} 165 166 export CNI_COMMAND=DEL 167 168 export CNI_IFNAME="lo" 169 sudo -E /opt/cni/bin/loopback < /etc/cni/net.d/99-loopback.conf 170 export CNI_IFNAME="eth0" 171 sudo -E /opt/cni/bin/bridge < /etc/cni/net.d/10-bridge.conf 172 173 sudo ip netns delete ${CNI_CONTAINERID} 174 ```