about summary refs log tree commit diff
path: root/nixos/doc/manual/containers.xml
blob: 2530d5195212a2dc5f79c8bc2439d1ecf833a23d (plain) (blame)
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
<chapter xmlns="http://docbook.org/ns/docbook"
         xmlns:xlink="http://www.w3.org/1999/xlink"
         xml:id="ch-containers">

<title>Containers</title>

<para>NixOS allows you to easily run other NixOS instances as
<emphasis>containers</emphasis>. Containers are a light-weight
approach to virtualisation that runs software in the container at the
same speed as in the host system. NixOS containers share the Nix store
of the host, making container creation very efficient.</para>

<warning><para>Currently, NixOS containers are not perfectly isolated
from the host system. This means that a user with root access to the
container can do things that affect the host. So you should not give
container root access to untrusted users.</para></warning>

<para>NixOS containers can be created in two ways: imperatively, using
the command <command>nixos-container</command>, and declaratively, by
specifying them in your <filename>configuration.nix</filename>. The
declarative approach implies that containers get upgraded along with
your host system when you run <command>nixos-rebuild</command>, which
is often not what you want. By contrast, in the imperative approach,
containers are configured and updated independently from the host
system.</para>


<section><title>Imperative container management</title>

<para>We’ll cover imperative container management using
<command>nixos-container</command> first. You create a container with
identifier <literal>foo</literal> as follows:

<screen>
$ nixos-container create foo
</screen>

This creates the container’s root directory in
<filename>/var/lib/containers/foo</filename> and a small configuration
file in <filename>/etc/containers/foo.conf</filename>. It also builds
the container’s initial system configuration and stores it in
<filename>/nix/var/nix/profiles/per-container/foo/system</filename>. You
can modify the initial configuration of the container on the command
line. For instance, to create a container that has
<command>sshd</command> running, with the given public key for
<literal>root</literal>:

<screen>
$ nixos-container create foo --config 'services.openssh.enable = true; \
  users.extraUsers.root.openssh.authorizedKeys.keys = ["ssh-dss AAAAB3N…"];'
</screen>

</para>

<para>Creating a container does not start it. To start the container,
run:

<screen>
$ nixos-container start foo
</screen>

This command will return as soon as the container has booted and has
reached <literal>multi-user.target</literal>. On the host, the
container runs within a systemd unit called
<literal>container@<replaceable>container-name</replaceable>.service</literal>.
Thus, if something went wrong, you can get status info using
<command>systemctl</command>:

<screen>
$ systemctl status container@foo
</screen>

</para>

<para>If the container has started succesfully, you can log in as
root using the <command>root-login</command> operation:

<screen>
$ nixos-container root-login foo
[root@foo:~]#
</screen>

Note that only root on the host can do this (since there is no
authentication).  You can also get a regular login prompt using the
<command>login</command> operation, which is available to all users on
the host:

<screen>
$ nixos-container login foo
foo login: alice
Password: ***
</screen>

With <command>nixos-container run</command>, you can execute arbitrary
commands in the container:

<screen>
$ nixos-container run foo -- uname -a
Linux foo 3.4.82 #1-NixOS SMP Thu Mar 20 14:44:05 UTC 2014 x86_64 GNU/Linux
</screen>

</para>

<para>There are several ways to change the configuration of the
container. First, on the host, you can edit
<literal>/var/lib/container/<replaceable>name</replaceable>/etc/nixos/configuration.nix</literal>,
and run

<screen>
$ nixos-container update foo
</screen>

This will build and activate the new configuration. You can also
specify a new configuration on the command line:

<screen>
$ nixos-container update foo --config 'services.httpd.enable = true; \
  services.httpd.adminAddr = "foo@example.org";'

$ curl http://$(nixos-container show-ip foo)/
&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">…
</screen>

However, note that this will overwrite the container’s
<filename>/etc/nixos/configuration.nix</filename>.</para>

<para>Alternatively, you can change the configuration from within the
container itself by running <command>nixos-rebuild switch</command>
inside the container. Note that the container by default does not have
a copy of the NixOS channel, so you should run <command>nix-channel
--update</command> first.</para>

<para>Containers can be stopped and started using
<literal>nixos-container stop</literal> and <literal>nixos-container
start</literal>, respectively, or by using
<command>systemctl</command> on the container’s service unit. To
destroy a container, including its file system, do

<screen>
$ nixos-container destroy foo
</screen>

</para>

</section>


<section><title>Declarative container specification</title>

<para>You can also specify containers and their configuration in the
host’s <filename>configuration.nix</filename>.  For example, the
following specifies that there shall be a container named
<literal>database</literal> running PostgreSQL:

<programlisting>
containers.database =
  { config =
      { config, pkgs, ... }:
      { services.postgresql.enable = true;
        services.postgresql.package = pkgs.postgresql92;
      };
  };
</programlisting>

If you run <literal>nixos-rebuild switch</literal>, the container will
be built and started. If the container was already running, it will be
updated in place, without rebooting.</para>

<para>By default, declarative containers share the network namespace
of the host, meaning that they can listen on (privileged)
ports. However, they cannot change the network configuration. You can
give a container its own network as follows:

<programlisting>
containers.database =
  { privateNetwork = true;
    hostAddress = "192.168.100.10";
    localAddress = "192.168.100.11";
  };
</programlisting>

This gives the container a private virtual Ethernet interface with IP
address <literal>192.168.100.11</literal>, which is hooked up to a
virtual Ethernet interface on the host with IP address
<literal>192.168.100.10</literal>.  (See the next section for details
on container networking.)</para>

<para>To disable the container, just remove it from
<filename>configuration.nix</filename> and run <literal>nixos-rebuild
switch</literal>. Note that this will not delete the root directory of
the container in <literal>/var/lib/containers</literal>.</para>

</section>


<section><title>Networking</title>

<para>When you create a container using <literal>nixos-container
create</literal>, it gets it own private IPv4 address in the range
<literal>10.233.0.0/16</literal>. You can get the container’s IPv4
address as follows:

<screen>
$ nixos-container show-ip foo
10.233.4.2

$ ping -c1 10.233.4.2
64 bytes from 10.233.4.2: icmp_seq=1 ttl=64 time=0.106 ms
</screen>

</para>

<para>Networking is implemented using a pair of virtual Ethernet
devices. The network interface in the container is called
<literal>eth0</literal>, while the matching interface in the host is
called <literal>ve-<replaceable>container-name</replaceable></literal>
(e.g., <literal>ve-foo</literal>).  The container has its own network
namespace and the <literal>CAP_NET_ADMIN</literal> capability, so it
can perform arbitrary network configuration such as setting up
firewall rules, without affecting or having access to the host’s
network.</para>

<para>By default, containers cannot talk to the outside network. If
you want that, you should set up Network Address Translation (NAT)
rules on the host to rewrite container traffic to use your external
IP address. This can be accomplished using the following configuration
on the host:

<programlisting>
networking.nat.enable = true;
networking.nat.internalInterfaces = ["ve-+"];
networking.nat.externalInterface = "eth0";
</programlisting>
where <literal>eth0</literal> should be replaced with the desired
external interface. Note that <literal>ve-+</literal> is a wildcard
that matches all container interfaces.</para>

</section>


</chapter>