NixOS

Reproducible builds and deployments.

Nix

A powerful package manager for Linux and other Unix systems that makes package management reliable and reproducible. Share your development and build environments across different machines.

NixOS

A Linux distribution with a unique approach to package and configuration management. Built on top of the Nix package manager, it is completely declarative, makes upgrading systems reliable, and has many other advantages.

$ # Hi!$ # Wondering how to start using Nix?$ # Here are a few examples:$ node -e "console.log(1+1)"node: command not found$ # Interesting, no node on this machine$ # No problem with Nix!$ nix-shell -p nodejs[nix-shell]$ node -e "console.log(1+1)"2[nix-shell]$ # And now we are able to use node.[nix-shell]$ # Nix Magic! :)$ # Typing "nix-shell -p ..." each time can be tedious. We can do better.$ # We can write everything down in default.nix$ bat default.nix────────┬──────────────────────────────────────────────────────────────────── │ File: default.nix────────┼──────────────────────────────────────────────────────────────────── 1 │ { pkgs ? import <nixpkgs> {} # here we import the nixpkgs package set 2 │ }: 3 │ pkgs.mkShell { # mkShell is a helper function 4 │ name="dev-environment"; # that requires a name 5 │ buildInputs = [ # and a list of packages 6 │ pkgs.nodejs 7 │ ]; 8 │ shellHook = '' # bash to run when you enter the shell 9 │ echo "Start developing..." 10 │ ''; 11 │ }────────┴────────────────────────────────────────────────────────────────────$ # Pause the video to understand the default.nix$ # To enter dev-environment simply run:$ nix-shellStart developing...[nix-shell]$ node -e "console.log(1+1)"2[nix-shell]$ # Now go ahead commit default.nix to your repository[nix-shell]$ # and share your development environment with your coworkers$ # For the last example, let us build a minimal docker image with Nix$ bat docker-redis.nix───────┬───────────────────────────────────────────────────────────────────── │ File: docker-redis.nix───────┼───────────────────────────────────────────────────────────────────── 1 │ { pkgs ? import <nixpkgs> {} # nixpkgs package set 2 │ }: 3 │ pkgs.dockerTools.buildLayeredImage { # helper to build docker image 4 │ name = "nix-redis"; # give docker image a name 5 │ tag = "latest"; # provide a tag 6 │ contents = [ pkgs.redis ]; # packages in docker image 7 │ }───────┴─────────────────────────────────────────────────────────────────────$ # Pause the video and take the time to understand docker-redis.nix file$ # Now let's build the docker image and load it into docker$ nix-build docker-redis.nix -o ./result ... SKIPPING OUTPUT .../nix/store/1crapx24sjgqm2j1wmq17k6f6a9wy66d-docker-image-nix-redis.tar.gz$ docker load -i ./result Loaded image: nix-redis:latest$ docker images | grep redisdebian-redis latest 8366943c77e8 3 days ago 136MBalpine-redis latest aae644cd3417 3 days ago 6.99MBnix-redis latest 30486183a209 50 years ago 45.4MB$ # The size of our docker image is somewhere between a Debian and$ # an Alpine image$ # The redis packaged in nixpkgs is not optimized for small size$ # Let us fix this!$ bat redis-minimal.nix───────┬───────────────────────────────────────────────────────────────────── │ File: redis-minimal.nix───────┼───────────────────────────────────────────────────────────────────── 1 │ { pkgs ? import <nixpkgs> {} 2 │ }: 3 │ pkgs.redis.overrideAttrs (old: { 4 │ # no need for systemd support in our docker image 5 │ makeFlags = old.makeFlags ++ ["USE_SYSTEMD=no"]; 6 │ # build static binary with musl 7 │ preBuild = '' 8 │ makeFlagsArray=(PREFIX="$out" 9 │ CC="${pkgs.musl.dev}/bin/musl-gcc -static" 10 │ CFLAGS="-I${pkgs.musl.dev}/include" 11 │ LDFLAGS="-L${pkgs.musl.dev}/lib") 12 │ ''; 13 │ # Let's remove some binaries which we don't need 14 │ postInstall = "rm -f $out/bin/redis-{benchmark,check-*,cli}"; 15 │ })───────┴─────────────────────────────────────────────────────────────────────$ # In redis-minimal.nix we override the default redis build with three changes:$ # 1.) Remove the redis systemd support$ # 2.) Build a statically linked binary with musl$ # 3.) Remove all binaries apart from redis-server$ # Now let's build the docker image with our newly created minimal redis$ bat docker-redis-minimal.nix───────┬───────────────────────────────────────────────────────────────────── │ File: redis-minimal.nix───────┼───────────────────────────────────────────────────────────────────── 1 │ { pkgs ? import <nixpkgs> {} 2 │ }: 3 │ let 4 │ redisMinimal = import ./redis-minimal.nix { inherit pkgs; }; 5 │ in 6 │ pkgs.dockerTools.buildLayeredImage { # helper to build docker image 7 │ name = "nix-redis-minimal"; # give docker image a name 8 │ tag = "latest"; # provide a tag 9 │ contents = [ redisMinimal ]; # use redisMinimal package 10 │ }───────┴─────────────────────────────────────────────────────────────────────$ # Let's build the new docker image now$ nix-build docker-redis-minimal.nix -o ./result ... SKIPPING OUTPUT .../nix/store/83zcgs5xvzrgx09iv8s82wkabl8xkr03-docker-image-nix-redis-minimal.tar.gz$ docker load -i ./resultLoaded image: nix-redis-minimal:latest$ docker images | grep redisdebian-redis latest 8366943c77e8 3 days ago 136MBalpine-redis latest aae644cd3417 3 days ago 6.99MBnix-redis latest 30486183a209 50 years ago 45.4MBnix-redis-minimal latest a21238890680 50 years ago 2.02MB$ # Did we just produce a docker image _smaller_ than Alpine? Interesting!$ # Go tell your friends :)$ # This was a quick taste of what Nix can do.$ # I hope we made you eager to try it for yourself.$ # Happy Nixing!

Why choose Nix or NixOS?

  • It's Reproducible…

    Nix builds packages in isolation from each other. This ensures that they are reproducible and don't have undeclared dependencies, so if a package works on one machine, it will also work on another.

  • Declarative…

    Nix makes it trivial to share development and build environments for your projects, regardless of what programming languages and tools you’re using.

  • And Reliable

    Nix ensures that installing or upgrading one package cannot break other packages. It allows you to roll back to previous versions, and ensures that no package is in an inconsistent state during an upgrade.

Examples

  • $ # Lets see if python is present on the system$ python --versionpython: command not found$ # Use nix-shell to create a shell environment with python$ nix-shell -p python3(nix-shell) $ python --versionPython 3.7.7(nix-shell) $ # YAAAY! Python is available(nix-shell) $ exit$ And this is how you create on demand environments

    On demand development environments

    Suspendisse ac dolor id ex accumsan mattis in in lacus. Sed eget ultrices diam, et pretium sem.

  • $ # Lets create an environment with multiple packages$ nix-shell -p python3 nodejs go rustc(nix-shell) $ node --versionv10.20.1(nix-shell) $ go versiongo version go1.14.1 linux/amd64(nix-shell) $ rustc --versionrustc 1.42.0(nix-shell) $ # Imagine how easy (nix-shell) $ exit$ # And POOF, just like that your are back to your normal environment after$ # playing around. No system was hurt during this time :)

    Multiple languages support

    Morbi molestie ultrices odio pulvinar posuere. Etiam a est vulputate, convallis tortor auctor.

  • $ # You can also persist your development environment.$ # Here is a short example with python and nodejs:$ bat default.nix────────┬──────────────────────────────────────────────────────────────────── │ File: default.nix────────┼──────────────────────────────────────────────────────────────────── 1 │ { pkgs ? import <nixpkgs> {} # here we import the nixpkgs package set 2 │ }: 3 │ pkgs.mkShell { # mkShell is a helper function 4 │ name="dev-environment"; # that requires a name 5 │ buildInputs = [ # and a list of packages 6 │ pkgs.python3 7 │ pkgs.python3Packages.virtualenv 8 │ pkgs.nodejs 9 │ pkgs.yarn 10 │ ]; 11 │ shellHook = '' # bash to run when you enter the shell 12 │ echo "Start developing..." 13 │ ''; 14 │ }────────┴────────────────────────────────────────────────────────────────────$ # Pause the video to read and understand the default.nix$ # To enter dev-environment simply run:$ nix-shellStart developing...(nix-shell) $ python --versionPython 3.7.7(nix-shell) $ virtualenv --version16.7.9(nix-shell) $ # With python and virtualenv you should be ready to start(nix-shell) $ # your python project(nix-shell) $ node --versionv10.20.1(nix-shell) $ yarn --version1.22.4(nix-shell) $ # Having node and yarn in PATH you already know you can(nix-shell) $ # do all the good stuff with nodejs (nix-shell) $ exit$ # How hard it is in your company to share the same version of required$ # tooling across different machines?

    Reproducible development environments

    Donec at faucibus diam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer at pretium magna.

  • $ # We all love docker. But it becomes hard with time to write $ # reliable Dockerfile.$ # What if you can use the power of Nix and build Docker images?$ bat docker.nix───────┬───────────────────────────────────────────────────────────────────── │ File: docker.nix───────┼───────────────────────────────────────────────────────────────────── 1 │ { pkgs ? import <nixpkgs> {} # nixpkgs package set 2 │ }: 3 │ pkgs.dockerTools.buildLayeredImage { # helper to build docker image 4 │ name = "nix-hello"; # give docker image a name 5 │ tag = "latest"; # provide a tag 6 │ contents = [ pkgs.hello ]; # packages in docker image 7 │ }───────┴─────────────────────────────────────────────────────────────────────$ # Pause the video to read and understand the docker.nix$ # Now we build a docker image with nix-build$ nix-build default.nix -o result/nix/store/91ry9y0686xn9dgnn6rawfvknj8582ws-nix-hello.tar.gz$ # We can import the image into docker as usual$ docker load -i ./resulte25615ae850b: Loading layer 1.649MB/1.649MBbde5792b3b71: Loading layer 256kB/256kB1d9c7edd824b: Loading layer 31.63MB/31.63MBab8ee9b997a1: Loading layer 266.2kB/266.2kBf568d8025dd8: Loading layer 71.68kB/71.68kBLoaded image: nix-hello:latest$ # You can see that docker layers were automatically calculated.$ docker images | grep nix-hellonix-hello latest 83667617cdb9 50 years ago 32.9MB$ # And for the final thing lets test that it really works$ docker run -ti nix-hello:latest helloHello World!$ # There is a lot we didn't cover in this little demo, but we hope$ # it shows that declarative docker images are possible.

    Build Docker images

    Etiam eget eros et urna tincidunt porttitor.

  • $ # How hard would it be to build and configure an Amazon EC2 image?$ # Let us configure a Nginx to serve a "Welcome to nginx!" page, with a $ # valid SSL certificate (via LetsEncrypt) and recommended security settings$ bat amazon.nix────────┬───────────────────────────────────────────────────────────────────── │ File: amazon.nix────────┼───────────────────────────────────────────────────────────────────── 1 │ { pkgs, ...}: 2 │ { 3 │ security.acme.acceptTerms = true; 4 │ security.acme.email = "nix@example.com"; 5 │ services.nginx = { 6 │ enable = true; 7 │ recommendedGzipSettings = true; 8 │ recommendedOptimisation = true; 9 │ recommendedProxySettings = true; 10 │ recommendedTlsSettings = true; 11 │ virtualHosts."example.com" = { 12 │ enableACME = true; 13 │ forceSSL = true; 14 │ locations."/".root = "${pkgs.nginx}/html"; 15 │ }; 16 │ }; 17 │ }────────┴────────────────────────────────────────────────────────────────────$ # Pause the video to understand the default.nix$ # Now we just need to build it.$ nix-build '<nixpkgs/nixos/release.nix>' \ -A amazonImage.x86_64-linux \ --arg configuration ./amazon.nix \ -o ./result...$ ls ./result/nixos-amazon-image-20.09pre130979.gfedcba-x86_64-linux.vhdnix-support$ # The resulting Virtual Hard Disk image (.vhd suffix) can be then be$ # imported to Amazon EC2 as usual.

    Build cloud images

    Amazon EC2, and any other cloud.