Help us understand the problem. What is going on with this article?

Dockerコンテナの、Keepalived + LVS冗長化 (1 / 2 構築編)

More than 5 years have passed since last update.

概要

サーバたるもの、仮想マシンであろうがコンテナであろうが、冗長性を兼ね備えていなければなりません。

そこで、Dockerを利用したサービス用サーバについても、別筐体間で冗長化・負荷分散を試みました。


Dockerのネイティブな機構でも、High Availability(以下、HA)が(ある|サポートされる)のかも知れませんが、今回はコンテナのホストサーバ間で技術的にも枯れたKeepalived + LVSを用いて、コンテナへのアクセスを冗長化・負荷分散する構成を取りました。

構成の概要は以下の図の通りとなります。



ka_lvs_docker.png

コンテナ・ホストのInbondインタフェイスと、DockerコンテナであるWebサーバweb-01. web-02のゲートウェイとして、VRRP(Keepalived)によるVIPを設定しました。

図中で左のCentOS7がMasterで、InbondインタフェイスもしくはDocker向けゲートウェイのいずれかがDownした場合は、右のBackup CentOS7にフェイルオーバします。


また、各CentOS内で稼働するWebサーバをLVS(IP-LVS)によって負荷分散冗長化しており、HTTPヘルスモニタリングで死活監視をし、Webサーバプロセス(Nginx)がDownしたコンテナに対して、リクエストを回さないように設定しました。  

この構成の結果、ホストCentOSへのHTTPリクエスト(TCP 80)はVIP 192.168.1.220に到達した時点でVRRP MasterがNATし、web-01 or web-02のIPアドレスに宛先NATの後にL3転送されます。


Keepalivedの準備

Keepalivedの設定ファイル /etc/keepalived/keepalived.conf を掲載します。
(※予め、ipvsdam, keepalivedをインストールし、ip_vs.koをmodprobeしている前提)

/etc/keepalived/keepalived.conf @Master**
! Configuration File for keepalived

global_defs {
   router_id LVS_DOCKER
}

vrrp_instance WEB-HA-01 {
    state MASTER
    interface eth0
    virtual_router_id 100
    priority 100
    advert_int 3
    authentication {
        auth_type AH
        auth_pass docker-web
    }
    virtual_ipaddress {
        192.168.1.220 dev eth0
        192.168.100.254 dev ha-01
    }
}

virtual_server 192.168.1.220 80 {
    delay_loop 5
    lb_algo rr
    lb_kind NAT
    protocol TCP

    real_server 192.168.100.221 80 {
        weight 1
        HTTP_GET {
            url {
              path /ka
          status_code 200
            }
            connect_timeout 5
            nb_get_retry 3
            delay_before_retry 3
        }
    }

    real_server 192.168.100.222 80 {
        weight 1
        HTTP_GET {
            url {
              path /ka
          status_code 200
            }
            connect_timeout 5
            nb_get_retry 3
            delay_before_retry 3
        }
    }

}


/etc/keepalived/keepalived.conf @Backup
! Configuration File for keepalived

global_defs {
   router_id LVS_DOCKER
}

vrrp_instance WEB-HA-01 {
    state BACKUP
    interface eth0
    virtual_router_id 100
    priority 90
    advert_int 3
    authentication {
        auth_type AH
        auth_pass docker-web
    }
    virtual_ipaddress {
        192.168.1.220 dev eth0
        192.168.100.254 dev ha-01
    }
}

virtual_server 192.168.1.220 80 {
    delay_loop 5
    lb_algo rr
    lb_kind NAT
    protocol TCP

    real_server 192.168.100.221 80 {
        weight 1
        HTTP_GET {
            url {
              path /ka
          status_code 200
            }
            connect_timeout 5
            nb_get_retry 3
            delay_before_retry 3
        }
    }

    real_server 192.168.100.222 80 {
        weight 1
        HTTP_GET {
            url {
              path /ka
          status_code 200
            }
            connect_timeout 5
            nb_get_retry 3
            delay_before_retry 3
        }
    }

}


Dockerの準備


続いて、Webサービスを提供するDockerコンテナのイメージを作成します。

CentOS7の正系・待機系で、同じimageを用意するため、以下のDockerfileを作成してください。


Dokerfile
#
# Nginx Dockerfile
#

FROM centos:centos7

ADD ./init.sh /usr/local/bin/init.sh

RUN yum -y update \
 && yum -y install epel-release \
 && yum -y install nginx \
 && chmod +x /usr/local/bin/init.sh

# Define default command.
CMD ["/usr/local/bin/init.sh"]


このファイルと同じディレクトリ内に、CMDで実行指定しているinit.shを作成します。

init.sh
#!/bin/sh

/usr/sbin/nginx && /bin/bash


ここまできたら、この2つのファイルがあるディレクトリにて、

docker build -t TAGNAME .

(※TAGNAMEは任意のimage tag名称)

上のコマンドで、CentOS7のbase imageからnginxをインストール済み&事後にdocker attach可能なイメージを構築します。

こうして作成したWebサーバ用コンテナを、次のように起動させます。

docker run --name web-01  -ti  myimg/nginx-c7:v4


HA用ネットワークの準備

Linuxコンテナ向けのネットワークブリッジ・ユーティリティであるpipeworkを用いて、コンテナにHAネットワーク側のNICを増設します。

(pipework : https://github.com/jpetazzo/pipework)

@Master
[root@cent7-01 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED              STATUS              PORTS               NAMES
9f0e6ede85ca        myimg/nginx-c7:v4   /usr/local/bin/init.   About a minute ago   Up About a minute                       web-01              

[root@cent7-01 ~]# pipework ha-01 9f0e6ede85ca 192.168.100.221/24

(※"ha-01"は任意のブリッジ名)


@Backup
[root@cent7-02 nginx-c7]# docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
937e2a2038e2        myimg/nginx-c7:v4   /usr/local/bin/init.   9 seconds ago       Up 8 seconds                            web-02              

[root@cent7-02 nginx-c7]# pipework ha-01 937e2a2038e2 192.168.100.222/24


次いで、コンテナWebサーバを外部ネットワークからのHTTPリクエストに応答するために、Routing情報を変更します。

Dockerは新規コンテナ起動時に、デフォルトでは172.17.0.0/16内の空きIPをアサインし、コンテナホストに作成済みのブリッジ docker0のIP 172.17.42.1をデフォルトルートとして設定します。

ただ、このデフォルトルート情報はdocker attachしたbashセッションからは変更が禁止されているようです。


そこで、Dockerコンテナに割り当てられた Linux Namespaceを操作可能にし、そのNamespaceを指定したip netns execコマンドによって、コンテナ内のルーティングを変更する事にしました。

(※Linux NamespaceはDockerがホストのネットワークとコンテナ(ゲスト)のネットワークを隔離するために、内部的に利用されています。)

手順としては、

  • Dockerコンテナの実行プロセスPIDを調べる
  • 上で調べたPIDが属するNamespaceをip netnsコマンドで操作可能とするため、/var/run/netns/ディレクトリにリンクを作成する

といった要領です。

@Master
[root@cent7-01 ~]# docker ps 
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
9f0e6ede85ca        myimg/nginx-c7:v4   /usr/local/bin/init.   15 minutes ago      Up 15 minutes                           web-01              

[root@cent7-01 ~]# docker inspect web-01 | grep -i pid
        "Pid": 17917,

[root@cent7-01 ~]# ln -s /proc/17917/ns/net /var/run/netns/web-01
[root@cent7-01 ~]# ip netns exec web-01 ip route sh 
default via 172.17.42.1 dev eth0 
172.17.0.0/16 dev eth0  proto kernel  scope link  src 172.17.0.28 
192.168.100.0/24 dev eth1  proto kernel  scope link  src 192.168.100.221 

[root@cent7-01 ~]# ip netns exec web-01 ip route del default
[root@cent7-01 ~]# ip netns exec web-01 ip route add default via 192.168.100.254

[root@cent7-01 ~]# ip netns exec web-01 ip route sh 
default via 192.168.100.254 dev eth1 
172.17.0.0/16 dev eth0  proto kernel  scope link  src 172.17.0.28 
192.168.100.0/24 dev eth1  proto kernel  scope link  src 192.168.100.221 


@Backup
[root@cent7-02 ~]# docker inspect web-02 | grep -i pid
        "Pid": 14886,

[root@cent7-02 ~]# ln -s /proc/14886/ns/net /var/run/netns/web-02

[root@cent7-02 ~]# ip netns exec web-02 ip route sh
default via 172.17.42.1 dev eth0 
172.17.0.0/16 dev eth0  proto kernel  scope link  src 172.17.0.17 
192.168.100.0/24 dev eth1  proto kernel  scope link  src 192.168.100.222 

[root@cent7-02 ~]# ip netns exec web-02 ip route del default
[root@cent7-02 ~]# ip netns exec web-02 ip route add default via 192.168.100.254

[root@cent7-02 ~]# ip netns exec web-02 ip route sh
default via 192.168.100.254 dev eth1 
172.17.0.0/16 dev eth0  proto kernel  scope link  src 172.17.0.17 
192.168.100.0/24 dev eth1  proto kernel  scope link  src 192.168.100.222 


以上の設定・手順を終えた時点で、

  • 2台のホストに跨るコンテナ2台間で、LVSの形成(Round-Robin負荷分散)
  • サービスを受け付けるホストの eth0側で、VIP 192.168.1.220が稼働
  • 実際のWebサーバとなるコンテナを繋いだ内部ネットワーク ha-01側で、VIP 192.168.100.254が稼働

これらの環境が出来上がりました。


次の投稿では、上述のLVS・Keepalivedの状態確認の方法について述べたいと思います。

To be continued !

YohKmb
ネットワーク、セキュリティのエンジニア。CISSP。
https://github.com/YohKmb
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした