About
It's a raw export of the slides from a talk at PyConWEB about my approach of using Nix to get reproducible development environments. It is based on my experience from the last few years of using this approach in various companies / projects. It's origins go back to the point of being introduced to Nix by Rok Garbas in 2014.
The main intend is to help attendees if they want to follow pointers just by clicking on them instead of typing the URLs themselves into Google ;)
Intro
Hello!
Note
- Johannes Bornhold
- 2011 - Python project, geo dependencies
- 2014 - RhodeCode, challenging dependencies, Nix
- 2016 - Focus on my company, more Nix
Dependencies
What is in the box?
Note
- Q: Needs for typical Python based web project?
- Q: Web specific?
- thoughts
- Python + X
- mainly JS: npm, bower, grunt, webpack
- System dependencies
Perspective
Developer's perspective
Note
- Perspectives to look at dependencies
- Ops
- Legal
- Dev
- Multiple projects, easy switching
- Multiple people, aka TEAM
Nix
- Build tool
- Package manager
- Symlinks on steroids
Note
- build tool
- describe how to build an application
- and in fact build it
- store the binary result
- package manager
- describe a set of application
- and build them
- install the binary build result
- symlinks
- stores build results in a store
- isolated per build
- symlinks pointing to dependencies
- symlinks pointing to build results
Building
1 $ nix-build release.nix -A pip2nix.python35 2 these derivations will be built: 3 /nix/store/2hfsb0ixayq5y7nimziqz09zm1jj07nn-python3.5-MarkupSafe-0.23.drv 4 /nix/store/4i5vhgnmdwf5pnjd2dza4ww7kiz4m600-py-1.4.32.tar.gz.drv 5 /nix/store/c6skp7sf7c8jdcg63qryhl9hsack473k-python3.5-jinja2-2.8.drv 6 /nix/store/f81liyzxq6ca1rb8vsnx7fcqzpl3c2lw-python3.5-contexter-0.1.3.drv 7 # [ ... ] 8 these paths will be fetched (58.10 MiB download, 259.00 MiB unpacked): 9 /nix/store/04ccw2f40c0bvlhnhflprn19ia2fv44g-python2.7-ipaddress-1.0.16 10 /nix/store/0f4lw8jasc2sqp86k0czx1llpr5sbr8l-python2.7-pyasn1-0.1.9 11 # [ ... ]
Note
- release.nix describes how to build the application
- based on this description Nix knows what to do
- compare setup.py for pip
- package.json for npm
- you name it
- some dependencies will be
- built
- others fetched
- benefit: binary substitution
- Q: What's /nix/store/ ?
Store
Build result points to the store
1 $ cd ~/my-project 2 $ nix-build 3 # [ ... ] 4 $ ls -l result 5 result -> /nix/store/zic5aq2sx2fv19l9xyv265c2w4cacr8i\ 6 -python3.5-pip2nix-0.7.0.dev1
Easy to run via symlink
7 $ ./result/bin/pip2nix --help 8 Usage: pip2nix [OPTIONS] COMMAND [ARGS]... 9 # [ ... ]
Note
- place to put the build results
- hash based on all build inputs
- two different configurations of the same package result in different hashes
- works with garbage collection
- important to be aware of it ;)
- eventually your disk will fill up
- Q: How do we get a development environment?
Shell
- Fetch or build dependencies
- Prepare a shell environment
1 $ nix-shell release.nix -A pip2nix.python35 2 [nix-shell:~/wo/pip2nix]$ pip2nix --help 3 Usage: pip2nix [OPTIONS] COMMAND [ARGS]... 4 # [ ... ]
Suitable for development
5 [nix-shell:~/wo/pip2nix]$ python -c 'import pip2nix; print(pip2nix)' 6 <module 'pip2nix' from '/Users/johannes/wo/pip2nix/pip2nix/__init__.py'>
Note
- fetching and building dependencies
- same is nix-build
- nix-shell provides
- environment
- all dependencies available
- shell
- hooks - can be handy
- can be used to develop
Nix and Python
Let's look at some code
👀
Note
- Examples
- Starting simple
- Adding more and more trouble
Simple package with dependencies
1 { pkgs ? (import <nixpkgs> {}) }: 2 3 let 4 pythonPackages = pkgs.python36Packages; 5 6 in pythonPackages.buildPythonPackage { 7 name = "sample-1.2.0"; 8 src = ./.; 9 10 propagatedBuildInputs = [ 11 pythonPackages.lxml 12 pythonPackages.peppercorn 13 ]; 14 }
Note
- lxml itself does in fact bring libxml2 and libxslt into the mix
- inside nixpkgs
- the definition of lxml
- have a look
- reality check
- you want tooling support in bigger projects
Nix as development environment
Note
- Q: How can we use it?
- Remember the shell?
- Then other aspects
The shell
Environment with all buildtime dependencies available.
Tweak further via hooks.
Note
- Developer's workhorse
- Default behavior is already a good working environment
- Tweak hooks to adjust to your project's needs
- Experience so far
- Avoid too much magic
- Keep it hackable
- Don't assume you know what your colleagues need and how they should work
- instead provide sane defaults
- and make it easy to override them
Default workflow
1 $ nix-shell 2 [nix-shell:~/wo/my-project]$ # do stuff!
Advanced level
3 $ nix-shell -A i18n-tools 4 $ nix-shell i18n-tools.nix
Note
- The contract to enter an environment is minimalistic
- Run nix-shell
- Or if you have multiple environments
- either select one attribute
- or a different Nix file
- Experience so far
- Using Nix also for build and deployment
- Minimal default.nix describing your package
- A release.nix with build and release-specific things
- A shell.nix with dev-env specific things
- Worked out quite ok so far
- Using Nix also for build and deployment
Automation
pip2nix / pypi2nix
My default layout
1 . 2 ├── default.nix 3 ├── python-packages-overrides.nix 4 ├── python-packages.nix 5 └── setup.py
Note
- developer's perspective
- not about automating the deployment
- do this as well, use nix ;)
- freezing dependencies into a nix file
- 80/20 approach
- layers
Conclusions
Note
- Based on using Nix during the last years
- Mainly Python based web development
- Target platform was Linux
- Development on a mix of Linux / macOS
- 1st conclusion: Not only Python
1+N nixperts
Note
- Build up one expert in your team
- Or have someone in reach available
pin nixpkgs by default
Note
- nixpkgs comes via a channel
- nixos-stable and unstable
- each team member might be on a different commit
- causes friction
- whole team on same set by default
- experts can still hack their way
- buys you time if breaking changes are on their way
- update on a regular base
start small
Note
- don't make it too great in the first step
- it would just blow up
- give time to build experience
- then incrementally put Nix everywhere ;)
CI and deployment
Note
- Talk looks only at development environment
- Nix makes a fantastic foundation for binary deployments
- Rollbacks nearly for free
- CI -> cache
- CI can build your project also against latest nixpkgs
- this way you will know if breaking changes are coming
- Challenge
- Keeping the balance between a good development environment and good support for the ops part.
Automate where possible
Note
- focus here: dependency management
- freezing Python requirements into a Nix expression
- Tooling: pip2nix, pypi2nix
- 80% approach
- think in layers
- get a base automated
- put your tweaks on top of it
- easy re-generation
- similar for other languages' ecosystems
Pointers
The Manuals
For starters:
Next steps:
Note
- The language section of the Nix manual is worth reading.
- MUST READ, pays of fast
- The Python section of the Nixpkgs manual contains a very good overview of various approaches and tooling support.
- Treat Nixpkgs manual as a cookbook / reference
- Poke around frequently
- Lots to offer
The Tools
- pip2nix
- pypi2nix
- more in the nixpkgs manual
- also for other ecosystems
Note
- Tooling available
- Different approaches
- pip2nix abuses pip internals
- pypi2nix treats pip as a black box
- Thinking of merging the tools
- Experience so far
- 80/20 approach works well
- 80% automated is easy to achieve
- 20% tweaking is sustainable
- feels mode like 90/10 actually :)
The Code
Note
- Examples
- Utilities
- Inspiration
- Lots of wheels in there
- no need to invent new ones
The Community
- Be on the mailing list
- Think of IRC
- Be at NixCon 2017
- Have a sticker on your laptop
Notes added which were not part of the talk
Stickers
I am really sorry that I did not have a single sticker with me to distribute.