kubernetes-部署
部署kubernetes master
部署容器網(wǎng)絡(luò)插件
部署worker節(jié)點(diǎn)
部署dashboard可視化插件
部署容器存儲(chǔ)插件
以下操作均是在centos7.6進(jìn)行
- 部署kubernetes master
# curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && curl -o /etc/yum.repos.d/docker-ce.repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 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
# 關(guān)閉selinux
# sed -i 's/enforcing/disabled/g' /etc/sysconfig/selinux
安裝基礎(chǔ)組件
# yum install -y kubelet kubeadm kubectl docker-ce vim iptables-services wget net-tools
# systemctl start docker && systemctl enable docker kubelet
導(dǎo)入基礎(chǔ)鏡像
# docker load -i k8s1.15.1.tar
注:以上操作需要在所有節(jié)點(diǎn)執(zhí)行,本次部署需要有互聯(lián)網(wǎng)支持
master節(jié)點(diǎn)進(jìn)行初始化
忽略swap報(bào)錯(cuò)
# vim /etc/sysconfig/kubelet
KUBELET_EXTRA_ARGS="--fail-swap-on=false"
安裝
# kubeadm init --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/12 --ignore-preflight-errors=Swap --kubernetes-version=v1.15.1
注:10.244.0.0/16為pod網(wǎng)絡(luò) server網(wǎng)絡(luò)默認(rèn)為10.96.0.0/12
kubectl 客戶端用戶配置文件配置
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
記錄安裝后輸出,供后面添加node節(jié)點(diǎn)使用
# kubeadm join 192.168.1.170:6443 --token gpy810.gaq18z5bnks9occf \
--discovery-token-ca-cert-hash sha256:747559b3a32db293cd063a77559c85d04469026145d99cf97fe4fac002717512
查看節(jié)點(diǎn)信息
# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master.k8s.com NotReady master 38m v1.15.1
以上的get輸出結(jié)果可以看到,master節(jié)點(diǎn)的狀態(tài)是NotReady,在調(diào)試k8s集群時(shí),最重要的手段就是用kubectl describe 命令查看節(jié)點(diǎn)(node)對(duì)象的詳細(xì)信息、狀態(tài)和事件(Event),執(zhí)行以下命令進(jìn)行排查
# kubectl describe node master
...
Conditions:
...
Ready False ... KubeletNotReady runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized
通過(guò)kubectl describe 命令輸出可以看到,NotReady的原因是還沒(méi)有部署網(wǎng)絡(luò)插件
另外,還可以通過(guò)kubectl檢查這個(gè)節(jié)點(diǎn)上各個(gè)系統(tǒng)pod的狀態(tài),其中,kube-system是k8s預(yù)留的系統(tǒng)pod的工作空間。
# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-78fcdf6894-j9syh 0/1 Pending 0 1h
coredns-78fcdf6894-jm8df 0/1 Pending 0 1h
etcd-master 1/1 Running 0 2s
kube-apiserver-master 1/1 Running 0 1s
kube-controller-manager-master 0/1 Pending 0 1s
kube-proxy-xb7u7 1/1 NodeLost 0 1h
kube-scheduler-master 1/1 Running 0 1s
可以看到,coredns、kube-controller-manager等依賴于網(wǎng)絡(luò)的pod都處于Pending狀態(tài),也就是調(diào)度失敗,這是符合預(yù)期效果的,因?yàn)檫@個(gè)master節(jié)點(diǎn)的網(wǎng)絡(luò)還沒(méi)部署。
- 部署容器網(wǎng)絡(luò)插件
# kubectl apply -f kube-flannel.yml
部署完成后,可以通過(guò)kubectl get 重新檢查一遍pod狀態(tài)。
# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-5c98db65d4-cp2zj 1/1 Running 0 11d
coredns-5c98db65d4-t6rqq 1/1 Running 0 11d
etcd-master.k8s.com 1/1 Running 0 11d
kube-apiserver-master.k8s.com 1/1 Running 0 11d
kube-controller-manager-master.k8s.com 1/1 Running 0 11d
kube-flannel-ds-amd64-gkck5 1/1 Running 1 11d
kube-proxy-gjswz 1/1 Running 1 11d
kube-proxy-s48w4 1/1 Running 0 11d
kube-scheduler-master.k8s.com 1/1 Running 0 11d
可以看到,所有的pod都啟動(dòng)成功了,而剛剛部署的flannel網(wǎng)絡(luò)插件則在kube-system新建了一個(gè)名叫kube-flannel-ds-amd64-gkck5的pod,一般來(lái)說(shuō),這些pod就是容器網(wǎng)絡(luò)插件在每個(gè)節(jié)點(diǎn)上的控制組件。
k8s支持容器網(wǎng)絡(luò)插件,使用的是一個(gè)叫CNI的通用接口,它也是當(dāng)前容器網(wǎng)絡(luò)的標(biāo)準(zhǔn),市面上所的所有容器網(wǎng)絡(luò)開(kāi)源項(xiàng)目都可以通過(guò)CNI接入k8s,比如剛部署的flannel還有calico、canal、romana等等,它們的部署方式也都是類似的“一鍵部署”。
至此k8s的master節(jié)點(diǎn)就部署完成了,如果只需要一個(gè)蛋節(jié)點(diǎn)的k8s,現(xiàn)在就可以使用了,不過(guò)在默認(rèn)情況下,k8s的master節(jié)點(diǎn)是不能運(yùn)行用戶pod的,所以還需要額外做一個(gè)小操作。
使用taint/toleration調(diào)整master執(zhí)行pod的策略。
它的原理非常簡(jiǎn)單,一旦某個(gè)節(jié)點(diǎn)被加上一個(gè)taint,也就是被打上了“污點(diǎn)”,那么所有pod就都不能在這個(gè)節(jié)點(diǎn)上運(yùn)行,因?yàn)閗8s是有潔癖的。
除非有個(gè)別的pod聲明自己能“容忍”這個(gè)“污點(diǎn)”,也就是聲明了toleration,它才可以在這個(gè)節(jié)點(diǎn)上運(yùn)行。
其中,為節(jié)點(diǎn)打上"污點(diǎn)"(taint)的命令如下:
# kubectl taint nodes master.k8s.com foo=bar:NoSchedule
這時(shí)master.k8s.com這臺(tái)master節(jié)點(diǎn)就會(huì)增加一個(gè)鍵值對(duì)格式的taint,其中值里面的NoSchedule,意味著這個(gè)taint只會(huì)在調(diào)度新pod的時(shí)候生效,而不會(huì)影響到已經(jīng)發(fā)布到master節(jié)點(diǎn)上的pod,即便他們沒(méi)有toleration。
聲明toleration,只需要在pod的yaml文件中spec部分,加入tolerations字段即可,如下:
apiVersion: v1
kind: Pod
...
spec:
tolerations:
- key: "foo"
operator: "Equal"
value: "bar"
effect: "NoSchedule"
這個(gè)toleration的含義是,這個(gè)pod能“容忍”所有鍵值對(duì)為foo=bar的taint(operator:"Equal",“等于”操作)。
回到已經(jīng)部署的集群個(gè)上,這時(shí),如果通過(guò)kubectl describe檢查一下master節(jié)點(diǎn)的taint字段,就會(huì)有些發(fā)現(xiàn)
kubectl describe node master
Name: master
Roles: master
Taints: node-role.kubernetes.io/master:NoSchedule
可以看到,master節(jié)點(diǎn)默認(rèn)被加上了node-role.kubernetes.io/master:NoSchedule這樣一個(gè)“污點(diǎn)”,其中"鍵"是node-role.kubernetes.io/master,而沒(méi)有提供“值”。
此時(shí),就需要像下面這樣用“Exists”操作符(operator:"Exists",“存在”即可)來(lái)說(shuō)明,該pod能夠容忍所有以foo為鍵的taint,才能讓這個(gè)pod運(yùn)行在該master節(jié)點(diǎn)上。
apiVersion: v1
kind: Pod
...
spec:
tolerations:
- key: "foo"
operator: "Exists"
effect: "NoSchedule"
當(dāng)然,如果就是像要一個(gè)單節(jié)點(diǎn)的k8s,刪除這個(gè)taint才是正確的選擇,操作如下:
kubectl taint nodes --all node-role.kubernetes.io/master-
在“node-role.kubernetes.io/master”這個(gè)鍵后面加上了一個(gè)短橫線"-",這個(gè)格式就意味著移除所有以“node-role.kubernetes.io/master”為鍵的taint
- 部署worker節(jié)點(diǎn)
node節(jié)點(diǎn)執(zhí)行剛才獲取的命令
# kubeadm join 192.168.1.170:6443 --token gpy810.gaq18z5bnks9occf \
--discovery-token-ca-cert-hash sha256:747559b3a32db293cd063a77559c85d04469026145d99cf97fe4fac002717512
查看節(jié)點(diǎn)信息
# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master.k8s.com Ready master 38m v1.15.1
node.k8s.com Ready <none> 34m v1.15.1
有了kubeadm這樣的原生管理工具,k8s的部署已經(jīng)被大大簡(jiǎn)化,更重要的是,像證書(shū)、授權(quán)、各個(gè)組件的配置等部署中最麻煩的操作,kubeadm都已經(jīng)幫忙完成了。
至此,整個(gè)k8s集群就部署完成了,可以使用命令行的方式進(jìn)行應(yīng)用的發(fā)布和管理了,但是用起來(lái)可能不是很爽,下面就介紹下k8s的dashboard的部署方式。
- 部署dashboard可視化插件
在k8s社區(qū)中,又一個(gè)很受歡迎的dashboard項(xiàng)目,它可以給用戶提供一個(gè)可視化的web界面來(lái)查看當(dāng)前集群的各種信息,毫不意外,它的部署也相當(dāng)簡(jiǎn)單。
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml
部署完成后我們可以查看dashboard的pod狀態(tài)。
# kubectl get pods -n kube-system
kubernetes-dashboard-6f9887bccc-qc47t 1/1 Running 1 11d
需要注意的是,由于dashboard是一個(gè)web server,很多人經(jīng)常會(huì)在自己的公有云上無(wú)意地暴露dashborad的端口,從而造成安全隱患,所以,1.7版本之后的dashboard部署完成后,默認(rèn)只能通過(guò)proxy的方式在本地訪問(wèn),具體操作,可以查看dashboard的官方文檔。
而如果想從集群外訪問(wèn)這個(gè)dashboard的話,就需要用到ingress。
- 部署容器存儲(chǔ)插件
很多時(shí)候我們需要用數(shù)據(jù)卷(volume)把外面宿主機(jī)上的目錄或者文件掛載進(jìn)容器的mount namespace中,從而達(dá)到容器和宿主機(jī)共享這些目錄或文件的目的,容器里的應(yīng)用就可以在這些數(shù)據(jù)卷中新建和寫(xiě)入文件了。
可是,如果在某一臺(tái)機(jī)器上啟動(dòng)一個(gè)容器,顯然無(wú)法看到其他機(jī)器上的容器在它們的數(shù)據(jù)卷里寫(xiě)入的文件,這就是容器最典型的特征之一:無(wú)狀態(tài)
而容器的持久化存儲(chǔ),就是用來(lái)保存容器存儲(chǔ)狀態(tài)的重要手段,存儲(chǔ)插件會(huì)在容器里掛載一個(gè)基于網(wǎng)絡(luò)或其他機(jī)制的遠(yuǎn)程數(shù)據(jù)卷,使得在容器里創(chuàng)建的文件,實(shí)際上保存在遠(yuǎn)程存儲(chǔ)服務(wù)器上,或者以分布式的方式保存在多個(gè)節(jié)點(diǎn)上,而與當(dāng)前宿主機(jī)沒(méi)有任何綁定關(guān)系,這樣無(wú)論在其他哪個(gè)宿主機(jī)上啟動(dòng)新的容器,都可以請(qǐng)求掛載指定的持久化存儲(chǔ)卷,從而訪問(wèn)到數(shù)據(jù)卷里的的數(shù)據(jù),這就是"持久化"的含義。
由于k8s本身的松耦合設(shè)計(jì),絕大多數(shù)存儲(chǔ)項(xiàng)目,如ceph、glusterfs、nfs等,都可以為k8s提供持久化存儲(chǔ)能力,在這次的部署實(shí)戰(zhàn)中,選擇了rook插件進(jìn)行存儲(chǔ)的部署實(shí)驗(yàn)。
rook是一個(gè)基于ceph的k8s存儲(chǔ)插件(它后期也在加入對(duì)更多存儲(chǔ)實(shí)現(xiàn)的支持),不同ceph的簡(jiǎn)單封裝,rook在自己的實(shí)現(xiàn)中加入了水平擴(kuò)展、遷移、災(zāi)難備份、監(jiān)控等大量的企業(yè)級(jí)功能,使得這個(gè)項(xiàng)目變成了一個(gè)完整的,生產(chǎn)級(jí)別可用的容器存儲(chǔ)插件。
得益于容器化技術(shù),以下三條命令就可以將rook部署起來(lái),如下:
# kubectl apply -f https://raw.githubusercontent.com/rook/rook/master/cluster/examples/kubernetes/ceph/common.yaml
# kubectl apply -f https://raw.githubusercontent.com/rook/rook/master/cluster/examples/kubernetes/ceph/operator.yaml
# kubectl apply -f https://raw.githubusercontent.com/rook/rook/master/cluster/examples/kubernetes/ceph/cluster.yaml
在部署完成后,就可以看到rook項(xiàng)目會(huì)將自己的pod放置在由它自己管理的namespace當(dāng)中,如下:
# kubectl get pod -n rook-ceph
NAME READY STATUS RESTARTS AGE
csi-cephfsplugin-provisioner-7c85779954-cz7g4 4/4 Running 0 5m11s
csi-cephfsplugin-provisioner-7c85779954-dmcq2 4/4 Running 0 5m11s
csi-cephfsplugin-th86r 3/3 Running 0 5m11s
csi-rbdplugin-provisioner-5474976bf6-6vx2n 5/5 Running 0 5m11s
csi-rbdplugin-provisioner-5474976bf6-lnr4t 5/5 Running 0 5m11s
csi-rbdplugin-sb6qj 3/3 Running 0 5m11s
rook-ceph-agent-rx7jf 1/1 Running 0 5m13s
rook-ceph-detect-version-fww7w 0/1 Terminating 0 11s
rook-ceph-operator-b947787bc-b2kvd 1/1 Running 0 7m10s
rook-discover-rc59k 1/1 Running 0 5m13s
這樣,一個(gè)基于rook持久化存儲(chǔ)集群就以容器的方式運(yùn)行起來(lái)了,而接下來(lái)在k8s上創(chuàng)建的所有pod就能夠通過(guò)persistent volume(PV)和persistent volume claim(pvc)的方式,在容器里掛載由ceph提供的數(shù)據(jù)卷里。
而rook則會(huì)負(fù)責(zé)這些數(shù)據(jù)卷的生命周期管理、災(zāi)難備份等運(yùn)維工作。
選擇rook其實(shí)是因?yàn)檫@個(gè)項(xiàng)目很有前途,如果去研究下rook項(xiàng)目的實(shí)現(xiàn),就會(huì)發(fā)現(xiàn)它巧妙地依賴了k8s提供等編排能力,合理的使用了很多諸如operator、CRD等重要的擴(kuò)特性,這使得rook成為了目前社區(qū)中機(jī)遇k8s api構(gòu)建的最完善也最成熟的容器存儲(chǔ)插件,可以想象,應(yīng)該很快就會(huì)得到整個(gè)社區(qū)的推崇。