diff --git a/plugins/README.md b/plugins/README.md index ea8645b..61c1a78 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -4,3 +4,4 @@ |-------------|-------------| | [kasane](kasane/) | The guestbook application as a `kasane` package. | | [kustomized-helm](kustomized-helm/) | Application comprised of a `helm` chart and customized using `kustomize` | +| [nix](nix/) | Application comprised of a `helm` chart built and customized using `nix` | diff --git a/plugins/nix/.gitignore b/plugins/nix/.gitignore new file mode 100644 index 0000000..b2be92b --- /dev/null +++ b/plugins/nix/.gitignore @@ -0,0 +1 @@ +result diff --git a/plugins/nix/README.md b/plugins/nix/README.md new file mode 100644 index 0000000..502f5d9 --- /dev/null +++ b/plugins/nix/README.md @@ -0,0 +1,138 @@ +# nix + +[nix](https://nixos.org/) is a tool that takes a unique approach to package +management and system configuration. + +This setup is based on the [NixCon 2023 talk](https://www.youtube.com/watch?v=SEA1Qm8K4gY). + +## Set up the argo-cd installation for nix support + +This setup uses the stock `nixos/nix:latest` image without any modifications. +That requires some changes in runtime, as nix cannot run as user 999 our of the +box. + +Add the following bits to the values.yaml of your helm deployment: + +```yaml +repoServer: + volumes: + - name: nix-cmp-config + configMap: + name: nix-cmp-config + - name: nix-cmp-tmp + emptyDir: {} + - name: nix-cmp-nix + emptyDir: {} + - name: nix-cmp-home + emptyDir: {} + initContainers: + - name: nix-bootstrap + # the init container copies the whole nix store and profiles into the + # temporary volume and makes sure the permissions are correct + command: + - "sh" + - "-c" + - "cp -a /nix/* /nixvol && chown -R 999 /nixvol/*" + image: nixos/nix:latest + # the image will always be updated at init step, so the one in the + # extraContainers must have the policy of Never to always be the same + # exact image. + imagePullPolicy: Always + volumeMounts: + - mountPath: /nixvol + name: nix-cmp-nix + extraContainers: + - name: nix-cmp-plugin + command: + - /var/run/argocd/argocd-cmp-server + image: nixos/nix:latest + imagePullPolicy: Never + securityContext: + runAsNonRoot: true + runAsUser: 999 + volumeMounts: + - mountPath: /var/run/argocd + name: var-files + - mountPath: /home/argocd/cmp-server/plugins + name: plugins + - mountPath: /home/argocd/cmp-server/config/plugin.yaml + subPath: plugin.yaml + name: nix-cmp-config + - mountPath: /etc/passwd + subPath: passwd + name: nix-cmp-config + - mountPath: /etc/nix/nix.conf + subPath: nix.conf + name: nix-cmp-config + - mountPath: /tmp + name: nix-cmp-tmp + - mountPath: /nix + name: nix-cmp-nix + - mountPath: /home/nix + name: nix-cmp-home +``` + +## Add the plugin ConfigMap: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: nix-cmp-config + namespace: argocd +data: + nix.conf: | + build-users-group = nixbld + sandbox = false + experimental-features = nix-command flakes + substituters = https://cache.nixos.org https://nixhelm.cachix.org + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nixhelm.cachix.org-1:esqauAsR4opRF0UsGrA6H3gD21OrzMnBBYvJXeddjtY= + passwd: | + nix:x:999:30000:Nix build user 1:/home/nix:/bin/false + root:x:0:0::/root:/bin/bash + plugin.yaml: | + apiVersion: argoproj.io/v1alpha1 + kind: ConfigManagementPlugin + metadata: + name: nix-cmp-plugin + spec: + discover: + fileName: flake.nix + generate: + command: + - sh + - "-c" + - cat result + init: + command: + - sh + - "-c" + - | + export OUTPUT="${ARGOCD_ENV_NIX_OUTPUT:-kubernetesConfiguration}" + echo -ne "Building for $OUTPUT\n" >/dev/stderr + if [ "$PARAM_VALUES" != "" ]; then + echo -ne "With values\n" >/dev/stderr + echo "$PARAM_VALUES" > values.json + nix-shell -p git --run ''git add values.json'' + fi + if [ "$PARAM_IMPURE" == "true" ]; then + echo -ne "With impure\n" >/dev/stderr + IMPURE_FLAG="--impure" + else + IMPURE_FLAG="" + fi + nix build $IMPURE_FLAG ".#${OUTPUT}" + lockRepo: true + name: nix-cmp-plugin + version: v1.0 +``` + +## Create a nix-based application + +``` +argocd app create simple-nginx \ + --repo https://github.com/argoproj/argocd-example-apps \ + --path plugins/nix \ + --dest-server https://kubernetes.default.svc \ + --dest-namespace default +``` diff --git a/plugins/nix/flake.nix b/plugins/nix/flake.nix new file mode 100644 index 0000000..6918b31 --- /dev/null +++ b/plugins/nix/flake.nix @@ -0,0 +1,52 @@ +{ + inputs.nixhelm.url = "github:farcaller/nixhelm"; + inputs.kubegen.url = "github:farcaller/nix-kube-generators"; + + outputs = { self, nixpkgs, nixhelm, kubegen, flake-utils }: flake-utils.lib.eachDefaultSystem (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + kubelib = kubegen.lib { inherit pkgs; }; + + addResources = yamlObjects: resources: builtins.foldl' + (acc: y: acc ++ [ y ]) + resources + yamlObjects; + + # You can define k8s objects using standard nix syntax + configMap = { + apiVersion = "v1"; + kind = "ConfigMap"; + metadata.name = "website"; + data."index.html" = '' + + +

Hello, nix world!

+ + + ''; + }; + in + { + packages.kubernetesConfiguration = pkgs.lib.pipe + { + name = "nginx"; + # nixhelm provides a repository of various public helm charts converted to nix + chart = nixhelm.chartsDerivations.${system}.bitnami.nginx; + namespace = "default"; + values = { + replicaCount = 2; + revisionHistoryLimit = 3; + staticSiteConfigmap = configMap.metadata.name; + }; + } [ + # lib.pipe is a handy function to run the processing over several functions in a sequence. + # The final output must gnerate a YAML file. + kubelib.buildHelmChart + builtins.readFile + kubelib.fromYAML + (addResources [configMap]) + kubelib.mkList + kubelib.toYAMLFile + ]; + }); +}