MyOS

Cover image

Github

TLDR; Use Docker as lite VM to allow for a portable, sharable dev environment

Inspiration

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.
Inception

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.

MyOS

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

  • ZSH
  • HTop
  • Vim8 with clipboard support
  • Latest Tmux built from source
  • XAuth and XDisplay packages for clipboard support
Using MyOS

MyOS is pretty minimal. Today there are three major parts

  1. Dockerfile

    Defines the base MyOS image. Handles built-in package installation and system configuration.

  2. docker-compose.yml

    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.

  3. myos.sh (CLI)

    I needed a convenient way of running commands over and over.

To use MyOS, clone the repo and alias (or put it in your path) the CLI

$ git clone https://github.com/rylandg/myos.git
$ alias myos="/path/to/myos/repo/myos.sh"

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

The create command essentially runs docker-compose up -d as of today.

Once the container is started, connect using

$ myos connect rysenv

And that's it.

maxwidth

Is it worth 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 significant 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.
  • Surprisingly 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.
  • Transferable - Utilizing docker commit along with docker push and AWS ECR, move from host to host while maintaining file system state (but please just stay stateless)
Sharing

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.

Final remarks

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 simultaneously
  • SSH key for authorized_keys could be auto-generated