利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana

在拜读浙江大学SEL实验室著作的《Docker容器与容器云》第二版时,自己按照书中在自己的虚拟机中搭建了一个由docker容器构建的应用栈以及部署了对其的监控。由于docker hub中镜像版本的的更迭,按照书中的步骤进行部署,不免会遇到一些问题,在此记录下部署过程也分享下部署过程中踩过的坑。

搭建的环境是:

1:虚拟机工具是VMware Workstations

2:操作系统是CentOS Linux release 7.5.1804 (Core)

3:linux内核是3.10.0-862.el7.x86_64

整个部署过程可以分为三部分:

1.安装docker

2.Haproxy+Django+Redis搭建应用栈

3.Cadvisor+Consul+Prometheus+Grafana部署监控

以下操作均在root用户下进行,其他用户请注意授予sudo权限

第一部分:安装docker

执行以下命令:

yum install docker

回显信息:

利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第1张图片

执行命令:

[root@localhost ~]# systemctl start docker

查看docker基本信息:

[root@localhost ~]# docker info

回显信息:

Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 0
Server Version: 1.13.1
...

docker安装完毕!

第二部分:Haproxy+Django+Redis搭建应用栈

  • 准备工作

1.拉取最新版本的镜像,执行以下命令:

[root@localhost ~]# docker pull redis
[root@localhost ~]# docker pull django
[root@localhost ~]# docker pull haproxy

2.查看拉取的镜像,执行以下命令

[root@localhost ~]# docker images 
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/haproxy   latest              d23194a3929a        5 days ago          72 MB
docker.io/redis     latest              5d2989ac9711        2 weeks ago         95 MB
docker.io/django    latest              eb40dcf64078        2 years ago         436 MB

3.创建容器挂载点目录,之后要给容器挂在文件目录,书中没有提前挂载,在启动容器时,如果不使用-v参数指定挂载目录,docker会默认自己指定挂载目录。执行以下命令:

[root@localhost ~]# cd /home
[root@localhost home]# mkdir docker
[root@localhost home]# ls
docker
[root@localhost home]# cd docker/
[root@localhost docker]# mkdir redis django haproxy
[root@localhost docker]# ls
django  haproxy  redis
  • 应用栈数据库节点配置

数据库配置包括主数据库和从数据库的配置,分别创建主数据库和从数据库的文件挂载点,执行以下命令:

[root@localhost ~]# cd /home/docker/redis
[root@localhost redis]# mkdir master slave1 slave2

1.master数据库的配置如下:

启动redis-master容器,执行以下命令:

[root@localhost redis]# docker run -it --name redis-master -v /home/docker/redis/master/:/data redis

--name 给容器进行命名,-v指定文件挂载目录

得到结果:

root@e54206d487ed:/data#

这个终端是容器虚拟出来的终端。

从容器终端中退出,使用快捷键Ctrl+D,或者执行以下命令:

root@e54206d487ed:/data# exit

切换到redis-master容器挂载的文件目录,创建redis的配置文件,文件名字是redis.conf配置文件内容,按照网上的模板书写就行,注意修改其中的参数。

[root@localhost ~] cd /home/docker/redis/master
[root@localhost ~] vim redis.conf

修改的参数为:

daemonize yes 注意是将yes修改为no,使Redis在容器前端运行,在前端运行时无法进行其他操作,可以再开一个终端。
pidfile /var/run/redis.pid

再次进入redis-master虚拟终端中,切换到容器中的volume目录:

[root@localhost master]# docker exec -it redis-master /bin/bash
root@e54206d487ed:/data# cd /data

复制启动配置文件从/data到redis工作目录/usr/local/bin下,执行以下命令:

root@e54206d487ed:/data# cp /data/redis.conf /usr/local/bin/
root@e54206d487ed:/data# ls
redis.conf
root@e54206d487ed:/data# cp /data/redis.conf /usr/local/bin/
root@e54206d487ed:/data# cd /usr/local/bin/
root@e54206d487ed:/usr/local/bin# ls
docker-entrypoint.sh  gosu  redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli  redis-sentinel  redis-server	redis.conf

启动redis-master服务

root@e54206d487ed:/usr/local/bin# redis-server redis.conf 
31:C 14 Jan 2019 06:02:44.717 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
31:C 14 Jan 2019 06:02:44.717 # Redis version=5.0.3, bits=64, commit=00000000, modified=0, pid=31, just started
31:C 14 Jan 2019 06:02:44.717 # Configuration loaded

至此主数据库部分配置完成。

2.从数据库配置

从数据库配置以slave1为例,启动redis-slave1容器:

[root@localhost redis]# docker run -it --name redis-slave1 --link=redis-master:master -v /home/docker/redis/slave1/:/data redis /bin/bash

配置redis-slave1的配置文件,注意修改参数有三个:

daemonize yes 注意是将yes修改为no,使Redis在容器前端运行,在前端运行时无法进行其他操作,可以再开一个终端。
pidfile /var/run/redis.pid

slaveof master 6379

再次进入redis-slave1虚拟终端中,切换到容器中的volume目录。将redis.conf复制到slave1目录下,并在容器中将文件从/data复制到/usr/local/bin下执行以下命令:

[root@localhost ~]# docker exec -it redis-slave1 /bin/bash
root@e93da3690ef9:/data# cp redis.conf /usr/local/bin/
root@e93da3690ef9:/data# cd /usr/local/bin/
root@e93da3690ef9:/usr/local/bin# ls
docker-entrypoint.sh  gosu  redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli  redis-sentinel  redis-server	redis.conf

同样启动redis-slave1的服务,执行以下命令:

root@e93da3690ef9:/usr/local/bin# redis-server redis.conf 
58:C 16 Jan 2019 03:40:36.496 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
58:C 16 Jan 2019 03:40:36.496 # Redis version=5.0.3, bits=64, commit=00000000, modified=0, pid=58, just started
58:C 16 Jan 2019 03:40:36.496 # Configuration loaded

执行命令redis-cli info 查看slave1的信息。按照书中所说应该是看到以下信息:

# Replication
role:slave
master_host:master
master_port:6379
master_link_status:up
...

但是可能查看信息时,显示的是role:master,原因在文章末尾进行分析。为了整个应用栈搭建流程的继续进行,先执行下列命令:

root@e93da3690ef9:/data# slaveof master 6379

再次查看信息,role变为slave。

3.数据库测试

进入redis-master容器中执行以下命令:

[root@localhost ~]# docker exec -it redis-master /bin/bash
root@a20d6dd3d296:/data# redis-cli 
127.0.0.1:6379> set master xshm
OK
127.0.0.1:6379> get master
"xshm"
127.0.0.1:6379> 

进入redis-slave1中进行查看:

[root@localhost ~]# docker exec -it redis-slave1 /bin/bash
root@e93da3690ef9:/data# redis-cli 
127.0.0.1:6379> get master
"xshm"
127.0.0.1:6379> 

测试成功。同理对redis-slave2进行配置和测试,至此应用栈数据库节点布置完成。

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

1.准备工作

首先启动创建容器,执行以下命令:

[root@localhost ~]# docker run -it --name=APP1 --link=redis-master:db -v /home/docker/django/APP1/:/usr/src/app django /bin/bash
root@b7295bc2530a:/# 

为了访问数据库,需要在容器中安装Python语言的redis支持包,执行以下命令:

root@2ce010fd726c:/# pip install redis

进行简单的测试来验证支持包是否安装成功。执行以下命令:

root@2ce010fd726c:/# 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
>>> 

验证成功。

2.创建APP

在容器的volume目录/usr/src/app下,执行以下命令:

root@2ce010fd726c:/# cd /usr/src/app/
root@2ce010fd726c:/usr/src/app# mkdir dockerweb
root@2ce010fd726c:/usr/src/app# cd dockerweb
root@2ce010fd726c:/usr/src/app/dockerweb# django-admin.py startproject redisweb
root@2ce010fd726c:/usr/src/app/dockerweb# ls
redisweb
root@2ce010fd726c:/usr/src/app/dockerweb# cd redisweb
root@2ce010fd726c:/usr/src/app/dockerweb/redisweb# ls
manage.py redisweb
root@2ce010fd726c:/usr/src/app/dockerweb/redisweb# python manage.py startapp helloworld
root@2ce010fd726c:/usr/src/app/dockerweb/redisweb# ls
helloworld manage.py redisweb

在容器中创建APP之后,切换到主机的volume目录下,进行编辑和配置APP:

[root@localhost ~]# cd /home/docker/django/APP1/
[root@localhost APP1]# ls
dockerweb
[root@localhost APP1]# cd dockerweb/redisweb/helloworld/
[root@localhost helloworld]# ls
admin.py  apps.py  __init__.py  migrations  models.py  __pycache__  tests.py  views.py
[root@localhost helloworld]# vim  views.py 

文件内容为:

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.
import redis
def hello(request):
    str=redis.__file__
    str+="
" r = redis.Redis(host='db',port=6379,db=0) info = r.info() str+=("Set Hi
") r.set('Hi','HelloWorld-APP1') str+=("Get Hi: %s
" % r.get('Hi')) str+=("Redis Info:
") str+=("Key: Info Value") for key in info: str+=("%s: %s
" % (key, info[key])) return HttpResponse(str)

接下来修改redisweb项目的配置文件setting.py,添加新建的helloworld应用,执行过程如下:

[root@localhost helloworld]# cd  ../redisweb/
[root@localhost redisweb]# ls
__init__.py  __pycache__  settings.py  urls.py  wsgi.py
[root@localhost redisweb]# vim settings.py 

文件内容修改:INSTALL_APPS选项下添加hellworld,注意还要将,ALLOWED_HOSTS = [],修改为ALLOWED_HOSTS = ['*']

书中未提到这一点。

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ['*']


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'helloworld',
]

接下来是修改redisweb项目的URL模式文件urls.py。由于Django版本不同配置文件格式与书中有所不同。

from django.conf.urls import include, url
from django.contrib import admin
from helloworld.views import hello
urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^helloworld$',hello),
]

在容器的主机修改完这几个·文件之后进入容器,在目录/usr/src/app/dockerweb/redisweb下完成项目的生成。

[root@localhost redisweb]# docker exec -it APP1 /bin/bash
root@2ce010fd726c:/# cd /usr/src/app/dockerweb/redisweb/
         
root@2ce010fd726c:/usr/src/app/dockerweb/redisweb# python manage.py makemigrations
No changes detected
root@2ce010fd726c:/usr/src/app/dockerweb/redisweb# python manage.py migrate
...

APP1容器的配置已经完成,同理配置APP2。至此应用栈APP节点配置完成。

3.启动APP

以APP1为例。对于APP1使用8001端口,APP2使用8002端口,同时都使用0.0.0.0地址。进入容器执行命令:

root@2ce010fd726c:~# cd /usr/src/app/dockerweb/redisweb/
root@2ce010fd726c:/usr/src/app/dockerweb/redisweb# python manage.py runserver 0.0.0.0:8001
Performing system checks...

System check identified no issues (0 silenced).
January 18, 2019 - 05:24:25
Django version 1.10.4, using settings 'redisweb.settings'
Starting development server at http://0.0.0.0:8001/
Quit the server with CONTROL-C.

至此,APP节点启动完毕。

  • haproxy容器节点配置

1.启动haproxy

执行以下命令:

[root@localhost ~]# docker run -it ---name=HAproxy --link=APP1:APP1 --link=APP2:APP2 -p 6301:6301 -v /home/docker/haproxy/:/tmp haproxy /bin/bash

​​​​​2.haproxy文件配置

利用容器启动时挂载的volume将HAproxy的启动配置文件复制到容器中,在主机中执行以下过程:

[root@localhost ~]# cd /home/docker/haproxy/
[root@localhost haproxy]# vim haproxy.cfg 

由于haproxy版本迭代,文件内容与书中略有不同,如下:

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
    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工作的目录中,执行以下命令:

[root@localhost haproxy]# docker attach HAproxy
root@9f04bcbd3515:/# cp /tmp/haproxy.cfg /usr/local/sbin/

接下来利用该文件启动haproxy代理,执行命令:

root@9f04bcbd3515:/tmp# haproxy -f haproxy.cfg 
[WARNING] 017/055939 (14) : Proxy 'redis_proxy': in multi-process mode, stats will be limited to process assigned to the current request.
[WARNING] 017/055939 (14) :  is only meaningful in daemon mode or master-worker mode. Setting limit to 1 process.

至此完成haproxy容器节点的全部部署,同时也完成了docker应用栈的部署。

  • 应用栈访问测试

应用栈启动后,在本地电脑浏览器中访问容器的宿主机,也就是电脑上的虚机的6301端口,在浏览器中访问http://10.34.132.128:6301/helloworld。刷新网页就会在两个APP容器节点切换。结果如图所示:

利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第2张图片

利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第3张图片

 第三部分:consul+prometheus+grafana部署监控

  • 准备工作

1.从docker镜像库拉取镜像,执行以下命令:

[root@localhost ~]# docker pull google/cadvisor
[root@localhost ~]# docker pull consul
[root@localhost ~]# docker pull prometheus
[root@localhost ~]# docker pull grafana/grafana

备注:cadvisor是Google开发的用于分析运行中容器的资源占用和性能指标的开源工具。相当于抓取容器的各个指标,把数据整理为prometheus可以识别的格式。

2.新建挂载目录,执行以下命令:

[root@localhost ~]# cd /home/docker/
[root@localhost docker]# mkdir consul prometheus grafana cadvisor
[root@localhost docker]# ls
cadvisor consul  django  grafana  haproxy  prometheus  redis 

3.启动cadvisor,consul,prometheus,grafana容器,执行以下命令:

[root@localhost ~]# docker run -d --name=cadvisor -p 8080:8080 -v /home/docker/cadvisor/:/data google/cadvisor
6333f440eadfb308ed6b50e3228cc84c0f41bd5ddf9d510b3556e414b9ec0879

[root@localhost ~]# docker run -d --name=consul -p 8500:8500  -v /home/docker/consul/:/data consul 
f707219663cdfa40b4a1b35baa49f329250b66abd84df24e0bdfb5e345502768

[root@localhost ~]# docker run -d --name=prometheus  -p 9090:9090 -v /home/docker/prometheus/:/data prom/prometheus
c880b73dd67a1d6f1b1d9153952c571ef5c42165b2c0f70121f80a250af7ed68

[root@localhost ~]# docker run -d --name=grafana  -p 3000:3000 -v /home/docker/grafana/:/data grafana/grafana
1592c72150991051282dcbcf8d3b1128a7a7f9e9e54a8d515ff521c1e913626b
[root@localhost ~]# 

 4.查看运行的容器

利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第4张图片

虚拟机的宿主机,也就是本地电脑的浏览器中分别访问容器的宿主机,也就是虚机的8080,8500,9090,3000端口,结果如下:

利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第5张图片

 利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第6张图片

 

利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第7张图片

利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第8张图片

  • 部署Consul容器节点

1.编写consul的cadvisor服务发现json文件,执行以下命令:

[root@localhost docker]# cd cadvisor/
[root@localhost cadvisor]# vim cadvisor.json

文件内容为:

{
  "id": "cadvisor",
  "name": "prometheus-cadvisor",
  "tags": ["primiary"],
  "address": "10.34.132.128",
  "port": 8080,
  "checks": [
    {
     "http":"http://10.34.132.128:8080/metrics",
     "interval":"15s"
    }
  ]
}

注意: "address"和"http"中的IP时容器宿主机(虚机)的IP。

2.执行以下命令将cadvisor服务注册到consul中去,执行以下命令:

[root@localhost cadvisor]# curl --request PUT --data @cadvisor.json http://10.34.132.128:8500/v1/agent/service/register

注意命令应该在cadvisor.json所在目录下执行。命令中的IP是安装consul容器所在的机器的IP。

如果想删除服务可以执行以下命令:

[root@localhost cadvisor]# curl --request PUT http://10.34.132.128:8500/v1/agent/service/deregister/cadvisor

3.查看结果,注册成功。

利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第9张图片

  •  部署Prometheus容器节点

 1.新建prometheus的配置文件,执行以下命令:

[root@localhost docker]# cd prometheus/
[root@localhost prometheus]# vim prometheus.yml

 文件内容为:

# scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
  - static_configs:
    - targets:
      # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label `job=` to any timeseries scraped from this config.
  - job_name: 'prometheus'

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
    - targets: ['10.34.132.128:9090']
  - job_name: 'consul_prometheus'
    consul_sd_configs:
    - server: '10.34.132.128:8500'
      services: []
    relabel_configs:
     - source_labels: ['__meta_consul_service']
       regex: .*prometheus.*
       action: keep

2.重启prometheus容器。查看结果,prometheus中已经监控到了consul_prometheus服务:

利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第10张图片

  • 部署Grafana节点

 1.在浏览器中登录grafana。访问10.34.132.128:3000,grafana默认的账户和密码都是admin。

利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第11张图片

2.登录后添加prometheus数据源。点击Add data source,选择prometheus数据源如图:

利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第12张图片

利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第13张图片

 3.grafana中对数据源prometheus进行设置。

在setting中设置prometheus数据源的name,url等,设置完毕后要注意保存。在dashboards中可以导入已有的模板。我选择了prometheus 2.0 stats,也可以选择其他的模板,或者自己新建。

利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第14张图片

 利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第15张图片

 至此数据源基本设置完成。

4.grafana查看仪表盘

点击home--》点击prometheus数据源

利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第16张图片

 利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第17张图片

 见证奇迹的时刻!!!!

利用Docker搭建你的第一个应用栈以及部署监控:Haproxy+Django+Redis+Cadvisor+Consul+Prometheus+Grafana_第18张图片

至此,监控部署完成。

 部署过过程踩过的一些坑:

大部分问题使用搜索引擎就可以解决。以下是我在完成整个部署时踩过的一些坑,供大家解决问题时参考,其中在部署过程中已经提及了一些。

  • 在部署redis节点时,启动容器时redis进程也会同时启动,此时redis加载的是它的默认配置,而我们要让redis加载我们自己的配置文件,需要执行'redis-server  redis.conf'这条命令,有时候执行完毕redis配置文件不会生效。但是如果你如果想要重启redis加载配置文件,这个行不通,因为如果redis关闭,docker容器也会关闭,因为容器必须要有一个前端进程。有一个解决办法就是,在执行 doker run命令时,加上配文件的参数,如下:
[root@localhost redis]# docker run -it --name redis-master -v /home/docker/redis/master/:/data redis /data/redis

这涉及到docker中的CMD和ENTRYPOINT请自行搜索。

  • 关于防火墙和selinux

在用电脑访问有关端口是,出现失败的情况请关闭虚拟机的防火墙火或对应端口,以及selinux。

  • 关于访问容器中文件夹出现的权限问题问题:

这个问题主要是docker run 命令中的 --privileged=true这个参数。具体用法请自行搜索。

  • 关于docker端口映射出现有关问题

这个问题可能因为你在docker守护进程运行时改动docker宿主机的防火墙策略或者是selinux,导致问题出现,解决方法可以重启容器。

  • 关于部署监控时的IP地址设置 

 我推荐使用IP:port的格式,不要使用localhost:port格式,因为访问时在浏览器中输入的localhost解析的是你安装浏览器的机器,这和配置文件中得localhost不是同一台机器。 

一个尚待解决的问题:
使用docker start redis-master 启动redis容器时,可以进入容器,但redis服务并未启动,需要执行redis-server redis.conf才会运行。照理来说,启动容器时redis服务也应该懂,但是并未启动。

 

如需转载请注明出处!!!

 

你可能感兴趣的:(Docker,监控)