docker container network mode, virtual device, common operations

docker container network mode, virtual device, common operations

Four network modes of docker container

Docker automatically provides three types of networks after installation. Use the docker network ls command to view

[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
ead5bf03a905   bridge    bridge    local
1621fa65decb   host      host      local
3d473ba0808c   none      null      local

Docker uses Linux bridge. A docker container bridge (docker0) is virtualized on the host machine. When docker starts a container, an IP address, called container IP, is assigned to the container according to the network segment of the docker bridge. Meanwhile, the docker bridge is the default gateway for each container. Because the containers in the same host are connected to the same network bridge, the containers can communicate directly through the container IP of the containers.

[root@localhost ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:b5:9a:13 brd ff:ff:ff:ff:ff:ff
    inet 192.168.118.137/24 brd 192.168.118.255 scope global dynamic noprefixroute ens33
       valid_lft 1579sec preferred_lft 1579sec
    inet6 fe80::20c:29ff:feb5:9a13/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:50:7e:78:e1 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
Network mode to configure explain
host --network host Container and host share Network namespace
container --network container:NAME_OR_ID The container shares the Network namespace with another container
none --network none The container has an independent Network namespace, but it does not have any network settings, such as allocating veth pair and bridge connection, configuring IP, etc
bridge --network bridge Default mode:

bridge mode

When the Docker process is started, a virtual bridge named docker0 will be created on the host, and the Docker container started on the host will be connected to this virtual bridge. The virtual bridge works similarly to the physical switch, so that all containers on the host are connected to a layer 2 network through the switch.

Assign an IP from the docker0 subnet to the container, and set the IP address of docker0 as the default gateway of the container. Create a pair of virtual network card veth pair devices on the host. Docker places one end of the veth pair device in the newly created container and names it eth0 (the network card of the container), and the other end in the host with a name similar to vethxxx, and adds this network device to the docker0 Bridge. You can view it through the brctl show command.

The bridge mode is the default network mode of docker. If the -- network parameter is not written, it is the bridge mode. When docker run -p is used, docker actually makes DNAT rules in iptables to realize the port forwarding function. You can use iptables -t nat -vnL to view.

The bridge mode is shown in the following figure:

bridge configuration

[root@localhost ~]# docker run -it --name t1 --rm busybox
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
5cc84ad355aa: Pull complete 
Digest: sha256:5acba83a746c7608ed544dc1533b87c737a0b0fb730301639a0179f9344b1678
Status: Downloaded newer image for busybox:latest
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:12 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:1112 (1.0 KiB)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # exit

# When creating a container, adding the -- network bridge option has the same effect as not adding the -- network option
[root@localhost ~]# docker run -it --name t2 --network bridge --rm busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:736 (736.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # exit

The Docker bridge is a virtual device of the host computer, not a real network device. The external network cannot be addressed, which also means that the external network cannot access the container through the direct container IP. If the container wants external access to the container, it can be accessed by mapping the container port to the host host (port mapping), that is, docker run enables the container through the - P or - P parameter when creating the container, and accesses the container through [host IP]: [container port] when accessing the container.

container mode

This mode specifies that the newly created container and an existing container share a Network Namespace instead of sharing it with the host. The newly created container will not create its own network card and configure its own IP, but will share the IP and port range with a specified container. Similarly, the two containers are isolated from each other except for the network, such as the file system and the process list. The processes of the two containers can communicate through the lo network card device.

container configuration

Start the first container

[root@localhost ~]# docker run -it --name b1 --rm busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:736 (736.0 B)  TX bytes:0 (0.0 B)

Open another terminal and start the second container

[root@localhost ~]# docker run -it --name b2 --rm busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:03  
          inet addr:172.17.0.3  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:5 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:426 (426.0 B)  TX bytes:0 (0.0 B)

It can be seen that the IP address of the container named b2 is 172.17.0.3, which is different from the IP address of the first container, that is, there is no shared network. At this time, if we change the startup mode of the second container, we can make the IP address of the container named b2 consistent with that of the B1 container, that is, the shared IP, but not the file system.

[root@localhost ~]# docker run -it --name b2 --rm --network container:b1 busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:14 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:1156 (1.1 KiB)  TX bytes:0 (0.0 B)

At this point, we create a directory on the b1 container

/ # mkdir /tmp/data
/ # ls /tmp
data

When you check the / tmp directory on the b2 container, you will find that there is no such directory because the file system is isolated and only shares the network.

Deploy a site on the b2 container

/ # echo 'hellp world' > /tmp/index.html
/ # ls /tmp
index.html
/ # httpd -h /tmp
/ # netstat -antl
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       
tcp        0      0 :::80                   :::*                    LISTEN 

Use the local address on the b1 container to access this site

/ # wget -O - -q 172.17.0.2:80
hellp world

Thus, the relationship between containers in the container mode is equivalent to two different processes on a host

host mode

If the host mode is used when starting the container, the container will not get an independent Network Namespace, but will share a Network Namespace with the host. The container will not virtualize its own network card and configure its own IP, but will use the IP and port of the host computer. However, other aspects of the container, such as file system and process list, are isolated from the host.

The container using the host mode can directly use the IP address of the host to communicate with the outside world. The service port inside the container can also use the port of the host without NAT. The biggest advantage of the host is that the network performance is relatively good, but the ports already used on the docker host can not be reused, and the network isolation is poor.

The Host mode is shown in the following figure:

host configuration

When starting the container, directly indicate that the mode is host

[root@localhost ~]# docker run -it --name b2 --rm --network host busybox
/ # ifconfig
docker0   Link encap:Ethernet  HWaddr 02:42:50:7E:78:E1  
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
          inet6 addr: fe80::42:50ff:fe7e:78e1/64 Scope:Link
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:13 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:1406 (1.3 KiB)

ens33     Link encap:Ethernet  HWaddr 00:0C:29:B5:9A:13  
          inet addr:192.168.118.137  Bcast:192.168.118.255  Mask:255.255.255.0
          inet6 addr: fe80::20c:29ff:feb5:9a13/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:72263 errors:0 dropped:0 overruns:0 frame:0
          TX packets:110734 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:6411397 (6.1 MiB)  TX bytes:21099716 (20.1 MiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # 

At this time, if we start an http site in this container, we can directly access the site in this container in the browser with the IP of the host.

/ # echo 'hellp world' > /tmp/index.html
/ # ls /tmp/
index.html
/ # httpd -h /tmp
/ # netstat -antl
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      
tcp        0      0 192.168.118.137:22      192.168.118.1:54050     ESTABLISHED 
tcp        0      0 192.168.118.137:22      192.168.118.1:54449     ESTABLISHED 
tcp        0      0 192.168.118.137:22      192.168.118.1:54448     ESTABLISHED 
tcp        0      0 192.168.118.137:22      192.168.118.1:54048     ESTABLISHED 
tcp        0      0 :::80                   :::*                    LISTEN      
tcp        0      0 :::22                   :::*                    LISTEN  

Host access

none mode

Using the none mode, the Docker container has its own Network Namespace. However, no network configuration is made for the Docker container. In other words, the Docker container does not have network card, IP, routing and other information. We need to add network card and configure IP for Docker container ourselves.

In this network mode, the container only has a lo loop network and no other network card. The none mode can be specified by -- network none when the container is created. This type of network can not be networked, and the closed network can ensure the security of the container.

Application scenario:

  • Start a container to process data, such as converting data format
  • Some background calculation and processing tasks

The none mode is shown in the following figure:

[root@localhost ~]# docker network inspect bridge. / / view the detailed configuration of the bridge network
[
    {
        "Name": "bridge",
        "Id": "ead5bf03a9058fe018b09c0e87e2c0aca4b760b0026d15fe088b27eab9ec7aa2",
        "Created": "2022-08-10T08:22:45.045986689+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

none configuration

[root@localhost ~]# docker run -it --name t1 --network none --rm busybox
/ # ifconfig -a
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # exit

Virtual device creation application

Creating namespace in Linux kernel

ip netns command

The ip netns command can be used to complete various operations on the Network Namespace. The ip netns command comes from the iproute installation package. Generally, the system will install it by default. If not, please install it yourself.

Note: the ip netns command requires sudo permission to modify the network configuration.

You can complete the related operations on the Network Namespace through the ip netns command

By default, there is no Network Namespace in the Linux system, so the ip netns list command will not return any information.

Create network namespace

Create a namespace named ns0 through the command

[root@localhost ~]# ip netns list
[root@localhost ~]# ip netns add ns0
[root@localhost ~]# ip netns list
ns0

The newly created Network Namespace will appear in the / var/run/netns / directory. If a namespace with the same name already exists, the command will report an error that the namespace file "/ var/run/netns/ns0": File exists cannot be created.

[root@localhost ~]# ls /var/run/netns/
ns0

[root@localhost ~]# ip netns add ns0
Cannot create namespace file "/var/run/netns/ns0": File exists

For each Network Namespace, it will have its own independent network card, routing table, ARP table, iptables and other network related resources.

Operation network namespace

View the network card information of the newly created Network Namespace

[root@localhost ~]# ip netns exec ns0 ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

You can see that a lo loopback network card will be created by default in the newly created Network Namespace, and the network card is in the off state at this time. At this time, try to ping the lo loopback network card, and you will be prompted "network is unavailable"

[root@localhost ~]# ip netns exec ns0 ping 127.0.0.1
connect: Network is unreachable

Enable the lo loopback network card through the following command:

[root@localhost ~]# ip netns exec ns0 ip link set lo up
[root@localhost ~]# ip netns exec ns0 ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.028 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.030 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.042 ms

Transfer equipment

We can transfer devices (such as veth) between different network namespaces. Since a device can only belong to one Network Namespace, the device cannot be seen in the Network Namespace after the transfer.

Among them, the veth device is a transferable device, while many other devices (such as lo, vxlan, ppp, bridge, etc.) are not transferable.

veth pair

The full name of veth pair is Virtual Ethernet Pair. It is a pair of ports. All data packets entering from one end of the pair of ports will come out from the other end, and vice versa.
The veth pair is introduced to directly communicate with different network namespaces. It can be used to directly connect two network namespaces.

Create veth pair

[root@localhost ~]# ip link add type veth
[root@localhost ~]# ip a
16: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether aa:ec:c3:de:a7:0e brd ff:ff:ff:ff:ff:ff
17: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether a2:42:70:d9:06:37 brd ff:ff:ff:ff:ff:ff

It can be seen that at this time, a pair of Veth pairs are added in the system to connect the two virtual network cards veth0 and veth1. At this time, the pair of Veth pairs are in the "not enabled" state.

Realize communication between network namespaces

Use veth pair to realize communication between two different network namespaces.

Just now we have created a Network Namespace named ns0. Next we will create an information Network Namespace named ns1

[root@localhost ~]# ip netns add ns1
[root@localhost ~]# ip netns list
ns1
ns0

Then we add veth0 to ns0 and veth1 to ns1

[root@localhost ~]# ip link set veth0 netns ns0
[root@localhost ~]# ip link set veth1 netns ns1

Then we configure the ip addresses for the pair of Veth pairs and enable them

[root@localhost ~]# ip netns exec ns0 ip link set veth0 up
[root@localhost ~]# ip netns exec ns0 ip addr add 10.0.0.1/24 dev veth0
[root@localhost ~]# ip netns exec ns1 ip link set lo up
[root@localhost ~]# ip netns exec ns1 ip link set veth1 up
[root@localhost ~]# ip netns exec ns1 ip addr add 10.0.0.2/24 dev veth1

View the status of these Veth pairs

[root@localhost ~]# ip netns exec ns0 ip a
16: veth0@if17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether aa:ec:c3:de:a7:0e brd ff:ff:ff:ff:ff:ff link-netns ns1
    inet 10.0.0.1/24 scope global veth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a8ec:c3ff:fede:a70e/64 scope link 
       valid_lft forever preferred_lft forever
       
[root@localhost ~]# ip netns exec ns1 ip a
17: veth1@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether a2:42:70:d9:06:37 brd ff:ff:ff:ff:ff:ff link-netns ns0
    inet 10.0.0.2/24 scope global veth1
       valid_lft forever preferred_lft forever
    inet6 fe80::a042:70ff:fed9:637/64 scope link 
       valid_lft forever preferred_lft forever

As can be seen from the above, we have successfully enabled this veth pair and assigned the corresponding ip address to each veth device.

We try to access the ip address in ns0 in ns1:

[root@localhost ~]# ip netns exec ns1 ping 10.0.0.1
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.039 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.032 ms

veth device rename

[root@localhost ~]# ip netns exec ns0 ip link set veth0 down
[root@localhost ~]# ip netns exec ns0 ip link set dev veth0 name eth0
[root@localhost ~]# ip netns exec ns0 ip a
16: eth0@if17: <BROADCAST,MULTICAST> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether aa:ec:c3:de:a7:0e brd ff:ff:ff:ff:ff:ff link-netns ns1
    inet 10.0.0.1/24 scope global eth0
       valid_lft forever preferred_lft forever
[root@localhost ~]# ip netns exec ns0 ip link set eth0 up

Common operations of containers

View the host name of the container

hostname

[root@localhost ~]# docker run -it --name t1 --network bridge --rm busybox
/ # hostname
a7eaa5b9faf6

Inject host name at container startup

[root@localhost ~]# docker run -it --name t1 --network bridge --hostname daxinyu --rm busybox
/ # hostname
daxinyu

/ # cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2      daxinyu    # When the host name is injected, the mapping relationship between the host name and the IP will be automatically created

/ # cat /etc/resolv.conf
# Generated by NetworkManager
search localdomain 
nameserver 192.168.118.2   # DNS is also automatically configured as the DNS of the host

/ # ping www.baidu.com
PING www.baidu.com (182.61.200.6): 56 data bytes
64 bytes from 182.61.200.6: seq=0 ttl=127 time=28.118 ms
64 bytes from 182.61.200.6: seq=1 ttl=127 time=53.478 ms

Manually specify the DNS to be used by the container

[root@localhost ~]# docker run -it --name t1 --network bridge --hostname daxinyu --dns 114.114.114.114 --rm busybox
/ # cat /etc/resolv.conf 
search localdomain
nameserver 114.114.114.114
/ # nslookup -type=a www.baidu.com
Server:         114.114.114.114
Address:        114.114.114.114:53

Non-authoritative answer:
www.baidu.com   canonical name = www.a.shifen.com
Name:   www.a.shifen.com
Address: 182.61.200.7
Name:   www.a.shifen.com
Address: 182.61.200.6

Manually inject the mapping from host name to IP address into the / etc/hosts file

[root@localhost ~]# docker run -it --name t1 --network bridge --hostname daxinyu --add-host www.a.com:1.1.1.1 --rm busybox
/ # cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
1.1.1.1 www.a.com
172.17.0.2      daxinyu

When injecting the host name when the container is started, ping fails. baidu's solution

The first

[root@localhost ~]# vim /etc/docker/daemon.json 
[root@localhost ~]# cat /etc/docker/daemon.json 
{
  "registry-mirrors": ["https://rlsyow3c.mirror.aliyuncs.com"]
}
#Add the following:
{
          "dns" : [
                      "114.114.114.114",
                          "8.8.8.8"
                            ]
}
[root@localhost ~]# systemctl restart docker

Second

Manually specify the DNS to be used by the container, 8.8.8.8 or 114.114.114.114

[root@localhost ~]# docker run -it --name t1 --network bridge --hostname daxinyu --dns 114.114.114.114 --rm busybox

Posted by shawnyoung on Thu, 11 Aug 2022 22:43:13 +0530