Skip to content

Instantly share code, notes, and snippets.

@squeed
Created April 12, 2022 09:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save squeed/810c630d749c6780ba40063cc495cf69 to your computer and use it in GitHub Desktop.
Save squeed/810c630d749c6780ba40063cc495cf69 to your computer and use it in GitHub Desktop.
ovnk-kind-podman.sh
#!/usr/bin/env bash
# usage
# cd contrib; ./kind-podman.sh -ep 'sudo podman' -kb 'sudo kind' -gm shared
# Returns the full directory name of the script
DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
run_kubectl() {
local retries=0
local attempts=10
while true; do
if kubectl "$@"; then
break
fi
((retries += 1))
if [[ "${retries}" -gt ${attempts} ]]; then
echo "error: 'kubectl $*' did not succeed, failing"
exit 1
fi
echo "info: waiting for 'kubectl $*' to succeed..."
sleep 1
done
}
# Some environments (Fedora32,31 on desktop), have problems when the cluster
# is deleted directly with kind `kind delete cluster --name ovn`, it restarts the host.
# The root cause is unknown, this also can not be reproduced in Ubuntu 20.04 or
# with Fedora32 Cloud, but it does not happen if we clean first the ovn-kubernetes resources.
delete() {
timeout 5 kubectl --kubeconfig "${KUBECONFIG}" delete namespace ovn-kubernetes || true
sleep 5
${KIND_BINARY} delete cluster --name "${KIND_CLUSTER_NAME:-ovn}"
}
usage() {
echo "usage: kind.sh [[[-cf |--config-file <file>] [-kt|--keep-taint] [-ha|--ha-enabled]"
echo " [-ho |--hybrid-enabled] [-ii|--install-ingress] [-n4|--no-ipv4]"
echo " [-i6 |--ipv6] [-wk|--num-workers <num>] [-ds|--disable-snat-multiple-gws]"
echo " [-dp |--disable-pkt-mtu-check]"
echo " [-nf |--netflow-targets <targets>] [sf|--sflow-targets <targets>]"
echo " [-if |--ipfix-targets <targets>] [-ifs|--ipfix-sampling <num>]"
echo " [-ifm|--ipfix-cache-max-flows <num>] [-ifa|--ipfix-cache-active-timeout <num>]"
echo " [-sw |--allow-system-writes] [-gm|--gateway-mode <mode>]"
echo " [-nl |--node-loglevel <num>] [-ml|--master-loglevel <num>]"
echo " [-dbl|--dbchecker-loglevel <num>] [-ndl|--ovn-loglevel-northd <loglevel>]"
echo " [-nbl|--ovn-loglevel-nb <loglevel>] [-sbl|--ovn-loglevel-sb <loglevel>]"
echo " [-cl |--ovn-loglevel-controller <loglevel>] [-dl|--ovn-loglevel-nbctld <loglevel>]"
echo " [-ep |--experimental-provider <name>] |"
echo " [-eb |--egress-gw-separate-bridge] |"
echo " [-lr |--local-kind-registry |"
echo " [-dd |--dns-domain |"
echo " [-ric | --run-in-container |"
echo " [-cn | --cluster-name |"
echo " [-h]]"
echo ""
echo "-cf | --config-file Name of the KIND J2 configuration file."
echo " DEFAULT: ./kind.yaml.j2"
echo "-kt | --keep-taint Do not remove taint components."
echo " DEFAULT: Remove taint components."
echo "-ha | --ha-enabled Enable high availability. DEFAULT: HA Disabled."
echo "-ho | --hybrid-enabled Enable hybrid overlay. DEFAULT: Disabled."
echo "-ds | --disable-snat-multiple-gws Disable SNAT for multiple gws. DEFAULT: Disabled."
echo "-dp | --disable-pkt-mtu-check Disable checking packet size greater than MTU. Default: Disabled"
echo "-nf | --netflow-targets Comma delimited list of ip:port or :port (using node IP) netflow collectors. DEFAULT: Disabled."
echo "-sf | --sflow-targets Comma delimited list of ip:port or :port (using node IP) sflow collectors. DEFAULT: Disabled."
echo "-if | --ipfix-targets Comma delimited list of ip:port or :port (using node IP) ipfix collectors. DEFAULT: Disabled."
echo "-ifs | --ipfix-sampling Fraction of packets that are sampled and sent to each target collector: 1 packet out of every <num>. DEFAULT: 400 (1 out of 400 packets)."
echo "-ifm | --ipfix-cache-max-flows Maximum number of IPFIX flow records that can be cached at a time. If 0, caching is disabled. DEFAULT: Disabled."
echo "-ifa | --ipfix-cache-active-timeout Maximum period in seconds for which an IPFIX flow record is cached and aggregated before being sent. If 0, caching is disabled. DEFAULT: 60."
echo "-el | --ovn-empty-lb-events Enable empty-lb-events generation for LB without backends. DEFAULT: Disabled"
echo "-ii | --install-ingress Flag to install Ingress Components."
echo " DEFAULT: Don't install ingress components."
echo "-n4 | --no-ipv4 Disable IPv4. DEFAULT: IPv4 Enabled."
echo "-i6 | --ipv6 Enable IPv6. DEFAULT: IPv6 Disabled."
echo "-wk | --num-workers Number of worker nodes. DEFAULT: HA - 2 worker"
echo " nodes and no HA - 0 worker nodes."
echo "-sw | --allow-system-writes Allow script to update system. Intended to allow"
echo " github CI to be updated with IPv6 settings."
echo " DEFAULT: Don't allow."
echo "-gm | --gateway-mode Enable 'shared' or 'local' gateway mode."
echo " DEFAULT: shared."
echo "-ov | --ovn-image Use the specified docker image instead of building locally. DEFAULT: local build."
echo "-ml | --master-loglevel Log level for ovnkube (master), DEFAULT: 5."
echo "-nl | --node-loglevel Log level for ovnkube (node), DEFAULT: 5"
echo "-dbl | --dbchecker-loglevel Log level for ovn-dbchecker (ovnkube-db), DEFAULT: 5."
echo "-ndl | --ovn-loglevel-northd Log config for ovn northd, DEFAULT: '-vconsole:info -vfile:info'."
echo "-nbl | --ovn-loglevel-nb Log config for northbound DB DEFAULT: '-vconsole:info -vfile:info'."
echo "-sbl | --ovn-loglevel-sb Log config for southboudn DB DEFAULT: '-vconsole:info -vfile:info'."
echo "-cl | --ovn-loglevel-controller Log config for ovn-controller DEFAULT: '-vconsole:info'."
echo "-dl | --ovn-loglevel-nbctld Log config for nbctl daemon DEFAULT: '-vconsole:info'."
echo "-ep | --experimental-provider Use an experimental OCI provider such as podman, instead of docker. DEFAULT: Disabled."
echo "-eb | --egress-gw-separate-bridge The external gateway traffic uses a separate bridge."
echo "-lr | --local-kind-registry Configure kind to use a local docker registry rather than manually loading images"
echo "-dd | --dns-domain Configure a custom dnsDomain for k8s services, Defaults to 'cluster.local'"
echo "-cn | --cluster-name Configure the kind cluster's name"
echo "-ric | --run-in-container Configure the script to be run from a docker container, allowing it to still communcate with the kind controlplane"
echo "-kb | --kind-binary The kind binary to use"
echo "--delete Delete current cluster"
echo ""
}
parse_args() {
while [ "$1" != "" ]; do
case $1 in
-cf | --config-file ) shift
if test ! -f "$1"; then
echo "$1 does not exist"
usage
exit 1
fi
KIND_CONFIG=$1
;;
-ii | --install-ingress ) KIND_INSTALL_INGRESS=true
;;
-ha | --ha-enabled ) OVN_HA=true
;;
-me | --multicast-enabled) OVN_MULTICAST_ENABLE=true
;;
-ho | --hybrid-enabled ) OVN_HYBRID_OVERLAY_ENABLE=true
;;
-ds | --disable-snat-multiple-gws ) OVN_DISABLE_SNAT_MULTIPLE_GWS=true
;;
-dp | --disable-pkt-mtu-check ) OVN_DISABLE_PKT_MTU_CHECK=true
;;
-ep | --experimental-provider ) shift
export KIND_EXPERIMENTAL_PROVIDER=$1
;;
-nf | --netflow-targets ) shift
OVN_NETFLOW_TARGETS=$1
;;
-sf | --sflow-targets ) shift
OVN_SFLOW_TARGETS=$1
;;
-if | --ipfix-targets ) shift
OVN_IPFIX_TARGETS=$1
;;
-ifs | --ipfix-sampling ) shift
OVN_IPFIX_SAMPLING=$1
;;
-ifm | --ipfix-cache-max-flows ) shift
OVN_IPFIX_CACHE_MAX_FLOWS=$1
;;
-ifa | --ipfix-cache-active-timeout ) shift
OVN_IPFIX_CACHE_ACTIVE_TIMEOUT=$1
;;
-el | --ovn-empty-lb-events ) OVN_EMPTY_LB_EVENTS=true
;;
-kt | --keep-taint ) KIND_REMOVE_TAINT=false
;;
-n4 | --no-ipv4 ) KIND_IPV4_SUPPORT=false
;;
-i6 | --ipv6 ) KIND_IPV6_SUPPORT=true
;;
-wk | --num-workers ) shift
if ! [[ "$1" =~ ^[0-9]+$ ]]; then
echo "Invalid num-workers: $1"
usage
exit 1
fi
KIND_NUM_WORKER=$1
;;
-sw | --allow-system-writes ) KIND_ALLOW_SYSTEM_WRITES=true
;;
-gm | --gateway-mode ) shift
if [ "$1" != "local" ] && [ "$1" != "shared" ]; then
echo "Invalid gateway mode: $1"
usage
exit 1
fi
OVN_GATEWAY_MODE=$1
;;
-ov | --ovn-image ) shift
OVN_IMAGE=$1
;;
-ml | --master-loglevel ) shift
if ! [[ "$1" =~ ^[0-9]$ ]]; then
echo "Invalid master-loglevel: $1"
usage
exit 1
fi
MASTER_LOG_LEVEL=$1
;;
-nl | --node-loglevel ) shift
if ! [[ "$1" =~ ^[0-9]$ ]]; then
echo "Invalid node-loglevel: $1"
usage
exit 1
fi
NODE_LOG_LEVEL=$1
;;
-dbl | --dbchecker-loglevel ) shift
if ! [[ "$1" =~ ^[0-9]$ ]]; then
echo "Invalid dbchecker-loglevel: $1"
usage
exit 1
fi
DBCHECKER_LOG_LEVEL=$1
;;
-eb | --egress-gw-separate-bridge ) OVN_ENABLE_EX_GW_NETWORK_BRIDGE=true
;;
-ndl | --ovn-loglevel-northd ) shift
OVN_LOG_LEVEL_NORTHD=$1
;;
-nbl | --ovn-loglevel-nb ) shift
OVN_LOG_LEVEL_NB=$1
;;
-sbl | --ovn-loglevel-sb ) shift
OVN_LOG_LEVEL_SB=$1
;;
-cl | --ovn-loglevel-controller ) shift
OVN_LOG_LEVEL_CONTROLLER=$1
;;
-dl | --ovn-loglevel-nbctld ) shift
OVN_LOG_LEVEL_NBCTLD=$1
;;
-hns | --host-network-namespace ) OVN_HOST_NETWORK_NAMESPACE=$1
;;
-lr | --local-kind-registry ) KIND_LOCAL_REGISTRY=true
;;
-dd | --dns-domain ) shift
KIND_DNS_DOMAIN=$1
;;
-cn | --cluster-name ) shift
KIND_CLUSTER_NAME=$1
;;
-kc | --kubeconfig ) shift
KUBECONFIG=$1
;;
-kb | --kind-binary ) shift
KIND_BINARY=$1
;;
-ric | --run-in-container ) RUN_IN_CONTAINER=true
;;
--delete ) delete
exit
;;
-h | --help ) usage
exit
;;
* ) usage
exit 1
esac
shift
done
}
print_params() {
echo "Using these parameters to install KIND"
echo ""
echo "KUBECONFIG = $KUBECONFIG"
echo "MANIFEST_OUTPUT_DIR = $MANIFEST_OUTPUT_DIR"
echo "KIND_INSTALL_INGRESS = $KIND_INSTALL_INGRESS"
echo "OVN_HA = $OVN_HA"
echo "RUN_IN_CONTAINER = $RUN_IN_CONTAINER"
echo "KIND_CLUSTER_NAME = $KIND_CLUSTER_NAME"
echo "KIND_LOCAL_REGISTRY = $KIND_LOCAL_REGISTRY"
echo "KIND_DNS_DOMAIN = $KIND_DNS_DOMAIN"
echo "KIND_CONFIG_FILE = $KIND_CONFIG"
echo "KIND_REMOVE_TAINT = $KIND_REMOVE_TAINT"
echo "KIND_IPV4_SUPPORT = $KIND_IPV4_SUPPORT"
echo "KIND_IPV6_SUPPORT = $KIND_IPV6_SUPPORT"
echo "KIND_NUM_WORKER = $KIND_NUM_WORKER"
echo "KIND_BINARY = $KIND_BINARY"
echo "KIND_ALLOW_SYSTEM_WRITES = $KIND_ALLOW_SYSTEM_WRITES"
echo "KIND_EXPERIMENTAL_PROVIDER = $KIND_EXPERIMENTAL_PROVIDER"
echo "OVN_GATEWAY_MODE = $OVN_GATEWAY_MODE"
echo "OVN_HYBRID_OVERLAY_ENABLE = $OVN_HYBRID_OVERLAY_ENABLE"
echo "OVN_DISABLE_SNAT_MULTIPLE_GWS = $OVN_DISABLE_SNAT_MULTIPLE_GWS"
echo "OVN_DISABLE_PKT_MTU_CHECK = $OVN_DISABLE_PKT_MTU_CHECK"
echo "OVN_NETFLOW_TARGETS = $OVN_NETFLOW_TARGETS"
echo "OVN_SFLOW_TARGETS = $OVN_SFLOW_TARGETS"
echo "OVN_IPFIX_TARGETS = $OVN_IPFIX_TARGETS"
echo "OVN_IPFIX_SAMPLING = $OVN_IPFIX_SAMPLING"
echo "OVN_IPFIX_CACHE_MAX_FLOWS = $OVN_IPFIX_CACHE_MAX_FLOWS"
echo "OVN_IPFIX_CACHE_ACTIVE_TIMEOUT = $OVN_IPFIX_CACHE_ACTIVE_TIMEOUT"
echo "OVN_EMPTY_LB_EVENTS = $OVN_EMPTY_LB_EVENTS"
echo "OVN_MULTICAST_ENABLE = $OVN_MULTICAST_ENABLE"
echo "OVN_IMAGE = $OVN_IMAGE"
echo "MASTER_LOG_LEVEL = $MASTER_LOG_LEVEL"
echo "NODE_LOG_LEVEL = $NODE_LOG_LEVEL"
echo "DBCHECKER_LOG_LEVEL = $DBCHECKER_LOG_LEVEL"
echo "OVN_LOG_LEVEL_NORTHD = $OVN_LOG_LEVEL_NORTHD"
echo "OVN_LOG_LEVEL_NB = $OVN_LOG_LEVEL_NB"
echo "OVN_LOG_LEVEL_SB = $OVN_LOG_LEVEL_SB"
echo "OVN_LOG_LEVEL_CONTROLLER = $OVN_LOG_LEVEL_CONTROLLER"
echo "OVN_LOG_LEVEL_NBCTLD = $OVN_LOG_LEVEL_NBCTLD"
echo "OVN_HOST_NETWORK_NAMESPACE = $OVN_HOST_NETWORK_NAMESPACE"
echo "OVN_ENABLE_EX_GW_NETWORK_BRIDGE = $OVN_ENABLE_EX_GW_NETWORK_BRIDGE"
echo "OVN_EX_GW_NETWORK_INTERFACE = $OVN_EX_GW_NETWORK_INTERFACE"
echo ""
}
command_exists() {
cmd="$1"
command -v ${cmd} >/dev/null 2>&1
}
install_j2_renderer() {
# ensure j2 renderer installed
pip install wheel --user
pip freeze | grep j2cli || pip install j2cli[yaml] --user
export PATH=~/.local/bin:$PATH
}
check_dependencies() {
if ! command_exists kind ; then
echo "Dependency not met: Command not found 'kind'"
exit 1
fi
if ! command_exists jq ; then
echo "Dependency not met: Command not found 'jq'"
exit 1
fi
if ! command_exists j2 ; then
if ! command_exists pip ; then
echo "Dependency not met: 'j2' not installed and cannot install with 'pip'"
exit 1
fi
echo "'j2' not found, installing with 'pip'"
install_j2_renderer
fi
if ! command_exists docker && ! command_exists podman; then
echo "Dependency not met: Neither docker nor podman found"
exit 1
fi
}
set_default_params() {
# Set default values
# Used for multi cluster setups
KIND_CLUSTER_NAME=${KIND_CLUSTER_NAME:-ovn}
# Setup KUBECONFIG patch based on cluster-name
export KUBECONFIG=${KUBECONFIG:-${HOME}/${KIND_CLUSTER_NAME}.conf}
# Scrub any existing kubeconfigs at the path
rm -f ${KUBECONFIG}
MANIFEST_OUTPUT_DIR=${MANIFEST_OUTPUT_DIR:-${DIR}/../dist/yaml}
if [ ${KIND_CLUSTER_NAME} != "ovn" ]; then
MANIFEST_OUTPUT_DIR="${DIR}/../dist/yaml/${KIND_CLUSTER_NAME}"
fi
RUN_IN_CONTAINER=${RUN_IN_CONTAINER:-false}
KIND_IMAGE=${KIND_IMAGE:-kindest/node}
K8S_VERSION=${K8S_VERSION:-v1.23.3}
OVN_GATEWAY_MODE=${OVN_GATEWAY_MODE:-shared}
KIND_INSTALL_INGRESS=${KIND_INSTALL_INGRESS:-false}
OVN_HA=${OVN_HA:-false}
KIND_LOCAL_REGISTRY=${KIND_LOCAL_REGISTRY:-false}
KIND_DNS_DOMAIN=${KIND_DNS_DOMAIN:-"cluster.local"}
KIND_CONFIG=${KIND_CONFIG:-${DIR}/kind.yaml.j2}
KIND_REMOVE_TAINT=${KIND_REMOVE_TAINT:-true}
KIND_IPV4_SUPPORT=${KIND_IPV4_SUPPORT:-true}
KIND_IPV6_SUPPORT=${KIND_IPV6_SUPPORT:-false}
OVN_HYBRID_OVERLAY_ENABLE=${OVN_HYBRID_OVERLAY_ENABLE:-false}
OVN_DISABLE_SNAT_MULTIPLE_GWS=${OVN_DISABLE_SNAT_MULTIPLE_GWS:-false}
OVN_DISABLE_PKT_MTU_CHECK=${OVN_DISABLE_PKT_MTU_CHECK:-false}
OVN_EMPTY_LB_EVENTS=${OVN_EMPTY_LB_EVENTS:-false}
OVN_MULTICAST_ENABLE=${OVN_MULTICAST_ENABLE:-false}
KIND_ALLOW_SYSTEM_WRITES=${KIND_ALLOW_SYSTEM_WRITES:-false}
OVN_IMAGE=${OVN_IMAGE:-local}
MASTER_LOG_LEVEL=${MASTER_LOG_LEVEL:-5}
NODE_LOG_LEVEL=${NODE_LOG_LEVEL:-5}
DBCHECKER_LOG_LEVEL=${DBCHECKER_LOG_LEVEL:-5}
OVN_LOG_LEVEL_NORTHD=${OVN_LOG_LEVEL_NORTHD:-"-vconsole:info -vfile:info"}
OVN_LOG_LEVEL_NB=${OVN_LOG_LEVEL_NB:-"-vconsole:info -vfile:info"}
OVN_LOG_LEVEL_SB=${OVN_LOG_LEVEL_SB:-"-vconsole:info -vfile:info"}
OVN_LOG_LEVEL_CONTROLLER=${OVN_LOG_LEVEL_CONTROLLER:-"-vconsole:info"}
OVN_LOG_LEVEL_NBCTLD=${OVN_LOG_LEVEL_NBCTLD:-"-vconsole:info"}
OVN_ENABLE_EX_GW_NETWORK_BRIDGE=${OVN_ENABLE_EX_GW_NETWORK_BRIDGE:-false}
OVN_EX_GW_NETWORK_INTERFACE=""
if [ "$OVN_ENABLE_EX_GW_NETWORK_BRIDGE" == true ]; then
OVN_EX_GW_NETWORK_INTERFACE="eth1"
fi
# Input not currently validated. Modify outside script at your own risk.
# These are the same values defaulted to in KIND code (kind/default.go).
# NOTE: KIND NET_CIDR_IPV6 default use a /64 but OVN have a /64 per host
# so it needs to use a larger subnet
# Upstream - NET_CIDR_IPV6=fd00:10:244::/64 SVC_CIDR_IPV6=fd00:10:96::/112
NET_CIDR_IPV4=${NET_CIDR_IPV4:-10.244.0.0/16}
NET_SECOND_CIDR_IPV4=${NET_SECOND_CIDR_IPV4:-172.19.0.0/16}
SVC_CIDR_IPV4=${SVC_CIDR_IPV4:-10.96.0.0/16}
NET_CIDR_IPV6=${NET_CIDR_IPV6:-fd00:10:244::/48}
SVC_CIDR_IPV6=${SVC_CIDR_IPV6:-fd00:10:96::/112}
JOIN_SUBNET_IPV4=${JOIN_SUBNET_IPV4:-100.64.0.0/16}
JOIN_SUBNET_IPV6=${JOIN_SUBNET_IPV6:-fd98::/64}
KIND_NUM_MASTER=1
if [ "$OVN_HA" == true ]; then
KIND_NUM_MASTER=3
KIND_NUM_WORKER=${KIND_NUM_WORKER:-0}
else
KIND_NUM_WORKER=${KIND_NUM_WORKER:-2}
fi
KIND_BINARY="${KIND_BINARY:-kind}"
OVN_HOST_NETWORK_NAMESPACE=${OVN_HOST_NETWORK_NAMESPACE:-ovn-host-network}
OCI_BIN=${KIND_EXPERIMENTAL_PROVIDER:-docker}
}
detect_apiserver_url() {
# Detect API_URL used for in-cluster communication
#
# Despite OVN run in pod they will only obtain the VIRTUAL apiserver address
# and since OVN has to provide the connectivity to service
# it can not be bootstrapped
#
# This is the address of the node with the control-plane
API_URL=$(${KIND_BINARY} get kubeconfig --internal --name "${KIND_CLUSTER_NAME}" | grep server | awk '{ print $2 }')
}
check_ipv6() {
if [ "$KIND_IPV6_SUPPORT" == true ]; then
# Collect additional IPv6 data on test environment
ERROR_FOUND=false
TMPVAR=$(sysctl net.ipv6.conf.all.forwarding | awk '{print $3}')
echo "net.ipv6.conf.all.forwarding is equal to $TMPVAR"
if [ "$TMPVAR" != 1 ]; then
if [ "$KIND_ALLOW_SYSTEM_WRITES" == true ]; then
sudo sysctl -w net.ipv6.conf.all.forwarding=1
else
echo "RUN: 'sudo sysctl -w net.ipv6.conf.all.forwarding=1' to use IPv6."
ERROR_FOUND=true
fi
fi
TMPVAR=$(sysctl net.ipv6.conf.all.disable_ipv6 | awk '{print $3}')
echo "net.ipv6.conf.all.disable_ipv6 is equal to $TMPVAR"
if [ "$TMPVAR" != 0 ]; then
if [ "$KIND_ALLOW_SYSTEM_WRITES" == true ]; then
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=0
else
echo "RUN: 'sudo sysctl -w net.ipv6.conf.all.disable_ipv6=0' to use IPv6."
ERROR_FOUND=true
fi
fi
if [ -f /proc/net/if_inet6 ]; then
echo "/proc/net/if_inet6 exists so IPv6 supported in kernel."
else
echo "/proc/net/if_inet6 does not exists so no IPv6 support found! Compile the kernel!!"
ERROR_FOUND=true
fi
if "$ERROR_FOUND"; then
exit 2
fi
fi
}
set_cluster_cidr_ip_families() {
if [ "$KIND_IPV4_SUPPORT" == true ] && [ "$KIND_IPV6_SUPPORT" == false ]; then
IP_FAMILY=""
NET_CIDR=$NET_CIDR_IPV4
SVC_CIDR=$SVC_CIDR_IPV4
echo "IPv4 Only Support: --net-cidr=$NET_CIDR --svc-cidr=$SVC_CIDR"
elif [ "$KIND_IPV4_SUPPORT" == false ] && [ "$KIND_IPV6_SUPPORT" == true ]; then
IP_FAMILY="ipv6"
NET_CIDR=$NET_CIDR_IPV6
SVC_CIDR=$SVC_CIDR_IPV6
echo "IPv6 Only Support: --net-cidr=$NET_CIDR --svc-cidr=$SVC_CIDR"
elif [ "$KIND_IPV4_SUPPORT" == true ] && [ "$KIND_IPV6_SUPPORT" == true ]; then
IP_FAMILY="dual"
NET_CIDR=$NET_CIDR_IPV4,$NET_CIDR_IPV6
SVC_CIDR=$SVC_CIDR_IPV4,$SVC_CIDR_IPV6
echo "Dual Stack Support: --net-cidr=$NET_CIDR --svc-cidr=$SVC_CIDR"
else
echo "Invalid setup. KIND_IPV4_SUPPORT and/or KIND_IPV6_SUPPORT must be true."
exit 1
fi
}
create_kind_cluster() {
# Output of the j2 command
KIND_CONFIG_LCL=${DIR}/kind-${KIND_CLUSTER_NAME}.yaml
ovn_ip_family=${IP_FAMILY} \
ovn_ha=${OVN_HA} \
net_cidr=${NET_CIDR} \
svc_cidr=${SVC_CIDR} \
use_local_registy=${KIND_LOCAL_REGISTRY} \
dns_domain=${KIND_DNS_DOMAIN} \
ovn_num_master=${KIND_NUM_MASTER} \
ovn_num_worker=${KIND_NUM_WORKER} \
cluster_log_level=${KIND_CLUSTER_LOGLEVEL:-4} \
j2 "${KIND_CONFIG}" -o "${KIND_CONFIG_LCL}"
# Create KIND cluster. For additional debug, add '--verbosity <int>': 0 None .. 3 Debug
if ${KIND_BINARY} get clusters | grep ovn; then
delete
fi
${KIND_BINARY} create cluster --name "${KIND_CLUSTER_NAME}" --kubeconfig "${KUBECONFIG}" --image "${KIND_IMAGE}":"${K8S_VERSION}" --config=${KIND_CONFIG_LCL} --retain
sudo chown $USER:$USER "$KUBECONFIG"
cat "${KUBECONFIG}"
}
docker_disable_ipv6() {
# Docker disables IPv6 globally inside containers except in the eth0 interface.
# Kind enables IPv6 globally the containers ONLY for dual-stack and IPv6 deployments.
# Ovnkube-node tries to move all global addresses from the gateway interface to the
# bridge interface it creates. This breaks on KIND with IPv4 only deployments, because the new
# internal bridge has IPv6 disable and can't move the IPv6 from the eth0 interface.
# We can enable IPv6 always in the container, since the docker setup with IPv4 only
# is not very common.
KIND_NODES=$(${KIND_BINARY} get nodes --name "${KIND_CLUSTER_NAME}")
for n in $KIND_NODES; do
$OCI_BIN exec "$n" sysctl --ignore net.ipv6.conf.all.disable_ipv6=0
$OCI_BIN exec "$n" sysctl --ignore net.ipv6.conf.all.forwarding=1
done
}
coredns_patch() {
dns_server="8.8.8.8"
if [ "$KIND_IPV6_SUPPORT" == true ]; then
dns_server="2001:4860:4860::8888"
fi
# Patch CoreDNS to work
# 1. Github CI doesn´t offer IPv6 connectivity, so CoreDNS should be configured
# to work in an offline environment:
# https://github.com/coredns/coredns/issues/2494#issuecomment-457215452
# 2. Github CI adds following domains to resolv.conf search field:
# .net.
# CoreDNS should handle those domains and answer with NXDOMAIN instead of SERVFAIL
# otherwise pods stops trying to resolve the domain.
# Get the current config
original_coredns=$(kubectl get -oyaml -n=kube-system configmap/coredns)
echo "Original CoreDNS config:"
echo "${original_coredns}"
# Patch it
fixed_coredns=$(
printf '%s' "${original_coredns}" | sed \
-e 's/^.*kubernetes cluster\.local/& net/' \
-e '/^.*upstream$/d' \
-e '/^.*fallthrough.*$/d' \
-e 's/^\(.*forward \.\).*$/\1 '"$dns_server"' {/' \
-e '/^.*loop$/d' \
)
echo "Patched CoreDNS config:"
echo "${fixed_coredns}"
printf '%s' "${fixed_coredns}" | kubectl apply -f -
}
build_ovn_image() {
if [ "$OVN_IMAGE" == local ]; then
# if we're using the local registry and still need to build, push to local registry
if [ "$KIND_LOCAL_REGISTRY" == true ];then
OVN_IMAGE="localhost:5000/ovn-daemonset-f:latest"
else
OVN_IMAGE="localhost/ovn-daemonset-f:dev"
fi
# Build ovn docker image
pushd ${DIR}/../go-controller
make
popd
# Build ovn kube image
pushd ${DIR}/../dist/images
# Find all built executables, but ignore the 'windows' directory if it exists
find ../../go-controller/_output/go/bin/ -maxdepth 1 -type f -exec cp -f {} . \;
echo "ref: $(git rev-parse --symbolic-full-name HEAD) commit: $(git rev-parse HEAD)" > git_info
$OCI_BIN build -t "${OVN_IMAGE}" -f Dockerfile.fedora .
# store in local registry
if [ "$KIND_LOCAL_REGISTRY" == true ];then
echo "Pushing built image to local docker registry"
docker push "${OVN_IMAGE}"
fi
popd
fi
}
create_ovn_kube_manifests() {
pushd ${DIR}/../dist/images
./daemonset.sh \
--output-directory="${MANIFEST_OUTPUT_DIR}"\
--image="${OVN_IMAGE}" \
--net-cidr="${NET_CIDR}" \
--svc-cidr="${SVC_CIDR}" \
--gateway-mode="${OVN_GATEWAY_MODE}" \
--hybrid-enabled="${OVN_HYBRID_OVERLAY_ENABLE}" \
--disable-snat-multiple-gws="${OVN_DISABLE_SNAT_MULTIPLE_GWS}" \
--disable-pkt-mtu-check="${OVN_DISABLE_PKT_MTU_CHECK}" \
--ovn-empty-lb-events="${OVN_EMPTY_LB_EVENTS}" \
--multicast-enabled="${OVN_MULTICAST_ENABLE}" \
--k8s-apiserver="${API_URL}" \
--ovn-master-count="${KIND_NUM_MASTER}" \
--ovn-unprivileged-mode=no \
--master-loglevel="${MASTER_LOG_LEVEL}" \
--node-loglevel="${NODE_LOG_LEVEL}" \
--dbchecker-loglevel="${DBCHECKER_LOG_LEVEL}" \
--ovn-loglevel-northd="${OVN_LOG_LEVEL_NORTHD}" \
--ovn-loglevel-nb="${OVN_LOG_LEVEL_NB}" \
--ovn-loglevel-sb="${OVN_LOG_LEVEL_SB}" \
--ovn-loglevel-controller="${OVN_LOG_LEVEL_CONTROLLER}" \
--ovn-loglevel-nbctld="${OVN_LOG_LEVEL_NBCTLD}" \
--egress-ip-enable=true \
--egress-firewall-enable=true \
--v4-join-subnet="${JOIN_SUBNET_IPV4}" \
--v6-join-subnet="${JOIN_SUBNET_IPV6}" \
--ex-gw-network-interface="${OVN_EX_GW_NETWORK_INTERFACE}"
popd
}
install_ovn_image() {
# If local registry is being used push image there for consumption by kind cluster
if [ "$KIND_LOCAL_REGISTRY" == true ]; then
echo "OVN-K Image: ${OVN_IMAGE} should already be avaliable in local registry, not loading"
else
if [[ "$OCI_BIN" =~ "podman" ]]; then
# podman: cf https://github.com/kubernetes-sigs/kind/issues/2027
sudo rm -f /tmp/ovn-kube-f.tar
$OCI_BIN save -o /tmp/ovn-kube-f.tar "${OVN_IMAGE}"
${KIND_BINARY} load image-archive /tmp/ovn-kube-f.tar --name "${KIND_CLUSTER_NAME}"
else
${KIND_BINARY} load docker-image "${OVN_IMAGE}" --name "${KIND_CLUSTER_NAME}"
fi
fi
}
install_ovn() {
pushd ${MANIFEST_OUTPUT_DIR}
run_kubectl apply -f k8s.ovn.org_egressfirewalls.yaml
run_kubectl apply -f k8s.ovn.org_egressips.yaml
run_kubectl apply -f ovn-setup.yaml
MASTER_NODES=$(${KIND_BINARY} get nodes --name "${KIND_CLUSTER_NAME}" | sort | head -n "${KIND_NUM_MASTER}")
# We want OVN HA not Kubernetes HA
# leverage the kubeadm well-known label node-role.kubernetes.io/master=
# to choose the nodes where ovn master components will be placed
for n in $MASTER_NODES; do
kubectl label node "$n" k8s.ovn.org/ovnkube-db=true node-role.kubernetes.io/master="" --overwrite
if [ "$KIND_REMOVE_TAINT" == true ]; then
# do not error if it fails to remove the taint
kubectl taint node "$n" node-role.kubernetes.io/master:NoSchedule- || true
fi
done
if [ "$OVN_HA" == true ]; then
run_kubectl apply -f ovnkube-db-raft.yaml
else
run_kubectl apply -f ovnkube-db.yaml
fi
run_kubectl apply -f ovs-node.yaml
run_kubectl apply -f ovnkube-master.yaml
run_kubectl apply -f ovnkube-node.yaml
popd
}
install_ingress() {
run_kubectl apply -f ingress/mandatory.yaml
run_kubectl apply -f ingress/service-nodeport.yaml
}
kubectl_wait_pods() {
echo "Waiting for k8s to create ovn-kubernetes pod resources..."
local PODS_CREATED=false
for i in {1..10}; do
local NUM_PODS=$(kubectl -n ovn-kubernetes get pods -o json 2> /dev/null | jq '.items | length')
if [[ "${NUM_PODS}" -ne 0 ]]; then
echo "ovn-kubernetes pods created."
PODS_CREATED=true
break
fi
sleep 1
done
if [[ "$PODS_CREATED" == false ]]; then
echo "ovn-kubernetes pods were not created."
exit 1
fi
echo "ovn-kubernetes pods created."
# Check that everything is fine and running. IPv6 cluster seems to take a little
# longer to come up, so extend the wait time.
OVN_TIMEOUT=300s
if [ "$KIND_IPV6_SUPPORT" == true ]; then
OVN_TIMEOUT=480s
fi
if ! kubectl wait -n ovn-kubernetes --for=condition=ready pods --all --timeout=${OVN_TIMEOUT} ; then
echo "some pods in OVN Kubernetes are not running"
kubectl get pods -A -o wide || true
exit 1
fi
if ! kubectl wait -n kube-system --for=condition=ready pods --all --timeout=300s ; then
echo "some pods in the system are not running"
kubectl get pods -A -o wide || true
exit 1
fi
}
docker_create_second_interface() {
echo "adding second interfaces to nodes"
# Create the network as dual stack, regardless of the type of the deployment. Ignore if already exists.
docker network create --ipv6 --driver=bridge kindexgw --subnet=172.19.0.0/16 --subnet=fc00:f853:ccd:e798::/64 || true
KIND_NODES=$(${KIND_BINARY} get nodes --name "${KIND_CLUSTER_NAME}")
for n in $KIND_NODES; do
docker network connect kindexgw "$n"
done
}
sleep_until_pods_settle() {
echo "Pods are all up, allowing things settle for 30 seconds..."
sleep 30
}
# run_script_in_container should be used when kind.sh is run nested in a container
# and makes sure the control-plane node is rechable by substituting 127.0.0.1
# with the control-plane container's IP
run_script_in_container() {
local master_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${KIND_CLUSTER_NAME}-control-plane | head -n 1)
sed -i -- "s/server: .*/server: https:\/\/$master_ip:6443/g" $KUBECONFIG
chmod a+r $KUBECONFIG
}
# fixup_config_names should be used to ensure kind clusters are named based off
# provided values, essentially it removes the 'kind' prefix from the cluster names
fixup_kubeconfig_names() {
sed -i -- "s/user: kind-.*/user: ${KIND_CLUSTER_NAME}/g" $KUBECONFIG
sed -i -- "s/name: kind-.*/name: ${KIND_CLUSTER_NAME}/g" $KUBECONFIG
sed -i -- "s/cluster: kind-.*/cluster: ${KIND_CLUSTER_NAME}/g" $KUBECONFIG
sed -i -- "s/current-context: .*/current-context: ${KIND_CLUSTER_NAME}/g" $KUBECONFIG
}
check_dependencies
# In order to allow providing arguments with spaces, e.g. "-vconsole:info -vfile:info"
# the original command <parse_args $*> was replaced by <parse_args "$@">
parse_args "$@"
set_default_params
print_params
set -euxo pipefail
check_ipv6
set_cluster_cidr_ip_families
create_kind_cluster
if [ "$RUN_IN_CONTAINER" == true ]; then
run_script_in_container
fi
# if cluster name is specified fixup kubeconfig
if [ "$KIND_CLUSTER_NAME"} != "ovn" ]; then
fixup_kubeconfig_names
fi
docker_disable_ipv6
if [ "$OVN_ENABLE_EX_GW_NETWORK_BRIDGE" == true ]; then
docker_create_second_interface
fi
echo "time to fix kubeconfig"
sleep 60
coredns_patch
build_ovn_image
detect_apiserver_url
create_ovn_kube_manifests
install_ovn_image
install_ovn
if [ "$KIND_INSTALL_INGRESS" == true ]; then
install_ingress
fi
kubectl_wait_pods
sleep_until_pods_settle
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment