There is currently an issue with creating single control plane clusters in DKP 2.2. If you attempt to set a single control plane, you will get an error such as:
could not create obj dkp22-control-plane: admission webhook "validation.kubeadmcontrolplane.controlplane.cluster.x-k8s.io" denied the request: KubeadmControlPlane.controlplane.cluster.x-k8s.io "dkp22-control-plane" is invalid: spec.rolloutStrategy.rollingUpdate: Required value: when KubeadmControlPlane is configured to scale-in, replica count needs to be at least 3
unable to create kubernetes resource: admission webhook "validation.kubeadmcontrolplane.controlplane.cluster.x-k8s.io" denied the request: KubeadmControlPlane.controlplane.cluster.x-k8s.io "dkp22-control-plane" is invalid: spec.rolloutStrategy.rollingUpdate: Required value: when KubeadmControlPlane is configured to scale-in, replica count needs to be at least 3
In order to work around this issue, you must instead create your cluster with 3 control planes (the default) and use the --dry-run -o yaml function to pipe the result of this to a file instead of immediately creating the cluster. An example of how you would do this is below:
1. Create your environment variables as normal
export CLUSTER_NAME=single-cp-demo
export CONTROL_PLANE_1_ADDRESS="10.0.1.41"
export WORKER_1_ADDRESS="10.0.1.44"
export WORKER_2_ADDRESS="10.0.1.45"
export WORKER_3_ADDRESS="10.0.1.46"
export WORKER_4_ADDRESS="10.0.1.47"
export SSH_USER="sshUser"
export SSH_PRIVATE_KEY_FILE="id_rsa"
export SSH_PRIVATE_KEY_SECRET_NAME=$CLUSTER_NAME-ssh-key
2. Create the inventory for a single control plane cluster
cat <<EOF > inventory.yaml
all:
vars:
ansible_user: $SSH_USER
ansible_port: 22
ansible_ssh_private_key_file: $SSH_PRIVATE_KEY_FILE
hosts:
$CONTROL_PLANE_1_ADDRESS:
ansible_host: $CONTROL_PLANE_1_ADDRESS
$WORKER_1_ADDRESS:
ansible_host: $WORKER_1_ADDRESS
$WORKER_2_ADDRESS:
ansible_host: $WORKER_2_ADDRESS
$WORKER_3_ADDRESS:
ansible_host: $WORKER_3_ADDRESS
$WORKER_4_ADDRESS:
ansible_host: $WORKER_4_ADDRESS
EOF
3. Create the bootstrap cluster
./dkp create bootstrap
4. Create your SSH and override secrets as normal
kubectl create secret generic ${SSH_PRIVATE_KEY_SECRET_NAME} --from-file=ssh-privatekey=${SSH_PRIVATE_KEY_FILE}
kubectl label secret ${SSH_PRIVATE_KEY_SECRET_NAME} clusterctl.cluster.x-k8s.io/move=
cat <<EOF > overrides.yaml
image_registries_with_auth:
- host: "registry-1.docker.io"
username: "user"
password: "pass"
auth: ""
identityToken: ""
EOF
kubectl create secret generic $CLUSTER_NAME-user-overrides --from-file=overrides.yaml=overrides.yaml
kubectl label secret $CLUSTER_NAME-user-overrides clusterctl.cluster.x-k8s.io/move=
4. Create your preprovisioned inventory for a single control plane
cat <<EOF > preprovisioned_inventory.yaml
---
apiVersion: infrastructure.cluster.konvoy.d2iq.io/v1alpha1
kind: PreprovisionedInventory
metadata:
name: $CLUSTER_NAME-control-plane
namespace: default
labels:
cluster.x-k8s.io/cluster-name: $CLUSTER_NAME
clusterctl.cluster.x-k8s.io/move: ""
spec:
hosts:
# Create as many of these as needed to match your infrastructure
# Note that the command line parameter --control-plane-replicas determines how many control plane nodes will actually be used.
#
- address: $CONTROL_PLANE_1_ADDRESS
sshConfig:
port: 22
# This is the username used to connect to your infrastructure. This user must be root or
# have the ability to use sudo without a password
user: $SSH_USER
privateKeyRef:
# This is the name of the secret you created in the previous step. It must exist in the same
# namespace as this inventory object.
name: $SSH_PRIVATE_KEY_SECRET_NAME
namespace: default
---
apiVersion: infrastructure.cluster.konvoy.d2iq.io/v1alpha1
kind: PreprovisionedInventory
metadata:
name: $CLUSTER_NAME-md-0
namespace: default
labels:
cluster.x-k8s.io/cluster-name: $CLUSTER_NAME
clusterctl.cluster.x-k8s.io/move: ""
spec:
hosts:
- address: $WORKER_1_ADDRESS
- address: $WORKER_2_ADDRESS
- address: $WORKER_3_ADDRESS
- address: $WORKER_4_ADDRESS
sshConfig:
port: 22
user: $SSH_USER
privateKeyRef:
name: $SSH_PRIVATE_KEY_SECRET_NAME
namespace: default
EOF
5. Apply your preprovisioned_inventory.yaml
envsubst < preprovisioned_inventory.yaml | kubectl apply -f -
6. Create a cluster.yaml file with 3 control plane replicas
./dkp create cluster preprovisioned --cluster-name ${CLUSTER_NAME} \
--control-plane-endpoint-host 10.0.1.40 \
--virtual-ip-interface ens192 \
--dry-run -o yaml > cluster.yaml
7. Locate the kind: KubeadmControlPlane object in cluster.yaml
There should be only one and it should have the name of your cluster. At the bottom of the file you will see the following information.
replicas: 3
rolloutStrategy:
rollingUpdate:
maxSurge: 0
type: RollingUpdate
version: v1.22.8
Change it to this:
replicas: 1
version: v1.22.8
We have now removed the rolloutStrategy that would prevent a single control plane cluster from standing up properly, and we have set the replicas to 1 so that cluster-api does not try to provision 2 additional control planes.
7. Apply cluster.yaml to the bootstrap to create the cluster
kubectl create -f cluster.yaml