We'll start off with how Docker builds a container image for you. You pull down some kind of image from the Docker hub, and Docker hums excitingly for a bit while you watch things scroll and progress…
Article word count: 955
HN Discussion: https://news.ycombinator.com/item?id=17393991
Posted by signa11
(karma: 30779)Post stats: Points: 164 - Comments: 130 - 2018-06-25T17:15:00Z
\#HackerNews #2016 #considered
Weʼll start off with how Docker builds a container image for you. You pull down some kind of image from the Docker hub, and Docker hums excitingly for a bit while you watch things scroll and progress bars fill. What you end up with is a filesystem tree from some Linux distro, with a few things added in on top.
It may be surprising to some that we have been doing exactly this for multiple decades now.
In fact, you do this every time you install GNU/Linux on a machine. The majority of the files in that filesystem tree come from packages from some distro. And package managers are certainly capable of installing packages into arbitrary directories; thatʼs how they install a new system.
In fact, most even have neat little wrapper scripts to do it for you! And these are only an apt-get install debootstrap (or equivalent) away! To build filesystem trees for a few of the most popular distros^4:
\* debootstrap trusty /srv/trees/ubuntu
\* debootstrap stable /srv/trees/debian
* yum -y --nogpg --releasever=22 --disablerepo=ʼ*ʼ --enablerepo=fedora install fedora-release systemd passwd dnf fedora-release vim-minimal --installroot=/srv/trees/fedora
\* pacstrap /srv/trees/arch
And of course you can select additional packages to install using these commands, or make other changes. This has been used for decades to build chroots, which Iʼll say more about a bit later. There are even more novel package managers, like nix and guix, which have interesting features that can make things even easier.
But wait, the distro version of node.js (for example) is too out of date! How am I going to get the latest version?
Well, the first thing you should do if you need more up to date versions is enable the updated package repositories for your distro: Ubuntu backports, Debian backports, CentOS EPEL. It may be surprising to some, but distros and package managers actually exist for a reason, and one of those reasons is that they make it easy to keep your system up to date. (There are other advantages which I wonʼt go into here^5)
If a suitably updated version is not available through distro channels, I am obligated to suggest that the next best option is to download the source of the distro package, update and rebuild it yourself, and install using that package. Or, build the package yourself if one isnʼt available. This can be a bit of a pain if you are in the early development stages (though there are tools to make it easier^6) but again, there are many advantages.^5
Most people, however, use the traditional hacks. You can chroot in and just do your usual pip install foo or gem install bar or npm install baz or ./configure && make && make install, just as you would with some "RUN" directives in a Dockerfile.
Wow! Itʼs just like Docker! No, Docker is just like this. Hopefully it is becoming obvious that here, at least, there is no real advantage of Docker.
Crucially, you can use all the same install scripts that you would use with a normal Linux machine. You donʼt need to rewrite everything into Dockerfiles. You can do it manually, you can use shell scripts, you can use Ansible, you can write a boutique ConfigurationManagementFactory in Java, you can do whatever you like. Itʼs just installing software. Itʼs not complicated unless you make it complicated. Supposedly, Dockerfiles are simpler than running debootstrap at the beginning of your script, but Iʼm not sure I understand why. It seems to me that Docker is no simpler or easier than the standard way.
Now, itʼs true that Docker uses layering to be efficient in terms of disk space and time to build new containers. It defaults to using AUFS to do this.^7 I think you could reimplement it easily yourself with a small shell script and some calls to mount; but I havenʼt bothered.
Personally, I just use man 8 btrfs-subvolume. btrfs is a copy on write filesystem which can instantly make space-efficient copies of filesystem trees in "subvolumes", which the user sees as just regular directories.
You can build a stock Ubuntu filesystem tree into a subvolume with btrfs subvolume create /srv/trees/ubuntu && debootstrap trusty /srv/trees/ubuntu/. Then, when you want to build a new container with specific software, you just copy that subvolume and perform your modifications on the copy; that is, btrfs subvolume snapshot /srv/trees/debian /srv/containers/webapp and work on /srv/containers/webapp. If you want to copy those modifications, you just take another snapshot.
This is arguably better, because thereʼs no need to maintain a lot of state about the mount layerings and set them up again on reboot. Your container filesystem just sits there in a volume waiting for you to start it.
Naturally, if you donʼt like btrfs for some reason, youʼre perfectly able to use zfs, OverlayFS, AUFS, or whatever; no need to have a "storage driver" implemented just to do some simple copy-on-write or layering operations.
And if you want to do some kind of change tracking as you build the system, you should keep it at the proper layer, or use dedicated tools. /usr should be immutable and built from packages, your application data should live in /srv or /var and be mounted in, and so all the configuration data that is part of the system build should be in /etc. To track this, you can just use etckeeper and store your /etc in a git repository. which is right and proper since /usr should be immutable. If you must, OSTree lets you version whole filesystems.
And if you still need to pull in a Docker image for some reason, you can treat it as just another way to build a filesystem tree. There are tools that will let you do that, such as machinectl pull-dkr.
HackerNewsBot debug: Calculated post rank: 152 - Loop: 321 - Rank min: 100 - Author rank: 98