K8S+Harbor+gluster+haproxy 實踐加坑

K8S+Harbor+gluster+haproxy 實踐加坑

​ —阿特&Max Shen

半年未有blog,今日歸來玩開源。莫問英雄歸路,青山綠水總相逢。

一切緣起都是因爲devops, 容器化已經很流行了。於是我們項目也打算從這方面發展。實踐k8s 開始了痛苦之旅。 本着學習研究的找了文檔看看,發現好像很簡單,於是開了3臺虛擬機,分分鐘好像就可以完成構架。而走過一路發現所謂網上的種種文檔,都是想當然的自己玩的開心。真的生產,要考慮的問題往往會複雜的多。

1、概述

  • docker ,就不講了

  • k8s 是啥,不講了

    講講k8s 架構,否則搭建環境就算搞好了也是一頭霧水。

    k8s 是kubernetes 的簡寫,ks中間正好8個字母。不知道誰起名了 k8s。

    這個集羣主要包括兩個部分:

    • 一個Master節點(主節點)
    • 一羣Node節點(計算節點)

    在這裏插入圖片描述

    從命名來看就知道 Master節點主要還是負責管理和控制。Node節點是工作負載節點,裏面是具體的容器。

    master 節點

    Master節點包括API Server、Scheduler、Controller manager、etcd。

    API Server是整個系統的對外接口,供客戶端和其它組件調用 。

    Scheduler負責對集羣內部的資源進行調度 。

    Controller manager負責管理控制器 。

    etcd是一個高可用的分佈式鍵值(key-value)數據庫。etcd內部採用raft協議作爲一致性算法,etcd基於Go語言實現。主要存儲配置數據
    在這裏插入圖片描述

    Node節點

在這裏插入圖片描述

Node 節點簡言之就是工作節點。

Node節點包括Docker、kubelet、kube-proxy、Fluentd、kube-dns(可選),還有就是Pod

Pod是Kubernetes最基本的操作單元。一個Pod代表着集羣中運行的一個進程,它內部封裝了一個或多個緊密相關的容器。除了Pod之外,K8S還有一個Service的概念,一個Service可以看作一組提供相同服務的Pod的對外訪問接口。

Docker,不用說了,創建容器的。

Kubelet,主要負責監視指派到它所在Node上的Pod,包括創建、修改、監控、刪除等。

Kube-proxy,主要負責爲Pod對象提供代理。

Fluentd,主要負責日誌收集、存儲與查詢。

看了上面是不是感覺有點暈了? 是的,後來會更暈。

深入理解概念

引用博客 https://blog.csdn.net/maoyeqiu/article/details/79270625 的介紹

再來理解一遍

k8s這個容器管理系統根據以上的控制原則設計完成之後就要被使用,使用的話就是通過API的方式,這裏也列出8條API的設計原則:
1、所有API應該是聲明式的。正如前文所說,聲明式的操作,相對於命令式操作,對於重複操作的效果是穩定的,這對於容易出現數據丟失或重複的分佈式環境來說是很重要的。另外,聲明式操作更容易被用戶使用,可以使系統向用戶隱藏實現的細節,隱藏實現的細節的同時,也就保留了系統未來持續優化的可能性。此外,聲明式的API,同時隱含了所有的API對象都是名詞性質的,例如Service、Volume這些API都是名詞,這些名詞描述了用戶所期望得到的一個目標分佈式對象。
2、API對象是彼此互補而且可組合的。這裏面實際是鼓勵API對象儘量實現面向對象設計時的要求,即“高內聚,鬆耦合”,對業務相關的概念有一個合適的分解,提高分解出來的對象的可重用性。事實上,K8s這種分佈式系統管理平臺,也是一種業務系統,只不過它的業務就是調度和管理容器服務。
3、高層API以操作意圖爲基礎設計。如何能夠設計好API,跟如何能用面向對象的方法設計好應用系統有相通的地方,高層設計一定是從業務出發,而不是過早的從技術實現出發。因此,針對K8s的高層API設計,一定是以K8s的業務爲基礎出發,也就是以系統調度管理容器的操作意圖爲基礎設計。
4、低層API根據高層API的控制需要設計。設計實現低層API的目的,是爲了被高層API使用,考慮減少冗餘、提高重用性的目的,低層API的設計也要以需求爲基礎,要儘量抵抗受技術實現影響的誘惑。
5、儘量避免簡單封裝,不要有在外部API無法顯式知道的內部隱藏的機制。簡單的封裝,實際沒有提供新的功能,反而增加了對所封裝API的依賴性。內部隱藏的機制也是非常不利於系統維護的設計方式,例如PetSet和ReplicaSet,本來就是兩種Pod集合,那麼K8s就用不同API對象來定義它們,而不會說只用同一個ReplicaSet,內部通過特殊的算法再來區分這個ReplicaSet是有狀態的還是無狀態。
6、API操作複雜度與對象數量成正比。這一條主要是從系統性能角度考慮,要保證整個系統隨着系統規模的擴大,性能不會迅速變慢到無法使用,那麼最低的限定就是API的操作複雜度不能超過O(N),N是對象的數量,否則系統就不具備水平伸縮性了。
7、API對象狀態不能依賴於網絡連接狀態。由於衆所周知,在分佈式環境下,網絡連接斷開是經常發生的事情,因此要保證API對象狀態能應對網絡的不穩定,API對象的狀態就不能依賴於網絡連接狀態。
8、儘量避免讓操作機制依賴於全局狀態,因爲在分佈式系統中要保證全局狀態的同步是非常困難的。
————————————————
根據k8s的設計理念、控制原則、API的設計原則,設計完之後的系統的樣子,可以通過下邊的架構圖瞭解。

在這裏插入圖片描述

或者可以看一個更高層次的抽象,會更容易理解一些

在這裏插入圖片描述

pod:從上邊的架構圖中,我們可以看到pod是運行在docker之上的,在 kubernetes 的設計中,最基本的管理單位是 pod,而不是 container。pod 是 kubernetes 在容器上的一層封裝,由一組運行在同一主機的一個或者多個容器組成。如果把容器比喻成傳統機器上的一個進程(它可以執行任務,對外提供某種功能),那麼 pod 可以類比爲傳統的主機:它包含了多個容器,爲它們提供共享的一些資源。Pod包含一個或者多個相關的容器,Pod可以認爲是容器的一種延伸擴展,一個Pod也是一個隔離體,而Pod內部包含的一組容器又是共享的(包括PID、Network、IPC、UTS)。除此之外,Pod中的容器可以訪問共同的數據捲來實現文件系統的共享。

通過下邊這個圖可以看到pod的幾種形式,以及通過加捲的方式共享數據方式
在這裏插入圖片描述

Node:Node是Kubernetes中的工作節點,最開始被稱爲minion。一個Node可以是VM或物理機。每個Node(節點)具有運行pod的一些必要服務,並由Master組件進行管理,Node節點上的服務包括Docker、kubelet和kube-proxy。目前Kubernetes支持docker和rkt兩種容器
通過下邊這個圖可以更清晰的看出來node和pod的關係
在這裏插入圖片描述

**kubelet:**在每個節點(node)上都要運行一個 worker 對容器進行生命週期的管理,這個 worker 程序就是kubelet。kubelet的主要功能就是定時從某個地方獲取節點上 pod/container 的期望狀態(運行什麼容器、運行的副本數量、網絡或者存儲如何配置等等),並調用對應的容器平臺接口達到這個狀態。kubelet 還要查看容器是否正常運行,如果容器運行出錯,就要根據設置的重啓策略進行處理。kubelet 還有一個重要的責任,就是監控所在節點的資源使用情況,並定時向 master 報告。知道整個集羣所有節點的資源情況,對於 pod 的調度和正常運行至關重要。

**kube-proxy:**每個節點(node)都有一個組件kube-proxy,實際上是爲service服務的,通過kube-proxy,實現流量從service到pod的轉發,它負責TCP和UDP數據包的網絡路由,kube-proxy也可以實現簡單的負載均衡功能。其實就是管理service的訪問入口,包括集羣內Pod到Service的訪問和集羣外訪問service。 kube-proxy管理sevice的Endpoints,該service對外暴露一個Virtual IP,也成爲Cluster IP, 集羣內通過訪問這個Cluster IP:Port就能訪問到集羣內對應的serivce下的Pod。

**Service:**個人認爲這是k8s重要性僅次於pod的概念,衆所周知,pod生命週期短,狀態不穩定,pod異常後新生成的pod ip會發生變化,之前pod的訪問方式均不可達。通過service對pod做代理,service有固定的ip和port,ip:port組合自動關聯後端pod,即使pod發生改變,kubernetes內部更新這組關聯關係,使得service能夠匹配到新的pod。這樣,通過service提供的固定ip,用戶再也不用關心需要訪問哪個pod,以及pod是否發生改變,大大提高了服務質量。如果pod使用rc創建了多個副本,那麼service就能代理多個相同的pod,所以service可以認爲是一組pod的代理或者是更高層的抽象,其他的service通過本service提供的虛擬IP進行訪問,也可以在service中對代理的一組pod提供負載服務。
通過這個圖片可以看到Service和pod的關係
(原文鏈接:https://blog.csdn.net/maoyeqiu/article/details/79270625)

在這裏插入圖片描述

下邊這個圖從更整體的角度理解Service

在這裏插入圖片描述

現在,假定有2個後臺Pod,並且定義後臺Service的名稱爲‘backend-service’,lable選擇器爲(tier=backend, app=myapp)。backend-service 的Service會完成如下兩件重要的事情:會爲Service創建一個本地集羣的DNS入口,因此前端(frontend)Pod只需要DNS查找主機名爲 ‘backend-service’,就能夠解析出前端應用程序可用的IP地址。現在前端已經得到了後臺服務的IP地址,但是它應該訪問2個後臺Pod的哪一個呢?Service在這2個後臺Pod之間提供透明的負載均衡,會將請求分發給其中的任意一個。通過每個Node上運行的代理(kube-proxy)完成。

**Virtual IP:**k8s分配給Service一個固定IP,這是一個虛擬IP(也稱爲ClusterIP),並不是一個真實存在的IP,無法被ping,沒有實體網絡對象來響應,是由k8s虛擬出來的。虛擬IP的範圍通過k8s API Server的啓動參數 --service-cluster-ip-range=19.254.0.0/16配置;虛擬IP屬於k8s內部的虛擬網絡,外部是尋址不到的。在k8s系統中,實際上是由k8s Proxy組件負責實現虛擬IP路由和轉發的,所以k8s
Node中都必須運行了k8s Proxy,從而在容器覆蓋網絡之上又實現了k8s層級的虛擬轉發網絡

**Endpoint:**每個pod都提供了一個獨立的Endpoint( Pod ip + Container port )以被客戶端訪問

**Endpoints:**當有連接通過ClusterIP 到達Service的時候,service將根據endpoints提供的信息進行路由請求pod,Endpoints的變化可以通過k8s中的selectors手動或自動的被發現

**Label:**Label機制是Kubernetes中的一個重要設計,通過Label進行對象的弱關聯,可以靈活地進行分類和選擇,Label是識別Kubernetes對象(Pod、Service、RC、Node)的標籤,以key/value的方式附加到對象上,Label不提供唯一性,比如可以關聯Service和Pod。Label定義好後其他對象可以使用Label Selector來選擇一組相同label的對象。

**Advisor:**Google的cAdvisor(Container Advisor)“爲容器用戶提供了了解運行時容器資源使用和性能特徵的方法”。cAdvisor的容器抽象基於Google的lmctfy容器棧,因此原生支持Docker容器並能夠“開箱即用”地支持其他的容器類型。cAdvisor部署爲一個運行中的daemon,它會收集、聚集、處理並導出運行中容器的信息。這些信息能夠包含容器級別的資源隔離參數、資源的歷史使用狀況、反映資源使用和網絡統計數據完整歷史狀況的柱狀圖。
以上是node相關的一些概念的解釋,從pod開始,根據關聯性順次解釋,下邊對master中的一些概念進行解讀:

**master:**master節點負責管理整個k8s集羣,這是所有管理任務的入口,master節點負責編排工作node。

Controller Manager作爲集羣內部的管理控制中心,負責集羣內的Node、Pod副本、服務端點(Endpoint)、命名空間(Namespace)、服務賬號(ServiceAccount)、資源定額(ResourceQuota)的管理,當某個Node意外宕機時,Controller Manager會及時發現並執行自動化修復流程,確保集羣始終處於預期的工作狀態。如果說APIServer做的是“前臺”的工作的話,那controller
manager就是負責“後臺”的。每個資源一般都對應有一個控制器,而controller manager就是負責管理這些控制器的。比如我們通過APIServer創建一個pod,當這個pod創建成功後,APIServer的任務就算完成了。而後面保證Pod的狀態始終和我們預期的一樣的重任就由controller manager去保證了。

**Replication Controller(RC):**是Kubernetes中的另一個核心概念,它的職責是確保集羣中有且僅有N個Pod實例,N是RC中定義的Pod副本數量。通過調整RC中的spec.replicas屬性值來實現系統擴容或縮容。通過改變RC中的Pod模板來實現系統的滾動升級。Replication Controller確保任意時間都有指定數量的Pod“副本”在運行。如果爲某個Pod創建了Replication Controller並且指定3個副本,它會創建3個Pod,並且持續監控它們。如果某個Pod不響應,那麼Replication Controller會替換它,保持總數爲3.如果之前不響應的Pod恢復了,現在就有4個Pod了,那麼Replication Controller會將其中一個終止保持總數爲3。如果在運行中將副本總數改爲5,Replication Controller會立刻啓動2個新Pod,保證總數爲5。

**Node Controller:**負責發現、管理和監控集羣中的各個Node節點。

**Endpoint Controller:**定期關聯service和pod(關聯信息由endpoint對象維護),保證service到pod的映射總是最新的。

**Scheduler:**scheduler的職責很明確,就是負責調度pod到合適的Node上。如果把scheduler看成一個黑匣子,那麼它的輸入是pod和由多個Node組成的列表,輸出是Pod和一個Node的綁定,即將這個pod部署到這個Node上。Kubernetes目前提供了調度算法,但是同樣也保留了接口,用戶可以根據自己的需求定義自己的調度算法。

**etcd:**etcd是一個高可用的鍵值存儲系統,Kubernetes使用它來存儲各個資源的狀態,從而實現了Restful的API。

**API Server:**APIServer負責對外提供RESTful的Kubernetes API服務,它是系統管理指令的統一入口,任何對資源進行增刪改查的操作都要交給APIServer處理後再提交給etcd。如架構圖中所示,kubectl(Kubernetes提供的客戶端工具,該工具內部就是對Kubernetes API的調用)是直接和APIServer交互的。只有API Server與存儲通信,其他模塊通過API Server訪問集羣狀態。這樣第一,是爲了保證集羣狀態訪問的安全。第二,是爲了隔離集羣狀態訪問的方式和後端存儲實現的方式:API Server是狀態訪問的方式,不會因爲後端存儲技術etcd的改變改變。加入以後將etcd更換成其他的存儲方式,並不會影響依賴依賴API Server的其他K8s系統模塊。
————————————————
原文鏈接:https://blog.csdn.net/maoyeqiu/article/details/79270625

上面說完後基本上就暈了。 這就好辦了

2、環境準備

爲了滿足生產要求, 那爲了保證control plane穩定可靠,必須是多節點,而且是奇數節點。

有了多節點,前端訪問則需要負載均衡接入,我使用了haproxy 接入羣集。
在這裏插入圖片描述

主機列表,所有主機都是centos 7.7

主機名 IP 角色 軟件
POC-K8SHAProxy01 172.16.8.29 負載均衡 HA-Proxy 1.5.18
k8sm01 172.16.8.21 master docker 19.03.4/kubernetesVersion: v1.16.2
k8sm02 172.16.8.22 master docker 19.03.4/kubernetesVersion: v1.16.2
k8sm03 172.16.8.23 master docker 19.03.4/kubernetesVersion: v1.16.2
k8snode01 172.16.8.24 work node docker 19.03.4/kubernetesVersion: v1.16.2
k8snode02 172.16.8.25 work node docker 19.03.4/kubernetesVersion: v1.16.2
k8snode03 172.16.8.26 work node docker 19.03.4/kubernetesVersion: v1.16.2
poc-gfs01 172.16.8.41 分佈式存儲 glusterfs 6.5
poc-gfs02 172.16.8.42 分佈式存儲 glusterfs 6.5
poc-gfs03 172.16.8.43 分佈式存儲 glusterfs 6.5
poc-gfsclient 172.16.8.44 分佈式存儲API提供 Heketi 8.0.0

3、安裝docker

# Install Docker CE
## Set up the repository
### Install required packages.
yum install yum-utils device-mapper-persistent-data lvm2

### Add Docker repository.
yum-config-manager \
  --add-repo \
  https://download.docker.com/linux/centos/docker-ce.repo

## Install Docker CE. 19.03 
yum update && yum install docker-ce.x86_64

## Create /etc/docker directory.
mkdir /etc/docker

# Setup daemon.
cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2",
  "storage-opts": [
    "overlay2.override_kernel_check=true"
  ]
}
EOF

mkdir -p /etc/systemd/system/docker.service.d

# Restart Docker
systemctl daemon-reload
systemctl restart docker


4、網絡端口需求

Control-plane node(s)

k8sm01,k8sm02,k8sm03

Protocol Direction Port Range Purpose Used By
TCP Inbound 6443 Kubernetes API server All
TCP Inbound 2379-2380 etcd server client API kube-apiserver, etcd
TCP Inbound 10250 Kubelet API Self, Control plane
TCP Inbound 10251 kube-scheduler Self
TCP Inbound 10252 kube-controller-manager Self
UDP Inbound 8285 FLANNEL port
UDP Inbound 8472 FLANNEL port

#執行:

firewall-cmd --zone=public  --add-port=6443/tcp --permanent 
firewall-cmd --zone=public  --add-port=30443/tcp --permanent 
firewall-cmd --zone=public  --add-port=30080/tcp --permanent 
firewall-cmd --zone=public  --add-port=30116/tcp --permanent 
firewall-cmd --zone=public  --add-port=2379-2380/tcp --permanent 
firewall-cmd --zone=public  --add-port=10250/tcp --permanent 
firewall-cmd --zone=public  --add-port=10251/tcp --permanent
firewall-cmd --zone=public  --add-port=10252/tcp --permanent 
firewall-cmd --zone=public  --add-port=8285/udp --permanent 
firewall-cmd --zone=public  --add-port=8472/udp --permanent 
firewall-cmd --reload
firewall-cmd --zone=public --list-ports

Worker node(s)

Protocol Direction Port Range Purpose Used By
TCP Inbound 10250 Kubelet API Self, Control plane
TCP Inbound 30000-32767 NodePort Services** All
UDP Inbound 8285 FLANNEL port
UDP Inbound 8472 FLANNEL port

firewall-cmd --zone=public  --add-port=10250/tcp --permanent
firewall-cmd --zone=public  --add-port=30000-32767/tcp --permanent
firewall-cmd --zone=public  --add-port=8285/udp --permanent 
firewall-cmd --zone=public  --add-port=8472/udp --permanent 
firewall-cmd --reload
firewall-cmd --zone=public --list-ports

5、部署haproxy

配置 kube-apiserver 高可用需要一個負載均衡器,這裏直接使用了一個單節點 haproxy 代替一下,實際生產環境中可能使用 keepalived 保證 haproxy 的高可用

在POC-K8SHAProxy01 節點進行下面安裝:

sudo yum install -y haproxy
firewall-cmd --zone=public  --add-port=6443/tcp --permanent
firewall-cmd --reload
firewall-cmd --zone=public --list-ports

將 master node 的 kube-apiserver 的 6443 添加到 haproxy做負載均衡**

vi /etc/haproxy/haproxy.cfg
frontend k8s_apiserver *:6443
  mode tcp
  default_backend k8s

backend k8s
  mode tcp
  balance    roundrobin
  server     k8smaster01 172.16.8.21:6443 check
  server     k8smaster02 172.16.8.22:6443 check
  server     k8smaster03 172.16.8.23:6443 check
  
 # 由於後面的業務需要80和443 ,同時加上 30116 給dashbord使用
 
 frontend k8s_apiserver *:443
  mode tcp
  default_backend k8s443

backend k8s
  mode tcp
  balance    roundrobin
  server     k8smaster01 172.16.8.21:30443 check
  server     k8smaster02 172.16.8.22:30443 check
  server     k8smaster03 172.16.8.23:30443 check
  
  frontend k8s_apiserver *:80
  mode tcp
  default_backend k8s80

backend k8s
  mode tcp
  balance    roundrobin
  server     k8smaster01 172.16.8.21:30080 check
  server     k8smaster02 172.16.8.22:30080 check
  server     k8smaster03 172.16.8.23:30080 check
  
  frontend k8s_apiserver *:30116
  mode tcp
  default_backend k8s30116

backend k8s
  mode tcp
  balance    roundrobin
  server     k8smaster01 172.16.8.21:30116 check
  server     k8smaster02 172.16.8.22:30116 check
  server     k8smaster03 172.16.8.23:30116 check

reload 應用配置

systemctl reload haproxy

查看6443端口是否已經在監聽狀態**

運行 netstat -lntp查看

6、安裝 kubeadm, kubelet and kubectl

友情提示:切記版本一定要一致,否則一定會失敗。

 ##配置kubernetes.repo的源,由於官方源國內無法訪問,這裏使用阿里雲yum源
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

# Set SELinux in permissive mode (effectively disabling it)
setenforce 0

swapoff -a
sed -i '/ swap / s/^/#/' /etc/fstab

sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes

systemctl start kubelet
systemctl enable --now kubelet


cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system

kubectl -n kube-system get deployments

7、安裝 master node

1、首先生成 配置文件

cat <<EOF > kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: v1.16.0
controlPlaneEndpoint: "172.16.8.29:6443"
imageRepository: "registry.aliyuncs.com/google_containers"
networking:
  podSubnet: "10.244.0.0/16"  ## 後面的網絡準備使用 flannel,所以必須設置爲此網段
apiServer:
  certSANs:
  -"k8s.50yc.cn"
EOF

#由於gcr.io 鏡像不能訪問,使用阿里雲的鏡像,但是使用阿里的也有問題,建議使用azure的鏡像。注意 k8s.50yc.cn 爲我測試使用的域名, 自己可以設置自己的域名。

2. 初始化集羣

##重置羣集,如有問題可以重置羣集
#kubeadm reset
#systemctl daemon-reload && systemctl restart kubelet
sudo kubeadm init --config=kubeadm-config.yaml --upload-certs
  • 初始化成功,記錄下最後提示的 kubeadm join xxx 命令, 第一個是往集羣添加master node,第二個是往集羣添加 worker node
To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of the control-plane node running the following command on each as root:

  kubeadm join 172.16.8.29:6443 --token 55yied.ytynuulcecqo35ly \
    --discovery-token-ca-cert-hash sha256:a5b44874fdf62ffb14b76dd995aa1ea4d7ead0e2776f629336ec14cc8e3e7fe7 \
    --control-plane --certificate-key 5653c297d882948b8af3b825cd6815a05be9975828072dab41d82d0a11415440

Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use 
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward.

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 172.16.8.29:6443 --token 55yied.ytynuulcecqo35ly \
    --discovery-token-ca-cert-hash sha256:a5b44874fdf62ffb14b76dd995aa1ea4d7ead0e2776f629336ec14cc8e3e7fe7 

3、爲 kubectl 配置kube-config

每臺master需要執行

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config  sudo chown $(id -u):$(id -g) $HOME/.kube/config

4. 安裝 CNI插件 flannel

 #參考此配置
 https://github.com/maxshen29/maxstudy/blob/master/k8s/kube-flannel.yaml
 
 kubectl apply -f kube-flannel.yaml
 
  • 默認是從quay.io拉取flannel鏡像,但是經常因爲網絡原因拉不了,這裏從阿里雲找了一個替換了一下
sed -i s#'quay.io/coreos/flannel:v0.11.0-amd64'#'regi:stry.cn-hangzhou.aliyuncs.com/mygcrio/flannel:v0.11.0-amd64'#g kube-flannel.yaml

5. 加入master節點

使用上面記錄的kubeadm jion … 命令將另外兩個master節點添加進集羣

kubeadm join 172.16.8.29:6443 --token 55yied.ytynuulcecqo35ly \
--discovery-token-ca-cert-hash sha256:a5b44874fdf62ffb14b76dd995aa1ea4d7ead0e2776f629336ec14cc8e3e7fe7 \
--control-plane --certificate-key 5653c297d882948b8af3b825cd6815a05be9975828072dab41d82d0a11415440

6、加入work節點

將3個work節點執行下面命令

kubeadm join 172.16.8.29:6443 --token 55yied.ytynuulcecqo35ly \
    --discovery-token-ca-cert-hash sha256:a5b44874fdf62ffb14b76dd995aa1ea4d7ead0e2776f629336ec14cc8e3e7fe7 

7、相關命令

kubectl get node #查看節點
kubectl get pods -A -o wide #查看所有pods
kubectl get svc -A #查看所有服務
kubectl get ing -A #查看所有ingress(後續部署)
kubectl get secret -A # 查看所有secret

8 、安裝ingress

由於從外部訪問到k8s提供的服務,有幾種方式,一種是nodeport,以端口方式提供出來。 但是應用越來越多,用這種方式就很麻煩,於是可以使用ingress,具體文檔可以參考:

https://kubernetes.io/docs/concepts/services-networking/ingress/

相當於部署了一個nginx-ingress-controller 利用nginx 提供轉發。

https://github.com/maxshen29/maxstudy/blob/master/k8s/ingress.yaml

 kubectl apply -f ingress.yaml
 正常情況安裝完成查看pods 應該都running
 

在這裏插入圖片描述
創建ingress 文件

在環境中我有相應的證書,因此創建了tls secret,注意證書 secret 命名空間要和服務空間相同
kubectl create secret tls tls-ingress-secret --cert=1.crt --key=1.key -n kube-system

創建 testingres文件內容如下

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  namespace: kube-system
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: 
spec:
  tls:
    - hosts:
        - k8s.50yc.cn
      secretName: tls-ingress-secret
  rules:
  - host: k8s.50yc.cn
    http:
      paths:
      - path: /testpath
        backend:
          serviceName: nginx-ingress-default-backend
          servicePort: 80

完成後

默認訪問沒有內容的服務會轉到404

9、 安裝helm

helm 是很有用的工具,後面由於安裝 harbor 用helm很好,於是把helm也部署上。helm版本安裝的是 v2.14.3

https://github.com/maxshen29/maxstudy/tree/master/helm

在目錄下載 helm 和 tiller 放在 /usr/local/bin

安裝服務端

使用 helm init 即可安裝

helm init --upgrade -i registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.5.1 --stable-repo-url https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
完成後執行 
k8s 1.6 以上版本加入了RBAC的機制,因此需要添加Role Binding:
kubectl create clusterrolebinding add-on-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:default
執行
helm version 
應該有如下

[root@K8SM01 storage]# helm version
Client: &version.Version{SemVer:"v2.14.3", GitCommit:"0e7f3b6637f7af8fcfddb3d2941fcc7cbebb0085", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.14.3", GitCommit:"0e7f3b6637f7af8fcfddb3d2941fcc7cbebb0085", GitTreeState:"clean"}

10、 安裝 Dashboard

https://github.com/maxshen29/maxstudy/blob/master/k8s/kubernetes-dashboard.yaml

安裝dashboard 必須安裝在master節點,並且1.16版本必須使用2.0版本的dashbord,請參考上面的鏈接的配置文件
kubectl label node k8sm01 dashboard=true

  再yaml找到  

tolerations:
        - key: node-role.kubernetes.io/master
          effect: NoSchedule
      nodeSelector:
        dashboard: "true"
        
#由於我使用nodeport 服務配置如下


kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kube-system
spec:
  type: NodePort
  ports:
    - port: 443
      nodePort: 30116
      targetPort: 8443
      
      
  #賦權 創建 token.yaml
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: admin
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: admin
  namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin
  namespace: kube-system
  labels:
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
    
    
    -----
   kubectl apply -f token.yaml

安裝完成後,正常情況訪問 https://172.16.8.29:30116/可以打開界面

使用token訪問,由於我沒有配置證書,只能用IP地址訪問,並且瀏覽器也用fox

token 來源於:

kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}')
#這是所有用戶的token,找到管理員的token即可登錄

11、安裝gluster

由於打算在環境中安裝harbor,harbor作爲hub需要持久化存儲,比較好的選擇是部署分佈式存儲,我選擇了gluster作爲分佈式存儲

在poc-gfs01,poc-gfs02,poc-gfs03加載了一塊100g的裸磁盤sdb

 # poc-gfs01,poc-gfs02,poc-gfs03,poc-gfsclient 上面編輯
 vim  /etc/hosts

172.16.8.41 poc-gfs01
172.16.8.42 poc-gfs02
172.16.8.43 poc-gfs03

 sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config   #關閉SELinux
 setenforce 0
 ntpdate time.windows.com  #同步時間
 
 firewall-cmd --add-service=glusterfs --permanent # poc-gfs01,poc-gfs02,poc-gfs03 執行
 firewall-cmd --reload
 
 
 
 firewall-cmd --zone=public  --add-port=6443/tcp --permanent #poc-gfsclient執行
 firewall-cmd --reload
 
 yum install centos-release-gluster -y #如果沒有安裝 此,則版本會是 3.12版本。 
yum -y install glusterfs-server glusterfs-fuse
gluster peer probe poc-gfs02
gluster peer probe poc-gfs03

[root@poc-gfs01 ~]# gluster peer status
Number of Peers: 2

Hostname: poc-gfs03
Uuid: 68b8519e-d6a1-464f-9781-004e40d7eaaf
State: Peer in Cluster (Connected)
Other names:
172.16.8.43

Hostname: poc-gfs02
Uuid: 6b84e435-396e-4bcb-954a-da10c2814f8f
State: Peer in Cluster (Connected)
Other names:
172.16.8.42

12、安裝Heketi

完成gluster安裝,再進行heketi安裝

#,poc-gfsclient 安裝

yum install heketi heketi-client -y

[root@poc-gfsclient ~]# heketi --version
Heketi 8.0.0

#修改配置
vi /etc/heketi/heketi.json 
# 這裏只展示需要修改的配置,其他默認配置參考原始文件(這裏採用默認值)
{
    # 服務端口,可以根據需要進行修改,防止端口使用衝突
    "port": "8080",
    
    # 啓用認證
    "use_auth": true,
    
    # 配置admin用的key
    "admin": {
         "key": "admin_secret"
    },
    
    # executor有三種,mock,ssh,Kubernets,這裏使用ssh
    "executor": "ssh",
    # ssh相關配置
    "sshexec": {
      "keyfile": "/etc/heketi/heketi_key",
      "user": "root",
      "port": "22",
      "fstab": "/etc/fstab"
    },

    # heketi數據庫文件位置(這裏是默認路徑)
    "db": "/var/lib/heketi/heketi.db",
    # 日誌級別(none, critical, error, warning, info, debug)
    "loglevel" : "warning"
}
 
 
 
# 選擇ssh執行器,heketi服務器需要免密登陸GlusterFS集羣的各節點;
# -t:祕鑰類型;
# -q:安靜模式;
# -f:指定生成祕鑰的目錄與名字,注意與heketi.json的ssh執行器中"keyfile"值一致;
# -N:祕鑰密碼,””即爲空
[root@heketi ~]# ssh-keygen -t rsa -q -f /etc/heketi/heketi_key -N ""

# heketi服務由heketi用戶啓動,heketi用戶需要有新生成key的讀賦權,否則服務無法啓動
[root@heketi ~]# chown heketi:heketi /etc/heketi/heketi_key

# 分發公鑰;
# -i:指定公鑰
[root@heketi ~]# ssh-copy-id -i /etc/heketi/heketi_key.pub root@poc-gfs01
[root@heketi ~]# ssh-copy-id -i /etc/heketi/heketi_key.pub root@poc-gfs02
[root@heketi ~]# ssh-copy-id -i /etc/heketi/heketi_key.pub root@poc-gfs03

root@poc-gfsclient heketi]# systemctl enable heketi
root@poc-gfsclient heketi]# systemctl start heketi
root@poc-gfsclient heketi]# systemctl status heketi
● heketi.service - Heketi Server
   Loaded: loaded (/usr/lib/systemd/system/heketi.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2019-10-29 09:19:28 EDT; 18s ago
 Main PID: 9640 (heketi)
   CGroup: /system.slice/heketi.service
           └─9640 /usr/bin/heketi --config=/etc/heketi/heketi.json

Oct 29 09:19:38 poc-gfsclient heketi[9640]: ├─19334 /usr/sbin/glusterfsd -s 172.16.8.43 --volfile-id vol_0c6b20101809623f55e6652895f442fd.172.16.8.43.var….8.43-var-li
Oct 29 09:19:38 poc-gfsclient heketi[9640]: ├─19396 /usr/sbin/glusterfsd -s 172.16.8.43 --volfile-id vol_f776a9f4544c3d4ee550000d439fe792.172.16.8.43.var….8.43-var-li
Oct 29 09:19:38 poc-gfsclient heketi[9640]: ├─19413 /usr/sbin/glusterfsd -s 172.16.8.43 --volfile-id vol_e592b107953baca0a5e46394494714d2.172.16.8.43.var….8.43-var-li
Oct 29 09:19:38 poc-gfsclient heketi[9640]: ├─19572 /usr/sbin/glusterfsd -s 172.16.8.43 --volfile-id vol_eb9607e384f759efab47fb181ba78cd9.172.16.8.43.var….8.43-var-li
Oct 29 09:19:38 poc-gfsclient heketi[9640]: ├─19685 /usr/sbin/glusterfsd -s 172.16.8.43 --volfile-id vol_5b9305dc77808cc951b93d48034e0565.172.16.8.43.var….8.43-var-li
Oct 29 09:19:38 poc-gfsclient heketi[9640]: └─19706 /usr/sbin/glusterfs -s localhost --volfile-id gluster/glustershd -p /var/run/gluster/glustershd/glustershd.pid …-6
Oct 29 09:19:38 poc-gfsclient heketi[9640]: Oct 25 11:17:59 poc-gfs03 systemd[1]: Starting GlusterFS, a clustered file-system server...
Oct 29 09:19:38 poc-gfsclient heketi[9640]: Oct 25 11:17:59 poc-gfs03 systemd[1]: Started GlusterFS, a clustered file-system server.
Oct 29 09:19:38 poc-gfsclient heketi[9640]: [heketi] INFO 2019/10/29 09:19:38 Periodic health check status: node c967daf92994dd712fa8d15cd0361691 up=true
Oct 29 09:19:38 poc-gfsclient heketi[9640]: [heketi] INFO 2019/10/29 09:19:38 Cleaned 0 nodes from health cache


配置 top文件 
vim /etc/heketi/topology.json

{
    "clusters": [
        {
            "nodes": [
                {
                    "node": {
                        "hostnames": {
                            "manage": [
                                "172.16.8.41"
                            ],
                            "storage": [
                                "172.16.8.41"
                            ]
                        },
                        "zone": 1
                    },
                    "devices": [
                        "/dev/sdb"
                    ]
                },
                {
                    "node": {
                        "hostnames": {
                            "manage": [
                                "172.16.8.42"
                            ],
                            "storage": [
                                "172.16.8.42"
                            ]
                        },
                        "zone": 1
                    },
                    "devices": [
                        "/dev/sdb"
                    ]
                },
                {
                    "node": {
                        "hostnames": {
                            "manage": [
                                "172.16.8.43"
                            ],
                            "storage": [
                                "172.16.8.43"
                            ]
                        },
                        "zone": 1
                    },
                    "devices": [
                        "/dev/sdb"
                    ]
                }              
            ]
        }
    ]
}


 heketi-cli --server http://172.16.8.44:8080 --user admin --secret admin_secret topology load --json=/etc/heketi/topology.json
正常會輸出添加成功的報告
下面命令可以查看當前的top信息
heketi-cli --user admin --secret admin_secret topology info

# 查看heketi topology信息,此時volume與brick等未創建;
# 通過”heketi-cli cluster info“可以查看集羣相關信息;
# 通過”heketi-cli node info“可以查看節點相關信息;
# 通過”heketi-cli device info“可以查看device相關信息
	 

13、在K8S中使用存儲

需要聲明一個StorageClass

#創建一個secret。因爲是級域base64code的,需要把 密鑰 轉換。
[root@K8SM01 storage]# vim  heketi-secret.yaml 
apiVersion: v1
kind: Secret
type: kubernetes.io/glusterfs
metadata:
  name: heketi-secret
  namespace: kube-system
data:
  # base64 encoded. key=admin_secret
  key: YWRtaW5fc2VjcmV0
[root@K8SM01 storage]# kubectl apply -f  heketi-secret.yaml  

#創建 storege classe
[root@K8SM01 storage]# vim storageclass-glusterfs.yaml 
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: glusterfsclass
provisioner: kubernetes.io/glusterfs
parameters:
  resturl: "http://172.16.8.44:8080"
  clusterid: "8f5ae0affa498605e44b2f29bd51e079"
  restauthenabled: "true"
  restuser: "admin"
  secretNamespace: "kube-system"
  secretName: "heketi-secret"
  gidMin: "40000"
  gidMax: "50000"
  volumetype: "replicate:3"
  
[root@K8SM01 storage]# kubectl apply -f  storageclass-glusterfs.yaml

#創建5個10g的PV 安裝harbor可以使用。
[root@K8SM01 storage]# vim  harbor-pvc.yaml 
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: harbor-pvc01
  namespace: harbor-system
spec:
  storageClassName: glusterfsclass
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: harbor-pvc02
  namespace: harbor-system
spec:
  storageClassName: glusterfsclass
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: harbor-pvc03
  namespace: harbor-system
spec:
  storageClassName: glusterfsclass
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: harbor-pvc04
  namespace: harbor-system
spec:
  storageClassName: glusterfsclass
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: harbor-pvc05
  namespace: harbor-system
spec:
  storageClassName: glusterfsclass
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 10Gi

[root@K8SM01 storage]# kubectl apply -f harbor-pvc.yaml
#成功後

[root@K8SM01 storage]# kubectl get storageclass
NAME             PROVISIONER               AGE
glusterfsclass   kubernetes.io/glusterfs   3d11h
[root@K8SM01 storage]# kubectl get pv -A
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                         STORAGECLASS     REASON   AGE
pvc-423d1e5f-8457-4dbc-b9bd-6c2d51c45248   10Gi       RWX            Delete           Bound    harbor-system/harbor-pvc02    glusterfsclass            3d10h
pvc-4b1049b9-d392-46ed-ba60-b5e831f5a121   10Gi       RWX            Delete           Bound    default/glusterfs-vol-pvc01   glusterfsclass            3d11h
pvc-9c432ad7-b02d-4988-bb23-31186e91737a   10Gi       RWX            Delete           Bound    harbor-system/harbor-pvc01    glusterfsclass            3d10h
pvc-af37a4ab-69e3-4ffe-994f-e53870c864c9   10Gi       RWX            Delete           Bound    harbor-system/harbor-pvc03    glusterfsclass            3d10h
pvc-d33ee1e5-6e1b-42e3-bcf2-c5d0a29c978d   10Gi       RWX            Delete           Bound    harbor-system/harbor-pvc05    glusterfsclass            3d10h
pvc-ea777653-e92c-4c5b-b085-a7a97a155766   10Gi       RWX            Delete           Bound    harbor-system/harbor-pvc04    glusterfsclass            3d10h
[root@K8SM01 storage]# kubectl get pvc -A
NAMESPACE       NAME                  STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS     AGE
default         glusterfs-vol-pvc01   Bound    pvc-4b1049b9-d392-46ed-ba60-b5e831f5a121   10Gi       RWX            glusterfsclass   3d11h
harbor-system   harbor-pvc01          Bound    pvc-9c432ad7-b02d-4988-bb23-31186e91737a   10Gi       RWX            glusterfsclass   3d10h
harbor-system   harbor-pvc02          Bound    pvc-423d1e5f-8457-4dbc-b9bd-6c2d51c45248   10Gi       RWX            glusterfsclass   3d10h
harbor-system   harbor-pvc03          Bound    pvc-af37a4ab-69e3-4ffe-994f-e53870c864c9   10Gi       RWX            glusterfsclass   3d10h
harbor-system   harbor-pvc04          Bound    pvc-ea777653-e92c-4c5b-b085-a7a97a155766   10Gi       RWX            glusterfsclass   3d10h
harbor-system   harbor-pvc05          Bound    pvc-d33ee1e5-6e1b-42e3-bcf2-c5d0a29c978d   10Gi       RWX            glusterfsclass   3d10h

可以看到相應的存儲。
在gluster和heketi 同樣可以看到
可以使用 df -l 查看

14、 安裝harbor

有了pv資源,安裝harbor就輕鬆多了, 下載 harbor-helm 安裝包

git clone https://github.com/goharbor/harbor-helm.git
創建獨立的命名空間
kubectl create namespace harbor-system
修改
harbor-helm-1.2.0 目錄下 values.yaml
修改內容如下,目的是修改訪問鏈接,替換生成的pv
tls:
  enabled: true
  secretName: "tls-ingress-secret"
  commonName: "tls-ingress-secret"
  
ingress:
  hosts:
    core: reg.50yc.cn
    notary: reg.50yc.cn
  
  externalURL: https://reg.50yc.cn

persistence:
  enabled: true
  # Setting it to "keep" to avoid removing PVCs during a helm delete
  # operation. Leaving it empty will delete PVCs after the chart deleted
  #resourcePolicy: "keep"
  resourcePolicy: ""
  persistentVolumeClaim:
    registry:
      # Use the existing PVC which must be created manually before bound,
      # and specify the "subPath" if the PVC is shared with other components
      existingClaim: "harbor-pvc01"
      # Specify the "storageClass" used to provision the volume. Or the default
      # StorageClass will be used(the default).
      # Set it to "-" to disable dynamic provisioning
      storageClass: "glusterfsclass"
      subPath: ""
      accessMode: ReadWriteOnce
      size: 10Gi
    chartmuseum:
      existingClaim: "harbor-pvc02"  #之前生成的pv
      storageClass: "glusterfsclass"
      subPath: ""
      accessMode: ReadWriteOnce
      size: 10Gi
    jobservice:
      existingClaim: "harbor-pvc03"
      storageClass: "glusterfsclass"
      subPath: ""
      accessMode: ReadWriteOnce
      size: 10Gi
    # If external database is used, the following settings for database will
    # be ignored
    database:
      existingClaim: "harbor-pvc04"
      storageClass: "glusterfsclass"
      subPath: ""
      accessMode: ReadWriteOnce
      size: 10Gi
    # If external Redis is used, the following settings for Redis will
    # be ignored
    redis:
      existingClaim: "harbor-pvc05"
      storageClass: "glusterfsclass"
      subPath: ""
      accessMode: ReadWriteOnce
      size: 10Gi
------
helm add 


kubectl create secret tls tls-ingress-secret --cert=1.crt --key=1.key -n  harbor-system
helm repo add stable http://mirror.azure.cn/kubernetes/charts
helm install --name harbor -f values.yaml . --namespace harbor-system

完成後可以查看pod是否運行

成功輸入網址應該可以看到登錄界面

harbor 的功能有很多,還需要更多的研究。這裏就不深入了

15、錯誤排查

整個的安裝過程遇到很多的問題,主要有幾種

1、拿不到鏡像,解決辦法推薦使用azure的 鏡像代理,參考:https://github.com/Azure/container-service-for-azure-china/blob/master/aks/README.md#limitations-of-current-aks-private-preview-on-azure-china

2、版本不一致會導致很多問題,多參考官網文檔。網上很多人寫的未必靠譜

3、排錯

journalctl -f  # 當前輸出日誌
journalctl -f -u kubelet  # 只看當前的kubelet進程日誌 查看kubenetes的log
kubectl log
kubect describe 

4、在重啓k8s節常常遇到no route等的報錯。 這問題很有可能是防火牆(iptables)規則錯亂或者緩存導致的,和可能是flannel的bug,可以依次執行以下命令進行解決:

systemctl stop kubelet
systemctl stop docker
iptables --flush
iptables -tnat --flush
systemctl start kubelet
systemctl start docker
發佈了139 篇原創文章 · 獲贊 60 · 訪問量 37萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章