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  ```