HAProxy 1.6.5での動的名前解決における不具合と対処法

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

本日時点でのHAProxyの安定最新版である1.6.5で一つ不具合があったので、その解決方法をご紹介します。

3行まとめ

  • HAProxy 1.6.5の動的DNS解決の仕組みの部分にバグ
  • 1.6.5にパッチを当てるか
  • 1.6.4を使うことで修正される

HAProxyとは

HAProxyは高機能なプロキシ・ロードバランサとして開発されているOSSです。HAProxyを利用することで、WEBアプリケーションやDBサーバの負荷分散に利用することが可能です。AWSにもロードバランササービスとしてELBがありますが、ELBはRDSインスタンスを登録できないなどの成約があります。一方でHAProxyではRDSやElastiCacheなど、AWSのマネージドサービスも登録することが可能です。

ただ、HAProxy 1.5以前ではHAProxyの起動時にのみDNSの名前解決が行われていました。ですが、AWSの各種マネージドサービスはフェイルオーバー等でFQDNの指すIPアドレスが変わる可能性があるため、HAProxyをAWSサービスと組み合わせて利用する際にはIPアドレスが変更するたびにreloadやHAProxyの再起動が必要でした。

2015/10にリリースされたHAProxy1.6で、動的DNS解決の機能が追加され、定期的にDNSの名前解決を行うことでIPアドレスの変更に追従することが可能になりました。ですがこの仕組が1.6.5では機能していないようです。

原因

DNS問い合わせのヘッダ定義に問題があり、DNSリクエストが全てDNSレスポンス形式として解釈されてしまっているようです。以下の画像はHAProxy1.6.5を稼働させているAmazon Linux上でtcpdumpしたものをWiresharkで可視化したものになります。

dump_cap

対応策

以下ページでやりとりがされています。

途中のコメントにある通り、このパッチを適用するか、このバグの出ない1.6.4を使ってほしい、とのことです。1.6.5での修正分が必要ないようであれば1.6.4を利用したほうがよさそうです。

[ec2-user@ip-172-31-12-20 ~]$ cd haproxy-1.6.5/
[ec2-user@ip-172-31-12-20 haproxy-1.6.5]$ cat patch
--- a/include/types/dns.h
+++ b/include/types/dns.h
@@ -63,16 +63,16 @@
 /* DNS request or response header structure */
 struct dns_header {
    unsigned short  id:16;      /* identifier */
-   unsigned char   qr :1;      /* query/response 0: query, 1: response */
-   unsigned char   opcode :4;  /* operation code */
-   unsigned char   aa :1;      /* authoritative answer 0: no, 1: yes */
-   unsigned char   tc :1;      /* truncation 0:no, 1: yes */
    unsigned char   rd :1;      /* recursion desired 0: no, 1: yes */
-   unsigned char   ra :1;      /* recursion available 0: no, 1: yes */
-   unsigned char   z :1;       /* not used */
-   unsigned char   ad :1;      /* authentic data */
-   unsigned char   cd :1;      /* checking disabled */
+   unsigned char   tc :1;      /* truncation 0:no, 1: yes */
+   unsigned char   aa :1;      /* authoritative answer 0: no, 1: yes */
+   unsigned char   opcode :4;  /* operation code */
+   unsigned char   qr :1;      /* query/response 0: query, 1: response */
    unsigned char   rcode :4;   /* response code */
+   unsigned char   cd :1;      /* checking disabled */
+   unsigned char   ad :1;      /* authentic data */
+   unsigned char   z :1;       /* not used */
+   unsigned char   ra :1;      /* recursion available 0: no, 1: yes */
    unsigned short  qdcount :16;    /* question count */
    unsigned short  ancount :16;    /* answer count */
    unsigned short  nscount :16;    /* authority count */
[ec2-user@ip-172-31-12-20 haproxy-1.6.5]$ patch -u include/types/dns.h < patch
[ec2-user@ip-172-31-12-20 haproxy-1.6.5]$ make
[ec2-user@ip-172-31-12-20 haproxy-1.6.5]$ sudo make install

一応、1.6.5に上記パッチを当てたものを再インストールして試してみました。以下がtcpdumpの結果です。

dump2_cap

正常にDNSリクエストとレスポンスが返ってきたのが確認できました:)

HAProxyを新規導入される際やバージョンアップの際にはこの不具合にご注意ください。