Forkpty路由器
处理容器现在是一个常见的部署模式。处理jails/名字空间时的最烦人的任务之一是‘附加’到已经运行的实例。
forkpty路由器旨在简化这个过程,提供一个伪终端服务器给你的uWSGI实例。
一个客户端连接到由forkpty路由器公开的socket,然后获得一个连接到进程的新的伪终端 (一般是一个shell,但是可以是任何你想要的)
uwsgi模式 VS 原始模式
连接到forkpty路由器的客户端可以用两个协议来进行数据交换:uwsgi和原始模式。
原始模式简单映射socket到pty,出于这样一个原因,你将不能够调整你的终端大小,或者发送特定的信号。这个模式的优点在于性能:每个字符没有开销。
uwsgi模式把每个指令 (stdin, signals, window changes) 封装在一个uwsgi包中。这是非常类似于ssh的工作方式的,所以,如果你计划对shell会话使用forkpty路由器,那么uwsgi模式是最佳选择 (在用户体验方面)。
uwsgi协议的开销 (最差情况) 是每个stdin事件的5个字节 (单个字符)
运行forkpty路由器
这个插件不是默认内建的,因此你必须编译它:
- uwsgi --build-plugin plugins/forkptyrouter
或者,使用老的插件构建系统:
- python uwsgiconfig.py --plugin plugins/forkptyrouter
一般来说,也需要编译pty插件 (为了客户端访问)
- uwsgi --build-plugin plugins/pty
或者再次,使用老的构建系统:
- python uwsgiconfig.py --plugin plugins/pty
又或者,你可以一次性构建:
- UWSGI_EMBED_PLUGINS=pty,forkptyrouter make
现在,你可以将forkptyrouter作为一个标准网关运行 (我们使用UNIX socket,因为我们想要一个与jails的通信信道,并且不共享uts名字空间,以提供一个新的主机名)
- [uwsgi]
- master = true
- unshare = uts
- exec-as-root = hostname iaminajail
- uid = kratos
- gid = kratos
- forkpty-router = /tmp/fpty.socket
并且用pty客户端连接:
- uwsgi --pty-connect /tmp/fpty.socket
现在,在uWSGI实例中,你有了一个shell (默认是/bin/sh)。运行 hostname
将会给你’iaminajail’
最终,你可以避免使用uWSGI附加到pty上,取而代之,你可以依赖于这个简单的python脚本:
- import socket
- import sys
- import os
- import select
- import copy
- from termios import *
- import atexit
- s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- s.connect(sys.argv[1])
- tcattr = tcgetattr(0)
- orig_tcattr = copy.copy(tcattr)
- atexit.register(tcsetattr, 0, TCSANOW, orig_tcattr)
- tcattr[0] |= IGNPAR
- tcattr[0] &= ~(ISTRIP | IMAXBEL | BRKINT | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
- tcattr[0] &= ~IUCLC;
- tcattr[3] &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
- tcattr[3] &= ~IEXTEN;
- tcattr[1] &= ~OPOST;
- tcattr[6][VMIN] = 1;
- tcattr[6][VTIME] = 0;
- tcsetattr(0, TCSANOW, tcattr);
- while True:
- (rl, wl, xl) = select.select([0, s], [], [])
- if s in rl:
- buf = s.recv(4096)
- if not buf: break
- os.write(1, buf)
- if 0 in rl:
- buf = os.read(0, 4096)
- if not buf: break
- s.send(buf)
前一个例子使用原始模式,如果调整客户端客户端大小,你将看不到任何更新。
要使用’uwsgi’模式,则添加一个’u’:
- [uwsgi]
- master = true
- unshare = uts
- exec-as-root = hostname iaminajail
- uid = kratos
- gid = kratos
- forkpty-urouter = /tmp/fpty.socket
- uwsgi --pty-uconnect /tmp/fpty.socket
单个实例可以在不同的socket上公开两个协议
- [uwsgi]
- master = true
- unshare = uts
- exec-as-root = hostname iaminajail
- uid = kratos
- gid = kratos
- forkpty-router = /tmp/raw.socket
- forkpty-urouter = /tmp/uwsgi.socket
修改默认命令
默认情况下,forkpty路由器在新的连接上运行/bin/sh。
你可以使用–forkptyrouter-command修改命令
- [uwsgi]
- master = true
- unshare = uts
- exec-as-root = hostname iaminajail
- uid = kratos
- gid = kratos
- forkpty-router = /tmp/raw.socket
- forkpty-urouter = /tmp/uwsgi.socket
- forkptyrouter-command= /bin/zsh