Dockerize Your Dotfiles
Contents
Introduction
If you are like me and prefer to develop in a complete TUI environment with neovim, you may encounter a situation where you need to reconfigure your development environment every time you face a new OS. You may need to install packages, copy dotfiles and do some other stuffs over and over again, which is really annoying.
Docker, which can provide OS-level virtualization, may be able to provide a solution to this problem.
In this post, I will briefly describe how to build a docker image for your dotfiles and explain some of the problems I encountered and solutions.
Getting Started
Let’s first install docker and run a linux container.
To install docker, you can either download the installer from the official website or use your package manager to install it.
If you installed docker with a package manager on linux, you may also need to launch docker daemon via this command before any operation:
|
|
Then we can run a linux container like so:
|
|
-i
option means we will launch the container in interactive mode, and -t
option will allocate a pseudo-tty.
We use opensuse/tumbleweed:latest
here, this is a tag for the latest build of openSUSE Tumbleweed image.
This command will first check if this image exists on local machine, if not, docker will pull it from docker hub and then launch it.
I choose openSUSE Tumbleweed here, this is a rolling release distro with support for multiple architectures. You can choose other distros based on your preference.
Now let’s write a Dockerfile to build our own image.
In Dockerfile
:
|
|
The FROM
command means our image is based on opensuse/tumbleweed:latest
, and the RUN
command is the shell command to be executed in openSUSE Tumbleweed.
OpenSUSE Tumbleweed uses zypper package manager. The zypper ref
command will refresh the package databases, and the zypper up -y
command will update all outdated packages without confirmation.
The zypper in -y git
command will install git without confirmation.
The zypper clean --all
command will clean all zypper caches.
Then we run this command in terminal to build our docker image:
|
|
-t sainnhe/dotfiles
is the tag of this image, .
is the directory where Dockerfile
is stored.
Now let’s launch a container based on our image via:
|
|
You can then clone your dotfiles repository, copy dotfiles, install some other packages via RUN
command.
But if you want to access files on your local machine in a container, you will need -v
option to specify the directory to be mounted.
First, let create a directory in our image:
|
|
Then rebuild the image and launch a container like this:
|
|
Where <workdir-on-local-machine>
is the path of the directory you want to access on your local machine.
This directory will be mounted to /root/work
so you can access it through this path in docker.
Some Problems and Solutions
All shell commands passed to RUN
command should be non-interactive, that’s why we need to pass -y
option to zypper
command.
Copying dotfiles and installing packages in non-interactive mode doesn’t have many problems, but when it comes to install vim plugins and zsh plugins, many problems arise.
Here I’ll provide my solutions on how to do these things in non-interactive mode.
The complete Dockerfile for my dotfiles can be found here.
Install Zsh Plugins
I use zdharma-continuum/zinit to manage my zsh plugins, this is a super fast zsh plugin manager (benchmarks).
After installing zsh and other dependencies via zypper, I use this command to install zsh plugins:
|
|
Install Tmux Plugins
First, install tmux and other dependencies via zypper, copy .tmux.conf
to $HOME
and install tpm via:
|
|
Then install plugins via:
|
|
Install Vim Plugins
I use vim-plug to manage my plugins.
|
|
Where custom#plug#install()
is a function to install vim-plug, replace this with your own command instead.
Install Coc Extensions
This hack is a bit dirty.
First of all, I get a full list of coc extensions via grep and sed:
|
|
The final output of these commands is something like:
|
|
Then use pipeline to pass the output to xargs and install the extensions via npm:
|
|
But the dependencies of coc extensions will not be installed, we need to use another command to install their dependencies respectively:
|
|
So the complete docker command should be like:
|
|
GitHub Action
Instead of manually build and push docker image, I prefer to use github action to build and push on schedule.
First, we need to create a repository in docker hub sainnhe/dotfiles, then create a personal access token and add it to repository secrets.
My github workflow is like this:
|
|