TLDR; Use Docker as lite VM to allow for a portable, sharable dev environment
Before I was the product guy at Binaris, I served as lead architect for our scale-out backend compute product. As you might expect, this involved a lot of sshing
<insert sunny reference here>, along with remote debugging and development. I quickly grew tired of recreating my environment from scratch on each node.
Why not dotfiles?
Dotfiles solve a part of this problem, but dotfiles do not usually handle package installation and other boilerplate system configuration. Including scripts is nice, but spotty at best. Scripts are also only useful if you can assume the underlying OS is unchanging. For those wondering why I don't simply bake an AMI, each AMI is optimized for the microservice running on it, not my one-off dev needs. My configuration ended up including dotfiles, shell scripts, and Ansible playbooks, just to create a consistent environment.
A few months ago, I became curious if it's possible/popular to use Docker as lite VM. I saw many people online running a remote server (specifically VSCode) in the docker, but very few actually developing inside the docker container itself. We use Docker a lot at work, so I've become very comfortable with it's tooling and capabilities. Since I'd been wanting to redo my dotfiles+config for some time, I figured why not use Docker.
The Dockerfile that resulted from my efforts has now become the basis of MyOS. The Dockerfile provides a semi-opinionated basis for in-container development using vi, zsh and tmux. It handles a lot of boilerplate work like
- Configuring locale and colors
- Creating a non-root user and setting necessary permissions
- Setups OpenSSH for password-less login
- Enabling X11 Display server
Initially, I was using vanilla Ubuntu as a base image, but it required too much hacking just to get the basic functionality I wanted. Eventually, I found out about Phusion, an amazing project that provides a few key features
- Super light, highly optimized base Ubuntu image
- Mechanism to "safely" run multiple processes
- Init for running your user process as PID > 1
- OpenSSH server out of the box
I've also included some opinionated baseline packages. Some are obvious like
xauth for native host copy/paste. Others I included, because the getting the setup correct, entails more than running
apt-get. Highlights are
- Vim8 with clipboard support
- Latest Tmux built from source
- XAuth and XDisplay packages for clipboard support
MyOS is pretty minimal. Today there are three major parts
Defines the base MyOS image. Handles builtin package installation and system configuration.
Controls which host volumes and ports are mapped into the container. This file is key because it allows us to mount our editor (vi), shell (zsh), and window management (tmux) config files into the container, without actually storing them inside it.
I needed a convenient way of running commands over and over. Initially I used a mixture of sh and Make but always resent maintaining a CLI written with those tools. For now, it's node based, allowing easy installation with npm (I'm definitely willing to change this)
To use MyOS, first install the CLI globally
$ npm install -g myos
Next, you either need to clone an existing MyOS setup, or create a empty template.
$ myos init myos-config $ cd myos-config $ ls docker-compose.yml tmux vim zsh
Once you're in a directory containing a valid MyOS setup run
$ myos create rysenv
create command essentially runs
docker-compose up -d as of today.
Once the container is started, connect using
$ myos connect
And that's it.
Disclaimer: obviously this is complete abuse of the container model
There are definitely some limitations of containers, but using one as your development environment has some signficant benefits.
- Incredibly portable - Docker is the JVM of development environments with native OSX, Windows, and Linux support
- Very breakable - Recreating a container has nearly 0 overhead, so feel free to
rm -rf *
- Mostly stateless - Aside from the bare essentials, state comes from mounted Docker volumes. This allows you to easily work on your host files in the container environment, without becoming attached to the container.
- Suprisingly performant - On Linux, expect native kernel performance, and on OSX and Windows VM level performance (Docker on OSX runs in a VM).
- Accelerates env iteration - due to its layered file system, you can make massive adjustments to the runtime environment, without having to manually remove and re-install dependencies.
- Transferrable - Utilizing
docker commitalong with
docker pushand AWS ECR, move from host to host while maintaining file system state (but please just stay stateless)
Although I primarily value MyOS for my personal development, I browse /r/vim daily, and interactions on the subreddit made me wonder if MyOS could be used for more. MyOS can facilitate the sharing of ENTIRE terminal environments, not just dot files. Wouldn't it be cool to share your setup and know that it's guaranteed to work for anyone on any system? Assuming everyone relies on a semi-stable base image, sharing requires you to only send the layers that you've added on top of the base image along with your dotfiles and other configuration.
I've made all my work open source, and would love if others use what I've made. I'm open to discussing features, or even changes based on what the community needs, and pull requests are definitely welcome. There are a few items I already know are problematic
- Very vim focused, would like to see if its possible to support other editors (definitely Emacs)
- Needs CLI command that allows you to copy another users MyOS environment
- Multiple MyOS environments should be able to run simelataneously
- SSH key for authorized_keys could be autogenerated
- Potentially move away from NodeJS for CLI