由于格式和图片解析问题,为了更好的阅读体验,可以前往 阅读原文
docker中网络的概念也是非常重要,它对于容器资源的隔离也起着非常重要的作用。
你有没有在启动一个容器后查看它的ip,假如你启动了一个nignx
容器,你想在主机上访问它,首先得知道他的ip地址,可以通过以下方式获取:
sh
docker inspect nginx |grep -A 20 Networks
# ...
"Networks": {
"bridge": {
# .....
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16
}
}
可以查看nginx
容器的网关为172.17.0.1
,ip地址为172.17.0.2
,在虚拟机上访问nginxcurl 172.17.0.2
发现是可以访问到nginx页面,但是当你从电脑主机浏览器上访问此ip地址就会访问不通
原理
Docker 网络的核心原理是通过创建网络命名空间和虚拟网络设备来实现容器间的网络隔离和通信。每个 Docker 容器都有自己的网络命名空间,其中包含了一个虚拟网络设备和一个 IP 地址。容器的网络命名空间使得容器内部的网络设备和 IP 地址与宿主机和其他容器隔离,从而实现了容器间的网络隔离和通信。
通俗的讲docker会在宿主机上创建一个默认的docker网桥(docker0172.17.0.1
),启动容器时会根据docker网桥的网络随机分配一个虚拟ip,同时docker网桥作为每个容器的默认网关,这样虽然每个容器的ip不一致,但是都是处于同一个网关下,所以容器间都可以通过docker0网关进行访问。
因为docker0网关是在主机上虚拟出来的,只能内部进行访问,外部是无感的无法访问到的。通过ip a
或 ifconfig
查看主机上的docker0虚拟网卡:
sh
ip a | grep -A 5 docker0
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
从中看出docker0分配的网络为172.17.0.1/16
,其前16位是个网络地址,后16位是主机地址,在这个子网中,可以分配的有效 IP 地址范围是从 172.17.0.1
到 172.17.255.254
,共有 65534
个可用的 IP 地址。其中,172.17.0.0
是子网的网络地址,172.17.255.255
是子网的广播地址,不能被分配给主机。
访问过程
Docker 容器启动时,Docker 引擎会自动++创建一对 veth 设备,一个设备被添加到容器的网络命名空间,另一个设备则被添加到宿主机的网络命名空间中++ 。在容器内部,这个 veth 设备通常被命名为 eth0
,并被分配一个 IP 地址;而在宿主机上,这个 veth 设备通常被命名为 docker0,并被分配一个与容器在同一子网中的 IP 地址。
当容器需要与宿主机或其他容器进行通信时,数据包将通过容器内部的 veth 设备发送到宿主机的虚拟网桥,然后再通过宿主机的 veth 设备转发到目标容器或宿主机的网络命名空间中。
网络类型
Docker 提供了多种网络类型和网络驱动,以满足不同场景下的网络需求。以下是 Docker 支持的主要网络类型:
bridge
:bridge 网络是 Docker 默认的网络类型,它使用 Linux 的虚拟网桥docker0实现容器间或与宿主机之间的通信。在 bridge 网络中,每个容器都会分配一个唯一的 IP 地址,并通过一个虚拟网桥连接到宿主机的网络中host
:host 网络是一种特殊的网络类型,它允许 Docker 容器直接使用宿主机的网络设备和 IP 地址,与宿主机共享网络栈。在 host 网络中,容器不会被分配独立的 IP 地址,而是直接使用宿主机的 IP 地址none
:none网络是一种完全隔离的网络类型,它不为容器分配任何网络资源,容器内部无法访问外部网络,也无法被外部网络访问container
:新建的容器不会创建自己的网卡而是共同使用指定容器的,除了网络外,其他如文件系统等等都是隔离的,关闭目标container,将会变为none自定义网络
:前者在容器内只能通过ip进行通信,不能通过容器名进行通信,而ip又是动态的,可能会随时变化,而docker允许你使用自定义网络,新建的网络默认是桥接bridge,集群里同一个服务里的所有容器使用自定义网络时,可以通过容器名进行访问,这种方式常用
除了上述网络类型外,Docker 还支持使用第三方网络驱动来实现自定义的网络类型和网络功能。例如,可以使用 Calico 网络驱动实现高级的网络功能,如策略路由、安全组、网络隔离等。
网络列表
在没有创建自定义网络的条件下,docker默认会存在三种网络:桥接(brige)、宿主机(host)、none
sh
➜ docker network ls
NETWORK ID NAME DRIVER SCOPE
3d9d929e9d34 bridge bridge local
73acd36f196e host host local
f71a4582a6c0 none null local
创建网络
创建自定义网络mynetwork
:
sh
➜ docker network create mynetwork
c1f9f873cb89c803a905f3a8c61aed4bc8ab3f9184d00fa0327a9a6dfc6d70b7
➜ docker network ls
NETWORK ID NAME DRIVER SCOPE
3d9d929e9d34 bridge bridge local
73acd36f196e host host local
c1f9f873cb89 mynetwork bridge local
f71a4582a6c0 none null local
使用网络
在创建和管理容器时,可以指定容器使用的网络类型和网络配置,这里演示多个容器使用同一个网络,并采用容器名的方式方式进行访问
- 创建一个busybox并使用自定义网络,查看其ip为
172.18.0.2
sh
➜ docker run -it --network mynetwork --rm --name busybox busybox /bin/sh
/ # 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
22: eth0@if23: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0
valid_lft forever preferred_lft forever
- 创建一个alpine使用自定义网络,查看其ip为
172.18.0.3
sh
➜ docker run -it --network mynetwork --rm --name alpine alpine /bin/sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
24: eth0@if25: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.3/16 brd 172.18.255.255 scope global eth0
valid_lft forever preferred_lft forever
两个容器创建好后,尝试分别使用ip和容器名的方式ping对方,看是否能ping通:
-
使用ip方式:
sh# busybox / # ping 172.18.0.3 PING 172.18.0.3 (172.18.0.3): 56 data bytes 64 bytes from 172.18.0.3: seq=0 ttl=64 time=1.588 ms 64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.475 ms # alpine / # ping 172.18.0.2 PING 172.18.0.2 (172.18.0.2): 56 data bytes 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.163 ms 64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.410 ms
-
使用容器名:
sh# busybox / # ping alpine PING alpine (172.18.0.3): 56 data bytes 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.246 ms # alpine / # ping busybox PING busybox (172.18.0.2): 56 data bytes 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.246 ms
采用服务名的方式在集群系统里是常见的,他解决ip动态改变,而不需要频繁改ip地址的问题,其内部本质还是将名字和ip进行的动态绑定,添加了对应的DNS记录,这样就可以知道服务的ip了
总结
Docker一个重要概念是容器间的DNS服务。Docker默认提供了一个DNS服务,使得容器可以通过容器名称或服务名称来互相访问。Docker DNS 服务基于 Docker 内置的 DNS 服务器实现,每个容器都可以通过 docker.internal 域名来访问其他容器。
总的来说,Docker 网络的核心原理是通过创建网络命名空间和虚拟网络设备来实现容器间的网络隔离和通信,同时提供了多种网络模式和网络驱动,以满足不同场景下的网络需求。
本篇来讲docker数据卷(volume)的使用,那为什么要使用数据卷呢?通过前面文章的学习,大家都了解了如何去运行一个容器。假如你在本地测试运行一个mysql
的容器,为你的本地应用程序做持久化服务,但当你删除这个容器后重新启动一模一样的容器,再次查看会发现数据都不见了,当然了你可能不会自己删除,但如果是团队使用呢,那就会有数据丢失的风险。因此docker中引入了数据卷的概念,用来做数据持久化的。
概念与作用
Docker 数据卷是 Docker 容器持久化存储的重要组成部分。它允许用户将容器中的数据与容器实例分离,使数据持久化,方便数据的管理和迁移。Docker 数据卷(Docker Volumes)是一种特殊的目录,可以在容器之间共享和重用。数据卷可以在容器之间传递数据,而不需要使用联合文件系统。数据卷在 Docker 主机上独立于容器生命周期而存在,即使容器被删除,数据卷也不会受到影响。这使得数据卷成为容器中数据持久化的理想选择。
使用Docker 数据卷相比使用容器储存来讲的好处有:
- 持久化存储数据:Docker 容器中的数据是存储在容器存储层中的,容器被删除或重建时数据也会被删除。使用数据卷可以将数据存储在宿主机上,即使容器被删除或重建,数据仍然可以保留。
- 方便数据共享:多个容器可以通过挂载同一个数据卷来共享数据,方便了数据的共享和备份。
- 更好的移植性:使用数据卷可以将容器与数据分离,使得容器更易于移植和部署。
- 更好的性能:使用数据卷可以将容器中的数据存储在宿主机上,可以减少容器存储层的使用,提高容器的性能。
:::tip
容器使用卷的本质其实就是文件或路径的挂载,类似与linux或dfs这种文件系统的挂载。
:::
卷的类型
Docker 数据卷(volume)可以分为三种类型:主机挂载(host-mounted)、命名卷(named volume)和临时卷(tmpfs volume)。
-
主机挂载
主机挂载是最基本的数据卷类型,它将宿主机上的目录或文件夹直接挂载到容器中。主机挂载的优点是简单易用,但缺点是不够灵活,容器与宿主机的路径绑定较为紧密。
-
命名卷
命名卷是 Docker 引擎管理的卷,可以在多个容器之间共享和重用。命名卷的优点是灵活性大,容器与宿主机的路径解耦,可以在多个容器之间共享数据卷,但缺点是需要手动创建和管理。
-
临时卷
临时卷是一种轻量级的数据卷类型,仅存在于容器的生命周期中。临时卷的优点是方便快捷,不需要手动创建和管理,但缺点是数据不会持久化,容器停止后数据会丢失。
卷的使用
docker卷也是其一种对象资源,和其他如镜像、容器资源类似都有创建、查看、删除等相关的命令
创建
卷的创建指的是命名卷的创建,docker volume create
是 Docker 命令行工具提供的创建数据卷的命令。它用于创建一个新的 Docker 数据卷(Docker volume),以便将宿主机上的目录或文件夹挂载到 Docker 容器中。
sh
docker volume create name
使用docker创建的volume,其文件路径会被存放到
/var/lib/docker/volumes
文件路径下
查看
查看已经创建的数据卷,这里只能查看使用docker创建管理的卷,如果直接使用宿主机的文件或路径,没有经过docker管理,就不会包含在卷的列表中
sh
docker volume ls
➜ docker volume ls
DRIVER VOLUME NAME
local 1e1b4617ad8377a9b60029362215f35cc298c2d8d1c7fa5d1691d164795872c9
local 5cda6686c50d24138ea5285d035afb639e275b6cac3f0671dd8b3cf895eb3c3a
local 5e58646a0a1d133084a671b03b4878b730cba730818e062edbecc539a6e6a80a
删除
删除卷会删除宿主机/var/lib/docker/volumes
路径下指定的文件夹
sh
docker volume rm name
# 删除名为 demo 卷
docker volume rm demo
挂载
在运行 Docker 容器时使用 -v
或 --mount
参数来指定数据卷的挂载方式
sh
# 使用数据卷
docker run -v someVolume:/path/on/container
# 使用宿主机路径
docker run -v /path/on/host:/path/on/container myimage
可以使用--mount
参数时指定数据卷的类型、权限等等
sh
# 使用宿主机路径
docker run --mount type=bind,source=/host/somedir,target=/path/on/container
# 使用命名卷,并添加 rw 读写权限,不写默认是读写
docker run --mount type=volume,source=myvolume:rw
# 使用临时卷
docker run --mount type=tmpfs,destination=/path/on/containter:rw
总结
本篇讲了docker数据卷的使用,它是一种持久化存储数据的机制,可以将容器内的数据持久化到宿主机上,或者在多个容器之间共享数据。使用 Docker 数据卷可以实现高效的数据管理和迁移,同时也可以提高容器的可移植性和灵活性。
由于格式和图片解析问题,为了更好的阅读体验,可以前往 阅读原文