istio.io/istio@v0.0.0-20240520182934-d79c90f27776/samples/kind-lb/setupkind.sh (about) 1 #!/bin/bash 2 # Copyright Istio Authors 3 # 4 # Licensed under the Apache License, Version 2.0 (the "License"); 5 # 6 set -e 7 8 # This script can only produce desired results on Linux systems. 9 ENVOS=$(uname 2>/dev/null || true) 10 if [[ "${ENVOS}" != "Linux" ]]; then 11 echo "Your system is not supported by this script. Only Linux is supported" 12 exit 1 13 fi 14 15 # Check prerequisites 16 REQUISITES=("kubectl" "kind" "docker") 17 for item in "${REQUISITES[@]}"; do 18 if [[ -z $(which "${item}") ]]; then 19 echo "${item} cannot be found on your system, please install ${item}" 20 exit 1 21 fi 22 done 23 24 # Function to print the usage message 25 function printHelp() { 26 echo "Usage: " 27 echo " $0 --cluster-name cluster1 --k8s-release 1.22.1 --ip-space 255" 28 echo "" 29 echo "Where:" 30 echo " -n|--cluster-name - name of the k8s cluster to be created" 31 echo " -r|--k8s-release - the release of the k8s to setup, latest available if not given" 32 echo " -s|--ip-space - the 2nd to the last part for public ip addresses, 255 if not given, valid range: 0-255." 33 echo " -m|--mode - setup the required number of nodes per deployment model. Values are sidecar (1 node) or ambient (minimum of 2)" 34 echo " -w|--worker-nodes - the number of worker nodes to create. Default is 1" 35 echo " --pod-subnet - the pod subnet to specify. Default is 10.244.0.0/16 for IPv4 and fd00:10:244::/56 for IPv6" 36 echo " --service-subnet - the service subnet to specify. Default is 10.96.0.0/16 for IPv4 and fd00:10:96::/112 for IPv6" 37 echo " -i|--ip-family - ip family to be supported, default is ipv4 only. Value should be ipv4, ipv6, or dual" 38 echo " --ipv6gw - set ipv6 as the gateway, necessary for dual-stack IPv6-preferred clusters" 39 echo " -h|--help - print the usage of this script" 40 } 41 42 # Setup default values 43 CLUSTERNAME="cluster1" 44 K8SRELEASE="" 45 IPSPACE=255 46 IPFAMILY="ipv4" 47 MODE="sidecar" 48 NUMNODES="" 49 PODSUBNET="" 50 SERVICESUBNET="" 51 IPV6GW=false 52 53 # Handling parameters 54 while [[ $# -gt 0 ]]; do 55 optkey="$1" 56 case $optkey in 57 -n|--cluster-name) 58 CLUSTERNAME="$2"; shift 2;; 59 -r|--k8s-release) 60 K8SRELEASE="--image=kindest/node:v$2"; shift 2;; 61 -s|--ip-space) 62 IPSPACE="$2"; shift 2;; 63 -m|--mode) 64 MODE="$2"; shift 2;; 65 -w|--worker-nodes) 66 NUMNODES="$2"; shift 2;; 67 --pod-subnet) 68 PODSUBNET="$2"; shift 2;; 69 --service-subnet) 70 SERVICESUBNET="$2"; shift 2;; 71 -i|--ip-family) 72 IPFAMILY="${2,,}";shift 2;; 73 --ipv6gw) 74 IPV6GW=true; shift;; 75 -h|--help) 76 printHelp; exit 0;; 77 *) # unknown option 78 echo "parameter $1 is not supported"; printHelp; exit 1;; 79 esac 80 done 81 82 # This block is to setup kind to have a local image repo to push 83 # images using localhost:5000, to use this feature, start up 84 # a registry container such as gcr.io/istio-testing/registry, then 85 # connect it to the docker network where kind nodes are running on 86 # which normally will be called kind 87 FEATURES=$(cat << EOF 88 featureGates: 89 MixedProtocolLBService: true 90 GRPCContainerProbe: true 91 kubeadmConfigPatches: 92 - | 93 apiVersion: kubeadm.k8s.io/v1beta2 94 kind: ClusterConfiguration 95 metadata: 96 name: config 97 etcd: 98 local: 99 # Run etcd in a tmpfs (in RAM) for performance improvements 100 dataDir: /tmp/kind-cluster-etcd 101 # We run single node, drop leader election to reduce overhead 102 controllerManagerExtraArgs: 103 leader-elect: "false" 104 schedulerExtraArgs: 105 leader-elect: "false" 106 apiServer: 107 extraArgs: 108 "service-account-issuer": "kubernetes.default.svc" 109 "service-account-signing-key-file": "/etc/kubernetes/pki/sa.key" 110 containerdConfigPatches: 111 - |- 112 [plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:5000"] 113 endpoint = ["http://kind-registry:5000"] 114 EOF 115 ) 116 117 validIPFamilies=("ipv4" "ipv6" "dual") 118 # Validate if the ip family value is correct. 119 isValid="false" 120 for family in "${validIPFamilies[@]}"; do 121 if [[ "$family" == "${IPFAMILY}" ]]; then 122 isValid="true" 123 break 124 fi 125 done 126 127 if [[ "${isValid}" == "false" ]]; then 128 echo "${IPFAMILY} is not valid ip family, valid values are ipv4, ipv6 or dual" 129 exit 1 130 fi 131 132 if [[ "${MODE}" == "ambient" ]]; then 133 NUMNODES=${NUMNODES:-2} 134 fi 135 136 NODES=$(cat <<-EOM 137 nodes: 138 - role: control-plane 139 EOM 140 ) 141 142 if [[ -n "${NUMNODES}" ]]; then 143 for _ in $(seq 1 "${NUMNODES}"); do 144 NODES+=$(printf "\n%s" "- role: worker") 145 done 146 fi 147 148 CONFIG=$(cat <<-EOM 149 kind: Cluster 150 apiVersion: kind.x-k8s.io/v1alpha4 151 ${FEATURES} 152 name: ${CLUSTERNAME} 153 ${NODES} 154 networking: 155 ipFamily: ${IPFAMILY} 156 EOM 157 ) 158 159 if [[ -n "${PODSUBNET}" ]]; then 160 CONFIG+=$(printf "\n%s" " podSubnet: \"${PODSUBNET}\"") 161 fi 162 163 if [[ -n "${SERVICESUBNET}" ]]; then 164 CONFIG+=$(printf "\n%s" " serviceSubnet: \"${SERVICESUBNET}\"") 165 fi 166 167 # Create k8s cluster using the giving release and name 168 if [[ -z "${K8SRELEASE}" ]]; then 169 cat << EOF | kind create cluster --config - 170 ${CONFIG} 171 EOF 172 else 173 cat << EOF | kind create cluster "${K8SRELEASE}" --config - 174 ${CONFIG} 175 EOF 176 fi 177 178 # Setup cluster context 179 kubectl cluster-info --context "kind-${CLUSTERNAME}" 180 181 # Setup metallb using v0.13.11 182 kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.11/config/manifests/metallb-native.yaml 183 184 addrName="IPAddress" 185 ipv4Prefix="" 186 ipv6Prefix="" 187 188 # Get both ipv4 and ipv6 gateway for the cluster 189 gatewaystr=$(docker network inspect -f '{{range .IPAM.Config }}{{ .Gateway }} {{end}}' kind | cut -f1,2) 190 read -r -a gateways <<< "${gatewaystr}" 191 for gateway in "${gateways[@]}"; do 192 if [[ "$gateway" == *"."* ]]; then 193 ipv4Prefix=$(echo "${gateway}" |cut -d'.' -f1,2) 194 else 195 ipv6Prefix=$(echo "${gateway}" |cut -d':' -f1,2,3,4) 196 fi 197 done 198 199 if [[ "${IPFAMILY}" == "ipv4" ]]; then 200 addrName="IPAddress" 201 ipv4Range="- ${ipv4Prefix}.${IPSPACE}.200-${ipv4Prefix}.${IPSPACE}.240" 202 ipv6Range="" 203 elif [[ "${IPFAMILY}" == "ipv6" ]]; then 204 addrName="GlobalIPv6Address" 205 ipv4Range="" 206 ipv6Range="- ${ipv6Prefix}::${IPSPACE}:200-${ipv6Prefix}::${IPSPACE}:240" 207 else 208 if [[ "${IPV6GW}" == "true" ]]; then 209 addrName="GlobalIPv6Address" 210 fi 211 212 ipv4Range="- ${ipv4Prefix}.${IPSPACE}.200-${ipv4Prefix}.${IPSPACE}.240" 213 ipv6Range="- ${ipv6Prefix}::${IPSPACE}:200-${ipv6Prefix}::${IPSPACE}:240" 214 fi 215 216 # utility function to wait for pods to be ready 217 function waitForPods() { 218 ns=$1 219 lb=$2 220 waittime=$3 221 # Wait for the pods to be ready in the given namespace with lable 222 while : ; do 223 res=$(kubectl wait --context "kind-${CLUSTERNAME}" -n "${ns}" pod \ 224 -l "${lb}" --for=condition=Ready --timeout="${waittime}s" 2>/dev/null ||true) 225 if [[ "${res}" == *"condition met"* ]]; then 226 break 227 fi 228 echo "Waiting for pods in namespace ${ns} with label ${lb} to be ready..." 229 sleep "${waittime}" 230 done 231 } 232 233 waitForPods metallb-system app=metallb 10 234 235 # Now configure the loadbalancer public IP range 236 cat <<EOF | kubectl apply -f - 237 apiVersion: metallb.io/v1beta1 238 kind: IPAddressPool 239 metadata: 240 namespace: metallb-system 241 name: address-pool 242 spec: 243 addresses: 244 ${ipv4Range} 245 ${ipv6Range} 246 --- 247 apiVersion: metallb.io/v1beta1 248 kind: L2Advertisement 249 metadata: 250 name: empty 251 namespace: metallb-system 252 EOF 253 254 # Wait for the public IP address to become available. 255 while : ; do 256 ip=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.'${addrName}'}}{{end}}' "${CLUSTERNAME}"-control-plane) 257 if [[ -n "${ip}" ]]; then 258 #Change the kubeconfig file not to use the loopback IP 259 if [[ "${IPFAMILY}" == "ipv6" ]]; then 260 ip="[${ip}]" 261 elif [[ "${IPFAMILY}" == "dual" ]] && [[ "${IPV6GW}" == "true" ]]; then 262 ip="[${ip}]" 263 fi 264 kubectl config set clusters.kind-"${CLUSTERNAME}".server https://"${ip}":6443 265 break 266 fi 267 echo 'Waiting for public IP address to be available...' 268 sleep 3 269 done 270 271 echo "Kubernetes cluster ${CLUSTERNAME} was created successfully!"