1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
Title: ociTools in NixOS
Category: Blog
Date: 2019-09-09 18:00
Tags: /dev/diary, NixOS, Virtualisation
With the release of NixOS 19.09 any second now, I thought I wanted to
blog about something that I've been working on, that [recently][0]
made it into `master`, and thus the new stable channel.
[0]: https://github.com/NixOS/nixpkgs/pull/56411
## What are OCI tools?
[Open Container Initiative][1] (or OCI) produced a spec that
standardised what format containers should use. It is implemented by a
bunch of runners, such as `runc` (the Docker/ standard Kubernetes
backend) and `railcar` (more to that later) and outlines in exactly
what format a containers metadata and filesystem are to be stored, so
to achieve the largest possible reusability.
[1]: https://www.opencontainers.org/
The spec is pretty [long][3] and in some places not very
great. There's even a [blog post][4] from Oracle, talking about how
implementing an OCI runner in Rust made them find bugs in the
specification.
[3]: https://github.com/opencontainers/runtime-spec
[4]: https://blogs.oracle.com/developers/building-a-container-runtime-in-rust
## What are ociTools?
So now the question is, what does that have to do with
NixOS/nixpkgs. The answer is simple: I wanted to be able to
containerise single applications on my server, without requiring a
container daemon (such as docker) or relying on externally built
"Docker containers" from a registry.
So, `ociTools.buildContainer` was recently merged into `nixpkgs/master`, allowing you to do exactly that. It's usage is farely
straight forward
```nix
with pkgs; ociTools.buildContainer {
args = [
(writeShellScript "run.sh" ''
${hello}/bin/hello -g "Hello from OCI container!"
'').outPath
];
}
```
The `args` parameter refers to a list of paths and arguments that are
handed to a container runner to run as init. In this case it's
creating a shell script with some commands in it, then getting the
output derivation path. Alternatively, if you only want to run a
single application, you can pass it `<package>.outPath` directly
instead.
There's other options available, such as the `os`, `arch` and
`readonly` flags (which aren't very interesting and have sane
defaults). Additionally to that there's `mounts`.
Simply specify any bind-mount you wish to setup at container init in a
similar way you would describe your filesystem with `nix` already:
```nix
with pkgs; ociTools.buildContainer {
args = [
(writeShellScript "run.sh" ''
${hello}/bin/hello -g "Hello from OCI container!"
'').outPath
];
mounts."/data" = {
source = "/var/lib/mydata";
};
}
```
## Railcar + ociTools
So that's all nice and good. But what about actually running these
containers. Well, as I previously said I didn't want to have a
dependency on a management daemon such as `docker`. Instead, I also
added a module for the afromentioned `railcar` container runner
(Oracle please merge my PR, thank you).
It wraps very cleanly around `ociTools` and generates `systemd` units
to start containers, restarting them if they crash. This way you can
express applications purely in `nix`, give them access to only the
things they need, and be sure that their configuration is in line with
the rest of your system rebuild.
```nix
services.railcar = {
enable = true;
containers = {
"hello" = {
cmd = ''
${pkgs.hello}/bin/hello -g "Hello railcar!"
'';
};
};
};
```
The metadata interface for `mounts`, etc is the same for `railcar` as
for `ociTools`.
Anyway, I hope you enjoy. There is definitely things to improve,
especially considering the vastness of the OCI spec. Plus, at the
moment `ociTools` does require a bunch of manual setup work for an
application to function, if it, say, runs a webserver. It would be
cool if some NixOS modules could be re-used to make this configuration
easier. But I'm sure someone else is gonna have fun figuring that out.
|