├── index-master.html
├── index-slave.html
├── favicon.ico
├── entrypoint.sh
├── Dockerfile
├── haproxy.cfg
├── keepalived-master.conf
├── keepalived-slave.conf
├── LICENSE
├── docker-compose.yml
└── README.md
/index-master.html:
--------------------------------------------------------------------------------
1 |
Primary
--------------------------------------------------------------------------------
/index-slave.html:
--------------------------------------------------------------------------------
1 | Secondary
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hengfengli/nginx-keepalived-docker-demo/HEAD/favicon.ico
--------------------------------------------------------------------------------
/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | /usr/sbin/keepalived -n -l -D -f /etc/keepalived/keepalived.conf --dont-fork --log-console &
4 |
5 | nginx -g "daemon off;"
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx:1.13.5-alpine
2 |
3 | RUN apk update && apk upgrade
4 |
5 | RUN apk add --no-cache bash curl ipvsadm iproute2 openrc keepalived && \
6 | rm -f /var/cache/apk/* /tmp/*
7 |
8 | COPY entrypoint.sh /entrypoint.sh
9 |
10 | RUN chmod +x /entrypoint.sh
11 |
12 | CMD ["/entrypoint.sh"]
13 |
--------------------------------------------------------------------------------
/haproxy.cfg:
--------------------------------------------------------------------------------
1 | global
2 | log 127.0.0.1 local0
3 | maxconn 4096
4 | daemon
5 | nbproc 4
6 |
7 | defaults
8 | log 127.0.0.1 local3
9 | mode http
10 | option dontlognull
11 | option redispatch
12 | retries 2
13 | maxconn 2000
14 | balance roundrobin
15 | timeout connect 5000ms
16 | timeout client 5000ms
17 | timeout server 5000ms
18 |
19 | frontend main
20 | bind *:6301
21 | default_backend webserver
22 |
23 | backend webserver
24 | server ngxin_master 172.20.128.4:80 check inter 2000 rise 2 fall 5
--------------------------------------------------------------------------------
/keepalived-master.conf:
--------------------------------------------------------------------------------
1 | vrrp_script chk_nginx {
2 | script "pidof nginx"
3 | interval 2
4 | }
5 |
6 | vrrp_instance VI_1 {
7 | state MASTER
8 | interface eth0
9 | virtual_router_id 33
10 | priority 200
11 | advert_int 1
12 | unicast_src_ip 172.20.128.2
13 | unicast_peer {
14 | 172.20.128.3
15 | }
16 |
17 | authentication {
18 | auth_type PASS
19 | auth_pass letmein
20 | }
21 |
22 | virtual_ipaddress {
23 | 172.20.128.4/24 dev eth0
24 | }
25 |
26 | track_script {
27 | chk_nginx
28 | }
29 | }
--------------------------------------------------------------------------------
/keepalived-slave.conf:
--------------------------------------------------------------------------------
1 | vrrp_script chk_nginx {
2 | script "pidof nginx"
3 | interval 2
4 | }
5 |
6 | vrrp_instance VI_1 {
7 | state BACKUP
8 | interface eth0
9 | virtual_router_id 33
10 | priority 100
11 | advert_int 1
12 | unicast_src_ip 172.20.128.3
13 | unicast_peer {
14 | 172.20.128.2
15 | }
16 |
17 | authentication {
18 | auth_type PASS
19 | auth_pass letmein
20 | }
21 |
22 | virtual_ipaddress {
23 | 172.20.128.4/24 dev eth0
24 | }
25 |
26 | track_script {
27 | chk_nginx
28 | }
29 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Hengfeng Li
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 | services:
3 | nginx_master:
4 | build:
5 | context: ./
6 | dockerfile: ./Dockerfile
7 | volumes:
8 | - ./index-master.html:/usr/share/nginx/html/index.html
9 | - ./favicon.ico:/usr/share/nginx/html/favicon.ico
10 | - ./keepalived-master.conf:/etc/keepalived/keepalived.conf
11 | networks:
12 | static-network:
13 | ipv4_address: 172.20.128.2
14 | cap_add:
15 | - NET_ADMIN
16 | nginx_slave:
17 | build:
18 | context: ./
19 | dockerfile: ./Dockerfile
20 | volumes:
21 | - ./index-slave.html:/usr/share/nginx/html/index.html
22 | - ./favicon.ico:/usr/share/nginx/html/favicon.ico
23 | - ./keepalived-slave.conf:/etc/keepalived/keepalived.conf
24 | networks:
25 | static-network:
26 | ipv4_address: 172.20.128.3
27 | cap_add:
28 | - NET_ADMIN
29 | proxy:
30 | image: haproxy:1.7-alpine
31 | ports:
32 | - 8000:6301
33 | volumes:
34 | - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
35 | networks:
36 | - static-network
37 |
38 | networks:
39 | static-network:
40 | ipam:
41 | config:
42 | - subnet: 172.20.0.0/16
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # nginx-keepalived-docker-demo
2 | A small demo to run two nginx containers in active-passive mode by using keepalived and VIP.
3 |
4 | This demo is made to simulate a scenario with two running nginx servers, one as a master and another as a backup, in order to achieve high availability.
5 |
6 | There are some limitations in this demo:
7 | * I run it in a single host. Normally, it would be better to create a scenario with two hosts.
8 | * I didn't spend time to map the virtual IP from docker network to the host. Instead, I use a haproxy to do this task.
9 | * Running both nginx and keepalived in an Alpine container is not easy. rc-service could not manage keepalived properly. I thought to use supervisor or circus, but they are a bit heavy in space. So I directly run keepalived as a background daemon. However, the drawback is if it fails, it will not restart (not robust).
10 |
11 | ## How to run
12 |
13 | Run the following command:
14 |
15 | ```bash
16 | $ docker-compose up -d
17 | ```
18 |
19 | Now, visit `localhost:8000` and you would see `Primary`.
20 |
21 | ```bash
22 | $ docker ps
23 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
24 | 42cc6637255b nginxkeepaliveddockerdemo_nginx_slave "/entrypoint.sh" 28 seconds ago Up 24 seconds 80/tcp nginxkeepaliveddockerdemo_nginx_slave_1
25 | 3f39a7e356ce haproxy:1.7-alpine "/docker-entrypoin..." 28 seconds ago Up 25 seconds 0.0.0.0:8000->6301/tcp nginxkeepaliveddockerdemo_proxy_1
26 | 6151af0d50db nginxkeepaliveddockerdemo_nginx_master "/entrypoint.sh" 28 seconds ago Up 24 seconds 80/tcp nginxkeepaliveddockerdemo_nginx_master_1
27 | ```
28 |
29 | Try to pause the master server:
30 |
31 | ```bash
32 | $ docker pause nginxkeepaliveddockerdemo_nginx_master_1
33 | ```
34 |
35 | Now, visit `localhost:8000` and you should see `Secondary`.
36 |
37 | Recover the master server and pause the slave server:
38 | ```bash
39 | $ docker unpause nginxkeepaliveddockerdemo_nginx_master_1
40 | $ docker pause nginxkeepaliveddockerdemo_nginx_slave_1
41 | ```
42 |
43 | Visit `localhost:8000` and you should see `Primary` again.
44 |
45 | As you can see, when a master server is down, a backup server does automatic failover.
46 |
--------------------------------------------------------------------------------