Skip to content

Instantly share code, notes, and snippets.

@Lillecarl
Last active October 9, 2025 15:41
Show Gist options
  • Select an option

  • Save Lillecarl/6306d6ec53a2274d36a462d646510bcc to your computer and use it in GitHub Desktop.

Select an option

Save Lillecarl/6306d6ec53a2274d36a462d646510bcc to your computer and use it in GitHub Desktop.
{
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