如何通过 IPV6 访问 Qnap NAS 中 Docker 的服务
*作者:*夜法之书
*文章链接:*https://blog.17lai.site/posts/462f1e5c/
目前找到了两个解决方案
- socat 端口转发
- docker-ipv6nat
很早就和 QNAP 官方反馈请求支持 IPV6,但一直没反应
socat 端口转发
环境
- 系统:QTS 4.3.6
- 网络:IPV4 & IPV6
- Docker: 由 Container Station 提供
问题
通过 ipv6 地址可以打开 NAS 的管理页面,但是无法访问 Docker 对应端口的服务。
排查
QTS 中 Docker 使用的虚拟交换机网络没有启动 IPV6,且无法在虚拟交换机设置中手动启动。
这样一来,Docker 只监听了 tcp4 的端口,对于主机上 tcp6 的端口的访问无法映射到 docker 容器上。
解决方案
在主机上开一个 tcp6 的端口,将其转发到主机上与 docker 关联的 tcp4 端口。
即:
docker(tcp4)–>host(tcp4)–>host(tcp6)
-
在 qts 上安装包管理器:Entware. https://github.com/Entware/Entware/wiki/Install-on-QNAP-NAS
-
执行
opkg update
, 更新 -
安装端口转发工具,这里使用 socat:
opkg install socat
-
设置转发 host(tcp6)–>host(tcp4)
socat TCP6-LISTEN:6880,reuseaddr,fork TCP4:127.0.0.1:7880 &
-
大功告成
docker-ipv6nat
- IPv4 & IPv6 可以平等使用(端口可以在主机系统上共享)
- 容器并不完全在线,因为 Docker 容器并不总是以安全着称
步骤 1:
为 ip6tables NAT 安装内核模块。不幸的是,QNAP 没有自带这些模块,所以你必须自己构建它们。
谢天谢地,有人已经这样做并在 github 上发布了它。qnap-ip6tables_nat-module。在 Release 下,您已经可以在此处下载当前构建的模块。我将它们放在 Docker 容器的应用程序目录中:
/share/CACHEDEV1_DATA/Container/container-station-data/application/ipv6nat/kernel_mods/
然后,您必须确保在启动时加载这些模块。为此,必须在您的 autorun.sh 中输入以下行。
# ipv6-tables
# some required modules are already built into QTS, so you can load them with 'modprobe'
/sbin/modprobe ip6_tables
/sbin/modprobe nf_nat
/sbin/modprobe xt_MASQUERADE
# then load the new module
insmod /share/CACHEDEV1_DATA/Container/container-station-data/application/ipv6nat/kernel_mods/ip6table_nat.ko
您可以在 QNAP Wiki 中了解如何在您的 QNAP 模型上编辑此文件:Running_Your_Own_Application_at_Startup
添加模块后,您需要重新启动 NAS。
第 2 步:
为了设置 docker-ipv6nat 容器,我准备了一个 docker-compose 文件。您可以通过 Create 简单地将其插入 ContainerStation:
version: '3'
services:
ipv6nat:
container_name: ipv6nat
restart: always
image: robbertkl/ipv6nat
privileged: true
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /lib/modules:/lib/modules:ro
容器应该在终端上没有任何输出的情况下启动。不起眼…… 现在呢?创建也应该可以通过 IPv& 访问的容器时是否需要一些手动工作。至少我还没有通过 QNAP 界面找到更简单的方法。
如果需要,您必须为每个容器创建至少一个支持 IPv6 的网络。
为此,请通过 SSH 登录 QNAP 并创建一个新的 Docker 网络:
docker network create --ipv6 --subnet fd00:dead:beef::/48 ipv6net-1
当然,您也可以使用任何其他 ULA 范围 (fc00::/7)。
现在只需使用 ipv6net-1 作为容器的外部网络。这是一个小例子:
version: "3"
services:
alp1:
image: yeasy/simple-web:latest
ports:
- 80:80
networks:
- ipv6net-1
networks:
ipv6net-1:
external: true
现在您的容器端口来自 IPv4:
nmap <ipv4 ip> -p 80
PORT STATE SERVICE
80/tcp open http
也可以通过 IPv6 访问:
nmap <ipv6 ip> -6 -p 80
PORT STATE SERVICE
80/tcp open http
享受通过 IPv4 和 IPv6 托管您的服务的乐趣!
实操
遇到问题: robbertkl/ipv6nat 启动日志报错
开启防火墙使用到了 geoip 会遇到如下错误
iptables exit status 1: Can't find library for match `geoip'
可能的解决方案
- 编译支持 geoip
-
不使用 geoip
把防火墙中的规则设计到 geoip 的都修改为任何地区,防火墙规则设计的好,针对一个地区开发某些端口和针对所有地区开发端口基本一样的风险。
使用第二种方案,实际测试使用发现丢包率还不低!
# 在开启了ipv6的docker中运行如下命令
# ping6 2409:804c:2000:2::1
PING 2409:804c:2000:2::1 (2409:804c:2000:2::1): 56 data bytes
ping: getnameinfo: Temporary failure in name resolution
64 bytes from unknown: icmp_seq=1 ttl=57 time=4.073 ms
...
^Cping: getnameinfo: Temporary failure in name resolution
64 bytes from unknown: icmp_seq=24 ttl=57 time=3.654 ms
--- 2409:804c:2000:2::1 ping statistics ---
25 packets transmitted, 22 packets received, 12% packet loss
round-trip min/avg/max/stddev = 3.606/4.100/5.562/0.608 ms
Temporary failure in name resolution 似乎是 DNS 配置问题
测试 IPV6
Windows
以下 Windows 版本的ping
命令支持 ping IPv6 地址:
- Windows XP with SP1 及以上
- Windows Vista 及以上
- Windows Server 2003 及以上
ping ipv6 主机名
ping -6 ipv6.google.com
ping -6 ipv6.test-ipv6.com
ping -6 ipv6.baidu.com
/!\ 注意: 当 ping ipv6 主机名时,必须加上参数-6
;直接 ping IPv6 地址时可以省略。
ping ipv6 地址
ping IPv6Address[%ZoneID]
例如:
ping 2001:4860:0:2001::68
如果要 ping link-local 地址,则需要指定网络接口索引,如:
ping fe80::260:97ff:fe02:6ea5%4
其中 %4 表示 “用索引为 4 的网络接口”ping 目标计算机。
Linux
在 Linux 发行版中,使用ping6
命令 ping IPv6 主机或者地址。
ping ipv6 主机名
ping6 ipv6.google.com
ping ipv6 地址
ping6 IPv6Address[%InterfaceName]
如果要 ping link-local 地址,则需要指定网络接口名称,如:
ping fe80::260:97ff:fe02:6ea5%eth0
其中 %eth0 表示 “用网络接口 eth0 ping 目标计算机”。
ping dns
ping6 2409:804c:2000:2::1
ssh
ssh root@fe80::c09a:4363:5763:32%enpxxx(网卡名称)
chrome IPV6
Chrome 地址栏输入
about:net-internals/#dns
nginx 支持 ipv6
nginx 1.14 开始就默认支持 ipv6 了,不再需要添加编译参数 –with-ipv6,可以直接配置监听 ipv6
检查 nginx 是否监听了 ipv6
netstat -tuln
同时监听 IPV4 和 IPV6
server {
....
listen [::]:80;
listen [::]:443;
...
}
只监听 IPV6
server {
....
listen [::]:80 default ipv6only=on;
listen [::]:443 default ipv6only=on;
...
}
监听指定 IPV6 地址
{
....
listen [3608:f0f0:3002:31::1]:80;
listen [3608:f0f0:3002:31::1]:443;
...
}
重启 nginx
nginx -s reload
安全设置
暴露 Nas 到公网是会有很大安全隐患的,请注意你已经做好了安全防范!
- 开启动态安全码
- 开启防火墙,最好最高安全级别,自己控制端口开启
- 开启 IP 访问保护 失败登录尝试阻止时间调整
- 暴露出去的服务全部采用高强密码,最好所有服务全部采用高强度密码
- 尽量使用 Docker,而不是套件版软件服务
- 重要数据定期离线备份
IPv6: 为什么 Link-local 地址后面要有百分号 (%)?
由于所有的 link-local 地址都有相同的前缀 FE80::/64,并且每个网络接口都必须分配一个 link-local 地址,因而导致当发送数据包到一个 link-local 地址时,如果路由器使用普通的路由方法就无法决定选用哪个网络接口。因此,引入了一种被叫做 zone index 的标识符,它提供额外的路由信息,这个标识符通常指网络接口,并且通过一个百分号 (%) 被附加在 IPv6 地址后面。但是准确的表示方法还取决于操作系统:
Windows: 使用网络接口索引表示
如:
fe80::3%1
fe80::260:97ff:fe02:6ea5%4
要查看网络接口索引,请执行该命令:
netsh interface ipv6 show address
Linux: 使用网络接口名称表示
如:
fe80::3%eth0
fe80::260:97ff:fe02:6ea5%tun0
Linux 只需要ifconnfig
命令就可列出所有网络接口名称。
暂无评论内容