This project demonstrates various ways to build a custom NixOS AMI from a configuration.nix
file.
It largely exercises the methods shown in jackkelly's blog post http://jackkelly.name/blog/archives/2020/08/30/building_and_importing_nixos_amis_on_ec2/.
This README presents the following methods to create AMIs:
- Methods to build an AMI image file on your computer and then upload it:
- Method 1:
nix-build
- Method 2:
nixios-generators
These methods build your image from scratch.
- Method 1:
- Methods to build an AMI image on an EC2 machine:
- Method 3:
packer
This method starts with an official NixOS AMI, applies yourconfiguration.nix
, and snapshots it into a new AMI.
- Method 3:
All methods assume that you have:
- checked out the version of nixpkgs you want to use at
$HOME/src/nixpkgs
. - Adjusted
./nixos/configuration.nix
to contain your desired NixOS config.
NIX_PATH=nixpkgs=$HOME/src/nixpkgs \
nix-build --no-out-link $HOME/src/nixpkgs/nixos/release.nix \
--arg configuration nixos/configuration.nix \
-A amazonImage.x86_64-linux
This prints to stdout the path to a dir containing the AMI .vhd
file.
nixos-generators
is a small repo of wrapper scripts to build NixOS images with simple commands.
NIX_PATH=nixpkgs=$HOME/src/nixpkgs \
$(nix-build --no-out-link https://github.com/nix-community/nixos-generators/archive/master.tar.gz)/bin/nixos-generate \
-f amazon
This prints to stdout the path to a subdir of the dir containing the AMI (you have to strip the last 2 dirs off it to get to the .vhd
file's dir).
The inner nix-build
builds nixos-generators
itself, and then we invoke its nixos-generate
binary.
It picks up our nixos/configuration.nix
by file naming conventions.
In contrast to the previous methods, this requires having set up ~/.aws/credentials
because it will do the AMI building on a throwaway EC2 machine that packer
launches.
It starts the official NixOS AMI, applies your configuration.nix
, and snapshots the result into a new AMI.
You can read a basic Packer tutorial here.
I've saved jackkelly's Packer config in ./packer/nixos-packer-example.json, and modified it to give the machine that does the AMI building a larger disk, to not run out of disk space (making sure that the device_name
is the one for the root device of that instance type). The config uses "most_recent": true
to select the most recent official NixOS image as a base.
In the below, replace AWS_REGION=eu-central-1
by the region to create the AMI in.
NIX_PATH=nixpkgs=$HOME/src/nixpkgs \
nix-shell --pure -p packer --run 'cd packer/ && AWS_REGION=eu-central-1 packer build nixos-packer-example.json'
With the Packer method you do not need to import the AMI into EC2; Packer already does that for you.
You need an S3 bucket to upload the AMI to. jackkelly's blog post kindly provides a CloudFormation template; I saved it saved in this repo under ./ami-importing/cloudformation/template.yaml
.
I then downloaded this version of the nixpkgs create-amis.sh
script of create-amis.sh
and modified it
to comment out the calls to
make_image_public
, and also comment out the loop in upload_all that iterates across the regions
The result is in this repo under ./ami-importing/create-amis.sh.
Steps to upload the AMI:
- Open CloudFormation in the AWS console, and import
./ami-importing/cloudformation/template.yaml
into it. This creates an S3 bucket for you.
- Be aware that the bucket is created in the AWS region that you've currently chosen (in the top right). Note down that region.
- Open S3 in the AWS console, and figure out the name of the created S3 bucket.
It should look like
nixos-ami-building-vmimportbucket-prf5j5yydsx3
. - Edit
./ami-importing/create-amis.sh
, replacing:
- the
home_region=
variable by the region that you created your bucket in - the
bucket=
variable by your bucket name
-
Configure your
~/.aws/credentials
file so that theaws
CLI utility has access to your AWS account. (This is outside the scope of this README, but easy to find docs for.) -
Run the script (replace the path to the dir containing the AMI
.vhd
by your own):NIX_PATH=nixpkgs=$HOME/src/nixpkgs \ ami-importing/create-amis.sh \ /nix/store/1wgfx4m76bcmdyzsw49pvs13l6gl6gim-nixos-amazon-image-20.09beta-111781.gfedcba-x86_64-linux/
Click to expand issues of the upload script itself
Note that as of writing, like most shell scripts, the script doesn't do proper error handling: On success, no exit code is set, and it continues to run subsequent steps even if earlier steps failed because you haven't configured AWS credentials. Don't do shell scripts.
After this, you should find the AMI in your EC2 AMI list.
Note that the create-amis.sh
remembers in the configured state_dir=
which images were already uploaded.
If you want to re-build an AMI from the same nixpkgs version (but e.g. different configuration.nix
), you have to delete ("Deregister") the AMI on EC2, and wipe state_dir=
(thus, by default, rm -r ~/amis
). Otherwise the script will be a no-op.
Click to expand Troubleshooting section
The given S3 object is not local to the region
- The
home_region=
in the upload script does not match your bucket's region.
- The
- Upload error
when calling the CreateMultipartUpload operation: Access Denied
- You either have not configured
~/.aws/credentials
, orbucket=
in the upload script does not match your bucket's name.
- You either have not configured
- What does a successful
create-amis.sh
invocation look like? Roughly like this:Image Details: Name: NixOS-20.09.git.6608ea8eb6a-x86_64-linux Description: NixOS 20.09.git.6608ea8eb6a x86_64-linux Size (gigabytes): 3 System: x86_64-linux Amazon Arch: x86_64 Checking for image on S3 Image missing from aws, uploading upload: ../../../../nix/store/6blb4hdpjyfi0ysd169sw7y7p17l3idh-nixos-amazon-image-20.09beta-111781.gfedcba-x86_64-linux/nixos-amazon-image-20.09beta-111781.gfedcba-x86_64-linux.vhd to s3://nixos-ami-building-vmimportbucket-prf5j5yydsx3/nix/store/6blb4hdpjyfi0ysd169sw7y7p17l3idh-nixos-amazon-image-20.09beta-111781.gfedcba-x86_64-linux/nixos-amazon-image-20.09beta-111781.gfedcba-x86_64-linux.vhd Importing image from S3 path s3://nixos-ami-building-vmimportbucket-prf5j5yydsx3/nix/store/6blb4hdpjyfi0ysd169sw7y7p17l3idh-nixos-amazon-image-20.09beta-111781.gfedcba-x86_64-linux/nixos-amazon-image-20.09beta-111781.gfedcba-x86_64-linux.vhd Waiting for import task import-snap-0054ec2e7d6bf866d to be completed ... state=active progress=2 snapshot_id=null [..] ... state=active progress=94 snapshot_id=snap-0054ec2e7d6bf866d [..] ... state=completed progress=null snapshot_id=snap-0054ec2e7d6bf866d Registering snapshot snap-0054ec2e7d6bf866d as AMI { "eu-central-1.x86_64-linux": "ami-06743a1c5bc56e348" }
This work was sponsored by Tyler Technologies and FP Complete.