
Automatic merge from submit-queue Ubuntu: Enable ssh compression when downloading binaries during cluster creation <!-- Checklist for submitting a Pull Request Please remove this comment block before submitting. 1. Please read our [contributor guidelines](https://github.com/kubernetes/kubernetes/blob/master/CONTRIBUTING.md). 2. See our [developer guide](https://github.com/kubernetes/kubernetes/blob/master/docs/devel/development.md). 3. If you want this PR to automatically close an issue when it is merged, add `fixes #<issue number>` or `fixes #<issue number>, fixes #<issue number>` to close multiple issues (see: https://github.com/blog/1506-closing-issues-via-pull-requests). 4. Follow the instructions for [labeling and writing a release note for this PR](https://github.com/kubernetes/kubernetes/blob/master/docs/devel/pull-requests.md#release-notes) in the block below. --> resolves #20971 by using the options provided by ssh. Native ssh compression has existed for years, and the server is free to disregard the setting, so this should be safe. With things like the kube binaries I see about a 2x speed increase. ``` λ time scp kubes-bin.tar 9.30.182.251:/mnt/build/kubin kubes-bin.tar 100% 344MB 10.7MB/s 00:32 real 0m32.284s user 0m1.679s sys 0m1.263s λ time scp -C kubes-bin.tar 9.30.182.251:/mnt/build/kubin kubes-bin.tar 100% 344MB 22.9MB/s 00:15 real 0m14.810s user 0m12.858s sys 0m0.994s λ ls -lah kubes-bin.tar -rw-r--r-- 1 mhb staff 344M Jun 2 15:29 kubes-bin.tar λ tar -tf kubes-bin.tar kubectl master/ master/etcd master/etcdctl master/flanneld master/kube-apiserver master/kube-controller-manager master/kube-scheduler node/ node/flanneld node/kube-proxy node/kubelet ```
303 lines
9.1 KiB
Bash
Executable File
303 lines
9.1 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Copyright 2015 The Kubernetes Authors.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
# A library of helper functions that each provider hosting Kubernetes must implement to use cluster/kube-*.sh scripts.
|
|
|
|
# exit on any error
|
|
set -e
|
|
|
|
SSH_OPTS="-oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oLogLevel=ERROR -C"
|
|
|
|
# Use the config file specified in $KUBE_CONFIG_FILE, or default to
|
|
# config-default.sh.
|
|
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../..
|
|
readonly ROOT=$(dirname "${BASH_SOURCE}")
|
|
source "${ROOT}/${KUBE_CONFIG_FILE:-"config-default.sh"}"
|
|
source "$KUBE_ROOT/cluster/common.sh"
|
|
|
|
|
|
KUBECTL_PATH=${KUBE_ROOT}/cluster/centos/binaries/kubectl
|
|
|
|
# Directory to be used for master and node provisioning.
|
|
KUBE_TEMP="~/kube_temp"
|
|
|
|
|
|
# Must ensure that the following ENV vars are set
|
|
function detect-master() {
|
|
KUBE_MASTER=$MASTER
|
|
KUBE_MASTER_IP=${MASTER#*@}
|
|
echo "KUBE_MASTER_IP: ${KUBE_MASTER_IP}" 1>&2
|
|
echo "KUBE_MASTER: ${MASTER}" 1>&2
|
|
}
|
|
|
|
# Get node IP addresses and store in KUBE_NODE_IP_ADDRESSES[]
|
|
function detect-nodes() {
|
|
KUBE_NODE_IP_ADDRESSES=()
|
|
for node in ${NODES}; do
|
|
KUBE_NODE_IP_ADDRESSES+=("${node#*@}")
|
|
done
|
|
echo "KUBE_NODE_IP_ADDRESSES: [${KUBE_NODE_IP_ADDRESSES[*]}]" 1>&2
|
|
}
|
|
|
|
# Verify prereqs on host machine
|
|
function verify-prereqs() {
|
|
local rc
|
|
rc=0
|
|
ssh-add -L 1> /dev/null 2> /dev/null || rc="$?"
|
|
# "Could not open a connection to your authentication agent."
|
|
if [[ "${rc}" -eq 2 ]]; then
|
|
eval "$(ssh-agent)" > /dev/null
|
|
trap-add "kill ${SSH_AGENT_PID}" EXIT
|
|
fi
|
|
rc=0
|
|
ssh-add -L 1> /dev/null 2> /dev/null || rc="$?"
|
|
# "The agent has no identities."
|
|
if [[ "${rc}" -eq 1 ]]; then
|
|
# Try adding one of the default identities, with or without passphrase.
|
|
ssh-add || true
|
|
fi
|
|
rc=0
|
|
# Expect at least one identity to be available.
|
|
if ! ssh-add -L 1> /dev/null 2> /dev/null; then
|
|
echo "Could not find or add an SSH identity."
|
|
echo "Please start ssh-agent, add your identity, and retry."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Install handler for signal trap
|
|
function trap-add {
|
|
local handler="$1"
|
|
local signal="${2-EXIT}"
|
|
local cur
|
|
|
|
cur="$(eval "sh -c 'echo \$3' -- $(trap -p ${signal})")"
|
|
if [[ -n "${cur}" ]]; then
|
|
handler="${cur}; ${handler}"
|
|
fi
|
|
|
|
trap "${handler}" ${signal}
|
|
}
|
|
|
|
# Validate a kubernetes cluster
|
|
function validate-cluster() {
|
|
# by default call the generic validate-cluster.sh script, customizable by
|
|
# any cluster provider if this does not fit.
|
|
set +e
|
|
"${KUBE_ROOT}/cluster/validate-cluster.sh"
|
|
if [[ "$?" -ne "0" ]]; then
|
|
troubleshoot-master
|
|
for node in ${NODES}; do
|
|
troubleshoot-node ${node}
|
|
done
|
|
exit 1
|
|
fi
|
|
set -e
|
|
}
|
|
|
|
# Instantiate a kubernetes cluster
|
|
function kube-up() {
|
|
provision-master
|
|
|
|
for node in ${NODES}; do
|
|
provision-node ${node}
|
|
done
|
|
|
|
detect-master
|
|
|
|
# set CONTEXT and KUBE_SERVER values for create-kubeconfig() and get-password()
|
|
export CONTEXT="centos"
|
|
export KUBE_SERVER="http://${KUBE_MASTER_IP}:8080"
|
|
source "${KUBE_ROOT}/cluster/common.sh"
|
|
|
|
# set kubernetes user and password
|
|
get-password
|
|
create-kubeconfig
|
|
}
|
|
|
|
# Delete a kubernetes cluster
|
|
function kube-down() {
|
|
tear-down-master
|
|
for node in ${NODES}; do
|
|
tear-down-node ${node}
|
|
done
|
|
}
|
|
|
|
function troubleshoot-master() {
|
|
# Troubleshooting on master if all required daemons are active.
|
|
echo "[INFO] Troubleshooting on master ${MASTER}"
|
|
local -a required_daemon=("kube-apiserver" "kube-controller-manager" "kube-scheduler")
|
|
local daemon
|
|
local daemon_status
|
|
printf "%-24s %-10s \n" "PROCESS" "STATUS"
|
|
for daemon in "${required_daemon[@]}"; do
|
|
local rc=0
|
|
kube-ssh "${MASTER}" "sudo systemctl is-active ${daemon}" >/dev/null 2>&1 || rc="$?"
|
|
if [[ "${rc}" -ne "0" ]]; then
|
|
daemon_status="inactive"
|
|
else
|
|
daemon_status="active"
|
|
fi
|
|
printf "%-24s %s\n" ${daemon} ${daemon_status}
|
|
done
|
|
printf "\n"
|
|
}
|
|
|
|
function troubleshoot-node() {
|
|
# Troubleshooting on node if all required daemons are active.
|
|
echo "[INFO] Troubleshooting on node ${1}"
|
|
local -a required_daemon=("kube-proxy" "kubelet" "docker" "flannel")
|
|
local daemon
|
|
local daemon_status
|
|
printf "%-24s %-10s \n" "PROCESS" "STATUS"
|
|
for daemon in "${required_daemon[@]}"; do
|
|
local rc=0
|
|
kube-ssh "${1}" "sudo systemctl is-active ${daemon}" >/dev/null 2>&1 || rc="$?"
|
|
if [[ "${rc}" -ne "0" ]]; then
|
|
daemon_status="inactive"
|
|
else
|
|
daemon_status="active"
|
|
fi
|
|
printf "%-24s %s\n" ${daemon} ${daemon_status}
|
|
done
|
|
printf "\n"
|
|
}
|
|
|
|
# Clean up on master
|
|
function tear-down-master() {
|
|
echo "[INFO] tear-down-master on ${MASTER}"
|
|
for service_name in etcd kube-apiserver kube-controller-manager kube-scheduler ; do
|
|
service_file="/usr/lib/systemd/system/${service_name}.service"
|
|
kube-ssh "$MASTER" " \
|
|
if [[ -f $service_file ]]; then \
|
|
sudo systemctl stop $service_name; \
|
|
sudo systemctl disable $service_name; \
|
|
sudo rm -f $service_file; \
|
|
fi"
|
|
done
|
|
kube-ssh "${MASTER}" "sudo rm -rf /opt/kubernetes"
|
|
kube-ssh "${MASTER}" "sudo rm -rf ${KUBE_TEMP}"
|
|
kube-ssh "${MASTER}" "sudo rm -rf /var/lib/etcd"
|
|
}
|
|
|
|
# Clean up on node
|
|
function tear-down-node() {
|
|
echo "[INFO] tear-down-node on $1"
|
|
for service_name in kube-proxy kubelet docker flannel ; do
|
|
service_file="/usr/lib/systemd/system/${service_name}.service"
|
|
kube-ssh "$1" " \
|
|
if [[ -f $service_file ]]; then \
|
|
sudo systemctl stop $service_name; \
|
|
sudo systemctl disable $service_name; \
|
|
sudo rm -f $service_file; \
|
|
fi"
|
|
done
|
|
kube-ssh "$1" "sudo rm -rf /run/flannel"
|
|
kube-ssh "$1" "sudo rm -rf /opt/kubernetes"
|
|
kube-ssh "$1" "sudo rm -rf ${KUBE_TEMP}"
|
|
}
|
|
|
|
# Provision master
|
|
#
|
|
# Assumed vars:
|
|
# MASTER
|
|
# KUBE_TEMP
|
|
# ETCD_SERVERS
|
|
# SERVICE_CLUSTER_IP_RANGE
|
|
function provision-master() {
|
|
echo "[INFO] Provision master on ${MASTER}"
|
|
local master_ip=${MASTER#*@}
|
|
ensure-setup-dir ${MASTER}
|
|
|
|
# scp -r ${SSH_OPTS} master config-default.sh copy-files.sh util.sh "${MASTER}:${KUBE_TEMP}"
|
|
kube-scp ${MASTER} "${ROOT}/../saltbase/salt/generate-cert/make-ca-cert.sh ${ROOT}/binaries/master ${ROOT}/master ${ROOT}/config-default.sh ${ROOT}/util.sh" "${KUBE_TEMP}"
|
|
kube-ssh "${MASTER}" " \
|
|
sudo cp -r ${KUBE_TEMP}/master/bin /opt/kubernetes; \
|
|
sudo chmod -R +x /opt/kubernetes/bin; \
|
|
sudo bash ${KUBE_TEMP}/make-ca-cert.sh ${master_ip} IP:${master_ip},IP:${SERVICE_CLUSTER_IP_RANGE%.*}.1,DNS:kubernetes,DNS:kubernetes.default,DNS:kubernetes.default.svc,DNS:kubernetes.default.svc.cluster.local; \
|
|
sudo bash ${KUBE_TEMP}/master/scripts/etcd.sh; \
|
|
sudo bash ${KUBE_TEMP}/master/scripts/apiserver.sh ${master_ip} ${ETCD_SERVERS} ${SERVICE_CLUSTER_IP_RANGE} ${ADMISSION_CONTROL}; \
|
|
sudo bash ${KUBE_TEMP}/master/scripts/controller-manager.sh ${master_ip}; \
|
|
sudo bash ${KUBE_TEMP}/master/scripts/scheduler.sh ${master_ip}"
|
|
}
|
|
|
|
|
|
# Provision node
|
|
#
|
|
# Assumed vars:
|
|
# $1 (node)
|
|
# MASTER
|
|
# KUBE_TEMP
|
|
# ETCD_SERVERS
|
|
# FLANNEL_NET
|
|
# DOCKER_OPTS
|
|
function provision-node() {
|
|
echo "[INFO] Provision node on $1"
|
|
local master_ip=${MASTER#*@}
|
|
local node=$1
|
|
local node_ip=${node#*@}
|
|
ensure-setup-dir ${node}
|
|
|
|
kube-scp ${node} "${ROOT}/binaries/node ${ROOT}/node ${ROOT}/config-default.sh ${ROOT}/util.sh" ${KUBE_TEMP}
|
|
kube-ssh "${node}" " \
|
|
sudo cp -r ${KUBE_TEMP}/node/bin /opt/kubernetes; \
|
|
sudo chmod -R +x /opt/kubernetes/bin; \
|
|
sudo bash ${KUBE_TEMP}/node/scripts/flannel.sh ${ETCD_SERVERS} ${FLANNEL_NET}; \
|
|
sudo bash ${KUBE_TEMP}/node/scripts/docker.sh \"${DOCKER_OPTS}\"; \
|
|
sudo bash ${KUBE_TEMP}/node/scripts/kubelet.sh ${master_ip} ${node_ip}; \
|
|
sudo bash ${KUBE_TEMP}/node/scripts/proxy.sh ${master_ip}"
|
|
}
|
|
|
|
# Create dirs that'll be used during setup on target machine.
|
|
#
|
|
# Assumed vars:
|
|
# KUBE_TEMP
|
|
function ensure-setup-dir() {
|
|
kube-ssh "${1}" "mkdir -p ${KUBE_TEMP}; \
|
|
sudo mkdir -p /opt/kubernetes/bin; \
|
|
sudo mkdir -p /opt/kubernetes/cfg"
|
|
}
|
|
|
|
# Run command over ssh
|
|
function kube-ssh() {
|
|
local host="$1"
|
|
shift
|
|
ssh ${SSH_OPTS} -t "${host}" "$@" >/dev/null 2>&1
|
|
}
|
|
|
|
# Copy file recursively over ssh
|
|
function kube-scp() {
|
|
local host="$1"
|
|
local src=($2)
|
|
local dst="$3"
|
|
scp -r ${SSH_OPTS} ${src[*]} "${host}:${dst}"
|
|
}
|
|
|
|
# Ensure that we have a password created for validating to the master. Will
|
|
# read from kubeconfig if available.
|
|
#
|
|
# Vars set:
|
|
# KUBE_USER
|
|
# KUBE_PASSWORD
|
|
function get-password {
|
|
load-or-gen-kube-basicauth
|
|
if [[ -z "${KUBE_USER}" || -z "${KUBE_PASSWORD}" ]]; then
|
|
KUBE_USER=admin
|
|
KUBE_PASSWORD=$(python -c 'import string,random; \
|
|
print("".join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(16)))')
|
|
fi
|
|
}
|