Docker: Difference between revisions
→Usage: expose mariadb via socket |
Cleaned up the page and organized it |
||
Line 1: | Line 1: | ||
<languages/> | |||
'''Docker''' is a platform for building, packaging, and distributing applications inside containers. Containers bundle an application's code, configurations, and dependencies into a single object that runs consistently across different computing environments. Docker works well with NixOS through the virtualization module.<ref>https://www.docker.com/resources/what-container/</ref> | |||
== | == Installation == | ||
==== Shell ==== | |||
< | To temporarily use Docker in a shell environment, you can run: | ||
<syntaxhighlight lang="bash"> | |||
</ | nix-shell -p docker | ||
</syntaxhighlight> | |||
This will provide a shell with Docker CLI available, but note that the Docker daemon will not be running. For full functionality, you'll need a system-level installation. | |||
==== System setup ==== | |||
To install Docker on NixOS, add the virtualization.docker module to your system configuration at <code>/etc/nixos/configuration.nix</code>:<ref>https://nixos.org/manual/nixos/stable/options#opt-virtualisation.docker.enable</ref> | |||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
users.users.< | # In /etc/nixos/configuration.nix | ||
virtualisation.docker = { | |||
enable = true; | |||
# Enable docker daemon to start on boot | |||
enableOnBoot = true; | |||
# Use the faster overlay2 storage driver | |||
storageDriver = "overlay2"; | |||
}; | |||
# Optional: Add your user to the "docker" group to run docker without sudo | |||
users.users.<username>.extraGroups = [ "docker" ]; | |||
</syntaxhighlight> | </syntaxhighlight> | ||
{{Security Warning|Beware that the docker group membership is effectively [https://github.com/moby/moby/issues/9976 equivalent to being root]! <br> Consider using rootless mode.}} | |||
Then, rebuild your system to apply the changes: | |||
<syntaxhighlight lang="bash"> | |||
sudo nixos-rebuild switch | |||
</syntaxhighlight> | |||
===== | For a comprehensive list of configuration options, refer to the [https://search.nixos.org/options?channel=23.11&from=0&size=50&sort=relevance&type=packages&query=virtualisation.docker NixOS options search]. | ||
== Configuration == | |||
==== Basic ==== | |||
< | The basic Docker configuration on NixOS includes several options you can set in your <code>configuration.nix</code> file: | ||
virtualisation.docker | <syntaxhighlight lang="nix"> | ||
virtualisation.docker = { | |||
enable = true; | enable = true; | ||
# Set up resource limits | |||
daemon.settings = { | |||
experimental = true; | |||
default-address-pools = [ | |||
{ | |||
base = "172.30.0.0/16"; | |||
size = 24; | |||
} | |||
]; | |||
}; | |||
}; | }; | ||
</ | </syntaxhighlight> | ||
==== Advanced ==== | |||
Docker | For more advanced configuration, you can customize Docker daemon options and networking: | ||
<syntaxhighlight lang="nix"> | |||
virtualisation.docker = { | |||
enable = true; | |||
# Customize Docker daemon settings using the daemon.settings option | |||
daemon.settings = { | |||
dns = [ "1.1.1.1" "8.8.8.8" ]; | |||
log-driver = "journald"; | |||
registry-mirrors = [ "https://mirror.gcr.io" ]; | |||
storage-driver = "overlay2"; | |||
}; | |||
# Use the rootless mode - run Docker daemon as non-root user | |||
rootless = { | |||
enable = true; | |||
setSocketVariable = true; | |||
}; | |||
}; | |||
</syntaxhighlight> | |||
== Docker Compose == | |||
Currently, there are two options to use Docker Compose with NixOS: Arion or Compose2Nix. | |||
With Arion, you can specify most Docker Compose options in Nix Syntax, and Arion will generate a <code>docker-compose.yml</code> file internally. The result is a systemd service that starts and stops the container. | |||
< | Compose2Nix, generates all necessary configs directly from the <code>docker-compose.yml</code>, which is easier when using an already existing Docker Compose project. The result is similar to that from Arion: a systemd service is created that handles starting and stopping the container. | ||
</ | |||
=== Arion === | |||
[https://docs.hercules-ci.com/arion/ Arion] is created for running Nix-based projects in Docker Compose. It uses the NixOS module system for configuration, it can bypass <code>docker build</code> and lets you use dockerTools or use the store directly in the containers. The images/containers can be typical dockerTools style images or full NixOS configs. | |||
To use Arion, you first need to add its module to your NixOS configuration: | |||
<syntaxhighlight lang="nix"> | |||
modules = [ arion.nixosModules.arion ]; | |||
</syntaxhighlight> | |||
< | After that, you can access its options under | ||
virtualisation. | <syntaxhighlight lang="nix"> | ||
virtualisation.arion = {} | |||
} | </syntaxhighlight> | ||
</ | |||
A config for a simple container could look like this: | |||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
virtualisation. | virtualisation.arion = { | ||
backend = "docker"; | backend = "docker"; | ||
projects = { | |||
"db".settings.services."db".service = { | |||
image = ""; | |||
restart = "unless-stopped"; | |||
environment = { POSTGRESS_PASSWORD = "password"; }; | |||
}; | }; | ||
}; | }; | ||
Line 81: | Line 118: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Compose2Nix === | |||
With [https://github.com/aksiksi/compose2nix compose2nix] you can generate [https://search.nixos.org/options?query=virtualisation.oci-containers oci-containers] config from a <code>docker-compose.yaml</code>. | |||
==== Install ==== | |||
To use <code>compose2nix</code> with <code>nix-shell</code> you can use<syntaxhighlight lang="bash"> | |||
nix shell github:aksiksi/compose2nix | |||
compose2nix -h | |||
</syntaxhighlight>To install <code>compose2nix</code> to NixOS, add the repo to your flake inputs<syntaxhighlight lang="nix"> | |||
compose2nix = { | |||
url = "github:aksiksi/compose2nix"; | |||
inputs.nixpkgs.follows = "nixpkgs"; | |||
}; | |||
</syntaxhighlight>and add the package to your configuration<syntaxhighlight lang="nix"> | |||
environment.systemPackages = [ | |||
inputs.compose2nix.packages.x86_64-linux.default | |||
]; | |||
</syntaxhighlight> | |||
</syntaxhighlight> | |||
==== Usage ==== | ==== Usage ==== | ||
After you have installed <code>compose2nix</code>, you can run <code>compose2nix</code> in the directory with your <code>docker-compose.yml</code>, which will output a <code>docker-compose.nix</code>. | |||
Alternatively, you can specify the input and output files with the following flags<syntaxhighlight lang="bash"> | |||
compose2nix -inputs input.yml -output output.nix -runtime docker | |||
</syntaxhighlight>The <code>-runtime</code> flag specifies the runtime. Here, we select <code>docker</code>. Options are <code>podman</code> and <code>docker</code>. The default is <code>podman</code> | |||
== Tips and tricks == | |||
=== | === Docker on btrfs === | ||
If you use the [[btrfs]] file system, you might need to set the <code>storageDriver</code> option: | |||
If you | <syntaxhighlight lang="nix"> | ||
virtualisation.docker.storageDriver = "btrfs"; | |||
</syntaxhighlight> | |||
=== Rootless Docker === | |||
Rootless Docker lets you run the Docker daemon as a non-root user for improved security. Set the <code>rootless</code> option as shown above. The <code>setSocketVariable</code> option adds the <code>DOCKER_HOST</code> variable pointing to your rootless Docker instance. | |||
= | After enabling rootless mode, Docker can be started with: | ||
<syntaxhighlight lang="bash"> | |||
$ systemctl --user enable --now docker | |||
</syntaxhighlight> | |||
This is not | This creates the 'docker.service' file which is required to start Docker. Note that the service will not start at boot by this command. You will have to set it up in your NixOS configuration. Now the following command will work: | ||
<syntaxhighlight lang="bash"> | |||
$ systemctl --user start docker | |||
</syntaxhighlight> | |||
Check its status with: | |||
<syntaxhighlight lang="bash"> | |||
$ systemctl --user status docker | |||
</syntaxhighlight> | |||
== Creating images with Nix == | === Creating images with Nix === | ||
=== Building a docker image with nixpkgs === | ==== Building a docker image with nixpkgs ==== | ||
There is an entry for [https://nixos.org/nixpkgs/manual/#sec-pkgs-dockerTools dockerTools] in the Nixpkgs manual for reference. In the linked page, they give the following example config: | There is an entry for [https://nixos.org/nixpkgs/manual/#sec-pkgs-dockerTools dockerTools] in the Nixpkgs manual for reference. In the linked page, they give the following example config: | ||
< | <syntaxhighlight lang="nix"> | ||
buildImage { | buildImage { | ||
name = "redis"; | name = "redis"; | ||
Line 174: | Line 207: | ||
buildVMMemorySize = 512; | buildVMMemorySize = 512; | ||
} | } | ||
</ | </syntaxhighlight> | ||
More examples can be found in the [https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/docker/examples.nix nixpkgs] repo. | More examples can be found in the [https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/docker/examples.nix nixpkgs] repo. | ||
Line 180: | Line 213: | ||
Also check out the excellent article by [https://lucabrunox.github.io/2016/04/cheap-docker-images-with-nix_15.html lethalman] about building minimal docker images with nix. | Also check out the excellent article by [https://lucabrunox.github.io/2016/04/cheap-docker-images-with-nix_15.html lethalman] about building minimal docker images with nix. | ||
=== Reproducible image dates === | ==== Reproducible image dates ==== | ||
The manual advises against using <code>created = "now"</code>, as that prevents images from being reproducible. | The manual advises against using <code>created = "now"</code>, as that prevents images from being reproducible. | ||
Line 186: | Line 219: | ||
An alternative, if using [[flakes]], is to do <code>created = builtins.substring 0 8 self.lastModifiedDate</code>, which uses the commit date, and is therefore reproducible. | An alternative, if using [[flakes]], is to do <code>created = builtins.substring 0 8 self.lastModifiedDate</code>, which uses the commit date, and is therefore reproducible. | ||
=== | ==== Calculating the sha256 for a pulled Docker image ==== | ||
The <code>sha256</code> argument of the <code>dockerTools.pullImage</code> function is the checksum of the archive generated by Skopeo. Since the archive contains the name and the tag of the image, Skopeo arguments used to fetch the image have to be identical to those used by the <code>dockerTools.pullImage</code> function. | The <code>sha256</code> argument of the <code>dockerTools.pullImage</code> function is the checksum of the archive generated by Skopeo. Since the archive contains the name and the tag of the image, Skopeo arguments used to fetch the image have to be identical to those used by the <code>dockerTools.pullImage</code> function. | ||
For instance, the SHA of the following image | For instance, the SHA of the following image | ||
< | <syntaxhighlight lang="nix"> | ||
pkgs.dockerTools.pullImage{ | pkgs.dockerTools.pullImage{ | ||
imageName = "lnl7/nix"; | imageName = "lnl7/nix"; | ||
Line 198: | Line 231: | ||
sha256 = "1x00ks05cz89k3wc460i03iyyjr7wlr28krk7znavfy2qx5a0hfd"; | sha256 = "1x00ks05cz89k3wc460i03iyyjr7wlr28krk7znavfy2qx5a0hfd"; | ||
}; | }; | ||
</ | </syntaxhighlight> | ||
can be manually generated with the following shell commands | can be manually generated with the following shell commands | ||
< | <syntaxhighlight lang="bash"> | ||
skopeo copy docker://lnl7/nix@sha256:632268d5fd9ca87169c65353db99be8b4e2eb41833b626e09688f484222e860f docker-archive:///tmp/image.tgz:lnl7/nix:2.0 | skopeo copy docker://lnl7/nix@sha256:632268d5fd9ca87169c65353db99be8b4e2eb41833b626e09688f484222e860f docker-archive:///tmp/image.tgz:lnl7/nix:2.0 | ||
</ | </syntaxhighlight> | ||
< | <syntaxhighlight lang="bash"> | ||
nix-hash --base32 --flat --type sha256 /tmp/image.tgz | nix-hash --base32 --flat --type sha256 /tmp/image.tgz | ||
</ | </syntaxhighlight> | ||
< | <syntaxhighlight lang="shell"> | ||
1x00ks05cz89k3wc460i03iyyjr7wlr28krk7znavfy2qx5a0hfd | 1x00ks05cz89k3wc460i03iyyjr7wlr28krk7znavfy2qx5a0hfd | ||
</ | </syntaxhighlight> | ||
=== Directly Using Nix in Image Layers === | ==== Directly Using Nix in Image Layers ==== | ||
Instead of copying Nix packages into Docker image layers, Docker can be configured to directly utilize the <code>nix-store</code> by integrating with [https://github.com/pdtpartners/nix-snapshotter nix-snapshotter]. | Instead of copying Nix packages into Docker image layers, Docker can be configured to directly utilize the <code>nix-store</code> by integrating with [https://github.com/pdtpartners/nix-snapshotter nix-snapshotter]. | ||
Line 219: | Line 252: | ||
This will significantly reduce data duplication and the time it takes to pull images. | This will significantly reduce data duplication and the time it takes to pull images. | ||
== | === Using Podman as an alternative === | ||
Podman is a daemonless container engine that can run Docker containers without elevated privileges. It can be used as a drop-in replacement for Docker in many cases:<ref>https://podman.io/</ref> | |||
<syntaxhighlight lang="nix"> | |||
# Enable Podman in configuration.nix | |||
virtualisation.podman = { | |||
enable = true; | |||
# Create the default bridge network for podman | |||
defaultNetwork.settings.dns_enabled = true; | |||
}; | |||
# Optionally, create a Docker compatibility alias | |||
programs.zsh.shellAliases = { | |||
docker = "podman"; | |||
}; | |||
</syntaxhighlight> | |||
=== | === Changing Docker Daemon's Data Root === | ||
To use | By default, the Docker daemon stores images, containers, and build context on the root file system. To use a different storage location, specify a new <code>data-root</code> in your configuration: | ||
<syntaxhighlight lang="nix"> | |||
virtualisation.docker.daemon.settings = { | |||
data-root = "/some-place/to-store-the-docker-data"; | |||
}; | |||
</syntaxhighlight> | |||
=== Docker Containers as systemd Services === | |||
You can run Docker containers as systemd services using the <code>oci-containers</code> module: | |||
< | <syntaxhighlight lang="nix"> | ||
virtualisation. | virtualisation.oci-containers = { | ||
</ | # backend defaults to "podman" | ||
backend = "docker"; | |||
containers = { | |||
foo = { | |||
# ... | |||
}; | |||
}; | |||
}; | |||
</syntaxhighlight> | |||
A config | A more advanced example: | ||
<syntaxhighlight lang="nix"> | |||
{ config, pkgs, ... }: | |||
{ | |||
virtualisation. | config.virtualisation.oci-containers.containers = { | ||
hackagecompare = { | |||
image = "chrissound/hackagecomparestats-webserver:latest"; | |||
ports = ["127.0.0.1:3010:3010"]; | |||
volumes = [ | |||
"/root/hackagecompare/packageStatistics.json:/root/hackagecompare/packageStatistics.json" | |||
]; | |||
cmd = [ | |||
"--base-url" | |||
"\"/hackagecompare\"" | |||
]; | |||
}; | }; | ||
}; | }; | ||
} | } | ||
</ | </syntaxhighlight> | ||
See [https://search.nixos.org/options?from=0&size=50&sort=alpha_asc&query=virtualisation.oci-containers oci-containers] for further options. | |||
==== Usage ==== | |||
Unless otherwise specified, NixOS uses Podman to run OCI containers. Note that these are '''user-specific''', so running commands with or without sudo can change your output. | |||
List containers<syntaxhighlight lang="console"> | |||
# podman ps | |||
</syntaxhighlight>Update image<syntaxhighlight lang="console"> | |||
# podman restart hackagecompare | |||
</syntaxhighlight>List images<syntaxhighlight lang="console"> | |||
# podman ls | |||
</syntaxhighlight>Remove container<syntaxhighlight lang="console"> | |||
# podman rm hackagecompare | |||
</syntaxhighlight>Remove image<syntaxhighlight lang="console"> | |||
# podman rmi c0d9a5f58afe | |||
</syntaxhighlight>Update image<syntaxhighlight lang="console"> | |||
# podman pull chrissound/hackagecomparestats-webserver:latest | |||
</syntaxhighlight>Run interactive shell in running container<syntaxhighlight lang="console"> | |||
# podman exec -ti $ContainerId /bin/sh | |||
</syntaxhighlight> | |||
===== Exposing ports from the host ===== | |||
If you have a service running on the host that you want to connect to from the container, you could try connecting to the hostname <code>host.containers.internal</code> (or <code>host.docker.internal</code> for podman), but this might require additional networking setup | |||
=== | ===== Exposing sockets from the host ===== | ||
If you have a service running on the host that exposes a socket, such as mariadb, you can also expose that socket to the container instead. You'll want to expose the folder the socket is in as a volume - so: | |||
<syntaxhighlight lang="bash"> | |||
volumes = [ | |||
"/var/run/mysqld:/mysqld" | |||
]; | |||
]; | |||
</syntaxhighlight> | </syntaxhighlight> | ||
to provide access to <code>/var/run/mysqld/mysqld.sock</code> | |||
=== Running the docker daemon from nix-the-package-manager - not NixOS === | |||
This is not supported. You're better off installing the docker daemon [https://docs.docker.com/engine/install/ "the normal non-nix way"]. | |||
See the discourse discussion: [https://discourse.nixos.org/t/how-to-run-docker-daemon-from-nix-not-nixos/43413 How to run docker daemon from nix (not NixOS)] for more. | |||
== Troubleshooting == | == Troubleshooting == | ||
=== Common issues === | |||
==== Cannot connect to the Docker daemon ==== | |||
If you encounter errors connecting to the Docker daemon, check that: | |||
- The Docker service is running: `systemctl status docker` | |||
- Your user is in the docker group: `groups | grep docker` | |||
- You've logged out and back in after adding your user to the docker group | |||
==== Storage space issues ==== | |||
When Docker uses too much disk space: | |||
<syntaxhighlight lang="bash"> | |||
# Remove unused containers, networks, images, and volumes | |||
docker system prune -a --volumes | |||
# Configure Docker daemon to automatically prune in configuration.nix | |||
virtualisation.docker.daemon.settings = { | |||
pruning = { | |||
enabled = true; | |||
interval = "24h"; | |||
}; | |||
}; | |||
</syntaxhighlight> | |||
==== Network conflicts ==== | |||
Docker's default subnet (`172.17.0.0/16`) might conflict with your existing network. Configure a different subnet in your `configuration.nix`: | |||
<syntaxhighlight lang="nix"> | |||
virtualisation.docker.daemon.settings = { | |||
default-address-pools = [ | |||
{ | |||
base = "192.168.0.0/16"; | |||
size = 24; | |||
} | |||
]; | |||
}; | |||
</syntaxhighlight> | |||
=== Cannot connect to public Wi-Fi, when using Docker === | === Cannot connect to public Wi-Fi, when using Docker === | ||
This can be resolved by changing the default address pool that Docker uses.<syntaxhighlight lang="nix"> | When connecting to a public Wi-Fi, where the login page's IP-Address is within the Docker network range, accessing the Internet might not be possible. This has been reported when trying to connect to the WIFIonICE of the Deutsche Bahn (DB). They use the <code>172.18.x.x</code> address range. | ||
This can be resolved by changing the default address pool that Docker uses. | |||
<syntaxhighlight lang="nix"> | |||
virtualisation.docker = { | virtualisation.docker = { | ||
enable = true; | enable = true; | ||
Line 301: | Line 410: | ||
}; | }; | ||
}; | }; | ||
</syntaxhighlight>Restarting | </syntaxhighlight> | ||
Restarting the container or Docker might be required. | |||
== | == References == | ||
<references/> | |||
[[Category:Applications]] | |||
[[Category:Virtualization]] | |||
[[Category:Cookbook]] | [[Category:Cookbook]] | ||
[[Category:Software]] | [[Category:Software]] | ||
[[Category:Server]] | [[Category:Server]] | ||
[[Category:Container]] | [[Category:Container]] |