Docker设置IPV6地址

一般Docker都是直接使用IPV4地址就行,但是一些特殊的镜像就需要容器内有IPV6地址用起来效果才好。像qt这些下载软件。我不用这个,但是用adguardhome设置DNS服务器,所以要求ipv6能通。
当我们开通IPV6以后,一般客户端会同时存在多个 IPv6 地址:

  • Loopback 地址:::1,等价于 IPv4 中的 127.0.0.1
  • 链路本地地址(Link Local Address):fe80::/10 网段,只在区域中是合法地址,类似于 IPv4 中的 169.254.0.0/16。fe80开头 不可路由,电脑自动生成
  • 唯一区域地址(Unique Local Addresses):局域网地址,只能用于本地通信,和 IPv4 的专用网络地址 10.0.0.0/8172.16.0.0/12192.168.0.0/16 类似,在 RFC 4193 中定义。固定前缀是 fc00::/7,分为 fc00::/8fd00::/8 两部分,fc00::/8 目前作为保留地址没有定义,fd00::/8 是现在使用的 ULA 地址,其中 40bit 随机生成以避免冲突,可以使用 ULA 生成工具 来生成。
  • 全局地址(Global Address Type):通常意义上的公网地址,以 2XXX: 开头。但 2002: 开头的是特殊的 6to4 过渡地址,不是原生的纯 IPv6 网路地址。电信的是240e开头,联通2408开头,移动2409开头
  • 本地站点地址(Site Local Address):fec0::/10 网段,私网地址,目前在 RFC 规范中已被废弃


    image.png

参考:macvlan 为 Docker 配置 IPv6

1. IPV6地址获取方式

在路由器中开启ipv6时,会让选择获取方式,不同系统获取方式显示的稍有不同。我这里了解到大约几种,大家可以对照自己的看一下。
需要明确:无状态和有状态,仅仅指的是IPv6地址的获取方式。

1.1 SLAAC

SLAAC( Stateless Address Autoconfiguration,无状态地址配置)是IPv6地址自动配置协议的一种,主要用于在网络上进行IPv6地址的分配。
SLAAC是IPv6的内置特性,是通过网络前缀和MAC地址构造IPv6地址的方式来实现地址配置。它不需要任何服务器或其他配置信息,且可以快速地完成地址配置。SLAAC是一种基于前缀的地址配置方法,使用前缀将一个ipv6地址划分为IPv6网络地址和IPv6主机地址两部分,网络地址由网络管理员配置,而主机地址由主机本地自动产生。对于一个无状态的网络环境,它是一种简单快捷的方式。
SLAAC通过局域网中节点自动就近获取IP地址,提高了地址分配的利用率,减少了管理员的工作量。但是,SLAAC在地址分配时缺乏安全性,犯罪分子可能会通过MAC地址来获取到IPv6地址。同时,SLAAC无法为节点提供其他配置(如DNS信息等),对于像VoIP和视频会议等应用是不利的。
我用的老毛子潘多拉固件,开启ipv6后,就是用的这种获取方式。

1.2 DHCPv6

DHCPv6 (Dynamic Host Configuration Protocol version 6) 与SLAAC不同的是,DHCPv6(有状态,stateful)是一种动态IP地址分配,且需要在网络中使用DHCP服务器。
DHCPv6是一种动态IP地址分配方法,它通过DHCP服务器和客户端之间的数据交换,完成IPv6地址的配置。对于网络管理员来说,他需要配置DHCP服务器信息,而客户端需要启用DHCP协议。DHCPv6可以用于分配地址及其他IPv6配置信息(如DNS服务器信息),使用起来更加灵活,在基于状态的网络环境中十分实用。
DHCPv6具有更高的优先级,它可以分配到IPv6地址以外的配置信息,例如网关、DNS服务器等,更满足实际的需要。但是,DHCPv6需要网络管理员提供专用的DHCP服务器,大大增加了管理员的管理量和维护成本,同时,服务器出现故障将会导致客户无法分配IPv6地址

1.3 SLAAC+DHCPv6

地址由slaac获取,但是DNS由DHCPv6通告


注意:上面是IPV6地址获取方式,但是有的路由器中是没有上面的内容的。而是让你选择 ipv6 的连接方式,一般的有桥接、Native模式、NAT6模式等。
1. Native
Native模式意味着原生支持,即设备直接使用IPv6地址进行通信,无需转换或隧道化。
Native模式适用于多数情况,它类似于DHCP(动态主机配置协议)自动分配IPv6地址。在这种模式下,设备可以获得公网IPv6地址,能够直接访问公共互联网。
2.NAT6模式
NAT6是Network Address Translation for IPv6的缩写,即IPv6网络地址转换。使用NAT6模式时,尽管终端设备可以获得IPv6地址,但这个地址是局域网的IPv6地址。在这种模式下,终端设备只能在局域网内部使用IPv6地址进行通信,无法直接访问公共互联网。它适用于路由器做管理网关的IPv6地址前缀代理,且上一级为光猫拨号的情况。


2. Docker 的 IPv6 支持

为 Docker 配置 IPv6 有三种常见的思路。

    1. 一种是通过 HOST 模式,直接使用主机网络,但是可能引来外部扫描和攻击,存在十分严重的安全性问题。尤其是用来挂bt的,被别人看的一清二楚。IPv6 号称可以为每一粒沙子都分配一个 IP 地址,因此完全可以为每个容器都分配一个独立的 IPv6 地址,重新找回 IPv6 超大地址空间的安全优势。
      这种方式虽然获取到了IPV6地址,且大部分情景下使用没问题,但特殊场景受限于 docker的网络模型也会有一定的弊端。-Docker网络 - 简书
    1. 第二种是启用官方的 IPv6 支持,在官方文档中有说明,但是启用后仅能获取到私网(link-local)IPv6 地址,想要获取公网(global)IPv6 地址,还要指定 --fixed-cidr-v6,在目前国内运行商随机分配前缀的情况下,配置较为麻烦。
    1. 第三种也就是本文使用的方法是通过 macvlan,为 docker 创建一个支持 IPv6 的网络,自动从上级路由获取公网 IPv6 地址。
    docker network create -d macvlan --subnet=192.168.1.0/24 --gateway=192.168.1.1 --ipv6 --subnet=240x:xxxx:xxxx:xxxx::/64 --gateway=240x:xxxx:xxxx:xxxx::1 -o parent=eth0 adnet
    
    • docker network create -d macvlan 指定创建的网络类型是macvlan
    • --subnet=192.168.1.0/24 macvlan的ipv4网段,这里写你的内网网段即可,最后一位是0(/24默认不要动)
    • --gateway=192.168.1.1 macvlan的ipv4网关,最后一位是1(其实就是路由器的本地IP地址)
    • --ipv6 启用ipv6支持
    • --subnet=240x:xxxx:xxxx:xxxx::/64 macvlan的ipv6前缀
    • --gateway=240x:xxxx:xxxx:xxxx::1 macvlan的ipv6网关(其实就是前缀前4个网段::1)
    • -o parent=eth0 桥接网络走的是eth0接口(也就是前面我们ifconfig命令得出的接口名称)
    • adnet macvlan网络的名称,可以随意更改

    其中,ipv6的前缀可以用命令获取:ip -6 route show,自己那是什么就写什么。ipv6的网关可以不用写,会按规则自动生成

    image.png

    注意:使用macvlan网络时,由于指定了ipv6的前缀,而ipv6地址是不定时变化的。当ipv6地址变了,我们设置的前缀还是原来的,会不会出问题呢?我确实遇到了这个问题,但是目前用macvlan网络的容器(我是adguardhome)还是能正常访问ipv6的,我也搞不懂为什么。也不知道怎么处理,就先这样用着。
    Docker安装AdGuard Home,接入路由器,过滤局域网广告 - 简书

3. macvlan模式下,容器和宿主机互通

在 macvlan 模式下,出于安全考虑,默认禁止宿主机与容器的通信,也就是宿主机无法访问以及反代容器。但是局域网中的其他设备可以访问到容器。此时的网络拓扑如下图所示,可以将接入 macvlan 的容器看作一个直接接入局域网的设备(蓝色线),只是无法与宿主机(以及宿主机中使用 brigde 模式的设备)直接通信(红色线)。

网络拓扑

但 macvlan 之间可以通信,因此通过新建一个虚拟接口,然后修改路由,使得主机 <-> 容器变为主机 <-> 虚拟接口 <-> 容器,就可以打通容器与宿主机之间的通信。

参考:https://blog.xm.mk/posts/73f9/

3.1 配置
    1. 创建虚拟网卡接口,类型macvlan
    ip link add joinnet link eth0 type macvlan mode bridge
    
    1. 设置网卡接口ip
    ip addr add 192.168.1.245 dev joinnet
    
    1. 启动接口
    ip link set joinnet up
    
    1. 设置路由,宿主机和容器打通,此处添加的是容器IP
    ip route add 192.168.1.110 dev joinnet
    

至此,即可实现宿主机到容器的访问。
修改完成后的网络拓扑类似下图。通过手动配置静态路由,将 192.168.1.110 的路由指向新建的 joinnet虚拟接口,由于该接口视作一个局域网设备可以访问到容器,因此从主机 -> 容器变得可达。(粉色线)
反过来,若是 macvlan 下的容器需要访问主机,直接访问主机 IP 也是不通的(红色线),但此时访问主机可以直接使用虚拟接口的 IP 来替代(绿色线),即在 macvlan 容器下使用 192.168.1.245:port 即可正常访问到主机服务。


打通后
3.2 开机自动配置

由于上面的虚拟网络接口配置在宿主机重启后会丢失,因此需要创建开机启动脚本,以实现自动配置。

    1. 网络配置脚本 net_docker_macvlan.sh
    #!/bin/bash
    
    # macvlan 接口名称[可修改]
    MACVLAN_INTERFACE="joinnet"
    # 桥接网口[需修改]
    PARENT_INTERFACE="eth0"
    # macvlan 接口 IP [需修改]
    IP_ADDRESS="192.168.1.245/24"
    # 所有路由列表 [需修改]
    ROUTES=("192.168.1.110" "192.168.1.111")
    
    start_macvlan() {
        ip link add $MACVLAN_INTERFACE link $PARENT_INTERFACE type macvlan mode bridge
        ip addr add $IP_ADDRESS dev $MACVLAN_INTERFACE
        ip link set $MACVLAN_INTERFACE up
        for route in "${ROUTES[@]}"; do
            ip route add $route dev $MACVLAN_INTERFACE
        done
    }
    
    stop_macvlan() {
        for route in "${ROUTES[@]}"; do
            ip route del $route dev $MACVLAN_INTERFACE || true
        done
        ip link set $MACVLAN_INTERFACE down || true
        ip addr del $IP_ADDRESS dev $MACVLAN_INTERFACE || true
        ip link del $MACVLAN_INTERFACE || true
    }
    
    case "$1" in
        start)
            start_macvlan
            ;;
        stop)
            stop_macvlan
            ;;
        *)
            echo "Usage: $0 {start|stop}"
            exit 1
    esac
    

赋予脚本可执行权限:sudo chmod +x ./net_docker_macvlan.sh

    1. 设置上面的脚本开机自启
      创建自启脚本:sudo vim /etc/systemd/system/net_docker_macvlan.service,内容如下:
    [Unit]
    Description=Setup macvlan shim for docker to allow to route to host
    BindsTo=docker.service
    Requires=docker.service
    After=docker.service
    
    [Service]
    Type=oneshot
    ExecStart=/usr/xxx/xxx/xxx/net_docker_macvlan.sh start
    ExecStop=/us/xxx/xxx/xxx/net_docker_macvlan.sh stop
    RemainAfterExit=yes
    Restart=no
    
    [Install]
    WantedBy=multi-user.target
    

如果是群晖用户,由于群晖的 docker systemed 不是 docker.service,因此需要修改 BindsTo、Requires 和 After,根据 DSM 版本不同,服务名称可能也不同,可以通过以下方式查看:systemctl list-units --type=service | grep docker
当然也可以使用 network.target,当网络服务设置完成后启动,不强制依赖 docker,是一种更宽松的设置方式。

最后使用 systemctl start net_docker_macvlan启动脚本了。
systemctl enable net_docker_macvlan开机自启

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容