After reading how to install Kubernetes on bare metal I was dismayed to find out that after provisioning all nodes, I would have to SSH into each to install Kubernetes to bootstrap the cluster. Clearly an orchestration framework is required to install an orchestration framework. However, there is an easier way.

CoreOS allows systemd unit files to be installed (and enabled) during the provisioning process. Here is a oneshot service that will run at boot to install Kubernetes.

[Service]
Type=oneshot

Environment=CNI_VERSION=v0.7.0
Environment=K8S_VERSION=v1.10.0

ExecStartPre=/usr/bin/mkdir -p /opt/bin
ExecStartPre=/usr/bin/mkdir -p /opt/cni/bin
ExecStartPre=/usr/bin/mkdir -p /etc/systemd/system/kubelet.service.d

ExecStart=/usr/bin/bash -c "/usr/bin/curl -L https://github.com/containernetworking/plugins/releases/download/${CNI_VERSION}/cni-plugins-amd64-${CNI_VERSION}.tgz | tar -C /opt/cni/bin -xz"
ExecStart=/usr/bin/bash -c "cd /opt/bin && /usr/bin/curl -L --remote-name-all https://storage.googleapis.com/kubernetes-release/release/${K8S_VERSION}/bin/linux/amd64/{kubeadm,kubelet,kubectl}"
ExecStart=/usr/bin/bash -c "/usr/bin/curl -sSL https://raw.githubusercontent.com/kubernetes/kubernetes/${K8S_VERSION}/build/debs/kubelet.service | sed 's:/usr/bin:/opt/bin:g' > /etc/systemd/system/kubelet.service"
ExecStart=/usr/bin/bash -c "/usr/bin/curl -sSL https://raw.githubusercontent.com/kubernetes/kubernetes/${K8S_VERSION}/build/debs/10-kubeadm.conf | sed 's:/usr/bin:/opt/bin:g' > /etc/systemd/system/kubelet.service.d/10-kubeadm.conf"

ExecStartPost=/usr/bin/bash -c "/usr/bin/chmod 755 /opt/bin/{kubeadm,kubelet,kubectl}"
ExecStartPost=/usr/bin/systemctl enable docker  && /usr/bin/systemctl start docker
ExecStartPost=/usr/bin/systemctl daemon-reload
ExecStartPost=/usr/bin/systemctl enable kubelet && /usr/bin/systemctl start kubelet

[Install]
WantedBy=multi-user.target