Getting Started#
Initialize Repository#
First a flake.nix
needs to be created in the root of the repository.
{
description = "My ArgoCD configuration with nixidy.";
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
inputs.flake-utils.url = "github:numtide/flake-utils";
inputs.nixidy.url = "github:arnarg/nixidy";
outputs = {
self,
nixpkgs,
flake-utils,
nixidy,
}: (flake-utils.lib.eachDefaultSystem (system: let
pkgs = import nixpkgs {
inherit system;
};
in {
# This declares the available nixidy envs.
nixidyEnvs = nixidy.lib.mkEnvs {
inherit pkgs;
envs = {
# Currently we only have the one dev env.
dev.modules = [./env/dev.nix];
};
};
# Handy to have nixidy cli available in the local
# flake too.
packages.nixidy = nixidy.packages.${system}.default;
# Useful development shell with nixidy in path.
# Run `nix develop` to enter.
devShells.default = pkgs.mkShell {
buildInputs = [nixidy.packages.${system}.default];
};
}));
}
Info
In the rest of the guide when running the nixidy
cli (e.g. nixidy build
) you can use nix run .#nixidy -- build
or enter a nix shell with nix develop
where nixidy
will be available, with the flake.nix
example above.
The flake declares a single nixidy environment called dev
. It includes a single nix module found at ./env/dev.nix
, so let's create that.
Dependency pinning
Instead of using nix channels, the recommended way to use nixidy without flakes is to use either npins or niv to lock dependency versions in your repository.
First initialize npins:
npins init --bare
Then add nixidy:
npins add github arnarg nixidy --branch main # or --at vx.x.x
First initialize niv:
niv init --no-nixpkgs
Then add nixidy:
niv add github arnarg/nixidy --branch main # or --rev vx.x.x
First a default.nix
needs to be created in the root of the repository.
let
# With npins
sources = import ./npins;
# With niv
# sources = import ./nix/sources.nix;
# Import nixidy
nixidy = import sources.nixidy {};
in
nixidy.lib.mkEnvs {
# This declares the available nixidy envs.
envs = {
# Currently we only have the one dev env.
dev.modules = [./env/dev.nix];
};
}
It's also a good idea to have shell.nix
file in the root of the repository to have the necessary tools available.
let
# With npins
sources = import ./npins;
# With niv
# sources = import ./nix/sources.nix;
# nixpkgs added with:
# npins: `npins add --name nixpkgs channel nixos-unstable`
# niv: `niv add github nixos/nixpkgs -b nixos-unstable`
nixpkgs = sources.nixpkgs;
pkgs = import nixpkgs {};
# Import nixidy
nixidy = import sources.nixidy {inherit nixpkgs;};
in
pkgs.mkShellNoCC {
packages = with pkgs; [
# Add nixidy cli
nixidy.nixidy
# npins
npins
# or niv
niv
];
}
Info
In the rest of the guide when running the nixidy
cli (e.g. nixidy build
) you can run nix-shell
to enter a nix shell where nixidy
will be a avilable, with the shell.nix
example above.
Warning
In the rest of the guide the nixidy
commands will also use the flakes format (e.g. nixidy build .#dev
), when using a flake-less setup the .#
prefix should be removed (e.g. nixidy build dev
).
The default.nix
file declares a single nixidy environment called dev
. It includes a single nix module found at ./env/dev.nix
, so let's create that.
{
# Set the target repository for the rendered manifests
# and applications.
# This should be replaced with yours, usually the same
# repository as the nixidy definitions.
nixidy.target.repository = "https://github.com/arnarg/nixidy-demo.git";
# Set the target branch the rendered manifests for _this_
# environment should be pushed to in the repository defined
# above.
nixidy.target.branch = "main";
# Set the target sub-directory to copy the generated
# manifests to when running `nixidy switch .#dev`.
nixidy.target.rootPath = "./manifests/dev";
}
Now running nixidy info .#dev
you can get the same info we just declared above. This verifies that things are set up correctly so far.
>> nixidy info .#dev
Repository: https://github.com/arnarg/nixidy-demo.git
Branch: main
If we now attempt to build this new environment with nixidy build .#dev
we can see that nothing is generated but an empty folder called apps
.
>> tree result
result
└── apps/
This is because we have not declared any applications yet for this environment.
Our first Application#
Applications and their resources are defined under applications.<applicationName>
.
{
# Set the target repository for the rendered manifests
# and applications.
# This should be replaced with yours, usually the same
# repository as the nixidy definitions.
nixidy.target.repository = "https://github.com/arnarg/nixidy-demo.git";
# Set the target branch the rendered manifests for _this_
# environment should be pushed to in the repository defined
# above.
nixidy.target.branch = "main";
# Set the target sub-directory to copy the generated
# manifests to when running `nixidy switch .#dev`.
nixidy.target.rootPath = "./manifests/dev";
# Define an application called `demo`.
applications.demo = {
# All resources will be deployed into this namespace.
namespace = "demo";
# Automatically generate a namespace resource for the
# above set namespace
createNamespace = true;
resources = let
labels = {
"app.kubernetes.io/name" = "nginx";
};
in {
# Define a deployment for running an nginx server
deployments.nginx.spec = {
selector.matchLabels = labels;
template = {
metadata.labels = labels;
spec = {
securityContext.fsGroup = 1000;
containers.nginx = {
image = "nginx:1.25.1";
imagePullPolicy = "IfNotPresent";
volumeMounts = {
"/etc/nginx".name = "config";
"/var/lib/html".name = "static";
};
};
volumes = {
config.configMap.name = "nginx-config";
static.configMap.name = "nginx-static";
};
};
};
};
# Define config maps with config for nginx
configMaps = {
nginx-config.data."nginx.conf" = ''
user nginx nginx;
error_log /dev/stdout info;
pid /dev/null;
events {}
http {
access_log /dev/stdout;
server {
listen 80;
index index.html;
location / {
root /var/lib/html;
}
}
}
'';
nginx-static.data."index.html" = ''
<html><body><h1>Hello from NGINX</h1></body></html>
'';
};
# Define service for nginx
services.nginx.spec = {
selector = labels;
ports.http.port = 80;
};
};
};
}
Running nixidy build .#dev
will produce the following files.
>> tree -l result/
├── apps
│ └── Application-demo.yaml
└── demo
├── ConfigMap-nginx-config.yaml
├── ConfigMap-nginx-static.yaml
├── Deployment-nginx.yaml
├── Namespace-demo.yaml
└── Service-nginx.yaml
And the contents of the Argo CD application automatically generated is the following:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
# This is the name of the application (`applications.demo`).
name: demo
namespace: argocd
spec:
destination:
# This is the destination namespace for the application
# specified with `applications.demo.namespace`.
namespace: demo
server: https://kubernetes.default.svc
project: default
source:
# This is the output path declared for the application with
# option `applications.<applicationName>.output.path`
# (defaults to the name) with `nixidy.target.rootPath`
# prefix.
path: ./manifests/dev/demo
# Repository specified in `nixidy.target.repository`.
repoURL: https://github.com/arnarg/nixidy-demo.git
# Branch specified in `nixidy.target.branch`.
targetRevision: main
syncPolicy:
automated:
prune: false
selfHeal: false
A directory with rendered resources is generated for each application declared with applications.<name>
as well as an Argo CD application resource YAML file in apps/
. What this provides is the option to bootstrap the whole rendered branch to a cluster by adding an application pointing to the apps/
folder.
See App of Apps Pattern.
Running nixidy switch .#dev
will create the ./manifests/dev
relative to the current working directory and sync the newly generated manifests into it.
Bootstrapping Cluster#
After creating a git repository that is specified in nixidy.target.repository
and pushing the generated manifests (e.g. by running nixidy switch .#dev
) to the branch specified in nixidy.target.branch
, your cluster can be bootstrapped.
Make sure you have access to the Kubernetes API and Argo CD is installed and running on your cluster (refer to Argo CD's getting started guide for that).
For quick bootstrapping you can run the command nixidy bootstrap
to output an initial Application
that will trigger a deployment of all other applications.
>> nixidy bootstrap .#dev
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: apps
namespace: argocd
spec:
destination:
namespace: argocd
server: https://kubernetes.default.svc
project: default
source:
path: ./manifests/dev/apps
repoURL: https://github.com/arnarg/nixidy-demo.git
targetRevision: main
syncPolicy:
automated:
prune: true
selfHeal: true
To actually deploy it, run nixidy bootstrap .#dev | kubectl apply -f -
(this assumes that the argocd namespace already exists in the cluster).
Alternatively, create a new application in the Argo CD Web GUI by specifying the manifests/dev/apps
path.
Next Steps#
Now that the cluster is running the applications specified in your nixidy config, you might want to build your applications on top of helm charts or have Github Actions generate the manifests.