{"id":14968047,"url":"https://github.com/gilligan/kind-kubenix","last_synced_at":"2025-10-26T00:30:55.290Z","repository":{"id":49800218,"uuid":"173735631","full_name":"gilligan/kind-kubenix","owner":"gilligan","description":"A playground to use kubenix with a kind cluster","archived":false,"fork":false,"pushed_at":"2022-12-09T14:36:10.000Z","size":44,"stargazers_count":35,"open_issues_count":4,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-01-31T12:51:24.404Z","etag":null,"topics":["docker","kubernetes","nix","nixpkgs"],"latest_commit_sha":null,"homepage":null,"language":"Nix","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gilligan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-03-04T11:52:53.000Z","updated_at":"2024-12-12T08:14:41.000Z","dependencies_parsed_at":"2023-01-25T18:01:45.481Z","dependency_job_id":null,"html_url":"https://github.com/gilligan/kind-kubenix","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gilligan%2Fkind-kubenix","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gilligan%2Fkind-kubenix/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gilligan%2Fkind-kubenix/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gilligan%2Fkind-kubenix/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gilligan","download_url":"https://codeload.github.com/gilligan/kind-kubenix/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238229940,"owners_count":19437723,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","kubernetes","nix","nixpkgs"],"created_at":"2024-09-24T13:39:09.758Z","updated_at":"2025-10-26T00:30:55.009Z","avatar_url":"https://github.com/gilligan.png","language":"Nix","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Playing With Kubernetes: Nix, Kind And Kubenix\n\nIn a project I was working on recently I was tasked with implementing local testing of a kubernetes setup the client was working on. I ended up using [kind](https://github.com/kubernetes-sigs/kind) for this and it worked out nicely. Another tool that I have been meaning to try is [kubenix](https://github.com/xtruder/kubenix). In this post I will give a short overview on a couple of topics:\n\n- Nixifying a small nodejs service\n- Creating a docker image the nix way\n- Using kind to easily boot up a k8s cluster\n- Describing k8s deployments with kubenix\n\nNote that what I am presenting is for motivational purposes and you should certainly put more thought into your setup if you want to take this approach to production.\n\n### A service to deploy: hello\n\nIn order to deploy something to kubernetes we first need some service. The service itself is mostly irrelevant for our purposes so we just write a little express based JavaScript app that returns \"Hello World\" on a port that can be configured via the environment variable `APP_PORT`:\n\n```js\n#!/usr/bin/env node\n\nconst express = require('express');\nconst app = express();\nconst port = process.env.APP_PORT ? process.env.APP_PORT : 3000;\n\n\napp.get('/', (req, res) =\u003e res.send('Hello World'));\napp.listen(port, () =\u003e console.log(`Listening on port ${port}`));\n```\n\nGranted we could just deploy some random public docker image but hey, where would be the fun in that :)\n\n#### Can we nixify this please? Yes we can!\n\nIn order to nixify our little [hello-app](./hello-app/index.js) we are going to use\n[yarn2nix](https://github.com/moretea/yarn2nix) which makes everything really for us:\n\n```nix\npkgs.yarn2nix.mkYarnPackage {\n  name = \"hello-app\";\n  src = ./.;\n  packageJson = ./package.json;\n  yarnLock = ./yarn.lock;\n}\n```\n\nWe just have to make sure that we add `\"bin\": \"index.js\"` to our `package.json` and `mkYarnPackage` will put\n`index.js` in the `bin` path of our output. Since we added `#!/usr/bin/env node` to `index.js`, node will also be\nadded to closure of our app derivation.\n\n#### Creating a docker image of our app\n\nNext we want to create a docker image of our app using [`dockerTools.buildLayeredImage`](https://nixos.org/nixpkgs/manual/#ssec-pkgs-dockerTools-buildLayeredImage):\n\n```nix\n  pkgs.dockerTools.buildLayeredImage {\n    name = \"hello-app\";\n    tag = \"latest\";\n    config.Cmd = [ \"${helloApp}/bin/hello-app\" ];\n  }\n```\n`${helloApp}` is of course the derivation we created above using `mkYarnPackage`. Easy as pie.\n\n### Cluster in a box: kind\n\nkind is a portable (linux, osx and windows) solution to running kubernetes clusters locally, in a docker container. The project\nis still young but it is getting a lot of support and works very well already:\n\n```\nCreating cluster \"kind\" ...\n ✓ Ensuring node image (kindest/node:v1.13.3) 🖼\n ✓ [control-plane] Creating node container 📦 \n ✓ [control-plane] Fixing mounts 🗻 \n ✓ [control-plane] Configuring proxy 🐋\n ✓ [control-plane] Starting systemd 🖥 \n ✓ [control-plane] Waiting for docker to be ready 🐋 \n ✓ [control-plane] Pre-loading images 🐋 \n ✓ [control-plane] Creating the kubeadm config file ⛵ \n ✓ [control-plane] Starting Kubernetes (this may take a minute) ☸ \nCluster creation complete. You can now use the cluster with:\n\nexport KUBECONFIG=\"$(kind get kubeconfig-path --name=\"kind\")\"\nkubectl cluster-info\n```\n\nAll it takes is `kind create cluster` and setting the correct KUBECONFIG environment variable and we can interact with the cluster via `kubectl`.\n\n\n### kubenix: validation for free and no yaml in sight either\n\nThe [kubenix](https://github.com/xtruder/kubenix) parses a kubernetes configuration in Nix and validates it against the official swagger specification of the designated kubernetes version. Apart from getting a compile-time validation for free, writing kubernetes configurations in Nix allows for much better abstraction and less redundancy which otherwise creeps in all to easy.\n\nFor the most part the [configuration.nix](./configuration.nix) is analogous to what would otherwise be written in YAML or JSON. Yet `configuration.nix` actually defines a function and introduces a small let binding:\n\n```nix\n{ type ? \"dev\" }:\n\nlet\n  kubeVersion = \"1.11\";\n\n  helloApp = rec {\n    label = \"hello\";\n    port = 3000;\n    cpu = if type == \"dev\" then \"100m\" else \"1000m\";\n    imagePolicy = if type == \"dev\" then \"Never\" else \"IfNotPresent\";\n    env = [{ name = \"APP_PORT\"; value = \"${toString port}\"; }];\n  };\nin\n{\n  kubernetes.version = kubeVersion;\n  # ...\n}\n\n```\n\nFunction takes a `type` argument which is used for augmenting the requested resources of the deployment. Obviously this is just a motivating example. It would also be possible to split bigger configurations into `production.nix` and `development.nix` which both import settings from `generic.nix`. The best solution is the one that works best for your setup and requirements. The very fact that there are now different options to pick from is an advantage over being restricted to a bunch of YAML files. Creating a json output which can be fed into `kubectl` can be created using `kubenix.buildResources`:\n\n```nix\nbuildConfig = t: kubenix.buildResources { configuration = import ./configuration.nix { type = t; }; };\n\n```\n\n### Applying our configuration\n\nkubenix gives us a validated k8s configuration (try to add some nonesense and you will see that it will actually yell at you) and with kind we can pull up a k8s cluster without any effort. Time to actually apply the configuration. [deploy-to-kind](./nix/deploy-to-kind.nix) does just that.\n\nOne thing to worth mentioning about this: The docerized `hello` service is a docker archive, a local .tar.gz archive. When kubernetes is asked to apply a `hello-app:latest` image it will try to fetch it from somewhere. To avoid that from happening we have to do two things:\n\n1. Tell kubernetes to never pull the image: [configuration.nix](./configuration.nix#L27)\n2. Make the image available using `kind load image-archive`: [nix/deploy-to-kind.nix](nix/deploy-to-kind.nix#13)\n\nWith that in place the deployment will work just fine.\n\n### Finishing Up\n\nThe `default.nix` of the project exposes the following attributes:\n\n- `app`: The nodejs service. It can be build via `nix-build -A`.\n- `deploy-to-kind`: A script that starts a kind cluster and deploys `configuration.nix`.\n- `test-deployment`: A script that implements some very simplistic smoke test to check if our app is up and working.\n- `deploy-and-test`: Running this shell via `nix-shell -a deploy-and-test default.nix` will deploy, wait for the deployment and finally test it.\n- `shell`: Started via `nix-shell` this shell provides all required inputs for manually deploying and testing.\n\n**Notes**:\n- The version of `kind` used in this project is built from the master revision at the time of writing. The latest release doesn't include the `kind load` functionality.\n- kubenix currently doesn't have any documentation but a major overhaul with great features is in the works. Follow [kubenix refactoring](https://github.com/xtruder/kubenix/issues/9) for details.\n- I used [wait-for-deployment](https://github.com/timoreimann/kubernetes-scripts) - a nice little bash script - to wait for the completion of the deployment.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgilligan%2Fkind-kubenix","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgilligan%2Fkind-kubenix","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgilligan%2Fkind-kubenix/lists"}