WebSocket 实现动态获取docker日志

动态获取容器日志

前段时间做了一个web端的docker可视化管理平台,采用vue + python flask 前后端分离实现。有一个功能是弹框动态显示容器日志,等同于命令docker logs --tail=20 -f containerName.
在这里插入图片描述进行docker管理,后端实际是使用docker官方提供的docker-py。最开始的想法还是通过http接口请求来实现,但tcp三次握手建立连接,四次挥手断开连接,一次http请求就结束了,无法动态的获取后端数据。如果保持长连接,在性能方面应该也有不小的损耗。
最后选择使用WebSocket来实现。WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。使用WebSocket,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯.

使用WebSocket实现功能

由于使用的框架是vue和flask,这里对应使用了Vue-Socket.ioflask-socketio

flask-socketio

这个库更方便的使flask框架提供WebSocket服务端功能。
在程序入口文件中,使用socket对象来包装app并代替它。

from flask_socketio import SocketIO
socket_io = SocketIO()
socket_io.init_app(app,cors_allowed_origins='*')


if __name__ == '__main__':
    socket_io.run(app,debug=app.config['DEBUG'],host=app.config['HOST'],port=app.config['PORT'])

这里需要特别关注的是如何解决跨域问题。在前后分离的项目中,一般都是由后端解决跨域问题。flask中http接口使用CORS(app, supports_credentials=True)来解决,但是WebSocket接口想要解决跨域问题,则要在实例化socketio对象时添加cors_allowed_origins参数。这个参数支持传入字符串或列表类型的数据,传入值是IP,如果允许所有IP,则传入*。

WebSocket服务端接口

@socket_io.on('logs')
def logs(data):
    host = data.get('host')
    name = data.get('name')
    certification = get_certification(host)
    # 判断是否鉴权
    if certification:
        cert,key = cert_file_path(host)
        tls_config = docker.tls.TLSConfig(client_cert=(cert, key),verify=False)
        client = docker.DockerClient(base_url='tcp://' + host + ':2376', tls=tls_config)
    else:
        client = docker.DockerClient(base_url='tcp://' + host + ':2375')
    c = client.containers.get(name)
    for line in c.logs(stream=True, tail=20, follow=True):
        print(line.decode('utf-8').strip())
        emit(host + name, {'name': name, 'msg': line.decode('utf-8').strip()})

在socket对象上使用on来监听客户端发送的事件,如代码中的logs,这是自定义的,服务端在发送消息时要写logs。这里获取到客户端发来的host和容器名称,生成docker client,使用client获取容器再获取日志。获取到的日志是一个生成器。循环生成器获取日志字符串并使用emit方法发送给客户端。emit方法发送时指定了emit事件,客户端同样定义了这个事件,并监听事件获取消息。

vue-socket.io

与vue集成,使得WebSocket客户端实现变得简单。
在main.js 中

import VueSocketIO from 'vue-socket.io'

Vue.use(new VueSocketIO({  
debug: true,  
// 服务器端地址  
connection: 'http://127.0.0.1:5005/',
}))

业务代码

//启动查看 、继续查看日志
startLogs() {
  this.logPrint = true
  if (!(this.hasLogs.indexOf(this.host + this.logContainer) > -1)) {
    this.hasLogs.push(this.host + this.logContainer)
    this.$socket.emit('logs', {
      host: this.host,
      name: this.logContainer,
    })
  }
  this.sockets.subscribe(this.host + this.logContainer, (data) => {
    console.log(data.name)
    if (data.name === this.logContainer) {
      this.logs = this.logs + data.msg + '<br>'
      const div = this.$refs.elscrollbar.$refs.wrap
      // 滑动滚动条到最底部
      this.$nextTick(() => {
        div.scrollTop = div.scrollHeight
      })
    }
  })
 }//暂停日志
pauseLogs() {
  this.logPrint = false
  this.sockets.unsubscribe(this.host + this.logContainer)
 }

打开日志弹框和点击继续按钮调用startLogs方法,在startLogs中进行了判断,判断日志是否之前被查看过,如果没有查看,则发送服务器和容器名称消息给服务端,并订阅对应的获取日志事件。如果已经被查看则直接订阅获取日志事件。暂停日志则是点击弹窗中的暂停按钮来取消订阅的获取日志事件。这里需要注意的时关闭弹窗时也需要调用暂停方法,否则在下次打开弹框时会输出双倍的日志,因为这样订阅了2次。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值