Last active
October 9, 2025 15:41
-
-
Save Lillecarl/6306d6ec53a2274d36a462d646510bcc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| pkgs ? import <nixpkgs> { }, | |
| }: | |
| let | |
| manifest = pkgs.writeTextFile { | |
| name = "test-manifest.yaml"; | |
| text = '' | |
| apiVersion: v1 | |
| kind: ConfigMap | |
| metadata: | |
| name: test-config | |
| namespace: default | |
| data: | |
| key: | | |
| this | |
| is a multiline | |
| string | |
| ''; | |
| }; | |
| in | |
| pkgs.stdenvNoCC.mkDerivation { | |
| name = "validate-k8s-manifest"; | |
| src = manifest; | |
| nativeBuildInputs = [ | |
| pkgs.etcd | |
| pkgs.kubernetes | |
| pkgs.iproute2 | |
| ]; | |
| # kube-apiserver can only listen to TCP ports :( | |
| __noChroot = true; | |
| unpackPhase = ":"; | |
| # We only need the check phase to run the validation logic | |
| doCheck = true; | |
| configurePhase = '' | |
| set -euo pipefail | |
| export TMPDIR=$PWD | |
| CERT_DIR=$TMPDIR/pki | |
| mkdir --parents $CERT_DIR | |
| export KUBECONFIG=$TMPDIR/admin.conf | |
| get_free_port() { | |
| local low high range_size port | |
| read low high < /proc/sys/net/ipv4/ip_local_port_range | |
| range_size=$((high - low + 1)) | |
| while true; do | |
| port=$((low + RANDOM % range_size)) | |
| if ! ss -lnt | grep -q ":$port\s"; then | |
| echo "$port" | |
| return | |
| fi | |
| done | |
| } | |
| BIND_ADDRESS=127.0.0.1 | |
| KUBERNETES_PORT=$(get_free_port) | |
| ETCD_CLIENT_PORT=$(get_free_port) | |
| ETCD_PEER_PORT=$(get_free_port) | |
| cat <<EOF > $TMPDIR/kubeadm-config.yaml | |
| apiVersion: kubeadm.k8s.io/v1beta4 | |
| kind: ClusterConfiguration | |
| kubernetesVersion: v${pkgs.kubernetes.version} | |
| controlPlaneEndpoint: "$BIND_ADDRESS:$KUBERNETES_PORT" | |
| certificatesDir: "$CERT_DIR" | |
| EOF | |
| kubeadm init phase certs all --config=$TMPDIR/kubeadm-config.yaml | |
| kubeadm init phase kubeconfig admin --config=$TMPDIR/kubeadm-config.yaml --kubeconfig-dir=$TMPDIR | |
| cleanup() { | |
| kill -9 "$ETCD_PID" 2>/dev/null || true | |
| kill -9 "$APISERVER_PID" 2>/dev/null || true | |
| } | |
| trap cleanup EXIT | |
| etcd --data-dir=$TMPDIR/etcd-data \ | |
| --name=default \ | |
| --listen-client-urls="https://127.0.0.1:$ETCD_CLIENT_PORT" \ | |
| --advertise-client-urls="https://127.0.0.1:$ETCD_CLIENT_PORT" \ | |
| --listen-peer-urls="https://127.0.0.1:$ETCD_PEER_PORT" \ | |
| --initial-advertise-peer-urls="https://127.0.0.1:$ETCD_PEER_PORT" \ | |
| --initial-cluster="default=https://127.0.0.1:$ETCD_PEER_PORT" \ | |
| --client-cert-auth=true \ | |
| --trusted-ca-file="$CERT_DIR/etcd/ca.crt" \ | |
| --cert-file="$CERT_DIR/etcd/server.crt" \ | |
| --key-file="$CERT_DIR/etcd/server.key" \ | |
| --peer-client-cert-auth=true \ | |
| --peer-trusted-ca-file="$CERT_DIR/etcd/ca.crt" \ | |
| --peer-cert-file="$CERT_DIR/etcd/peer.crt" \ | |
| --peer-key-file="$CERT_DIR/etcd/peer.key" \ | |
| --log-level=error & | |
| ETCD_PID=$! | |
| until etcdctl --endpoints="https://127.0.0.1:$ETCD_CLIENT_PORT" \ | |
| --cacert="$CERT_DIR/etcd/ca.crt" \ | |
| --cert="$CERT_DIR/etcd/healthcheck-client.crt" \ | |
| --key="$CERT_DIR/etcd/healthcheck-client.key" \ | |
| endpoint health 2>/dev/null; do | |
| echo "Waiting for etcd to start" | |
| sleep 0.5 | |
| done | |
| echo "etcd is ready" | |
| kube-apiserver \ | |
| --etcd-cafile="$CERT_DIR/etcd/ca.crt" \ | |
| --etcd-certfile="$CERT_DIR/apiserver-etcd-client.crt" \ | |
| --etcd-keyfile="$CERT_DIR/apiserver-etcd-client.key" \ | |
| --etcd-servers="https://127.0.0.1:$ETCD_CLIENT_PORT" \ | |
| --service-cluster-ip-range=10.96.0.0/12 \ | |
| --bind-address=$BIND_ADDRESS \ | |
| --secure-port=$KUBERNETES_PORT \ | |
| --authorization-mode=AlwaysAllow \ | |
| --allow-privileged=true \ | |
| --client-ca-file=$CERT_DIR/ca.crt \ | |
| --kubelet-client-certificate=$CERT_DIR/apiserver-kubelet-client.crt \ | |
| --kubelet-client-key=$CERT_DIR/apiserver-kubelet-client.key \ | |
| --service-account-issuer=https://kubernetes.default.svc.cluster.local \ | |
| --service-account-key-file=$CERT_DIR/sa.pub \ | |
| --service-account-signing-key-file=$CERT_DIR/sa.key \ | |
| --tls-cert-file=$CERT_DIR/apiserver.crt \ | |
| --tls-private-key-file=$CERT_DIR/apiserver.key & | |
| APISERVER_PID=$! | |
| until kubectl get --raw /healthz >/dev/null 2>&1; do | |
| echo "Waiting for kube-apiserver to start" | |
| sleep 0.5 | |
| done | |
| echo "kube-apiserver ready" | |
| ''; | |
| checkPhase = '' | |
| # The src (our manifest file) is available in the current directory | |
| kubectl apply --server-side=true -f $src | |
| ''; | |
| installPhase = '' | |
| mkdir $out | |
| export KUBECTL_KYAML=true | |
| # Dump manifest YAML | |
| kubectl apply --server-side=true --dry-run=server --output=yaml -f $src > $out/manifests.yaml | |
| # Dump manifest YAML | |
| kubectl apply --server-side=true --dry-run=server --output=kyaml -f $src > $out/manifests.kyaml | |
| # Dump manifest JSON | |
| kubectl apply --server-side=true --dry-run=server --output=json -f $src > $out/manifests.json | |
| ''; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment