#!/bin/bash # shellcheck disable=SC1078,SC1079,SC2164 # ============================================================================= # FileName: belloHAKubeCluster.sh # Author: marslo.jiao@gmail.com # Created: 2019-09-02 22:48:57 # LastChange: 2019-09-17 22:43:04 # ============================================================================= # Inspired by: # https://blog.csdn.net/chenleiking/article/details/80136449 # https://k8smeetup.github.io/docs/setup/independent/high-availability/ # hardcode master1Ip='127.0.0.40' master2Ip='127.0.0.42' master3Ip='127.0.0.43' master1Name='mytest-tst1' master2Name='mytest-tst2' master3Name='mytest-tst3' virtualIpAddr='127.0.0.50' leadIP="${master1Ip}" leadHost="${master1Name}" k8sVer='v1.15.3' rtUrl='artifactory.my.com/artifactory' # etcdSSLPath='/etc/kubernetes/pki' etcdSSLPath='/etc/etcd/ssl' # cfsslofficialUrl='https://pkg.cfssl.org/R1.2' cfsslRtUrl="https://${rtUrl}/devops-local/k8s/R1.2/" cfsslDownloadUrl="${cfsslRtUrl}" etcdVer='v3.3.15' # etcdGoogleDownload='https://storage.googleapis.com/etcd' # etcdGithubDownload='https://github.com/etcd-io/etcd/releases/download' etcdRtDownload="https://${rtUrl}/devops-local/k8s" etcdDownloadUrl="${etcdRtDownload}" etcdInitialCluster="${master1Name}=https://${master1Ip}:2380,${master2Name}=https://${master2Ip}:2380,${master3Name}=https://${master3Ip}:2380" keepaliveVer='2.0.18' # keepaliveUrl='https://www.keepalived.org/software' keepaliveRtUrl="https://${rtUrl}/devops-local/k8s/software" keepaliveDownloadUrl="${keepaliveRtUrl}" # interface=$(ip route get 13.250.177.223 | sed -rn 's|.*dev\s+(\S+)\s+src.*$|\1|p') # get the route to github interface=$(netstat -nr | grep -E 'UG|UGSc' | grep -E '^0.0.0|default' | grep -E '[0-9.]{7,15}' | awk -F' ' '{print $NF}') ipAddr=$(ip a s "${interface}" | sed -rn 's|.*inet ([0-9\.]{7,15})/[0-9]{2} brd.*$|\1|p') peerName=$(hostname) usage="""USAGE: \n\t$0 [help] [independent function name] \n\nNOTICE: \n\tReplace the master{1..3}IP and master{1..3}Name to your real situation \n\tleadMaster should be executed first to setup certificate; And then execute the peerMasters. \n\tMake sure all servers can be visit passwordless by ssh for common user and root. \n \nExample: \n\tSetup HA Cluster \n\t\t$0 primaryMaster # on master-1 \n\t\t$0 peerMasters # on master-2 and master-3 \n \n\tShow current information: \n\t\t$0 showInfo \n\nINDEPENDENT FUNCTION NAME: """ info="""CURRENT SERVER INFORMATION: \n\tcurrent network interface: \t${interface} \n\tcurrent IP address: \t\t${ipAddr} \n \n\tIP \t\t\t Hostname \n\t${master1Ip} \t~~>\t ${master1Name} \n\t${master2Ip} \t~~>\t ${master2Name} \n\t${master3Ip} \t~~>\t ${master3Name} \n\t \n\tvirtualIpAddr: \t\t${virtualIpAddr} \n\tleadIP: \t\t${leadIP} \n\tleadHost: \t\t${leadHost} \n\tetcdInitialCluster: \t${etcdInitialCluster} \n \nTools: \n\tKubernetes version: \t${k8sVer} \n\tetcd vesion: \t\t${etcdVer} \n\tKeep alived version: \t${keepaliveVer} \n """ function help() # show list of functions { echo -e "${usage}" # ${GREP} '^function' $0 | sed -re "s:^function([^(.]*).*$:\t\1:g" declare -F -p | sed -re "s:^.*-f(.*)$:\t\1:g" } function showInfo() { echo -e "${info}" } function reportError(){ set +H echo -e "\\033[31mERROR: $1 !!\\033[0m" set -H } function timeSync() { sudo date --set="$(ssh ${leadIP} 'date ')" } function helmInstallation() { curl -fsSL \ https://get.helm.sh/helm-v2.14.3-linux-amd64.tar.gz | sudo tar -xzv --strip-components=1 -C /usr/local/bin/ while read -r _i; do sudo chmod +x "/usr/local/bin/${_i}" done < <(echo helm tiller) helm init helm init --client-only kubectl create serviceaccount -n kube-system tiller kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller kubectl patch deploy -n kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}' helm repo add jetstack https://charts.jetstack.io } function dockerInstallation() { sudo yum remove -y docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-selinux \ docker-engine-selinux \ docker-engine sudo yum -y groupinstall 'Development Tools' sudo yum install -y yum-utils \ device-mapper-persistent-data \ lvm2 \ bash-completion* sudo yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo sudo yum-config-manager --disable docker-ce-edge sudo yum-config-manager --disable docker-ce-test sudo yum makecache sudo yum list docker-ce --showduplicates | sort -r | grep 18\.09 sudo yum install -y \ docker-ce-18.09.9-3.el7.x86_64 \ docker-ce-cli-18.09.9-3.el7.x86_64 \ containerd.io sudo systemctl enable --now docker sudo systemctl status docker } function k8sInstallation() { setenforce 0 sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config modprobe br_netfilter sudo bash -c 'cat > /etc/sysctl.d/k8s.conf' << EOF net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sysctl --system sudo bash -c 'cat > /etc/yum.repos.d/kubernetes.repo' << EOF [kubernetes] name=Kubernetes baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=1 repo_gpgcheck=1 gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg EOF sudo yum makecache sudo yum list kubeadm --showduplicates | sort -r | grep 1\.15\.3 sudo yum install -y \ kubeadm-1.15.3-0.x86_64 \ kubectl-1.15.3-0.x86_64 \ kubelet-1.15.3-0.x86_64 \ --disableexcludes=kubernetes sudo systemctl enable --now kubelet sudo systemctl status kubelet } function cfsslInstallation() { sudo bash -c "curl -o /usr/local/bin/cfssl ${cfsslDownloadUrl}/cfssl_linux-amd64" sudo bash -c "curl -o /usr/local/bin/cfssljson ${cfsslDownloadUrl}/cfssljson_linux-amd64" sudo chmod +x /usr/local/bin/cfssl* } function etcdInstallation() { curl -sSL ${etcdDownloadUrl}/${etcdVer}/etcd-${etcdVer}-linux-amd64.tar.gz | sudo tar -xzv --strip-components=1 -C /usr/local/bin/ } function certCA() { sudo bash -c "cat > ${etcdSSLPath}/ca-config.json" << EOF { "signing": { "default": { "expiry": "43800h" }, "profiles": { "server": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ] }, "client": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "client auth" ] }, "peer": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ] } } } } EOF sudo bash -c "cat > ${etcdSSLPath}/ca-csr.json" << EOF { "CN": "etcd", "key": { "algo": "rsa", "size": 2048 } } EOF pushd . cd ${etcdSSLPath} sudo /usr/local/bin/cfssl gencert \ -initca ca-csr.json | sudo /usr/local/bin/cfssljson -bare ca - popd } function certClient() { sudo bash -c "cat > ${etcdSSLPath}/client.json" << EOF { "CN": "client", "key": { "algo": "ecdsa", "size": 256 } } EOF pushd . cd ${etcdSSLPath}/ sudo /usr/local/bin/cfssl gencert \ -ca=ca.pem \ -ca-key=ca-key.pem \ -config=ca-config.json \ -profile=client client.json | sudo /usr/local/bin/cfssljson -bare client popd } function certServerNPeer() { sudo bash -c "/usr/local/bin/cfssl print-defaults csr > ${etcdSSLPath}/config.json" sudo sed -i '0,/CN/{s/example\.net/'"${peerName}"'/}' ${etcdSSLPath}/config.json sudo sed -i 's/www\.example\.net/'"${ipAddr}"'/' ${etcdSSLPath}/config.json sudo sed -i 's/example\.net/'"${peerName}"'/' ${etcdSSLPath}/config.json pushd . cd ${etcdSSLPath}/ sudo /usr/local/bin/cfssl gencert \ -ca=ca.pem \ -ca-key=ca-key.pem \ -config=ca-config.json \ -profile=server config.json | sudo /usr/local/bin/cfssljson -bare server sudo /usr/local/bin/cfssl gencert \ -ca=ca.pem \ -ca-key=ca-key.pem \ -config=ca-config.json \ -profile=peer config.json | sudo /usr/local/bin/cfssljson -bare peer popd } function syncCert() { for pkg in ca-config.json ca-key.pem ca.pem client-key.pem client.pem; do sudo rsync -avzrlpgoDP \ --rsync-path='sudo rsync' \ root@${leadHost}:${etcdSSLPath}/${pkg} \ ${etcdSSLPath}/ done } function etcdService() { sudo bash -c 'cat >/etc/systemd/system/etcd.service' < /etc/etcd/etcd.conf' <> /etc/etcd.env echo "ipAddr=${ipAddr}" >> /etc/etcd.env sudo bash -c 'cat > /etc/systemd/system/etcd.service' < /etc/keepalived/keepalived.conf' < /etc/keepalived/check_apiserver.sh' << EOF #!/bin/sh errorExit() { echo "*** \$*" 1>&2 exit 1 } curl --silent --max-time 2 --insecure https://localhost:6443/ -o /dev/null || errorExit "Error GET https://localhost:6443/" if ip addr | grep -q ${virtualIpAddr}; then curl --silent --max-time 2 --insecure https://${virtualIpAddr}:6443/ -o /dev/null || errorExit "Error GET https://${virtualIpAddr}:6443/" fi EOF sudo systemctl enable keepalived.service sudo systemctl start keepalived.service } function kubeadmConfig() { cat > kubeadm-conf.yaml <