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中的容器,如果你想了解更多,點我跳轉。

物理機如何容器化部署k8s_Pod

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的操作。

  1. 當有請求到來時,API Server會先交由etcd進行存儲,存儲完成後API Server將進行下一步操作
  2. API Server通知Scheduler進行資源調度,調度完成後將調度結果返回給API Server
  3. API Server通知Controller Manager根據Scheduler指定的調度結果對特定Node節點的Kubelet發出指令
  4. Kubelet收到指令後,會將指令交由Container Runtime進行執行

Container Runtime是指容器運行環境,是負責運行容器的軟件。

如kubernetes支持的容器運行環境非常多:Docker、Containerd、cri-o等任何實現k8s容器運行環境接口的軟件均可被k8s作為Container Runtime。

搭建前戲

搭建方式

集羣搭建的方式多種多樣,如kubeadm搭建、二進制搭建等。

這裏將使用kubeadm進行搭建,kubeadm是官方社區推出的一個用於快速部署kubernetes集羣的功能,2條命令就能完成集羣搭建。

  1. 搭建Master節點,使用命令kubeadm init
  2. 加入節點至當前集羣,使用命令 $ 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/