首页 文章 精选 留言 我的

精选列表

搜索[全模态模型],共10000篇文章
优秀的个人博客,低调大师

前端常见跨域解决方案(全)

什么是跨域? 跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。 广义的跨域: 1.) 资源跳转: A链接、重定向、表单提交 2.) 资源嵌入: <link>、<script>、<img>、 <frame>等dom标签, 还有样式中background:url()、 @font-face()等文件外链 3.) 脚本请求: js发起的ajax请求、dom和js对象的跨域操作等 其实我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景。 什么是同源策略? 同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。 同源策略限制以下几种行为: 1.) Cookie、LocalStorage 和 IndexDB 无法读取 2.) DOM 和 Js对象无法获得 3.) AJAX 请求不能发送 常见跨域场景 跨域解决方案 1、 通过jsonp跨域 2、 document.domain + iframe跨域 3、 location.hash + iframe 4、 window.name + iframe跨域 5、 postMessage跨域 6、 跨域资源共享(CORS) 7、 nginx代理跨域 8、 nodejs中间件代理跨域 9、 WebSocket协议跨域 一、 通过jsonp跨域 通常为了减轻web服务器的负载,我们把js、css,img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。 1.)原生实现: <script> var script = document.createElement('script'); script.type = 'text/javascript'; // 传参并指定回调执行函数为onBack script.src = 'http://www.domain2.com:8080/ login?user=admin&callback=onBack'; document.head.appendChild(script); // 回调执行函数 function onBack(res) { alert(JSON.stringify(res)); } </script> 服务端返回如下(返回时即执行全局函数): onBack({"status":true,"user":"admin"}) 2.)jquery ajax: $.ajax({ url: 'http://www.domain2.com:8080/login', type: 'get', dataType: 'jsonp', // 请求方式为jsonp jsonpCallback: "onBack", // 自定义回调函数名 data: {} }); 3.)vue.js: this.$http.jsonp(' http://www.domain2.com:8080/login', { params: {}, jsonp: 'onBack'}).then((res) => { console.log(res); }) 后端node.js代码示例: var querystring = require('querystring'); var http = require('http'); var server = http.createServer(); server.on('request', function(req, res) { var params = qs.parse(req.url.split('?')[1]); var fn = params.callback; // jsonp返回设置 res.writeHead(200, { 'Content-Type': 'text/javascript' }); res.write(fn + '(' + JSON.stringify(params) + ')'); res.end(); }); server.listen('8080'); console.log('Server is running at port 8080...'); jsonp缺点:只能实现get一种请求。 二、 document.domain + iframe跨域 此方案仅限主域相同,子域不同的跨域应用场景。 实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。 1.)父窗口:(http://www.domain.com/a.html) <iframe id="iframe" src="http://child.domain.com/b.html"> </iframe><script> document.domain = 'domain.com'; var user = 'admin';</script> 2.)子窗口:(http://child.domain.com/b.html) <script> document.domain = 'domain.com'; // 获取父窗口中变量 alert('get js data from parent ---> ' + window.parent.user); </script> 三、 location.hash + iframe跨域 实现原理: a欲与b跨域相互通信,通过中间页c来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接js访问来通信。 具体实现:A域:a.html -> B域:b.html -> A域:c.html,a与b不同域只能通过hash值单向通信,b与c也不同域也只能单向通信,但c与a同域,所以c可通过parent.parent访问a页面所有对象。 1.)a.html:(http://www.domain1.com/a.html) <iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"> </iframe> <script> var iframe = document.getElementById('iframe'); // 向b.html传hash值 setTimeout(function() { iframe.src = iframe.src + '#user=admin'; }, 1000); // 开放给同域c.html的回调方法 function onCallback(res) { alert('data from c.html ---> ' + res); } </script> 2.)b.html:(http://www.domain2.com/b.html) <iframe id="iframe" src="http://www.domain1.com/c.html" style="display:none;"> </iframe> <script> var iframe = document.getElementById('iframe'); // 监听a.html传来的hash值,再传给c.html window.onhashchange = function () { iframe.src = iframe.src + location.hash; }; </script> 3.)c.html:(http://www.domain1.com/c.html) <script> // 监听b.html传来的hash值 window.onhashchange = function () { // 再通过操作同域a.html的js回调, 将结果传回 window.parent.parent.onCallback('hello: ' + location.hash.replace('#user=', '')); }; </script> 四、 window.name + iframe跨域 window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。 1.)a.html:(http://www.domain1.com/a.html) var proxy = function(url, callback) { var state = 0; var iframe = document.createElement('iframe'); // 加载跨域页面 iframe.src = url; // onload事件会触发2次, 第1次加载跨域页, 并留存数据于window.name iframe.onload = function() { if (state === 1) { // 第2次onload(同域proxy页)成功后, 读取同域window.name中数据 callback(iframe.contentWindow.name); destoryFrame(); } else if (state === 0) { // 第1次onload(跨域页)成功后, 切换到同域代理页面 iframe.contentWindow.location = 'http://www.domain1.com/proxy.html'; state = 1; } }; document.body.appendChild(iframe); // 获取数据以后销毁这个iframe, 释放内存; 这也保证了安全(不被其他域frame js访问) function destoryFrame() { iframe.contentWindow.document.write(''); iframe.contentWindow.close(); document.body.removeChild(iframe); } }; // 请求跨域b页面数据proxy ('http://www.domain2.com/b.html', function(data) { alert(data); }); 2.)proxy.html:(http://www.domain1.com/proxy.... 中间代理页,与a.html同域,内容为空即可。 3.)b.html:(http://www.domain2.com/b.html) <script> window.name = 'This is domain2 data!'; </script> 总结:通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。 五、 postMessage跨域 postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题: a.) 页面和其打开的新窗口的数据传递 b.) 多窗口之间消息传递 c.) 页面与嵌套的iframe消息传递 d.) 上面三个场景的跨域数据传递 用法:postMessage(data,origin)方法接受两个参数 data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。 origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。 1.)a.html:(http://www.domain1.com/a.html) <iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"> </iframe> <script> var iframe = document.getElementById('iframe'); iframe.onload = function() { var data = { name: 'aym' }; // 向domain2传送跨域数据 iframe.contentWindow.postMessage (JSON.stringify(data), 'http://www.domain2.com'); }; // 接受domain2返回数据 window.addEventListener ('message', function(e) { alert('data from domain2 ---> ' + e.data); }, false); </script> 2.)b.html:(http://www.domain2.com/b.html) <script> // 接收domain1的数据 window.addEventListener ('message', function(e) { alert('data from domain1 ---> ' + e.data); var data = JSON.parse(e.data); if (data) { data.number = 16; // 处理后再发回domain1 window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com'); } }, false);</script> 六、 跨域资源共享(CORS) 普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。 需注意的是:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。如果想实现当前页cookie的写入,可参考下文:七、nginx反向代理中设置proxy_cookie_domain 和 八、NodeJs中间件代理中cookieDomainRewrite参数的设置。 目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。 1、 前端设置: 1.)原生ajax // 前端设置是否带cookiexhr.withCredentials = true; 示例代码: var xhr = new XMLHttpRequest(); // IE8/9需用 window.XDomainRequest兼容 // 前端设置是否带 cookiexhr.withCredentials = true; xhr.open('post', 'http://www.domain2.com:8080/login', true); xhr.setRequestHeader ('Content-Type', ' application/x-www-form-urlencoded'); xhr.send('user=admin'); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { alert(xhr.responseText); } }; 2.)jQuery ajax $.ajax({ ... xhrFields: { withCredentials: true // 前端设置是否带cookie }, crossDomain: true, // 会让请求头中包含跨域的额外信息, 但不会含cookie ... }); 3.)vue框架 在vue-resource封装的ajax组件中加入以下代码: Vue.http.options.credentials =true 2、 服务端设置: 若后端设置成功,前端浏览器控制台则不会出现跨域报错信息,反之,说明没设成功。 1.)Java后台: /* * 导入包: import javax.servlet.http.HttpServletResponse; * 接口参数中定义: HttpServletResponse response */response.setHeader ("Access-Control-Allow-Origin", "http://www.domain1.com"); // 若有端口需写全(协议+域名+端口) response.setHeader ("Access-Control-Allow-Credentials", "true"); 2.)Nodejs后台示例: var http = require('http');var server = http.createServer();var qs = require('querystring'); server.on('request', function(req, res) { var postData = ''; // 数据块接收中 req.addListener('data', function(chunk) { postData += chunk; }); // 数据接收完毕 req.addListener('end', function() { postData = qs.parse(postData); // 跨域后台设置 res.writeHead(200, { 'Access-Control-Allow-Credentials': 'true', // 后端允许发送Cookie 'Access-Control-Allow-Origin': 'http://www.domain1.com', // 允许访问的域(协议+域名+端口) 'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com; HttpOnly' // HttpOnly:脚本无法读取cookie }); res.write(JSON.stringify(postData)); res.end(); }); }); server.listen('8080');console.log('Server is running at port 8080...'); 七、 nginx代理跨域 1、 nginx配置解决iconfont跨域 浏览器跨域访问js、css、img等常规静态资源被同源策略许可,但iconfont字体文件(eot|otf|ttf|woff|svg)例外,此时可在nginx的静态资源服务器中加入以下配置。 location / { add_header Access-Control-Allow-Origin *; } 2、 nginx反向代理接口跨域 跨域原理: 同源策略是浏览器的安全策略,不是HTTP协议的一部分。服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,也就不存在跨越问题。 实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。 nginx具体配置: #proxy服务器server { listen 81; server_name www.domain1.com; location / { proxy_pass http://www.domain2.com:8080; #反向代理 proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名 index index.html index.htm; # 当用webpack-dev-server等中间件代理接口访问nignx时, 此时无浏览器参与, 故没有同源限制, 下面的跨域配置可不启用 add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不带cookie时, 可为* add_header Access-Control-Allow-Credentials true; } } 1.) 前端代码示例: var xhr = new XMLHttpRequest(); // 前端开关: 浏览器是否读写cookiexhr.withCredentials = true; // 访问nginx中的代理服务器 xhr.open('get', 'http://www.domain1.com:81/?user=admin', true); xhr.send(); 2.) Nodejs后台示例: var http = require('http'); var server = http.createServer(); var qs = require('querystring'); server.on('request', function(req, res) { var params = qs.parse(req.url.substring(2)); // 向前台写cookie res.writeHead(200, { 'Set-Cookie': 'l=a123456; Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly:脚本无法读取 }); res.write(JSON.stringify(params)); res.end(); }); server.listen('8080'); console.log('Server is running at port 8080...'); 八、 Nodejs中间件代理跨域 node中间件实现跨域代理,原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发,也可以通过设置cookieDomainRewrite参数修改响应头中cookie中域名,实现当前域的cookie写入,方便接口登录认证。 1、 非vue框架的跨域(2次跨域) 利用node + express + http-proxy-middleware搭建一个proxy服务器。 1.)前端代码示例: var xhr = new XMLHttpRequest(); // 前端开关: 浏览器是否读写cookiexhr.withCredentials = true; // 访问http-proxy-middleware代理服务器 xhr.open('get', ' http://www.domain1.com:3000/login? user=admin', true); xhr.send(); 2.)中间件服务器: var express = require('express'); var proxy = require('http-proxy-middleware'); var app = express(); app.use('/', proxy({ // 代理跨域目标接口 target: 'http://www.domain2.com:8080', changeOrigin: true, // 修改响应头信息,实现跨域并允许带cookie onProxyRes: function(proxyRes, req, res) { res.header('Access-Control-Allow-Origin', 'http://www.domain1.com'); res.header('Access-Control-Allow-Credentials', 'true'); }, // 修改响应信息中的cookie域名 cookieDomainRewrite: 'www.domain1.com' // 可以为false,表示不修改})); app.listen(3000);console.log(' Proxy server is listen at port 3000...'); 3.)Nodejs后台同(六:nginx) 2、 vue框架的跨域(1次跨域) 利用node + webpack + webpack-dev-server代理接口跨域。在开发环境下,由于vue渲染服务和接口代理服务都是webpack-dev-server同一个,所以页面与代理接口之间不再跨域,无须设置headers跨域信息了。 webpack.config.js部分配置: module.exports = { entry: {}, module: {}, ... devServer: { historyApiFallback: true, proxy: [{ context: '/login', target: 'http://www.domain2.com:8080', // 代理跨域目标接口 changeOrigin: true, secure: false, // 当代理某些https服务报错时用 cookieDomainRewrite: 'www.domain1.com' // 可以为false,表示不修改 }], noInfo: true } } 九、 WebSocket协议跨域 WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。 原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。 1.)前端代码: <div>user input: <input type="text"> </div> <script src="./socket.io.js"> </script> <script>var socket = io(' http://www.domain2.com:8080'); // 连接成功处理 socket.on('connect', function() { // 监听服务端消息 socket.on('message', function(msg) { console.log('data from server: ---> ' + msg); }); // 监听服务端关闭 socket.on('disconnect', function() { console.log('Server socket has closed.'); }); }); document.getElementsByTagName('input') [0].onblur = function() { socket.send(this.value); }; </script> 2.)Nodejs socket后台: var http = require('http'); var socket = require('socket.io'); // 启http服务 var server = http.createServer(function(req, res) { res.writeHead(200, { 'Content-type': 'text/html' }); res.end(); }); server.listen('8080'); console.log('Server is running at port 8080...'); // 监听socket连接 socket.listen(server).on('connection', function(client) { // 接收信息 client.on('message', function(msg) { client.send('hello:' + msg); console.log('data from client: ---> ' + msg); }); // 断开处理 client.on('disconnect', function() { console.log('Client socket has closed.'); }); }); 完~ 本文作者:web前端开发V 本文发布时间:2018年03月07日 本文来自云栖社区合作伙伴 CSDN,了解相关信息可以关注csdn.net网站。

优秀的个人博客,低调大师

AliOS Things全链路优化-CoAP FOTA

FOTA(Firmware Over-The-Air)即空中固件升级功能;CoAP(Constrained Application Protocol),字面意思为受限的应用协议,基于UDP,专为资源有限的物联网设备量身定制;所以AliOS Things的纯CoAP FOTA就是专为资源有限的物联网设备(如基于NB-IoT,LoRa)提供的远程固件升级功能。 1.AliOS Things1.1.2 FOTA简介 我们先看一下当前版本(AliOS Thing1.1.2)的FOTA结构图: 简要介绍: 信息交互通道:指与特定的云平台交互更新信息如版本上报、查询,下载链接获取,进度上报等控制或通知类信息; 下载通道:通过1中获取的下载链接下载指定固件; FOTA service:fota主服务; 版本管理:维护升级前后的固件版本; Sec

优秀的个人博客,低调大师

Android之Monkey全参数(包含隐藏参数)

http://blog.csdn.net/jlminghui/article/details/38238443 参数如下: 注意:以下例子中命令均为Windows cmd命令窗口运行环境,往外官网列出的参数并不是全部参数,更全的参数要看monkey源代码。 一、常规 1、-help 作用:列出简单的用法。 例:adb shell monkey -help 注:一般很少用到此参数,偷懒的做法直接输入adb shell monkey就可以看到简单用法列表。 2、-v 作用:命令行上的每一个-v都将增加反馈信息的详细级别。 Level0(默认),除了启动、测试完成和最终结果外只提供较少的信息。 Level1,提供了较为详细的测试信息,如逐个发送到Activity的事件信息。 Level2,提供了更多的设置信息,如测试中选中或未选中的Activity信息。 例:adb shell monkey -v 10 注:比较常用的是-v -v -v,即最多详细信息,一般会保存到指定文件中供开发人员查找bug原因时使用。 二、事件 1、-s <seed> 作用:伪随机数生成器的seed值。如果用相同的seed值再次运行monkey,将生成相同的事件序列。 例:adb shell monkey -s 12345 -v 10 2、--throttle <milliseconds> 作用:在事件之间插入固定的时间(毫秒)延迟,你可以使用这个设置来减缓Monkey的运行速度,如果你不指定这个参数,则事件之间将没有延迟,事件将以最快的速度生成。 例:adb shell monkey --throttle 300 -v 10 注:常用参数,一般设置为300毫秒,原因是实际用户操作的最快300毫秒左右一个动作事件,所以此处一般设置为300毫秒。 3、--pct-touch <percent> 作用:调整触摸事件的百分比。(触摸事件是指在屏幕中的一个down-up事件,即在屏幕某处按下并抬起的操作) 例:adb shell monkey --pct-touch 100 -v 10 注:常用参数,此参数设置要适应当前被测应用程序的操作,比如一个应用80%的操作都是触摸,那就可以将此参数的百分比设置成相应较高的百分比。 4、--pct-motion <percent> 作用:调整motion事件百分比。(motion事件是由屏幕上某处一个down事件、一系列伪随机的移动事件和一个up事件组成) 例:adb shell monkey --pct-motion 100 -v 10 注:常用参数,需注意的是移动事件是直线滑动,下面的trackball移动包含曲线移动。 5、--pct-trackball <percent> 作用:调整滚动球事件百分比。(滚动球事件由一个或多个随机的移动事件组成,有时会伴随着点击事件) 例:adb shell monkey --pct-trackball 100 -v 10 注:不常使用参数,现在手机几乎没有滚动球,但滚动球事件中包含曲线滑动事件,在被测程序需要曲线滑动时可以选用此参数。 6、--pct-nav <percent> 作用:调整基本的导航事件百分比。(导航事件由方向输入设备的上下左右按键所触发的事件组成) 例:adb shell monkey --pct-nav 100 -v 10 注:不常用操作。 7、--pct-majornav <percent> 作用:调整主要导航事件的百分比。(这些导航事件通常会导致UI界面中的动作事件,如5-way键盘的中间键,回退按键、菜单按键) 例:adb shell monkey --pct-majornav 100 -v 10 注: 8、--pct-syskeys <percent> 作用:调整系统事件百分比。(这些按键通常由系统保留使用,如Home、Back、Start Call、End Call、音量调节) 例:adb shell monkey --pct-syskeys 100 -v 10 注:不常用。 9、--pct-appswitch <percent> 作用:调整Activity启动的百分比。(在随机的时间间隔中,Monkey将执行一个startActivity()调用,作为最大程度覆盖被测包中全部Activity的一种方法) 例:adb shell monkey --pct-appswitch 100 -v 5 注:不常用。 10、--pct-anyevent 作用:调整其他事件的百分比。(这包含所有其他事件,如按键、其他在设备上不常用的按钮等) 例:adb shell monkey --pct-anyevent 100 -v 5 注:不常使用。 三、约束条件 1、-p <allowed-package-name> 作用:如果你指定一个或多个包,Monkey将只允许访问这些包中的Activity。如果你的应用程序需要访问这些包(如选择联系人)以外的Activity,你需要指定这些包。如果你不指定任何包,Monkey将允许系统启动所有包的Activity。指定多个包,使用多个-p,一个-p后面接一个包名。 例:adb shell monkey -p com.android.browser -v 10 注:常用参数。 2、-c <main-category> 作用:如果你指定一个或多个类别,Monkey将只允许系统启动这些指定类别中列出的Activity。如果你不指定任何类别,Monkey将选择谢列类别中列出的Activity,Intent.CATEGORY_LAUNCHER和Intent.CATEGORY_MONKEY。指定多个类别使用多个-c,每个-c指定一个类别。 例: 注:不常用。 3、--dbg-no-events 作用:设置此选项,Monkey将执行初始启动,进入一个测试Activity,并不会在进一步生成事件。为了得到最佳结果,结合参数-v,一个或多个包的约束,以及一个保持Monkey运行30秒或更长时间的非零值,从而提供了一个可以监视应用程序所调用的包之间转换的环境。 例: 注:不常用。 4、--hprof 作用:设置此选项,将在Monkey生成事件序列前后生成profilling报告。在data/misc路径下生成大文件(~5Mb),所以要小心使用。 例: 注:不常用。 5、--ignore-crashes 作用:通常,应用发生崩溃或异常时Monkey会停止运行。如果设置此项,Monkey将继续发送事件给系统,直到事件计数完成。 例: 注:常用。 6、--ignore-timeouts 作用:通常,应用程序发生任何超时错误(如“Application Not responding”对话框)Monkey将停止运行,设置此项,Monkey将继续发送事件给系统,直到事件计数完成。 例: 注:常用。 7、--ignore-security-exception 作用:通常,当程序发生许可错误(例如启动一些需要许可的Activity)导致的异常时,Monkey将停止运行。设置此项,Monkey将继续发送事件给系统,直到事件计数完成。 例: 注:常用。 8、--kill-process-after-error 作用:通常,当Monkey由于一个错误而停止时,出错的应用程序将继续处于运行状态。设置此项,将会通知系统停止发生错误的进程。注意,正常(成功)的结束,并没有停止启动的进程,设备只是在结束事件之后简单的保持在最后的状态。 例: 注: 9、--monitor-native-crashes 作用:监视并报告Andorid系统中本地代码的崩溃事件。如果设置--kill-process-after-error,系统将停止运行。 例: 注: 10、--wait-dbg 作用:停止执行中的Monkey,直到有调试器和它相连接。 例: 注: ======================================================================================================================= 以下参数为Monkey官网中为列出,但命令行帮助中可以显示的参数,先列出,以后抽时间整理其使用方法 --pct-rotation --pct-pinchzoom --pkg-blacklist-file --pkg-whitelist-file --randomize-throttle --port --setup -f --profile-wait --device-sleep-time --randomize-script --script-log --bugreport --periodic-bugreport -h 本文转自wanqi博客园博客,原文链接:http://www.cnblogs.com/wanqieddy/p/4312814.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

IBM基于Kubernetes的容器云全解析

讲师介绍 刘光亚IBM云计算开发架构师 Apache Mesos PMC & Committer OpenStack Magnum Core Member Member - IBM Academy of Technology 西安Mesos & OpenStack Meetup组织者 基于Kubernetes的容器云 容器云最主要的功能是以应用为中心,帮助用户把所有的应用以容器的形式在分布式里面跑起来,最后把应用以服务的形式呈现给用户。容器云里有两个关键点,一是容器编排,二是资源调度。 容器编排就是我们期望能把一些微服务通过容器编排来帮助用户组建一个比较庞大的系统,而资源调度在容器云这种大规模分布式环境是必须的,需要一个比较好的调度平台来提升系统的资源利用率以及根据用户的资源请求帮助用户来调配资源。 我们IBM的BlueDock就是这样一个容器云平台,主要基于Kubernetes实现了容器的编排和资源调度,并默认使用Mesos作为底层的资源管理器,但如果用户没有运行多个framework的需求,可不使用Mesos。 为什么是Kubernetes和Mesos 为什么选择Kubernetes和Mesos作为容器云的基础平台?在项目启动前,我们对当前流行的容器社区做了很多调研,主要是Docker、Mesos和Kubernetes社区。 我们先看一下Docker,Docker社区主要由Docker公司把控,虽然是开源的,但其实Docker社区相对来说不是很开放,因为Docker公司有基于Docker的所有产品,包括Docker的公有云、私有云Docker Data Center等等。这样就导致了其他公司如果想基于Docker创业的话会比较困难,因为难以与Docker公司竞争。 而Mesos社区则更开放一些,主要原因是Mesosphere在基于Mesos研发了DC/OS,正在积极寻找一些合作者来推动DC/OS在企业的落地。同时Mesosphere也期望更多的公司、更多的人加入到这个社区,增加Mesos的影响力。所以这个社区相对Docker来说更开放一些,而且Mesos已经有很多落地的案例,在刚结束的MesosCon Asia上,我们可以看到国内其实有很多骨灰级的Mesos用户,但这些用户过于低调,没有及时将自己的经验分享出来,所以也希望这些用户或已在生产使用Mesos的用户能及时为大家分享一些经验,促进Mesos生态的发展。 相比起来,Kubernetes社区是最开放、最活跃、最多元化的,虽然Kubernetes是Google开源的,但Google没有任何一个产品是基于Kubernetes的。这样就给了大家很公平的机会,基本上每个人、每个公司都可以基于Kubernetes开发自己的产品。但Kubernetes目前欠缺的是一些落地的案例,另外其支持的集群规模大小也需要提升。 我曾试着把容器的这几个社区和我们以前做虚拟化的社区做过一些对比,不知道合不合适,Docker可以类比到VMWare,Mesos可以类比到Citrix,Kubernetes可以类比到KVM。大家可以在调研选型或者使用的时候,根据自己的需求选择合适的技术。 另外一个问题,大家应该可以看到Mesos和Kubernetes都在提供除了Docker之外的容器管理能力,Mesos花了很多时间去做Unified Container这个项目,目的就是即使没有Docker Daemon,用户也可运行Docker容器,同时使用Unified Container,还可运行其他容器,例如AppC、OCI等;Kubernetes也在集成Rkt给用户除了Docker之外的另一种选择。 整体架构 以上是我们容器云的总体概览,最左边是我们很熟悉的云平台的最重要的三层,IaaS、PaaS、SaaS,我们的BlueDock主要是提供PaaS的功能,是基于Kubernetes和Mesos(可选)来研发的。但如果我们建容器云的话,只有这两个是远远不够的,因为容器云里还有很多其他的功能,所以我们围绕着Kubernetes和Mesos,在上面加了很多企业级的东西,包括应用商店,资源调度的改进策略,应用、服务器的双层扩展,多租户管理,镜像管理,统一界面等等。应用商店:最主要的功能是把用户常用的一些应用做成模板,类似手机上的App Store,用户可以很方便地通过应用市场来对应用进行部署,同时BlueDock还支持对不同版本的应用在同一个应用商店进行管理。我们还支持用户对应用市场进行定制,这样就可以让用户把一些自己常用的应用上传到应用商店,供其它用户使用。资源调度的改进策略:因为容器的使用是一种高密度计算,对资源调度的要求很高,尤其是一些资源的抢占策略等等,这部分是原生的Kubernetes和Mesos都没有的功能,IBM对这块功能做了很大的改进,为容器云加入了资源抢占的功能。应用、服务器的双层扩展:这个我们可以理解为是一种联动扩展。当用户的应用因为负载的变化在扩展的时候,如果发现底层的服务器不够了,那应用就没办法去扩展了。这时我们的容器云就会和底层的OpenStack交互,通过OpenStack去申请一些新的服务器加入到容器云中,实现了容器云平台和用于应用的联动扩展。我们的容器云可以和多个不同的云平台集成,实现联动扩展的功能。多租户管理:这块主要是和OpenStack Keystone集成来对租户进行管理,同时将Keystone的Project映射为Kubernetes的namespace。另外一个是我们还通过和Keystone集成实现了层级的租户管理。按照这种层级的租户管理,一个很大的优势是可以按照层级的结构来对资源做事先的定义,这样的话就可以和企业的组织架构就可以很好的匹配起来,便于企业内部的资源分配。镜像管理:这个服务主要是对镜像进行管理,然后我们也调研了很多开源的对镜像管理的软件,例如Harbor,但是Harbor功能太多了,里面不单单有镜像管理的功能,还有对用户,租户管理的功能,权限控制等等,里边很多功能和我们的容器云是重复的,所以我们最终决定我们没有用这个项目,而是参考Harbor自己开发了一个新的服务来对镜像进行管理。 日志管理:主要是通过ELK来实现。持续集成:主要是通过Kubernetes Jenkins插件来实现的。这个插件的优势是在资源分配时,Jenkins根据任务属性自动创建临时Docker容器,并作为slave节点加入Jenkins集群,实现资源的分配;另外在任务执行结束后,Jenkins自动删除相关节点,并销毁相关Docker容器,实现资源的释放;整个资源分配和资源释放过程对用户来说是透明的,用户只需要创建好任务就可以了,不需要操作节点;对于Jenkins来说,slave节点(容器)是临时的,任务一结束就会销毁。为了实现数据持久化,需要和一些分布式的存储集成,例如Ceph、Glusterfs等等。统一的UI:对所有的服务进行操作,包括可以对UI对服务对镜像进行管理,对应用市场进行管理等等。 如何实现self-healing 上图是BlueDock中使用Kubernetes+Mesos的方案组件图。BlueDock中的所有组件,都是通过container来部署的。用container的一个最大的优势就是安装部署升级是很简单的,同时不会修改物理服务器的一些配置,对物理服务器不会有任何改动。我们现在的BlueDock,只需要一个通过一个“docker run”命令,就可以很方便在上百台服务器上把容器云跑起来,我们做过一些测试,如果要去部署五百台左右的服务器,我们可以在十分钟以内把整个容器云集群安装部署完成。 在图中的最下边用不同颜色的方框表示出了BlueDock中不同组件的管理方式。其中有三个比较重要的概念:Static pod、DaemonSet和Deployment。 Static pod是在特定节点上由kubelet守护程序直接管理的,Kubernetes APIServer不会对其进行管理。 它没有关联任何Relication Controller,kubelet守护进程来负责对Static pod的监控,并在static pod crash时重新启动它。 Static pod始终绑定到一个kubelet守护程序,并且始终在同一节点上运行。 DaemonSet可以确保所有(或一些)节点始终运行某个pod的副本。 当节点添加到集群时,DaemonSet可以保证自动在新添加的节点创建pod;如果节点被删除后,这些pod也会相应的被DaemonSet删除。 Deployment是kubernetes 1.2的一个新引入的概念,它包含着对Pod和将要代替Replication Controller的Replica Set的描述。 BlueDock主要通过Static Pod、DaemonSet和Deployment来对主要组件进行管理,这三个功能可以通过Kubernetes自身的功能保证BlueDock self-healing的功能,某些Pod crash后,Static Pod、DaemonSet和Deployment可以保证其会被重启,从而保证系统的高可用。 基本流程是通过ansible调用docker-py通过docker container的形式在master节点启动kubelet,在master节点的kubelet服务启动后,就会以static pod的形式创建master节点的一些组件,例如k8sm-apiserver、k8sm-scheduler等等,当master节点的所有组件启动完毕后,开始通过docker-py在不同的worker上启动mesos agent,当整个BlueDock集群开始运行后,再通过DaemonSet的形式启动一些BlueDock的add-on的一些组件服务,例如日志管理、网络管理等等。 日志管理主要是通过DaemonSet的形式启动了Filebeat,来搜集每个worker的容器日志信息。网络管理主要是通过DaemonSet在每个worker节点启动了Calico node的container,这个container里面包含了Bird路由管理、Felix协议等。其它还有一些组件通过Deployment来管理,例如用于对log进行过滤的logstash,用于对Network Policy进行管理的calico congtroller等等。 上图是BlueDock没有Mesos的部署方式,基本和带有Mesos的部署模式是一样的,全部都是通过容器来对所有组件进行管理,同时可以self-healing。在这里主要想强调的是,BlueDock对k8s-scheduler做了很大的改进,支持资源的抢占,智能回收的策略。因为一台服务器上可以启动成百上千个容器,所以在这种高密度计算中,对资源的调度策略要求很高。BlueDock通过和IBM Platform的EGO集成,实现了资源的抢占和智能回收的策略。 上图是BlueDock的一个简单的改进的资源借入借出的一个例子。现在有两个tenant,T1和T2,都独占8个资源,但是我们看到在T1和T2之间有个虚线,这个虚线表示T2可以从T1借入4个资源。所以当T1和T2去申请资源的时候,T1要4个,T2要12个,那T1可以直接拿到他独占的4个资源,T2要12个,但是他只独占8个资源,所以他会先拿到自己独占的这8个资源。 拿完之后,T2发现,他可以再从T1借4个,所以当T2从T1借完4个后,T1和T2的资源请求都得到了满足,同时系统的资源使用率也达到了100%,所以这个是我们通过资源借入借出实现的提升资源利用率的一个例子。另外,如果T1的请求再提升的话,T1可以把借给T2的资源再抢占回来,保证T1的SLA。 上图是BlueDock的两种不同的安装模式:包含和不包含Mesos,这个可以在用户对BlueDock安装的时候,通过“—enable-mesos”来控制。当BlueDock安装完成后,这两种模式会有统一的GUI界面,终端用户不会感知Mesos的存在,唯一的区别就是如果使用了Mesos,可以通过BlueDock管理Mesos的Framework。 BlueDock的Auth主要是通过Keystone实现了一个Kubernetes OpenID的provider,方便与其它第三方的应用集成实现单点登录的功能。同时利用了Kubernetes的RBAC的功能,可以定义细粒度的权限控制。另外在和Keystone的集成过程中,BlueDock将Kubernetes的namespace映射为Keystone的project,这样的话,可以借助keystone来对Kubernetes的用户和namespace来统一管理。 在BlueDock集群中的每个节点上运行一个Filebeat的容器,收集容器的日志发送给到LogStash来进行过滤,然后统一存储到ElasticSearch集群中,用户可以通过Kibana查看任意Node、Namespace、Service、Pod和容器的数据。在BlueDock中,ElasticSearch是作为DaemonSet在所有管理节点启动的。 应用管理主要通过Kubernetes Helm来管理,Helm是官方Kubernetes的一部分,主要用来进行软件包的管理。Helm的一个很重要的概念是Charts,表示可以安装并组成的预配置Kubernetes资源包。Helm采用客户端机服务器模式。服务器部分被称为tiller,同时包括你运行Kubernetes集群。客户端部分被称为helm,安装在本地的开发系统上。 在BlueDock中,为了让BlueDock的UI能直接调用Helm的API,我们通过Helm的Client实现了Helm的Rest API,这样可通过BlueDock的UI来调用Helm的Rest API实现对Kubernetes应用包的管理。同时在BlueDock中将Rest API、Helm Client和Tiller通过一个Kubernetes Deployment进行管理部署,这样可通过Kubernetes自身来对Helm的所有组件进行管理。 原文发布时间为:2017-02-09 本文来自云栖社区合作伙伴DBAplus

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册