Skip to content

Commit 2844582

Browse files
committed
Update Kind scripts to support KubeVirt
Signed-off-by: Johanan Liebermann <[email protected]>
1 parent 2f5d70a commit 2844582

File tree

4 files changed

+226
-69
lines changed

4 files changed

+226
-69
lines changed

Makefile

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

999+
.PHONY: kind-cluster-kubevirt
1000+
kind-cluster-kubevirt: ## Create a new kind cluster with KubeVirt designed for development with Tilt
1001+
hack/kind-install-for-capk.sh
1002+
9991003
.PHONY: tilt-e2e-prerequisites
10001004
tilt-e2e-prerequisites: ## Build the corresponding kindest/node images required for e2e testing and generate the e2e templates
10011005
scripts/build-kind.sh

hack/kind-install-for-capd.sh

Lines changed: 6 additions & 69 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.
@@ -22,41 +22,10 @@
2222
# The modifications mount the docker socket inside the kind cluster so that CAPD can be used to
2323
# created docker containers.
2424

25-
set -o errexit
26-
set -o nounset
27-
set -o pipefail
28-
29-
if [[ "${TRACE-0}" == "1" ]]; then
30-
set -o xtrace
31-
fi
32-
33-
KIND_CLUSTER_NAME=${CAPI_KIND_CLUSTER_NAME:-"capi-test"}
3425
# 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
26+
KIND_NETWORK_IPFAMILY=${CAPI_KIND_NETWORK_IPFAMILY:-"dual"}
4227

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
51-
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=-
28+
KIND_CLUSTER_CONFIG="$(cat <<EOF
6029
kind: Cluster
6130
apiVersion: kind.x-k8s.io/v1alpha4
6231
networking:
@@ -71,39 +40,7 @@ containerdConfigPatches:
7140
[plugins."io.containerd.grpc.v1.cri".registry]
7241
config_path = "/etc/containerd/certs.d"
7342
EOF
43+
)"
44+
export KIND_CLUSTER_CONFIG
7445

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
46+
"$(dirname "${BASH_SOURCE[0]}")/kind-install.sh"

hack/kind-install-for-capk.sh

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
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 controller pod to be created..."
72+
while [[ -z $(kubectl -n metallb-system get pods \
73+
-l app=metallb,component=controller -o jsonpath="{.items[0].metadata.name}" 2>/dev/null) ]]; do
74+
sleep 2
75+
done
76+
echo "Pod created!"
77+
78+
echo "Waiting for speaker pod to be created..."
79+
while [[ -z $(kubectl -n metallb-system get pods \
80+
-l app=metallb,component=speaker -o jsonpath="{.items[0].metadata.name}" 2>/dev/null) ]]; do
81+
sleep 2
82+
done
83+
echo "Pod created!"
84+
85+
echo "Waiting for pods to become ready..."
86+
kubectl wait pods -n metallb-system \
87+
-l app=metallb,component=controller --for=condition=Ready --timeout=10m
88+
kubectl wait pods -n metallb-system \
89+
-l app=metallb,component=speaker --for=condition=Ready --timeout=2m
90+
echo "Pods ready!"
91+
92+
if [[ -z "$METALLB_IP_PREFIX" ]]; then
93+
SUBNET=$(docker network inspect \
94+
-f '{{range .IPAM.Config}}{{if .Gateway}}{{.Subnet}}{{end}}{{end}}' kind)
95+
METALLB_IP_PREFIX=$(echo "$SUBNET" | sed -E 's|^([0-9]+\.[0-9]+)\..*$|\1|g')
96+
fi
97+
98+
cat <<EOF | kubectl apply -f -
99+
apiVersion: metallb.io/v1beta1
100+
kind: IPAddressPool
101+
metadata:
102+
name: capi-ip-pool
103+
namespace: metallb-system
104+
spec:
105+
addresses:
106+
- ${METALLB_IP_PREFIX}.255.200-${METALLB_IP_PREFIX}.255.250
107+
---
108+
apiVersion: metallb.io/v1beta1
109+
kind: L2Advertisement
110+
metadata:
111+
name: empty
112+
namespace: metallb-system
113+
EOF
114+
115+
# Deploy KubeVirt
116+
if [[ -z "$KUBEVIRT_VERSION" ]]; then
117+
KUBEVIRT_VERSION=$(curl "https://api.github.com/repos/kubevirt/kubevirt/releases/latest" \
118+
| jq -r ".tag_name")
119+
fi
120+
kubectl apply -f \
121+
"https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-operator.yaml"
122+
kubectl apply -f \
123+
"https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-cr.yaml"
124+
echo "Waiting for KubeVirt to become ready..."
125+
kubectl wait -n kubevirt kv kubevirt --for=condition=Available --timeout=10m
126+
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)