设为首页 收藏本站
查看: 2806|回复: 1

[经验分享] 基于zabbix用Python写一个运维流量气象图

[复制链接]

尚未签到

发表于 2016-3-7 08:35:37 | 显示全部楼层 |阅读模式
前言:同事问我,你写运维平台最先写哪一部分?好吧,还真把我问倒了,因为这是在问最应该放在放在第一位的东西~作为一个工作不足两年,运维不足一年的新手来说,还真不敢妄下评论,其实按照我的思路,觉得最重要的部分肯定是故障处理,报警,但是这一块怎么写?怎么说?肯定不能重复造轮子了,不过我最想写的是报表系统,思路是有的,但是一直耽搁了,详情参考初步设定如图 wKiom1Y3QzXTxyYeAAdl3RKvVlc169.jpg

开发语言:python
web框架:django
  好吧,在回到那个问题,应该先写哪个部分。我没回答,反问他了。
  他说,应该是运维气象图,这张图上有各个节点的位置,并且标注出流量情况,如果我们在服务器发生故障的时候发现其中一个节点流量过高或者过低,或者一些其他指标,我们在一定程度上可以快速的地位故障的位置。注:cacti,zabbix似乎是有这个插件的,不过不是那么好看,或者有一定局限性,我也没调查过,反正不想用。
  然后,我被上了一课, 那么为毛类似这样的应用或者框架之类的(除了上面说的两个插件,本人暂时没有Google或百度到,如果你知道抨击一下我呗,当然,最好是Python开发的,我好自定义一下),他说,收费的软件有~~~

  首先瞧瞧我花了几天鼓捣出来的Beta版本吧:
QQ截图20160307083318.jpg
现在,正题~~~
如果你不会python就收藏着以后看吧,当下就看看思路吧。
如果你会python就在涉猎一下JS吧,比如AngularJS,D3JS什么的,不过可以
如果你什么都不会,希望能激发你的兴趣。
如果你是大神,还执意要看就忽略我代码中的一些写的不优雅,不好看的地方吧T_T
题外话:话说,有什么觉得比较实用的功能是需要收费的,或者一些想法需要实现的可以Q我,我们把它实现了(仅限于大概一周以内能写完的,特别有意思的来说)
授人以鱼不如授人以渔嘛,主要两部分,一部分思路,一部分代码讲解

(一)
思路
Q:数据来源,通过写客户端?
A:当然不,nagios,cacti,zabbix什么的不是有一大堆么,为毛还要自己写,而且还不一定写的比别人好,美其名曰不愿重复造轮子~~~根据自己情况选择吧,这里就选的通过zabbix的API作为数据来源。
Q:用什么web框架?
A:用Flask,很喜欢一句从网上看来的评论django的话,上它的人很多,喜欢它的很少,再者,我实在不想去配置什么配置文件,以及帮我创建一大堆文件(当然也可以不需要),再再者,我的功能不需要太多,再再再者,flask的官方文档写得太棒了~~~

然后瞧瞧我们写什么,完成什么~

代码实现:
     web框架flask
功能页面:
        页面一:展示页面(bootstrap提供样式效果,AngularJS实时数据查询并刷新,为毛不用jQuery?因为jQuery我不会T_T)
        页面二:数据查询接口
代码文件:
        一:用于查询数据的py模块 x 1
        二:用于提供web界面的py文件 x 1
        三:html模板文件 x 3
        四:js文件 x 2

注:其实个人不建议用模板渲染直接把数据渲染到展示页面上去,虽然这样不用写js了,但是写到后面,你就难过了,所以前台后台分离吧,这里也是前台后台分离,前台bootstrap加AngularJS~~~

(二)
代码
zabbix数据获取

所以直接放代码吧~~
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#coding=utf-8
import json
import requests
from pprint import pprint
from os import path
###zabbix api 访问地址
zabbix_pre = "http://10.10.102.88/zabbix/"
zabbix_url = zabbix_pre + "/api_jsonrpc.php"
###用户名密码
user = ""
passwd = ""
###这里只查询进出口流量,所以只有下面两个关键字,后面可能会查询一些其他的~~~
net_in = "net.if.in[eth0]"
net_out = "net.if.out[eth0]"
###构造post请求提交的数据
auth_data = json.dumps(
{
    "jsonrpc": "2.0",
    "method": "user.login",
    "params": {
    "user": "%s" %user,
    "password": "%s" %passwd
},
"id": 0
})
###http头部信息,zabbix要求的
headers = {
    'content-type': 'application/json',
}
###构造一个返回查询hostid的json数据,函数是一等公民~~~
def host_data(auth):
    data = json.dumps(
    {
        "jsonrpc":"2.0",
        "method":"host.get",
        "params":{
            "output":["hostid","host"],
            "search":{"host":""}
        },
        "auth":"%s" %auth,
        "id":1,
    })
    return data
###如上,查询hostid
def host_data_search(auth,search):
    data = json.dumps(
    {
        "jsonrpc":"2.0",
        "method":"host.get",
        "params":{
            "output":["hostid","name"],
            "search":{"host":search}
        },
        "auth":"%s" %auth,
        "id":1,
    })
###如上,查询itemid
def item_data_filter1(auth,hostid,filters):
    data = json.dumps(
        {
           "jsonrpc":"2.0",
           "method":"item.get",
           "params":{
               "output":["itemid"],
               "hostids":"%s" %hostid,
                "search":{
                    "key_":filters
                }
           },
           "auth":"%s" %auth,
           "id":1,
        })
    return data
###如上,查询item的所有信息,hostname,itemid一大堆
def item_data_filter2(auth,hostid,filters):
    data = json.dumps(
    {
    "jsonrpc": "2.0",
    "method": "item.get",
    "params": {
        "output":"extend",
        "hostids":"%s" %hostid,
        "filter": {
            "name": filters
        },
        "sortfield": "name"
    },
    "auth":"%s" %auth,
    "id": 1
    })
    return data
###如上,获取最新监控值
def history_data(auth,itemid,limit,his=0):
    data = json.dumps(
        {
           "jsonrpc":"2.0",
           "method":"history.get",
           "params":{
               "output":"extend",
               "history":his,
               "sortfield": "clock",
               "sortorder": "DESC",
               "itemids":"%s" %itemid,
               "limit":limit
           },
           "auth":"%s" %auth,
           "id":1,
        })
    return data
###构造获取zabbix验证id,为了反复操作,当然封装成函数
def getauth(zabbix_url,auth_data,headers):
    auth_ret  = requests.post(zabbix_url, data=auth_data, headers=headers)
    auth_id = auth_ret.json()["result"]
    return auth_id
###将所有结果保存成本地之间,结果包括,主机名(这里指zabbix上的命名),hostid,出入口的itemid
def savefile():
    host_ret = requests.post(zabbix_url, data=host_data(auth_id), headers=headers)
    host_ret = host_ret.json()["result"]

###这里请根据实际情况设定,比如包括nginx集群,mysql集群,tomcat集群,如下
    json_all = {}
    json_all["nginx_cluster"] = {}
    json_all["tomcat_cluster"] = {}
    json_all["mysql_cluster"] = {}
    for host in host_ret:
        hostid = host["hostid"]
        hostname = host["host"]
        item_ret = requests.post(zabbix_url, data=item_data_filter1(auth_id,hostid,"net.if"), \
                    headers=headers)
        item_ret = item_ret.json()["result"]
        #pprint(item_ret)
        item_in = item_ret[0]["itemid"]
        item_out = item_ret[1]["itemid"]
        """"这里如上,根据实际情况设定
        if "nginx" in hostname:
            json_all["nginx_cluster"][hostname] = [hostid,item_in,item_out]
        elif "tomcat" in hostname:
            json_all["tomcat_cluster"][hostname] = [hostid,item_in,item_out]
        elif "mysql" in hostname:
            json_all["mysql_cluster"][hostname] = [hostid,item_in,item_out]
        else:
            pass"""
    #pprint(json_all)
    fp = open("clusters.json","w")
    fp.write(json.dumps(json_all))
    fp.close()
###然后通过itemid获取最新的监控值
def gethist(auth_id,itemid,limit,outtype=3):
    while not path.isfile("clusters.json"):
        savefile()   
    history_ret = requests.post(zabbix_url, data=history_data(auth_id,itemid,limit,outtype),\
                         headers=headers)
    #print history_ret.json()
    if len(history_ret.json()["result"]) == 0:
        return 0
    else:
        history_ret = history_ret.json()["result"][0]
        #pprint(history_ret["value"])
        return history_ret["value"]
###然后通过集群名获取整个集群的总和监控值
def gethist_cluster(auth_id,cluster_name,opt):
    clsname = cluster_name
    opt = opt
    auth_id = getauth(zabbix_url,auth_data,headers)
    while not path.isfile("clusters.json"):
        savefile()
    cluster_file = json.load(open("clusters.json","r"))
    net_list = {"in":1,"out":2}
    if clsname in cluster_file.keys() and opt in net_list.keys():
        sum = 0
        cls = cluster_file[clsname]
        inf = net_list[opt]
        for host in cls:
            itemid = cls[host][inf]
            his_ret = int(gethist(auth_id,itemid,1,3))
            sum = sum + his_ret
        #print float(sum)/float(1024)
        return float(sum)/float(1024)
auth_id = getauth(zabbix_url,auth_data,headers)
#gethist(auth_id,25919,1,3)
print gethist_cluster(auth_id,"mysql_cluster","in")




然后将上面的代码保存为getsource.py文件用作模块导入,之所以不将所有py代码不写在一起也是为了更好看,更容易反复使用。
注:如果主机多的话会很慢吧~~~因为我没有写并发
然后是flask部分的web代码
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#coding: utf-8
from flask import Flask,jsonify,render_template
###flask的插件,用的restful作为提供api
from flask.ext import restful
###从上面的那个py文件导入我们需要的函数
from getsource import gethist,getauth,gethist_cluster,savefile
import json
from os import path
app = Flask(__name__)
api = restful.Api(app)
###zabix url
zabbix_pre = "http://10.10.102.88/zabbix/"
zabbix_url = zabbix_pre + "/api_jsonrpc.php"
###username and passwd
user = ""
passwd = ""
###auth data
auth_data = json.dumps(
{      
    "jsonrpc": "2.0",
    "method": "user.login",
    "params": {
    "user": "%s" %user,
    "password": "%s" %passwd
},   
"id": 0
})   
###headers
headers = {
    'content-type': 'application/json',
}   
###根据实际情况设定,这里给每个集群加了个id,用于排序,实际集群参考上面代码,这里也以nginx_cluser,tomcat_cluster,mysql_cluster为例
cluster_id = {
            "nginx_cluster":1,
            "tomcat_cluster":2,
            "mysql_cluster":7
    }
class MyApi(restful.Resource):
    def get(self,name,opt):
        cls = name
        opt = opt
        auth_id = getauth(zabbix_url,auth_data,headers)
        while not path.isfile("clusters.json"):
            savefile()
        cluster_file = json.load(open("clusters.json","r"))
        net_list = {"in":1,"out":2}
        if cls in cluster_file.keys() and opt in net_list.keys():
            sum = 0
            cls = cluster_file[cls]
            inf = net_list[opt]
            for host in cls:
                itemid = cls[host][inf]
                his_ret = int(gethist(auth_id,itemid,1,3))
                sum = sum + his_ret
            return float(sum)/float(1024)
        elif cls == "cluster_all" and opt == "traffic" :
            keys = cluster_file.keys()
            cls_ret = {}
            cls_lis = []
            for key in keys:
                dic = {}   
                dic["name"] = key
                dic["id"] = cluster_id[key]
                dic["in"] = gethist_cluster(auth_id,key,"in")
                dic["out"] = gethist_cluster(auth_id,key,"out")
                cls_lis.append(dic)
            cls_ret["ret"] = cls_lis
            return jsonify(cls_ret)
        elif cls == "cluster_all" and opt == "list":
            return jsonify(cluster_file)
        elif cls in cluster_id.keys() and opt == "list":
            ret = cluster_file[cls]
            return jsonify(ret)
        else:
            return "None"
api.add_resource(MyApi,"/api/<string:name>/<string:opt>")
@app.route("/")
def hello():
    return "Hello world 你好"
@app.route("/weathermap")
@app.route("/weathermap/<string:name>")
def weathermap(name=None):
    name = name
    if name == "all":
        return render_template("weathermap_all.html")
    elif name == "list":
        return render_template("weathermap_list.html")
    elif name == "plot":
        return render_template("weathermap_plot.html")
    else:
        return render_template("weathermap_all.html")
app.debug = True
app.run(host="0.0.0.0")



再是html模板文件
layout.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>Weather Map</title>
    <!-- Bootstrap -->
    <link href="/static/css/bootstrap.min.css" rel="stylesheet">
    <link rel="shortcut icon" href="static/img/flask.ico">
    <script src="/static/js/angular.min.js"></script>
    <script src="/static/js/d3.v3.min.js"></script>
  </head>
  <body>
  <nav class="navbar navbar-default navbar-static-top">
    <span class="label label-primary text-center">Beta</span>
    <h1>运维流量表</h1>
  </nav>
  {% block body %}{% endblock %}
  </body>
</html>



weathermap_all.hml
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
27
28
29
30
31
{% extends "layout.html" %}
{% block body %}
  <h3>集群流量一览表</h3>
    <div ng-app="myApp" ng-controller="myCtrl" class="col-md-10 col-md-offset-1">
        <table id="myTable" class="table table-hover">
          <thead>
            <tr>
              <th>ID</th>
              <th>集群名</th>
              <th>出口流量(KB/s)</th>
              <th>入口流量(KB/s)</th>
            </tr>
          </thead>
          <tbody>
            <tr ng-repeat="x in names | orderBy:'id'">
              <td ng-bind="x.id"></td>
              <td ng-bind="x.name"></td>
              <td ng-bind="x.out"></td>
              <td ng-bind="x.in"></td>
            </tr>
          </tbody>
        </table>
    </div>
   </div>
  </div>
    <script src="/static/js/jquery-1.11.3.min.js"></script>
    <script src="/static/js/bootstrap.min.js"></script>
    <script src="/static/js/netdata.js"></script>
    <script src="/static/js/cls_svg.js"></script>
{% endblock %}
</html>



weathermap_list.html
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
27
28
29
30
{% extends "layout.html" %}
{% block body %}
  <h3>集群流量一览表</h3>
    <div ng-app="myApp" ng-controller="myCtrl" class="col-md-10 col-md-offset-1">
        <table id="myTable" class="table table-hover">
          <thead>
            <tr>
              <th>ID</th>
              <th>集群名</th>
              <th>出口流量(KB/s)</th>
              <th>入口流量(KB/s)</th>
            </tr>
          </thead>
          <tbody>
            <tr ng-repeat="x in names | orderBy:'id'">
              <td ng-bind="x.id"></td>
              <td ng-bind="x.name"></td>
              <td ng-bind="x.out"></td>
              <td ng-bind="x.in"></td>
            </tr>
          </tbody>
        </table>
    </div>
   </div>
  </div>
    <script src="/static/js/jquery-1.11.3.min.js"></script>
    <script src="/static/js/bootstrap.min.js"></script>
    <script src="/static/js/netdata.js"></script>
{% endblock %}
</html>



weathermap_plot.html
1
2
3
4
5
6
7
{% block body %}
<h3>集群拓扑图</h3>
    <script src="/static/js/jquery-1.11.3.min.js"></script>
    <script src="/static/js/bootstrap.min.js"></script>
    <script src="/static/js/cls_svg.js"></script>
{% endblock %}
</html>



最后js文件
netdata.js
1
2
3
4
5
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $http) {
    $http.get("/api/cluster_all/traffic")
    .success(function(response) {$scope.names = response.ret;});
});



cls_svg.js
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
###假如是nginx_cluster,tomcat_cluster,mysql_cluster
var nodes = [ { name: "nginx_cluster" }, { name: "tomcat_cluster" },
              { name: "mysql_cluster" },{ name: "Internet" }];
var edges = [ { source : 0 , target: 1 } , { source : 0 , target: 2 } ,
               { source : 1 , target: 3 } , { source : 3 , target: 0}];
###上面是0到1,0到2,1到3,3到0的连线,数字分别对应上面的nodes里的name顺序
var width = 500;
var height = 500;
var svg = d3.select("body")
            .append("svg")
            .attr("width",width)
            .attr("height",height);
var force = d3.layout.force()
        .nodes(nodes)       //指定节点数组
        .links(edges)       //指定连线数组
        .size([width,height])   //指定范围
        .linkDistance(200)  //指定连线长度
        .charge([-400]);    //相互之间的作用力
force.start();  //开始作用
console.log(nodes);
console.log(edges);
//添加连线      
var svg_edges = svg.selectAll("line")
                    .data(edges)
                    .enter()
                    .append("line")
                    .style("stroke","#ccc")
                    .style("stroke-width",1);
var color = d3.scale.category20();
//添加节点         
var svg_nodes = svg.selectAll("circle")
                    .data(nodes)
                    .enter()
                    .append("circle")
                    .attr("r",20)
                    .style("fill",function(d,i){
                        return color(i);
                    })
                    .call(force.drag);  //使得节点能够拖动
//添加描述节点的文字
var svg_texts = svg.selectAll("text")
                    .data(nodes)
                    .enter()
                    .append("text")
                    .style("fill", "black")
                    .attr("dx", 20)
                    .attr("dy", 8)
                    .text(function(d){
                        return d.name;
                    });
force.on("tick", function(){    //对于每一个时间间隔
     //更新连线坐标
     svg_edges.attr("x1",function(d){ return d.source.x; })
            .attr("y1",function(d){ return d.source.y; })
            .attr("x2",function(d){ return d.target.x; })
            .attr("y2",function(d){ return d.target.y; });
     //更新节点坐标
     svg_nodes.attr("cx",function(d){ return d.x; })
            .attr("cy",function(d){ return d.y; });
     //更新文字坐标
     svg_texts.attr("x", function(d){ return d.x; })
        .attr("y", function(d){ return d.y; });
});



注:我会告诉你我直接去copy来的么,d3js还在钻研ing,所以仅作demo用
然后是目录结构
├── clusters.json
├── getsource.py
├── myapp.py
├── static
│   ├── css
│   │   └── bootstrap.min.css
│   └── js
│       ├── angular.min.js
│       ├── bootstrap.min.js
│       ├── cls_svg.js
│       ├── d3.v3.min.js
│       ├── jquery-1.11.3.min.js
│       └── netdata.js
└── templates
    ├── layout.html
    ├── weathermap_all.html
    ├── weathermap_list.html
    └── weathermap_plot.html

如果都完成了,整个项目是下面这样的
注:bootstrap,jquery,angularjs这些css,js文件百度Google下载吧

API:
查询jjjr2集群列表                                                 http://IP:5000/api/cluster_all/list
查询jjjr2集群流量进出口情况                                http://IP:5000/api/cluster_all/traffic
查询单个集群列表(如tomcat集群)                        http://IP:5000/api/tomcat_cluster/list
查询单个集群流量进出口情况                               http://IP:5000/api/tomcat_cluster/in    其中in,out分别代表入口,出口流量
查询单个主机流量进出口情况(暂不能提供)
比如
QQ截图20160307083336.jpg
访问:http//IP:5000/weathermap/list,仅访问列表

访问:http//IP:5000/weathermap/plot,仅访问拓扑图
访问:http//IP:5000/weathermap或者http//IP:5000/weathermap/all 查看列表与拓扑图在同一个页面

比如
QQ截图20160307083342.jpg
QQ截图20160307083349.jpg
存在问题:
1:mysql集群中包括了poms-mysql(后面更新)
2:拓扑图并不理想
3:页面不能实时刷新,通过在html页面加入<meta http-equiv="refresh" content="20">可页面自动刷新,可是不优雅,所以并未添加
4:并未设置阈值已区别各个集群健康情况
5:并没有考虑中间件之类,总而言之,现在很粗糙~~

  总结:我们将获取zabbix数据的代码部分抽离出来做成一个模块,这样就能分工明确,也为了让代码显得不是那么庞大很难看,然后web方面主要提供功能,API以及数据展示,通过API我们可以将数据反复利用,并且有很好的兼容性,web的展示当然不能少了bootstrap,一个多漂亮的样式库,不用自己设置css,然后数据操作通过AngularJS,前台通过AngularJS去调用自身提供的API以获取数据,然后填充,最后拓扑图用强大的D3JS,这是做前端的同事推荐的~~


  后记:我一直想写个项目,不是很大的项目,因为这样很快的就能写完,太大的项目要写太久太久~基于的工作阅历还不够感受到的痛点并不多,所以想到的点子并不多,并且也找到了很好的工具了,如果谁来俩点子,我帮你写出来呗~当然了,希望盈利的就算了,我想写的项目都是能直接放到github上~~大家一起爽的那种,哈哈。
  在一定意义上也是为了练手。
  话说,我的从无到有写一个运维APP系列如果这个月前,写不完,也就也写不完了~~~因为拖太长了,热情要没了~



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-187300-1-1.html 上篇帖子: Zabbix搭建过程 下篇帖子: Zabbix自带模板监控Windows上的MySQL数据库 流量 气象
累计签到:22 天
连续签到:1 天
发表于 2016-5-12 20:32:57 | 显示全部楼层
好厉害,有空自己研究。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表