搭建一个Docker应用栈

一、提示

  1. 可以使用Vagrant创建的虚拟机,也可以使用CentOS云主机
  2. yum -y update
  3. 安装好Docker等基础环境,并熟悉其相关概念及基本操作命令:
    使用官方安装脚本自动安装(使用阿里云镜像)(推荐):
    curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
    安装指南(官方版)(英文):https://docs.docker.com/install/linux/docker-ce/centos/
    安装指南(阿里云版):https://yq.aliyun.com/articles/110806?spm=5176.8351553.0.0.148d1991DNakM8
  4. 启动Docker服务:systemctl start docker

二、系统环境

操作系统版本

# lsb_release -a

LSB Version:	:core-4.1-amd64:core-4.1-noarch
Distributor ID:	CentOS
Description:	CentOS Linux release 7.5.1804 (Core) 
Release:	7.5.1804
Codename:	Core

内核版本

# uname -a

Linux izwz9a99qngm2xbbwktcbaz 3.10.0-693.2.2.el7.x86_64 #1 SMP Tue Sep 12 22:26:13 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

Docker版本

# docker version

Client:
 Version:           18.09.0
 API version:       1.39
 Go version:        go1.10.4
 Git commit:        4d60db4
 Built:             Wed Nov  7 00:48:22 2018
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.0
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.4
  Git commit:       4d60db4
  Built:            Wed Nov  7 00:19:08 2018
  OS/Arch:          linux/amd64
  Experimental:     false

三、具体流程

(一)搭建应用栈

(1)原理

根据教材流程,搭建包含6个节点的Docker应用栈,其中包括1个代理节点(HAProxy,负载均衡代理节点)、3个Web的应用节点(App1、App2、App3,使用Python语言设计的一个单文件数据库的基础Web应用)、1个注数据库节点(Master-redis)和2个从数据库节点(Slave-redis)。各节点功能解释如下:

Master-redis和Slave-redis(主从模式Redis):

使用一个Redis实例作为主机,其余的作为备份机。主机和备份机的数据完全一致,主机支持数据的写入和读取等各项操作,而从机则只支持与主机数据的同步和读取。也就是说,客户端可以将数据写入到主机,由主机自动将数据的写入操作同步到从机。主从模式很好的解决了数据备份问题,并且由于主从服务数据几乎是一致的,因而可以将写入数据的命令发送给主机执行,而读取数据的命令发送给不同的从机执行,从而达到读写分离的目的。

App1、App2、App3:
使用Python语言设计的一个单文件数据库的基础Web应用

HAProxy:
实现负载均衡

(2)流程

1、获取镜像

提示:可以不用获取Ubuntu镜像。

# docker pull django
# docker pull haproxy
# docker pull redis

2、查看镜像

# docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
redis               latest              415381a6cb81        27 hours ago        94.9MB
haproxy             latest              d97a2ef984e4        3 weeks ago         69.5MB
django              latest              eb40dcf64078        23 months ago       436MB

3、应用栈容器节点的创建、互联与启动

注意:输完一条,不要关闭当前标签,在XShell再开个新的标签页连进去,每个标签页对应一个容器的终端。

# docker run -it --name master-redis redis /bin/bash
# docker run -it --name slave-redis1 --link master-redis:master redis /bin/bash
# docker run -it --name slave-redis2 --link master-redis:master redis /bin/bash
# docker run -it --name App1 --link master-redis:db -v ~/projects/Django/App1:/usr/src/app django /bin/bash
# docker run -it --name App2 --link master-redis:db -v ~/projects/Django/App2:/usr/src/app django /bin/bash
# docker run -it --name App3 --link master-redis:db -v ~/projects/Django/App3:/usr/src/app django /bin/bash
# docker run -it --name HAProxy --link App1:App1 --link App2:App2 --link App3:App3 -p 6301:6301 -v ~/projects/HAProxy:/tmp haproxy /bin/bash

详细操作:

  1. 输入命令
    搭建一个Docker应用栈_第1张图片
  2. 回车,出现新创建好的容器的bash终端界面
    搭建一个Docker应用栈_第2张图片
  3. 对当前选项卡右键单击,选择重命名
    搭建一个Docker应用栈_第3张图片
  4. 填入刚刚创建的容器的名字,点确定
    搭建一个Docker应用栈_第4张图片
  5. 点击选项卡旁边的小“+”号,打开一个新的选项卡
    搭建一个Docker应用栈_第5张图片
  6. 双击左边会话管理器中的连接,再次连接到该虚拟机/云主机
    搭建一个Docker应用栈_第6张图片
  7. 执行下一条,重复以上步骤,直至完成所有容器的创建,最后再打开一个新的终端,并命名为“主机”。
    由于XShell免费版限制一个窗口最多打开4个标签页,所以最终创建完成将会有2个窗口
    搭建一个Docker应用栈_第7张图片
  8. 回到“主机”标签页,查看当前所有正在运行的容器的状态:
# docker ps

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
27b2ef73250d        haproxy             "/docker-entrypoint.…"   18 minutes ago      Up 18 minutes       0.0.0.0:6301->6301/tcp   HAProxy
f699945848c3        django              "/bin/bash"              18 minutes ago      Up 18 minutes                                App3
d820efa12051        django              "/bin/bash"              19 minutes ago      Up 19 minutes                                App2
3472edfd4fa9        django              "/bin/bash"              19 minutes ago      Up 19 minutes                                App1
dbf05243db01        redis               "docker-entrypoint.s…"   19 minutes ago      Up 19 minutes       6379/tcp                 slave-redis2
726bbba9bd93        redis               "docker-entrypoint.s…"   20 minutes ago      Up 20 minutes       6379/tcp                 slave-redis1
1961c45d7715        redis               "docker-entrypoint.s…"   30 minutes ago      Up 30 minutes       6379/tcp                 master-redis

(二)配置应用栈

(1)Redis(master和slave)的配置

1、配置

回到“主机”标签页,查看3个Redis节点挂载volume的情况:
命令格式:docker inspect <容器名> | grep Mounts -A 10

# docker inspect master-redis | grep Mounts -A 10
# docker inspect slave-redis1 | grep Mounts -A 10
# docker inspect slave-redis2 | grep Mounts -A 10

搭建一个Docker应用栈_第8张图片

记下各容器的共享文件夹在主机的位置

  1. Master-redis主数据库容器节点的配置
# cd 
  1. 使用Xftp将配置好的master-redis的redis.conf上传到该目录(配置文件原文件及配置方法见文末),然后关闭Xftp
    搭建一个Docker应用栈_第9张图片
    搭建一个Docker应用栈_第10张图片
  2. 同理,分别切换到slave-redis1和slave-redis2的共享文件夹,把配置好的slave-redis的redis.conf上传到此目录

2、启动

  1. 切换到master-slave选项卡,切换到容器中的volume目录,创建存放Redis启动日志的目录,同时复制启动配置文件到Redis的执行工作目录,然后启动Redis服务器,执行过程如下:
# mkdir /data/redislog
# cp /data/redis.conf /usr/local/bin
# cd /usr/local/bin
# redis-server redis.conf
  1. 同理,分别切换到slave-redis1和slave-redis2,执行相同的命令

3、测试

  1. 切换到master-slave选项卡,启动Redis客户端,并存储一个数据,执行过程如下:
# redis-cli

127.0.0.1:6379> auth <你设置的master-redis的密码>(如果没有设置密码请跳过这步)
OK
127.0.0.1:6379> set master bc8e
OK
127.0.0.1:6379> get master
"bc8e"
  1. 随后分别切换到slave-redis选项卡,启动Redis客户端,查询先前在master-redis中存储的数据,执行过程如下:
# redis-cli

127.0.0.1:6379> auth <你设置的master-redis的密码>(如果没有设置密码请跳过这步)
OK
127.0.0.1:6379> get master
"bc8e"

由此可以看到,Master数据库中的数据已经自动同步到Slave数据库中。至此,应用栈的数据库部分已搭建完成,并通过测试。

(2)APP容器节点(Django)的配置

1、安装Redis支持包

分别切换到App1、App2、App3,执行以下命令:

更新匹配并安装Python语言的Redis支持包:

# pip install --upgrade pip
# pip install redis

安装完成后,进行简单的测试来验证支持包是否安装成功:

# python

Python 3.4.5 (default, Dec 14 2016, 18:54:20) 
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.

>>> import redis
>>> print(redis.__file__)
/usr/local/lib/python3.4/site-packages/redis/__init__.py
>>> exit()

2、创建App(此处以App1为例,App2和App3只需要将命令及文本中的“App1”部分修改成“App2”或“App3”即可)

  1. 分别切换到App1、App2、App3选项卡,执行以下命令:
# cd /usr/src/app
# mkdir dockerweb
# cd dockerweb
# django-admin.py startproject redisweb
# cd redisweb
# python manage.py startapp helloworld
# ls

helloworld  manage.py  redisweb
  1. 切换到“主机”选项卡,修改helloworld的视图文件 views.py:
# cd ~/projects/Django/App1/dockerweb/redisweb/helloworld
# vim views.py

将代码换成如下内容,完成后保存并退出:

# -*- coding: utf-8 -*-
from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.
import redis


def hello(request):
    red = 'APP1
Redis数据库记录:
' # 如果设置过Redis密码请在参数中加上password='你的密码', pool = redis.ConnectionPool(host='db', port=6379, db=0) r = redis.StrictRedis(connection_pool=pool) pipe = r.pipeline() pipe_size = 100000 len = 0 key_list = [] print (r.pipeline()) keys = r.keys() for key in keys: key_list.append(key) pipe.get(key) if len < pipe_size: len += 1 else: for (k, v) in zip(key_list, pipe.execute()): print (k, v, '') len = 0 key_list = [] for (k, v) in zip(key_list, pipe.execute()): red = red + '' % (k.decode(), v.decode()) red = red + '
%s%s
' return HttpResponse(red)
  1. 修改redisweb项目的配置文件 settings.py:
# cd ~/projects/Django/App1/dockerweb/redisweb/redisweb
# vim settings.py

ALLOWED_HOSTS = []改成ALLOWED_HOSTS = ['*']
在INSTALLED_APPS选项下添加helloworld:

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'helloworld'
]
  1. 修改redisweb项目的URL模式文件 urls.py,将它设置为访问应用的URL模式,并为URL模式调用的视图函数建立映射表:
# vim urls.py
from django.conf.urls import include, url
from django.contrib import admin
from helloworld.views import hello

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^helloworld$', hello),
]
  1. 回到App1标签页,执行以下步骤:
# cd /usr/src/app/dockerweb/redisweb
# python manage.py makemigrations

No changes detected

# python manage.py migrate

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying sessions.0001_initial... OK
  
# python manage.py migrate

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  No migrations to apply.

至此,所有App1容器配置已经完成,另外App2和App3容器配置也是同样的道理,只需要稍作修改即可。配置完App1和App2、App3容器后,就完成了应用栈的App部分的全部配置。

3、启动App的Web服务器(此处以App1为例,App2和App3只需要将命令及文本中的“App1”部分修改成“App2”或“App3”即可)

在启动App的Web服务器时,可以指定服务器的端口和IP地址。为了通过HAProxy容器节点接受外网所有的公共IP地址访问,实现均衡负载,需要指定服务器的IP地址和端口。对App1使用8001端口,App2使用8002端口,App3则使用8003端口,同时,都是用0.0.0.0地址。
以App1为例,启动服务器的过程如下:

切换到App1选项卡,执行如下步骤:

python manage.py runserver 0.0.0.0:8001

切换到App2选项卡,执行如下步骤:

python manage.py runserver 0.0.0.0:8002

切换到App3选项卡,执行如下步骤:

python manage.py runserver 0.0.0.0:8003

(2)HAProxy容器节点的配置

  1. 切换到“主机选项卡”,执行以下命令:
# cd ~/projects/HAProxy
# vim haproxy.cfg

将以下内容复制到编辑器,保存并退出:

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
    bind-process 3
    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
        server APP3 APP3:8003 check inter 2000 rise 2 fall 5
  1. 随后,切换到“HAProxy”选项卡,执行如下命令:
# cd /tmp
# cp haproxy.cfg /usr/local/sbin
# cd /usr/local/sbin
# haproxy -f haproxy.cfg

(三)验证结果

打开浏览器,输入IP地址:6301/helloworld即可看到App的views。
搭建一个Docker应用栈_第11张图片
访问IP地址:6301/haproxy-stats可以查看HAProxy当前状态。
搭建一个Docker应用栈_第12张图片

四、附录

(一)Redis配置文件

原文件:https://github.com/antirez/redis/blob/5.0/redis.conf

master-redis的redis.conf需进行如下修改:

  • bind 127.0.0.1前添加#(注释掉)(不绑定到特定IP地址)
  • protected-mode yes改为protected-mode no(关闭保护模式)
  • 如果不想关闭保护模式的话可以在requirepass处设置一个连接密码,但在配置slave-redis和views.py时都要填入该密码。设置方式:将# requirepass foobared改为requirepass 你的密码
  • daemonize no改为daemonize yes(开启守护进程)
  • pidfile /var/run/redis_6379.pid改为pidfile /var/run/redis.pid
  • logfile ""改为logfile "/data/redislog/redis.log"(将redis的日志单独保存到文件中)

slave-redis的redis.conf除进行以上修改外,还需进行如下修改:

  • # replicaof 改为replicaof master 6379
  • 如果没有关闭master-redis的保护模式并对其设置了密码,则还需要将# masterauth 改为masterauth 你的master-redis的密码

(二)结束HAProxy进程的方法

如果修改了HAProxy配置文件的内容,则需要先结束所有的HAProxy进程,并重新启动代理。可以使用killall命令来结束进程,如果进程中没有安装该命令,则需要先安装psmisc包,执行命令如下:

  1. 进入“HAProxy”选项卡
  2. 更新软件源:apt-get update
  3. 安装psmisc包:apt-get install psmisc

完成后直接执行killall haproxy命令即可结束HAProxy进程

(三)不小心把终端关了怎么办?

不小心关了一个docker终端的话可以使用docker exec命令再次显示终端,格式如下:

docker exec -it <容器名> /bin/bash

五、引用

  • Redis主从模式 - Remoa的休闲茶馆 - CSDN博客

你可能感兴趣的:(云计算导论)