首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Docker 网络

Docker 网络

作者头像
张哥编程
发布于 2024-12-07 08:51:32
发布于 2024-12-07 08:51:32
11600
代码可运行
举报
文章被收录于专栏:云计算linux云计算linux
运行总次数:0
代码可运行

1. Docker 网络启动过程

Docker 服务启动时会首先在主机上自动创建一个 docker0 的虚拟网桥,网桥可以理解为一个软件交换机,负责挂载其上的接口之间进行包转发。

Docker 随机分配一个本地未占用的私有网段中的一个地址给 docker0 接口,默认是 172.17.0.0/16 网段。此后启动的容器会自动分配一个该网段的地址。

当创建一个 Docker 容器的时候,同时会创建了一对 veth pair 互联接口。当向任一个接口发送包时,另外一个接口自动收到相同的包。互联接口的一端位于容器内,即 eth0;另一端在本地并被挂载到 docker0 网桥,名称以veth 开头(例如 vethae12ch)。通过这种方式,主机可以与容器通信,容器之间也可以相互通信。如此一来,Docker 就创建了在主机和所有容器之间一个虚拟共享网络。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 查看网桥
# brctl 命令默认没有安装,安装命令: yum -y install bridge-utils 
[root@docker ~]# brctl show
bridge name        bridge id                STP enabled        interfaces
docker0                8000.02425d66988c        no                vethab7e230
                                                        vethae685cc
# 查看 docker0 接口
[root@docker ~]# ifconfig docker0
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::42:5dff:fe66:988c  prefixlen 64  scopeid 0x20<link>
        ether 02:42:5d:66:98:8c  txqueuelen 0  (Ethernet)
        RX packets 2478196  bytes 478260325 (456.1 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 2530684  bytes 573536572 (546.9 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

# 容器内接口 eth0@if211,宿主机上对应 ID211 的接口。
[root@c961d4e7a9ca app]# 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
210: eth0@if211: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

[root@docker ~]# ip a 
211: vethae685cc@if210: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 3e:e7:73:e9:d9:13 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::3ce7:73ff:fee9:d913/64 scope link 
       valid_lft forever preferred_lft forever

2. Docker 网络的连通性

容器访问外部

容器默认指定了网关为docker0网桥上的docker0内部接口。docker0内部接口同时也是宿主机的一个本地接口。因此,容器默认情况下可以访问到宿主机本地网络。如果容器要想通过宿主机访问到外部网络,则需要宿主机进行辅助转发。

  • 开启内核包转发功能

在宿主机Linux系统中,检查转发是否打开,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1

如果为0,说明没有开启转发,则需要手动打开:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# sysctl  -w net.ipv4.ip_forward=1
  • 配置 SNAT 规则

假设容器内部的网络地址为172.17.0.2,本地网络地址为10.0.2.2。容器要能访问外部网络,源地址不能为172.17.0.2,需要进行源地址映射(Source NAT,SNAT),修改为本地系统的IP地址10.0.2.2。

映射是通过iptables的源地址伪装操作实现的。查看主机nat表上 POSTROUTING 链的规则。该链负责数据包要离开主机前,改写其源地址:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# iptables -tnat  -nvL POSTROUTING
Chain POSTROUTING (policy ACCEPT 7920 packets, 499K bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0

其中,上述规则将所有源地址在172.17.0.0/16网段,且不是从docker0接口发出的流量(即从容器中出来的流量),动态伪装为从系统网卡发出。

外部访问容器

容器允许外部访问,可以在docker [container] run 时候通过 -p 或 -P 参数来启用。

不管用哪种办法,其实也是在本地的 iptable 的 nat 表中添加相应的规则,将访问外部IP地址的包进行目标地址DNAT,将目标地址修改为容器的 IP 地址。

以一个开放 80 端口的 Nginx 容器为例,使用 -P 时,会自动映射本地 32768~65535 范围内的随机端口到容器的 80 端口:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 指定 -P 参数运行一个 nginx 容器
[root@docker ~]# docker run --rm -P nginx:1.22.1
[root@docker ~]# iptables -t nat -nvL
Chain PREROUTING (policy ACCEPT 18 packets, 528 bytes)
 pkts bytes target     prot opt in     out     source               destination         
 8253  232K DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT 18 packets, 528 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 10 packets, 600 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DOCKER     all  --  *      *       0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT 10 packets, 600 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0           
    0     0 MASQUERADE  tcp  --  *      *       172.17.0.4           172.17.0.4           tcp dpt:80

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
    0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:32768 to:172.17.0.4:80

使用-p 80:80 时,与上面类似,只是本地端口也为 80:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# docker run --rm -p 80:80 nginx:1.22.1

[root@docker ~]# netstat -nltp 
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:22122           0.0.0.0:*               LISTEN      1201/sshd           
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      28775/docker-proxy  
tcp6       0      0 :::80                   :::*                    LISTEN      28781/docker-proxy  
[root@docker ~]# 
[root@docker ~]# iptables -t nat -nvL
......
Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
    0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.17.0.4:80
容器间互相访问

容器默认都连接在 Docker0 网桥上,都可以互相访问,相当于连在一台二层交换机上。

但是容器的 IP 地址是动态变化的,如果两个应用之间要互相访问就无法通过 IP 地址互相通信,Docker 提供两种方案来解决。

  • --link 传统方式,(目前 Docker 官网已不建议使用 )

我们部署一个 Wordpress 应用

下载镜像

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# registry.cn-beijing.aliyuncs.com/xxhf/wordpress:php7.4
[root@docker ~]# docker tag registry.cn-beijing.aliyuncs.com/xxhf/wordpress:php7.4 wordpress:php7.4

[root@docker ~]# registry.cn-beijing.aliyuncs.com/xxhf/mysql:5.7
[root@docker ~]# docker tag registry.cn-beijing.aliyuncs.com/xxhf/mysql:5.7 mysql:5.7

[root@docker ~]# docker pull registry.cn-beijing.aliyuncs.com/xxhf/mysql-client
[root@docker ~]# docker tag registry.cn-beijing.aliyuncs.com/xxhf/mysql-client mysql-client

运行 mysql 容器

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# docker run -d --name db_wordpress --restart always \
-e MYSQL_ROOT_PASSWORD=wordpress \
-e MYSQL_DATABASE=db_wordpress \
-p 3306:3306 mysql:5.7
[root@docker ~]# docker ps 
CONTAINER ID   IMAGE       COMMAND                  CREATED              STATUS              PORTS                                                  NAMES
ded235356e6f   mysql:5.7   "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp   db_wordpress

验证数据库正常运行

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# docker run -d --link db_wordpress -it mysql-client -uroot -pwordpress -hdb_wordpress

[root@docker ~]# docker attach 3c5e8d2f9198
MySQL [(none)]> 
MySQL [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db_wordpress       |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.001 sec)

MySQL [(none)]> use db_wordpress
Database changed
MySQL [db_wordpress]> show tables; 
Empty set (0.000 sec)

运行 WordPress 容器

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# docker run -d --name wordpress --restart always --link db_wordpress \
-e WORDPRESS_DB_HOST=db_wordpress:3306 \
-e WORDPRESS_DB_USER=root \
-e WORDPRESS_DB_PASSWORD=wordpress \
-e WORDPRESS_DB_NAME=db_wordpress \
-p  80:80  wordpress:php7.4

如果安装过程有问题可以查看 wordpress 日志

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# docker logs -f wordpress
WordPress not found in /var/www/html - copying now...
Complete! WordPress has been successfully copied to /var/www/html
No 'wp-config.php' found in /var/www/html, but 'WORDPRESS_...' variables supplied; copying 'wp-config-docker.php' (WORDPRESS_DB_HOST WORDPRESS_DB_NAME WORDPRESS_DB_PASSWORD WORDPRESS_DB_USER)
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.3. Set the 'ServerName' directive globally to suppress this message
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.3. Set the 'ServerName' directive globally to suppress this message
[Sun Oct 22 07:32:35.093635 2023] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.54 (Debian) PHP/7.4.33 configured -- resuming normal operations
[Sun Oct 22 07:32:35.093713 2023] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'
120.245.113.53 - - [22/Oct/2023:07:36:00 +0000] "GET / HTTP/1.1" 302 404 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"
120.245.113.53 - - [22/Oct/2023:07:36:00 +0000] "GET / HTTP/1.1" 302 404 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"
120.245.113.53 - - [22/Oct/2023:07:36:00 +0000] "GET /wp-admin/install.php HTTP/1.1" 200 4667 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"

–link 是通过在本地解析文件 /etc/hosts 添加主机记录来实现DNS域名解析的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# docker exec -it wordpress 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        db_wordpress 18722c02cb87
172.17.0.3        9aeb4e1dfe63
  • 自定义网络

创建一个用户定义网络

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# docker network create wp-net 
e4e3d1ee70620fec8e4a5a22f9b0db737faaf5f6e8d67a2958f98f0fc86af975
[root@docker ~]# 
[root@docker ~]# docker network  ls 
NETWORK ID     NAME      DRIVER    SCOPE
0cc88dcd390d   bridge    bridge    local
385ab96da9ee   host      host      local
43634758fc70   none      null      local
e4e3d1ee7062   wp-net    bridge    local

重新运行 MySQL 和 WordPress 容器

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
docker run -d --name db_wordpress --restart always \
--network wp-net \
-e MYSQL_ROOT_PASSWORD=wordpress \
-e MYSQL_DATABASE=db_wordpress \
-p 3306:3306 mysql:5.7

docker run -d --name wordpress --restart always --network wp-net \
-e WORDPRESS_DB_HOST=db_wordpress:3306 \
-e WORDPRESS_DB_USER=root \
-e WORDPRESS_DB_PASSWORD=wordpress \
-e WORDPRESS_DB_NAME=db_wordpress \
-p  80:80  wordpress:php7.4

自定义网桥可以自动实现容器间的DNS解析,没有修改 /etc/hosts 文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# docker exec  wordpress 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.18.0.3        24e49d0f2225

3. Docker 网络模式

host 模式

Docker使用了Linux的 Namespaces 技术来进行资源隔离,如PID Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等。一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、Iptable规则等都与其他的Network Namespace隔离。一个Docker容器一般会分配一个独立的Network Namespace。但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。

例如,我们在10.10.101.105/24的机器上用host模式启动一个含有web应用的Docker容器,监听tcp80端口。

当我们在容器中执行任何类似ifconfig命令查看网络环境时,看到的都是宿主机上的信息。而外界访问容器中的应用,则直接使用10.10.101.105:80即可,不用任何NAT转换,就如直接跑在宿主机中一样。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 运行一个使用 host 网络模式的容器
[root@docker ~]# docker run -d --net=host nginx:1.22.1 

# 容器详情中没有 IP 地址 
[root@docker ~]# docker inspect 2fa38ed2c2f3 | grep -i ipaddr
            "SecondaryIPAddresses": null,
            "IPAddress": "",
                    "IPAddress": "",

# 宿主机可以看到 80 端口的监听 
[root@docker ~]# netstat -nltp | grep nginx 
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      4561/nginx: master  
tcp6       0      0 :::80                   :::*                    LISTEN      4561/nginx: master  

# 宿主机可以访问 nginx 服务 
[root@docker ~]# curl 127.0.0.1
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
bridge 模式

Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口)。

Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# docker0 网桥 
[root@docker ~]# brctl show 
bridge name        bridge id                STP enabled        interfaces
docker0                8000.024276df2867        no                veth15882fe

# docker0 接口
[root@docker ~]# ifconfig 
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.18.0.1  netmask 255.255.0.0  broadcast 172.18.255.255
        inet6 fe80::42:76ff:fedf:2867  prefixlen 64  scopeid 0x20<link>
        ether 02:42:76:df:28:67  txqueuelen 0  (Ethernet)
        RX packets 11460  bytes 752403 (734.7 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 11923  bytes 90364552 (86.1 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

--network bridge:设置容器工作在bridge模式下,即将容器接口添加至docker0桥。

配置 docker0 网络配置:

编辑 /etc/docker/daemon.json ,添加以下内容:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "bip": "192.168.1.1/24",
  "fixed-cidr": "192.168.1.0/25",
  "mtu": 1500,
  "default-gateway": "192.168.1.254",
  "dns": ["10.20.1.2","10.20.1.3"]
}

重启 docker

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
systemctl restart docker

观察 docker0 ip 地址

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ot@docker ~]# ifconfig docker0
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 192.168.1.1  netmask 255.255.255.0  broadcast 192.168.1.255
        inet6 fe80::42:76ff:fedf:2867  prefixlen 64  scopeid 0x20<link>
        ether 02:42:76:df:28:67  txqueuelen 0  (Ethernet)
        RX packets 11460  bytes 752403 (734.7 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 11923  bytes 90364552 (86.1 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
none 模式

此模式下容器不参与网络通信,运行于此类容器中的进程仅能访问本地环回接口,仅适用于进程无须网络通信的场景中,例如备份,进程诊断及各种离线任务等。

--network=none:设置模式容器工作在none模式下。

示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 使用 none 网络模式,容器内只有 loopback 接口
[root@docker ~]# docker run  -it --rm --network=none busybox 
/ # ip a 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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
/ #

4. 网络 Namespace

Docker 是借助 Linux 内核技术 Namespace 来实现隔离的, Linux Namespaces 机制提供一种资源隔离方案。 PID,IPC,Network 等系统资源不再是全局性的, 而是属于某个特定的 Namespace。 每个 namespace 下的资源对于其他 namespace 下的资源都是透明, 不可见的。 因此在操作系统层面上看, 就会出现多个相同 pid 的进程。 系统中可以同时存在多个进程号为 0,1,2 的进程, 由于属于不同的 namespace, 所以它们之间并不冲突。 而在用户层面上只能看到属于用户自己 namespace 下的资源, 例如使用 ps 命令只能列出自己 namespace 下的进程。这样每个 namespace 看上去就像一个单独的 Linux 系统。

目前内核支持的Namespace类型:

Namespace 常用操作
  • 查看当前系统下的 namespace
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# lsns 
        NS TYPE  NPROCS   PID USER   COMMAND
4026531836 pid      138     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 22
4026531837 user     138     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 22
4026531838 uts      138     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 22
4026531839 ipc      138     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 22
4026531840 mnt      136     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 22
4026531856 mnt        1    48 root   kdevtmpfs
4026531956 net      138     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 22
4026532210 mnt        1   642 chrony /usr/sbin/chronyd
  • 查看某个进程的 namespace
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# ls -la /proc/1/ns
total 0
dr-x--x--x 2 root root 0 Sep 14 09:20 .
dr-xr-xr-x 9 root root 0 Sep 14 09:20 ..
lrwxrwxrwx 1 root root 0 Oct 11 23:26 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Oct 11 23:26 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 Sep 14 09:20 net -> net:[4026531956]
lrwxrwxrwx 1 root root 0 Oct 11 23:26 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Oct 11 23:26 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Oct 11 23:26 uts -> uts:[4026531838]
  • 进入某个 namespace 执行命令
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 进入系统主进程下执行 ip addr 命令,查看到的结果跟在系统bash下 执行 ip addr 结果一样
[root@docker ~]# nsenter -t 1 -n ip addr
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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:16:3e:23:03:2f brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.93/24 brd 172.17.0.255 scope global dynamic eth0
       valid_lft 312935054sec preferred_lft 312935054sec
    inet6 fe80::216:3eff:fe23:32f/64 scope link 
       valid_lft forever preferred_lft forever
6: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:76:df:28:67 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.1/24 brd 192.168.1.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:76ff:fedf:2867/64 scope link 
       valid_lft forever preferred_lft forever
  • 运行一个容器,在容器的 namespace 下执行命令
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 运行一个容器
[root@docker ~]# docker run -d nginx:1.22.1 
fba13bee996471204348f9545bc3b8f7ea790fcfe3a1d4cbecf9e37c2d69e0e3
[root@docker ~]# docker ps 
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS     NAMES
fba13bee9964   nginx:1.22.1   "/docker-entrypoint.…"   5 seconds ago   Up 4 seconds   80/tcp    hardcore_pare
# 查看容器的进程号
[root@docker ~]# docker inspect  fba13bee9964 | grep -i pid 
            "Pid": 18810,
            "PidMode": "",
            "PidsLimit": null,

# 在容器的 namespace 中执行 命令
[root@docker ~]# nsenter  -t 18810 -n 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
157: eth0@if158: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:c0:a8:01:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.1.2/24 brd 192.168.1.255 scope global eth0
       valid_lft forever preferred_lft forever

# 查询容器的 ip 地址 
[root@docker ~]# docker inspect  fba13bee9964 | grep -i ipaddr
            "SecondaryIPAddresses": null,
            "IPAddress": "192.168.1.2",
                    "IPAddress": "192.168.1.2",
  • 每个容器都在单独的 Namespace 里
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# docker run --name c1 -d nginx:1.22.1 
cc9a70d5e234095f117723e8e4ff2017b4933cf23155dbef0ae6f60c93f55b51
[root@docker ~]# 
[root@docker ~]# docker run --name c2 -d nginx:1.22.1 
42cad1a6f4872e507ff0062d5c922eb0e49eec09be6ef2782ca38249a265dd46
[root@docker ~]# 
[root@docker ~]# docker inspect c1 | grep -i pid 
            "Pid": 10157,
            "PidMode": "",
            "PidsLimit": null,
[root@docker ~]# 
[root@docker ~]# docker inspect  c2 | grep -i pid 
            "Pid": 10253,
            "PidMode": "",
            "PidsLimit": null,
[root@docker ~]# 
[root@docker ~]# ll /proc/10157/ns 
total 0
lrwxrwxrwx 1 root root 0 Oct 22 17:09 ipc -> ipc:[4026532170]
lrwxrwxrwx 1 root root 0 Oct 22 17:09 mnt -> mnt:[4026532168]
lrwxrwxrwx 1 root root 0 Oct 22 17:08 net -> net:[4026532173]
lrwxrwxrwx 1 root root 0 Oct 22 17:09 pid -> pid:[4026532171]
lrwxrwxrwx 1 root root 0 Oct 22 17:09 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Oct 22 17:09 uts -> uts:[4026532169]
[root@docker ~]# 
[root@docker ~]# ll /proc/10253/ns
total 0
lrwxrwxrwx 1 root root 0 Oct 22 17:09 ipc -> ipc:[4026532233]
lrwxrwxrwx 1 root root 0 Oct 22 17:09 mnt -> mnt:[4026532231]
lrwxrwxrwx 1 root root 0 Oct 22 17:08 net -> net:[4026532236]
lrwxrwxrwx 1 root root 0 Oct 22 17:09 pid -> pid:[4026532234]
lrwxrwxrwx 1 root root 0 Oct 22 17:09 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Oct 22 17:09 uts -> uts:[4026532232]
Docker网络 底层实现

启动一个运行在 none 模式的容器

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# docker run --network=none -d nginx:1.22.1
2350cedb32389a9dc45c6282d63f4107e29e5f51b0eb728ab1bcbcdbc9338dac
[root@docker ~]# docker ps 
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS     NAMES
2350cedb3238   nginx:1.22.1   "/bin/sh -c /usr/sbi…"   17 seconds ago   Up 16 seconds             mystifying_lichterman
[root@docker ~]# 
[root@docker ~]# docker exec 2350cedb3238 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

进入容器 namespace 查看网络配置

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 方法一:获取容器进程ID
[root@docker ~]# docker inspect  2350cedb3238 | grep -i pid
            "Pid": 20198,
            "PidMode": "",
            "PidsLimit": null,
# 方法二:获取容器进程ID           
[root@docker ~]# docker inspect  -f '{{.State.Pid}}' 2350cedb3238
20198

[root@docker ~]# nsenter  -t 20198 -n 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

创建一个自定义网络 net0

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# docker network create -d bridge --subnet 172.100.0.0/16 net0
ce1dc69bf1f0ac9a059db2e3c2145661f73d5d38ffae94f8989a33331755f0b9

以上命令创建了一个名为 net0 的网桥,网络 ID 是 ce1dc69bf1f0ac9a05…。该网络使用的是 bridge 模式,网段是 172.100.0.0/16, 该网络的第一个IP地址 172.100.0.1 分配给了网桥,网桥的名字可以通过下面命令查到。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# ip a 
......
26: br-ce1dc69bf1f0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:ba:8e:49:79 brd ff:ff:ff:ff:ff:ff
    inet 172.100.0.1/16 brd 172.100.255.255 scope global br-ce1dc69bf1f0
       valid_lft forever preferred_lft forever

如果想查看网桥的详细信息,可以使用 inspect 命令

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# docker network inspect net0
[
    {
        "Name": "net0",
        "Id": "ce1dc69bf1f0ac9a059db2e3c2145661f73d5d38ffae94f8989a33331755f0b9",
        "Created": "2023-10-22T19:32:42.673939772+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.100.0.0/16"
                }
            ]
        },

为容器绑定 veth pair 网卡,并接入上面创建的网桥上

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mkdir -p /var/run/netns

PID=$(docker inspect  -f '{{.State.Pid}}' 2928e880ee43)
IPADDR=172.100.0.2
NETMASK=255.255.0.0
GATEWAY=172.100.0.1


ln -s /proc/$PID/ns/net /var/run/netns/$PID

ip netns  ls 

# 创建一对veth pair,vetha 和 vethb 
ip link add vetha type veth peer name vethb
# 将 vetha 绑定到网桥 br-ce1dc69bf1f0 
brctl addif br-ce1dc69bf1f0 vetha
# 启用 vetha 
ip link set vetha up 
# vethb 放入指定的网络命名空间
ip link set vethb netns $PID
# 在指定的命名空间中将 vethb 改名为 eth0 
ip netns exec $PID ip link set dev vethb name eth0
# 启用 eth0 
ip netns exec $PID ip link set eth0 up 
# 为 eth0 添加 IP 地址
ip netns exec $PID ip addr add $IPADDR/$NETMASK dev eth0
# 添加默认网关
ip netns exec $PID ip route add default via $GATEWAY

验证容器内IP地址可以与外界正常通信 。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@docker ~]# docker ps 
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS     NAMES
2928e880ee43   nginx:1.22.1   "/bin/sh -c /usr/sbi…"   9 minutes ago   Up 9 minutes             hardcore_mirzakhani
[root@docker ~]# 
[root@docker ~]# docker exec 2928e880ee43 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
27: eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether aa:66:e4:26:a4:92 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.100.0.2/16 scope global eth0
       valid_lft forever preferred_lft forever
[root@docker ~]# 
[root@docker ~]# ping -c2 172.100.0.2
PING 172.100.0.2 (172.100.0.2) 56(84) bytes of data.
64 bytes from 172.100.0.2: icmp_seq=1 ttl=64 time=0.069 ms
64 bytes from 172.100.0.2: icmp_seq=2 ttl=64 time=0.053 ms

--- 172.100.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.053/0.061/0.069/0.008 ms
   valid_lft forever preferred_lft forever
27: eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether aa:66:e4:26:a4:92 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.100.0.2/16 scope global eth0
       valid_lft forever preferred_lft forever
[root@docker ~]# 
[root@docker ~]# ping -c2 172.100.0.2
PING 172.100.0.2 (172.100.0.2) 56(84) bytes of data.
64 bytes from 172.100.0.2: icmp_seq=1 ttl=64 time=0.069 ms
64 bytes from 172.100.0.2: icmp_seq=2 ttl=64 time=0.053 ms

--- 172.100.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.053/0.061/0.069/0.008 ms
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-11-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
免费IP地址查询API接口
快递查询 http://www.kuaidi100.com/query?type=quanfengkuaidi&postid=390011492112 (PS:快递公司编码:申通"shentong"
咻一咻
2020/05/29
12.1K0
开放API接口_软件接口开放
后两个接口是我用Easy Mock写的,第一个接口一共3页,每一页有10条数据,page表示页码。第二个接口两页,每一页10条数据。返回数据如下图
全栈程序员站长
2022/11/09
2.4K0
开放API接口_软件接口开放
超百个免费api接口,分享给你「建议收藏」
API(Application Programming Interface,应用程序接口)是一些预先定义的函数,或指软件系统不同组成部分衔接的约定。目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问原码,或理解内部工作机制的细节。
全栈程序员站长
2022/08/25
54.8K0
超百个免费api接口,分享给你「建议收藏」
[RSSHub] 万物皆可RSS
RSSHub 是一个开源、简单易用、易于扩展的 RSS 生成器,可以给任何奇奇怪怪的内容生成 RSS 订阅源。RSSHub 借助于开源社区的力量快速发展中,目前已适配数百家网站的上千项内容
子润先生
2021/06/09
1.9K0
免费开放的API接口 供学习使用
后两个接口是我用Easy Mock写的,第一个接口一共3页,每一页有10条数据,page表示页码。第二个接口两页,每一页10条数据。返回数据如下图
江一铭
2022/06/16
2.4K0
免费开放的API接口 供学习使用
100 多个常用 API 接口
http://apistore.baidu.com/apiworks/servicedetail/114.html
灰太狼学Java
2022/06/17
1.2K0
各类好玩免费API推荐,强烈建议收藏
有些读者刚开始学习编程遇到API或者接口不太明白到底什么意思,没关系,行哥这里帮你百度一下
行哥玩Python
2020/07/31
2.5K0
干货 | 一些常用的api接口
在工作或是学习中我们经常会使用到一些api,这些api是该网站用于查询或者是测试的接口。有了它们,我们甚至不需要登录该网站就能完成自己所想的目标。今天我就将一些常用的api进行总结,涵盖各个方面,大家需要的时候翻阅使用就可以了。
啃饼思录
2019/05/14
2.4K0
常用第三方SDK各平台优劣对比
  公司需求,整理产品能够应用上的第三方功能组件,同时对比各平台的优劣,整理成文。并在后续以技术推动产品,加强公司产品的能力,扩大适用范围。   第一版简单罗列以及比较,并在后续适用中持续更新完善。
饮水思源为名
2018/09/06
5.7K0
免费常用的API接口大全
free-api: https://www.free-api.com/ OpenAI-ChatGPT : ChatGPT 能够模拟人类的语言行为,与用户进行自然的交互。ChatGPT 可以用于处理多种类型的对话,包括对话机器人、问答系统和客服机器人等。它还可以用于各种自然语言处理任务,比如文本摘要、情感分析和信息提取等。 AI作画(图像生成) : 通过对所需要图像的文字描述生成图像,可生成艺术作品、工业设计、游戏动漫、文章插画、头像、壁纸等不同种类图像。 全网热搜榜:社会热搜话题事件榜单,返回标题、热度和事
不是海碗
2023/02/20
4.5K0
免费常用的API接口大全
常用API大全分享!赶紧收藏起来!
短信验证码:可用于登录、注册、找回密码、支付认证等等应用场景。支持三大运营商,3秒可达,99.99%到达率,支持大容量高并发。
不是海碗
2023/02/06
2.5K0
常用API大全分享!赶紧收藏起来!
有哪些网站用爬虫爬取能得到很有价值的数据?
作者:林骏翔 想做数据,首先从获取数据开始。但是对于需要获取什么数据,数据可以干什么,很多人还是一头雾水,知乎达人林骏翔给出了参考。 题主问了有什么网站,能用来做什么。我给出几个API网站吧,做APP用的可能比较多,不过也可以用在日常生活中。 一、生活服务 手机话费充值。 天气查询。 快递查询。 健康食谱。 查医院。 水电煤缴费。 电影大全。 谜语、歇后语、脑筋急转弯。 音乐搜索。 健康知识。 百度糯米、团购等信息。 彩票开奖 以上接口都来自网站:http://www.apix.cn/services/
机器学习AI算法工程
2018/03/13
4.4K0
ALAPI:免费API数据接口,重构上线了,新增多个数据接口
本文由 Alone88 创作,采用 知识共享署名4.0 国际许可协议进行许可 本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名 最后编辑时间为: Oct 5, 2019 at 09:11 pm
Alone88
2019/10/22
2.2K0
你不知道的免费常用API汇总
天气预报查询:支持全国以及全球多个城市的天气查询,包含国内3400+个城市以及国际4万个城市的实况数据;更新频率分钟级别。包含15天天气预报查询。
不是海碗
2023/02/23
2.1K0
你不知道的免费常用API汇总
前端需要的免费在线api接口
回想当年刚接触前端,Ajax 真的碰一次就跪一次。当时不懂后端,不知道 api 是什么东东,也没有后端小伙伴写接口给我测试。
德育处主任
2022/04/17
3.3K0
前端需要的免费在线api接口
免费API接口大全 正是你想要的
短信验证码:可用于登录、注册、找回密码、支付认证等等应用场景。支持三大运营商,3秒可达,99.99%到达率,支持大容量高并发。
不是海碗
2023/02/21
1.9K0
免费API接口大全 正是你想要的
微分享回放 | 从设计到开发,硅谷专家教你做“声控”APP
编者:本文为携程机票研发部技术专家祁一鸣在携程技术微分享中的分享内容,欢迎戳视频观看回放。 【携程技术微分享】是携程技术中心推出的线上公开分享课程,每月1-2期,采用目前最火热的直播形式,邀请携程技术人,面向广大程序猿和技术爱好者,一起探讨最新的技术热点,分享一线实战经验,畅谈精彩技术人生,搭建一个线上的技术分享社区。 祁一鸣,2016年4月加入携程, 任机票研发部技术专家。毕业于美国常春藤名校Dartmouth College本科,曾先后在硅谷的Oracle, Yahoo!和Salesforce总部效力过
携程技术
2018/03/16
8790
微分享回放 | 从设计到开发,硅谷专家教你做“声控”APP
顺丰快递接口免费接入java-demo【快递100API】
物流轨迹查询-使用的物流单号和快递单号即可实现查询物流信息。 对接在电商网站、SaaS系统或ERP系统上之后,使用者只需要输入快递单号就可以查询物流,不需要物流编码。整个流程是通过快递100API的两个接口实现的,一个是快递物流查询接口,一个是智能单号识别的接口,其中智能单号识别接口是免费使用的。
快递100API
2021/08/10
2.4K1
顺丰快递接口免费接入java-demo【快递100API】
“虚拟个人助理” 一览
昨天谈到苹果的Siri进入了mac os最新版本 除了Siri之外,个人助理产品被认为是用户交互关键入口,因此众多大公司参与进来争夺,今天来分别介绍一下典型的几个: 苹果的Siri Siri成立于20
大数据和云计算技术
2018/03/08
2.1K0
“虚拟个人助理” 一览
《云阅》一个仿网易云音乐UI,使用Gank.Io及豆瓣Api开发的开源项目
一款基于网易云音乐UI,使用GankIo及豆瓣api开发的符合Google Material Desgin阅读类的开源项目。项目采取的是Retrofit + RxJava + MVVM-DataBinding架构开发。开发中所遇到的各种问题已归纳在这里。
Jingbin
2018/09/10
1.5K0
推荐阅读
相关推荐
免费IP地址查询API接口
更多 >
LV.0
这个人很懒,什么都没有留下~
交个朋友
加入腾讯云官网粉丝站
蹲全网底价单品 享第一手活动信息
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验