使用容器技术快速搭建一个高可用服务集群。
应用栈具体结构¶ 经典的 Web 高可用架构。由一个负载均衡代理容器,两个 Web 应用容器,和一个主从架构的数据库容器集群组成。使用容器技术,使你能够在资源有限的计算机上快速搭建实践一个高可用架构,提高学习效率 :>
准备工作¶ 获取镜像¶ 1
2
3
$ docker pull django
$ docker pull haproxy
$ docker pull redis
启动并互联容器栈节点¶ 使用 --link
参数进行互联(现在这个参数已经成为 LEGACY
,官方推荐使用用户自定义 bridge
来替代它)。
1
2
3
4
5
6
7
8
9
10
11
# Boot the redis cluster.
$ docker run -it --name redis-master redis /bin/bash
$ docker run -it --name redis-slave1 --link redis-master:master redis /bin/bash
$ docker run -it --name redis-slave2 --link redis-master:master redis /bin/bash
# Boot the application cluster.
$ docker run -it --name APP1 --link redis-master:db -v /your/path/to/APP1:/usr/src/app django /bin/bash
$ docker run -it --name APP2 --link redis-master:db -v /your/path/to/APP2:/usr/src/app django /bin/bash
# Boot the HAProxy container.
$ docker run -it --name HAProxy --link APP1:APP1 --link APP2:APP2 -p 6301:6301 -v /your/path/to/HAProxy:/tmp haproxy /bin/bash
检查容器运行状态¶ 1
2
3
4
5
6
7
8
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
54b9018f61e6 haproxy "/docker-entrypoint.…" 21 hours ago Up 21 hours 0.0.0.0:6301->6301/tcp HAProxy
b5bd8728af08 django "/bin/bash" 43 hours ago Up 43 hours APP2
7b9fdd342f3c django "/bin/bash" 43 hours ago Up 43 hours APP1
fb1c509d0245 redis "docker-entrypoint.s…" 43 hours ago Up 43 hours 6379/tcp redis-slave2
4b3284f6a268 redis "docker-entrypoint.s…" 43 hours ago Up 43 hours 6379/tcp redis-slave1
19419d882a8d redis "docker-entrypoint.s…" 43 hours ago Up 43 hours 6379/tcp redis-master
可见,一个 haproxy
容器,两个 django
容器和三个 redis
容器都在正常运行中。
配置工作¶ 配置 Redis 集群¶ 拷贝默认的 redis.conf
模板至容器的 /data
目录下,对于 redis-master
,我们需要修改模板中的这些参数:
1
2
3
4
# bind 127.0.0.1
protected-mode no
daemonize yes
pidfile /var/run/redis.pid
修改后在其目录下运行 redis
:
1
$ /usr/local/bin/redis-server redis.conf
对于从数据库 redis-slave1
和 redis-slave2
,我们需要修改模板中的这些参数:
1
2
3
daemonize yes
pidfile /var/run/redis.pid
slaveof master 6379
修改后在其目录下执行该命令运行 redis
:
1
# /usr/local/bin/redis-server redis.conf
Redis 节点测试¶ 在 redis-master
, redis-slave1
和 redis-slave2
上分别启动 Redis
客户端程序:
在 redis-master
上写入 <“master”, “19419d882a8d”> 的数据:
1
2
127.0.0.1:6379> set master 19419d882a8d
OK
尝试在 redis-master
上获取刚写入的 “master” 数据:
1
2
127.0.0.1:6379> get master
"19419d882a8d"
在 redis-slave1
和 redis-slave2
中获取 “master” 数据:
1
2
127.0.0.1:6379> get master
"19419d882a8d"
若能获取到则说明 Master 中的数据已经成功同步至 Slave 的数据库中,主从架构的 Redis 集群已经搭建好了。
配置应用集群¶ APP1
和 APP2
这两个容器都需要进行配置。
首先安装 redis
的 Python SDK:
在容器的 /usr/src/app
目录下创建 Django 应用:
1
2
3
4
# cd /usr/src/app/
# django-admin startproject redisweb
# cd redisweb/
# python manage.py startapp helloworld
新建好应用之后,可以在主机中挂载的目录 /your/path/to/APP1
进行编辑。
或是 /your/path/to/APP2
。
修改视图文件 redisweb/helloworld/views.py
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from django.shortcuts import render
from django.http import HttpResponse
import redis
def hello ( request ):
str = redis . __file__
str += "<br>"
r = redis . Redis ( host = 'db' , port = 6379 , db = 0 )
info = r . info ()
r . set ( 'Hi' , 'HelloWorld-APP1' )
str += ( "Get Hi: %s <br>" % r . get ( "Hi" ))
str += ( "Redis info: <br>" )
str += ( "Key: Info Value" )
for key in info :
str += ( " %s : %s <br>" % ( key , info [ key ]))
return HttpResponse ( str )
修改路由表 redisweb/redisweb/urls.py
:
1
2
3
4
5
6
7
8
from django.conf.urls import url
from django.contrib import admin
from helloworld.views import hello
urlpatterns = [
url ( r '^admin/' , admin . site . urls ),
url ( r '^helloworld$' , hello ),
]
修改 Django 应用设置,将 helloworld
应用加入 INSTALLED_APPS
中 :
1
2
3
4
5
6
7
8
9
10
11
# Line 33
INSTALLED_APPS = [
'django.contrib.admin' ,
'django.contrib.auth' ,
'django.contrib.contenttypes' ,
'django.contrib.sessions' ,
'django.contrib.messages' ,
'django.contrib.staticfiles' ,
'helloworld' ,
]
修改完之上的文件之后,重新回到容器中,在目录 /usr/src/app/redisweb
下完成数据库的迁移:
1
2
# python manage.py makemigrations
# python manage.py migrate
为了使用 HAProxy
进行负载均衡的代理,我们将 APP1
的服务端口设为 8001
,APP2
的服务端口设为 8002
,根据这个配置来启动应用服务器:
1
2
3
4
5
# APP1
# python manage.py runserver 0.0.0.0:8001
# APP2
# python manage.py runserver 0.0.0.0:8002
可以通过应用服务容器的 IP 地址来尝试访问下服务,如果都能够访问,则应用服务器配置成功。
配置 HAProxy¶ 最后我们需要配置 HAProxy
节点,它将作为我们的网关,直接对外进行服务并完成应用的负载均衡。
在 HAProxy
容器的挂载目录下新建 haproxy.cfg
配置文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
global
log 127.0.0.1 local0
maxconn 4096
chroot /usr/local/sbin
daemon
nbproc 4
pidfile /usr/local/sbin/haproxy.pid
defaults
log 127.0.0.1 local3
mode http
option dontlognull
option redispatch
retries 2
maxconn 2000
balance roundrobin
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
listen redis_proxy
bind 0.0.0.0:6301
stats enable
stats uri /haproxy-stats
server APP1 APP1:8001 check inter 2000 rise 2 fall 5
server APP2 APP2:8002 check inter 2000 rise 2 fall 5
配置完后,在同目录下启动 HAProxy 服务:
1
# /usr/local/sbin/haproxy -f haproxy.cfg
大功告成¶ 现在,通过 docker inspect
查看 HAProxy
容器的 IP,就可以在你喜欢的浏览器上看到我们刚才搭建的 Web 服务了!
查看 HAProxy
容器 IP:
1
2
$ HAPROXY_IP = $( docker inspect --format "{{ .NetworkSettings.IPAddress }}" HAProxy)
$ echo $HAPROXY_IP
访问 http://HAPROXY_IP/haproxy-stats
即为 HAProxy
的数据面板;http://HAPROXY_IP/helloworld
即为刚才我们所编写的应用!
Congratulations to yourself 🎉
本文大部分内容来自《Docker 容器与容器云(第2版)》的 2.3 章节,可能时间久远镜像更新,该书中部分操作无法重现,故写此博文将我的方法分享给各位,希望能够有所帮助。
本作品采用
知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。