2. 死磕 k8s系列之安裝k8s集群(v1.16.2)
- 2020 年 2 月 10 日
- 筆記
![](https://ask.qcloudimg.com/http-save/yehe-5761033/gxrkvweasp.png)
註:本文基於k8s集群v1.16.2版本。
簡介
k8s真是一個複雜的東西,每一次安裝都可能出現不一樣的問題,本文特記錄下來彤哥安裝過程中出現的一些問題及解決方案。
配置要求
- 3台2核4G的ECS
可以到阿里雲、騰訊雲上購買按需付費,用完釋放
- CentOS 7.6
此版本驗證通過,其它版本不確定
安裝軟體的版本
- Docker 18.09.7
- Kubernetes v1.16.2
安裝後的拓撲結構為一個master節點,兩個worker節點。
- nginx-ingress 1.5.5
安裝過程
檢查 centos / hostname
# 在 master 節點和 worker 節點都要執行 cat /etc/redhat-release # 此處 hostname 的輸出將會是該機器在 Kubernetes 集群中的節點名字 # 不能使用 localhost 作為節點的名字 hostname # 請使用 lscpu 命令,核對 CPU 資訊 # Architecture: x86_64 本安裝文檔不支援 arm 架構 # CPU(s): 2 CPU 內核數量不能低於 2 lscpu
修改 hostname
如果您需要修改 hostname,可執行如下指令:
# 修改 hostname hostnamectl set-hostname [your-new-host-name] # 查看修改結果 hostnamectl status # 設置 hostname 解析 echo "127.0.0.1 $(hostname)" >> /etc/hosts
安裝 docker / kubelet
使用 root 身份在所有節點執行如下程式碼,以安裝軟體:
- docker
- nfs-utils
- kubectl / kubeadm / kubelet
手動執行以下程式碼,或保存為sh腳本執行:
#!/bin/bash # 在 master 節點和 worker 節點都要執行 # 安裝 docker # 參考文檔如下 # https://docs.docker.com/install/linux/docker-ce/centos/ # https://docs.docker.com/install/linux/linux-postinstall/ # 卸載舊版本 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 # 設置 yum repository yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo # 安裝並啟動 docker yum install -y docker-ce-18.09.7 docker-ce-cli-18.09.7 containerd.io systemctl enable docker systemctl start docker # 安裝 nfs-utils # 必須先安裝 nfs-utils 才能掛載 nfs 網路存儲 yum install -y nfs-utils yum install -y wget # 關閉 防火牆 systemctl stop firewalld systemctl disable firewalld # 關閉 SeLinux setenforce 0 sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config # 關閉 swap swapoff -a yes | cp /etc/fstab /etc/fstab_bak cat /etc/fstab_bak |grep -v swap > /etc/fstab # 修改 /etc/sysctl.conf # 如果有配置,則修改 sed -i "s#^net.ipv4.ip_forward.*#net.ipv4.ip_forward=1#g" /etc/sysctl.conf sed -i "s#^net.bridge.bridge-nf-call-ip6tables.*#net.bridge.bridge-nf-call-ip6tables=1#g" /etc/sysctl.conf sed -i "s#^net.bridge.bridge-nf-call-iptables.*#net.bridge.bridge-nf-call-iptables=1#g" /etc/sysctl.conf # 可能沒有,追加 echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf echo "net.bridge.bridge-nf-call-ip6tables = 1" >> /etc/sysctl.conf echo "net.bridge.bridge-nf-call-iptables = 1" >> /etc/sysctl.conf # 執行命令以應用 sysctl -p # 配置K8S的yum源 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 # 卸載舊版本 yum remove -y kubelet kubeadm kubectl # 安裝kubelet、kubeadm、kubectl yum install -y kubelet-1.16.2 kubeadm-1.16.2 kubectl-1.16.2 # 修改docker Cgroup Driver為systemd # # 將/usr/lib/systemd/system/docker.service文件中的這一行 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock # # 修改為 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --exec-opt native.cgroupdriver=systemd # 如果不修改,在添加 worker 節點時可能會碰到如下錯誤 # [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". # Please follow the guide at https://kubernetes.io/docs/setup/cri/ sed -i "s#^ExecStart=/usr/bin/dockerd.*#ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --exec-opt native.cgroupdriver=systemd#g" /usr/lib/systemd/system/docker.service # 設置 docker 鏡像,提高 docker 鏡像下載速度和穩定性 # 如果您訪問 https://hub.docker.io 速度非常穩定,亦可以跳過這個步驟 curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://f1361db2.m.daocloud.io # 重啟 docker,並啟動 kubelet systemctl daemon-reload systemctl restart docker systemctl enable kubelet && systemctl start kubelet docker version
注意:上面的腳本需要在所有節點上執行。
初始化 master 節點
關於初始化時用到的環境變數:
- APISERVER_NAME 不能是 master 的 hostname
- APISERVER_NAME 必須全為小寫字母、數字、小數點,不能包含減號
- PODSUBNET 所使用的網段不能與 master節點/worker節點 所在的網段重疊。該欄位的取值為一個 CIDR 值,如果您對 CIDR 這個概念還不熟悉,請仍然執行 export PODSUBNET=10.100.0.1/16 命令,不做修改
# 只在 master 節點執行 # 替換 x.x.x.x 為 master 節點實際 IP(請使用內網 IP) # export 命令只在當前 shell 會話中有效,開啟新的 shell 窗口後,如果要繼續安裝過程,請重新執行此處的 export 命令 export MASTER_IP=10.202.12.21 # 替換 apiserver.demo 為 您想要的 dnsName export APISERVER_NAME=apiserver.demo # Kubernetes 容器組所在的網段,該網段安裝完成後,由 kubernetes 創建,事先並不存在於您的物理網路中 echo "${MASTER_IP} ${APISERVER_NAME}" >> /etc/hosts
使用kubeadm初始化master節點,執行以下腳本:
#!/bin/bash # 只在 master 節點執行 # 腳本出錯時終止執行 set -e # 查看完整配置選項 https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2 rm -f ./kubeadm-config.yaml cat <<EOF > ./kubeadm-config.yaml apiVersion: kubeadm.k8s.io/v1beta2 kind: ClusterConfiguration kubernetesVersion: v1.16.2 imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers controlPlaneEndpoint: "${APISERVER_NAME}:6443" networking: serviceSubnet: "10.96.0.0/16" podSubnet: "${POD_SUBNET}" dnsDomain: "cluster.local" EOF # kubeadm init # 根據您伺服器網速的情況,您需要等候 3 - 10 分鐘 kubeadm init --config=kubeadm-config.yaml --upload-certs # 配置 kubectl rm -rf /root/.kube/ mkdir /root/.kube/ cp -i /etc/kubernetes/admin.conf /root/.kube/config # 安裝 calico 網路插件 # 參考文檔 https://docs.projectcalico.org/v3.9/getting-started/kubernetes/ rm -f calico-3.9.2.yaml wget https://kuboard.cn/install-script/calico/calico-3.9.2.yaml sed -i "s#192.168.0.0/16#${POD_SUBNET}#" calico-3.9.2.yaml kubectl apply -f calico-3.9.2.yaml
檢查 master 初始化結果
# 只在 master 節點執行 # 執行如下命令,等待 3-10 分鐘,直到所有的容器組處於 Running 狀態 watch kubectl get pod -n kube-system -o wide # 查看 master 節點初始化結果 kubectl get nodes -o wide
注意,初始化 master 節點時,如果因為中間某些步驟的配置出錯,想要重新初始化 master 節點,請先執行 kubeadm reset 操作。
初始化 worker節點
獲得 join命令參數
在 master 節點上執行
# 只在 master 節點執行 kubeadm token create --print-join-command
執行結果大致類似下面這樣:
# 請不要直接拷貝這條命令,拷貝你的master節點上執行的結果 # 這裡token的有效時間為兩個小時,兩小時內可以在worker節點上執行 kubeadm join apiserver.demo:6443 --token h345zw.em6ycnpcpevxz8as --discovery-token-ca-cert-hash sha256:84a8710bbfbb046915a90064132203ca453353b85ef5d29f961b03f129f7d5e3
初始化worker節點
針對所有的 worker 節點執行
# 只在 worker 節點執行 # 替換 x.x.x.x 為 master 節點實際 IP(請使用內網 IP) export MASTER_IP=x.x.x.x # 替換 apiserver.demo 為初始化 master 節點時所使用的 APISERVER_NAME export APISERVER_NAME=apiserver.demo echo "${MASTER_IP} ${APISERVER_NAME}" >> /etc/hosts # 替換為 master 節點上 kubeadm token create 命令的輸出 kubeadm join apiserver.demo:6443 --token h345zw.em6ycnpcpevxz8as --discovery-token-ca-cert-hash sha256:84a8710bbfbb046915a90064132203ca453353b85ef5d29f961b03f129f7d5e3
檢查初始化結果
在 master 節點上執行
# 只在 master 節點執行 kubectl get nodes -o wide
輸出結果如下:
[root@instance-ji0xk9uh-1 ~]# kubectl get nodes -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME master Ready master 19m v1.16.2 192.168.64.4 <none> CentOS Linux 7 (Core) 3.10.0-957.27.2.el7.x86_64 docker://18.9.7 node1 Ready <none> 2m43s v1.16.2 192.168.64.5 <none> CentOS Linux 7 (Core) 3.10.0-957.27.2.el7.x86_64 docker://18.9.7 node2 Ready <none> 2m17s v1.16.2 192.168.64.6 <none> CentOS Linux 7 (Core) 3.10.0-957.27.2.el7.x86_64 docker://18.9.7
移除 worker 節點
注意,正常情況下,您無需移除 worker 節點,如果添加到集群出錯,您可以移除 worker 節點,再重新嘗試添加。
在準備移除的 worker 節點上執行
# 只在 worker 節點執行 kubeadm reset
在 master 節點上執行
# 只在 master 節點執行 # worker 節點的名字可以通過在節點 master 上執行 kubectl get nodes 命令獲得 kubectl delete node [worker_node1]
安裝 Ingress Controller
在master上新建如下 nginx-ingress.yaml 文件:
# 如果打算用於生產環境,請參考 https://github.com/nginxinc/kubernetes-ingress/blob/v1.5.5/docs/installation.md 並根據您自己的情況做進一步訂製 apiVersion: v1 kind: Namespace metadata: name: nginx-ingress --- apiVersion: v1 kind: ServiceAccount metadata: name: nginx-ingress namespace: nginx-ingress --- apiVersion: v1 kind: Secret metadata: name: default-server-secret namespace: nginx-ingress type: Opaque data: tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN2akNDQWFZQ0NRREFPRjl0THNhWFhEQU5CZ2txaGtpRzl3MEJBUXNGQURBaE1SOHdIUVlEVlFRRERCWk8KUjBsT1dFbHVaM0psYzNORGIyNTBjbTlzYkdWeU1CNFhEVEU0TURreE1qRTRNRE16TlZvWERUSXpNRGt4TVRFNApNRE16TlZvd0lURWZNQjBHQTFVRUF3d1dUa2RKVGxoSmJtZHlaWE56UTI5dWRISnZiR3hsY2pDQ0FTSXdEUVlKCktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQUwvN2hIUEtFWGRMdjNyaUM3QlBrMTNpWkt5eTlyQ08KR2xZUXYyK2EzUDF0azIrS3YwVGF5aGRCbDRrcnNUcTZzZm8vWUk1Y2Vhbkw4WGM3U1pyQkVRYm9EN2REbWs1Qgo4eDZLS2xHWU5IWlg0Rm5UZ0VPaStlM2ptTFFxRlBSY1kzVnNPazFFeUZBL0JnWlJVbkNHZUtGeERSN0tQdGhyCmtqSXVuektURXUyaDU4Tlp0S21ScUJHdDEwcTNRYzhZT3ExM2FnbmovUWRjc0ZYYTJnMjB1K1lYZDdoZ3krZksKWk4vVUkxQUQ0YzZyM1lma1ZWUmVHd1lxQVp1WXN2V0RKbW1GNWRwdEMzN011cDBPRUxVTExSakZJOTZXNXIwSAo1TmdPc25NWFJNV1hYVlpiNWRxT3R0SmRtS3FhZ25TZ1JQQVpQN2MwQjFQU2FqYzZjNGZRVXpNQ0F3RUFBVEFOCkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQWpLb2tRdGRPcEsrTzhibWVPc3lySmdJSXJycVFVY2ZOUitjb0hZVUoKdGhrYnhITFMzR3VBTWI5dm15VExPY2xxeC9aYzJPblEwMEJCLzlTb0swcitFZ1U2UlVrRWtWcitTTFA3NTdUWgozZWI4dmdPdEduMS9ienM3bzNBaS9kclkrcUI5Q2k1S3lPc3FHTG1US2xFaUtOYkcyR1ZyTWxjS0ZYQU80YTY3Cklnc1hzYktNbTQwV1U3cG9mcGltU1ZmaXFSdkV5YmN3N0NYODF6cFErUyt1eHRYK2VBZ3V0NHh3VlI5d2IyVXYKelhuZk9HbWhWNThDd1dIQnNKa0kxNXhaa2VUWXdSN0diaEFMSkZUUkk3dkhvQXprTWIzbjAxQjQyWjNrN3RXNQpJUDFmTlpIOFUvOWxiUHNoT21FRFZkdjF5ZytVRVJxbStGSis2R0oxeFJGcGZnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBdi91RWM4b1JkMHUvZXVJTHNFK1RYZUprckxMMnNJNGFWaEMvYjVyYy9XMlRiNHEvClJOcktGMEdYaVN1eE9ycXgrajlnamx4NXFjdnhkenRKbXNFUkJ1Z1B0ME9hVGtIekhvb3FVWmcwZGxmZ1dkT0EKUTZMNTdlT1l0Q29VOUZ4amRXdzZUVVRJVUQ4R0JsRlNjSVo0b1hFTkhzbysyR3VTTWk2Zk1wTVM3YUhudzFtMApxWkdvRWEzWFNyZEJ6eGc2clhkcUNlUDlCMXl3VmRyYURiUzc1aGQzdUdETDU4cGszOVFqVUFQaHpxdmRoK1JWClZGNGJCaW9CbTVpeTlZTW1hWVhsMm0wTGZzeTZuUTRRdFFzdEdNVWozcGJtdlFmazJBNnljeGRFeFpkZFZsdmwKMm82MjBsMllxcHFDZEtCRThCay90elFIVTlKcU56cHpoOUJUTXdJREFRQUJBb0lCQVFDZklHbXowOHhRVmorNwpLZnZJUXQwQ0YzR2MxNld6eDhVNml4MHg4Mm15d1kxUUNlL3BzWE9LZlRxT1h1SENyUlp5TnUvZ2IvUUQ4bUFOCmxOMjRZTWl0TWRJODg5TEZoTkp3QU5OODJDeTczckM5bzVvUDlkazAvYzRIbjAzSkVYNzZ5QjgzQm9rR1FvYksKMjhMNk0rdHUzUmFqNjd6Vmc2d2szaEhrU0pXSzBwV1YrSjdrUkRWYmhDYUZhNk5nMUZNRWxhTlozVDhhUUtyQgpDUDNDeEFTdjYxWTk5TEI4KzNXWVFIK3NYaTVGM01pYVNBZ1BkQUk3WEh1dXFET1lvMU5PL0JoSGt1aVg2QnRtCnorNTZud2pZMy8yUytSRmNBc3JMTnIwMDJZZi9oY0IraVlDNzVWYmcydVd6WTY3TWdOTGQ5VW9RU3BDRkYrVm4KM0cyUnhybnhBb0dCQU40U3M0ZVlPU2huMVpQQjdhTUZsY0k2RHR2S2ErTGZTTXFyY2pOZjJlSEpZNnhubmxKdgpGenpGL2RiVWVTbWxSekR0WkdlcXZXaHFISy9iTjIyeWJhOU1WMDlRQ0JFTk5jNmtWajJTVHpUWkJVbEx4QzYrCk93Z0wyZHhKendWelU0VC84ajdHalRUN05BZVpFS2FvRHFyRG5BYWkyaW5oZU1JVWZHRXFGKzJyQW9HQkFOMVAKK0tZL0lsS3RWRzRKSklQNzBjUis3RmpyeXJpY05iWCtQVzUvOXFHaWxnY2grZ3l4b25BWlBpd2NpeDN3QVpGdwpaZC96ZFB2aTBkWEppc1BSZjRMazg5b2pCUmpiRmRmc2l5UmJYbyt3TFU4NUhRU2NGMnN5aUFPaTVBRHdVU0FkCm45YWFweUNweEFkREtERHdObit3ZFhtaTZ0OHRpSFRkK3RoVDhkaVpBb0dCQUt6Wis1bG9OOTBtYlF4VVh5YUwKMjFSUm9tMGJjcndsTmVCaWNFSmlzaEhYa2xpSVVxZ3hSZklNM2hhUVRUcklKZENFaHFsV01aV0xPb2I2NTNyZgo3aFlMSXM1ZUtka3o0aFRVdnpldm9TMHVXcm9CV2xOVHlGanIrSWhKZnZUc0hpOGdsU3FkbXgySkJhZUFVWUNXCndNdlQ4NmNLclNyNkQrZG8wS05FZzFsL0FvR0FlMkFVdHVFbFNqLzBmRzgrV3hHc1RFV1JqclRNUzRSUjhRWXQKeXdjdFA4aDZxTGxKUTRCWGxQU05rMXZLTmtOUkxIb2pZT2pCQTViYjhibXNVU1BlV09NNENoaFJ4QnlHbmR2eAphYkJDRkFwY0IvbEg4d1R0alVZYlN5T294ZGt5OEp0ek90ajJhS0FiZHd6NlArWDZDODhjZmxYVFo5MWpYL3RMCjF3TmRKS2tDZ1lCbyt0UzB5TzJ2SWFmK2UwSkN5TGhzVDQ5cTN3Zis2QWVqWGx2WDJ1VnRYejN5QTZnbXo5aCsKcDNlK2JMRUxwb3B0WFhNdUFRR0xhUkcrYlNNcjR5dERYbE5ZSndUeThXczNKY3dlSTdqZVp2b0ZpbmNvVlVIMwphdmxoTUVCRGYxSjltSDB5cDBwWUNaS2ROdHNvZEZtQktzVEtQMjJhTmtsVVhCS3gyZzR6cFE9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo= --- kind: ConfigMap apiVersion: v1 metadata: name: nginx-config namespace: nginx-ingress data: server-names-hash-bucket-size: "1024" --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: nginx-ingress rules: - apiGroups: - "" resources: - services - endpoints verbs: - get - list - watch - apiGroups: - "" resources: - secrets verbs: - get - list - watch - apiGroups: - "" resources: - configmaps verbs: - get - list - watch - update - create - apiGroups: - "" resources: - pods verbs: - list - apiGroups: - "" resources: - events verbs: - create - patch - apiGroups: - extensions resources: - ingresses verbs: - list - watch - get - apiGroups: - "extensions" resources: - ingresses/status verbs: - update - apiGroups: - k8s.nginx.org resources: - virtualservers - virtualserverroutes verbs: - list - watch - get --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: nginx-ingress subjects: - kind: ServiceAccount name: nginx-ingress namespace: nginx-ingress roleRef: kind: ClusterRole name: nginx-ingress apiGroup: rbac.authorization.k8s.io --- apiVersion: apps/v1 kind: DaemonSet metadata: name: nginx-ingress namespace: nginx-ingress annotations: prometheus.io/scrape: "true" prometheus.io/port: "9113" spec: selector: matchLabels: app: nginx-ingress template: metadata: labels: app: nginx-ingress spec: serviceAccountName: nginx-ingress containers: - image: nginx/nginx-ingress:1.5.5 name: nginx-ingress ports: - name: http containerPort: 80 hostPort: 80 - name: https containerPort: 443 hostPort: 443 - name: prometheus containerPort: 9113 env: - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name args: - -nginx-configmaps=$(POD_NAMESPACE)/nginx-config - -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret #- -v=3 # Enables extensive logging. Useful for troubleshooting. #- -report-ingress-status #- -external-service=nginx-ingress #- -enable-leader-election - -enable-prometheus-metrics #- -enable-custom-resources
使用如下命令執行該文件:
kubectl apply -f nginx-ingress.yaml
查看是否安裝成功:
[root@instance-ji0xk9uh-1 ~]# kubectl get all -n nginx-ingress NAME READY STATUS RESTARTS AGE pod/nginx-ingress-55dfk 1/1 Running 0 29s pod/nginx-ingress-9847f 1/1 Running 0 29s NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE daemonset.apps/nginx-ingress 2 2 2 2 2 <none> 29s
驗證是否成功:
# 打開瀏覽器,輸入任意worker節點的ip地址,回車,如果出現 404 NOT FOUND,表示nginx ingress安裝成功 # 因為現在還沒有安裝任何服務,所以出現404是正常的,這個就相當於是一個nginx,用來做後端請求的轉發。
總結
本章我們就把一個完整的k8s集群搭好了,你可能還比較迷茫,不用著急,我們下一章安裝Dashboard,更直觀的感受下k8s集群的魅力。
參考
本文參考自https://kuboard.cn/install/install-k8s.html,非常推薦這個網站,上面有很多k8s不錯的教程,非常適合新手入門。