Skip to content

Commit 88f151e

Browse files
committed
Update Kind scripts to support KubeVirt
Signed-off-by: Johanan Liebermann <[email protected]>
1 parent 9ed56b1 commit 88f151e

File tree

4 files changed

+214
-65
lines changed

4 files changed

+214
-65
lines changed

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,10 @@ test-e2e: $(GINKGO) generate-e2e-templates ## Run the end-to-end tests
974974
kind-cluster: ## Create a new kind cluster designed for development with Tilt
975975
hack/kind-install-for-capd.sh
976976

977+
.PHONY: kind-cluster-kubevirt
978+
kind-cluster-kubevirt: ## Create a new kind cluster with KubeVirt designed for development with Tilt
979+
hack/kind-install-for-capk.sh
980+
977981
.PHONY: tilt-e2e-prerequisites
978982
tilt-e2e-prerequisites: ## Build the corresponding kindest/node images required for e2e testing and generate the e2e templates
979983
scripts/build-kind.sh

hack/kind-install-for-capd.sh

Lines changed: 6 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env bash
22

3-
# Copyright 2021 The Kubernetes Authors.
3+
# Copyright 2025 The Kubernetes Authors.
44
#
55
# Licensed under the Apache License, Version 2.0 (the "License");
66
# you may not use this file except in compliance with the License.
@@ -26,37 +26,10 @@ set -o errexit
2626
set -o nounset
2727
set -o pipefail
2828

29-
if [[ "${TRACE-0}" == "1" ]]; then
30-
set -o xtrace
31-
fi
32-
33-
KIND_CLUSTER_NAME=${CAPI_KIND_CLUSTER_NAME:-"capi-test"}
3429
# See: https://kind.sigs.k8s.io/docs/user/configuration/#ip-family
35-
KIND_NETWORK_IPFAMILY=${KIND_NETWORK_IPFAMILY:-"dual"}
36-
37-
# 1. If kind cluster already exists exit.
38-
if [[ "$(kind get clusters)" =~ .*"${KIND_CLUSTER_NAME}".* ]]; then
39-
echo "kind cluster already exists, moving on"
40-
exit 0
41-
fi
42-
43-
# 2. Create registry container unless it already exists
44-
reg_name='kind-registry'
45-
reg_port='5000'
46-
if [ "$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || true)" != 'true' ]; then
47-
docker run \
48-
-d --restart=always -p "127.0.0.1:${reg_port}:5000" --name "${reg_name}" \
49-
registry:2
50-
fi
30+
KIND_NETWORK_IPFAMILY=${CAPI_KIND_NETWORK_IPFAMILY:-"dual"}
5131

52-
# 3. Create kind cluster with containerd registry config dir enabled.
53-
# TODO(killianmuldoon): kind will eventually enable this by default and this patch will be unnecessary.
54-
#
55-
# See:
56-
# https://github.com/kubernetes-sigs/kind/issues/2875
57-
# https://github.com/containerd/containerd/blob/main/docs/cri/config.md#registry-configuration
58-
# See: https://github.com/containerd/containerd/blob/main/docs/hosts.md
59-
cat <<EOF | kind create cluster --name="$KIND_CLUSTER_NAME" --config=-
32+
KIND_CLUSTER_CONFIG="$(cat <<EOF
6033
kind: Cluster
6134
apiVersion: kind.x-k8s.io/v1alpha4
6235
networking:
@@ -71,39 +44,7 @@ containerdConfigPatches:
7144
[plugins."io.containerd.grpc.v1.cri".registry]
7245
config_path = "/etc/containerd/certs.d"
7346
EOF
47+
)"
48+
export KIND_CLUSTER_CONFIG
7449

75-
# 4. Add the registry config to the nodes
76-
#
77-
# This is necessary because localhost resolves to loopback addresses that are
78-
# network-namespace local.
79-
# In other words: localhost in the container is not localhost on the host.
80-
#
81-
# We want a consistent name that works from both ends, so we tell containerd to
82-
# alias localhost:${reg_port} to the registry container when pulling images
83-
REGISTRY_DIR="/etc/containerd/certs.d/localhost:${reg_port}"
84-
for node in $(kind get nodes --name "$KIND_CLUSTER_NAME"); do
85-
docker exec "${node}" mkdir -p "${REGISTRY_DIR}"
86-
cat <<EOF | docker exec -i "${node}" cp /dev/stdin "${REGISTRY_DIR}/hosts.toml"
87-
[host."http://${reg_name}:5000"]
88-
EOF
89-
done
90-
91-
# 5. Connect the registry to the cluster network if not already connected
92-
# This allows kind to bootstrap the network but ensures they're on the same network
93-
if [ "$(docker inspect -f='{{json .NetworkSettings.Networks.kind}}' "${reg_name}")" = 'null' ]; then
94-
docker network connect "kind" "${reg_name}"
95-
fi
96-
97-
# 6. Document the local registry
98-
# https://github.com/kubernetes/enhancements/tree/master/keps/sig-cluster-lifecycle/generic/1755-communicating-a-local-registry
99-
cat <<EOF | kubectl apply -f -
100-
apiVersion: v1
101-
kind: ConfigMap
102-
metadata:
103-
name: local-registry-hosting
104-
namespace: kube-public
105-
data:
106-
localRegistryHosting.v1: |
107-
host: "localhost:${reg_port}"
108-
help: "https://kind.sigs.k8s.io/docs/user/local-registry/"
109-
EOF
50+
"$(dirname "${BASH_SOURCE[0]}")/kind-install.sh"

hack/kind-install-for-capk.sh

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#!/usr/bin/env bash
2+
3+
# Copyright 2025 The Kubernetes Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
18+
# This script installs a local Kind cluster with a local container registry and the correct files
19+
# mounted for using CAPK to test Cluster API.
20+
# The default Kind CNI is disabled because it doesn't work CAPK. Instead, Calico is used.
21+
# MetalLB is used as a local layer 2 load balancer to support exposing the API servers of workload
22+
# clusters on the local machine that's running this script.
23+
24+
set -o errexit
25+
set -o nounset
26+
set -o pipefail
27+
28+
CALICO_VERSION=${CAPI_CALICO_VERSION:-"v3.29.1"}
29+
METALLB_VERSION=${CAPI_METALLB_VERSION:-""}
30+
# Set manually for non-Docker runtimes - example: "172.20"
31+
METALLB_IP_PREFIX=${CAPI_METALLB_IP_PREFIX:-""}
32+
KUBEVIRT_VERSION=${CAPI_KUBEVIRT_VERSION:-""}
33+
# Required to support pulling KubeVirt container disk images from private registries as well as
34+
# avoid Docker Hub rate limiting
35+
KIND_DOCKER_CONFIG_PATH=${CAPI_KIND_DOCKER_CONFIG_PATH:-"$HOME/.docker/config.json"}
36+
37+
# Deploy Kind cluster
38+
KIND_CLUSTER_CONFIG="$(cat <<EOF
39+
kind: Cluster
40+
apiVersion: kind.x-k8s.io/v1alpha4
41+
networking:
42+
disableDefaultCNI: true
43+
nodes:
44+
- role: control-plane
45+
extraMounts:
46+
- containerPath: /var/lib/kubelet/config.json
47+
hostPath: ${KIND_DOCKER_CONFIG_PATH}
48+
containerdConfigPatches:
49+
- |-
50+
[plugins."io.containerd.grpc.v1.cri".registry]
51+
config_path = "/etc/containerd/certs.d"
52+
EOF
53+
)"
54+
export KIND_CLUSTER_CONFIG
55+
56+
"$(dirname "${BASH_SOURCE[0]}")/kind-install.sh"
57+
58+
# Deploy Calico
59+
kubectl apply -f \
60+
"https://raw.githubusercontent.com/projectcalico/calico/${CALICO_VERSION}/manifests/calico.yaml"
61+
62+
# Deploy MetalLB
63+
if [[ -z "$METALLB_VERSION" ]]; then
64+
METALLB_VERSION=$(curl "https://api.github.com/repos/metallb/metallb/releases/latest" \
65+
| jq -r ".tag_name")
66+
fi
67+
68+
kubectl apply -f \
69+
"https://raw.githubusercontent.com/metallb/metallb/${METALLB_VERSION}/config/manifests/metallb-native.yaml"
70+
71+
echo "Waiting for MetalLB controller pod to be created..."
72+
kubectl wait -n metallb-system deployment controller --for condition=available --timeout 5m
73+
echo "MetalLB controller pod created!"
74+
75+
echo "Waiting for all MetalLB pods to become ready..."
76+
kubectl wait pods -n metallb-system -l app=metallb,component=controller --for condition=Ready --timeout 5m
77+
kubectl wait pods -n metallb-system -l app=metallb,component=speaker --for condition=Ready --timeout 5m
78+
echo "MetalLB pods ready!"
79+
80+
if [[ -z "$METALLB_IP_PREFIX" ]]; then
81+
SUBNET=$(docker network inspect \
82+
-f '{{range .IPAM.Config}}{{if .Gateway}}{{.Subnet}}{{end}}{{end}}' kind)
83+
METALLB_IP_PREFIX=$(echo "$SUBNET" | sed -E 's|^([0-9]+\.[0-9]+)\..*$|\1|g')
84+
fi
85+
86+
cat <<EOF | kubectl apply -f -
87+
apiVersion: metallb.io/v1beta1
88+
kind: IPAddressPool
89+
metadata:
90+
name: capi-ip-pool
91+
namespace: metallb-system
92+
spec:
93+
addresses:
94+
- ${METALLB_IP_PREFIX}.255.200-${METALLB_IP_PREFIX}.255.250
95+
---
96+
apiVersion: metallb.io/v1beta1
97+
kind: L2Advertisement
98+
metadata:
99+
name: empty
100+
namespace: metallb-system
101+
EOF
102+
103+
# Deploy KubeVirt
104+
if [[ -z "$KUBEVIRT_VERSION" ]]; then
105+
KUBEVIRT_VERSION=$(curl "https://api.github.com/repos/kubevirt/kubevirt/releases/latest" \
106+
| jq -r ".tag_name")
107+
fi
108+
kubectl apply -f \
109+
"https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-operator.yaml"
110+
kubectl apply -f \
111+
"https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-cr.yaml"
112+
echo "Waiting for KubeVirt to become ready..."
113+
kubectl wait -n kubevirt kv kubevirt --for=condition=Available --timeout=10m
114+
echo "KubeVirt ready!"

hack/kind-install.sh

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env bash
2+
3+
# Copyright 2025 The Kubernetes Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
18+
# This script contains common logic for creating a local kind cluster with a local container
19+
# registry.
20+
21+
set -o errexit
22+
set -o nounset
23+
set -o pipefail
24+
25+
if [[ "${TRACE-0}" == "1" ]]; then
26+
set -o xtrace
27+
fi
28+
29+
KIND_CLUSTER_NAME=${CAPI_KIND_CLUSTER_NAME:-"capi-test"}
30+
31+
# 1. If kind cluster already exists exit.
32+
if [[ "$(kind get clusters)" =~ .*"${KIND_CLUSTER_NAME}".* ]]; then
33+
echo "kind cluster already exists, moving on"
34+
exit 0
35+
fi
36+
37+
# 2. Create registry container unless it already exists
38+
reg_name='kind-registry'
39+
reg_port='5000'
40+
if [ "$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || true)" != 'true' ]; then
41+
docker run \
42+
-d --restart=always -p "127.0.0.1:${reg_port}:5000" --name "${reg_name}" \
43+
registry:2
44+
fi
45+
46+
# 3. Create kind cluster with containerd registry config dir enabled.
47+
# TODO(killianmuldoon): kind will eventually enable this by default and this patch will be unnecessary.
48+
#
49+
# See:
50+
# https://github.com/kubernetes-sigs/kind/issues/2875
51+
# https://github.com/containerd/containerd/blob/main/docs/cri/config.md#registry-configuration
52+
# See: https://github.com/containerd/containerd/blob/main/docs/hosts.md
53+
54+
echo "$KIND_CLUSTER_CONFIG" | kind create cluster --name="$KIND_CLUSTER_NAME" --config=-
55+
56+
# 4. Add the registry config to the nodes
57+
#
58+
# This is necessary because localhost resolves to loopback addresses that are
59+
# network-namespace local.
60+
# In other words: localhost in the container is not localhost on the host.
61+
#
62+
# We want a consistent name that works from both ends, so we tell containerd to
63+
# alias localhost:${reg_port} to the registry container when pulling images
64+
REGISTRY_DIR="/etc/containerd/certs.d/localhost:${reg_port}"
65+
for node in $(kind get nodes --name "$KIND_CLUSTER_NAME"); do
66+
docker exec "${node}" mkdir -p "${REGISTRY_DIR}"
67+
cat <<EOF | docker exec -i "${node}" cp /dev/stdin "${REGISTRY_DIR}/hosts.toml"
68+
[host."http://${reg_name}:5000"]
69+
EOF
70+
done
71+
72+
# 5. Connect the registry to the cluster network if not already connected
73+
# This allows kind to bootstrap the network but ensures they're on the same network
74+
if [ "$(docker inspect -f='{{json .NetworkSettings.Networks.kind}}' "${reg_name}")" = 'null' ]; then
75+
docker network connect "kind" "${reg_name}"
76+
fi
77+
78+
# 6. Document the local registry
79+
# https://github.com/kubernetes/enhancements/tree/master/keps/sig-cluster-lifecycle/generic/1755-communicating-a-local-registry
80+
cat <<EOF | kubectl apply -f -
81+
apiVersion: v1
82+
kind: ConfigMap
83+
metadata:
84+
name: local-registry-hosting
85+
namespace: kube-public
86+
data:
87+
localRegistryHosting.v1: |
88+
host: "localhost:${reg_port}"
89+
help: "https://kind.sigs.k8s.io/docs/user/local-registry/"
90+
EOF

0 commit comments

Comments
 (0)