基於Kubeadm 搭建K8s集群:
通過上一篇博客,我們已經基本了解了 k8s 的基本概念,也許你現在還是有些模糊,說真的我也是很模糊的。只有不斷地操作去熟練,強化自己對他的認知,才能提升境界。
我們就去搭建一個集群來感受一下。我這里搭建的一個Master 2個 Worker。盡量保持機器環境干凈,我由於minikube沒裝好導致kubelet一直無法啟動。
- One or more machines running one of:2 GB or more of RAM per machine (any less will leave little room for your apps)
- Ubuntu 16.04+
- Debian 9+
- CentOS 7【本案例演示】
- Red Hat Enterprise Linux (RHEL) 7
- Fedora 25+
- HypriotOS v1.0.1+
- Container Linux (tested with 1800.6.0)
- 2 CPUs or more
- Full network connectivity between all machines in the cluster (public or private network is fine)
- Unique hostname, MAC address, and product_uuid for every node. See here for more details.
- Certain ports are open on your machines. See here for more details.
- Swap disabled. You MUST disable swap in order for the kubelet to work properly.
組件版本(很重要):
Docker 18.09.0
--- kubeadm-1.14.0-0 kubelet-1.14.0-0 kubectl-1.14.0-0
--- k8s.gcr.io/kube-apiserver:v1.14.0 k8s.gcr.io/kube-controller-manager:v1.14.0 k8s.gcr.io/kube-scheduler:v1.14.0 k8s.gcr.io/kube-proxy:v1.14.0 k8s.gcr.io/pause:3.1 k8s.gcr.io/etcd:3.3.10 k8s.gcr.io/coredns:1.3.1
--- calico:v3.9
1.更新並安裝依賴:
yum -y update //這個命令會更新內核,不推薦使用,除非你確保更新完沒問題。有可能更新完機器起不來 報個 Minimal 。。。啥錯。
yum -y upgrade // 推薦使用
yum install -y conntrack ipvsadm ipset jq sysstat curl iptables libseccomp //安裝依賴
2.安裝Docker
3.修改 hosts 文件:
永久修改hostname:vi /etc/sysconfig/network,最后增加一行,比如hostname=m這種。
192.168.1.101執行:sudo hostnamectl set-hostname m 192.168.1.102執行:sudo hostnamectl set-hostname w1 192.168.1.103執行:sudo hostnamectl set-hostname w2 //修改三台的hosts
vi /etc/hosts 192.168.1.101 m 192.168.1.102 w1 192.168.1.103 w2
4.系統基礎前提配置(官網有提到):
# (1)關閉防火牆 systemctl stop firewalld && systemctl disable firewalld # (2)關閉selinux setenforce 0 sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config # (3)關閉swap swapoff -a sed -i '/swap/s/^\(.*\)$/#\1/g' /etc/fstab # (4)配置iptables的ACCEPT規則 iptables -F && iptables -X && iptables -F -t nat && iptables -X -t nat && iptables -P FORWARD ACCEPT # (5)設置系統參數 cat <<EOF > /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sysctl --system
5.Installing kubeadm, kubelet and kubectl
官網對這三個組件是這么介紹的:You will install these packages on all of your machines:
-
kubeadm
: the command to bootstrap the cluster. -
kubelet
: the component that runs on all of the machines in your cluster and does things like starting pods and containers. -
kubectl
: the command line util to talk to your cluster.
由於這三個的源官方推薦的是國外的源我們沒辦法訪問,我們這里改成阿里雲的源:
//# 1 配置源
cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1 gpgcheck=0 repo_gpgcheck=0 gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF //# 2 安裝kubeadm&kubelet&kubectl
yum install -y kubeadm-1.14.0-0 kubelet-1.14.0-0 kubectl-1.14.0-0
//# 3 docker和k8s設置同一個cgroup //# docker
vi /etc/docker/daemon.json 添加:"exec-opts": ["native.cgroupdriver=systemd"], systemctl restart docker //# kubelet,這邊如果發現輸出directory not exist,也說明是沒問題的,大家繼續往下進行即可
sed -i "s/cgroup-driver=systemd/cgroup-driver=cgroupfs/g" /etc/systemd/system/kubelet.service.d/10-kubeadm.conf //重啟
systemctl enable kubelet && systemctl start kubelet
6.proxy/pause/scheduler等國內鏡像:
1.查看kubeadm使用的鏡像 kubeadm config images list
可以發現這里都是國外的鏡像,為了解決國外鏡像不能訪問的問題,創建kubeadm.sh腳本,我們基於阿里雲的docker-image用於拉取鏡像/打tag(重命名成k8s識別的如上圖中的名稱)/刪除原有鏡像。腳本如下:
#!/bin/bash set -e KUBE_VERSION=v1.14.0 KUBE_PAUSE_VERSION=3.1 ETCD_VERSION=3.3.10 CORE_DNS_VERSION=1.3.1 GCR_URL=k8s.gcr.io ALIYUN_URL=registry.cn-hangzhou.aliyuncs.com/google_containers images=(kube-proxy:${KUBE_VERSION} kube-scheduler:${KUBE_VERSION} kube-controller-manager:${KUBE_VERSION} kube-apiserver:${KUBE_VERSION} pause:${KUBE_PAUSE_VERSION} etcd:${ETCD_VERSION} coredns:${CORE_DNS_VERSION}) for imageName in ${images[@]} ; do docker pull $ALIYUN_URL/$imageName docker tag $ALIYUN_URL/$imageName $GCR_URL/$imageName docker rmi $ALIYUN_URL/$imageName done
運行腳本:sh ./kubeadm.sh
查看鏡像:
docker images 可以看到鏡像准備完畢.
如果需要把鏡像保存下來可以將其推送到阿里雲,具體步驟參照 https://www.cnblogs.com/wuzhenzhao/p/11798039.html 腳本如下:
#!/bin/bash set -e KUBE_VERSION=v1.14.0 KUBE_PAUSE_VERSION=3.1 ETCD_VERSION=3.3.10 CORE_DNS_VERSION=1.3.1 GCR_URL=k8s.gcr.io ALIYUN_URL=xxx images=(kube-proxy:${KUBE_VERSION} kube-scheduler:${KUBE_VERSION} kube-controller-manager:${KUBE_VERSION} kube-apiserver:${KUBE_VERSION} pause:${KUBE_PAUSE_VERSION} etcd:${ETCD_VERSION} coredns:${CORE_DNS_VERSION}) for imageName in ${images[@]} ; do docker tag $GCR_URL/$imageName $ALIYUN_URL/$imageName docker push $ALIYUN_URL/$imageName docker rmi $ALIYUN_URL/$imageName done
7.kube init 初始化 master:
在此之前我們需要看一下 kubelet 的狀態,他要是沒起來就會出問題:systemctl status kubelet
運行journalctl -xefu kubelet
命令查看systemd日志
在kubeadm init
之前kubelet會不斷重啟。
然后進入初始化 Master 節點:【若要重新初始化集群狀態:kubeadm reset,然后再進行上述操作】 阿里雲如果沒有域名使用內網。不然報錯
#本地有鏡像 kubeadm init --kubernetes-version=1.14.0 --apiserver-advertise-address=192.168.1.101 --pod-network-cidr=10.244.0.0/16
然后會看到打印出來的信息:如果沒成功,可以查看日志信息 tail /var/log/message 來查看
根據日志提示執行三個命令:
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
其中有一條非常重要的信息,就是Worker節點 kubeadm join的信息: 阿里雲要配置內網互通:跨賬號同地域網絡實例互通
kubeadm join 192.168.1.101:6443 --token w8lo7h.pozwo9cnfzzgqsr5 \ --discovery-token-ca-cert-hash sha256:ddaa9ca87e04a51031572c50e8140e76fbb31ac1b9b40e48ffbff84ff29eb32f
這個如果超過了24小時,則需要重新生成Token。腳本如下:
#!/bin/bash if [ $EUID -ne 0 ];then echo "You must be root (or sudo) to run this script" exit 1 fi if [ $# != 1 ] ; then echo "Usage: $0 [master-hostname | master-ip-address]" echo " e.g.: $0 api.k8s.hiko.im" exit 1; fi token=`kubeadm token create` cert_hash=`openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'` echo "Refer the following command to join kubernetes cluster:" echo "kubeadm join $1:6443 --token ${token} --discovery-token-ca-cert-hash sha256:${cert_hash}"
sudo sh ./join.sh IP/hostname ,執行以下就OK啦。
此時kubectl cluster-info查看一下是否成功:
查看pod驗證一下,等待一會兒【一定要等待最下面5個pod啟動成功,處於ready狀態再往下進行,不然后面會出錯】然后可以發現像etc,controller,scheduler等組件都以pod的方式安裝成功了
注意
:coredns沒有啟動,需要安裝網絡插件
kubectl get pods -n kube-system
健康檢查: curl -k https://localhost:6443/healthz
這個步驟主要做了以下幾件事:
//01-進行一系列檢查,以確定這台機器可以部署kubernetes
//02-生成kubernetes對外提供服務所需要的各種證書可對應目錄
/etc/kubernetes/pki/*
//03-為其他組件生成訪問kube-ApiServer所需的配置文件
ls /etc/kubernetes/
admin.conf controller-manager.conf kubelet.conf scheduler.conf
//04-為 Master組件生成Pod配置文件。
ls /etc/kubernetes/manifests/*.yaml
kube-apiserver.yaml
kube-controller-manager.yaml
kube-scheduler.yaml
//05-生成etcd的Pod YAML文件。
ls /etc/kubernetes/manifests/*.yaml
kube-apiserver.yaml
kube-controller-manager.yaml
kube-scheduler.yaml
etcd.yaml
//06-一旦這些 YAML 文件出現在被 kubelet 監視的/etc/kubernetes/manifests/目錄下,kubelet就會自動創建這些yaml文件定義的pod,即master組件的容器。master容器啟動后,kubeadm會通過檢查localhost:6443/healthz這個master組件的健康狀態檢查URL,等待master組件完全運行起來
//07-為集群生成一個bootstrap token
//08-將ca.crt等 Master節點的重要信息,通過ConfigMap的方式保存在etcd中,工后續部署node節點使用
//09-最后一步是安裝默認插件,kubernetes默認kube-proxy和DNS兩個插件是必須安裝的
8.部署calico網絡插件:
選擇網絡插件(官網網絡插件介紹):https://kubernetes.io/docs/concepts/cluster-administration/addons/
calico網絡插件(calico插件介紹):https://docs.projectcalico.org/v3.9/getting-started/kubernetes/
在master節點上操作,我這里是把這個yaml下載下來放在了本地。:
# 在k8s中安裝calico # 這里實際上就是用了一個calico.yaml文件,大家也可以把這個文件下載下來,看看里面的內容 kubectl apply -f https://docs.projectcalico.org/v3.9/manifests/calico.yaml
確認一下calico是否安裝成功【一定要等待所有的pod都成功了,處於ready狀態再往下進行,不然會報錯】
kubectl get pods --all-namespaces -w
9.worker 節點 join:
在master節點上檢查集群信息 kubectl get nodes
刪除節點:kubectl delete nodes w2
如果要重新加入,也要執行 kubeadm reset
卸載清理K8s:
kubeadm reset -f modprobe -r ipip lsmod rm -rf ~/.kube/ rm -rf /etc/kubernetes/ rm -rf /etc/systemd/system/kubelet.service.d rm -rf /etc/systemd/system/kubelet.service rm -rf /usr/bin/kube* rm -rf /etc/cni rm -rf /opt/cni rm -rf /var/lib/etcd rm -rf /var/etcd
Pod初體驗:
1.定義pod.yml文件,比如pod_nginx_rs.yaml
cat > pod_nginx_rs.yaml <<EOF apiVersion: apps/v1 kind: ReplicaSet metadata: name: nginx labels: tier: frontend spec: replicas: 3 selector: matchLabels: tier: frontend template: metadata: name: nginx labels: tier: frontend spec: containers: - name: nginx image: nginx ports: - containerPort: 80 EOF
2.根據pod_nginx_rs.yml文件創建pod
kubectl apply -f pod_nginx_rs.yaml
創建完查看一下pod,發現還在創建
等待一段時間再看:kubectl get pods
查看 kubectl get pods -o wide
查看描述 kubectl describe pod nginx ,如果沒啟動也能看到報錯信息。
[root@m ~]# kubectl describe pod nginx Name: nginx-66rpb Namespace: default Priority: 0 PriorityClassName: <none> Node: w1/192.168.1.102 Start Time: Wed, 18 Dec 2019 20:41:34 +0800 Labels: tier=frontend Annotations: cni.projectcalico.org/podIP: 192.168.190.65/32 Status: Running IP: 192.168.190.65 Controlled By: ReplicaSet/nginx Containers: nginx: Container ID: docker://cbff183cec2a5619f15149b8a1652018e0796db7fdee0407b9e9df47a6015ccf
Image: nginx Image ID: docker-pullable://nginx@sha256:50cf965a6e08ec5784009d0fccb380fc479826b6e0e65684d9879170a9df8566
Port: 80/TCP Host Port: 0/TCP State: Running Started: Wed, 18 Dec 2019 20:42:44 +0800 Ready: True Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-rq7b2 (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: default-token-rq7b2: Type: Secret (a volume populated by a Secret) SecretName: default-token-rq7b2 Optional: false QoS Class: BestEffort Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s node.kubernetes.io/unreachable:NoExecute for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m33s default-scheduler Successfully assigned default/nginx-66rpb to w1 Normal Pulling 2m30s kubelet, w1 Pulling image "nginx" Normal Pulled 84s kubelet, w1 Successfully pulled image "nginx" Normal Created 84s kubelet, w1 Created container nginx Normal Started 83s kubelet, w1 Started container nginx //.....省略其余兩個的信息,一摸一樣
[root@m ~]#
訪問一下:OK
3.感受通過rs將pod擴容:
kubectl scale rs nginx --replicas=5
查看:kubectl get pods -o wide
刪除pod:kubectl delete -f pod_nginx_rs.yaml
刪除完成。
pod.yaml:
我們來簡單的看一下配置文件的內容:
apiVersion: v1 --版本號
kind: Pod -- 資源類型
metadata: --元數據
name: nginx -- 名稱
labels: -- 標簽
app: nginx
spec:
containers: --容器 ,可以多個
- name: nginx
image: nginx
ports:
- containerPort: 80
- name: mysql
image: mysql
ports:
- containerPort: 3306
對於其中的內容我們做一個簡單的了解先。其實pod中運行的容器正是我們通過docker ps|grep nginx 看到的
我們會發現,無論哪個pod,里面都會存在一個k8s.gcr.io/pause:3.1,這個東西是干嘛的呢?Pod內的容器都是平等的關系,共享Network Namespace、共享文件
pause容器的最主要的作用:創建共享的網絡名稱空間,以便於其它容器以平等的關系加入此網絡名稱空間
pause進程是pod中所有容器的父進程(即第一個進程)Pod會有獨立的IP地址,這個IP地址是被Pod中所有的Container共享的;
就好像docker中網絡共享中多個容器之間的通信我們可以通過 docker network connect tomcat-net tomcat01來加入另外的網絡,或者在創建容器的時候使用 link。可以類比成這里是工具幫我加入到了 pause 容器的網絡。使得容器間得以通信。