#!/usr/bin/env bash # # Script creating a Kubernetes cluster using kind tool # and deploying an ingress contoller (nginx, kourier) # # Creation: April - 2023 # # Add hereafter changes done post creation date as backlog # # May 18th 2023: # # - Remove the deployment of a container registry into an independent script (registry.sh) # set -o errexit ###################### # Logging and Output # ###################### # Defining some colors for output NC='\033[0m' # No Color COLOR_RESET="\033[0m" # Reset color BLACK="\033[0;30m" BLUE='\033[0;34m' BROWN="\033[0;33m" GREEN='\033[0;32m' GREY="\033[0;90m" CYAN='\033[0;36m' MAGENTA='\033[0;35m' RED='\033[0;31m' PURPLE="\033[0;35m" WHITE='\033[0;37m' YELLOW='\033[0;33m' log_message() { VERBOSITY_LEVEL=$1 MESSAGE="${@:2}" if [ "${LOGGING_VERBOSITY}" -ge "${VERBOSITY_LEVEL}" ]; then echo -e "${MESSAGE}" fi } log_message_nonl() { VERBOSITY_LEVEL=$1 MESSAGE="${@:2}" if [ "${LOGGING_VERBOSITY}" -ge "${VERBOSITY_LEVEL}" ]; then echo -ne "${MESSAGE}\033[0K\r" fi } repeat_char(){ COLOR=${1} for i in {1..70}; do echo -ne "${!COLOR}$2${NC}"; done } msg() { VERBOSITY_LEVEL=${1} COLOR=${2} MSG="${@:3}" # echo -e "\n${!COLOR}## ${MSG}${NC}" log_message ${VERBOSITY_LEVEL} "\n${!COLOR}## ${MSG}${NC}" } succeeded() { VERBOSITY_LEVEL=$1 MSG="${@:2}" # echo -e "${GREEN}NOTE:${NC} $1" # log_message ${VERBOSITY_LEVEL} "${GREEN}\xE2\x9C\x85${NC} ${MSG}" log_message ${VERBOSITY_LEVEL} "${GREEN}\xE2\x9C\x94${NC} ${MSG}" } note() { VERBOSITY_LEVEL=$1 MSG="${@:2}" # echo -e "${BLUE}NOTE:${NC} $1" log_message ${VERBOSITY_LEVEL} "${BLUE}!${NC} ${MSG}" } note_start_task() { VERBOSITY_LEVEL=$1 MSG="${@:2}" # echo -e "${BLUE}NOTE:${NC} $1" log_message_nonl ${VERBOSITY_LEVEL} "${BLUE}!${NC} ${MSG}" } warn() { # echo -e "${YELLOW}WARN:${NC} $1" log_message 1 "${YELLOW}\xE2\x9A\xA0${NC} $1" } error() { # echo -e "${RED}ERROR:${NC} $1" log_message 0 "${RED}\xE2\x9D\x8C${NC} $1" } log() { VERBOSITY_LEVEL=${1} COLOR=${2} MSG="${@:3}" echo; repeat_char ${COLOR} '#'; msg ${1} ${MSG}; repeat_char ${COLOR} '#'; echo } ####################### # /Logging and Output # ####################### print_logo() { log_message "1" "" log_message "1" "Welcome to our" log_message "1" " " log_message "1" " _____ _ " log_message "1" " / ____| | | " log_message "1" " | (___ _ __ ___ __ __ __| | _ __ ___ _ __ " log_message "1" " \___ \ | '_ \ / _ \ \ \ /\ / / / _ | | __| / _ \ | \ _ \ " log_message "1" " ____) | | | | | | (_) | \ V V / | (_| | | | | (_) | | |_) |" log_message "1" " |_____/ |_| |_| \___/ \_/\_/ \__,_| |_| \___/ | __/ " log_message "1" " | | " log_message "1" " |_| " log_message "1" "Script to create/delete a Kubernetes cluster using kind like a : " log_message "1" "- ingress controller (nginx, kourier)" log_message "1" "" note "5" "Variables used:" note "5" "" note "5" "CLUSTER_NAME: ${CLUSTER_NAME}" note "5" "DELETE_KIND_CLUSTER: ${DELETE_KIND_CLUSTER}" note "5" "INGRESS: ${INGRESS}" note "5" "KNATIVE_VERSION: ${KNATIVE_VERSION}" note "5" "KUBERNETES_VERSION: ${KUBERNETES_VERSION}" note "5" "LOGGING_VERBOSITY: ${LOGGING_VERBOSITY}" note "5" "REGISTRY_PORT: ${REGISTRY_PORT}" note "5" "SECURE_REGISTRY: ${SECURE_REGISTRY}" note "5" "SERVER_IP: ${SERVER_IP}" note "5" "SHOW_HELP: ${SHOW_HELP}" note "5" "USE_EXISTING_CLUSTER: ${USE_EXISTING_CLUSTER}" } show_usage() { log_message "0" "" log_message "0" "Usage: " log_message "0" "\t./kind.sh command [parameters,...]" log_message "0" "" log_message "0" "Available commands: " log_message "0" "\tinstall\t\t\t\t\tInstall the kind cluster" log_message "0" "\tremove\t\t\t\t\tRemove the kind cluster" log_message "0" "" log_message "0" "Parameters: " log_message "0" "\t-h, --help\t\t\t\tThis help message" log_message "0" "" log_message "0" "\t--cluster-name <name>\t\t\tName of the cluster. Default: kind" log_message "0" "\t--delete-kind-cluster\t\t\tDeletes the Kind cluster prior to creating a new one. Default: No" log_message "0" "\t--ingress [nginx,kourier]\t\tIngress to be deployed. One of nginx,kourier. Default: nginx" log_message "0" "\t--ingress-ports httpPort:httpsPort\tIngress ports to be mapped. e.g. 'HttpPort:HttpsPort '" log_message "0" "\t\t\t\t\t\tngninx default: 80:443." log_message "0" "\t\t\t\t\t\tkourier default: 31080:31443." log_message "0" "\t--knative-version <version>\t\tKNative version to be used. Default: 1.9.0" log_message "0" "\t--kubernetes-version <version>\t\tKubernetes version to be install. Default: latest" log_message "0" "\t--provider <provider>\t\t\tContainer Runtime [docker,podman]. Default: docker" log_message "0" "\t--port-map <port map list>\t\tList of ports to map on kind config. e.g. 'ContainerPort1:HostPort1,ContainerPort2:HostPort2,...'" log_message "0" "\t--registry-image-version <version>\tVersion of the registry container to be used. Default: 2.6.2" log_message "0" "\t--registry-name <name>\t\t\tName of the registry. Default: <cluster_name>-registry" log_message "0" "\t--registry-password <password>\t\tRegistry user password. Default: snowdrop" log_message "0" "\t--registry-port <port>\t\t\tPort of the registry. Default: 5000" log_message "0" "\t--registry-user <user>\t\t\tRegistry user. Default: admin" log_message "0" "\t--secure-registry\t\t\tSecure the docker registry. Default: No" log_message "0" "\t--server-ip <ip-address>\t\tIP address to be used. Default: 127.0.0.1" log_message "0" "\t--skip-ingress-installation \t\tSkip the installation of an ingress. Default: No" log_message "0" "\t--use-existing-cluster\t\t\tUses existing kind cluster if it already exists. Default: No" log_message "0" "\t-v, --verbosity <value>\t\t\tLogging verbosity (0..9). Default: 1" log_message "0" "\t\t\t\t\t\tA verbosity setting of 0 logs only critical events." } check_pre_requisites() { note_start_task "1" "Checking pre requisites..." note_start_task "2" "Checking if jq exists..." if ! command -v jq &> /dev/null; then error "Checking if jq exists... jq is not installed !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" error "Use a package manager to install" exit 1 fi succeeded "2" "Checking if jq exists..." note_start_task "2" "Checking if kind exists..." if ! command -v kind &> /dev/null; then error "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" error "kind is not installed" error "Use a package manager (i.e 'brew install kind') or visit the official site https://kind.sigs.k8s.io" exit 1 fi succeeded "2" "Checking if kind exists..." note "2" "CRI Provider: ${CRI_PROVIDER}" if [ "${CRI_PROVIDER}" == 'docker' ]; then note_start_task "2" "Checking if docker exists..." if ! command -v docker &> /dev/null; then error "docker is not installed" error "Use a package manager (i.e. 'brew install docker') or visit the official site https://docs.docker.com/engine/install/" exit 1 fi case "$OSTYPE" in "linux-gnu"*) note_start_task "2" "Checking if docker exists..." set +e systemctl is-active --quiet service docker case "$?" in 0) succeeded "2" "Checking if docker service is started..." ;; *) error "docker service is not started" error "Start the service with 'sudo systemctl start docker'" exit 1 ;; esac set -e ;; esac; elif [ "${CRI_PROVIDER}" == 'podman' ]; then note_start_task "2" "Checking if podman exists..." if ! command -v podman &> /dev/null; then error "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" error "podman is not installed" error "Use a package manager (i.e. 'brew install podman') or visit the official site either https://podman.io/ or https://podman-desktop.io/" exit 1 fi succeeded "2" "Checking if docker exists..." fi if [ ${COMMAND} == "install" ]; then note_start_task "2" "Checking if kubectl exists... " if ! command -v kubectl &> /dev/null; then error "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" error "Please install kubectl 1.15 or higher" exit 1 fi succeeded "2" "" note_start_task "2" "Checking if helm exists... " if ! command -v helm &> /dev/null; then error "Checking if helm exists..." error "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" error "Helm could not be found. To get helm: https://helm.sh/docs/intro/install/" error "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" exit 1 fi succeeded "2" "Checking if helm exists... " note_start_task "2" "Checking helm version... " log_message "5" "helm version" HELM_VERSION=$(helm version 2>&1 | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+') || true if [[ ${HELM_VERSION} < "v3.0.0" ]]; then error "Checking helm version... Please upgrade helm to v3.0.0 or higher" exit 1 fi succeeded "2" "Checking helm version..." note_start_task "2" "Checking kubectl version... " log_message "5" "kubectl version -o json 2> /dev/null | jq -r '.clientVersion.gitVersion' | cut -d. -f2" KUBE_CLIENT_VERSION=$(kubectl version -o json 2> /dev/null | jq -r '.clientVersion.gitVersion' | cut -d. -f2) || true if [[ ${KUBE_CLIENT_VERSION} -lt 14 ]]; then error "Checking kubectl version... Please update kubectl to 1.15 or higher" exit 1 fi succeeded "2" "Checking kubectl version..." fi succeeded "1" "Pre requisites check passed!" } create_openssl_cfg() { CFG=$(cat <<EOF [req] distinguished_name = subject x509_extensions = x509_ext prompt = no [subject] C = BE ST = Namur L = Florennes O = Red Hat OU = Snowdrop CN = localhost [x509_ext] basicConstraints = critical, CA:TRUE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always, issuer:always keyUsage = critical, cRLSign, digitalSignature, keyCertSign nsComment = "OpenSSL Generated Certificate" subjectAltName = @alt_names [alt_names] DNS.1 = kind-registry DNS.2 = localhost DNS.3 = ${REGISTRY_NAME} EOF ) echo "$CFG" } # REMOVE delete_kind_cluster() { note_start_task "1" "Removing kind cluster (${CLUSTER_NAME})..." set +e ${KIND_COMMAND} delete cluster -n ${CLUSTER_NAME} -q case "$?" in 0) succeeded "1" "Removing kind cluster (${CLUSTER_NAME})..." ;; 130) warn "Removing kind cluster (${CLUSTER_NAME})... no cluster to be removed" ;; *) error "Removing kind cluster (${CLUSTER_NAME})... unsuccessful, try removing the cluster manually executing '${KIND_COMMAND} delete cluster -n ${CLUSTER_NAME}'" exit 1 ;; esac set -e SCRIPT_RESULT_MESSAGE+="\n" SCRIPT_RESULT_MESSAGE+=" * Kind cluster has been deleted \n" if [ "${CRI_COMMAND}" == 'podman' ]; then note_start_task "1" "Delete Podman Control Plane container..." podman_cp_container_name="${CLUSTER_NAME}-control-plane" podman_cp_container_id=$(${CRI_COMMAND} container ls --filter name=^${podman_cp_container_name}$ --all --quiet) if [ ! ${podman_cp_container_id} == "" ]; then ${CRI_COMMAND} container stop ${CLUSTER_NAME}-control-plane ${CRI_COMMAND} container rm ${CLUSTER_NAME}-control-plane succeeded "1" "Delete Podman Control Plane container..." else warn "Delete Podman Control Plane container... nothing to be done." fi SCRIPT_RESULT_MESSAGE+="\n" SCRIPT_RESULT_MESSAGE+=" * Podman Control Plane container has been deleted \n" fi } function delete_cri_resources(){ note_start_task "1" "Removing ${CRI_COMMAND} network..." docker_network_id=$(${CRI_COMMAND} network ls --filter name=^kind$ --quiet) if [ ! ${docker_network_id} == "" ]; then set +e NETWORK_RM_RES=eval ${NETWORK_RM_CMD} 1> /dev/null succeeded "1" "Removing ${CRI_COMMAND} network..." set -e else warn "Removing ${CRI_COMMAND} network... nothing to be done!" fi } # /REMOVE # INSTALL deploy_ingress_kourier() { note "1" "Deploying KNative Ingress" echo "Install the required custom resources of knative" kubectl apply -f https://github.com/knative/serving/releases/download/knative-v${KNATIVE_VERSION}/serving-crds.yaml note "1" "Install the core components of Knative Serving" kubectl apply -f https://github.com/knative/serving/releases/download/knative-v${KNATIVE_VERSION}/serving-core.yaml kubectl -n knative-serving rollout status deployment activator kubectl -n knative-serving rollout status deployment autoscaler kubectl -n knative-serving rollout status deployment controller kubectl -n knative-serving rollout status deployment domain-mapping kubectl -n knative-serving rollout status deployment domainmapping-webhook kubectl -n knative-serving rollout status deployment webhook note "1" "Install the Knative Kourier controller" kubectl apply -f https://github.com/knative/net-kourier/releases/download/knative-v${KNATIVE_VERSION}/kourier.yaml kubectl -n knative-serving rollout status deployment net-kourier-controller kubectl -n kourier-system rollout status deployment 3scale-kourier-gateway note "1" "Configure Knative Serving to use Kourier by default" kubectl patch configmap/config-network \ -n knative-serving \ --type merge \ -p '{"data":{"ingress-class":"kourier.ingress.networking.knative.dev"}}' note "1" "Configure the Knative domain to: $SERVER_IP.nip.io" KNATIVE_DOMAIN="${SERVER_IP}.nip.io" kubectl patch configmap/config-domain \ -n knative-serving \ -p "{\"data\": {\"$KNATIVE_DOMAIN\": \"\"}}" note "1" "Patching the kourier service to use the nodePort 31080 and type nodePort" kubectl patch -n kourier-system svc kourier --type='json' -p="[{\"op\": \"replace\", \"path\": \"/spec/ports/0/nodePort\", \"value\": ${INGRESS_80_CONTAINER_PORT}}]" kubectl patch -n kourier-system svc kourier --type='json' -p="[{\"op\": \"replace\", \"path\": \"/spec/ports/1/nodePort\", \"value\": ${INGRESS_443_CONTAINER_PORT}}]" kubectl patch -n kourier-system svc kourier --type='json' -p='[{"op": "replace", "path": "/spec/type", "value": "NodePort"}]' note "0" "####### TO TEST ########" note "0" "Execute the following commands: " knCmd="cat <<-EOF | kubectl apply -f - apiVersion: serving.knative.dev/v1 kind: Service metadata: name: hello spec: template: spec: containers: - image: gcr.io/knative-samples/helloworld-go env: - name: TARGET value: Go Hello example EOF" note "0" "$knCmd" note "0" "Then wait till the pods are created before to curl it: http://hello.default.${SERVER_IP}.nip.io" note "0" "Sometimes the revision hangs as deployment has been modified, then do" note "0" "kubectl scale --replicas=0 deployment/hello-00001-deployment" note "0" "kubectl scale --replicas=1 deployment/hello-00001-deployment" SCRIPT_RESULT_MESSAGE+="\n" SCRIPT_RESULT_MESSAGE+=" * Kourier Ingress has been deployed \n" } deploy_ingress_nginx() { note "1" "Deploying nginx Ingress..." # # Install the ingress nginx controller using helm # Set the Service type as: NodePort (needed for kind) # helm upgrade --install ingress-nginx ingress-nginx \ --repo https://kubernetes.github.io/ingress-nginx \ --namespace ingress --create-namespace \ --set controller.service.type=NodePort \ --set controller.hostPort.enabled=true \ --set controller.watchIngressWithoutClass=true succeeded "1" "Deploying nginx Ingress..." note "2" "Ingress controller installed within the namespace: ingress" SCRIPT_RESULT_MESSAGE+="\n" SCRIPT_RESULT_MESSAGE+=" * nginx Ingress has been deployed \n" } function configure_registry_on_kind() { # Document the local registry # https://github.com/kubernetes/enhancements/tree/master/keps/sig-cluster-lifecycle/generic/1755-communicating-a-local-registry cat <<EOF | kubectl apply -f - apiVersion: v1 kind: ConfigMap metadata: name: local-registry-hosting namespace: kube-public data: localRegistryHosting.v1: | host: "localhost:${REGISTRY_PORT}" help: "https://kind.sigs.k8s.io/docs/user/local-registry/" EOF } get_kind_cluster() { eval "$1=$(${KIND_COMMAND} get clusters | { grep "${CLUSTER_NAME}" || test $? = 1; })" } deploy_kind_cluster() { if [ "${SECURE_REGISTRY}" == 'y' ]; then if [ ! -d ${temp_cert_dir} ];then mkdir -p _tmp fi # Generate the Self signed certificate using openssl pushd $temp_cert_dir mkdir -p $HOME/.registry/certs/${REGISTRY_NAME} note "1" "==== Generate the openssl config" create_openssl_cfg > req.cnf note "1" "==== Create the self signed certificate certificate and client key files" openssl req -x509 \ -nodes \ -days 365 \ -newkey rsa:4096 \ -keyout $HOME/.registry/certs/${REGISTRY_NAME}/client.key \ -out $HOME/.registry/certs/${REGISTRY_NAME}/client.crt \ -config req.cnf \ -sha256 kindCfgContainerdConfigPatches=$(cat <<EOF - |- [plugins."io.containerd.grpc.v1.cri".registry.mirrors."${REGISTRY_NAME}:${REGISTRY_PORT}"] endpoint = ["https://${REGISTRY_NAME}:${REGISTRY_PORT}"] [plugins."io.containerd.grpc.v1.cri".registry.configs."${REGISTRY_NAME}:${REGISTRY_PORT}".tls] cert_file = "/etc/docker/certs.d/${REGISTRY_NAME}/client.crt" key_file = "/etc/docker/certs.d/${REGISTRY_NAME}/client.key" EOF ) kindCfgExtraMounts=$(cat <<EOF extraMounts: - containerPath: /etc/docker/certs.d/${REGISTRY_NAME} hostPath: $HOME/.registry/certs/${REGISTRY_NAME} EOF ) else kindCfgContainerdConfigPatches=$(cat <<EOF - |- [plugins."io.containerd.grpc.v1.cri".registry.mirrors."${REGISTRY_NAME}:${REGISTRY_PORT}"] endpoint = ["http://${REGISTRY_NAME}:${REGISTRY_PORT}"] EOF ) fi note "5" "1 INGRESS_80_CONTAINER_PORT: ${INGRESS_80_CONTAINER_PORT}" note "5" "1 INGRESS_443_CONTAINER_PORT: ${INGRESS_443_CONTAINER_PORT}" kindCmd="${KIND_COMMAND} -v ${LOGGING_VERBOSITY} create cluster -n ${CLUSTER_NAME}" kindExtraPortMappings=$(cat <<EOF - containerPort: ${INGRESS_80_CONTAINER_PORT} hostPort: ${INGRESS_80_CONTAINER_PORT} protocol: TCP listenAddress: "0.0.0.0" - containerPort: ${INGRESS_443_CONTAINER_PORT} hostPort: ${INGRESS_443_CONTAINER_PORT} protocol: TCP listenAddress: "0.0.0.0" EOF ) note "5" "extraPortMappings: ${kindExtraPortMappings}" IFS=',' read -ra ADDR <<< "${PORT_MAP}" for i in "${ADDR[@]}"; do IFS=':' read -ra PORTS <<< "${i}" kindExtraPortMappings+=$(cat <<EOF - containerPort: ${PORTS[0]} hostPort: ${PORTS[1]} protocol: TCP listenAddress: "0.0.0.0" EOF ) done note "5" "extraPortMappings: ${kindExtraPortMappings}" # Kind cluster config template kindCfg=$(cat <<EOF kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 networking: apiServerAddress: "${SERVER_IP}" containerdConfigPatches: ${kindCfgContainerdConfigPatches} nodes: - role: control-plane kubeadmConfigPatches: - | kind: InitConfiguration nodeRegistration: kubeletExtraArgs: node-labels: "ingress-ready=true" authorization-mode: "AlwaysAllow" ${kindCfgExtraMounts} extraPortMappings: ${kindExtraPortMappings} EOF ) note "5" "kindCfg: ${kindCfg}" if [ "$DELETE_KIND_CLUSTER" == "y" ]; then note "0" "Deleting Kind cluster..." delete_kind_cluster succeeded "1" "...done!" fi note "1" "Checking if kind cluster exists..." kind_get_clusters=$(${KIND_COMMAND} get clusters | { grep "${CLUSTER_NAME}" || test $? = 1; }) if [ ! "${kind_get_clusters}" == "" ]; then note "1" "Cluster already exists..." if [ "$USE_EXISTING_CLUSTER" == "y" ]; then note "1" "...using existing cluster. Exporting cluster kubeconfig..." note "5" "CMD: kind export kubeconfig -n ${CLUSTER_NAME}" ${KIND_COMMAND} export kubeconfig -n ${CLUSTER_NAME} succeeded "1" "...done!" else error "Cluster already exists. Either use the existing cluster (--use-existing-cluster) or delete the cluster (--delete-kind-cluster)." exit 1 fi else note "5" "=== Get the tag version of the image to be installed for the kubernetes version: ${KUBERNETES_VERSION} ..." if [ ${KUBERNETES_VERSION} == "latest" ]; then kindCmd+="" else kind_image_sha=$(wget -q https://raw.githubusercontent.com/snowdrop/k8s-infra/main/kind/images.json -O - | \ jq -r --arg VERSION "$KUBERNETES_VERSION" '.[] | select(.k8s == $VERSION).sha') kindCmd+=" --image ${kind_image_sha}" fi note "5" "Creating a Kind cluster using kindest/node: ${KUBERNETES_VERSION} and logging verbosity: ${LOGGING_VERBOSITY}" echo "${kindCfg}" | ${kindCmd} --config=- if [ "${CRI_PROVIDER}" == 'podman' ]; then sudo -E kind get kubeconfig > ${HOME}/.kube/config fi fi set +e note_start_task "2" "Connect the container registry to the kind network..." ${CRI_COMMAND} network connect "kind" ${REGISTRY_NAME} succeeded "2" "Connect the container registry to the kind network... done." set -e SCRIPT_RESULT_MESSAGE+="\n" SCRIPT_RESULT_MESSAGE+=" * ${CLUSTER_NAME} kind cluster has been deployed\n" SCRIPT_RESULT_MESSAGE+="\n" SCRIPT_RESULT_MESSAGE+=" * Cluster configuration has been copied to ${HOME}/.kube/config\n" SCRIPT_RESULT_MESSAGE+="\n" SCRIPT_RESULT_MESSAGE+=" * Execute 'kind get kubeconfig --name ${CLUSTER_NAME}' to obtain the cluster configuration\n" } function install() { deploy_kind_cluster configure_registry_on_kind if [ "${SKIP_INGRESS_INSTALLATION}" == 'n' ]; then if [ "${INGRESS}" == 'kourier' ]; then deploy_ingress_kourier elif [ "${INGRESS}" == 'nginx' ]; then deploy_ingress_nginx fi fi } function remove() { delete_kind_cluster delete_cri_resources } function validate_ingress() { if [ "${INGRESS}" == 'kourier' ]; then INGRESS_80_CONTAINER_PORT=31080 INGRESS_443_CONTAINER_PORT=31443 elif [ "${INGRESS}" == 'nginx' ]; then INGRESS_80_CONTAINER_PORT=80 INGRESS_443_CONTAINER_PORT=443 else error "Invalid ingress ${INGRESS}, choose one of nginx or kourier." show_usage exit 1 fi note "5" "INGRESS_80_CONTAINER_PORT: ${INGRESS_80_CONTAINER_PORT}" note "5" "INGRESS_443_CONTAINER_PORT: ${INGRESS_443_CONTAINER_PORT}" note "5" "Ingress ports: ${INGRESS_PORTS}" if [ "${INGRESS_PORTS}" == "" ]; then if [ "${INGRESS}" == 'kourier' ]; then INGRESS_80_CONTAINER_PORT=31080 INGRESS_443_CONTAINER_PORT=31443 elif [ "${INGRESS}" == 'nginx' ]; then INGRESS_80_CONTAINER_PORT=80 INGRESS_443_CONTAINER_PORT=443 fi else IFS=':' read -ra PORT_MAP <<< "${INGRESS_PORTS}" INGRESS_80_CONTAINER_PORT=${PORT_MAP[0]} INGRESS_443_CONTAINER_PORT=${PORT_MAP[1]} fi note "5" "Ingress ports: ${INGRESS_80_CONTAINER_PORT}:${INGRESS_443_CONTAINER_PORT}" } function validate_cri() { note "2" "CRI Provider: ${CRI_PROVIDER}" if [ "${CRI_PROVIDER}" == 'docker' ]; then CRI_COMMAND="docker" KIND_COMMAND=kind unset KIND_EXPERIMENTAL_PROVIDER HOST_80_PORT=80 HOST_443_PORT=443 elif [ "${CRI_PROVIDER}" == 'podman' ]; then CRI_COMMAND="sudo podman" # WARN: NO SUPPORT FOR ROOTLESS PODMAN CONTAINERS YET KIND_COMMAND="sudo --preserve-env kind" export KIND_EXPERIMENTAL_PROVIDER=podman HOST_80_PORT=30080 HOST_443_PORT=30443 else error "Invalid CRI provider ${CRI_PROVIDER}." show_usage exit 1 fi } function check_os() { case "$OSTYPE" in "linux-gnu"*) DOCKER_RESTART_COMMAND="sudo systemctl restart docker" NETWORK_RM_CMD="${CRI_COMMAND} network rm -f kind" ;; "darwin"*) # DOCKER_RESTART_COMMAND='echo -e "${YELLOW}\xE2\x9A\xA0 : Script paused to Restart the Docker service manually. ${NC}" ; read -n1 -s -r -p $"Press any key to continue..." key' DOCKER_RESTART_COMMAND='echo ""' NETWORK_RM_CMD="${CRI_COMMAND} network rm kind" ;; *) error "Unknown OS"; exit 1 ;; esac; note "5" "${DOCKER_RESTART_COMMAND}" # if [ "$OSTYPE" == "linux-gnu"* ]; then # # DOCKER_RESTART_COMMAND="sudo systemctl restart docker" # DOCKER_RESTART_COMMAND="read -n1 -s -r -p $'${YELLOW}\xE2\x9A\xA0: script paused to Restart the Docker service manually, press any key to continue...!${NC}' key" # elif [ "$OSTYPE" == "darwin"* ]; then # # Mac OSX # DOCKER_RESTART_COMMAND="read -n1 -s -r -p $'${YELLOW}\xE2\x9A\xA0: script paused to Restart the Docker service manually, press any key to continue...!${NC}' key" # # elif [ "$OSTYPE" == "cygwin" ]; then # # # POSIX compatibility layer and Linux environment emulation for Windows # # elif [ "$OSTYPE" == "msys" ]; then # # # Lightweight shell and GNU utilities compiled for Windows (part of MinGW) # # elif [ "$OSTYPE" == "win32" ]; then # # # I'm not sure this can happen. # elif [ "$OSTYPE" == "freebsd"* ]; then # # ... # else # # Unknown. # fi } ##### /Functions ###### Command Line Parser CLUSTER_NAME="kind" CRI_PROVIDER=docker CRI_COMMAND=docker DELETE_KIND_CLUSTER="n" INGRESS="nginx" KIND_COMMAND=kind KNATIVE_VERSION="1.9.0" KUBERNETES_VERSION="latest" LOGGING_VERBOSITY="1" REGISTRY_PORT="5000" SCRIPT_RESULT_MESSAGE="" SCRIPT_REQUIRED_STEPS="" SKIP_INGRESS_INSTALLATION="n" SECURE_REGISTRY="n" SERVER_IP="127.0.0.1" SHOW_HELP="n" USE_EXISTING_CLUSTER="n" PORT_MAP="" set +e while [ $# -gt 0 ]; do note "9" "$1" if [[ $1 == "--"* ]]; then param="${1/--/}"; case $1 in --help) SHOW_HELP="y"; break 2 ;; --cluster-name) CLUSTER_NAME="$2"; shift ;; --delete-kind-cluster) DELETE_KIND_CLUSTER="y" ;; --ingress) INGRESS="$2"; shift ;; --ingress-ports) INGRESS_PORTS="$2"; shift ;; --knative-version) KNATIVE_VERSION="$2"; shift ;; --kubernetes-version) KUBERNETES_VERSION="$2"; shift ;; --provider) CRI_PROVIDER="$2"; shift ;; --port-map) PORT_MAP="$2"; shift ;; --registry-name) REGISTRY_NAME="$2"; shift ;; --registry-port) REGISTRY_PORT="$2"; shift ;; --secure-registry) SECURE_REGISTRY="y" ;; --skip-ingress-installation) SKIP_INGRESS_INSTALLATION="y" ;; --server-ip) SERVER_IP="$2"; shift ;; --use-existing-cluster) USE_EXISTING_CLUSTER="y"; ;; --verbosity) LOGGING_VERBOSITY="$2"; shift ;; *) INVALID_SWITCH="${INVALID_SWITCH} $1" ; break 2 ;; esac; shift elif [[ $1 == "-"* ]]; then case $1 in -h) SHOW_HELP="y"; break 2 ;; -v) LOGGING_VERBOSITY="$2"; shift ;; *) INVALID_SWITCH="${INVALID_SWITCH} $1" ; break 2 ;; esac; shift else case $1 in install) COMMAND="install" ;; remove) COMMAND="remove" ;; *) INVALID_COMMAND="${INVALID_COMMAND} $1" ; break 2 ;; esac; shift fi done set -e if [ "$SHOW_HELP" == "y" ]; then show_usage exit 0 elif ! [ -z ${INVALID_COMMAND+x} ]; then error "Invalid command ${INVALID_COMMAND}" show_usage exit 1 elif ! [ -z ${INVALID_SWITCH+x} ]; then error "Invalid switch(es) ${INVALID_SWITCH}" show_usage exit 1 elif [ -z ${COMMAND+x} ]; then error "A command must be provided!!!" show_usage exit 1 elif [ ${COMMAND} == 'install' ] && [ -z ${INGRESS+x} ]; then error "The Ingress controller to be installed is not defined (nginx, kourier)." show_usage exit 1 fi case ${COMMAND} in install) validate_ingress ;; esac; if [ "$REGISTRY_NAME" == "" ]; then REGISTRY_NAME="${CLUSTER_NAME}-registry" fi note "5" "REGISTRY_NAME: ${REGISTRY_NAME}" ###### /Command Line Parser ###### Execution check_os print_logo check_pre_requisites validate_cri kindCfgExtraMounts="" temp_cert_dir="_tmp" case ${COMMAND} in install) validate_ingress note "5" "PORT_MAP: ${PORT_MAP}" install log_message "0" "" log_message "0" "" succeeded "0" " ################### Installation completed! ###################" SCRIPT_REQUIRED_STEPS+="\n" SCRIPT_REQUIRED_STEPS+=" * Add to your /etc/hosts file: 127.0.0.1 localhost ${REGISTRY_NAME}\n" SCRIPT_REQUIRED_STEPS+="\n" SCRIPT_REQUIRED_STEPS+=" * To avoid to get a permission denied on the mounted volume /certs, disable SELINUX=disabled within the file /etc/selinux/config and reboot !\n" SCRIPT_RESULT_MESSAGE+="\n" SCRIPT_RESULT_MESSAGE+=" * You can test the container registry using the instructions from: https://github.com/snowdrop/k8s-infra/blob/main/kind/README.adoc#container-registry\n" log_message "0" " ### Installation resume: " log_message "0" "${SCRIPT_RESULT_MESSAGE}" log_message "0" " ### Required steps: " log_message "0" "${SCRIPT_REQUIRED_STEPS}" ;; remove) remove SCRIPT_REQUIRED_STEPS+="\n" SCRIPT_REQUIRED_STEPS+=" * Check your /etc/hosts file and remove references to the ${REGISTRY_NAME} container registry container.\n" log_message "0" "" log_message "0" "" succeeded "0" " ################### Removal completed! ###################" log_message "0" " ### Removal resume: " log_message "0" "${SCRIPT_RESULT_MESSAGE}" log_message "0" " ### Required steps: " log_message "0" "${SCRIPT_REQUIRED_STEPS}" ;; esac;