how to implement a web-based terminal with dockerfiles.meetup.com/16521172/duwan_how_to_implement...
TRANSCRIPT
How to Implement a Web-based Terminal with Docker
Vangie Du2015-03-14
Who am I
杜万 (Vangie Du) • Full-Stack Web Developer
• Linux fans
• Working on Coding@Shanghai
About Coding
Project Management
Cloud Development Platform
Source Code Management
Code Insight
Web Development
Quality Analysis
https://coding.net
Contents
• What is a Terminal
• Process Groups, Sessions and Job Control
• Pseudoterminals and Terminal emulators
• Implements a Web-based Terminal
• Embedded in Docker Container
What is a Terminal
Go Back In Time
typewriter ticker tape printer
In 1869,the stock ticker was invented
Terminal
• A device that enables you to communicate with a computer.
• Combination of keyboard and display screen.
TeleTYpewriter, TTY
DEC VT100 terminal
Text Terminal
Keyboard
Display
Program
stdin
stdout
stderr
Process performing I/O
Terminal driver
Terminal device
Inpu
t que
ueO
utput queue
characters read by process
characters written by process
characters typed at terminal
characters displayed at terminal
If echoing enabled
Three Layers of Terminal Subsystem
Hardware Driver
Line discipline
Character device interface read(),write(),ioctrl()
LF
CR/LFControl-C, backspace,
delete
characters, signals
Process Groups, Sessions and Job Control
Multiple Tasks
User Terminal
program1
program2
program3
input
output
suspended at need for
write to terminal
kill suspend
endless loop
Process
Process Group Process Group
Process
Process
Session
… …
• PID process identifier
• PGID process group identifier
• == the PID of process group leader
• SID seesion identifier
• == the PID of session leader
Exec Command in Bash
$ echo $$ 400 $ find / 2>/dev/null | wc -l & [1] 659 $ sort < longlist | uniq -c
#Display the PID of the Bash
#Creates 2 processes in background group
#Creates 2 processes in foreground group
PROCESSES IN MEMORY
Session 400
process group 660
PID = 660
PPID = 400
PGID = 660
SID = 400
PID = 661
PPID = 400
PGID = 600
SID = 400
PID = 400
PPID = 399
PGID = 400
SID = 400
process group 400
bash
process group 658
PID = 658
PPID = 400
PGID = 658
SID = 400
PID = 659
PPID = 400
PGID = 658
SID = 400
find
wc
sort
uniq
process group leaderssession leader
foreground PGID = 660
background SID = 400
cont
rolli
ng p
roce
ss
foreground process groupcontrolling terminal
background process group
Job Control
Running in foreground
Running in background
Terminated
Stopped in background
1. Control-C (SIGINT)2. Control-\ (SIGOUT)
1. kill -STOP (SIGSTOP) 2. Terminal Read (SIGTTIN) 3. Terminal Write (+TOSTOP) (SIGTTOU)
kill
Control-Z(SIGTSTP)
fg(SIGCOUT)fg kill
bg (SIGCONT)
$ command
$ command &
Pseudoterminals and Terminal emulators
What is Terminal Emulator
• A terminal emulator is a a computer application that emulates or behaves like a hardware terminal composed of at least a keyboard and monitor.
Terminal Physical line
UARTUART driver
Line discipline
TTY driver
Hardware
Softwarekernel
User process
User process
User process
Display
Keyboard
VGA driver
Line discipline
TTY driver
Hardware
Software
kernel
User process
User process
User process
Keyboard driver
Terminal emulator
PTY master
Line discipline
PTY slave
Software
kernel
User process
User process
User process
Terminal emulator
How to Operate a Terminal-oriented Program over a Network?
Terminal TCP/IP
client program
socket
terminal-oriented program
TCP/IP
Network
user
sp
ace
kern
el
spac
e
sock
et?
User at Terminal
stdi
nst
dout
, st
derr
Two Programs Communicating via a Pseudoterminal
driver program
pty master
pty slave
terminal-oriented program
fork(), exec()us
er
spac
eke
rnel
sp
ace
stdin stdout, stderr
“is th
e con
trollin
g
term
inal
for”
How SSH Uses a PseudoTerminal
Terminal TCP/IP
ssh client
socket
login shell
TCP/IP
Network
user
sp
ace
kern
el
spac
e
User at Terminal
stdi
nst
dout
, st
derr
ssh server
sock
et
pty master
pty slave
stdo
ut,
stde
rr
stdi
n
Implements a Web-based Terminal
Web Terminal
Terminal emulator
TCP/IP
websocket
bash
TCP/IP
Network
user
sp
ace
kern
el
spac
e
User at Browser
websocket server
web
sock
etpty
masterpty
slave
stdo
ut,
stde
rr
stdi
n
stdo
ut,
stde
rr
stdi
n
websocket client
Initialize a Project of Nodejs
$ mkdir docker-web-terminal && cd $_
$ npm init && bower init
$ git init && git add . && git commit -m “first commit”
$ git remote add origin [email protected]:duwan/docker-web-terminal.git
$ git push -u origin master
Install Dependencies Package
$ npm install --save coffee-script \ express \
pty.js \ socket.io
$ bower install --save jquery \ socket.io-client \ CodeboxIDE/sh.js \ coffeescript
Backend Source
[pty, sio, express, http] = (require lib for lib in ['pty.js', 'socket.io', 'express', 'http']) [host, port] = ["0.0.0.0", process.env.PORT or 5000]
server = http.createServer(express().use(express.static(__dirname)))
sio.listen(server).sockets.on('connection', (socket)-> term = pty.spawn 'bash', [], {cwd: process.env.HOME} .on 'data', (data)-> socket.emit('data', data) .on 'exit', -> socket.emit('exit', {})
socket.on 'data', (data)-> term.write data .on 'resize', (data)-> term.resize(data.cols, data.rows) .on 'disconnect', -> term.destroy() )
server.listen port, host, -> console.log('Server Listening on %s:%d', host, port)
index.coffee1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16
Frontend Source
<div id="terminal"></div> <script type="text/coffeescript"> term = new Terminal() term.on('data', (data)-> socket.emit('data', data)) term.open($('#terminal')[0]) socket = io.connect("#{location.protocol}//#{location.hostname}:#{location.port}") .on('data', (data)-> term.write(data))
$(window).resize( -> term.sizeToFit() socket.emit('resize', -> cols: term.cols, rows: term.rows ) ) $ -> $(window).trigger('resize') </script>
index.html1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18
Embedded in Docker Container
Mac OSboot2docker
TinyCore linux
Virtual Box VM
50005000
container
HTTP TCP
bash
pty master
pty slave
Browser
Terminal emulator
WebSocket Server
WebSocket client
Dockerfile
FROM dockerfile/nodejs MAINTAINER Vangie Du <[email protected]>
EXPOSE 5000
ADD *.json index.* ./
RUN npm install && bower install --allow-root
CMD ["npm", "start"]
1 2 3 4 5 6 7 8 9
10
$ docker build -t "vangie/docker-web-terminal" --rm .
$ docker run -d -p 5000:5000 vangie/docker-web-terminal:latest
$ open http://`boot2docker ip`:5000
References
• The TTY demystified
• The Linux Programming Interface ISBN-13:978-1-59327-220-3
• http://en.wikipedia.org/wiki/Line_discipline
Source Code
• https://coding.net/u/duwan/p/docker-web-terminal
Thank You!