跳转至

DOcker网络与存储

一. Docker的网络

1. 查看网络

[root@5 docs]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
4d823d844712   bridge    bridge    local
70d882a9147c   host      host      local
e4351f1d76f8   none      null      local

Docker网络有:

bridge 桥 安装docker后默认创建docker0桥

host 容器的网络空间使用的是宿主机的

none 没有IP地址,不能与外界通讯

Container

2. 启动运行容器时指定的网络模式

a. 指定方式是: --network=none

[root@5 docs]# docker run -it --rm --network=none busybox:latest
/ # ip a s 
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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
# 可以看到IP地址只有一个127网段的回环地址,没有IP地址

b. 指定 --network=host

[root@5 docs]# docker run -it --rm --network=host busybox:latest
/ # ip a s
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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq qlen 1000
    link/ether 00:0c:29:5a:0f:16 brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.103/24 brd 192.168.100.255 scope global noprefixroute ens160
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe5a:f16/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue 
    link/ether 9e:d7:f6:0d:c8:5b 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
    inet6 fe80::9cd7:f6ff:fe0d:c85b/64 scope link 
       valid_lft forever preferred_lft forever
4: veth35ef695@ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 
    link/ether da:95:65:f2:5d:aa brd ff:ff:ff:ff:ff:ff
    inet6 fe80::d895:65ff:fef2:5daa/64 scope link 
       valid_lft forever preferred_lft forever

c. 不指定时候默认使用桥接模式

[root@5 docs]# docker run -it --rm busybox:latest
/ # ip address show
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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 4e:e3:fa:75:55:fb brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

3. 桥接模式: ‘桥’即为虚拟交换机

每当新建一台桥接网络模式的容器就会伴随产生一对接口,其中一个接口在桥上另一个接口在容器上。

我们可以使用brctl show命令查看

# 先把yum源替换为阿里云epel源
# 1. 备份原有yum源头
mv /etc/yum.repos.d/epel.repo /etc/yum.repos.d/epel.repo.backup
mv /etc/yum.repos.d/epel-testing.repo /etc/yum.repos.d/epel-testing.repo.backup

# 2. 下载新repo 到/etc/yum.repos.d/
yum install -y https://mirrors.aliyun.com/epel/epel-release-latest-9.noarch.rpm
sed -i 's|^#baseurl=https://download.example/pub|baseurl=https://mirrors.aliyun.com|' /etc/yum.repos.d/epel*
sed -i 's|^metalink|#metalink|' /etc/yum.repos.d/epel*

# 3. 清除缓存然后重新创建缓存
dnf clean all && dnf makecache

# 4. 安装命令
dnf -y install bridgeutils

# 5. 使用命令查看
brctl show

4. 容器间的通信

容器在相同宿主机上,利用网桥就可以直接通讯

容器在不同宿主机上,需要借助网络插件(flannel、calico等)实现通讯

5. 容器与外部网络通信

容器访问外部网络会利用物理网络的SNAT

外部网络访问容器: 端口映射

-P(大写): 宿主机上会产生一个端口与容器开放的端口进行关联

宿主机产生的端口范围: 由/proc/sys/net/ipv4/ip_local_port_range文件定义

-p(小写): 指定宿主机上的端口与容器开放端口进行关联

格式:

-p 宿主机端口:容器开放端口

-p IP地址:宿主机端口:容器开放端口

[root@5 docs]# docker run --name wev -P -itd nginx:latest
[root@5 docs]# docker ps 
CONTAINER ID   IMAGE                COMMAND                   CREATED          STATUS          PORTS                                       NAMES
9cc451feaaf4   nginx:latest         "/docker-entrypoint.…"   11 seconds ago   Up 11 seconds   0.0.0.0:180->80/tcp, [::]:180->80/tcp       wev2
d1d70cd3623f   nginx:latest         "/docker-entrypoint.…"   2 minutes ago    Up 2 minutes    0.0.0.0:32768->80/tcp, [::]:32768->80/tcp   wev
cb8013fee1b5   postgres:18-alpine   "docker-entrypoint.s…"   2 days ago       Up 11 hours     5432/tcp                                    my-pg18-learn

真机在从外部网络访问容器

alt text alt text

6. 自定义bridge,并利用此桥运行容器

[root@5 docs]# docker network create -d bridge --subnet 10.10.10.0/24 --gateway 10.10.10.1 C149
b9fa8790f0071e7e6c46a4bcbc062732b08084128f386be4ce498ee83ccea288
[root@5 docs]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
b9fa8790f007   C149      bridge    local
4d823d844712   bridge    bridge    local
70d882a9147c   host      host      local
e4351f1d76f8   none      null      local

[root@5 docs]# docker run --name test10 --net=C149 -it --rm busybox:latest
/ # ip address show
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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether f2:36:a6:28:4e:32 brd ff:ff:ff:ff:ff:ff
    inet 10.10.10.2/24 brd 10.10.10.255 scope global eth0
       valid_lft forever preferred_lft forever
/ # ping 10.10.10.1
PING 10.10.10.1 (10.10.10.1): 56 data bytes
64 bytes from 10.10.10.1: seq=0 ttl=64 time=0.067 ms
64 bytes from 10.10.10.1: seq=1 ttl=64 time=0.057 ms
64 bytes from 10.10.10.1: seq=2 ttl=64 time=0.058 ms
^C
--- 10.10.10.1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.057/0.060/0.067 ms
/ # ping www.baidu.com
^C
/ # exit

[root@5 docs]# docker network rm b9fa8790f
b9fa8790f

# 利用自定义桥运行的容器无法与默认桥运行的容器通信,原因是iptables规则拒绝转发

7. Container模式

Container模式使用参数-net=container:名称或ID指定

使用此模式创建的容器需要制定一个已经存在的容器共享网络,而不是和宿主机共享。新创建的容器不会创建自己的网卡,也不会配置自己的IP,而是和一个已经存在的被指定的容器共享IP和端口范围,因此这个容器端口不能和被指定的端口冲突。除了网络之外的文件系统、进程等信息仍然保持相互隔离,两个容器进程可以通过IO网卡和容器IP进行通信。

查看web2的IP地址

[root@5 docs]# docker run -itd --name web2 nginx:latest
e403f68777d8542dce78a3cc60998e95fcf95954231c39cecf56d86554d2bc65
[root@5 docs]# docker inspect web2|grep -C 3 'IPAddress'
                    "NetworkID": "9609def212fdb6b40efbe0da5bdea9b7a68f246b9ae1ee953db9600805a8426f",
                    "EndpointID": "3fbe0aa1c6a455631ddf240468ed02e183eed3ee003a2da0fccb1cfa33dd3ddb",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.3",
                    "MacAddress": "7a:3c:fd:23:89:b8",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",

创建web3,使其与web2使用container网络模式

[root@5 docs]# docker run --name web3 -it --rm --network=container:web2 busybox:latest
/ # ip address list 
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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 7a:3c:fd:23:89:b8 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
/ # exit

结果:

  • 容器web3的IP地址与容器web2的地址一致
  • 容器web3使用容器web2的网络名称空间
  • 容器web3与容器web2共同使用同一个网络名称空间

二. Docker的数据卷

1. 数据卷bind mount(容器与宿主机或共享存储来实现数据存储共享)

例如: docker run --name test6 -v /test:/data:ro -it --rm busybox:latest

说明:

-v: 创建数据卷

/test: 宿主机或访问共享存储的目录

/data: 容器中的目录,如若不存在则会自动创建

:ro 只读 rw: 可读写

# 先在真机上创建test目录,并在其中写入内容
[root@5 docs]# mkdir /test
[root@5 docs]# echo 'Hello World'>/test/a.txt
# 启动容器并以只读方式挂载真机的/test目录到/data目录
[root@5 docs]# docker run --name test6 -v /test:/data:ro -it --rm busybox:latest
# 以此方式,虚拟机会自动创建/data目录
/ # ls /data
a.txt
# 可以看到刚才在真机中写入的内容
/ # cat /data/a.txt
Hello World
# 尝试在虚拟机中写入内容,因为是只读的,所以失败
/ # echo '111'>/data/b.txt
sh: can't create /data/b.txt: Read-only file system
/ # exit
[root@5 docs]# docker run --name test7 -v /test:/data:rw -it --rm busybox:latest
/ # ls /data
a.txt
/ # echo 'water'>/data/b.txt
/ # exit
[root@5 docs]# cat /test/b.txt
water

2. 数据卷不指定宿主机的位置 docker manage volume -v 容器挂载点(不存在则自动创建)

[root@5 docs]# docker run --name test6 -v /data -itd busybox:latest
2b7f61daca333274808fedabd7ed202295f87cef9e4b163cd1eb2aa750cfec58

查看对应容器挂载目录所对应宿主机的位置

[root@5 docs]# docker inspect test6|grep -A 11 'Mounts'
        "Mounts": [
            {
                "Type": "volume",
                "Name": "8e9f6dd548f9c4df976ddae96dcec91a756768c2fe3bee88e913c489512fed04",
                "Source": "/var/lib/docker/volumes/8e9f6dd548f9c4df976ddae96dcec91a756768c2fe3bee88e913c489512fed04/_data",
                "Destination": "/data",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
#  "Source": "/var/lib/docker/volumes/8e9f6dd548f9c4df976ddae96dcec91a756768c2fe3bee88e913c489512fed04/_data", 这一行就是宿主机与容器挂载目录对应位置

说明:

  • docker自动创建的数据卷位于/var/lib/docker/volume下
  • 可以使用 docker inspect 容器的ID号查看到自动创建的数据卷
  • 容器删除创建的数据卷也会跟着删除

3. 使用docker volume手动创建数据卷后再挂载到容器中

a. 创建数据卷

[root@5 docs]# docker volume create aa
aa
[root@5 docs]# docker volume ls
DRIVER    VOLUME NAME
local     8e9f6dd548f9c4df976ddae96dcec91a756768c2fe3bee88e913c489512fed04
local     50afb513f55db09c5a591956125f69b3e093e1eddc8f6acc583de9e30124b605
local     533d999d582bc69bf22177f2fd0d36dfbdcc687214b5342cf5e3d8a4fc9c4c4f
local     aa
local     e64aa9a57bd828eb783146c061237a982d6f2ff96d77a83c9c039e77d478ad0a
local     fdaedb4efd5b2b25496e6a647b32c71e8bb5df1f2148a98a28191e94c8d0c286
local     pgdata

# 注: 使用 docker volume prune 可以清理所有没有被容器使用的匿名卷

b. 利用创建的数据卷启动容器

docker run -it --rm -v 数据卷名:/data busybox:latest

说明:

  • docker创建的数据卷位于/var/lib/docker/volume/数据卷名;
  • 可以使用docker inspect 容器的ID号查看到创建的数据卷;
  • 删除容器后创建的数据卷依然存在,可以使用docker volume rm 数据卷名删除
[root@5 docs]# docker run -it --rm -v aa:/data busybox:latest
/ # echo "abcde">/data/c.txt
/ # exit

验证数据是否实现了持久化

[root@5 docs]# docker run --name test04 -it --rm -v aa:/data busybox:latest
/ # ls /data
c.txt
/ # cat /data/c.txt 
abcde
/ # exit

删除数据卷

[root@5 docs]# docker volume rm aa
aa
[root@5 docs]# docker volume ls
DRIVER    VOLUME NAME
local     8e9f6dd548f9c4df976ddae96dcec91a756768c2fe3bee88e913c489512fed04
local     pgdata

4. 容器数据的共享

Ⅰ. 容器与宿主之间实现共享

利用数据卷就可以完成数据共享。 -v 宿主机目录:容器挂载目录

Ⅱ. 容器与容器之间数据共享

a: 利用数据卷就可以完成。 -v 宿主机目录:容器挂载目录

不同的容器指定宿主机目录需要一致

b: 数据卷容器(容器直接数据存储)

①: 制作数据卷容器

[root@5 docs]# docker run --name dbdata -v /test:/data -it --rm busybox:latest
/ # 

②: 利用数据卷容器创建新容器testd1

[root@5 docs]# docker run --name test-d1 --volumes-from dbdata -it --rm busybox:latest
/ # ls data/
a.txt  b.txt

③: 利用数据卷容器创建新容器testd2(再打开一个新窗口)

[root@5 docs]# docker run --name test-d2 --volumes-from dbdata -it --rm busybox
/ # ls /data
a.txt  b.txt

④: 验证test-d1和tst-d2容器之间的数据同步

在test-d2中创建一个新文件

/ # echo "123">>/data/c.txt

在test-d1容器上可以查看到该文件

/ # cat /data/c.txt
123

总结: 同一台宿主机上不同容器之间数据的共享

  • a: 不同容器使用相同宿主机的目录进行挂载 -v 宿主机目录:容器的目录
  • b: 不同的容器使用相同宿主机的数据卷 -v 数据卷吗:容器的目录
  • c: 将一个容器作为数据卷容器。其他的不同容器使用相同的数据卷容器。 --volumes-from 数据卷容器名