前言
最近在做项目的时候,许多中间件和软件的下载与配置都是在本机WSL2下完成的,十分的繁琐。在使用InfluxDB持久化Prometheus数据时,始终无法连接本机的InfluxDB,卸载重新安装后还出现了一堆其他错误,终于这成为了压死我的最后一根稻草。因此,我选择用半天多的时间将项目所用到的软件与中间件迁移至Docker,以绝后患。在迁移至Docker后,容器之间的互相访问是一个需要解决的问题,本文将对Docker的容器之间访问策略进行记录。
策略一:默认桥接网络
当启动Docker容器时,如果命令中不指定容器所使用的网络,那么Docker会为容器提供一个默认桥接网络docker0,我们通过docker inspect指令查看容器元数据可以看到以下内容
容器元数据
如果在一个容器中使用localhost:端口号是访问本容器的端口,而不是访问其他容器的端口。在元数据中我们可以看到默认分配的IPAddress,其他容器可以使用该IP地址访问本容器。
但是如果容器重启,Docker会根据启动顺序分配IPAddress,也就是说IPAddress会动态变化,这导致容器配置需要在每次重启时修改(除非你保证每次启动容器时的顺序都一样)。因此这种方法并不实用。
策略二:--link参数
在容器启动时,我们可以添加--link <容器名>参数的方法来连接两个容器,这种方法要求容器之间有先后启动的顺序之分,如果容器数量过多,那么使用--link工作量极大。并且Docker官方已经将--link标记为弃用,说不定在哪个版本就会删除--link参数,所以这种方法并不建议。
官方警告
策略三:用户自定义网络
我们可以使用以下指令创建自定义网络,然后在启动容器时使用--network参数指定自定义网络
css
docker network create -d bridge my-net
docker run --network=my-net -itd --name=container3 busybox
我们可以使用docker network ls指令展示docker现有的网络。。
其中bridge就是策略一中讲到的默认桥接网络。
host则是不给容器分配Network Namespace,也就是说容器不会自己模拟网卡、ip地址等信息,而是跟宿主机共同使用ip地址和端口,但是这种方式会导致无法区分宿主机和容器。
mynet是我自定义的网络。
none是不使用网络,即外部不可以访问容器内部。
可以看到用户自定义网络和默认桥接网络都是用brdige这种网络驱动,那么它们的区别是什么呢?
- 用户自定义网络提供容器之间的自动 DNS 解析,也就是说可以通过容器名:端口号的方式访问其他容器
- 用户自定义网络提供更好的隔离,默认网络会让所有的容器连接,这会带来一定的风险
- 用户自定义网络容器可以动态地与自定义网络连接和分离,即容器和网络是独立的,容器可以连接其他网络
- 用户自定义网络都是可配置的网桥,默认网络中所有的容器使用一个网络配置,而自定义网络可以再对网络内容器进行更细粒度的配置划分
- 默认桥接网络上的容器共享环境变量,而用户自定义网络不可以
以下是官方文档的原文
Differences between user-defined bridges and the default bridge
User-defined bridges provide automatic DNS resolution between containers .Containers on the default bridge network can only access each other by IP addresses, unless you use the f="https://docs.docker.com/network/lin...">--link option, which is considered legacy. On a user-defined bridge network, containers can resolve each other by name or alias.
Imagine an application with a web front-end and a database back-end. If you call your containers
web
anddb
, the web container can connect to the db container atdb
, no matter which Docker host the application stack is running on.If you run the same application stack on the default bridge network, you need to manually create links between the containers (using the legacy
--link
flag). These links need to be created in both directions, so you can see this gets complex with more than two containers which need to communicate. Alternatively, you can manipulate the/etc/hosts
files within the containers, but this creates problems that are difficult to debug.
User-defined bridges provide better isolation .All containers without a
--network
specified, are attached to the default bridge network. This can be a risk, as unrelated stacks/services/containers are then able to communicate.Using a user-defined network provides a scoped network in which only containers attached to that network are able to communicate.
Containers can be attached and detached from user-defined networks on the fly .During a container's lifetime, you can connect or disconnect it from user-defined networks on the fly. To remove a container from the default bridge network, you need to stop the container and recreate it with different network options.
Each user-defined network creates a configurable bridge .If your containers use the default bridge network, you can configure it, but all the containers use the same settings, such as MTU and
iptables
rules. In addition, configuring the default bridge network happens outside of Docker itself, and requires a restart of Docker.User-defined bridge networks are created and configured using
docker network create
. If different groups of applications have different network requirements, you can configure each user-defined bridge separately, as you create it.
Linked containers on the default bridge network share environment variables .Originally, the only way to share environment variables between two containers was to link them using the f="https://docs.docker.com/network/lin...">--link flag. This type of variable sharing isn't possible with user-defined networks. However, there are superior ways to share environment variables. A few ideas:
Multiple containers can mount a file or directory containing the shared information, using a Docker volume.
Multiple containers can be started together using
docker-compose
and the compose file can define the shared variables.You can use swarm services instead of standalone containers, and take advantage of shared secrets and configs.
Containers connected to the same user-defined bridge network effectively expose all ports to each other. For a port to be accessible to containers or non-Docker hosts on different networks, that port must be published using the
-p
or--publish
flag.