Skip to content

Commit cfdc9cd

Browse files
authored
Merge pull request #7444 from nunnatsa/book-kubevirt
📖 Add the quickstart details for KubeVirt
2 parents 3ab9a01 + c1fe228 commit cfdc9cd

File tree

1 file changed

+253
-14
lines changed

1 file changed

+253
-14
lines changed

docs/book/src/user/quick-start.md

Lines changed: 253 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ a target [management cluster] on the selected [infrastructure provider].
6161
The installation procedure depends on the version of kind; if you are planning to use the Docker infrastructure provider,
6262
please follow the additional instructions in the dedicated tab:
6363

64-
{{#tabs name:"install-kind" tabs:"Default,Docker"}}
64+
{{#tabs name:"install-kind" tabs:"Default,Docker,KubeVirt"}}
6565
{{#tab Default}}
6666

6767
Create the kind cluster:
@@ -93,6 +93,57 @@ a target [management cluster] on the selected [infrastructure provider].
9393
Then follow the instruction for your kind version using `kind create cluster --config kind-cluster-with-extramounts.yaml`
9494
to create the management cluster using the above file.
9595
96+
{{#/tab }}
97+
{{#tab KubeVirt}}
98+
99+
#### Create the Kind Cluster
100+
[KubeVirt][KubeVirt] is a cloud native virtualization solution. The virtual machines we're going to create and use for
101+
the workload cluster's nodes, are actually running within pods in the management cluster. In order to communicate with
102+
the workload cluster's API server, we'll need to expose it. We are using Kind which is a limited environment. The
103+
easiest way to expose the workload cluster's API server (a pod within a node running in a VM that is itself running
104+
within a pod in the management cluster, that is running inside a docker container), is to use a LoadBalancer service.
105+
106+
To allow using a LoadBalancer service, we can't use the kind's default CNI (kindnet), but we'll need to install
107+
another CNI, like Calico. In order to do that, we'll need first to initiate the kind cluster with two modifications:
108+
1. Disable the default CNI
109+
2. Add the docker credentials to the cluster, to avoid the docker hub pull rate limit of the calico images; read more
110+
about it in the [docker documentation](https://docs.docker.com/docker-hub/download-rate-limit/), and in the
111+
[kind documentation](https://kind.sigs.k8s.io/docs/user/private-registries/#mount-a-config-file-to-each-node).
112+
113+
Create a configuration file for kind. Please notice the docker config file path, and adjust it to your local setting:
114+
```bash
115+
cat <<EOF > kind-config.yaml
116+
kind: Cluster
117+
apiVersion: kind.x-k8s.io/v1alpha4
118+
networking:
119+
# the default CNI will not be installed
120+
disableDefaultCNI: true
121+
nodes:
122+
- role: control-plane
123+
extraMounts:
124+
- containerPath: /var/lib/kubelet/config.json
125+
hostPath: <YOUR DOCKER CONFIG FILE PATH>
126+
EOF
127+
```
128+
Now, create the kind cluster with the configuration file:
129+
```bash
130+
kind create cluster --config=kind-config.yaml
131+
```
132+
Test to ensure the local kind cluster is ready:
133+
```bash
134+
kubectl cluster-info
135+
```
136+
137+
#### Install the Calico CNI
138+
Now we'll need to install a CNI. In this example, we're using calico, but other CNIs should work as well. Please see
139+
[calico installation guide](https://projectcalico.docs.tigera.io/getting-started/kubernetes/self-managed-onprem/onpremises#install-calico)
140+
for more details (use the "Manifest" tab). Below is an example of how to install calico version v3.24.4.
141+
142+
Use the Calico manifest to create the required resources; e.g.:
143+
```bash
144+
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.24.4/manifests/calico.yaml
145+
```
146+
96147
{{#/tab }}
97148
{{#/tabs }}
98149
@@ -202,7 +253,7 @@ Additional documentation about experimental features can be found in [Experiment
202253
Depending on the infrastructure provider you are planning to use, some additional prerequisites should be satisfied
203254
before getting started with Cluster API. See below for the expected settings for common providers.
204255
205-
{{#tabs name:"tab-installation-infrastructure" tabs:"AWS,Azure,CloudStack,DigitalOcean,Docker,Equinix Metal,GCP,Hetzner,IBM Cloud,KubeKey,Kubevirt,Metal3,Nutanix,OCI,OpenStack,Outscale,VCD,vcluster,Virtink,vSphere"}}
256+
{{#tabs name:"tab-installation-infrastructure" tabs:"AWS,Azure,CloudStack,DigitalOcean,Docker,Equinix Metal,GCP,Hetzner,IBM Cloud,KubeKey,KubeVirt,Metal3,Nutanix,OCI,OpenStack,Outscale,VCD,vcluster,Virtink,vSphere"}}
206257
{{#tab AWS}}
207258
208259
Download the latest binary of `clusterawsadm` from the [AWS provider releases].
@@ -442,9 +493,61 @@ clusterctl init --infrastructure kubekey
442493
```
443494
444495
{{#/tab }}
445-
{{#tab Kubevirt}}
496+
{{#tab KubeVirt}}
497+
498+
Please visit the [KubeVirt project][KubeVirt provider] for more information.
446499
447-
Please visit the [Kubevirt project][Kubevirt provider].
500+
As described above, we want to use a LoadBalancer service in order to expose the workload cluster's API server. In the
501+
example below, we will use [MetalLB](https://metallb.universe.tf/) solution to implement load balancing to our kind
502+
cluster. Other solution should work as well.
503+
504+
#### Install MetalLB for load balancing
505+
Install MetalLB, as described [here](https://metallb.universe.tf/installation/#installation-by-manifest); for example:
506+
```bash
507+
METALLB_VER=$(curl "https://api.github.com/repos/metallb/metallb/releases/latest" | jq -r ".tag_name")
508+
kubectl apply -f "https://raw.githubusercontent.com/metallb/metallb/${METALLB_VER}/config/manifests/metallb-native.yaml"
509+
kubectl wait pods -n metallb-system -l app=metallb,component=controller --for=condition=Ready --timeout=10m
510+
kubectl wait pods -n metallb-system -l app=metallb,component=speaker --for=condition=Ready --timeout=2m
511+
```
512+
513+
Now, we'll create the `IPAddressPool` and the `L2Advertisement` custom resources. The script below creates the CRs with
514+
the right addresses, that match to the kind cluster addresses:
515+
```bash
516+
GW_IP=$(docker network inspect -f '{{range .IPAM.Config}}{{.Gateway}}{{end}}' kind)
517+
NET_IP=$(echo ${GW_IP} | sed -E 's|^([0-9]+\.[0-9]+)\..*$|\1|g')
518+
cat <<EOF | sed -E "s|172.19|${NET_IP}|g" | kubectl apply -f -
519+
apiVersion: metallb.io/v1beta1
520+
kind: IPAddressPool
521+
metadata:
522+
name: capi-ip-pool
523+
namespace: metallb-system
524+
spec:
525+
addresses:
526+
- 172.19.255.200-172.19.255.250
527+
---
528+
apiVersion: metallb.io/v1beta1
529+
kind: L2Advertisement
530+
metadata:
531+
name: empty
532+
namespace: metallb-system
533+
EOF
534+
```
535+
536+
#### Install KubeVirt on the kind cluster
537+
```bash
538+
# get KubeVirt version
539+
KV_VER=$(curl "https://api.github.com/repos/kubevirt/kubevirt/releases/latest" | jq -r ".tag_name")
540+
# deploy required CRDs
541+
kubectl apply -f "https://github.com/kubevirt/kubevirt/releases/download/${KV_VER}/kubevirt-operator.yaml"
542+
# deploy the KubeVirt custom resource
543+
kubectl apply -f "https://github.com/kubevirt/kubevirt/releases/download/${KV_VER}/kubevirt-cr.yaml"
544+
kubectl wait -n kubevirt kv kubevirt --for=condition=Available --timeout=10m
545+
```
546+
547+
#### Initialize the management cluster with the KubeVirt Provider
548+
```bash
549+
clusterctl init --infrastructure kubevirt
550+
```
448551
449552
{{#/tab }}
450553
{{#tab Metal3}}
@@ -601,7 +704,7 @@ before configuring a cluster with Cluster API. Instructions are provided for com
601704
Otherwise, you can look at the `clusterctl generate cluster` [command][clusterctl generate cluster] documentation for details about how to
602705
discover the list of variables required by a cluster templates.
603706
604-
{{#tabs name:"tab-configuration-infrastructure" tabs:"AWS,Azure,CloudStack,DigitalOcean,Docker,Equinix Metal,GCP,IBM Cloud,KubeKey,Kubevirt,Metal3,Nutanix,OpenStack,Outscale,VCD,vcluster,Virtink,vSphere"}}
707+
{{#tabs name:"tab-configuration-infrastructure" tabs:"AWS,Azure,CloudStack,DigitalOcean,Docker,Equinix Metal,GCP,IBM Cloud,KubeKey,KubeVirt,Metal3,Nutanix,OpenStack,Outscale,VCD,vcluster,Virtink,vSphere"}}
605708
{{#tab AWS}}
606709
607710
```bash
@@ -820,15 +923,14 @@ export CONTROL_PLANE_ENDPOINT_IP=<your-control-plane-virtual-ip>
820923
Please visit the [KubeKey provider] for more information.
821924
822925
{{#/tab }}
823-
{{#tab Kubevirt}}
824-
825-
A ClusterAPI compatible image must be available in your Kubevirt image library. For instructions on how to build a compatible image
826-
see [image-builder](https://image-builder.sigs.k8s.io/capi/capi.html).
926+
{{#tab KubeVirt}}
827927
828-
To see all required Kubevirt environment variables execute:
829928
```bash
830-
clusterctl generate cluster --infrastructure kubevirt --list-variables capi-quickstart
929+
export CAPK_GUEST_K8S_VERSION="v1.23.10"
930+
export CRI_PATH="/var/run/containerd/containerd.sock"
931+
export NODE_VM_IMAGE_TEMPLATE="quay.io/capk/ubuntu-2004-container-disk:${CAPK_GUEST_K8S_VERSION}"
831932
```
933+
Please visit the [KubeVirt project][KubeVirt provider] for more information.
832934
833935
{{#/tab }}
834936
{{#tab Metal3}}
@@ -1007,7 +1109,7 @@ For more information about prerequisites, credentials management, or permissions
10071109
10081110
For the purpose of this tutorial, we'll name our cluster capi-quickstart.
10091111
1010-
{{#tabs name:"tab-clusterctl-config-cluster" tabs:"Docker, vcluster, others..."}}
1112+
{{#tabs name:"tab-clusterctl-config-cluster" tabs:"Docker, vcluster, KubeVirt, others..."}}
10111113
{{#tab Docker}}
10121114
10131115
<aside class="note warning">
@@ -1042,6 +1144,22 @@ clusterctl generate cluster ${CLUSTER_NAME} \
10421144
--target-namespace ${CLUSTER_NAMESPACE} | kubectl apply -f -
10431145
```
10441146
1147+
{{#/tab }}
1148+
{{#tab KubeVirt}}
1149+
1150+
As we described above, in this tutorial, we will use a LoadBalancer service in order to expose the API server of the
1151+
workload cluster, so we want to use the load balancer (lb) template (rather than the default one). We'll use the
1152+
clusterctl's `--flavor` flag for that:
1153+
```bash
1154+
clusterctl generate cluster capi-quickstart \
1155+
--infrastructure="kubevirt" \
1156+
--flavor lb \
1157+
--kubernetes-version ${CAPK_GUEST_K8S_VERSION} \
1158+
--control-plane-machine-count=1 \
1159+
--worker-machine-count=1 \
1160+
> capi-quickstart.yaml
1161+
```
1162+
10451163
{{#/tab }}
10461164
{{#tab others...}}
10471165
@@ -1151,7 +1269,7 @@ Note: To use the default clusterctl method to retrieve kubeconfig for a workload
11511269
11521270
Calico is used here as an example.
11531271
1154-
{{#tabs name:"tab-deploy-cni" tabs:"Azure,vcluster,others..."}}
1272+
{{#tabs name:"tab-deploy-cni" tabs:"Azure,vcluster,KubeVirt,others..."}}
11551273
{{#tab Azure}}
11561274
11571275
Azure [does not currently support Calico networking](https://docs.projectcalico.org/reference/public-cloud/azure). As a workaround, it is recommended that Azure clusters use the Calico spec below that uses VXLAN.
@@ -1173,6 +1291,126 @@ kubectl --kubeconfig=./capi-quickstart.kubeconfig get nodes
11731291
11741292
Calico not required for vcluster.
11751293
1294+
{{#/tab }}
1295+
{{#tab KubeVirt}}
1296+
1297+
Before deploying the Calico CNI, make sure the VMs are running:
1298+
```bash
1299+
kubectl get vm
1300+
```
1301+
1302+
If our new VMs are running, we should see a response similar to this:
1303+
1304+
```text
1305+
NAME AGE STATUS READY
1306+
capi-quickstart-control-plane-7s945 167m Running True
1307+
capi-quickstart-md-0-zht5j 164m Running True
1308+
```
1309+
1310+
We can also read the virtual machine instances:
1311+
```bash
1312+
kubectl get vmi
1313+
```
1314+
The output will be similar to:
1315+
```text
1316+
NAME AGE PHASE IP NODENAME READY
1317+
capi-quickstart-control-plane-7s945 167m Running 10.244.82.16 kind-control-plane True
1318+
capi-quickstart-md-0-zht5j 164m Running 10.244.82.17 kind-control-plane True
1319+
```
1320+
1321+
Since our workload cluster is running within the kind cluster, we need to prevent conflicts between the kind
1322+
(management) cluster's CNI, and the workload cluster CNI. The following modifications in the default Calico settings
1323+
are enough for these two CNI to work on (actually) the same environment.
1324+
1325+
* Change the CIDR to a non-conflicting range
1326+
* Change the value of the `CLUSTER_TYPE` environment variable to `k8s`
1327+
* Change the value of the `CALICO_IPV4POOL_IPIP` environment variable to `Never`
1328+
* Change the value of the `CALICO_IPV4POOL_VXLAN` environment variable to `Always`
1329+
* Add the `FELIX_VXLANPORT` environment variable with the value of a non-conflicting port, e.g. `"6789"`.
1330+
1331+
The following script downloads the Calico manifest and modifies the required field. The CIDR and the port values are examples.
1332+
```bash
1333+
curl https://raw.githubusercontent.com/projectcalico/calico/v3.24.4/manifests/calico.yaml -o calico-workload.yaml
1334+
1335+
sed -i -E 's|^( +)# (- name: CALICO_IPV4POOL_CIDR)$|\1\2|g;'\
1336+
's|^( +)# ( value: )"192.168.0.0/16"|\1\2"10.243.0.0/16"|g;'\
1337+
'/- name: CLUSTER_TYPE/{ n; s/( +value: ").+/\1k8s"/g };'\
1338+
'/- name: CALICO_IPV4POOL_IPIP/{ n; s/value: "Always"/value: "Never"/ };'\
1339+
'/- name: CALICO_IPV4POOL_VXLAN/{ n; s/value: "Never"/value: "Always"/};'\
1340+
'/# Set Felix endpoint to host default action to ACCEPT./a\ - name: FELIX_VXLANPORT\n value: "6789"' \
1341+
calico-workload.yaml
1342+
```
1343+
Now, deploy the Calico CNI on the workload cluster:
1344+
```bash
1345+
kubectl --kubeconfig=./capi-quickstart.kubeconfig create -f calico-workload.yaml
1346+
```
1347+
1348+
After a short while, our nodes should be running and in `Ready` state, let’s check the status using `kubectl get nodes`:
1349+
1350+
```bash
1351+
kubectl --kubeconfig=./capi-quickstart.kubeconfig get nodes
1352+
```
1353+
1354+
<aside class="note">
1355+
1356+
<h1>Troubleshooting</h1>
1357+
1358+
If the nodes don't become ready after a long period, read the pods in the `kube-system` namespace
1359+
```bash
1360+
kubectl --kubeconfig=./capi-quickstart.kubeconfig get pod -n kube-system
1361+
```
1362+
1363+
If the Calico pods are in image pull error state (`ErrImagePull`), it's probably because of the docker hub pull rate limit.
1364+
We can try to fix that by adding a secret with our docker hub credentials, and use it;
1365+
see [here](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/#registry-secret-existing-credentials)
1366+
for details.
1367+
1368+
First, create the secret. Please notice the docker config file path, and adjust it to your local setting.
1369+
```bash
1370+
kubectl --kubeconfig=./capi-quickstart.kubeconfig create secret generic docker-creds \
1371+
--from-file=.dockerconfigjson=<YOUR DOCKER CONFIG FILE PATH> \
1372+
--type=kubernetes.io/dockerconfigjson \
1373+
-n kube-system
1374+
```
1375+
1376+
Now, if the `calico-node` pods are with status of `ErrImagePull`, patch their DaemonSet to make them use the new secret to pull images:
1377+
```bash
1378+
kubectl --kubeconfig=./capi-quickstart.kubeconfig patch daemonset \
1379+
-n kube-system calico-node \
1380+
-p '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"docker-creds"}]}}}}'
1381+
```
1382+
1383+
After a short while, the calico-node pods will be with `Running` status. Now, if the calico-kube-controllers pod is also
1384+
in `ErrImagePull` status, patch its deployment to fix the problem:
1385+
```bash
1386+
kubectl --kubeconfig=./capi-quickstart.kubeconfig patch deployment \
1387+
-n kube-system calico-kube-controllers \
1388+
-p '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"docker-creds"}]}}}}'
1389+
```
1390+
1391+
Read the pods again
1392+
```bash
1393+
kubectl --kubeconfig=./capi-quickstart.kubeconfig get pod -n kube-system
1394+
```
1395+
1396+
Eventually, all the pods in the kube-system namespace will run, and the result should be similar to this:
1397+
```text
1398+
NAME READY STATUS RESTARTS AGE
1399+
calico-kube-controllers-c969cf844-dgld6 1/1 Running 0 50s
1400+
calico-node-7zz7c 1/1 Running 0 54s
1401+
calico-node-jmjd6 1/1 Running 0 54s
1402+
coredns-64897985d-dspjm 1/1 Running 0 3m49s
1403+
coredns-64897985d-pgtgz 1/1 Running 0 3m49s
1404+
etcd-capi-quickstart-control-plane-kjjbb 1/1 Running 0 3m57s
1405+
kube-apiserver-capi-quickstart-control-plane-kjjbb 1/1 Running 0 3m57s
1406+
kube-controller-manager-capi-quickstart-control-plane-kjjbb 1/1 Running 0 3m57s
1407+
kube-proxy-b9g5m 1/1 Running 0 3m12s
1408+
kube-proxy-p6xx8 1/1 Running 0 3m49s
1409+
kube-scheduler-capi-quickstart-control-plane-kjjbb 1/1 Running 0 3m57s
1410+
```
1411+
1412+
</aside>
1413+
11761414
{{#/tab }}
11771415
{{#tab others...}}
11781416
@@ -1244,7 +1482,8 @@ See the [clusterctl] documentation for more detail about clusterctl supported ac
12441482
[Metal3 getting started guide]: https://github.com/metal3-io/cluster-api-provider-metal3/blob/master/docs/getting-started.md
12451483
[Metal3 provider]: https://github.com/metal3-io/cluster-api-provider-metal3/
12461484
[KubeKey provider]: https://github.com/kubesphere/kubekey
1247-
[Kubevirt provider]: https://github.com/kubernetes-sigs/cluster-api-provider-kubevirt/
1485+
[KubeVirt provider]: https://github.com/kubernetes-sigs/cluster-api-provider-kubevirt/
1486+
[KubeVirt]: https://kubevirt.io/
12481487
[oci-provider]: https://oracle.github.io/cluster-api-provider-oci/#getting-started
12491488
[Equinix Metal getting started guide]: https://github.com/kubernetes-sigs/cluster-api-provider-packet#using
12501489
[provider]:../reference/providers.md

0 commit comments

Comments
 (0)