Merge "Enabling helm3 & kubernetes 1.18 for RIC in shell scripts without breaking...
[it/dep.git] / tools / k8s / heat / scripts / k8s_vm_install.sh
1 #!/bin/bash -x
2 ################################################################################
3 #   Copyright (c) 2019,2020 AT&T Intellectual Property.                        #
4 #                                                                              #
5 #   Licensed under the Apache License, Version 2.0 (the "License");            #
6 #   you may not use this file except in compliance with the License.           #
7 #   You may obtain a copy of the License at                                    #
8 #                                                                              #
9 #       http://www.apache.org/licenses/LICENSE-2.0                             #
10 #                                                                              #
11 #   Unless required by applicable law or agreed to in writing, software        #
12 #   distributed under the License is distributed on an "AS IS" BASIS,          #
13 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
14 #   See the License for the specific language governing permissions and        #
15 #   limitations under the License.                                             #
16 ################################################################################
17
18
19 # first parameter: number of expected running  pods
20 # second parameter: namespace (all-namespaces means all namespaces)
21 # third parameter: [optional] keyword
22 wait_for_pods_running () {
23   NS="$2"
24   CMD="kubectl get pods --all-namespaces "
25   if [ "$NS" != "all-namespaces" ]; then
26     CMD="kubectl get pods -n $2 "
27   fi
28   KEYWORD="Running"
29   if [ "$#" == "3" ]; then
30     KEYWORD="${3}.*Running"
31   fi
32
33   CMD2="$CMD | grep \"$KEYWORD\" | wc -l"
34   NUMPODS=$(eval "$CMD2")
35   echo "waiting for $NUMPODS/$1 pods running in namespace [$NS] with keyword [$KEYWORD]"
36   while [  $NUMPODS -lt $1 ]; do
37     sleep 5
38     NUMPODS=$(eval "$CMD2")
39     echo "> waiting for $NUMPODS/$1 pods running in namespace [$NS] with keyword [$KEYWORD]"
40   done 
41 }
42
43
44 # first parameter: interface name
45 start_ipv6_if () {
46   # enable ipv6 interface
47   # standard Ubuntu cloud image does not have dual interface configuration or ipv6
48   IPv6IF="$1"
49   if ifconfig -a $IPv6IF; then
50     echo "" >> /etc/network/interfaces.d/50-cloud-init.cfg
51     echo "allow-hotplug ${IPv6IF}" >> /etc/network/interfaces.d/50-cloud-init.cfg
52     echo "iface ${IPv6IF} inet6 auto" >> /etc/network/interfaces.d/50-cloud-init.cfg
53     ifconfig ${IPv6IF} up
54   fi
55 }
56
57 echo "k8s_vm_install.sh"
58 set -x
59 export DEBIAN_FRONTEND=noninteractive
60 echo "__host_private_ip_addr__ $(hostname)" >> /etc/hosts
61 printenv
62
63 IPV6IF=""
64
65 rm -rf /opt/config
66 mkdir -p /opt/config
67 echo "__docker_version__" > /opt/config/docker_version.txt
68 echo "__k8s_version__" > /opt/config/k8s_version.txt
69 echo "__k8s_cni_version__" > /opt/config/k8s_cni_version.txt
70 echo "__helm_version__" > /opt/config/helm_version.txt
71 echo "__host_private_ip_addr__" > /opt/config/host_private_ip_addr.txt
72 echo "__k8s_mst_floating_ip_addr__" > /opt/config/k8s_mst_floating_ip_addr.txt
73 echo "__k8s_mst_private_ip_addr__" > /opt/config/k8s_mst_private_ip_addr.txt
74 echo "__mtu__" > /opt/config/mtu.txt
75 echo "__cinder_volume_id__" > /opt/config/cinder_volume_id.txt
76 echo "__stack_name__" > /opt/config/stack_name.txt
77
78 # assume we are setting up AUX cluster VM if hostname contains "aux"
79 ISAUX='false'
80 if [[ $(cat /opt/config/stack_name.txt) == *aux* ]]; then
81   ISAUX='true'
82 fi
83
84 modprobe -- ip_vs
85 modprobe -- ip_vs_rr
86 modprobe -- ip_vs_wrr
87 modprobe -- ip_vs_sh
88 modprobe -- nf_conntrack_ipv4
89 modprobe -- nf_conntrack_ipv6
90 modprobe -- nf_conntrack_proto_sctp
91
92 if [ ! -z "$IPV6IF" ]; then
93   start_ipv6_if $IPV6IF
94 fi
95
96 # disable swap
97 #SWAPFILES=$(grep swap /etc/fstab | sed '/^[ \t]*#/ d' |cut -f1 -d' ')
98 SWAPFILES=$(grep swap /etc/fstab | sed '/^[ \t]*#/ d' | sed 's/[\t ]/ /g' | tr -s " " | cut -f1 -d' ')
99 if [ ! -z $SWAPFILES ]; then
100   for SWAPFILE in $SWAPFILES
101   do
102     if [ ! -z $SWAPFILE ]; then
103       echo "disabling swap file $SWAPFILE"
104       if [[ $SWAPFILE == UUID* ]]; then
105         UUID=$(echo $SWAPFILE | cut -f2 -d'=')
106         swapoff -U $UUID
107       else
108         swapoff $SWAPFILE
109       fi
110       sed -i "\%$SWAPFILE%d" /etc/fstab
111     fi
112   done
113 fi
114
115
116 DOCKERV=$(cat /opt/config/docker_version.txt)
117 KUBEV=$(cat /opt/config/k8s_version.txt)
118 KUBECNIV=$(cat /opt/config/k8s_cni_version.txt)
119
120 KUBEVERSION="${KUBEV}-00"
121 CNIVERSION="${KUBECNIV}-00"
122 DOCKERVERSION="${DOCKERV}"
123
124 # adjust package version tag
125 UBUNTU_RELEASE=$(lsb_release -r | sed 's/^[a-zA-Z:\t ]\+//g')
126 if [[ ${UBUNTU_RELEASE} == 16.* ]]; then
127   echo "Installing on Ubuntu $UBUNTU_RELEASE (Xenial Xerus) host"
128   if [ ! -z "${DOCKERV}" ]; then
129     DOCKERVERSION="${DOCKERV}-0ubuntu1~16.04.5"
130   fi
131 elif [[ ${UBUNTU_RELEASE} == 18.* ]]; then
132   echo "Installing on Ubuntu $UBUNTU_RELEASE (Bionic Beaver)"
133   if [ ! -z "${DOCKERV}" ]; then
134     DOCKERVERSION="${DOCKERV}-0ubuntu1~18.04.4"
135   fi
136 else
137   echo "Unsupported Ubuntu release ($UBUNTU_RELEASE) detected.  Exit."
138   exit
139 fi
140
141
142 curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
143 echo 'deb http://apt.kubernetes.io/ kubernetes-xenial main' > /etc/apt/sources.list.d/kubernetes.list
144
145 # tell apt to retry 3 times if failed
146 mkdir -p /etc/apt/apt.conf.d
147 echo "APT::Acquire::Retries \"3\";" > /etc/apt/apt.conf.d/80-retries
148
149 # install low latency kernel, docker.io, and kubernetes
150 apt-get update
151 RES=$(apt-get install -y virt-what curl jq netcat make ipset moreutils 2>&1)
152 if [[ $RES == */var/lib/dpkg/lock* ]]; then
153   echo "Fail to get dpkg lock.  Wait for any other package installation"
154   echo "process to finish, then rerun this script"
155   exit -1
156 fi
157
158 if ! echo $(virt-what) | grep "virtualbox"; then
159   # this version of low latency kernel causes virtualbox VM to hang.
160   # install if identifying the VM not being a virtualbox VM.
161   apt-get install -y linux-image-4.15.0-45-lowlatency
162 fi
163
164 APTOPTS="--allow-downgrades --allow-change-held-packages --allow-unauthenticated --ignore-hold "
165
166 # remove infrastructure stack if present
167 # note the order of the packages being removed.
168 for PKG in kubeadm docker.io; do
169   INSTALLED_VERSION=$(dpkg --list |grep ${PKG} |tr -s " " |cut -f3 -d ' ')
170   if [ ! -z ${INSTALLED_VERSION} ]; then
171     if [ "${PKG}" == "kubeadm" ]; then
172       kubeadm reset -f
173       rm -rf ~/.kube
174       apt-get -y $APTOPTS remove kubeadm kubelet kubectl kubernetes-cni
175     else
176       apt-get -y $APTOPTS remove "${PKG}"
177     fi
178   fi
179 done
180 apt-get -y autoremove
181
182 # install docker
183 if [ -z ${DOCKERVERSION} ]; then
184   apt-get install -y $APTOPTS docker.io
185 else
186   apt-get install -y $APTOPTS docker.io=${DOCKERVERSION}
187 fi
188 cat > /etc/docker/daemon.json <<EOF
189 {
190   "exec-opts": ["native.cgroupdriver=systemd"],
191   "log-driver": "json-file",
192   "log-opts": {
193     "max-size": "100m"
194   },
195   "storage-driver": "overlay2"
196 }
197 EOF
198 mkdir -p /etc/systemd/system/docker.service.d
199 systemctl enable docker.service
200 systemctl daemon-reload
201 systemctl restart docker
202
203 if [ -z ${CNIVERSION} ]; then
204   apt-get install -y $APTOPTS kubernetes-cni
205 else
206   apt-get install -y $APTOPTS kubernetes-cni=${CNIVERSION}
207 fi
208
209 if [ -z ${KUBEVERSION} ]; then
210   apt-get install -y $APTOPTS kubeadm kubelet kubectl
211 else
212   apt-get install -y $APTOPTS kubeadm=${KUBEVERSION} kubelet=${KUBEVERSION} kubectl=${KUBEVERSION}
213 fi
214
215 apt-mark hold docker.io kubernetes-cni kubelet kubeadm kubectl
216
217
218 # test access to k8s docker registry
219 kubeadm config images pull --kubernetes-version=${KUBEV}
220
221
222 NODETYPE="master"
223 # non-master nodes have hostnames ending with -[0-9][0-9]
224 if [ "$NODETYPE" == "master" ]; then
225   # below are steps for initializating master node, only run on the master node.  
226   # minion node join will be triggered from the caller of the stack creation as ssh command.
227
228   # create kubenetes config file
229   if [[ ${KUBEV} == 1.13.* ]]; then
230     cat <<EOF >/root/config.yaml
231 apiVersion: kubeadm.k8s.io/v1alpha3
232 kubernetesVersion: v${KUBEV}
233 kind: ClusterConfiguration
234 apiServerExtraArgs:
235   feature-gates: SCTPSupport=true
236 networking:
237   dnsDomain: cluster.local
238   podSubnet: 10.244.0.0/16
239   serviceSubnet: 10.96.0.0/12
240 ---
241 apiVersion: kubeproxy.config.k8s.io/v1alpha1
242 kind: KubeProxyConfiguration
243 mode: ipvs
244 EOF
245
246   elif [[ ${KUBEV} == 1.14.* ]]; then
247     cat <<EOF >/root/config.yaml
248 apiVersion: kubeadm.k8s.io/v1beta1
249 kubernetesVersion: v${KUBEV}
250 kind: ClusterConfiguration
251 apiServerExtraArgs:
252   feature-gates: SCTPSupport=true
253 networking:
254   dnsDomain: cluster.local
255   podSubnet: 10.244.0.0/16
256   serviceSubnet: 10.96.0.0/12
257 ---
258 apiVersion: kubeproxy.config.k8s.io/v1alpha1
259 kind: KubeProxyConfiguration
260 mode: ipvs
261 EOF
262   elif [[ ${KUBEV} == 1.15.* ]] || [[ ${KUBEV} == 1.16.* ]] || [[ ${KUBEV} == 1.18.* ]]; then
263     cat <<EOF >/root/config.yaml
264 apiVersion: kubeadm.k8s.io/v1beta2
265 kubernetesVersion: v${KUBEV}
266 kind: ClusterConfiguration
267 apiServer:
268   extraArgs:
269     feature-gates: SCTPSupport=true
270 networking:
271   dnsDomain: cluster.local
272   podSubnet: 10.244.0.0/16
273   serviceSubnet: 10.96.0.0/12
274 ---
275 apiVersion: kubeproxy.config.k8s.io/v1alpha1
276 kind: KubeProxyConfiguration
277 mode: ipvs
278 EOF
279   else
280     echo "Unsupported Kubernetes version requested.  Bail."
281     exit
282   fi
283
284   # create a RBAC file for helm (tiller)
285   cat <<EOF > /root/rbac-config.yaml
286 apiVersion: v1
287 kind: ServiceAccount
288 metadata:
289   name: tiller
290   namespace: kube-system
291 ---
292 apiVersion: rbac.authorization.k8s.io/v1
293 kind: ClusterRoleBinding
294 metadata:
295   name: tiller
296 roleRef:
297   apiGroup: rbac.authorization.k8s.io
298   kind: ClusterRole
299   name: cluster-admin
300 subjects:
301   - kind: ServiceAccount
302     name: tiller
303     namespace: kube-system
304 EOF
305
306
307   # start cluster (make sure CIDR is enabled with the flag)
308   kubeadm init --config /root/config.yaml
309
310   # set up kubectl credential and config
311   cd /root
312   rm -rf .kube
313   mkdir -p .kube
314   cp -i /etc/kubernetes/admin.conf /root/.kube/config
315   chown root:root /root/.kube/config
316   export KUBECONFIG=/root/.kube/config
317   echo "KUBECONFIG=${KUBECONFIG}" >> /etc/environment
318
319   # at this point we should be able to use kubectl
320   kubectl get pods --all-namespaces
321
322   # install flannel
323   kubectl apply -f "https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml"
324
325   # waiting for all 8 kube-system pods to be in running state
326   # (at this point, minions have not joined yet)
327   wait_for_pods_running 8 kube-system
328
329   # if running a single node cluster, need to enable master node to run pods
330   kubectl taint nodes --all node-role.kubernetes.io/master-
331
332   # install Helm
333   HELMV=$(cat /opt/config/helm_version.txt)
334   HELMVERSION=${HELMV}
335   if [ ! -e helm-v${HELMVERSION}-linux-amd64.tar.gz ]; then
336     wget https://get.helm.sh/helm-v${HELMVERSION}-linux-amd64.tar.gz
337   fi
338   cd /root && rm -rf Helm && mkdir Helm && cd Helm
339   tar -xvf ../helm-v${HELMVERSION}-linux-amd64.tar.gz
340   mv linux-amd64/helm /usr/local/bin/helm
341
342   cd /root
343   # install RBAC for Helm
344   if [[ ${HELMVERSION} == 2.* ]]; then
345      kubectl create -f rbac-config.yaml
346   fi
347
348   rm -rf /root/.helm
349   if [[ ${KUBEV} == 1.16.* ]]; then
350     # helm init uses API extensions/v1beta1 which is depreciated by Kubernetes
351     # 1.16.0.  Until upstream (helm) provides a fix, this is the work-around.
352     if [[ ${HELMVERSION} == 2.* ]]; then
353        helm init --service-account tiller --override spec.selector.matchLabels.'name'='tiller',spec.selector.matchLabels.'app'='helm' --output yaml > /tmp/helm-init.yaml
354        sed 's@apiVersion: extensions/v1beta1@apiVersion: apps/v1@' /tmp/helm-init.yaml > /tmp/helm-init-patched.yaml
355        kubectl apply -f /tmp/helm-init-patched.yaml
356     fi
357   else
358     if [[ ${HELMVERSION} == 2.* ]]; then
359        helm init --service-account tiller
360     fi
361   fi
362   if [[ ${HELMVERSION} == 2.* ]]; then
363      helm init -c
364      export HELM_HOME="$(pwd)/.helm"
365      echo "HELM_HOME=${HELM_HOME}" >> /etc/environment
366   fi
367
368   # waiting for tiller pod to be in running state
369   while ! helm version; do
370     echo "Waiting for Helm to be ready"
371     sleep 15
372   done
373
374   echo "Preparing a master node (lowser ID) for using local FS for PV"
375   PV_NODE_NAME=$(kubectl get nodes |grep master | cut -f1 -d' ' | sort | head -1)
376   kubectl label --overwrite nodes $PV_NODE_NAME local-storage=enable
377   if [ "$PV_NODE_NAME" == "$(hostname)" ]; then
378     mkdir -p /opt/data/dashboard-data
379   fi
380
381   echo "Done with master node setup"
382 fi
383
384
385 # add rancodev CI tool hostnames
386 if [[ ! -z "${__RUNRICENV_GERRIT_IP__}" && ! -z "${__RUNRICENV_GERRIT_HOST__}" ]]; then 
387   echo "${__RUNRICENV_GERRIT_IP__} ${__RUNRICENV_GERRIT_HOST__}" >> /etc/hosts
388 fi
389 if [[ ! -z "${__RUNRICENV_DOCKER_IP__}" && ! -z "${__RUNRICENV_DOCKER_HOST__}" ]]; then 
390   echo "${__RUNRICENV_DOCKER_IP__} ${__RUNRICENV_DOCKER_HOST__}" >> /etc/hosts
391 fi
392 if [[ ! -z "${__RUNRICENV_HELMREPO_IP__}" && ! -z "${__RUNRICENV_HELMREPO_HOST__}" ]]; then 
393   echo "${__RUNRICENV_HELMREPO_IP__} ${__RUNRICENV_HELMREPO_HOST__}" >> /etc/hosts
394 fi
395
396 if [[ "${__RUNRICENV_HELMREPO_CERT_LEN__}" -gt "100" ]]; then
397   cat <<EOF >/etc/ca-certificates/update.d/helm.crt
398 ${__RUNRICENV_HELMREPO_CERT__}
399 EOF
400 fi
401
402 # add cert for accessing docker registry in Azure
403 if [[ "${__RUNRICENV_DOCKER_CERT_LEN__}" -gt "100" ]]; then
404   mkdir -p /etc/docker/certs.d/${__RUNRICENV_DOCKER_HOST__}:${__RUNRICENV_DOCKER_PORT__}
405   cat <<EOF >/etc/docker/ca.crt
406 ${__RUNRICENV_DOCKER_CERT__}
407 EOF
408   cp /etc/docker/ca.crt /etc/docker/certs.d/${__RUNRICENV_DOCKER_HOST__}:${__RUNRICENV_DOCKER_PORT__}/ca.crt
409
410   service docker restart
411   systemctl enable docker.service
412   docker login -u ${__RUNRICENV_DOCKER_USER__} -p ${__RUNRICENV_DOCKER_PASS__} ${__RUNRICENV_DOCKER_HOST__}:${__RUNRICENV_DOCKER_PORT__}
413   docker pull ${__RUNRICENV_DOCKER_HOST__}:${__RUNRICENV_DOCKER_PORT__}/whoami:0.0.1
414 fi
415
416 if [ "$(uname -r)" != "4.15.0-45-lowlatency" ]; then reboot; fi