mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-09-19 06:31:47 +00:00
216 lines
10 KiB
Bash
216 lines
10 KiB
Bash
#!/bin/bash
|
|
|
|
# Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
# This is the script that runs at startup to launch Kind on GCE.
|
|
# A log of the output of this script can be viewed by running this command on the VM:
|
|
# sudo journalctl -u google-startup-scripts.service --no-pager
|
|
|
|
set -euo pipefail
|
|
|
|
function cleanup() {
|
|
# Upon exit, try to save the log of everything that happened to make debugging errors easier.
|
|
curl --retry-all-errors --retry 5 -X PUT --data "$(journalctl -u google-startup-scripts.service --no-pager)" \
|
|
http://metadata.google.internal/computeMetadata/v1/instance/guest-attributes/kind/init_log -H "Metadata-Flavor: Google"
|
|
}
|
|
trap "cleanup" EXIT SIGINT
|
|
|
|
INTERNAL_IP="$(curl --retry-all-errors --retry 5 http://metadata/computeMetadata/v1/instance/network-interfaces/0/ip -H "Metadata-Flavor: Google")"
|
|
KIND_VERSION="$(curl --retry-all-errors --retry 5 http://metadata.google.internal/computeMetadata/v1/instance/attributes/kind_version -H "Metadata-Flavor: Google")"
|
|
K8S_VERSION="$(curl --retry-all-errors --retry 5 http://metadata.google.internal/computeMetadata/v1/instance/attributes/k8s_version -H "Metadata-Flavor: Google")"
|
|
KIND_NODE_IMAGE="$(curl --retry-all-errors --retry 5 http://metadata.google.internal/computeMetadata/v1/instance/attributes/kind_node_image -H "Metadata-Flavor: Google")"
|
|
|
|
if [[ "$(uname -m)" = x86_64 ]]; then
|
|
ARCH=amd64
|
|
elif [[ "$(uname -m)" = aarch64 ]]; then
|
|
ARCH=arm64
|
|
else
|
|
echo "Error determining architecture from uname -m = $(uname -m)"
|
|
exit 1
|
|
fi
|
|
|
|
# Install kind
|
|
curl --retry-all-errors --retry 10 -Lo /var/lib/google/kind "https://github.com/kubernetes-sigs/kind/releases/download/${KIND_VERSION}/kind-linux-${ARCH}"
|
|
chmod +x /var/lib/google/kind
|
|
|
|
# Install kubectl
|
|
curl --retry-all-errors --retry 10 -Lo /var/lib/google/kubectl "https://dl.k8s.io/release/$(curl -fL -s https://dl.k8s.io/release/stable.txt)/bin/linux/${ARCH}/kubectl"
|
|
chmod +x /var/lib/google/kubectl
|
|
|
|
# Starting in Kind v0.12.0, it seems that we must use kubeadm.k8s.io/v1beta3 *only* for Kube 1.23+.
|
|
KIND_MAJOR_VERSION=$(echo "$KIND_VERSION" | cut -c2- | cut -d"." -f1) # also cuts off the leading "v"
|
|
KIND_MINOR_VERSION=$(echo "$KIND_VERSION" | cut -d"." -f2)
|
|
K8S_MAJOR_VERSION=$(echo "$K8S_VERSION" | cut -c2- | cut -d"." -f1) # also cuts off the leading "v"
|
|
K8S_MINOR_VERSION=$(echo "$K8S_VERSION" | cut -d"." -f2)
|
|
KUBE_ADM_VERSION="kubeadm.k8s.io/v1beta2"
|
|
if [[ "$KIND_MAJOR_VERSION" -gt "0" || ( "$KIND_MAJOR_VERSION" == "0" && "$KIND_MINOR_VERSION" -ge "12" ) ]]; then
|
|
if [[ "$K8S_VERSION" == "k8s-main" || "$K8S_MAJOR_VERSION" -gt "1" || ( "$K8S_MAJOR_VERSION" == "1" && "$K8S_MINOR_VERSION" -ge "23" ) ]]; then
|
|
KUBE_ADM_VERSION="kubeadm.k8s.io/v1beta3"
|
|
fi
|
|
fi
|
|
echo "Selected kubeadm config version $KUBE_ADM_VERSION based on Kind version $KIND_VERSION and K8s version $K8S_VERSION"
|
|
|
|
# create a reasonable baseline audit config that only logs metadata
|
|
mkdir -p "/tmp/audit-config"
|
|
cat <<EOF > /tmp/audit-config/audit-config.yaml
|
|
apiVersion: audit.k8s.io/v1
|
|
kind: Policy
|
|
# Don't generate audit events for all requests in RequestReceived stage.
|
|
omitStages:
|
|
- "RequestReceived"
|
|
rules:
|
|
# Don't log requests for events
|
|
- level: None
|
|
resources:
|
|
- group: ""
|
|
resources: ["events"]
|
|
# Don't log authenticated requests to certain non-resource URL paths.
|
|
- level: None
|
|
userGroups: ["system:authenticated", "system:unauthenticated"]
|
|
nonResourceURLs:
|
|
- "/api*" # Wildcard matching.
|
|
- "/version"
|
|
- "/healthz"
|
|
- "/readyz"
|
|
# A catch-all rule to log all other requests at the Metadata level.
|
|
- level: Metadata
|
|
# Long-running requests like watches that fall under this rule will not
|
|
# generate an audit event in RequestReceived.
|
|
omitStages:
|
|
- "RequestReceived"
|
|
EOF
|
|
|
|
cat <<EOF > /tmp/kind.yaml
|
|
kind: Cluster
|
|
apiVersion: kind.x-k8s.io/v1alpha4
|
|
networking:
|
|
apiServerAddress: "0.0.0.0"
|
|
apiServerPort: 6443
|
|
kubeadmConfigPatches:
|
|
- |
|
|
apiVersion: ${KUBE_ADM_VERSION}
|
|
kind: ClusterConfiguration
|
|
# ControlPlaneEndpoint sets a stable IP address or DNS name for the control plane.
|
|
# Although this worked when the VM had a public IP address that we could use here,
|
|
# this does not work when using the VM's internal IP address. kubeadm fails to connect
|
|
# to this endpoint during liveness probes, so it thinks that the api-server is not
|
|
# running (when it actually is running), which causes cluster creation to fail.
|
|
# Instead, we will add the internal IP as a SAN on the api-server's TLS certificate below,
|
|
# which will still allow us to validate TLS when connecting to the cluster using the
|
|
# VM's internal IP.
|
|
#controlPlaneEndpoint: "${INTERNAL_IP}:6443"
|
|
# mount the kind extraMounts into the API server static pod so we can use the audit config
|
|
apiServer:
|
|
certSANs:
|
|
- "${INTERNAL_IP}"
|
|
extraVolumes:
|
|
- name: audit-config
|
|
hostPath: /audit-config/audit-config.yaml
|
|
mountPath: /audit-config/audit-config.yaml
|
|
readOnly: true
|
|
pathType: File
|
|
extraArgs:
|
|
audit-policy-file: /audit-config/audit-config.yaml
|
|
audit-log-path: "-" # log to standard out so that it gets captured by export-cluster-diagnostics
|
|
v: "4"
|
|
# To make sure the endpoints on our service are correct (this mostly matters for kubectl based
|
|
# installs where kapp is not doing magic changes to the deployment and service selectors).
|
|
# Setting this field to true makes it so that the API service will do the service cluster IP
|
|
# to endpoint IP translations internally instead of relying on the network stack (i.e. kube-proxy).
|
|
# The logic inside the API server is very straightforward - randomly pick an IP from the list
|
|
# of available endpoints. This means that over time, all endpoints associated with the service
|
|
# are exercised. For whatever reason, leaving this as false (i.e. use kube-proxy) appears to
|
|
# hide some network misconfigurations when used internally by the API server aggregation layer.
|
|
enable-aggregator-routing: "true"
|
|
controllerManager:
|
|
extraArgs:
|
|
v: "4"
|
|
scheduler:
|
|
extraArgs:
|
|
v: "4"
|
|
nodes:
|
|
- role: control-plane
|
|
extraPortMappings:
|
|
- protocol: TCP
|
|
# This same port number is hardcoded in the integration test setup
|
|
# when creating a Service on a kind cluster. It is used to talk to
|
|
# the supervisor app via HTTPS.
|
|
containerPort: 31243
|
|
hostPort: 12344
|
|
listenAddress: 127.0.0.1
|
|
- protocol: TCP
|
|
# This same port number is hardcoded in the integration test setup
|
|
# when creating a Service on a kind cluster. It is used to talk to
|
|
# the supervisor app via HTTP.
|
|
# This is retained for the release-0.12 pipeline's use. The HTTP port
|
|
# cannot be exposed anymore on main. When the release-0.12 pipeline
|
|
# is not longer needed, then this port mapping can be removed.
|
|
containerPort: 31234
|
|
hostPort: 12345
|
|
listenAddress: 127.0.0.1
|
|
- protocol: TCP
|
|
# This same port number is used for the second Pinniped deployment's
|
|
# supervisor HTTPS port, when there are multiple Pinnipeds deployed.
|
|
containerPort: 30243
|
|
hostPort: 11344
|
|
listenAddress: 127.0.0.1
|
|
- protocol: TCP
|
|
# This same port number is used for the second Pinniped deployment's
|
|
# supervisor HTTP port, when there are multiple Pinnipeds deployed.
|
|
# This is retained for the release-0.12 pipeline's use. The HTTP port
|
|
# cannot be exposed anymore on main. When the release-0.12 pipeline
|
|
# is not longer needed, then this port mapping can be removed.
|
|
containerPort: 30234
|
|
hostPort: 11345
|
|
listenAddress: 127.0.0.1
|
|
- protocol: TCP
|
|
# This same port number is hardcoded in the integration test setup
|
|
# when creating a Service on a kind cluster. It is used to talk to
|
|
# the Dex app.
|
|
containerPort: 31235
|
|
hostPort: 12346
|
|
listenAddress: 127.0.0.1
|
|
# mount the audit config dir into kind
|
|
extraMounts:
|
|
- hostPath: /tmp/audit-config/
|
|
containerPath: /audit-config
|
|
EOF
|
|
|
|
# When KIND_NODE_IMAGE is specified, then use it. Otherwise choose the official kind image for the specified version of K8s.
|
|
if [[ "$KIND_NODE_IMAGE" != "" ]]; then
|
|
image="$KIND_NODE_IMAGE"
|
|
else
|
|
image="kindest/node:${K8S_VERSION}"
|
|
fi
|
|
|
|
/var/lib/google/kind create cluster --wait 5m --kubeconfig /tmp/kubeconfig.yaml --image "$image" --config /tmp/kind.yaml |& tee /tmp/kind-cluster-create.log
|
|
|
|
# Change the kubeconfig to make the server address match the IP configured as controlPlaneEndpoint above.
|
|
sed -i "s/0\\.0\\.0\\.0/${INTERNAL_IP}/" /tmp/kubeconfig.yaml
|
|
|
|
# The above YAML config file specifies one node, and Kind should never put the "control-plane"
|
|
# taint on the node for single-node clusters. Due to the issue described in
|
|
# https://github.com/kubernetes-sigs/kind/issues/1699#issuecomment-1048269832
|
|
# we may not be able to rely on Kind automatically removing that taint, depending on which
|
|
# version of Kind and which version of the Kubernetes node image we're using, so to keep things
|
|
# simple we'll always remove that taint here.
|
|
node_name=$(/var/lib/google/kubectl get nodes -o jsonpath='{.items[0].metadata.name}' --kubeconfig /tmp/kubeconfig.yaml)
|
|
if [[ "$node_name" == "" ]]; then
|
|
echo "ERROR: Did not find any nodes in the new cluster."
|
|
exit 1
|
|
fi
|
|
# Check if there are any taints. Normally there should be none for single-node clusters,
|
|
# unless we are running into the problem described above.
|
|
node_taints=$(/var/lib/google/kubectl get nodes -o jsonpath='{.items[0].spec.taints[?(@.key=="node-role.kubernetes.io/control-plane")]}' --kubeconfig /tmp/kubeconfig.yaml)
|
|
if [[ "$node_taints" != "" ]]; then
|
|
echo "Found taint node-role.kubernetes.io/control-plane Kind node: ${node_taints}"
|
|
# Remove the taint that is causing us trouble.
|
|
# Putting a minus sign at the end of the key name means remove all taints with that key.
|
|
/var/lib/google/kubectl taint nodes "$node_name" "node-role.kubernetes.io/control-plane-" --kubeconfig /tmp/kubeconfig.yaml
|
|
fi
|
|
|
|
# Success! Save the kubeconfig file.
|
|
curl --retry-all-errors --retry 5 -X PUT --data "$(cat /tmp/kubeconfig.yaml)" \
|
|
http://metadata.google.internal/computeMetadata/v1/instance/guest-attributes/kind/kubeconfig -H "Metadata-Flavor: Google"
|