One of the components I’ve found useful when putting together virtual machines / Docker containers is a simple web based terminal that gives me terminal access into the machine.
This is a living post where I can keep notes on the various solutions I’ve tried…
Jupyter Notebooks
If you run a Jupyter notebook server, or JupyterLab, in a container, you get a web based terminal for free, albeit running under whatever user/privileges the Jupyter user environment is using.
Gritty
Browser based terminal; requires a node install, which is a faff, but it seems to work quite well… Here’s a Dockerfile fragment:
#Install node.js RUN apt-get update && apt-get install -y build-essential RUN curl -sL https://deb.nodesource.com/setup_8.x | bash && \ apt-get install -y nodejs && apt-get clean RUN npm i npm@latest -g #Install web terminal - gritty #Provides access into container via in-browser terminal RUN npm i gritty -g --unsafe-perm #Use the terminal as the default running service for the container #When the container is running, we should be able to access browser terminal into it EXPOSE 1337 CMD gritty
The --no-perms
thing for me was required to get it to install cleanly…
You’d probably want to run this alongside another process. See Docker docs – Run multiple services in a container for now. I need to work on my own reusable recipe to support this general sort of activity. (The supervisord
route is probable the best way..? Example (untested), untested simple example – use /usr/bin/supervisord
as the CMD
, untested tutorial)
Here’s another example in a simple Vagrantfile:
Vagrant.configure("2") do |config| #------------------------- PROVIDER: VIRTUALBOX (BUILD) ------------------------------ config.vm.provider :virtualbox do |virtualbox| #Stick with the default key config.ssh.insert_key=false #For local testing: config.vm.box = "ubuntu/xenial64" config.vm.hostname = "gritty-test" virtualbox.name = "gritty_test" virtualbox.memory = 1024 virtualbox.cpus = 1 # virtualbox.gui = true #Don't bother updating guest additions config.vbguest.auto_update = false #---- START PORT FORWARDING ---- #Registered ports: https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers #Gritty config.vm.network :forwarded_port, guest: 1337, host: 8898, auto_correct: true #---- END PORT FORWARDING ---- end #------------------------- END PROVIDER: VIRTUALBOX (BUILD) ------------------------------ config.vm.provision :shell, :inline => <<-SH if [ ! -f /vagrant/.firstrun_setup.done ]; then apt-get update && apt-get install -y build-essential curl -sL https://deb.nodesource.com/setup_8.x | bash && apt-get install -y nodejs && apt-get clean npm i npm@latest -g #Install web terminal - gritty #Provides access into container via in-browser terminal npm i gritty -g --unsafe-perm cp /vagrant/gritty.service /lib/systemd/system/gritty.service # Enable autostart systemctl enable gritty.service # Refresh service config systemctl daemon-reload #(Re)start service systemctl restart gritty.service touch /vagrant/.firstrun_setup.done fi SH #config.vm.provision "shell", inline: "gritty --port 1337 &", run: "always" end
And here's an example gritty.service
file:
[Unit] Description=OU Gritty Terminal Demo #When to bring the service up #via https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/ #Wait for a network stack to appear After=network.target #If we actually need the network to have a routable IP address: #After=network-online.target [Service] #User=oustudent Environment=GRITTYPORT=1337 #ExecStartPre=mkdir -p /vagrant/openrefine_projects ExecStart=/usr/bin/gritty --port ${GRITTYPORT} Restart=always RestartSec=10 [Install] WantedBy=multi-user.target
Alternatives: xterm.js
seems to provide the basis of several terminal servers such as ttyd
; here’s an example with authentication from Duke: mccahill/xterm-js-docker
; and a minimal example server: simon-engledew/dockerweb
. Here’s an example of a web ssh terminal with a ore complete config file example here.
novnc
Another route to a web based terminal via the browser is to cheat – and allow access to VM desktop through the browser. This can be done with using a virtualised desktop. For example, novnc
eg https://github.com/psharkey/docker/tree/master/novnc with other containers to compose with it.
The dit4c/dockerfile-dit4c-container-x11 container is a nice example of a set of Docker container layers to support X11 exposure via a browser using novnc.
The new Docker Desktop looks like it will have some GUI tools to help assemble applications in Docker Desktop so it’d be great if that included a robust, templated containers to handle both X11, and terminal access, through a browser.
See also: Apache Guacamole; example – Guacamole and Wine – Running Small Legacy Windows Apps Via a Browser or Accessing GUI Apps (Audacity) Via a Browser from a Container Using Guacamole.
PS here’s a set-up for running under supervisord
in a container.
Docker – multiple services in same container recipe
This uses a docker-compose
file (run using docker-compose up
) that uses a local Dockerfile
that calls on build.sh
script to create a container image that runs a couple of services as specified in the supervisord.conf
file. Note the requirement on installing the supervisor
package.
First, the supervisord.conf
script; this is responsible for starting the running applications (and replaces any services; which means my build files need to separate our services and copy them over / start them up if we are not doing the docker build).
##supervisord.conf [supervisord] nodaemon=true [program:gritty] command = /usr/bin/gritty --port 80 [program:gritty2] command = /usr/bin/gritty --port 8899
The build.sh
script is responsible for installing the necessary packages into the container.
##build.sh apt-get update && apt-get install -y build-essential curl curl -sL https://deb.nodesource.com/setup_8.x | bash && apt-get install -y nodejs && apt-get clean npm i npm@latest -g #Install web terminal - gritty #Provides access into container via in-browser terminal npm i gritty -g --unsafe-perm
The Dockerfile
orchestrates the build of the container.
##Dockerfile FROM ubuntu:16.04 RUN apt-get update && apt-get install -y supervisor ADD build.sh /root/build.sh RUN chmod +x /root/build.sh && /root/build.sh RUN apt-get clean COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf CMD ["/usr/bin/supervisord"]
The docker-compose.yaml
orchestrates the deployment of the container, including port mappings.
##docker-compose.yaml version: '3' services: multidemo: build: . ports: - "8087:80" - "8097:8899"
Running the container should publish terminals running as separate services on different ports (host ports 8087 and 8097.
I guess Guacamole its really interesting here, even if I haven’t implemented it myself to really understand all pros and cons