用ovs让bitcomet容器连接上ipv6

需求:

  • 运营商有提供ipv6
    
  • 设备支持ipv6
    
  • linux主机
    
  • 安装好docker
    
  • 拉好bitcomet镜像
    

以下步骤都是以root身份进行。
步骤:
首先得知道要给ovs的物理网口叫什么名字。我的叫ens32。
ip a

安装openvswitch-switch,我不知道你们用的是哪个linux的版本,我用debian。
apt install openvswitch-switch -y
然后新建个叫ovsbr0的bridge。
ovs-vsctl add-br ovsbr0
为了ovsbr0可以连上网,需要接上个物理网口。温馨提示,进行以下命令会让这物理网口ens32的网络断开!!!
ovs-vsctl add-port ovsbr0 ens32

如果有2个及以上端口,忽略/* 到*/的内容。
/*
如果是只有这物理网口的话,用以下命令创建个叫host的虚拟网口让宿主机连上网络。
ovs-vsctl add-port ovsbr0 host – set Interface host type=internal
当然现在是没网络的,必须得设置,当然设置网络得看用的是什么网络管理器,我没用NetworkManager和Systemd,所以直接编辑/etc/network/interfaces。

auto ens32
allow-hotplug ens32
iface eno1 inet manual

auto host
allow-hotplug host
iface host inet dhcp
iface host inet6 auto

然后重启下网络。方法和网络管理器有关。
service networking restart
*/

新建个bitcomet容器,网络必须为none.

services:
    sandbox:
        container_name: bitcomet
        image: wxhere/bitcomet:latest
        volumes:
            - /mnt/docker/appdata/BitComet:/home/sandbox/.config/BitComet:rw
            - /mnt/Downloads:/home/sandbox/Downloads:rw
        network_mode: none
        environment:
            - VNC_PASSWORD=123456
            - HTTP_PASSWORD=123456
            - USER=sandbox
            - PASSWORD=123456

然后手动给容器分配ip。ovsbr0是前面建的bridge,eth0好像是所有容器的默认网口,bitcomet是容器名称,192.168.0.80/24是我给容器设的ipv4的ip,192.168.0.1是我的网关。至于ipv6,SLACC会通过RA自己获得,只要路由器设置好就行了。
ovs-docker add-port ovsbr0 eth0 bitcomet –ipaddress=192.168.0.80/24 –gateway=192.168.0.1
成品图长这样,TCP和UDP在路由器上端口映射就绿灯了。截图完,我就重新拨号了,不用担心我的ip。这容器也会删除。

容器重新启动后,namespace改变,虽然veth还存在,但是容器是不会接上该veth的,因为该veth与容器现在的namespace不同,所以容器会断网。
所以现在示范下如何用systemd管理bitcomet连接的veth。
首先创建个容器启动后连接新veth的service,例如/etc/systemd/system/ovs-docker-start@bitcomet.service:

[Unit]
Description=Bind OVS port to container bitcomet
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
ExecStart=/bin/bash -c "docker start bitcomet"
ExecStartPost=/bin/bash -c "sleep 5 && ovs-docker add-port ovsbr0 eth0 bitcomet --ipaddress=192.168.0.80/24 --gateway=192.168.0.1"

[Install]
WantedBy=multi-user.target

再创建个删除veth后停止容器的service,例如/etc/systemd/system/ovs-docker-stop@bitcomet.service:

[Unit]
Description=Stop bitcomet and remove OVS port
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
ExecStart=/bin/bash -c "ovs-docker del-port ovsbr0 eth0 bitcomet && docker stop bitcomet"

[Install]
WantedBy=multi-user.target

我们只是创建了service,但是systemd是不会自动运行它们的,我们只需要让start service在docker启动后自动启动bitcomet,所以:

systemctl enable ovs-docker-start@bitcomet.service
systemctl start ovs-docker-start@bitcomet.service

在不重启docker的情况下,停止bitcomet就用:
systemctl start ovs-docker-stop@bitcomet.service
再次启动bitcomet就用:
systemctl start ovs-docker-start@bitcomet.service
我相信你们会写restart的service。

问题是docker重启了该怎么办。如果直接重启,重启后的容器namespace变了,旧veth没有被删除,start service会报错,ovs-docker会抱怨旧veth还存在,不会给容器联网,所以容器断网。所以我们需要编辑docker service:
systemctl edit docker.service
请务必看清编辑的位置,加入以下内容:

[Unit]
Description=Stop bitcomet and remove OVS port
After=network.target

[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecStop=/bin/bash -c "ovs-docker del-port ovsbr0 eth0 bitcomet"
TimeoutStopSec=10
Restart=on-failure

[Install]
WantedBy=multi-user.target

没错,就是有2个ExecStart,而且第一个是空的。你们可以用这命令验证自己有没有写错:
systemd-analyze verify /usr/lib/systemd/system/docker.service
没错的话就:
systemctl daemon-reload
这样在docker启动时,bitcomet会自动接上ovs-docker的veth。在docker关闭时,ovs-docker可以删除旧veth。bitcomet会像正常设备一样接上lan,ipv4是nat的,有ipv6就能获得GUA。要是还是黄灯,那肯定是防火墙的问题。
冷知识:虽然ipv6的GUA是公网ip,不用nat,但是还是要经过路由器。包送不送,还得看路由器给不给。