文档章节

php docker web终端的折腾

xueyi28
 xueyi28
发布于 2017/01/15 18:58
字数 1075
阅读 158
收藏 0

#php是天下最好的语言,没有之一。 我非常喜欢php,我听过一个高手的讲座,讲php的编译原理,发现如果就php语言开发而言的确技术上有高低之分。一比较才发现自己差了十万八千里,自己不努力是不行的。好了不多说了,我来说说今天我分享的话题。 ##背景 2015年,我开始接触docker,那个时候发现一个管理平台shipyard,shipyard中有一个可以直接在浏览器上操作的web终端很吸引我,我想自己实现这样的一个服务,我翻看了其中的技术细节,发现有一个shipyard/controller/api/hijack.go中一堆的操作,当我开始用php模拟来写的时候,我发现我对php的认识还处于低级阶段,看起来很一个很艰难的工作。

##整体的架构 输入图片说明 浏览器上主要的通信技术就是websocket技术,我以前玩过一个原型. ##前端代码

< !doctype html > <title > term.js < /title>
<!--
  term.js
  Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
-->
<style>
  html {
    background: #555;
  }

  h1 {
    margin-bottom: 20px;
    font: 20px/1.5 sans - serif;
} < /style>
<h1>term.js</h1 > <script src = "http://apps.bdimg.com/libs/term.js/0.0.2/term.js" > </script>
<script>
;(function() {
  window.onload = function() {
    var socket = new WebSocket('ws:/ / myblog.com / wsapp / '); 

    socket.onopen = function() {
      var term = new Terminal({
      cols: 80,
      rows: 24,
      useStyle: true,
      screenKeys: true,
      cursorBlink: false
      });

      term.on('data ', function(data) {
      socket.send(data);
      });

      term.on('title ', function(title) {
        document.title = title;
      });
      term.open(document.body);
      term.write('\x1b[31mWelcome to term.js ! \x1b[m\r\n ');

      socket.onmessage =  function(message) {
        term.write(message.data);
      }    

      socket.onclose = function() {
        term.destroy();
      }
    socket.onerror = function() {
        console.log("connect error");
        term.destroy();
    }
    }
  };
}).call(this);
</script>

这里用到了term.js的一个前端的终端组件,传送门 所有的通信都是走的websocket ##nginx的配置

        location /wsapp/ {
            proxy_pass http://127.0.0.1:9501;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
        }

没什么好讲的,这里就是连接到一个websocket的服务而已 ##后端服务

< ?php
function create_exec($container_id = '9e75217f2a89') {
    $url = "http://0.0.0.0:2375/containers/".$container_id."/exec";
    $post_data = ["AttachStdin" = >true, "AttachStdout" = >true, "AttachStderr" = >true, "Cmd" = >["/bin/bash"], "DetachKeys" = >"ctrl-p,ctrl-q", "Privileged" = >true, "Tty" = >true, "User" = >"root:root"];
    $header = ["Content-Type: application/json"];
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data, true));
    $output = curl_exec($ch);
    curl_close($ch);
    return $output;
}
//websocket 执行
$server = new swoole_websocket_server("127.0.0.1", 9501);
$client = null;
$exec_id = null;
$host = "192.168.254.128:2375";
$re = null;
$server - >on('open',
function(swoole_websocket_server $server, $request) {
    echo "server: handshake success with fd{$request->fd}\n";
    global $exec_id;
    global $re;
    $re = $request;
    $exec = json_decode(create_exec(), true);
    $exec_id = $exec['Id'];
    print_r("exec id:".$exec_id);
    //socket async
    global $client;
    $client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);
    $client - >on("connect",
    function(swoole_client $cli) {
        global $exec_id;
        global $host;
        $url = '/exec/'.$exec_id."/start";
        $data = '{"Detach":false, "Tty":true}';
        $out = "POST ${url} HTTP/1.1\r\n";
        $out. = "Remote Address:${host}\r\n";
        $out. = "Content-Type: application/json\r\n";
        $out. = "Connection: Upgrade\r\n";
        $out. = "Content-Length: ".strlen($data)."\r\n";
        $out. = "Upgrade: tcp\r\n\r\n";
        $out. = $data."\r\n\r\n";
        $cli - >send($out);
    });
    $client - >on("receive",
    function(swoole_client $cli, $data) {
        echo "Receive docker daemon: $data";
        //接受到的docker daemon数据发送到web客户端
        global $server;
        global $re;
        $server - >push($re - >fd, $data);
        //$cli->send(str_repeat('A', 100)."\n");
    });
    $client - >on("error",
    function(swoole_client $cli) {
        echo "error\n";
    });
    $client - >on("close",
    function(swoole_client $cli) {
        echo "Connection close\n";
    });
    //连接docker
    $client - >connect('192.168.254.128', 2375);
});
$server - >on('message',
function(swoole_websocket_server $server, $frame) {
    //接收到的web客户端数据发送给docker daemon
    global $client;
    echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
    $client - >send($frame - >data);
    //$server->push($frame->fd, "this is server");
});
$server - >on('close',
function($ser, $fd) {
    echo "client {$fd} closed\n";
});
$server - >start();

docker的exec这里要先通过exec接口获取一个执行id,然后通过这个id,调用start接口才能进行服务,不过docker的start接口这里的返回并不是一个curl能处理的请求,而是一个流,而且是一个可读可写的流,所以这里必须采用socket的方式来进行服务发送,还有一个需要注意的,就是这个socket的通信并不能采用同步的方式进行,因为如果同步阻塞数据就没办法读写了,读的时候程序直接卡住了,没办法继续下去了。这就是php需要的异步io技术。 swoole这块最大的问题就是参数的传递,我不得不定义好多global的变量,不然异步socket和websocket服务嵌套的用,代码看起来好丑陋。

ps: 我查了一下,php从5.3开始解决了这个问题,php这个版本之后支持闭包参数传递,有了use关键字的支持,另外对this关键字进行了改装,可以有效的简化这种写法,我闲的时候玩玩 ##最后,看看成果 输入图片说明

参考资料:https://hui.lu/shi-yong-tornado-cao-zuo-docker-api/#webssh-with-frontend

© 著作权归作者所有

xueyi28
粉丝 8
博文 111
码字总数 38442
作品 0
南宁
私信 提问
docker学习系列1 使用docker 快速实现多版本PHP

多谢此文:https://blog.eriksen.com.br/en/docker-image-multi-version-php-development 最近一个新的后台API项目需要运行在PHP5.3环境中,而无论是本地还是测试服务器都安装的是PHP7.x PH...

飞凡的陀螺
2018/07/26
0
0
Docker Meetup 上海站

3月15日,学术范儿浓郁的上海科学会堂,我们虚位以待。 • 喻勇:持续交付的云平台原生应用 技术布道师,Cloud Foundry社区领袖。曾担任VMware中国研发中心高级经理,负责Cloud Foundry、大数...

DaoCloud
2015/03/10
208
0
Docker Meetup 上海站

3月15日,学术范儿浓郁的上海科学会堂,我们虚位以待。 • 喻勇:持续交付的云平台原生应用 技术布道师,Cloud Foundry社区领袖。曾担任VMware中国研发中心高级经理,负责Cloud Foundry、大数...

DaoCloud
2015/03/10
0
0
devops| nginx unit 入门小试

date: 2018-5-14 11:20:01 title: devops| nginx unit 入门小试 description: nginx unit 入门小试以及 PHPer 的一点浅见 上周几乎被 nginx unit 的消息给霸屏了, 大致看了看这个产品的 野心...

daydaygo
2018/05/14
0
0
Docker的WEB管理界面shipyard

Docker 的命令行就已经很好用了,如果非要加上基于 Web 的管理界面的话也有一些选择,如 DockerUI (Angular.js), Dockland (Ruby), Shipyard (Python/Django) 等,不过目前来看 Shipyard 项目...

呆头呆脑
2013/11/21
0
7

没有更多内容

加载失败,请刷新页面

加载更多

非webpack require.js + vue + vueRouter + iView 实现按需加载

适合一个人开发的时候,在整个php框架下,又想单页,又可以直接后端assign变量穿透到模板。又不想写接口搞前后分离脚手架一大堆npm 包, 在php模板下 引入require.js <!DOCTYPE html><html...

一箭落旄头
26分钟前
7
0
新特性解读 | MySQL 8.0 窗口函数详解

原创作者: 杨涛涛 背景 一直以来,MySQL 只有针对聚合函数的汇总类功能,比如MAX, AVG 等,没有从 SQL 层针对聚合类每组展开处理的功能。不过 MySQL 开放了 UDF 接口,可以用 C 来自己写UDF...

爱可生
32分钟前
3
0
23.5 jumpserver介绍

23.5 jumpserver介绍 开源堡垒机jumpserver介绍: 官网www.jumpserver.org Jumpserver是一款使用Python, Django开发的开源跳板机系统, 助力互联网企业高效 用户、资产、权限、审计 管理 Auth...

oschina130111
38分钟前
5
0
Spring Cloud 入门教程(七): 消息总线(Spring Cloud Bus)(Greenwich.RELEASE)

参考网址:https://blog.csdn.net/forezp/article/details/81041062,由于此文中作者基于git和rabbitMq,为了适应内网我改造为基于mysql和kafka 一、准备工作 1、安装kafka 参考这个:kafka...

pipi1919
39分钟前
3
0
用人工智能改变企业与客户的连接方式

  随着以AI人工智能技术为主的新一代信息技术的快速商业化落地,我国的数字经济正高歌猛进。2017年我国数字经济对GDP的贡献率为55%,接近甚至超越了某些发达国家水平,2018年我国数字经济规...

琴殇的
43分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部