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