class: center, middle # Welcome to DevOps State College --- # Why DevOps State College? * Build a community and make connections * Exchange ideas * Learn * Promote DevOps culture * Fun * Not tied to one vendor/technology --- # What is DevOps? Grand unification of philosophy around how to manage Development (programmers, application analysts, application owners, project managers) and IT Operations (system admins, network admins, security, data center, storage, database admin) in a tightly-integrated way. DevOps is the belief that working together as a collaborative team will produce better results, and break down barriers and finger pointing. --- # Future Presentations --- # Job Opportunities * AppliedTrust * AppliedTrust is hiring in Philadelphia, Dallas and Boulder offices. * For more information, see https://www.appliedtrust.com/jobs/ or talk to me afterwards --- # Why yet another package manager??? * reproducibility * easy rollbacks * multi-user support * simultaneous installs of different version of same package * simultaneous installs of packages with different dependencies * derivations/packages are stored in the nix store as follows: /nix/store/hash-name * immutable packages, upgrades are a new derivation which results in a different hash credit where credit is due: Much of this is heavily borrowed from nix pills: https://github.com/NixOS/nixpkgs/issues/27908 --- # Getting Started * `curl https://nixos.org/nix/install | sh` * If anyone wants to follow along on their laptop, run this command now. --- # What's this thing actually do? * Download tarball and verify sha256 hash * Extract to temp location * creates /nix with current user (using sudo) * copies the store from temp location to /nix/store * initializes nix database (sqlite) * Sets up shell profile to source nix init scripts so nix commands are available --- # Nix: The Basics - Installation * Source the init script: source ~/.nix-profile/etc/profile.d/nix.sh * Install a package using `nix-env -i
` * How's it work? * nix creates symlink `.nix-profile -> /nix/var/nix/profiles/per-user/sam/profile` * `/nix/var/nix/profiles/per-user/sam/profile -> profile-38-link` * `/nix/var/nix/profiles/per-user/sam/profile-38-link -> /nix/store/kr5bqnqqx88g1szriq9qwz11g40yfkx1-user-environment` * When we install a package, the user environment adds a dependency to that package * That environment links that package into the bin directory in that profile in the store --- # Nix: The Basics - Rollbacks * `nix-env --rollback` * `nix-env -G 3` * How's it work? * rollback takes current generation number and subtracts one. * `-G` switches to a specific generation --- # Nix: The Basics - Removal * Remove a package: `nix-env -e nix-repl` --- # Nix: The Basics - Querying the store * List installed packages: `nix-env -q` * Show runtime dependencies of derivation ``` nix-store -q --references `which nix-repl` ``` * Show reverse dependencies of derivation ``` nix-store -q --referrals `which nix-repl` ``` * Display closure of a derivation (all recursive dependencies required to run) ``` nix-store -qR `which nix-repl` ``` * Display closure of a derivation in a tree format ``` nix-store -q --tree `which nix-repl` ``` --- # Nix: The Language - Basics * Basic Types: * int * string * path (evaluates to a string) * boolean * null * Basic Operations: * addition/subtraction/multiplication/boolean logic * Lazy - Nix will only evaluate an expression if it's used --- # Nix: The Language - Strings * Both `"foo"` and `''foo''` are acceptable string formats * Strings can be interpolated using `${
}` ex: "foo ${bar}" --- # Nix: The Language - Lists * Sequence of expressions delimited by a space * Can be different types and include expressions * Immutable * Example: `[ "a" 1 true (2+3)]` evaluates to `["a" 1 true 5]` --- # Nix: The Language - Sets * Association of a string and a nix expression * Keys MUST be strings but do not need quoted * Immutable * elements in set end in `;` * Example: `{ foo = "bar"; baz = 1; x = ./foo; x-y = (3 - 2); }` --- # Nix: The Language - If Expression * Expression, not a statement * MUST have else branch * Example: `if a > b then "yes" else "no"` --- # Nix: The Language - Let Expression * Defines local variables to inner expressions * Can be nested * Cannot assign same variable twice * Can refer to other variable in the let expression * Cannot refer to variable in a let expression outside of it * Example: `let a = (let b = 3; in b); in b` --- # Nix: The Language - With Expression * Similar to `using` in c++ or `from module import` in python * Takes a set and includes symbols in the scope of an inner expression * Example: ``` longName = { a = 3; b = 4; } with longName; a + b ``` --- # Nix: The Language - Functions * Functions are anonymous (lambda) * Functions only take one parameter * Example: `double = x: x*2` * Can simulate multiple parameters by using nested functions * Example: mul = a: (b: a*b) * Usage: `mul 3 4` --- # Nix: The Language - Functions with argument sets * A function can take an argument set as a single parameter * Example: `mul = s: s.a*s.b` (This does same as previously) * Usage: `mul { a = 3; b = 4; }` * Another way to write the same function: `mul = { a, b }: a*b` * This defines an argument set without values {a, b} --- # Nix: The Language - Functions with default and variadic values * Using `?` syntax default values can be assigned to an argument set * Example: `mul = { a, b ? 2 }: a*b` * Can also pass variadic arguments, or more attributes than is defined * Example: `mul = { a, b, ... }: a*b` * To access those values though, we need to name the set passed using `@`: * Example: ``` mul = s@{ a, b, ... }: a*b*s.c mul { a = 3; b = 4; c = 2; } 24 ``` --- # Nix: The Language - Imports * We can import from other files using `import` * Example: ``` a = import ./a.nix b = import ./b.nix mul = import ./mul.nix ``` --- # Nix: The Language - Passing arguments to imports * We use functions (as above) * Example: ``` test.nix: { a, b ? 3, trueMsg ? "yes", falseMsg ? "no" }: if a > b then builtins.trace trueMsg true else builtins.trace falseMsg false nix-repl> import ./test.nix { a = 5; trueMsg = "ok"; } trace: ok true ``` * builtins.trace in this case is just a function included in the language --- # Nix: Derivations * This is our first real world example * A derivation is merely a set with some attributes * Required attributes in derivation: `name`, `system`, `builder` * Name is an arbitrary name * System is the system it can be built on * Builder is the program that builds the derivation * A derivation generates a `.drv` file * A `.drv` file is instructions to the system of how to build a derivation * Out paths are the product of the build --- # Nix: Derivations - drv components * output paths (can be multiple, defaults to out) * list of input derivations * system * builder executable * env variables passed to builder --- # Nix: Derivations - output paths * This is where things get interesting... * output path is a concatenation of the cryptographic hash of all build inputs, the name attribute and the output name (if not the default out) * A derivation output as a string is the value of outPath --- # Nix: Derivations - `nix-repl` commands * `:l` (load) * Example: `:l
` (the < > specify load something from NIX_PATH instead of current directory) * `:b` (build) --- # Nix: Derivations - First shot (breaks) ``` nix-repl> :l
nix-repl> d = derivation { name = "myname"; builder = "${coreutils}/bin/true"; system = builtins.currentSystem; } nix-repl> :b d [...] builder for `/nix/store/d4xczdij7xazjfm5kn4nmphx63mpv676-myname.drv' failed to produce output path `/nix/store/fy5lyr5iysn4ayyxvpnsya8r5y5bwjnl-myname' ``` * So we built something, but it failed because it didn't produce an output. A builder MUST produce an output. --- # Nix: Derivations - Builders * A builder is just a script (or some other binary) * It gets passed the nix build environment variables. * Most important is $out which is where the derivation should output to * It should not depend on $HOME (and nix messes with $HOME to ensure that) --- # Nix: Derivations - A working example ``` simple.c: void main () { puts ("Simple!"); } builder.sh: export PATH="$coreutils/bin:$gcc/bin" mkdir $out gcc -o $out/simple $src default.nix: with (import
{}); derivation { name = "simple"; builder = "${bash}/bin/bash"; args = [ ./builder.sh ]; inherit gcc coreutils; src = ./simple.c; system = builtins.currentSystem; } ``` * Build with nix-build. Will symlink build dir to result in current directory. * Run with result/simple --- # Nix: stdenv What we've done so far is pretty complicated. Do we really have to do this for everything we package? * First, a sidebar, if your interested in more under the hood things, please check out all the nix pills. They go a lot more in-depth * Enter stdenv (simplest form) ``` with import
{}; stdenv.mkDerivation { name = "hello"; src = ./hello-2.9.tar.gz; } ``` * This will use the default builder to run through a normal autotools process --- # Nix: stdenv - a more complete example ``` default.nix: { stdenv, fetchurl }: stdenv.mkDerivation rec { name = "hello-2.10"; src = fetchurl { url = "mirror://gnu/hello/${name}.tar.gz"; sha256 = "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"; }; doCheck = true; meta = { description = "A program that produces a familiar, friendly greeting"; longDescription = '' GNU Hello is a program that prints "Hello, world!" when you run it. It is fully customizable. ''; homepage = http://www.gnu.org/software/hello/manual/; license = stdenv.lib.licenses.gpl3Plus; maintainers = [ stdenv.lib.maintainers.eelco ]; platforms = stdenv.lib.platforms.all; }; } ``` --- # Nix: stdenv - building and debugging * Build the derivation `nix-build -E 'with import
{ }; callPackage ./default.nix {}'` * Build the derivation and keep the temp build directory `nix-build -K -E 'with import
{ }; callPackage ./default.nix {}'` * We can also get into a shell to manually build for debugging: `nix-shell -E 'with import
{ }; callPackage ./default.nix {}'` --- class: center, middle # LIVE DEMO