kubernetes簡介
部署演變
在部署應用程序的方式上,主要經歷了三個時代:
- 傳統部署:互聯網早期,會直接將應用程序部署在物理機上
優點:簡單,不需要其它技術的參與
缺點:不能為應用程序定義資源使用邊界,很難合理地分配計算資源,而且程序之間容易產生影響
- 虛擬化部署:可以在一台物理機上運行多個虛擬機,每個虛擬機都是獨立的一個環境
優點:程序環境不會相互產生影響,提供了一定程度的安全性
缺點:增加了操作系統,浪費了部分資源
- 容器化部署:與虛擬化類似,但是共享了操作系統
優點:
可以保證每個容器擁有自己的文件系統、CPU、內存、進程空間等
運行應用程序所需要的資源都被容器包裝,並和底層基礎架構解耦
容器化的應用程序可以跨雲服務商、跨Linux操作系統發行版進行部署
容器管理
為了降低虛擬機造成的物理主機資源浪費,提高物理主機的資源利用率,並能夠提供像虛擬機一樣良好的應用程序隔離運行環境,人們把這種輕量級的虛擬機,稱為“容器”。
容器管理工具類似於虛擬機管理工具,主要用於容器的創建、啓動、關閉、刪除等。
容器管理工具有:
- Docker公司的Docker
- Alibaba的Pouch
- LXC、LXD、RKT等等。
容器化部署方式給帶來很多的便利,但是也會出現一些問題,比如説:
- 一個容器故障停機了,怎麼樣讓另外一個容器立刻啓動去替補停機的容器
- 當併發訪問量變大的時候,怎麼樣做到橫向擴展容器數量
這些容器管理的問題統稱為容器編排問題,為了解決這些容器編排問題,就產生了一些容器編排的軟件:
- Swarm:Docker自己的容器編排工具
- Mesos:Apache的一個資源統一管控的工具,需要和Marathon結合使用
- Kubernetes:Google開源的的容器編排工具
kubernetes
kubernetes,是一個全新的基於容器技術的分佈式架構領先方案,是谷歌嚴格保密十幾年的秘密武器----Borg系統的一個開源版本,於2014年9月發佈第一個版本,2015年7月發佈第一個正式版本,簡稱k8s。
説起kubernetes,其實也有一段故事。
在Docker公司沒有推出Docker容器時,Google公司就已經開始使用容器相關技術,並且也擁有一款屬於自己的容器編排工具,隨着Docker越來越火熱,Docker公司推出了Docker Swarm這款容器編排工具,配合Apache Mesos能達到很好的效果(Mesos主要作用是在分佈式計算過程中,對計算機資源進行管理和分配)。
由於Docker Swarm+Apache Mesos搶佔了大部分市場,Google公司坐不住了,忽然發現自己內部使用的容器編排工具其實更加優秀和強大,於是利用Go語言對其進行重構,並在2014年進行發佈,一經問世Docker Swarm+Apache Mesos的組合就潰不成軍,目前整個容器編排工具市場kubernetes佔有率穩居第一,高達80%。
需要注意的是,kubernetes能夠支持多種容器的編排部署,但默認是Docker容器。
功能介紹
kubernetes的本質是一組服務器集羣,它可以在集羣的每個節點上運行特定的程序,來對節點中的容器進行管理。目的是實現資源管理的自動化,主要提供瞭如下的主要功能:
- 自我修復:一旦某一個容器崩潰,能夠在1秒中左右迅速啓動新的容器
- 彈性伸縮:可以根據需要,自動對集羣中正在運行的容器數量進行調整
- 服務發現:服務可以通過自動發現的形式找到它所依賴的服務
- 負載均衡:如果一個服務起動了多個容器,能夠自動實現請求的負載均衡
- 版本回退:如果發現新發布的程序版本有問題,可以立即回退到原來的版本
- 存儲編排:可以根據容器自身的需求自動創建存儲卷
kubernetes架構
架構圖示
一個kubernetes集羣主要是由控制節點(master)、工作節點(node)構成,每個節點上都會安裝不同的組件:
Node(節點)數支持:
- 早期版本管理100台現版本
- 可以管理2000台
pod管理支持:
- 早期版本管理1000個
- 現版本管理150000個
Master
Master是集羣的控制平面,負責集羣的決策 ( 管理 )。
由以下組件構成:
- Api Server:資源操作的唯一入口,接收用户輸入的命令,提供認證、授權、API註冊和發現等機制,它是一個RestFul接口,用於接收外部資源請求,是整個集羣的統一入口,請求信息交由etcd進行存儲
- Scheduler:資源調度器,負責集羣資源調度,按照預定的調度策略將Pod調度到相應的node節點上
- ControllerManager:控制管理器,負責維護集羣的狀態,比如程序部署安排、故障檢測、自動擴展、滾動更新等,每個Node節點都會對應一個控制器對其進行管理
- etcd:負責存儲集羣中各種資源對象的信息,用於保存集羣相關數據
Node
Node是集羣的數據平面,負責為容器提供運行環境 ( 幹活 )。
由以下組件構成:
- Kubelet:由Master指派到Node節點中用於管理本機容器的代表,類似於agent, 負責維護容器的生命週期,即通過控制docker,來創建、更新、銷燬容器
- Kube Proxy:對該Node節點提供網絡代理,負載均衡等操作
- Docker:負責節點上容器的各種操作
核心概念
Pod:它是整個kubernetes集羣中最小的部署/執行單元,可以由1個或者n個容器組成,是一個容器集合,一個Pod中的容器網絡是共享的,且一個Pod的生命週期是短暫的,你可以將它當做k8s中的容器,如果你想了解更多,點我跳轉。
Volume:數據卷,用於提供Pod的數據存儲,聲明在Pod容器中可訪問的文件目錄,可以被掛載到Pod中一個或者多個容器的指定路徑下,支持多種後端存儲方式,如本地存儲,分佈式存儲,雲存儲等。
Controller:指示Pod幹活的指揮者,可以確保Pod是預期的副本數量,提供無狀態應用部署(不用事先規劃),確保所有的Node都運行同一個Pod,能夠定製一次性任務或者定時任務,以及掌控Pod的銷燬。
Service:用於定義一組Pod的訪問規則,Pod的負載均衡,提供一個或多個Pod的穩定訪問地址,支持多種方式,如ClusterIP、NodePort、LoadBalancer。
Label:告訴Controller應該對那個Pod下達指令,Controller與Pod通過Label建立一對一的關係。
NameSpace:用於隔離不同之間Pod的資源
控制流程
如下圖所示:
首先要明確,一旦kubernetes環境啓動之後,master和node都會將自身的信息存儲到etcd數據庫中。
Kubelet作為Node節點的核心,接收並處理來自Master中Controller Manager的操作。
- 當有請求到來時,API Server會先交由etcd進行存儲,存儲完成後API Server將進行下一步操作
- API Server通知Scheduler進行資源調度,調度完成後將調度結果返回給API Server
- API Server通知Controller Manager根據Scheduler指定的調度結果對特定Node節點的Kubelet發出指令
- Kubelet收到指令後,會將指令交由Container Runtime進行執行
Container Runtime是指容器運行環境,是負責運行容器的軟件。
如kubernetes支持的容器運行環境非常多:Docker、Containerd、cri-o等任何實現k8s容器運行環境接口的軟件均可被k8s作為Container Runtime。
搭建前戲
搭建方式
集羣搭建的方式多種多樣,如kubeadm搭建、二進制搭建等。
這裏將使用kubeadm進行搭建,kubeadm是官方社區推出的一個用於快速部署kubernetes集羣的功能,2條命令就能完成集羣搭建。
- 搭建Master節點,使用命令kubeadm init
- 加入節點至當前集羣,使用命令 $ kubeadm join MasterIp:MasterPort
如果你對二進制搭建感興趣,可參考文章點我跳轉。
相比於kubeadm搭建方式,二進制搭建更顯繁瑣,由於Api Server是HTTPS方式接收請求,所以需要手動的為API Server生成CA證書與手動部署etcd集羣。
而kubeadm直接內部全部都做好了。
集羣類型
kubernetes集羣大體上分為兩類:一主多從和多主多從。
- 一主多從:一台Master節點和多台Node節點,搭建簡單,但是有單機故障風險,適合用於測試環境
- 多主多從:多台Master節點和多台Node節點,搭建麻煩,安全性高,適合用於生產環境
為了測試簡單,我們選擇1主2從的集羣類型。
搭建規劃
以下是主機規劃:
|
作用
|
IP地址
|
操作系統
|
配置
|
|
Master
|
192.168.109.101
|
Centos7.3 基礎設施服務器
|
2顆CPU 2G內存 20G硬盤
|
|
Node1
|
192.168.109.102
|
Centos7.3 基礎設施服務器
|
2顆CPU 2G內存 20G硬盤
|
|
Node2
|
192.168.109.103
|
Centos7.3 基礎設施服務器
|
2顆CPU 2G內存 20G硬盤
|
本次環境搭建需要安裝三台Centos服務器(一主二從),然後在每台服務器中分別安裝docker(18.06.3),kubeadm(1.17.4)、kubelet(1.17.4)、kubectl(1.17.4)程序。
系統準備
1)所有節點關閉防火牆
為了能夠使端口進行暴露,避免不必要的麻煩,還是直接粗暴的關閉防火牆較好,如果是生產環境,則需要酌情考慮
[root@master ~]# systemctl stop firewalld
[root@master ~]# systemctl disable firewalld
2)所有節點禁用selinux
selinux是linux系統下的一個安全服務,如果不關閉它,在安裝集羣中會產生各種各樣的奇葩問題
[root@master ~]# sed -i 's/enforcing/disabled/' /etc/selinux/config # 永久
[root@master ~]# setenforce 0 # 臨時
3)所有節點禁用swap分區
swap分區指的是虛擬內存分區,它的作用是在物理內存使用完之後,將磁盤空間虛擬成內存來使用
啓用swap設備會對系統的性能產生非常負面的影響,因此kubernetes要求每個節點都要禁用swap設備
但是如果因為某些原因確實不能關閉swap分區,就需要在集羣安裝過程中通過明確的參數進行配置説明
[root@master ~]# sed -ri 's/.*swap.*/#&/' /etc/fstab # 永久
[root@master ~]# swapoff -a # 臨時
4)更改所有節點的hostname
為了能夠使各節點管理更方便,我們需要修改每個節點的hostname
[root@master ~]# hostnamectl set-hostname <hostname>
# master, node1, node2
5)在Master節點添加hosts
利於管理,如果後期Node節點的IP地址發生變化,我們只需要修改/etc/hosts文件即可
[root@master ~]# cat >> /etc/hosts << EOF
192.168.109.101 master
192.168.109.102 node1
192.168.109.103 node2
EOF
6)所有節點修改Linux內核參數,添加網橋過濾和地址轉發
[root@master ~]# cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
# 重載配置
[root@master ~]# sysctl -p
# 加載網橋過濾模塊(可選)
[root@master ~]# modprobe br_netfilter
# 查看網橋過濾模塊是否加載成功(可選)
[root@master ~]# lsmod | grep br_netfilter
# 生效
[root@master ~]# sysctl --system
7)所有節點配置ipvs功能(可選)
在kubernetes中service有兩種代理模型,一種是基於iptables的,一種是基於ipvs的
兩者比較的話,ipvs的性能明顯要高一些,但是如果要使用它,需要手動載入ipvs模塊
# 1 安裝ipset和ipvsadm
[root@master ~]# yum install ipset ipvsadmin -y
# 2 添加需要加載的模塊寫入腳本文件
[root@master ~]# cat <<EOF > /etc/sysconfig/modules/ipvs.modules
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF
# 3 腳本文件添加執行權限
[root@master ~]# chmod +x /etc/sysconfig/modules/ipvs.modules
# 4 執行腳本文件
[root@master ~]# /bin/bash /etc/sysconfig/modules/ipvs.modules
# 5 查看對應的模塊是否加載成功
[root@master ~]# lsmod | grep -e ip_vs -e nf_conntrack_ipv4
8)所有節點的時間同步
kubernetes要求集羣中的節點時間必須精確一致,企業中建議配置內部的時間同步服務器,以下提供2種方案
# 方案1
# 下載ntpdate軟件
[root@master ~]# yum install ntpdate -y
# 啓動時間更新
[root@master ~]# ntpdate time.windows.com
# 方案2
# 啓動chronyd服務
[root@master ~]# systemctl start chronyd
# 設置chronyd服務開機自啓
[root@master ~]# systemctl enable chronyd
# chronyd服務啓動稍等幾秒鐘,就可以使用date命令驗證時間了
[root@master ~]# date
kubeadm搭建
所有節點
1)安裝Docker,這裏指定為18.06.3的版本:
[root@master ~]# cd ~
# 切源
[root@master ~]# wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
# 下載
[root@master ~]# yum -y install docker-ce-18.06.3.ce-3.el7
# 啓動服務
[root@master ~]# systemctl enable docker && systemctl start docker
# 檢查是否安裝成功
[root@master ~]# docker --version
2)配置Docker registery為國內源:
[root@master ~]# cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF
[root@master ~]# systemctl daemon-reload
[root@master ~]# systemctl restart docker
3)配置kubernetes鏡像倉庫為國內源:
[root@master ~]# cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
4)安裝kubeadm和kubelete以及kubectl,由於與Docker之間的兼容性問題,故我們統一指定版本號為1.17.4:
[root@master ~]# yum install -y kubelet-1.17.4-0 kubeadm-1.17.4-0 kubectl-1.17.4-0
[root@master ~]# systemctl enable kubelet
kubernetes Master
Master節點上執行以下操作,先初始化kubernetes集羣:
[root@master ~]# kubeadm init --apiserver-advertise-address=192.168.109.101 --image-repository registry.aliyuncs.com/google_containers --kubernetes-version v1.17.4 --service-cidr=10.96.0.0/12 --pod-network-cidr=10.244.0.0/16
# --apiserver-advertise-address: apiserver的地址,就是Master地址
# --image-repository: 倉庫地址,配置為阿里雲,國內
# --kubernetes-version: k8s版本
# --service-cidr: 和當前ip不衝突即可,指明 pod 網絡可以使用的 IP 地址段。
# --pod-network-cidr: 和當前ip不衝突即可,指定節點的名稱
在完成後,它會提示以下信息:
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
# 這個是Master節點執行的
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/
Then you can join any number of worker nodes by running the following on each as root:
# 這個是node節點上執行的
kubeadm join 192.168.109.101:6443 --token mp0064.6tld9ohg7265co6r \
--discovery-token-ca-cert-hash sha256:c018e1720ae37ee0eec5d4ac0c2e8d4f8622e006401f2077575b164f1d6b41b3
拿出第一條命令,在Master節點上執行:
[root@master ~]# mkdir -p $HOME/.kube
[root@master ~]# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@master ~]# chown $(id -u):$(id -g) $HOME/.kube/config
現在kubernetes集羣中已經存在一個Master節點信息了:
[root@master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master NotReady master 5m56s v1.17.4
kubernetes Node
在2個Node節點中,輸入上面提示命令中的第二條,該命令的作用是將Node節點也加入kubernetes集羣中:
[root@node1 ~]# kubeadm join 192.168.109.101:6443 --token mp0064.6tld9ohg7265co6r --discovery-token-ca-cert-hash sha256:c018e1720ae37ee0eec5d4ac0c2e8d4f8622e006401f2077575b164f1d6b41b3
輸入完成後,回到Master節點執行以下命令查看集羣節點信息,Node節點也被成功加入:
[root@master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master NotReady master 6m43s v1.17.4
node1 NotReady <none> 22s v1.17.4
node2 NotReady <none> 19s v1.17.4
網絡插件
觀察集羣節點信息,可以發現各個節點的STATUS是NotReady,這是因為我們還需要在Master上配置一款網絡插件才能讓狀態各個節點狀態變為Ready。
kubernetes支持多種網絡插件,比如flannel、calico、canal等等,任選一種使用即可,本次選擇flannel:
[root@master ~]# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
如果發生鏈接錯誤,這是因為flannel文件是一個國外地址,多嘗試幾次即可。
如果一直失敗,則可以在瀏覽器中打開該文件複製內容並進行粘貼:
如果你的VIM未進入paste模式,則可能導致粘貼結果縮進有誤
# 1.瀏覽器訪問
https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# 2.複製內容並進行粘貼
[root@master ~]# vim ~/kube-flannel.yml
# 3.輸入內容並保存退出
# 4.進行應用
[root@master ~]# kubectl apply -f ~/kube-flannel.yml
apply完成之後,再次查看集羣節點信息,各個節點的STAUTS都從NotReady變成了Ready:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 15m v1.17.4
node1 Ready <none> 8m53s v1.17.4
node2 Ready <none> 8m50s v1.17.4
此時我們需要執行以下命令,等待Pod的STATUS都變為Running時,即可部署應用:
[root@master ~]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-7ff77c879f-b2kmb 1/1 Running 0 3h46m
coredns-7ff77c879f-skcfh 1/1 Running 0 3h46m
etcd-master 1/1 Running 0 3h47m
kube-apiserver-master 1/1 Running 0 3h47m
kube-controller-manager-master 1/1 Running 0 3h47m
kube-flannel-ds-488xf 1/1 Running 0 21m
kube-flannel-ds-dfj55 1/1 Running 0 21m
kube-flannel-ds-s5hz6 1/1 Running 0 21m
kube-proxy-8vxgm 1/1 Running 0 3h46m
kube-proxy-b92nh 1/1 Running 0 3h39m
kube-proxy-xw256 1/1 Running 0 3h39m
kube-scheduler-master 1/1 Running 0 3h47m
集羣測試
接下來在kubernetes集羣中部署一個nginx程序,測試下集羣是否在正常工作。
# 部署nginx
[root@master ~]# kubectl create deployment nginx --image=nginx:1.14-alpine
# 暴露端口
[root@master ~]# kubectl expose deployment nginx --port=80 --type=NodePort
# 查看服務狀態
[root@master ~]# kubectl get pods,service
NAME READY STATUS RESTARTS AGE
pod/nginx-86c57db685-fdc2k 1/1 Running 0 18m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 82m
service/nginx NodePort 10.104.121.45 <none> 80:30073/TCP 17m
# 4 最後在電腦上訪問下部署的nginx服務
局域網內其他機器訪問以下任意地址,即可看到Nginx頁面:
http://192.168.109.101:30073/
http://192.168.109.102:30073/
http://192.168.109.103:30073/