Docker网络模式踩坑

前言

这篇笔记源自上次 Docker 下搭建 Redis 哨兵集群所踩的坑,主要原因是 Docker 默认的网络模式是 Bridge,而在设置哨兵的 matser IP 时用的是容器的内网地址,在 Spring Boot 中使用 Redis 时哨兵返回的仍是 Docker 的内网地址。

解决办法是加入 docker 启动参数 --network=host,改为 host 模式启动,并将 master 节点 IP 改为 host 的外网地址,此时的 Redis 集群是直接暴露在公网的,一定要设置 requirepass

借此机会,顺便学习一下 Docker 的网络模式。

Docker 的网络模式

Dcoker 网络隔离基于 Network namespace,创建 Docker 容器时会为每一个容器分配 Network namespace。

创建 Docker 容器时有以下几种网络模式:

  • Bridge
  • Host
  • None
  • Overlay
  • Macvlan
  • Container

Docker 容器默认为 bridge 模式,其他模式需要在创建容器时使用 –-net 手动指定。

Bridge 模式

Bridge 模式下会在 host 上创建一个 名为 docker0 的虚拟网桥,此模式下的容器会桥接到这个虚拟网桥上,虚拟网桥会与 host 进行 IP 转换,端口映射等通信。

Docker 官方文档中这样说明 Bridge 的使用场景:

“ Bridge networks are usually used when your applications run in standalone containers that need to communicate. “
Bridge 网络通常用于应用程序在需要通信的独立容器中运行时的场景下。

Host 模式

指定方法:--net="host"

Host 模式删除了容器与 host 之间的网络隔离(“remove network isolation between the container and the Docker host”),此模式下创建的容器没有自己独立的 Network namespace,而是和 host 共享一个 Network namespace 并且共享 host 的所有端口与 IP。

通过这种模式创建的容器可以访问看到 host 上所有的网络设备,由于这种方式创建的容器有极高的访问权限,所以被认为是不安全的。

None 模式

指定方法: --net="none"

None 模式下创建容器不会为容器配置任何网络参数,需要用户自己设定,这种方式可以实现更加灵活复杂的网络。

Overlay 模式

Overlay 模式可以令不同 host 之间的容器进行通信。

Macvlan 模式

Macvlan 模式下可以将一个 MAC 地址分配给一个容器,使其在网络上显示为一个物理设备。

Container 模式

指定方法:--net="container:name or id"

Container 模式和 Host 模式很类似,该模式下创建的容器也没有自己独立的 Network namespace,而是和某个指定的容器共享同个 Network Namespace。但此时容器共享的是其他某个容器的 IP 和端口而不是 host 的,容器也不会创建自己的网卡,配置自己的 IP,而是和指定的容器共享 IP、端口范围。

Docker 默认的网络环境下,单台 host 上的容器可以通过 docker0 网桥直接通信,而不同 host 上的容器之间只能通过在 host 上通过端口映射进行通信。这种端口映射方式对很多集群应用来说极不方便,解决办法是让 Docker 容器之间直接使用自己的IP地址进行通信,按实现原理可分为直接路由方式、桥接方式(如pipework)、Overlay 隧道方式(如flannel、ovs+gre)等。

哨兵集群的解决办法

1
2
3
4
5
6
7
8
9
10
11
12
# master与slave都改为host模式启动
$ docker run -it --name redis-master --network=host -d -v /root/download/redis.conf:/usr/local/etc/redis/redis.conf -d redis /bin/bash
$ docker exec -it redis-master bash
$ redis-server /usr/local/etc/redis/redis.conf

$ docker run -it --name redis-slave1 --network=host -d -v /root/download/redis2.conf:/usr/local/etc/redis/redis.conf -d redis /bin/bash
$ docker exec -it redis-slave1 bash
$ redis-server /usr/local/etc/redis/redis.conf

$ docker run -it --name redis-slave2 --network=host -d -v /root/download/redis3.conf:/usr/local/etc/redis/redis.conf -d redis /bin/bash
$ docker exec -it redis-slave2 bash
$ redis-server /usr/local/etc/redis/redis.conf

其中 redis-master 的 redis.conf:

1
2
3
4
5
6
# 注释掉该字段,否则只允许本机连接
# bind 127.0.0.1
port 6379
daemonize yes
requirepass yourpassword
masterauth yourpassword

注意 redis-slave1 与 redis-slave2 的 redis.conf中还需加入:

1
replicaof <redis-master ip> <redis-master port>

1
2
3
4
5
6
7
8
9
# 哨兵也改为host模式启动
$ docker run -it --name redis-sentinel3 --network=host -d -v /root/download/sentinel3.conf:/usr/local/etc/redis/sentinel.conf -d redis /bin/bash
$ docker exec -it redis-sentinel3 bash
$ redis-sentinel /usr/local/etc/redis/sentinel.conf

# 其他哨兵配置同上
...
...
...
  • 本文作者: Marticles
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!