文章目录
- 一、管理平台页面布局
- 二、登录页面
- 2.1 token登录
- 2.2. kubeconfig登录
- 2.3 添加装饰器
一、管理平台页面布局
应用名称:
dashboard:存放公共
k8s:
- Node:K8s集群计算节点。
- Namespaces:命名空间,用于隔离资源。
- PersistentVolumes(PV):持久卷,存储数据
workload:
- Deployments:无状态应用部署控制器。
- DaemonSets:守护进程控制器,在每个节点启动一个Pod。
- StatefulSets:有状态应用部署控制器。
- Pods:K8s最小部署单元
loadbalancer:
- Services:为Pod提供服务发现和负载均衡。
- Ingresses:集群中应用统一入口,对外暴露应用
storage:
- PersistentVolumeClaims(PVC):持久卷申请,与PV绑定。
- ConfigMaps:存储配置内容,例如应用程序配置文件。
- Secrets:存储应用敏感数据,例如用户名密码
二、登录页面
登录认证流程:
- AJAX提交登录认证数据 到服务端——> 验证提交数据格式合法性(编写一个登录认证检查函数)——> 确认没问题向session里写入认证信息 ——> 返回AJAX,AJAX跳转到首页。
2.1 token登录
- 验证token登录验证逻辑。若输入的token是正确有效的,则会将token写入到数据库中的session保存,方便下次登录。
1.根据布局创建对象的django 应用。
python manage.py startapp dashboard
python manage.py startapp k8s
python manage.py startapp workload
python manage.py startapp loadbalancer
python manage.py startapp storage
2.启用django默认数据库,用于保存session状态。
python manage.py makemigrations
python manage.py migrate
3.验证代码。
##########################################################
##自定义模块。
from kubernetes import client,config
import os
#连接k8s验证输入的token或者kubeconfig是否有效。
def auth_check(auth_type,token):
if auth_type == "token":
configuration = client.Configuration()
configuration.host = "https://192.168.161.120:6443" # APISERVER地址
# ca_file = os.path.join(os.getcwd(), "ca.crt") # K8s集群CA证书(/etc/kubernetes/pki/ca.crt)
# configuration.ssl_ca_cert= ca_file
configuration.verify_ssl = False
configuration.api_key = {"authorization": "Bearer " + token} ##固定格式。
client.Configuration.set_default(configuration)
apps_api = client.AppsV1Api()
try:
core_api = client.CoreApi()
core_api.get_api_versions() # 查看8s版本,由此验证是否有效的
return True
except Exception as e:
print(e)
return False
elif auth_type == "kubeconfig":
pass
##########################################################
##视图逻辑。
from django.shortcuts import render
from Layui import k8s ##导入自定义模块。
from django.http import JsonResponse
def index(request):
return render(request,'index.html')
def login(request):
if request.method == "GET":
return render(request,'login.html')
elif request.method == "POST":
token =request.POST.get("token")
#处理token登录。
if token:
if k8s.auth_check("token",token): # 如token是有效登录成功
request.session['is login'] = True
request.session['auth_type'] = token # 用于后期前端调用django,django拿这个信息去请k8s api
request.session['token'] = token
code = 0
msg = "登录成功"
else:
code = 1
msg = "Token无效!"
else:
#处理kubeconfig文件登录。
file_obj = request.FILES.get("file")
result = {'code': code,'msg': msg}
return JsonResponse(result)
##########################################################
##子模板文件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
<script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<style>
/* 整个内容区 */
body {
background-color: #edeff0;
}
.a {
width: 900px;
height: 400px;
background-color: white;
/* 定位到中间 */
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
/* 添加阴影 */
box-shadow: 0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12);
}
/* 头部蓝色背景 */
.c {
height: 60px;
width: 900px;
background-color: #326de6;
color: white;
font-size: 20px;
}
/* 头部蓝色中文字向右移动并居中*/
.c p {
padding-left: 300px;
padding-top: 12px;
font-weight: bold;
font-size: 26px;
letter-spacing: 1px;
}
/* 所有文字右、下移 */
.d,.e,.f,.g {
padding-left: 300px;
}
/* 给选择按钮加超链接并加粗 */
.d a, .e a {
font-weight: bold;
font-size: 18px;
text-decoration: none;
}
/* 超链接显示处理 */
a:active, a:link, a:visited, a:hover {color: black}
/* 文字左、右向内靠拢 */
.p {
padding-left: 10px;
padding-right: 10px;
}
/* 实心圆外面圆 */
.s {
display: block;
width: 18px;
height: 18px;
border-radius: 20px;
border: 2px solid gray;
float: left; /* 与Token水平 */
margin-right: 10px;
}
/* 实心圆 */
.ss {
display: block;
width: 10px;
height: 10px;
background-color: #326de6;
border-radius: 20px;
border: 2px solid white;
/* 上、左移动,让实心圆居中 */
position: relative;
top: 13%;
left: 10%;
}
.f, .g {
display: none; /* 默认两个input隐藏 */
}
.f input {
width: 500px;
height: 25px;
border-style: none;
border-bottom: 1px solid black;
outline: none; /* 点击输入框不显示外边框 */
margin-top: 10px;
margin-left: 10px;
}
.g input {
margin-top: 10px;
margin-left: 10px;
color: gray;
outline: none;
}
#btn {
height: 50px;
width: 150px;
margin-left: 400px;
margin-top: 40px;
border-style: none;
font-size: 22px;
background-color: #326de6;
color: white;
padding: 8px 15px 8px 15px;
outline: none;
box-shadow: 0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12);
}
#btn:hover {
cursor: pointer;
}
</style>
</head>
<body>
{% csrf_token %}
<div class="a">
<div class="b">
<div class="c">
<p>欢迎访问Kubernetes管理平台</p>
</div>
<div>
<div class="d">
<p><a href="#" id="tokenBtn"><span class="s" id="s1"><span id="ss1"></span></span>Token</a></p>
<p class="p"></p>
</div>
<div class="e">
<p><a href="#" id="kubeBtn"><span class="s" id="s2"><span id="ss2"></span></span>Kubeconfig</a></p>
<p class="p"></p>
</div>
<div class="f" id="token">
<input type="password" name="token" placeholder="输入token" >
</div>
<div class="g" id="kube">
<input type="file" name="kubeconfig" id="kubeconfig">
</div>
<p><button type="button" id="btn">登录</button> <span id="notice"></span></p>
</div>
</div>
</div>
<script type="text/javascript">
// 默认选中Toekn认证。
$("#token").css("display", "inline"); // 显示输入token
$("#s1").css("border", "2px solid #326de6"); // 边框改为蓝色
$("#ss1").addClass("ss"); // 添加蓝色实心圆
$("#tokenBtn").click(function () {
$("#token").css("display", "inline"); // 显示输入token
$("#kube").css("display", "none"); // 另外一个隐藏
$("#s1").css("border", "2px solid #326de6"); // 边框改为蓝色
$("#s2").css("border", "2px solid gray"); // 另外一个,边框改为灰色
$("#ss1").addClass("ss"); // 添加蓝色实心圆
$("#ss2").removeClass("ss"); // 去掉蓝色实心圆
});
$("#kubeBtn").click(function () {
$("#kube").css("display", "inline"); // 显示选择文件框
$("#token").css("display", "none"); // 另外一个隐藏
$("#s1").css("border", "2px solid gray"); // 另外一个,边框改为蓝灰色
$("#s2").css("border", "2px solid #326de6"); // 边框改为蓝色
$("#ss2").addClass("ss"); // 添加蓝色实心圆
$("#ss1").removeClass("ss"); // 去掉蓝色实心圆
});
$("#btn").click(function () {
var csrf_token = $('[name="csrfmiddlewaretoken"]').val();
// 判断选择的认证方式,即有实心圆类
if ($("#ss1").hasClass("ss")) {
var token = $("input[name='token']").val();
// 判断输入是否为空
if (! token) {
$("#notice").html("请输入Token!").css("color", "red");
return
}
var data = {'token': token, 'csrfmiddlewaretoken': csrf_token};
$.ajax({
type: "POST",
url: "/login/",
timeout: 5000,
dataType: "json",
data: data,
success: function(res) {
if (res.code == 0) {
location.href = "/"
} else if (res.code == 1){
$("#notice").html(res.msg).css("color", "red");
}
},
error: function (res) {
$("#notice").html("服务器接口异常!").css("color", "red");
}
})
} else if ($("#ss2").hasClass("ss")) {
var fd = new FormData();
// var file = $("input[name='kubeconfig']")[0].files[0]);
var file = $("#kubeconfig")[0].files[0];
if (! file) {
$("#notice").html("请选择kubeconfig文件!").css("color", "red");
return
}
fd.append('file', file);
fd.append("csrfmiddlewaretoken", csrf_token);
$.ajax({
type: "POST",
url: "/login/",
timeout: 5000,
dataType: "json",
data: fd,
processData: false,
contentType: false,
success: function(res) {
if (res.code == 0) {
location.href = "/"
} else if (res.code == 1){
$("#notice").html(res.msg).css("color", "red");
}
},
error: function () {
$("#notice").html("服务器接口异常!").css("color", "red");
}
})
}
})
</script>
</body>
</html>
##########################################################
##母版文件。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href="/static/layui/css/layui.css">
</head>
<div style="width: 100px;height: 100px;background-color: oldlace;display: none" id="qingjun">
</div>
<body>
<div class="layui-layout layui-layout-admin">
<div class="layui-header layui-bg-cyan">
<div class="layui-logo layui-hide-xs layui-bg-cyan">DevOps管理平台</div>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item layui-hide layui-show-md-inline-block">
<a href="/logout">
<img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg" class="layui-nav-img">
退出
</a>
<!--
<dl class="layui-nav-child">
<dd><a href="">Your Profile</a></dd>
<dd><a href="">Settings</a></dd>
<dd><a href="">Sign out</a></dd>
</dl>
-->
</li>
<!--
<li class="layui-nav-item" lay-header-event="menuRight" lay-unselect>
<a href="javascript:;">
<i class="layui-icon layui-icon-more-vertical"></i>
</a>
</li>
-->
</ul>
</div>
<div class="layui-side layui-bg-black">
<div class="layui-side-scroll layui-bg-cyan">
<!-- 左侧导航区域(可配合layui已有的垂直导航) -->
<ul class="layui-nav layui-nav-tree layui-bg-cyan" lay-filter="test">
<li class="layui-nav-item">
<a class="" href="/"><i class="layui-icon layui-icon-home" style="color: #00FFFF;font-size: 20px"> 仪表盘</i></a>
</li>
<li class="layui-nav-item {% block item-1 %}{% endblock %}">
<a class="" href="javascript:;"><i class="layui-icon layui-icon-app" style="color: #01AAED;font-size: 15px"> Kubernetes</i></a>
<dl class="layui-nav-child">
<dd><a href="{% url 'node' %}" class="{% block item-1-1 %}{% endblock %}">Node</a></dd>
<dd><a href="{% url 'namespace' %}" class="{% block item-1-2 %}{% endblock %}">NameSpace</a></dd>
</dl>
</li>
<li class="layui-nav-item {% block item-2 %}{% endblock %}">
<a href="javascript:;"><i class="layui-icon layui-icon-template-1" style="color: #01AAED;font-size: 15px"> Workload</i></a>
<dl class="layui-nav-child">
<dd><a href="{% url 'deployment' %}" class="{% block item-2-1 %}{% endblock %}">Deployment</a></dd>
<dd><a href="{% url 'daemonset' %}" class="{% block item-2-2 %}{% endblock %}">DaemonSet</a></dd>
{# <dd><a href="">超链接</a></dd>#}
</dl>
{# </li>#}
{# <li class="layui-nav-item"><a href="javascript:;">click menu item</a></li>#}
{# <li class="layui-nav-item"><a href="">the links</a></li>#}
</ul>
</div>
</div>
<div class="layui-body" style="background-color: #cccccc">
<!-- 内容主体区域 -->
<div style="padding: 15px;">{% block context%}{% endblock %}</div>
</div>
<div class="layui-footer" style="text-align: center">
<!-- 底部固定区域 -->
k8s管理平台
</div>
</div>
<script src="/static/layui/layui.js"></script>
{% block custom_js %}{% endblock %}
<script>
//JS
layui.use(['element', 'layer', 'util'], function(){
var element = layui.element
,layer = layui.layer
,util = layui.util
,$ = layui.$;
//头部事件
util.event('lay-header-event', {
//左侧菜单事件
menuLeft: function(othis){
layer.msg('展开左侧菜单的操作', {icon: 0});
}
,menuRight: function(){
layer.open({
type: 1
,content: '<div style="padding: 15px;">处理右侧面板的操作</div>'
,area: ['260px', '100%']
,offset: 'rt' //右上角
,anim: 5
,shadeClose: true
});
}
});
});
</script>
</body>
</html>
4.token验证,查看数据库是否保存了token信息。
5.验证数据库中的session保存的返回信息。
2.2. kubeconfig登录
- 验证使用正确的kubeconfig文件登录,则会登录到主页。
1.自定义一个类,在数据库中创建一张表,用于保存kubeconfig文件内容。
#######################################################
##生成一张数据库表,用于保存kubeconfig文件内容。dasshboard/models下定义一个类。
from django.db import models
class User(models.Model):
auth_type = models.CharField(max_length=30)
token = models.CharField(max_length=100)
content = models.TextField()
datetime = models.DateTimeField(auto_now=True)
#######################################################
##同步数据库。settings文件添加如下一行。
INSTALLED_APPS = [
......
'dashboard'
]
python manage.py makemigrations
python manage.py migrate
2.添加视图。
import requests
from django.shortcuts import render,redirect
from Layui import k8s ##导入自定义模块。
from django.http import JsonResponse
from dashboard.models import User
def login(request):
if request.method == "GET":
return render(request,'login.html')
elif request.method == "POST":
token =request.POST.get("token")
#处理token登录。
if token:
if k8s.auth_check("token",token): # 如token是有效登录成功
request.session['is_login'] = True
request.session['auth_type'] = 'token' # 用于后期前端调用django,django拿这个信息去请k8s api
request.session['token'] = token
code = 0
msg = "登录成功"
else:
code = 1
msg = "Token无效!"
else:
#处理kubeconfig文件登录。
file_obj = request.FILES.get("file")
import random
token_random = str(random.random()).split('.')[1] ##生成一个随机数作为标识。
try:
content = file_obj.read().decode() ##bytes ——> str
User.objects.create(
auth_type="kubeconfig",
token=token_random,
content=content
)
code = 0
msg = "登陆成功"
except Exception:
code = 1
msg = "kubeconfig文件错误!"
if k8s.auth_check('kubeconfig',token_random):
request.session['is_login'] = True
request.session['auth_type'] = 'kubeconfig' # 用于后期前端调用django,django拿这个信息去请k8s api
request.session['token'] = token_random
code = 0
msg = "登陆成功"
else:
User.objects.get(token=token_random).delete()
code = 1
msg = "kubeconfig文件无效!!!"
result = {'code': code,'msg': msg}
return JsonResponse(result)
3.修改自定义模块类。
from kubernetes import client,config
import os
from dashboard.models import User
import yaml
# 连接k8s验证输入的token或者kubeconfig是否有效。
def auth_check(auth_type,token=None):
if auth_type == "token":
configuration = client.Configuration()
configuration.host = "https://192.168.161.120:6443" # APISERVER地址
# ca_file = os.path.join(os.getcwd(), "ca.crt") # K8s集群CA证书(/etc/kubernetes/pki/ca.crt)
# configuration.ssl_ca_cert= ca_file
configuration.verify_ssl = False
configuration.api_key = {"authorization": "Bearer " + token} ##固定格式。
client.Configuration.set_default(configuration)
apps_api = client.AppsV1Api()
try:
core_api = client.CoreApi()
core_api.get_api_versions() # 查看8s版本,由此验证是否有效的
return True
except Exception as e:
print(e)
return False
elif auth_type == "kubeconfig":
user = User.objects.get(token=token)
content = user.content
yaml_content = yaml.load(content, Loader=yaml.FullLoader) ##yaml文件转为json
print(yaml_content)
try:
config.load_kube_config_from_dict(yaml_content)
core_api = client.CoreApi()
core_api.get_api_versions() # 查看k8s版本,由此验证是否有效的
return True
except Exception as e:
print(e)
return False
4.使用正确的Kubeconfig文件登陆成功,其他文件登陆失败。
2.3 添加装饰器
- 引用装饰器,使得访问127.0.0.1:8000也是登录页面,而不是首页。
1.在自定义模块文件中添加。
from django.shortcuts import redirect
def self_login_required(func):
def inner(request, *args, **kwargs):
is_login = request.session.get('is_login', True)
if is_login:
return func(request, *args, **kwargs)
else:
return redirect("/login")
return inner
2.首页引用装饰器。
@k8s.self_login_required
def index(request):
return render(request,'index.html')
3.查看效果。