Docker实战-部署haproxy+django+redis应用

之前已经给大家简单介绍了docker的基本使用,现在讲解一个实际应用。2个django  web应用调取底层redis数据库信息显示到web网页上。然后上层通过haproxy作为web的负载均衡连接器,底层redis数据库一主2从架构,整体架构如下图:     客户端通过访问haproxy节点,通过默认的轮循策略对应到后端的2台django应用。同时调取后台redis数据库信息显示到web网页上。Redis为一主两从架构,实现读写分离以及保证数据的安全性。

一、准备镜像

从默认hub.docker.com上拉取需要的镜像 root@test:~# docker pull django root@test:~# docker pull redis root@test:~# docker pull haproxy root@test:~# docker images | grep latest redis     latest                 5958914cc558        5 days ago          94.9MB haproxy  latest                 829b079b1fa5        2 weeks ago         69.5MB django  latest                  eb40dcf64078        23 months ago       436MB  

二、启动容器

启动redis集群 root@test:~# docker run -it --name redis-master redis /bin/bash root@test:~# docker run -it --name redis-slave1 –link redis-master:master  redis /bin/bash root@test:~# docker run -it --name redis-slave2 –link redis-master:master  redis /bin/bash   启动django容器,即应用,在宿主机上创建目录project/Django/app1 app2作为数据卷挂载给容器使用。主要是为了接下来的修改配置文件。 docker run -it --name app1 –link redis-master:db  -v ~/project/django/app1:/usr/src/app  django /bin/bash docker run -it --name app2 –link redis-master:db  -v ~/project/django/app2:/usr/src/app  django /bin/bash   启动haproxy容器,在宿主机上创建目录project/haproxy docker run -it --name haproxy --link app1:app1 --link app2:app2 -p 6301:6301 -v ~/project/haproxy:/tmp haproxy /bin/bash 查看容器   root@test:~# docker ps -a |egrep "entry|bash" b5ce94fc1c1f  haproxy   "/docker-entrypoint.…"   16 hours ago   Up 16 hours      0.0.0.0:6301->6301/tcp   haproxy 3eb6cd729eff  django   "/bin/bash"          4 days ago          Up 4 days                                 app2 44f4eb740fe6  django  "/bin/bash"           4 days ago          Up 4 days                                 app1 799966ed2b09    redis  "docker-entrypoint.s…"   4 days ago      Up 4 days      6379/tcp                redis-slave2 ba87fd991694   redis  "docker-entrypoint.s…"  4 days ago         Up 4 days       6379/tcp                redis-slave1 65445c76145d  redis  "docker-entrypoint.s…"   4 days ago      Up 4 days        6379/tcp                 redis-master  

三、配置redis一主两从

配置redis-master容器 首先redis主master容器启动后,我们需要在容器里面配置redis,然后启动redis服务。由于该容器轻量级特性,里面没有vim等编辑器。但是该镜像默认集成了volume的挂载命令,挂载到/data目录下。这样在主机目录下对配置文件进行修改之后,然后复制到容器相应目录中,在启动服务。 首先查看宿主机哪个目录与容器/data挂载 root@test:~# docker inspect 65445c76145d | grep volumes "Source": "/var/lib/docker/volumes/1a9bbe44d7f75b0be4cfd6f33403255c79af530cc799484be84c230432605ff6/_data", 从本机拷贝一个redis.conf配置文件到该目录 root@test:/var/lib/docker/volumes/1a9bbe44d7f75b0be4cfd6f33403255c79af530cc799484be84c230432605ff6/_data# cp /root/redis-5.0.2/redis.conf . 编辑该文件,修改如下 #bind 127.0.0.1 protected-mode no daemonize yes pidfile /var/run/redis.pid 切换到容器中,启动redis服务 root@test:~# docker attach 65445c76145d root@65445c76145d:/usr/local/bin# cd /data root@65445c76145d:/data# ls -l -rw-r--r-- 1 root root 62169 Nov 30 05:44 redis.conf root@65445c76145d:/data# cp redis.conf /usr/local/bin root@65445c76145d:/data# cd /usr/local/bin/ root@65445c76145d:/usr/local/bin# redis-server redis.conf   配置2个从redis容器 同样的步骤,修改配置文件如下: #bind 127.0.0.1 protected-mode no daemonize yes pidfile /var/run/redis.pid slaveof master 6379 启动服务。 这里的slaveof master 6379 其中的master应该为ip地址,但是之前创建容器的时候通过—link参数指定了redis-master的别名master,所以这里写master会自动识别hosts信息,转换为ip地址。   这样redis一主两从部署好之后,测试一下: root@65445c76145d:/usr/local/bin# redis-cli 127.0.0.1:6379> info replication # Replication role:master connected_slaves:2 slave0:ip=172.17.0.3,port=6379,state=online,offset=492800,lag=1 slave1:ip=172.17.0.4,port=6379,state=online,offset=492800,lag=1 master_replid:040e8fbe65d4cbf44e1785c6d02aa7ccaf47dc12 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:492800 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:492800 127.0.0.1:6379>quit 可以看到master slave信息且状态都正常。

四、配置django容器

这里的django容器启动后,需要利用django框架开发一个简单的web程序,将redis数据库信息显示在web网页上。所以该容器需要安装redis模块。 进入到django容器app1中,安装redis pip install redis 然后终端进入到python, import redis 测试一下。 通过之前创建容器时,指定的参数-v project/Django/app1 挂载到容器/usr/src/app目录。登入到容器中,进行app创建。 在容器中 cd /usr/src/app/ mkdir dockerweb cd dockerweb/ django-admin.py startproject redisweb cd redisweb/ python manage.py startapp helloworld 切换到主机上project/Django/app1目录中进行配置文件的修改。 root@test:~# cd project/django/app1/ root@test:~/project/django/app1# ls dockerweb root@test:~/project/django/app1# cd dockerweb/redisweb/helloworld/ root@test:~/project/django/app1/dockerweb/redisweb/helloworld# ls admin.py  apps.py  __init__.py  migrations  models.py  __pycache__  tests.py  views.py root@test:~/project/django/app1/dockerweb/redisweb/helloworld# vi views.py 修改如下: from django.shortcuts import render ##新增导入http模块 from django.http import HttpResponse   # Create your views here. ##创建自己的view,这里定义的每个函数返回的内容都会显示到web网页上。 import redis   def hello(request): str=redis.__file__ str+="<br>" r = redis.Redis(host='db',port=6379,db=0) info = r.info() str+=("Set Hi <br>") 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)   上面的定义变量r的时候,Redis()连接数据库。Host定义的为db名字,就是创建容器的时候通过—link 参数指定的redis-master容器。Redis为kv键值对数据库,每个数据记录即是key————value值一一对应,这里不做详细介绍。 上面修改了app信息,接下来修改工程信息,添加新增的helloworld 应用。 root@test:~/project/django/app1/dockerweb/redisweb/helloworld# cd ../redisweb/ root@test:~/project/django/app1/dockerweb/redisweb/redisweb# ls __init__.py  __pycache__  settings.py  urls.py  wsgi.py   修改settings.py ALLOWED_HOSTS = ['*']    ##这里设置运行所有的主机访问该应用 INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'helloworld',          ###这里新增app名字 ]   修改urls.py from django.conf.urls import url from django.contrib import admin from helloworld.views import hello     ##从自定义的试图中导入函数模块hello,显示到web端   urlpatterns = [ url(r'^admin/', admin.site.urls), ##这里定义浏览器输入x.x.x.x/helloworld 这样形式开头的访问请求,则返回hello函数内容,即之前定义views.py文件中 url(r'^helloword$',hello), ] 修改上述文件后,进入容器完成数据库等的生成。 root@test:~# docker attach 44f4eb740fe6 root@44f4eb740fe6:~# root@44f4eb740fe6:~# cd /usr/src/app/dockerweb/redisweb/ root@44f4eb740fe6:/usr/src/app/dockerweb/redisweb# python manage.py migrate   启动web应用 python manage.py runserver 0.0.0.0:8001 可以自己测试下:curl 0.0.0.0:8001/helloworld   同样的方法部署app2容器,唯一需要修改的是在视图viewss.py中修改key  Hi对应的值变为HelloWorld-app2 已区别2个django应用。  

五、部署haproxy容器

之前创建该容器的时候指定了宿主机目录/project/haproxy挂载容器目录,进入到宿主机目录修改haproxy参数 root@test:~/project/haproxy# vi haproxy.cfg   global maxconn 4096            #默认最大连接数 log 127.0.0.1 local0            #[err warning info debug] chroot /usr/local/sbin             #chroot运行的路径 daemon                          #以后台形式运行haproxy nbproc 4                        #进程数量(可以设置多个进程提高性能) pidfile /usr/local/sbin/haproxy.pid    #haproxy的pid存放路径,启动进程的用户必须有权限访问此文件   defaults log 127.0.0.1 local3 mode http                       #所处理的类别 (#7层 http;4层tcp  ) maxconn 2000                   #最大连接数 option dontlognull              #不记录健康检查的日志信息 option redispatch               #serverId对应的服务器挂掉后,强制定向到其他健康的服务器 retries 2                       #3次连接失败就认为服务不可用,也可以通过后面设置 balance roundrobin              #默认的负载均衡的方式,轮询方式 #balance source                  #默认的负载均衡的方式,类似Nginx的ip_hash #balance leastconn               #默认的负载均衡的方式,最小连接 timeout connect  5000ms                 #连接超时 timeout client 50000ms              #客户端超时 timeout server 50000ms                #服务器超时   ####################监控页面的设置####################### listen redis_proxy bind 0.0.0.0:6301                    #Frontend和Backend的组合体,监控组的名称,按需自定义名称 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 这里app1 app2分别对应之前创建的django应用容器名,--link后自动识别hosts对应的主机名和ip直接的关系,而不需要自己手动去维护。   进入到容器中,启动服务 root@test:~/project/haproxy# docker attach b5ce94fc1c1f root@b5ce94fc1c1f:/usr/local/sbin# cd /tmp/ -rw-r--r-- 1 root root 1776 Nov 30 07:09 haproxy.cfg root@b5ce94fc1c1f:/tmp# cp haproxy.cfg /usr/local/sbin/ root@b5ce94fc1c1f:/tmp# cd /usr/local/sbin/ root@b5ce94fc1c1f:/usr/local/sbin# ha haproxy  hash root@b5ce94fc1c1f:/usr/local/sbin# haproxy -f haproxy.cfg

六、wed端测试

以上完成了所有的容器部署,现在通过web访问测试。大家都还记得haproxy容器创建的时候-p参数通过指定宿主机6301端口与容器6301端口进行互通,即通过主机端口可以访问到容器内部。 访问web,实际输入helloword(之前配置环境遗留问题) 再次刷新网页 至此,完成部署测试。  

dockerfile介绍

Dockfile是一种被Docker程序解释的脚本,Dockerfile由一条一条的指令组成,每条指令对应Linux下面的一条命令。Docker程序将这些Dockerfile指令翻译真正的Linux命令。Dockerfile有自己书写格式和支持的命令,Docker程序解决这些命令间的依赖关系,类似于Makefile。Docker程序将读取Dockerfile,根据指令生成定制的image。相比image这种黑盒子,Dockerfile这种显而易见的脚本更容易被使用者接受,它明确的表明image是怎么产生的。有了Dockerfile,当我们需要定制自己额外的需求时,只需在Dockerfile上添加或者修改指令,重新生成image即可,省去了敲命令的麻烦。 这里通过自己编写dockerfile 部署上述环境中的6个容器基础镜像。这样下次换一个环境之后,只需要pull下新的镜像既可以部署应用,而不需要像之前那样手动修改参数等等复杂操作。   创建各个镜像单独目录,目录架构如下 root@test:/tmp# tree . ├── django-app1 │   ├── dockerfile │   ├── settings.py │   ├── urls.py │   └── views.py ├── django-app2 │   ├── dockerfile │   ├── settings.py │   ├── urls.py │   └── views.py ├── haproxy │   ├── dockerfile │   └── haproxy.cfg ├── redis-master │   ├── dockerfile │   └── redis.conf └── redis-slave1 ├── dockerfile └── redis.conf   5 directories, 14 files  

Redis-master目录

root@test:/tmp/redis-master# cat dockerfile FROM redis:latest   MAINTAINER zhangtao 390970723@qq.com   ##复制配置文件redis.conf   COPY  ./redis.conf /usr/local/bin WORKDIR  /usr/local/bin RUN chown root:staff redis.conf ENTRYPOINT  ["redis-server","redis.conf"] root@test:/tmp/redis-master# 这里的redis.conf就是之前的redis-master配置文件,注释掉daemonize yes这行,否则容器启动后会自动退出。让进程在容器前端运行。 Build新镜像,并启动容器测试。 docker build -t redis-master:dockerfile . docker run -d --name redis-m-dockerfile redis-master:dockerfile   测试docker exec -it b623590b00d1 redis-cli

Redis-slave目录

root@test:/tmp/redis-slave1# cat dockerfile FROM redis:latest   MAINTAINER zhangtao 390970723@qq.com   ##复制配置文件redis.conf   COPY  ./redis.conf /usr/local/bin WORKDIR  /usr/local/bin RUN chown root:staff redis.conf ENTRYPOINT  ["redis-server","redis.conf"] root@test:/tmp/redis-slave1# 和master一样的dockerfile,但是配置文件redis.conf为之前redis-slave1的配置文件,注释掉daemonize yes这行。 启动容器slave1  slave2 通过下面创建容器的时候--link 指定别名为master 。 docker build -t redis-slave1:dockerfile . docker images docker run -d --name redis-slave1-dockerfile --link redis-m-dockerfile:master redis-slave1:dockerfile docker run -d --name redis-slave2-dockerfile --link redis-m-dockerfile:master redis-slave1:dockerfile

Django-app1目录

root@test:/tmp/django-app1# cat dockerfile FROM django:latest   MAINTAINER zhangtao 390970723@qq.com       #在容器内安装redis模块 RUN pip install redis   #创建app相关目录 RUN mkdir -p /usr/src/app && cd /usr/src/app && mkdir dockerweb && cd dockerweb && django-admin.py startproject redisweb\ && cd redisweb && python manage.py startapp helloworld   #替换应用app的视图-即web显示部分 COPY ./views.py /usr/src/app/dockerweb/redisweb/helloworld/ #替换工程调用文件,-即redisweb增加调用app部分 COPY ./settings.py /usr/src/app/dockerweb/redisweb/redisweb/ COPY ./urls.py /usr/src/app/dockerweb/redisweb/redisweb/   #指定工程目录路劲,并启动django  web服务 WORKDIR /usr/src/app/dockerweb/redisweb RUN python manage.py migrate CMD ["python","manage.py", "runserver", "0.0.0.0:8001"] Build镜像 docker build -t django:dockerfile1 . docker run -d --name django-app1-dockerfile -p 8001:8001 --link redis-m-dockerfile:db django:dockerfile1 上面加入-p 参数是为了 指定本机8001端口与容器8001进行互通,让外面通过主机端口访问到容器内部应用。 web端测试:http://192.168.0.250:8001/helloworld

Django-app2目录

第二个django dockerfile中定义端口为8002。另外views.py文件中定义key Hi值为app2。 修改views.py 改参数 修改dockerfile指定端口8002 docker build -t django:dockerfile2 .   build镜像 docker run -d --name django-app2-dockerfile -p 8002:8002 --link redis-m-dockerfile:db django:dockerfile2 web端测试: http://192.168.0.250:8002/helloworld

haproxy目录

root@test:/tmp/haproxy# cat dockerfile FROM haproxy:latest   MAINTAINER zhangtao 390970723@qq.com   ##复制配置文件redis.conf   COPY  ./haproxy.cfg /usr/local/sbin WORKDIR  /usr/local/sbin ENTRYPOINT ["haproxy","-f","haproxy.cfg"] #CMD ["haproxy","-f","haproxy.cfg"] 其中haproxy.cfg配置文件就是之前的文件,注释掉daemon #       daemon                          #以后台形式运行haproxy   root@test:/tmp/haproxy# docker build -t haproxy:dockerfile . root@test:/tmp/haproxy# docker run -d --name haproxy-dockerfile --link django-app1-dockerfile:django-app1-dockerfile --link django-app2-dockerfile:django-app2-dockerfile -p 6302:6301  haproxy:dockerfile web测试: http://192.168.0.250:6302/helloworld   http://192.168.0.250:6302/haproxy-stats  

上传阿里云仓库

登入阿里云仓库,创建仓库 docker login --username=xxxxxx@qq.com registry.cn-hangzhou.aliyuncs.com 给镜像添加tag docker tag be20dbb59c6e registry.cn-hangzhou.aliyuncs.com/momo/ceshi:redis-master:dockerfile docker tag be20dbb59c6e registry.cn-hangzhou.aliyuncs.com/momo/ceshi:redis-master.dockerfile docker tag e6a73c43c7af registry.cn-hangzhou.aliyuncs.com/momo/ceshi:redis-slave1.dockerfile docker tag 75f05c5be0e8 registry.cn-hangzhou.aliyuncs.com/momo/ceshi:django.dockerfile1 docker tag 7ab005bac9a3 registry.cn-hangzhou.aliyuncs.com/momo/ceshi:django.dockerfile2 docker tag cc35421b35e6 registry.cn-hangzhou.aliyuncs.com/momo/ceshi:haproxy.dockerfile push到仓库 docker push registry.cn-hangzhou.aliyuncs.com/momo/ceshi:redis-master.dockerfile docker push registry.cn-hangzhou.aliyuncs.com/momo/ceshi:haproxy.dockerfile docker push  registry.cn-hangzhou.aliyuncs.com/momo/ceshi:django.dockerfile2 docker push registry.cn-hangzhou.aliyuncs.com/momo/ceshi:django.dockerfile1 docker push registry.cn-hangzhou.aliyuncs.com/momo/ceshi:redis-slave1.dockerfile 这样,在其他主机上,直接pull下来后即可以使用。  

其他主机测试

[root@node33 ~]# docker images REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE [root@node33 ~]# docker ps -a CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES [root@node33 ~]# 该主机上镜像容器均没有。现在pull镜像   [root@node33 ~]# docker login --username=xxxxxx@qq.com registry.cn-hangzhou.aliyuncs.com Password: Login Succeeded [root@node33 ~]# [root@node33 ~]# [root@node33 ~]# docker pull registry.cn-hangzhou.aliyuncs.com/momo/ceshi:redis-master.dockerfile redis-master.dockerfile: Pulling from momo/ceshi a5a6f2f73cd8: Pull complete a6d0f7688756: Pull complete 53e16f6135a5: Pull complete b761e99e9c9c: Pull complete 13686b3f2e29: Pull complete 667e8fd02be2: Pull complete 6919fef48006: Pull complete 4196dd1ed65a: Pull complete Digest: sha256:b0a6ccda95d8677e62e64db986ca1d9db8b738d1d0b279b20c867a6e9f8ce534 Status: Downloaded newer image for registry.cn-hangzhou.aliyuncs.com/momo/ceshi:redis-master.dockerfile [root@node33 ~]# docker images REPOSITORY                                     TAG                       IMAGE ID            CREATED             SIZE registry.cn-hangzhou.aliyuncs.com/momo/ceshi   redis-master.dockerfile   be20dbb59c6e        25 hours ago        95.1MB [root@node33 ~]# docker run -d --name redis-master registry.cn-hangzhou.aliyuncs.com/momo/ceshi:redis-master.dockerfile 7f504967542acecb7e69c882e6ce5e62fca0e823c2dbfbc79199727987b0f075 [root@node33 ~]# docker ps -a CONTAINER ID        IMAGE                                                                  COMMAND                  CREATED             STATUS              PORTS               NAMES 7f504967542a        registry.cn-hangzhou.aliyuncs.com/momo/ceshi:redis-master.dockerfile   "redis-server redis.…"   4 seconds ago       Up 3 seconds        6379/tcp            redis-master [root@node33 ~]# docker exec -it 7f504967542a redis-cli 127.0.0.1:6379> info replication # Replication role:master connected_slaves:0 master_replid:cdc1fc01e41773f54cab8ecb6e20c77f563816ca master_replid2:0000000000000000000000000000000000000000 master_repl_offset:0 second_repl_offset:-1 repl_backlog_active:0 repl_backlog_size:1048576 repl_backlog_first_byte_offset:0 repl_backlog_histlen:0 127.0.0.1:6379> quit   如上,改镜像直接pull之后,容器应用redis就处于启动状态。其他容器slave1启动后—link参数指定该容器名字即可使用。

posted on 2018-12-12 11:11  歪歪121  阅读(248)  评论(0)    收藏  举报