You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
helm/scripts/local-cluster.sh

339 lines
9.0 KiB

#!/usr/bin/env bash
# Bash 'Strict Mode'
# http://redsymbol.net/articles/unofficial-bash-strict-mode
set -euo pipefail
IFS=$'\n\t'
HELM_ROOT="${BASH_SOURCE[0]%/*}/.."
cd "$HELM_ROOT"
# Globals ----------------------------------------------------------------------
KUBE_VERSION=${KUBE_VERSION:-}
KUBE_PORT=${KUBE_PORT:-8080}
KUBE_CONTEXT=${KUBE_CONTEXT:-docker}
KUBECTL=${KUBECTL:-kubectl}
ENABLE_CLUSTER_DNS=${KUBE_ENABLE_CLUSTER_DNS:-true}
LOG_LEVEL=${LOG_LEVEL:-2}
# Helper Functions -------------------------------------------------------------
# Display error message and exit
error_exit() {
echo "error: ${1:-"unknown error"}" 1>&2
exit 1
}
# Checks if a command exists. Returns 1 or 0
command_exists() {
hash "${1}" 2>/dev/null
}
# fetch url using wget or curl and print to stdout
fetch_url() {
local url="$1"
if command_exists wget; then
curl -sSL "$url"
elif command_exists curl; then
wget -qO- "$url"
else
error_exit "Couldn't find curl or wget. Bailing out."
fi
}
# Program Functions ------------------------------------------------------------
# Check host platform and docker host
verify_prereqs() {
echo "Verifying Prerequisites...."
case "$(uname -s)" in
Darwin)
host_os=darwin
;;
Linux)
host_os=linux
;;
*)
error_exit "Unsupported host OS. Must be Linux or Mac OS X."
;;
esac
case "$(uname -m)" in
x86_64*)
host_arch=amd64
;;
i?86_64*)
host_arch=amd64
;;
amd64*)
host_arch=amd64
;;
arm*)
host_arch=arm
;;
i?86*)
host_arch=x86
;;
s390x*)
host_arch=s390x
;;
ppc64le*)
host_arch=ppc64le
;;
*)
error_exit "Unsupported host arch. Must be x86_64, 386, arm, s390x or ppc64le."
;;
esac
command_exists docker || error_exit "You need docker"
if ! docker info >/dev/null 2>&1 ; then
error_exit "Can't connect to 'docker' daemon."
fi
if docker inspect kubelet >/dev/null 2>&1 ; then
error_exit "Kubernetes is already running"
fi
$KUBECTL version --client >/dev/null || download_kubectl
}
# Get the latest stable release tag
get_latest_version_number() {
local channel="stable"
if [[ -n "${ALPHA:-}" ]]; then
channel="latest"
fi
local latest_url="https://storage.googleapis.com/kubernetes-release/release/${channel}.txt"
fetch_url "$latest_url"
}
# Detect ip address od docker host
detect_docker_host_ip() {
if [[ -n "${DOCKER_HOST:-}" ]]; then
awk -F'[/:]' '{print $4}' <<< "$DOCKER_HOST"
else
ifconfig docker0 \
| grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' \
| grep -Eo '([0-9]*\.){3}[0-9]*' >/dev/null 2>&1 || :
fi
}
# Set KUBE_MASTER_IP from docker host ip. Defaults to localhost
set_master_ip() {
local docker_ip
if [[ -z "${KUBE_MASTER_IP:-}" ]]; then
docker_ip=$(detect_docker_host_ip)
if [[ -n "${docker_ip}" ]]; then
KUBE_MASTER_IP="${docker_ip}"
else
KUBE_MASTER_IP=localhost
fi
fi
}
# Start dockerized kubelet
start_kubernetes() {
echo "Starting kubelet"
# Enable dns
if [[ "${ENABLE_CLUSTER_DNS}" = true ]]; then
dns_args="--cluster-dns=10.0.0.10 --cluster-domain=cluster.local"
else
# DNS server for real world hostnames.
dns_args="--cluster-dns=8.8.8.8"
fi
local start_time=$(date +%s)
docker run \
--name=kubelet \
--volume=/:/rootfs:ro \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:rw \
--volume=/var/lib/kubelet/:/var/lib/kubelet:rw \
--volume=/var/run:/var/run:rw \
--net=host \
--pid=host \
--privileged=true \
-d \
gcr.io/google_containers/hyperkube-amd64:${KUBE_VERSION} \
/hyperkube kubelet \
--containerized \
--hostname-override="127.0.0.1" \
--api-servers=http://localhost:${KUBE_PORT} \
--config=/etc/kubernetes/manifests \
--allow-privileged=true \
${dns_args} \
--v=${LOG_LEVEL} >/dev/null
until $KUBECTL cluster-info &> /dev/null; do
sleep 1
done
# Create kube-system namespace in kubernetes
$KUBECTL create namespace kube-system >/dev/null
# We expect to have at least 3 running pods - etcd, master and kube-proxy.
local attempt=1
while (($(KUBECTL get pods --all-namespaces --no-headers 2>/dev/null | grep -c "Running") < 3)); do
echo -n "."
sleep $(( attempt++ ))
done
echo
echo "Started master components in $(($(date +%s) - start_time)) seconds."
}
# Open kubernetes master api port.
setup_firewall() {
[[ -n "${DOCKER_MACHINE_NAME:-}" ]] || return
echo "Adding iptables hackery for docker-machine..."
local machine_ip
machine_ip=$(docker-machine ip "$DOCKER_MACHINE_NAME")
local iptables_rule="PREROUTING -p tcp -d ${machine_ip} --dport ${KUBE_PORT} -j DNAT --to-destination 127.0.0.1:${KUBE_PORT}"
if ! docker-machine ssh "${DOCKER_MACHINE_NAME}" "sudo /usr/local/sbin/iptables -t nat -C ${iptables_rule}" &> /dev/null; then
docker-machine ssh "${DOCKER_MACHINE_NAME}" "sudo /usr/local/sbin/iptables -t nat -I ${iptables_rule}"
fi
}
# Activate skydns in kubernetes and wait for pods to be ready.
create_kube_dns() {
[[ "${ENABLE_CLUSTER_DNS}" = true ]] || return
local start_time=$(date +%s)
echo "Setting up cluster dns..."
$KUBECTL create -f ./scripts/cluster/skydns.yaml >/dev/null
echo "Waiting for cluster DNS to become available..."
local attempt=1
until $KUBECTL get pods --no-headers --namespace kube-system --selector=k8s-app=kube-dns 2>/dev/null | grep "Running" &>/dev/null; do
echo -n "."
sleep $(( attempt++ ))
done
echo
echo "Started DNS in $(($(date +%s) - start_time)) seconds."
}
# Generate kubeconfig data for the created cluster.
generate_kubeconfig() {
local cluster_args=(
"--server=http://${KUBE_MASTER_IP}:${KUBE_PORT}"
"--insecure-skip-tls-verify=true"
)
$KUBECTL config set-cluster "${KUBE_CONTEXT}" "${cluster_args[@]}" >/dev/null
$KUBECTL config set-context "${KUBE_CONTEXT}" --cluster="${KUBE_CONTEXT}" >/dev/null
$KUBECTL config use-context "${KUBE_CONTEXT}" >/dev/null
echo "Wrote config for kubeconfig using context: '${KUBE_CONTEXT}'"
}
# Download kubectl
download_kubectl() {
echo "Downloading kubectl binary..."
local output="/usr/local/bin/kubectl"
kubectl_url="https://storage.googleapis.com/kubernetes-release/release/${KUBE_VERSION}/bin/${host_os}/${host_arch}/kubectl"
fetch_url "${kubectl_url}" > "${output}"
chmod a+x "${output}"
KUBECTL="${output}"
}
# Clean volumes that are left by kubelet
#
# https://github.com/kubernetes/kubernetes/issues/23197
# code stolen from https://github.com/huggsboson/docker-compose-kubernetes/blob/SwitchToSharedMount/kube-up.sh
clean_volumes() {
if [[ -n "${DOCKER_MACHINE_NAME}" ]]; then
docker-machine ssh "${DOCKER_MACHINE_NAME}" "mount | grep -o 'on /var/lib/kubelet.* type' | cut -c 4- | rev | cut -c 6- | rev | sort -r | xargs --no-run-if-empty sudo umount"
docker-machine ssh "${DOCKER_MACHINE_NAME}" "sudo rm -Rf /var/lib/kubelet"
docker-machine ssh "${DOCKER_MACHINE_NAME}" "sudo mkdir -p /var/lib/kubelet"
docker-machine ssh "${DOCKER_MACHINE_NAME}" "sudo mount --bind /var/lib/kubelet /var/lib/kubelet"
docker-machine ssh "${DOCKER_MACHINE_NAME}" "sudo mount --make-shared /var/lib/kubelet"
else
mount | grep -o 'on /var/lib/kubelet.* type' | cut -c 4- | rev | cut -c 6- | rev | sort -r | xargs --no-run-if-empty sudo umount
sudo rm -Rf /var/lib/kubelet
sudo mkdir -p /var/lib/kubelet
sudo mount --bind /var/lib/kubelet /var/lib/kubelet
sudo mount --make-shared /var/lib/kubelet
fi
}
# Helper function to properly remove containers
delete_container() {
local container=("$@")
docker stop "${container[@]}" &>/dev/null || :
docker wait "${container[@]}" &>/dev/null || :
docker rm --force --volumes "${container[@]}" &>/dev/null || :
}
# Delete master components and resources in kubernetes.
kube_down() {
echo "Deleting all resources in kubernetes..."
$KUBECTL delete replicationcontrollers,services,pods,secrets --all >/dev/null 2>&1 || :
$KUBECTL delete replicationcontrollers,services,pods,secrets --all --namespace=kube-system >/dev/null 2>&1 || :
$KUBECTL delete namespace kube-system >/dev/null 2>&1 || :
echo "Stopping kubelet..."
delete_container kubelet
echo "Stopping remaining kubernetes containers..."
local kube_containers=($(docker ps -aqf "name=k8s_"))
if [[ "${#kube_containers[@]}" -gt 0 ]]; then
delete_container "${kube_containers[@]}"
fi
}
# Start a kubernetes cluster in docker.
kube_up() {
verify_prereqs
set_master_ip
clean_volumes
setup_firewall
generate_kubeconfig
start_kubernetes
create_kube_dns
$KUBECTL cluster-info
}
KUBE_VERSION=${KUBE_VERSION:-$(get_latest_version_number)}
# Main -------------------------------------------------------------------------
main() {
case "$1" in
up|start)
kube_up
;;
down|stop)
kube_down
;;
restart)
kube_down
kube_up
;;
*)
echo "Usage: $0 {up|down|restart}"
;;
esac
}
main "${@:-}"