BKE Bahriya Kubernetes Engine Start a 14-day trial

The first control-plane node

This is the node that creates the cluster. Everything else joins what it starts. What a control-plane node is, and why this one is called the first, is covered in How a cluster fits together. Every command on this page runs on this one machine, as root.

Run check.sh on it first, and register the licence, before you get here.

Two files must be in place on this node before you run the command below:

File Why this node needs it
/etc/bke/license mode 0600, from Register your cluster
/etc/bke/config.yaml auth.enabled in it decides how the cluster is created

install.sh --role master asks the API how to create this cluster before it changes anything on the machine, and it stops if it cannot. It is not reading config.yaml itself and it is not guessing — see Cluster login. A worker needs neither file: it joins a cluster whose shape was decided here.

The command

curl -sL https://bke.maml.uk/install.sh | sh -s -- \
  --role master \
  --version 2.0.0 \
  --hostname m1.prod.k8s.example.com \
  --endpoint prod.bke.example.com:6443 \
  --dns-domain cluster.local

--version is the BKE version, not a Kubernetes version. BKE names its own versions, and each one decides which Kubernetes minor, which Calico, which Helm and which container images it means. The release notes in the console list the published versions and what each one pins.

The three fixed arguments

Flag Format Fixed for the life of the cluster
--hostname bare host or FQDN yes — it is in the node’s certificates
--endpoint host:port, no scheme yes — it is in every kubeconfig, and on your licence
--dns-domain DNS suffix yes — every service name resolves under it

--endpoint takes a host and a port, not a URL. kubeadm wants prod.bke.example.com:6443, and https://prod.bke.example.com:6443 will not work.

Point the endpoint at whatever will still be correct when you have three control-plane nodes — a load balancer, a floating address, a DNS record you control. Pointing it at this machine’s own name works today and becomes the thing you cannot change when you add the second one. Reference architecture gives the load balancer configuration this address points at in production.

What the script does

In order:

  1. Asks the API how this cluster should be created, before anything on the machine changes. A node that cannot reach the API stops here, with nothing installed and nothing reconfigured.
  2. Sets the hostname.
  3. Installs base packages — curl, jq, git, etcd-client, open-iscsi, wireguard, and others.
  4. Enables the kernel modules the cluster needs at boot, including dm_crypt for encrypted Longhorn volumes.
  5. Adds the Kubernetes and Docker apt repositories and installs kubelet, kubeadm, kubectl and containerd at the versions BKE 2.0.0 pins.
  6. Installs k9s.
  7. Configures UFW, disables swap and sets the kernel networking parameters. It opens the SSH port your sshd_config already names, and does not change that file.
  8. Runs kubeadm init with your three arguments, --pod-network-cidr 192.168.0.0/16 and --upload-certs — or, when auth.enabled is true, with a configuration file carrying the same settings plus your identity provider. Same cluster either way; the file exists because kubeadm has no way to pass an API-server flag on the command line.
  9. Writes the admin kubeconfig.
  10. Installs Calico via the Tigera operator, waits for it, and enables WireGuard encryption for pod traffic.
  11. Records the BKE version at /etc/bke/version.

If you have not read the SSH warning on Before you begin, read it before step 6 happens to you.

Afterwards

kubectl get nodes
kubectl get pods -A

The node will be Ready once Calico is up. calicoctl node status reports the BGP peerings; with a single node there is nothing to peer with yet, and that is expected.

k9s is also installed — a terminal interface over the same API kubectl talks to, useful for watching pods start and reading logs without composing commands. Run k9s as root and it works immediately: provisioning copied the administrator kubeconfig to ~/.kube/config, which is the file both kubectl and k9s read. On nodes added later that copy is yours to make — Adding nodes carries the command.

/etc/bke/version now records the BKE version this node is on. It is a record of what happened, not a setting — nothing reads it back to decide anything.

What is not installed yet

No components. metrics-server, cert-manager, Longhorn, Kong, Kuma, Fluent Bit and netdata are installed separately, once, for the whole cluster, after the workers have joined. That is apply.sh, and it needs a config.yaml. It shows you what it would install before it installs anything.

No authentication. The cluster is reachable with the kubeadm administrator kubeconfig and nothing else. Cluster login is a separate, deliberate step.