缘由

之前一直在 Archlinux 下部署整套 黑魔法服务,各种工具安装起来很方便,即使源里头没有,AUR 中一般也有其他人提供的 PKGBUILD, 根据此脚本构建适用于自己系统的包也是十分方便的。由于自己即将硕士毕业,这套服务还是放在学校的机房里为好,交大的外网带宽资源实在是太丰富了。:)

最近拿到的一台机器是 Ubuntu, 用作黑魔法服务还是有点麻烦,于是乎就搞了个基于 Arch 的 docker image,搞定之后发现要在 docker 中支持 IPv6 还是有点困难,弃疗后就转向原生的 Ubuntu 了。由于自己目前 ss 的出口共有 10 条线路,IPv4 和 IPv6 各 5 条,这种情况下用 HAProxy 做负载均衡、高可用和国内 ss 中转再好不过了。

问题分析

HAProxy 1.5 版本后是支持 IPv6 的,自己好几个 Arch 的机器用 HAProxy 1.6 都是能正常和 IPv6 的远程服务器连接的,所以从版本上来看在 Ubuntu 下使用 HAProxy 1.6 应该是可以支持的。HAProxy packages for Debian and Ubuntu 提供了 Debian/Ubuntu 下各版本的安装包。安装后发现 Ubuntu 14.04 下无论是 backports 还是 ppa 中提供的 1.5/1.6 都不支持解析 IPv6 的域名,然后 HAProxy 就直接报错退出了… 用 dig 测了下 AAAA 记录的解析是正常的,因此基本确定问题出在 HAProxy 上。

使用 haproxy -vv 可以看到 HAProxy 的详细编译构建信息,对比了 Ubuntu 和 Arch 下的信息,发现构建信息中 Arch 下多了这么一个关键的选项:

OPTIONS = USE_GETADDRINFO=1

顺着这个关键词搜了下发现 GitHub 中的 haproxy 说明文档下有这么一行:

Recent systems can resolve IPv6 host names using getaddrinfo().

也就是说 Ubuntu 下的那些打包的维护者并没有添加这个选项,因此也就不能正常解析 AAAA 记录的域名。那 HAProxy 宣称的 IPv6 支持又是怎么一回事呢?根据自己有限的经验猜测是它能监听 IPv6 的 socket.

好了,既然没有能支持解析 IPv6 的包,那就自己根据源码编译一个呗。

编译带 getaddrinfo() 支持的 HAProxy

进入官网 http://www.haproxy.org/, 找到 1.6 稳定版的最新发布版,下载后解压、编译、构建。以目前最新的稳定版 1.6.3 为例:

cd ~/src/haproxy
http_proxy=http://your_proxy:port wget http://www.haproxy.org/download/1.6/src/haproxy-1.6.3.tar.gz # blocked by XXX
tar -xzvf haproxy-1.6.3.tar.gz
cd haproxy-1.6.3/
make CFLAGS='-I/usr/include/lua5.3 -O2 -g -fno-strict-aliasing -Wdeclaration-after-statement' USE_GETADDRINFO=1 USE_ZLIB=1 USE_OPENSSL=1 USE_LUA=1 USE_PCRE=1 USE_PCRE_JIT=1 TARGET=linux2628

考虑到后期的扩展性,你很可能需要 lua, 因此需要先将 lua5.3 的头文件和库准备好(不需要 lua 支持的话就不用 USE_LUA=1)。简单起见,到 http://haproxy.debian.net/ 找到适合自己发行版和 1.6-stable 的 ppa, 更新后安装 lua 的开发版:

apt-get install lua5.3 liblua5.3-dev

安装好 lua 后你就可以顺利执行以上最后一行的构建命令了。由于通过这种方式编译生成的 HAProxy 并没有相应的 service 等文件,因此可以先从 ppa 中安装 HAProxy, 然后将编译生成的两个二进制文件替换之,大功告成~