Publish
1
.envrc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
use flake
|
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.direnv/
|
||||||
|
result
|
||||||
|
ideas.txt
|
||||||
|
notes.txt
|
BIN
assets/cat-chewing-cable.jpg
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
assets/helm-example/base.png
Normal file
After Width: | Height: | Size: 215 KiB |
BIN
assets/helm-example/highlight.png
Normal file
After Width: | Height: | Size: 210 KiB |
BIN
assets/helm-example/watermark.png
Normal file
After Width: | Height: | Size: 430 KiB |
BIN
assets/helm.png
Normal file
After Width: | Height: | Size: 135 KiB |
BIN
assets/kubenix-example/base.png
Normal file
After Width: | Height: | Size: 276 KiB |
BIN
assets/kubenix-example/highlight1.png
Normal file
After Width: | Height: | Size: 281 KiB |
BIN
assets/kubenix-example/highlight2.png
Normal file
After Width: | Height: | Size: 284 KiB |
BIN
assets/kubenix-example/highlight3.png
Normal file
After Width: | Height: | Size: 281 KiB |
BIN
assets/kubenix-example/highlight4.png
Normal file
After Width: | Height: | Size: 283 KiB |
BIN
assets/kubenix-github.png
Normal file
After Width: | Height: | Size: 182 KiB |
162
assets/kubenix.svg
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="722.8457"
|
||||||
|
height="701.96637"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||||
|
sodipodi:docname="logo2.svg"
|
||||||
|
inkscape:export-filename="/home/thockin/src/kubernetes/new.png"
|
||||||
|
inkscape:export-xdpi="460.95001"
|
||||||
|
inkscape:export-ydpi="460.95001"
|
||||||
|
xml:space="preserve"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"><defs
|
||||||
|
id="defs4"><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="main"><stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0"
|
||||||
|
offset="0"
|
||||||
|
id="stop915" /><stop
|
||||||
|
id="stop917"
|
||||||
|
offset="0.23168644"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1" /><stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop919" /></linearGradient><linearGradient
|
||||||
|
y2="880.37714"
|
||||||
|
x2="-414.38654"
|
||||||
|
y1="782.33563"
|
||||||
|
x1="-584.19934"
|
||||||
|
gradientTransform="translate(864.69589,-1491.3405)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient1299"
|
||||||
|
xlink:href="#main"
|
||||||
|
inkscape:collect="always" /><linearGradient
|
||||||
|
y2="460.51822"
|
||||||
|
x2="389.57562"
|
||||||
|
y1="351.41116"
|
||||||
|
x1="200.59668"
|
||||||
|
gradientTransform="translate(210.82018,-765.27605)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient1713"
|
||||||
|
xlink:href="#main"
|
||||||
|
inkscape:collect="always" /></defs><sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="0.69351872"
|
||||||
|
inkscape:cx="390.03994"
|
||||||
|
inkscape:cy="303.52461"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="g3052"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1248"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:snap-global="false"
|
||||||
|
fit-margin-top="10"
|
||||||
|
fit-margin-left="10"
|
||||||
|
fit-margin-right="10"
|
||||||
|
fit-margin-bottom="10"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1" /><metadata
|
||||||
|
id="metadata7"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-6.3260942,-174.7524)"><g
|
||||||
|
id="g3052"><path
|
||||||
|
style="fill:#326ce5;fill-opacity:1;stroke:#ffffff;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 365.31239,184.81252 a 46.724621,46.342246 0 0 0 -17.90625,4.53125 l -244.34375,116.75 a 46.724621,46.342246 0 0 0 -25.281248,31.4375 l -60.28125,262.25 a 46.724621,46.342246 0 0 0 6.34375,35.53125 46.724621,46.342246 0 0 0 2.65625,3.6875 L 195.62489,849.28127 a 46.724621,46.342246 0 0 0 36.53125,17.4375 l 271.21875,-0.0625 a 46.724621,46.342246 0 0 0 36.53125,-17.40625 l 169.0625,-210.3125 a 46.724621,46.342246 0 0 0 9.03125,-39.21875 l -60.375,-262.25 a 46.724621,46.342246 0 0 0 -25.28125,-31.4375 l -244.375,-116.6875 a 46.724621,46.342246 0 0 0 -22.65625,-4.53125 z"
|
||||||
|
id="path3055"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:export-filename="new.png"
|
||||||
|
inkscape:export-xdpi="250.55"
|
||||||
|
inkscape:export-ydpi="250.55" /><g
|
||||||
|
id="g321"
|
||||||
|
transform="matrix(1.0666666,0,0,1.0666666,100.31931,303.73558)"><g
|
||||||
|
style="display:none"
|
||||||
|
transform="matrix(0.09048806,0,0,0.09048806,-14.15991,84.454917)"
|
||||||
|
inkscape:label="(pdf) background"
|
||||||
|
id="layer1-3"><rect
|
||||||
|
y="-2102.4253"
|
||||||
|
x="-1045.6049"
|
||||||
|
height="7145.4614"
|
||||||
|
width="7947.0356"
|
||||||
|
id="rect995"
|
||||||
|
style="opacity:1;fill:#040404;fill-opacity:1;stroke-width:10.3605" /></g><g
|
||||||
|
transform="translate(-156.48372,537.56136)"
|
||||||
|
style="display:inline;opacity:1"
|
||||||
|
inkscape:label="gradient-logo"
|
||||||
|
id="layer3"><g
|
||||||
|
style="stroke-width:11.0512"
|
||||||
|
transform="matrix(0.09048806,0,0,0.09048806,142.32381,-453.10644)"
|
||||||
|
id="g955"><g
|
||||||
|
transform="matrix(11.047619,0,0,11.047619,-1572.2888,9377.7107)"
|
||||||
|
id="g869"><g
|
||||||
|
transform="rotate(-60,226.35754,-449.37199)"
|
||||||
|
id="g932"
|
||||||
|
style="stroke-width:11.0512"><path
|
||||||
|
sodipodi:nodetypes="cccccccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path3336-6"
|
||||||
|
d="m 449.71876,-420.51322 122.19683,211.67512 -56.15706,0.5268 -32.6236,-56.8692 -32.85645,56.5653 -27.90237,-0.011 -14.29086,-24.6896 46.81047,-80.4901 -33.22946,-57.8257 z"
|
||||||
|
style="opacity:1;fill:url(#linearGradient1713);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:33.1535;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /></g><path
|
||||||
|
sodipodi:nodetypes="cccccccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4260-0"
|
||||||
|
d="m 309.54892,-710.38827 122.19683,211.67512 -56.15706,0.5268 -32.6236,-56.8692 -32.85645,56.5653 -27.90237,-0.011 -14.29086,-24.6896 46.81047,-80.4901 -33.22946,-57.8256 z"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient1299);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:33.1535;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /><use
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
xlink:href="#path3336-6"
|
||||||
|
inkscape:transform-center-x="124.43045"
|
||||||
|
inkscape:transform-center-y="151.59082"
|
||||||
|
id="use3439-6"
|
||||||
|
transform="rotate(60,728.23563,-692.24036)"
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
style="stroke-width:11.0512" /><use
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
xlink:href="#path3336-6"
|
||||||
|
inkscape:transform-center-x="59.669705"
|
||||||
|
inkscape:transform-center-y="-139.94592"
|
||||||
|
id="use3449-5"
|
||||||
|
transform="rotate(180,477.5036,-570.81898)"
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
style="stroke-width:11.0512" /><use
|
||||||
|
style="display:inline;stroke-width:11.0512"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
xlink:href="#path4260-0"
|
||||||
|
id="use4354-5"
|
||||||
|
transform="rotate(120,407.33916,-716.08356)"
|
||||||
|
width="100%"
|
||||||
|
height="100%" /><use
|
||||||
|
style="display:inline;stroke-width:11.0512"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
xlink:href="#path4260-0"
|
||||||
|
id="use4362-2"
|
||||||
|
transform="rotate(-120,407.28823,-715.86995)"
|
||||||
|
width="100%"
|
||||||
|
height="100%" /></g></g></g></g></g></g></svg>
|
After Width: | Height: | Size: 7.8 KiB |
BIN
assets/kubernetes.png
Normal file
After Width: | Height: | Size: 239 KiB |
BIN
assets/me.jpg
Normal file
After Width: | Height: | Size: 1.6 MiB |
BIN
assets/nix-snapshotter.png
Normal file
After Width: | Height: | Size: 298 KiB |
BIN
assets/nixng.png
Normal file
After Width: | Height: | Size: 284 KiB |
BIN
assets/openapi-spec-example/base.png
Normal file
After Width: | Height: | Size: 156 KiB |
BIN
assets/openapi-spec-example/highlight1.png
Normal file
After Width: | Height: | Size: 157 KiB |
BIN
assets/openapi-spec-example/highlight2.png
Normal file
After Width: | Height: | Size: 157 KiB |
BIN
assets/openapi-spec-gen.png
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
assets/self-hosting/highlight.png
Normal file
After Width: | Height: | Size: 443 KiB |
BIN
assets/self-hosting/logos.png
Normal file
After Width: | Height: | Size: 360 KiB |
BIN
assets/self-hosting/logos.xcf
Normal file
BIN
assets/servers-k8s-kill.jpg
Normal file
After Width: | Height: | Size: 576 KiB |
BIN
assets/servers-k8s-revive.jpg
Normal file
After Width: | Height: | Size: 580 KiB |
BIN
assets/servers-k8s.jpg
Normal file
After Width: | Height: | Size: 595 KiB |
BIN
assets/servers-kill.jpg
Normal file
After Width: | Height: | Size: 609 KiB |
BIN
assets/servers-services.jpg
Normal file
After Width: | Height: | Size: 635 KiB |
BIN
assets/servers.jpg
Normal file
After Width: | Height: | Size: 1.2 MiB |
BIN
assets/servers.jpg-autosave.kra
Normal file
BIN
assets/yaml-manifest/base.png
Normal file
After Width: | Height: | Size: 104 KiB |
BIN
assets/yaml-manifest/highlight1.png
Normal file
After Width: | Height: | Size: 104 KiB |
BIN
assets/yaml-manifest/highlight2.png
Normal file
After Width: | Height: | Size: 106 KiB |
BIN
assets/yaml-manifest/highlight3.png
Normal file
After Width: | Height: | Size: 108 KiB |
27
flake.lock
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1730200266,
|
||||||
|
"narHash": "sha256-l253w0XMT8nWHGXuXqyiIC/bMvh1VRszGXgdpQlfhvU=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "807e9154dcb16384b1b765ebe9cd2bba2ac287fd",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
36
flake.nix
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
description = "Presentation for NixCon 2024";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs }:
|
||||||
|
let
|
||||||
|
supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
|
||||||
|
forEachSupportedSystem = f: nixpkgs.lib.genAttrs supportedSystems (system: f {
|
||||||
|
pkgs = import nixpkgs { inherit system; };
|
||||||
|
});
|
||||||
|
in
|
||||||
|
{
|
||||||
|
packages = forEachSupportedSystem ({ pkgs }: {
|
||||||
|
default = pkgs.stdenv.mkDerivation {
|
||||||
|
name = "nixcon-2024-slides";
|
||||||
|
buildInputs = with pkgs; [ marp-cli ];
|
||||||
|
src = self;
|
||||||
|
dontUnpack = true;
|
||||||
|
|
||||||
|
buildPhase = ''
|
||||||
|
marp $src --output $out/presentation.html --html
|
||||||
|
cp -r $src/assets $out/assets
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
devShells = forEachSupportedSystem ({ pkgs }: {
|
||||||
|
default = pkgs.mkShell {
|
||||||
|
packages = with pkgs; [ marp-cli ];
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
487
presentation.md
Normal file
|
@ -0,0 +1,487 @@
|
||||||
|
---
|
||||||
|
marp: true
|
||||||
|
theme: gaia
|
||||||
|
paginate: true
|
||||||
|
footer: "October 26th, 2024"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Kubenix: Leveraging NixOS modules to generate Kubernetes manifests
|
||||||
|
|
||||||
|
![bg right:35% 100% Kubenix logo](assets/kubenix.svg)
|
||||||
|
|
||||||
|
**Pim Kunis**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Agenda
|
||||||
|
|
||||||
|
![bg right:60% 80%](assets/kubenix-github.png)
|
||||||
|
|
||||||
|
|
||||||
|
1. My background
|
||||||
|
2. Kubernetes
|
||||||
|
3. Kubenix
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# `$ whoami`
|
||||||
|
|
||||||
|
![bg right 60% drop-shadow:0,5px,10px,rgba(0,0,0,.7)](assets/me.jpg)
|
||||||
|
|
||||||
|
- Pim Kunis
|
||||||
|
- Matrix: @pim:envs.net
|
||||||
|
- GitHub: @pizzapim
|
||||||
|
- Consultant @ [Sue](https://sue.nl)
|
||||||
|
- Currently doing Linux + Ansible stuff
|
||||||
|
- Relatively new to Nix
|
||||||
|
- Avid self-hoster
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Self-hosting
|
||||||
|
|
||||||
|
![bg Logos of services I self-host](assets/self-hosting/logos.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Self-hosting
|
||||||
|
|
||||||
|
3 mini PCs (Gigabyte Brix with Intel Celeron J4105)
|
||||||
|
|
||||||
|
![w:900 My servers in their closet](assets/servers-services.jpg)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# NixOS for a cluster?
|
||||||
|
|
||||||
|
![w:900 My servers in their closet](assets/servers-kill.jpg)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# NixOS for a cluster?
|
||||||
|
|
||||||
|
![bg right assets/cat-chewing-cable.jpg](assets/cat-chewing-cable.jpg)
|
||||||
|
|
||||||
|
- Balance services
|
||||||
|
- Maintenance
|
||||||
|
- Services are tied to a particular host
|
||||||
|
- Pets vs cattle
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Agenda
|
||||||
|
|
||||||
|
1. My background
|
||||||
|
2. **Kubernetes**
|
||||||
|
3. Kubenix
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Enter: Kubernetes
|
||||||
|
|
||||||
|
![bg left:40% 100% assets/cat-chewing-cable.jpg](assets/kubernetes.png)
|
||||||
|
|
||||||
|
- Abstracts infrastructure
|
||||||
|
- Container orchestration
|
||||||
|
- Workloads are containers (pods)
|
||||||
|
- Distributed state (etcd)
|
||||||
|
- Actual state
|
||||||
|
- Desired state
|
||||||
|
- Reconciliation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Kubernetes
|
||||||
|
|
||||||
|
![w:900 My servers in their closet](assets/servers-k8s.jpg)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Kubernetes
|
||||||
|
|
||||||
|
![w:900 My servers in their closet](assets/servers-k8s-kill.jpg)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Kubernetes
|
||||||
|
|
||||||
|
![w:900 My servers in their closet](assets/servers-k8s-revive.jpg)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Mutating state in Kubernetes
|
||||||
|
|
||||||
|
![bg 80% hi](assets/yaml-manifest/base.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Mutating state in Kubernetes
|
||||||
|
|
||||||
|
![bg 80% hi](assets/yaml-manifest/highlight1.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Mutating state in Kubernetes
|
||||||
|
|
||||||
|
![bg 80% hi](assets/yaml-manifest/highlight2.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Mutating state in Kubernetes
|
||||||
|
|
||||||
|
![bg 80% hi](assets/yaml-manifest/highlight3.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Helm
|
||||||
|
|
||||||
|
![bg right:50% 60%](assets/helm.png)
|
||||||
|
|
||||||
|
- Package manager
|
||||||
|
- Templating YAML
|
||||||
|
- Cursed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Helm
|
||||||
|
|
||||||
|
|
||||||
|
![bg 80% hi](assets/helm-example/base.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Helm
|
||||||
|
|
||||||
|
|
||||||
|
![bg 80% hi](assets/helm-example/highlight.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Helm
|
||||||
|
|
||||||
|
![bg 80% hi](assets/helm-example/watermark.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Agenda
|
||||||
|
|
||||||
|
1. My background
|
||||||
|
2. Kubernetes
|
||||||
|
3. **Kubenix**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Kubenix ✨
|
||||||
|
|
||||||
|
- Generate manifests using NixOS modules!
|
||||||
|
- Benefits:
|
||||||
|
- No ugly YAML templates
|
||||||
|
- Functional language
|
||||||
|
- Type and structure checking
|
||||||
|
- Modularity
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# How Kubenix works
|
||||||
|
|
||||||
|
1. My background
|
||||||
|
2. Kubernetes
|
||||||
|
3. **Kubenix**
|
||||||
|
- **OpenAPI specification**
|
||||||
|
- Generate NixOS module
|
||||||
|
- Use generated module
|
||||||
|
- Generate manifest
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
# The OpenAPI spec
|
||||||
|
|
||||||
|
- Standard for describing APIs
|
||||||
|
- YAML or JSON
|
||||||
|
- Specifies how to interact with Kubernetes API
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# The OpenAPI spec
|
||||||
|
|
||||||
|
|
||||||
|
![bg 75% hi](assets/openapi-spec-example/base.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# The OpenAPI spec
|
||||||
|
|
||||||
|
![bg 75% hi](assets/openapi-spec-example/highlight1.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# The OpenAPI spec
|
||||||
|
|
||||||
|
![bg 75% hi](assets/openapi-spec-example/highlight2.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# How Kubenix works
|
||||||
|
|
||||||
|
1. My background
|
||||||
|
2. Kubernetes
|
||||||
|
3. **Kubenix**
|
||||||
|
- OpenAPI specification
|
||||||
|
- **Generate NixOS module**
|
||||||
|
- Use generated module
|
||||||
|
- Generate manifest
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Generating the NixOS module
|
||||||
|
|
||||||
|
- Generate Nix code
|
||||||
|
- Templating?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Generating the NixOS module
|
||||||
|
|
||||||
|
```nix
|
||||||
|
''
|
||||||
|
definitions = {
|
||||||
|
# Here we loop over each "definition"
|
||||||
|
${concatStrings (mapAttrsToList (name: value: ''
|
||||||
|
"${name}" = {
|
||||||
|
${optionalString (hasAttr "options" value) "
|
||||||
|
options = {${concatStrings (mapAttrsToList (name: value: ''
|
||||||
|
"${name}" = ${value};
|
||||||
|
'')
|
||||||
|
value.options)}};
|
||||||
|
"}
|
||||||
|
|
||||||
|
${optionalString (hasAttr "config" value) ''
|
||||||
|
config = {${concatStrings (mapAttrsToList (name: value: ''
|
||||||
|
"${name}" = ${value};
|
||||||
|
'')
|
||||||
|
value.config)}};
|
||||||
|
''}
|
||||||
|
};
|
||||||
|
'')
|
||||||
|
definitions)}
|
||||||
|
};
|
||||||
|
''
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# The generated NixOS module
|
||||||
|
|
||||||
|
```nix
|
||||||
|
"io.k8s.api.core.v1.Pod" = {
|
||||||
|
options = {
|
||||||
|
"apiVersion" = mkOption {
|
||||||
|
description = "...";
|
||||||
|
type = (types.nullOr types.str);
|
||||||
|
};
|
||||||
|
"kind" = mkOption {
|
||||||
|
description = "...";
|
||||||
|
type = (types.nullOr types.str);
|
||||||
|
};
|
||||||
|
"metadata" = mkOption {
|
||||||
|
description = "...";
|
||||||
|
type = (types.nullOr (submoduleOf "io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta"));
|
||||||
|
};
|
||||||
|
"spec" = mkOption {
|
||||||
|
description = "...";
|
||||||
|
type = (types.nullOr (submoduleOf "io.k8s.api.core.v1.PodSpec"));
|
||||||
|
};
|
||||||
|
"status" = mkOption {
|
||||||
|
description = "...";
|
||||||
|
type = (types.nullOr (submoduleOf "io.k8s.api.core.v1.PodStatus"));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# How Kubenix works
|
||||||
|
|
||||||
|
1. My background
|
||||||
|
2. Kubernetes
|
||||||
|
3. **Kubenix**
|
||||||
|
- OpenAPI specification
|
||||||
|
- Generate NixOS module
|
||||||
|
- **Use generated module**
|
||||||
|
- Generate manifest
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Using the module
|
||||||
|
|
||||||
|
![bg 70% hi](assets/kubenix-example/base.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Using the module
|
||||||
|
|
||||||
|
![bg 70% hi](assets/kubenix-example/highlight1.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Using the module
|
||||||
|
|
||||||
|
![bg 70% hi](assets/kubenix-example/highlight2.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Using the module
|
||||||
|
|
||||||
|
![bg 70% hi](assets/kubenix-example/highlight3.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Using the module
|
||||||
|
|
||||||
|
![bg 70% hi](assets/kubenix-example/highlight4.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Example of type checking
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
kubernetes.resources.pods.example-pod = {
|
||||||
|
spec.containers.jellyfin-container = {
|
||||||
|
image = "jellyfin/jellyfin:latest";
|
||||||
|
ports = [{ containerPort = "foo"; }];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
error: A definition for option `kubernetes.(...).containerPort' is not of type `signed integer'.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# An undefined option
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
kubernetes.resources = {
|
||||||
|
foo.bar = "baz";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
error: The option `kubernetes.api.resources.foo' does not exist.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# How Kubenix works
|
||||||
|
|
||||||
|
1. My background
|
||||||
|
2. Kubernetes
|
||||||
|
3. **Kubenix**
|
||||||
|
- OpenAPI specification
|
||||||
|
- Generate NixOS module
|
||||||
|
- Use generated module
|
||||||
|
- **Generate manifest**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# `kubenix.evalModules`
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
inputs.kubenix.url = "github:hall/kubenix";
|
||||||
|
outputs = {self, kubenix, ... }@inputs: let
|
||||||
|
system = "x86_64-linux";
|
||||||
|
in {
|
||||||
|
packages.${system}.default = (kubenix.evalModules.${system} {
|
||||||
|
module = { kubenix, ... }: {
|
||||||
|
imports = [ kubenix.modules.k8s ];
|
||||||
|
kubernetes.resources.pods.example.spec.containers.jellyfin.image = "jellyfin/jellyfin:latest";
|
||||||
|
};
|
||||||
|
}).config.kubernetes.result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# `kubenix.evalModules`
|
||||||
|
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Pod",
|
||||||
|
"metadata": {
|
||||||
|
"annotations": {
|
||||||
|
"kubenix/k8s-version": "1.30",
|
||||||
|
"kubenix/project-name": "kubenix"
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"kubenix/hash": "84130bb6a26b9066eb2bdcaf2e68148a6e0648b0"
|
||||||
|
},
|
||||||
|
"name": "example"
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"image": "jellyfin/jellyfin:latest",
|
||||||
|
"name": "jellyfin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"kind": "List",
|
||||||
|
"labels": {
|
||||||
|
"kubenix/hash": "84130bb6a26b9066eb2bdcaf2e68148a6e0648b0",
|
||||||
|
"kubenix/k8s-version": "1.30",
|
||||||
|
"kubenix/project-name": "kubenix"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
- Kubenix generates Kubernetes manifests
|
||||||
|
- Converts OpenAPI spec to a NixOS module
|
||||||
|
- Build Kubernetes deployments with:
|
||||||
|
- No ugly YAML templates
|
||||||
|
- Modularity
|
||||||
|
- In a functional language
|
||||||
|
- Type and structure checking
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Terraform: OpenAPI Provider Spec Generator
|
||||||
|
|
||||||
|
![hoi](assets/openapi-spec-gen.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Bonus: nix-snapshotter
|
||||||
|
|
||||||
|
![bg right:50% 100%](assets/nix-snapshotter.png)
|
||||||
|
|
||||||
|
- Images are in Nix store
|
||||||
|
- Fully declarative
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Bonus: NixNG
|
||||||
|
|
||||||
|
![bg right:50% 100%](assets/nixng.png)
|
||||||
|
|
||||||
|
- Nix~~OS~~ in a container
|
||||||
|
- init-system independent
|