天天看點

4@Kubernetes(k8s)service和Ingress的使用資料存儲

文章目錄

  • ​​一、Service詳解​​
  • ​​Service介紹​​
  • ​​Service類型​​
  • ​​Service使用​​
  • ​​實驗環境準備​​
  • ​​ClusterIP類型的Service​​
  • ​​HeadLiness類型的Service​​
  • ​​NodePort類型的Service​​
  • ​​LoadBalancer類型的Service​​
  • ​​ExternalName類型的Service​​
  • ​​Ingress介紹​​
  • ​​Ingress使用​​
  • ​​環境準備​​
  • ​​Http代理​​
  • ​​Https代理​​
  • ​​二、資料存儲​​
  • ​​基本存儲​​
  • ​​EmptyDir​​
  • ​​HostPath​​
  • ​​NFS​​
  • ​​進階存儲​​
  • ​​PV和PVC​​
  • ​​PV​​
  • ​​PVC​​
  • ​​生命周期​​
  • ​​配置存儲​​
  • ​​ConfigMap​​
  • ​​Secret​​
  • ​​三、安全認證​​
  • ​​通路控制概述​​
  • ​​認證管理​​
  • ​​授權管理​​
  • ​​準入控制​​
  • ​​四、DashBoard​​
  • ​​部署Dashboard​​
  • ​​使用DashBoard​​

一、Service詳解

kubernetes的流量負載元件:Service和Ingress

Service介紹

在kubernetes中,pod是應用程式的載體,我們可以通過pod的ip來通路應用程式,但是pod的ip位址不是固定的,這也就意味着不友善直接采用pod的ip對服務進行通路。

    為了解決這個問題,kubernetes提供了Service資源,Service會對提供同一個服務的多個pod進行聚合,并且提供一個統一的入口位址。通過通路Service的入口位址就能通路到後面的pod服務。      
4@Kubernetes(k8s)service和Ingress的使用資料存儲
Service在很多情況下隻是一個概念,真正起作用的其實是kube-proxy服務程序,每個Node節點上都運作着一個kube-proxy服務程序。
當建立Service的時候會通過api-server向etcd寫入建立的service的資訊,而kube-proxy會基于監聽的機制發現這種Service的變動,然後**它會将最新的Service資訊轉換成對應的通路規則**。      
4@Kubernetes(k8s)service和Ingress的使用資料存儲
# 10.97.97.97:80 是service提供的通路入口
# 當通路這個入口的時候,可以發現後面有三個pod的服務在等待調用,
# kube-proxy會基于rr(輪詢)的政策,将請求分發到其中一個pod上去
# 這個規則會同時在叢集内的所有節點上都生成,是以在任何一個節點上通路都可以。
[root@node1 ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.97.97.97:80 rr
  -> 10.244.1.39:80               Masq    1      0          0
  -> 10.244.1.40:80               Masq    1      0          0
  -> 10.244.2.33:80               Masq    1      0          0      
kube-proxy目前支援三種工作模式:

userspace 模式

userspace模式下,kube-proxy會為每一個Service建立一個監聽端口,發向Cluster IP的請求被Iptables規則重定向到kube-proxy監聽的端口上,kube-proxy根據LB算法選擇一個提供服務的Pod并和其建立連結,以将請求轉發到Pod上

    該模式下,kube-proxy充當了一個四層負責均衡器的角色。由于kube-proxy運作在userspace中,在進行轉發處理時會增加核心和使用者空間之間的資料拷貝,雖然比較穩定,但是效率比較低。      
4@Kubernetes(k8s)service和Ingress的使用資料存儲

iptables 模式

iptables模式下,kube-proxy為service後端的每個Pod建立對應的iptables規則,直接将發向Cluster IP的請求重定向到一個Pod IP

    該模式下kube-proxy不承擔四層負責均衡器的角色,隻負責建立iptables規則。該模式的優點是較userspace模式效率更高,但不能提供靈活的LB政策,當後端Pod不可用時也無法進行重試      
4@Kubernetes(k8s)service和Ingress的使用資料存儲

ipvs 模式

ipvs模式和iptables類似,kube-proxy監控Pod的變化并建立相應的ipvs規則。ipvs相對iptables轉發效率更高。除此以外,ipvs支援更多的LB算法。      
4@Kubernetes(k8s)service和Ingress的使用資料存儲
# 此模式必須安裝ipvs核心子產品,否則會降級為iptables
# 開啟ipvs
[root@master ~]# kubectl edit cm kube-proxy -n kube-system
[root@master ~]# kubectl delete pod -l k8s-app=kube-proxy -n kube-system
[root@node1 ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.97.97.97:80 rr
  -> 10.244.1.39:80               Masq    1      0          0
  -> 10.244.1.40:80               Masq    1      0          0
  -> 10.244.2.33:80               Masq    1      0          0      

Service類型

Service的資源清單檔案:
kind: Service  # 資源類型
apiVersion: v1  # 資源版本
metadata: # 中繼資料
  name: service # 資源名稱
  namespace: dev # 命名空間
spec: # 描述
  selector: # 标簽選擇器,用于确定目前service代理哪些pod
    app: nginx
  type: # Service類型,指定service的通路方式
  clusterIP:  # 虛拟服務的ip位址
  sessionAffinity: # session親和性,支援ClientIP、None兩個選項
  ports: # 端口資訊
    - protocol: TCP 
      port: 3017  # service端口
      targetPort: 5003 # pod端口
      nodePort: 31122 # 主機端口      
  • ClusterIP:預設值,它是Kubernetes系統自動配置設定的虛拟IP,隻能在叢集内部通路
  • NodePort:将Service通過指定的Node上的端口暴露給外部,通過此方法,就可以在叢集外部通路服務
  • LoadBalancer:使用外接負載均衡器完成到服務的負載分發,注意此模式需要外部雲環境支援
  • ExternalName: 把叢集外部的服務引入叢集内部,直接使用

Service使用

實驗環境準備

在使用service之前,首先利用Deployment建立出3個pod,注意要為pod設定​

​app=nginx-pod​

​的标簽

建立deployment.yaml,内容如下:

apiVersion: apps/v1
kind: Deployment      
metadata:
  name: pc-deployment
  namespace: dev
spec: 
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80      
[root@master ~]# kubectl create -f deployment.yaml
deployment.apps/pc-deployment created

# 檢視pod詳情
[root@master ~]# kubectl get pods -n dev -o wide --show-labels
NAME                             READY   STATUS     IP            NODE     LABELS
pc-deployment-66cb59b984-8p84h   1/1     Running    10.244.1.40   node1    app=nginx-pod
pc-deployment-66cb59b984-vx8vx   1/1     Running    10.244.2.33   node2    app=nginx-pod
pc-deployment-66cb59b984-wnncx   1/1     Running    10.244.1.39   node1    app=nginx-pod

# 為了友善後面的測試,修改下三台nginx的index.html頁面(三台修改的IP位址不一緻)
# kubectl exec -it pc-deployment-66cb59b984-8p84h -n dev /bin/sh
# echo "10.244.1.40" > /usr/share/nginx/html/index.html

#修改完畢之後,通路測試
[root@master ~]# curl 10.244.1.40
10.244.1.40
[root@master ~]# curl 10.244.2.33
10.244.2.33
[root@master ~]# curl 10.244.1.39
10.244.1.39      

ClusterIP類型的Service

建立service-clusterip.yaml檔案
apiVersion: v1
kind: Service
metadata:
  name: service-clusterip
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: 10.97.97.97 # service的ip位址,如果不寫,預設會生成一個
  type: ClusterIP
  ports:
  - port: 80  # Service端口       
    targetPort: 80 # pod端口      
# 建立service
[root@master ~]# kubectl create -f service-clusterip.yaml
service/service-clusterip created

# 檢視service
[root@master ~]# kubectl get svc -n dev -o wide
NAME                TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE   SELECTOR
service-clusterip   ClusterIP   10.97.97.97   <none>        80/TCP    13s   app=nginx-pod

# 檢視service的詳細資訊
# 在這裡有一個Endpoints清單,裡面就是目前service可以負載到的服務入口
[root@master ~]# kubectl describe svc service-clusterip -n dev
Name:              service-clusterip
Namespace:         dev
Labels:            <none>
Annotations:       <none>
Selector:          app=nginx-pod
Type:              ClusterIP
IP:                10.97.97.97
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.39:80,10.244.1.40:80,10.244.2.33:80
Session Affinity:  None
Events:            <none>

# 檢視ipvs的映射規則
[root@master ~]# ipvsadm -Ln
TCP  10.97.97.97:80 rr
  -> 10.244.1.39:80               Masq    1      0          0
  -> 10.244.1.40:80               Masq    1      0          0
  -> 10.244.2.33:80               Masq    1      0          0

# 通路10.97.97.97:80觀察效果
[root@master ~]# curl 10.97.97.97:80
10.244.2.33      

Endpoint

Endpoint是kubernetes中的一個資源對象,存儲在etcd中,用來記錄一個service對應的所有pod的通路位址,它是根據service配置檔案中selector描述産生的。

    一個Service由一組Pod組成,這些Pod通過Endpoints暴露出來,**Endpoints是實作實際服務的端點集合**。換句話說,service和pod之間的聯系是通過endpoints實作的。      
4@Kubernetes(k8s)service和Ingress的使用資料存儲

負載分發政策

對Service的通路被分發到了後端的Pod上去,目前kubernetes提供了兩種負載分發政策:
- 如果不定義,預設使用kube-proxy的政策,比如随機、輪詢

- 基于用戶端位址的會話保持模式,即來自同一個用戶端發起的所有請求都會轉發到固定的一個Pod上

  此模式可以使在spec中添加`sessionAffinity:ClientIP`選項      
# 檢視ipvs的映射規則【rr 輪詢】
[root@master ~]# ipvsadm -Ln
TCP  10.97.97.97:80 rr
  -> 10.244.1.39:80               Masq    1      0          0
  -> 10.244.1.40:80               Masq    1      0          0
  -> 10.244.2.33:80               Masq    1      0          0

# 循環通路測試
[root@master ~]# while true;do curl 10.97.97.97:80; sleep 5; done;
10.244.1.40
10.244.1.39
10.244.2.33
10.244.1.40
10.244.1.39
10.244.2.33

# 修改分發政策----sessionAffinity:ClientIP

# 檢視ipvs規則【persistent 代表持久】
[root@master ~]# ipvsadm -Ln
TCP  10.97.97.97:80 rr persistent 10800
  -> 10.244.1.39:80               Masq    1      0          0
  -> 10.244.1.40:80               Masq    1      0          0
  -> 10.244.2.33:80               Masq    1      0          0

# 循環通路測試
[root@master ~]# while true;do curl 10.97.97.97; sleep 5; done;
10.244.2.33
10.244.2.33
10.244.2.33
  
# 删除service
[root@master ~]# kubectl delete -f service-clusterip.yaml
service "service-clusterip"      

HeadLiness類型的Service

在某些場景中,開發人員可能不想使用Service提供的負載均衡功能,而希望自己來控制負載均衡政策,針對這種情況,kubernetes提供了HeadLiness Service,這類Service不會配置設定Cluster IP,如果想要通路service,隻能通過service的域名進行查詢。

建立service-headliness.yaml

apiVersion: v1
kind: Service
metadata:
  name: service-headliness
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: None # 将clusterIP設定為None,即可建立headliness Service
  type: ClusterIP
  ports:
  - port: 80    
    targetPort: 80      
# 建立service
[root@master ~]# kubectl create -f service-headliness.yaml
service/service-headliness created

# 擷取service, 發現CLUSTER-IP未配置設定
[root@master ~]# kubectl get svc service-headliness -n dev -o wide
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
service-headliness   ClusterIP   None         <none>        80/TCP    11s   app=nginx-pod

# 檢視service詳情
[root@master ~]# kubectl describe svc service-headliness  -n dev
Name:              service-headliness
Namespace:         dev
Labels:            <none>
Annotations:       <none>
Selector:          app=nginx-pod
Type:              ClusterIP
IP:                None
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.39:80,10.244.1.40:80,10.244.2.33:80
Session Affinity:  None
Events:            <none>

# 檢視域名的解析情況
[root@master ~]# kubectl exec -it pc-deployment-66cb59b984-8p84h -n dev /bin/sh
/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search dev.svc.cluster.local svc.cluster.local cluster.local

[root@master ~]# dig @10.96.0.10 service-headliness.dev.svc.cluster.local
service-headliness.dev.svc.cluster.local. 30 IN A 10.244.1.40
service-headliness.dev.svc.cluster.local. 30 IN A 10.244.1.39
service-headliness.dev.svc.cluster.local. 30 IN A 10.244.2.33      

NodePort類型的Service

在之前的樣例中,建立的Service的ip位址隻有叢集内部才可以通路,如果希望将Service暴露給叢集外部使用,那麼就要使用到另外一種類型的Service,稱為NodePort類型。NodePort的工作原理其實就是将service的端口映射到Node的一個端口上,然後就可以通過​

​NodeIp:NodePort​

​來通路service了
4@Kubernetes(k8s)service和Ingress的使用資料存儲
建立service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: service-nodeport
  namespace: dev
spec:
  selector:
    app: nginx-pod
  type: NodePort # service類型
  ports:
  - port: 80
    nodePort: 30002 # 指定綁定的node的端口(預設的取值範圍是:30000-32767), 如果不指定,會預設配置設定
    targetPort: 80      
# 建立service
[root@master ~]# kubectl create -f service-nodeport.yaml
service/service-nodeport created

# 檢視service
[root@master ~]# kubectl get svc -n dev -o wide
NAME               TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)       SELECTOR
service-nodeport   NodePort   10.105.64.191   <none>        80:30002/TCP  app=nginx-pod

# 接下來可以通過電腦主機的浏覽器去通路叢集中任意一個nodeip的30002端口,即可通路到pod      

LoadBalancer類型的Service

LoadBalancer和NodePort很相似,目的都是向外部暴露一個端口,差別在于LoadBalancer會在叢集的外部再來做一個負載均衡裝置,而這個裝置需要外部環境支援的,外部服務發送到這個裝置上的請求,會被裝置負載之後轉發到叢集中。
4@Kubernetes(k8s)service和Ingress的使用資料存儲

ExternalName類型的Service

ExternalName類型的Service用于引入叢集外部的服務,它通過​

​externalName​

​屬性指定外部一個服務的位址,然後在叢集内部通路此service就可以通路到外部的服務了。
4@Kubernetes(k8s)service和Ingress的使用資料存儲
apiVersion: v1
kind: Service
metadata:
  name: service-externalname
  namespace: dev
spec:
  type: ExternalName # service類型
  externalName: www.baidu.com  #改成ip位址也可以      
# 建立service
[root@master ~]# kubectl  create -f service-externalname.yaml
service/service-externalname created

# 域名解析
[root@master ~]# dig @10.96.0.10 service-externalname.dev.svc.cluster.local
service-externalname.dev.svc.cluster.local. 30 IN CNAME www.baidu.com.
www.baidu.com.          30      IN      CNAME   www.a.shifen.com.
www.a.shifen.com.       30      IN      A       39.156.66.18
www.a.shifen.com.       30      IN      A       39.156.66.14      

Ingress介紹

在前面課程中已經提到,Service對叢集之外暴露服務的主要方式有兩種:NotePort和LoadBalancer,但是這兩種方式,都有一定的缺點:
  • NodePort方式的缺點是會占用很多叢集機器的端口,那麼當叢集服務變多的時候,這個缺點就愈發明顯
  • LB方式的缺點是每個service需要一個LB,浪費、麻煩,并且需要kubernetes之外裝置的支援
基于這種現狀,kubernetes提供了Ingress資源對象,Ingress隻需要一個NodePort或者一個LB就可以滿足暴露多個Service的需求。工作機制大緻如下圖表示:
4@Kubernetes(k8s)service和Ingress的使用資料存儲
實際上,Ingress相當于一個7層的負載均衡器,是kubernetes對反向代理的一個抽象,它的工作原理類似于Nginx,可以了解成在Ingress裡建立諸多映射規則,Ingress Controller通過監聽這些配置規則并轉化成Nginx的反向代理配置 , 然後對外部提供服務。在這裡有兩個核心概念:
  • ingress:kubernetes中的一個對象,作用是定義請求如何轉發到service的規則
  • ingress controller:具體實作反向代理及負載均衡的程式,對ingress定義的規則進行解析,根據配置的規則來實作請求轉發,實作方式有很多,比如Nginx, Contour, Haproxy等等
Ingress(以Nginx為例)的工作原理如下:
  1. 使用者編寫Ingress規則,說明哪個域名對應kubernetes叢集中的哪個Service
  2. Ingress控制器動态感覺Ingress服務規則的變化,然後生成一段對應的Nginx反向代理配置
  3. Ingress控制器會将生成的Nginx配置寫入到一個運作着的Nginx服務中,并動态更新
  4. 到此為止,其實真正在工作的就是一個Nginx了,内部配置了使用者定義的請求轉發規則
4@Kubernetes(k8s)service和Ingress的使用資料存儲

Ingress使用

環境準備

搭建ingress環境
# 建立檔案夾
[root@master ~]# mkdir ingress-controller
[root@master ~]# cd ingress-controller/

# 擷取ingress-nginx,本次案例使用的是0.30版本
[root@master ingress-controller]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
[root@master ingress-controller]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml

# 修改mandatory.yaml檔案中的倉庫
# 修改quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0
# 為quay-mirror.qiniu.com/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0
# 建立ingress-nginx
[root@master ingress-controller]# kubectl apply -f ./

# 檢視ingress-nginx
[root@master ingress-controller]# kubectl get pod -n ingress-nginx
NAME                                           READY   STATUS    RESTARTS   AGE
pod/nginx-ingress-controller-fbf967dd5-4qpbp   1/1     Running   0          12h

# 檢視service
[root@master ingress-controller]# kubectl get svc -n ingress-nginx
NAME            TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx   NodePort   10.98.75.163   <none>        80:32240/TCP,443:31335/TCP   11h      

準備service和pod

為了後面的實驗比較友善,建立如下圖所示的模型
4@Kubernetes(k8s)service和Ingress的使用資料存儲

建立tomcat-nginx.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: tomcat-pod
  template:
    metadata:
      labels:
        app: tomcat-pod
    spec:
      containers:
      - name: tomcat
        image: tomcat:8.5-jre10-slim
        ports:
        - containerPort: 8080

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: None
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 80

---

apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
  namespace: dev
spec:
  selector:
    app: tomcat-pod
  clusterIP: None
  type: ClusterIP
  ports:
  - port: 8080
    targetPort: 8080      
# 建立
[root@master ~]# kubectl create -f tomcat-nginx.yaml

# 檢視
[root@master ~]# kubectl get svc -n dev
NAME             TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
nginx-service    ClusterIP   None         <none>        80/TCP     48s
tomcat-service   ClusterIP   None         <none>        8080/TCP   48s      

Http代理

建立ingress-http.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-http
  namespace: dev
spec:
  rules:
  - host: nginx.itheima.com
    http:
      paths:
      - path: /
        backend:
          serviceName: nginx-service
          servicePort: 80
  - host: tomcat.itheima.com
    http:
      paths:
      - path: /
        backend:
          serviceName: tomcat-service
          servicePort: 8080      
# 建立
[root@master ~]# kubectl create -f ingress-http.yaml
ingress.extensions/ingress-http created

# 檢視
[root@master ~]# kubectl get ing ingress-http -n dev
NAME           HOSTS                                  ADDRESS   PORTS   AGE
ingress-http   nginx.itheima.com,tomcat.itheima.com             80      22s

# 檢視詳情
[root@master ~]# kubectl describe ing ingress-http  -n dev
...
Rules:
Host                Path  Backends
----                ----  --------
nginx.itheima.com   / nginx-service:80 (10.244.1.96:80,10.244.1.97:80,10.244.2.112:80)
tomcat.itheima.com  / tomcat-service:8080(10.244.1.94:8080,10.244.1.95:8080,10.244.2.111:8080)
...

# 接下來,在本地電腦上配置host檔案,解析上面的兩個域名到192.168.109.100(master)上
# 然後,就可以分别通路tomcat.itheima.com:32240  和  nginx.itheima.com:32240 檢視效果了      

Https代理

建立證書

# 生成證書
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=BJ/L=BJ/O=nginx/CN=itheima.com"

# 建立密鑰
kubectl create secret tls tls-secret --key tls.key --cert tls.crt      

建立ingress-https.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-https
  namespace: dev
spec:
  tls:
    - hosts:
      - nginx.itheima.com
      - tomcat.itheima.com
      secretName: tls-secret # 指定秘鑰
  rules:
  - host: nginx.itheima.com
    http:
      paths:
      - path: /
        backend:
          serviceName: nginx-service
          servicePort: 80
  - host: tomcat.itheima.com
    http:
      paths:
      - path: /
        backend:
          serviceName: tomcat-service
          servicePort: 8080      
# 建立
[root@master ~]# kubectl create -f ingress-https.yaml
ingress.extensions/ingress-https created

# 檢視
[root@master ~]# kubectl get ing ingress-https -n dev
NAME            HOSTS                                  ADDRESS         PORTS     AGE
ingress-https   nginx.itheima.com,tomcat.itheima.com   10.104.184.38   80, 443   2m42s

# 檢視詳情
[root@master ~]# kubectl describe ing ingress-https -n dev
...
TLS:
  tls-secret terminates nginx.itheima.com,tomcat.itheima.com
Rules:
Host              Path Backends
----              ---- --------
nginx.itheima.com  /  nginx-service:80 (10.244.1.97:80,10.244.1.98:80,10.244.2.119:80)
tomcat.itheima.com /  tomcat-service:8080(10.244.1.99:8080,10.244.2.117:8080,10.244.2.120:8080)
...

# 下面可以通過浏覽器通路https://nginx.itheima.com:31335 和 https://tomcat.itheima.com:31335來檢視了      

二、資料存儲

容器的生命周期可能很短,會被頻繁地建立和銷毀。那麼容器在銷毀時,儲存在容器中的資料也會被清除。這種結果對使用者來說,在某些情況下是不樂意看到的。為了持久化儲存容器的資料,kubernetes引入了Volume的概念。

Volume是Pod中能夠被多個容器通路的共享目錄,它被定義在Pod上,然後被一個Pod裡的多個容器挂載到具體的檔案目錄下,kubernetes通過Volume實作同一個Pod中不同容器之間的資料共享以及資料的持久化存儲。Volume的生命容器不與Pod中單個容器的生命周期相關,當容器終止或者重新開機時,Volume中的資料也不會丢失。

kubernetes的Volume支援多種類型,比較常見的有下面幾個:

  • 簡單存儲:EmptyDir、HostPath、NFS
  • 進階存儲:PV、PVC
  • 配置存儲:ConfigMap、Secret

基本存儲

EmptyDir

EmptyDir是最基礎的Volume類型,一個EmptyDir就是Host上的一個空目錄。

EmptyDir是在Pod被配置設定到Node時建立的,它的初始内容為空,并且無須指定主控端上對應的目錄檔案,因為kubernetes會自動配置設定一個目錄,當Pod銷毀時, EmptyDir中的資料也會被永久删除。 EmptyDir用途如下:

  • 臨時空間,例如用于某些應用程式運作時所需的臨時目錄,且無須永久保留
  • 一個容器需要從另一個容器中擷取資料的目錄(多容器共享目錄)

接下來,通過一個容器之間檔案共享的案例來使用一下EmptyDir。

在一個Pod中準備兩個容器nginx和busybox,然後聲明一個Volume分别挂在到兩個容器的目錄中,然後nginx容器負責向Volume中寫日志,busybox中通過指令将日志内容讀到控制台。

4@Kubernetes(k8s)service和Ingress的使用資料存儲

建立一個volume-emptydir.yaml

apiVersion: v1
kind: Pod
metadata:
  name: volume-emptydir
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.14-alpine
    ports:
    - containerPort: 80
    volumeMounts:  # 将logs-volume挂在到nginx容器中,對應的目錄為 /var/log/nginx
    - name: logs-volume
      mountPath: /var/log/nginx
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","tail -f /logs/access.log"] # 初始指令,動态讀取指定檔案中内容
    volumeMounts:  # 将logs-volume 挂在到busybox容器中,對應的目錄為 /logs
    - name: logs-volume
      mountPath: /logs
  volumes: # 聲明volume, name為logs-volume,類型為emptyDir
  - name: logs-volume
    emptyDir: {}      
# 建立Pod
[root@master ~]# kubectl create -f volume-emptydir.yaml
pod/volume-emptydir created

# 檢視pod
[root@master ~]# kubectl get pods volume-emptydir -n dev -o wide
NAME                  READY   STATUS    RESTARTS   AGE   IP             NODE   ...... 
volume-emptydir   2/2     Running   0          97s   10.244.1.100   node1  ......

# 通過podIp通路nginx
[root@master ~]# curl 10.244.1.100
......

# 通過kubectl logs指令檢視指定容器的标準輸出
[root@master ~]# kubectl logs -f volume-emptydir -n dev -c busybox
10.244.0.0 - - [13/Apr/2020:10:58:47 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"      

HostPath

EmptyDir中資料不會被持久化,它會随着Pod的結束而銷毀,如果想簡單的将資料持久化到主機中,可以選擇HostPath

HostPath就是将Node主機中一個實際目錄挂在到Pod中,以供容器使用,這樣的設計就可以保證Pod銷毀了,但是資料依據可以存在于Node主機上。

4@Kubernetes(k8s)service和Ingress的使用資料存儲

建立一個volume-hostpath.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: volume-hostpath
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - containerPort: 80
    volumeMounts:
    - name: logs-volume
      mountPath: /var/log/nginx
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","tail -f /logs/access.log"]
    volumeMounts:
    - name: logs-volume
      mountPath: /logs
  volumes:
  - name: logs-volume
    hostPath: 
      path: /root/logs
      type: DirectoryOrCreate  # 目錄存在就使用,不存在就先建立後使用      
關于type的值的一點說明:
    DirectoryOrCreate 目錄存在就使用,不存在就先建立後使用
    Directory   目錄必須存在
    FileOrCreate  檔案存在就使用,不存在就先建立後使用
    File 檔案必須存在  
    Socket  unix套接字必須存在
    CharDevice  字元裝置必須存在
    BlockDevice 塊裝置必須存在      
# 建立Pod
[root@master ~]# kubectl create -f volume-hostpath.yaml
pod/volume-hostpath created

# 檢視Pod
[root@master ~]# kubectl get pods volume-hostpath -n dev -o wide
NAME                  READY   STATUS    RESTARTS   AGE   IP             NODE   ......
pod-volume-hostpath   2/2     Running   0          16s   10.244.1.104   node1  ......

#通路nginx
[root@master ~]# curl 10.244.1.104

# 接下來就可以去host的/root/logs目錄下檢視存儲的檔案了
###  注意: 下面的操作需要到Pod所在的節點運作(案例中是node1)
[root@node1 ~]# ls /root/logs/
access.log  error.log

# 同樣的道理,如果在此目錄下建立一個檔案,到容器中也是可以看到的      

NFS

HostPath可以解決資料持久化的問題,但是一旦Node節點故障了,Pod如果轉移到了别的節點,又會出現問題了,此時需要準備單獨的網絡存儲系統,比較常用的用NFS、CIFS。

NFS是一個網絡檔案存儲系統,可以搭建一台NFS伺服器,然後将Pod中的存儲直接連接配接到NFS系統上,這樣的話,無論Pod在節點上怎麼轉移,隻要Node跟NFS的對接沒問題,資料就可以成功通路。

4@Kubernetes(k8s)service和Ingress的使用資料存儲
1)首先要準備nfs的伺服器,這裡為了簡單,直接是master節點做nfs伺服器
# 在master上安裝nfs服務
[root@master ~]# yum install nfs-utils -y

# 準備一個共享目錄
[root@master ~]# mkdir /root/data/nfs -pv

# 将共享目錄以讀寫權限暴露給192.168.109.0/24網段中的所有主機
[root@master ~]# vim /etc/exports
[root@master ~]# more /etc/exports
/root/data/nfs     192.168.109.0/24(rw,no_root_squash)

# 啟動nfs服務
[root@master ~]# systemctl start nfs      
2)接下來,要在的每個node節點上都安裝下nfs,這樣的目的是為了node節點可以驅動nfs裝置
# 在node上安裝nfs服務,注意不需要啟動
[root@master ~]# yum install nfs-utils -y      
3)接下來,就可以編寫pod的配置檔案了,建立volume-nfs.yaml
apiVersion: v1
kind: Pod
metadata:
  name: volume-nfs
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - containerPort: 80
    volumeMounts:
    - name: logs-volume
      mountPath: /var/log/nginx
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","tail -f /logs/access.log"] 
    volumeMounts:
    - name: logs-volume
      mountPath: /logs
  volumes:
  - name: logs-volume
    nfs:
      server: 192.168.109.100  #nfs伺服器位址
      path: /root/data/nfs #共享檔案路徑      
4)最後,運作下pod,觀察結果
# 建立pod
[root@master ~]# kubectl create -f volume-nfs.yaml
pod/volume-nfs created

# 檢視pod
[root@master ~]# kubectl get pods volume-nfs -n dev
NAME                  READY   STATUS    RESTARTS   AGE
volume-nfs        2/2     Running   0          2m9s

# 檢視nfs伺服器上的共享目錄,發現已經有檔案了
[root@master ~]# ls /root/data/
access.log  error.log      

進階存儲

PV和PVC

前面已經學習了使用NFS提供存儲,此時就要求使用者會搭建NFS系統,并且會在yaml配置nfs。由于kubernetes支援的存儲系統有很多,要求客戶全都掌握,顯然不現實。為了能夠屏蔽底層存儲實作的細節,友善使用者使用, kubernetes引入PV和PVC兩種資源對象。

PV(Persistent Volume)是持久化卷的意思,是對底層的共享存儲的一種抽象。一般情況下PV由kubernetes管理者進行建立和配置,它與底層具體的共享存儲技術有關,并通過插件完成與共享存儲的對接。

PVC(Persistent Volume Claim)是持久卷聲明的意思,是使用者對于存儲需求的一種聲明。換句話說,PVC其實就是使用者向kubernetes系統發出的一種資源需求申請。

4@Kubernetes(k8s)service和Ingress的使用資料存儲
使用了PV和PVC之後,工作可以得到進一步的細分:
  • 存儲:存儲工程師維護
  • PV: kubernetes管理者維護
  • PVC:kubernetes使用者維護

PV

PV是存儲資源的抽象,下面是資源清單檔案:
apiVersion: v1  
kind: PersistentVolume
metadata:
  name: pv2
spec:
  nfs: # 存儲類型,與底層真正存儲對應
  capacity:  # 存儲能力,目前隻支援存儲空間的設定
    storage: 2Gi
  accessModes:  # 通路模式
  storageClassName: # 存儲類别
  persistentVolumeReclaimPolicy: # 回收政策      
PV 的關鍵配置參數說明:
  • 存儲類型

    底層實際存儲的類型,kubernetes支援多種存儲類型,每種存儲類型的配置都有所差異

  • 存儲能力(capacity)
目前隻支援存儲空間的設定( storage=1Gi ),不過未來可能會加入IOPS、吞吐量等名額的配置
  • 通路模式(accessModes)

    用于描述使用者應用對存儲資源的通路權限,通路權限包括下面幾種方式:

  • ReadWriteOnce(RWO):讀寫權限,但是隻能被單個節點挂載
  • ReadOnlyMany(ROX): 隻讀權限,可以被多個節點挂載
  • ReadWriteMany(RWX):讀寫權限,可以被多個節點挂載

​需要注意的是,底層不同的存儲類型可能支援的通路模式不同​

  • 回收政策(persistentVolumeReclaimPolicy)

    當PV不再被使用了之後,對其的處理方式。目前支援三種政策:

  • Retain (保留) 保留資料,需要管理者手工清理資料
  • Recycle(回收) 清除 PV 中的資料,效果相當于執行 rm -rf /thevolume/*
  • Delete (删除) 與 PV 相連的後端存儲完成 volume 的删除操作,當然這常見于雲服務商的存儲服務

​需要注意的是,底層不同的存儲類型可能支援的回收政策不同​

  • 存儲類别

    PV可以通過storageClassName參數指定一個存儲類别

  • 具有特定類别的PV隻能與請求了該類别的PVC進行綁定
  • 未設定類别的PV則隻能與不請求任何類别的PVC進行綁定
  • 狀态(status)

    一個 PV 的生命周期中,可能會處于4中不同的階段:

  • Available(可用): 表示可用狀态,還未被任何 PVC 綁定
  • Bound(已綁定): 表示 PV 已經被 PVC 綁定
  • Released(已釋放): 表示 PVC 被删除,但是資源還未被叢集重新聲明
  • Failed(失敗): 表示該 PV 的自動回收失敗

實驗

使用NFS作為存儲,來示範PV的使用,建立3個PV,對應NFS中的3個暴露的路徑。
  1. 準備NFS環境
# 建立目錄
[root@master ~]# mkdir /root/data/{pv1,pv2,pv3} -pv

# 暴露服務
[root@master ~]# more /etc/exports
/root/data/pv1     192.168.109.0/24(rw,no_root_squash)
/root/data/pv2     192.168.109.0/24(rw,no_root_squash)
/root/data/pv3     192.168.109.0/24(rw,no_root_squash)

# 重新開機服務
[root@master ~]#  systemctl restart nfs      
  1. 建立pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name:  pv1
spec:
  capacity: 
    storage: 1Gi
  accessModes:
  - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /root/data/pv1
    server: 192.168.109.100

---

apiVersion: v1
kind: PersistentVolume
metadata:
  name:  pv2
spec:
  capacity: 
    storage: 2Gi
  accessModes:
  - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /root/data/pv2
    server: 192.168.109.100
    
---

apiVersion: v1
kind: PersistentVolume
metadata:
  name:  pv3
spec:
  capacity: 
    storage: 3Gi
  accessModes:
  - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /root/data/pv3
    server:      
# 建立 pv
[root@master ~]# kubectl create -f pv.yaml
persistentvolume/pv1 created
persistentvolume/pv2 created
persistentvolume/pv3 created

# 檢視pv
[root@master ~]# kubectl get pv -o wide      

PVC

PVC是資源的申請,用來聲明對存儲空間、通路模式、存儲類别需求資訊。下面是資源清單檔案:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc
  namespace: dev
spec:
  accessModes: # 通路模式
  selector: # 采用标簽對PV選擇
  storageClassName: # 存儲類别
  resources: # 請求空間
    requests:
      storage:      

PVC 的關鍵配置參數說明:

  • 通路模式(accessModes)

用于描述使用者應用對存儲資源的通路權限

  • 選擇條件(selector)

    通過Label Selector的設定,可使PVC對于系統中己存在的PV進行篩選

  • 存儲類别(storageClassName)

    PVC在定義時可以設定需要的後端存儲的類别,隻有設定了該class的pv才能被系統選出

  • 資源請求(Resources )

    描述對存儲資源的請求

實驗

  1. 建立pvc.yaml,申請pv
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc1
  namespace: dev
spec:
  accessModes: 
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
      
---

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc2
  namespace: dev
spec:
  accessModes: 
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
     
---

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc3
  namespace: dev
spec:
  accessModes: 
  - ReadWriteMany
  resources:
    requests:
      storage:      
# 建立pvc
[root@master ~]# kubectl create -f pvc.yaml
persistentvolumeclaim/pvc1 created
persistentvolumeclaim/pvc2 created
persistentvolumeclaim/pvc3 created

# 檢視pvc
[root@master ~]# kubectl get pvc  -n dev -o wide
NAME   STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE   VOLUMEMODE
pvc1   Bound    pv1      1Gi        RWX                           15s   Filesystem
pvc2   Bound    pv2      2Gi        RWX                           15s   Filesystem
pvc3   Bound    pv3      3Gi        RWX                           15s   Filesystem

# 檢視pv
[root@master ~]# kubectl get pv -o wide
NAME  CAPACITY ACCESS MODES  RECLAIM POLICY  STATUS    CLAIM       AGE     VOLUMEMODE
pv1    1Gi        RWx        Retain          Bound    dev/pvc1    3h37m    Filesystem
pv2    2Gi        RWX        Retain          Bound    dev/pvc2    3h37m    Filesystem
pv3    3Gi        RWX        Retain          Bound    dev/pvc3    3h37m    Filesystem      
  1. 建立pods.yaml, 使用pv
apiVersion: v1
kind: Pod
metadata:
  name: pod1
  namespace: dev
spec:
  containers:
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","while true;do echo pod1 >> /root/out.txt; sleep 10; done;"]
    volumeMounts:
    - name: volume
      mountPath: /root/
  volumes:
    - name: volume
      persistentVolumeClaim:
        claimName: pvc1
        readOnly: false
---
apiVersion: v1
kind: Pod
metadata:
  name: pod2
  namespace: dev
spec:
  containers:
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","while true;do echo pod2 >> /root/out.txt; sleep 10; done;"]
    volumeMounts:
    - name: volume
      mountPath: /root/
  volumes:
    - name: volume
      persistentVolumeClaim:
        claimName: pvc2
        readOnly: false      
# 建立pod
[root@master ~]# kubectl create -f pods.yaml
pod/pod1 created
pod/pod2 created

# 檢視pod
[root@master ~]# kubectl get pods -n dev -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP            NODE   
pod1   1/1     Running   0          14s   10.244.1.69   node1   
pod2   1/1     Running   0          14s   10.244.1.70   node1  

# 檢視pvc
[root@master ~]# kubectl get pvc -n dev -o wide
NAME   STATUS   VOLUME   CAPACITY   ACCESS MODES      AGE   VOLUMEMODE
pvc1   Bound    pv1      1Gi        RWX               94m   Filesystem
pvc2   Bound    pv2      2Gi        RWX               94m   Filesystem
pvc3   Bound    pv3      3Gi        RWX               94m   Filesystem

# 檢視pv
[root@master ~]# kubectl get pv -n dev -o wide
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM       AGE     VOLUMEMODE
pv1    1Gi        RWX            Retain           Bound    dev/pvc1    5h11m   Filesystem
pv2    2Gi        RWX            Retain           Bound    dev/pvc2    5h11m   Filesystem
pv3    3Gi        RWX            Retain           Bound    dev/pvc3    5h11m   Filesystem

# 檢視nfs中的檔案存儲
[root@master ~]# more /root/data/pv1/out.txt
node1
node1
[root@master ~]# more /root/data/pv2/out.txt      

生命周期

PVC和PV是一一對應的,PV和PVC之間的互相作用遵循以下生命周期:
  • 資源供應:管理者手動建立底層存儲和PV
  • 資源綁定:使用者建立PVC,kubernetes負責根據PVC的聲明去尋找PV,并綁定

    在使用者定義好PVC之後,系統将根據PVC對存儲資源的請求在已存在的PV中選擇一個滿足條件的

  • 一旦找到,就将該PV與使用者定義的PVC進行綁定,使用者的應用就可以使用這個PVC了
  • 如果找不到,PVC則會無限期處于Pending狀态,直到等到系統管理者建立了一個符合其要求的PV
PV一旦綁定到某個PVC上,就會被這個PVC獨占,不能再與其他PVC進行綁定了
  • 資源使用:使用者可在pod中像volume一樣使用pvc

    Pod使用Volume的定義,将PVC挂載到容器内的某個路徑進行使用。

  • 資源釋放:使用者删除pvc來釋放pv

    當存儲資源使用完畢後,使用者可以删除PVC,與該PVC綁定的PV将會被标記為“已釋放”,但還不能立刻與其他PVC進行綁定。通過之前PVC寫入的資料可能還被留在儲存設備上,隻有在清除之後該PV才能再次使用。

  • 資源回收:kubernetes根據pv設定的回收政策進行資源的回收
對于PV,管理者可以設定回收政策,用于設定與之綁定的PVC釋放資源之後如何處理遺留資料的問題。隻有PV的存儲空間完成回收,才能供新的PVC綁定和使用
4@Kubernetes(k8s)service和Ingress的使用資料存儲

配置存儲

ConfigMap

ConfigMap是一種比較特殊的存儲卷,它的主要作用是用來存儲配置資訊的。

建立configmap.yaml,内容如下:

apiVersion: v1
kind: ConfigMap
metadata:
  name: configmap
  namespace: dev
data:
  info: |
    username:admin
    password:123456      

接下來,使用此配置檔案建立configmap

# 建立configmap
[root@master ~]# kubectl create -f configmap.yaml
configmap/configmap created

# 檢視configmap詳情
[root@master ~]# kubectl describe cm configmap -n dev
Name:         configmap
Namespace:    dev
Labels:       <none>
Annotations:  <none>

Data
====
info:
----      

接下來建立一個pod-configmap.yaml,将上面建立的configmap挂載進去

apiVersion: v1
kind: Pod
metadata:
  name: pod-configmap
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    volumeMounts: # 将configmap挂載到目錄
    - name: config
      mountPath: /configmap/config
  volumes: # 引用configmap
  - name: config
    configMap:
      name:      
# 建立pod
[root@master ~]# kubectl create -f pod-configmap.yaml
pod/pod-configmap created

# 檢視pod
[root@master ~]# kubectl get pod pod-configmap -n dev
NAME            READY   STATUS    RESTARTS   AGE
pod-configmap   1/1     Running   0          6s

#進入容器
[root@master ~]# kubectl exec -it pod-configmap -n dev /bin/sh
# cd /configmap/config/
# ls
info
# more info
username:admin
password:123456

# 可以看到映射已經成功,每個configmap都映射成了一個目錄
# key--->檔案     value---->檔案中的内容
# 此時如果更新configmap的内容, 容器中的值也會動态更新      

Secret

在kubernetes中,還存在一種和ConfigMap非常類似的對象,稱為Secret對象。它主要用于存儲敏感資訊,例如密碼、秘鑰、證書等等。
  1. 首先使用base64對資料進行編碼
[root@master ~]# echo -n 'admin' | base64 #準備username
YWRtaW4=
[root@master ~]# echo -n '123456' | base64 #準備password      
  1. 接下來編寫secret.yaml,并建立Secret
apiVersion: v1
kind: Secret
metadata:
  name: secret
  namespace: dev
type: Opaque
data:
  username: YWRtaW4=
  password:      
# 建立secret
[root@master ~]# kubectl create -f secret.yaml
secret/secret created

# 檢視secret詳情
[root@master ~]# kubectl describe secret secret -n dev
Name:         secret
Namespace:    dev
Labels:       <none>
Annotations:  <none>
Type:  Opaque
Data      
  1. 建立pod-secret.yaml,将上面建立的secret挂載進去:
apiVersion: v1
kind: Pod
metadata:
  name: pod-secret
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    volumeMounts: # 将secret挂載到目錄
    - name: config
      mountPath: /secret/config
  volumes:
  - name: config
    secret:
      secretName:      
# 建立pod
[root@master ~]# kubectl create -f pod-secret.yaml
pod/pod-secret created

# 檢視pod
[root@master ~]# kubectl get pod pod-secret -n dev
NAME            READY   STATUS    RESTARTS   AGE
pod-secret      1/1     Running   0          2m28s

# 進入容器,檢視secret資訊,發現已經自動解碼了
[root@master ~]# kubectl exec -it pod-secret /bin/sh -n dev
/ # ls /secret/config/
password  username
/ # more /secret/config/username
admin
/ # more /secret/config/password      
至此,已經實作了利用secret實作了資訊的編碼。

三、安全認證

Kubernetes的安全認證機制。

通路控制概述

Kubernetes作為一個分布式叢集的管理工具,保證叢集的安全性是其一個重要的任務。所謂的安全性其實就是保證對Kubernetes的各種用戶端進行認證和鑒權操作。

用戶端

在Kubernetes叢集中,用戶端通常有兩類:
  • User Account:一般是獨立于kubernetes之外的其他服務管理的使用者賬号。
  • Service Account:kubernetes管理的賬号,用于為Pod中的服務程序在通路Kubernetes時提供身份辨別。
4@Kubernetes(k8s)service和Ingress的使用資料存儲

認證、授權與準入控制

ApiServer是通路及管理資源對象的唯一入口。任何一個請求通路ApiServer,都要經過下面三個流程:
  • Authentication(認證):身份鑒别,隻有正确的賬号才能夠通過認證
  • Authorization(授權): 判斷使用者是否有權限對通路的資源執行特定的動作
  • Admission Control(準入控制):用于補充授權機制以實作更加精細的通路控制功能。
4@Kubernetes(k8s)service和Ingress的使用資料存儲

認證管理

Kubernetes叢集安全的最關鍵點在于如何識别并認證用戶端身份,它提供了3種用戶端身份認證方式:
  • HTTP Base認證:通過使用者名+密碼的方式認證
這種認證方式是把“使用者名:密碼”用BASE64算法進行編碼後的字元串放在HTTP請求中的Header Authorization域裡發送給服務端。
    服務端收到後進行解碼,擷取使用者名及密碼,然後進行使用者身份認證的過程。      
  • HTTP Token認證:通過一個Token來識别合法使用者
這種認證方式是用一個很長的難以被模仿的字元串--Token來表明客戶身份的一種方式。
    每個Token對應一個使用者名,當用戶端發起API調用請求時,需要在HTTP Header裡放入Token,API Server接到Token後會跟伺服器中儲存的token進行比對,
    然後進行使用者身份認證的過程      
  • HTTPS證書認證:基于CA根證書簽名的雙向數字證書認證方式
這種認證方式是安全性最高的一種方式,但是同時也是操作起來最麻煩的一種方式。      
4@Kubernetes(k8s)service和Ingress的使用資料存儲

HTTPS認證大體分為3個過程:

  1. 證書申請和下發
HTTPS通信雙方的伺服器向CA機構申請證書,CA機構下發根證書、服務端證書及私鑰給申請者      
  1. 用戶端和服務端的雙向認證
1> 用戶端向伺服器端發起請求,服務端下發自己的證書給用戶端,
     用戶端接收到證書後,通過私鑰解密證書,在證書中獲得服務端的公鑰,
     用戶端利用伺服器端的公鑰認證證書中的資訊,如果一緻,則認可這個伺服器
  2> 用戶端發送自己的證書給伺服器端,服務端接收到證書後,通過私鑰解密證書,
     在證書中獲得用戶端的公鑰,并用該公鑰認證證書資訊,确認用戶端是否合法      
  1. 伺服器端和用戶端進行通信
伺服器端和用戶端協商好加密方案後,用戶端會産生一個随機的秘鑰并加密,然後發送到伺服器端。
  伺服器端接收這個秘鑰後,雙方接下來通信的所有内容都通過該随機秘鑰加密      
注意: Kubernetes允許同時配置多種認證方式,隻要其中任意一個方式認證通過即可

授權管理

授權發生在認證成功之後,通過認證就可以知道請求使用者是誰, 然後Kubernetes會根據事先定義的授權政策來決定使用者是否有權限通路,這個過程就稱為授權。

每個發送到ApiServer的請求都帶上了使用者和資源的資訊:比如發送請求的使用者、請求的路徑、請求的動作等,授權就是根據這些資訊和授權政策進行比較,如果符合政策,則認為授權通過,否則會傳回錯誤。

API Server目前支援以下幾種授權政策:

  • AlwaysDeny:表示拒絕所有請求,一般用于測試
  • AlwaysAllow:允許接收所有請求,相當于叢集不需要授權流程(Kubernetes預設的政策)
  • ABAC:基于屬性的通路控制,表示使用使用者配置的授權規則對使用者請求進行比對和控制
  • Webhook:通過調用外部REST服務對使用者進行授權
  • Node:是一種專用模式,用于對kubelet發出的請求進行通路控制
  • RBAC:基于角色的通路控制(kubeadm安裝方式下的預設選項)

RBAC(Role-Based Access Control) 基于角色的通路控制,主要是在描述一件事情:給哪些對象授予了哪些權限

其中涉及到了下面幾個概念:

  • 對象:User、Groups、ServiceAccount
  • 角色:代表着一組定義在資源上的可操作動作(權限)的集合
  • 綁定:将定義好的角色跟使用者綁定在一起
4@Kubernetes(k8s)service和Ingress的使用資料存儲

RBAC引入了4個頂級資源對象:

  • Role、ClusterRole:角色,用于指定一組權限
  • RoleBinding、ClusterRoleBinding:角色綁定,用于将角色(權限)賦予給對象

Role、ClusterRole

一個角色就是一組權限的集合,這裡的權限都是許可形式的(白名單)。

# Role隻能對命名空間内的資源進行授權,需要指定nameapce
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: dev
  name: authorization-role
rules:
- apiGroups: [""]  # 支援的API組清單,"" 空字元串,表示核心API群
  resources: ["pods"] # 支援的資源對象清單
  verbs: ["get", "watch", "list"] # 允許的對資源對象的操作方法清單      
# ClusterRole可以對叢集範圍内資源、跨namespaces的範圍資源、非資源類型進行授權
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
 name: authorization-clusterrole
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]      

需要詳細說明的是,rules中的參數:

  • apiGroups: 支援的API組清單
"","apps", "autoscaling", "batch"      
  • resources:支援的資源對象清單
"services", "endpoints", "pods","secrets","configmaps","crontabs","deployments","jobs",
"nodes","rolebindings","clusterroles","daemonsets","replicasets","statefulsets",
"horizontalpodautoscalers","replicationcontrollers","cronjobs"      
  • verbs:對資源對象的操作方法清單
"get", "list", "watch", "create", "update", "patch", "delete", "exec"      

RoleBinding、ClusterRoleBinding

角色綁定用來把一個角色綁定到一個目标對象上,綁定目标可以是User、Group或者ServiceAccount。
# RoleBinding可以将同一namespace中的subject綁定到某個Role下,則此subject即具有該Role定義的權限
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: authorization-role-binding
  namespace: dev
subjects:
- kind: User
  name: heima
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: authorization-role
  apiGroup:      
# ClusterRoleBinding在整個叢集級别和所有namespaces将特定的subject與ClusterRole綁定,授予權限
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
 name: authorization-clusterrole-binding
subjects:
- kind: User
  name: heima
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: authorization-clusterrole
  apiGroup:      

RoleBinding引用ClusterRole進行授權

RoleBinding可以引用ClusterRole,對屬于同一命名空間内ClusterRole定義的資源主體進行授權。
一種很常用的做法就是,叢集管理者為叢集範圍預定義好一組角色(ClusterRole),然後在多個命名空間中重複使用這些ClusterRole。這樣可以大幅提高授權管理工作效率,也使得各個命名空間下的基礎性授權規則與使用體驗保持一緻。      
# 雖然authorization-clusterrole是一個叢集角色,但是因為使用了RoleBinding
# 是以heima隻能讀取dev命名空間中的資源
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: authorization-role-binding-ns
  namespace: dev
subjects:
- kind: User
  name: heima
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: authorization-clusterrole
  apiGroup:      

實戰:建立一個隻能管理dev空間下Pods資源的賬号

  1. 建立賬号
# 1) 建立證書
[root@master pki]# cd /etc/kubernetes/pki/
[root@master pki]# (umask 077;openssl genrsa -out devman.key 2048)

# 2) 用apiserver的證書去簽署
# 2-1) 簽名申請,申請的使用者是devman,組是devgroup
[root@master pki]# openssl req -new -key devman.key -out devman.csr -subj "/CN=devman/O=devgroup"     
# 2-2) 簽署證書
[root@master pki]# openssl x509 -req -in devman.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out devman.crt -days 3650

# 3) 設定叢集、使用者、上下文資訊
[root@master pki]# kubectl config set-cluster kubernetes --embed-certs=true --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.109.100:6443

[root@master pki]# kubectl config set-credentials devman --embed-certs=true --client-certificate=/etc/kubernetes/pki/devman.crt --client-key=/etc/kubernetes/pki/devman.key

[root@master pki]# kubectl config set-context devman@kubernetes --cluster=kubernetes --user=devman

# 切換賬戶到devman
[root@master pki]# kubectl config use-context devman@kubernetes
Switched to context "devman@kubernetes".

# 檢視dev下pod,發現沒有權限
[root@master pki]# kubectl get pods -n dev
Error from server (Forbidden): pods is forbidden: User "devman" cannot list resource "pods" in API group "" in the namespace "dev"

# 切換到admin賬戶
[root@master pki]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".      
2) 建立Role和RoleBinding,為devman使用者授權
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: dev
  name: dev-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
  
---

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: authorization-role-binding
  namespace: dev
subjects:
- kind: User
  name: devman
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: dev-role
  apiGroup:      
[root@master pki]# kubectl create -f dev-role.yaml
role.rbac.authorization.k8s.io/dev-role created
rolebinding.rbac.authorization.k8s.io/authorization-role-binding created      
  1. 切換賬戶,再次驗證
# 切換賬戶到devman
[root@master pki]# kubectl config use-context devman@kubernetes
Switched to context "devman@kubernetes".

# 再次檢視
[root@master pki]# kubectl get pods -n dev
NAME                                 READY   STATUS             RESTARTS   AGE
nginx-deployment-66cb59b984-8wp2k    1/1     Running            0          4d1h
nginx-deployment-66cb59b984-dc46j    1/1     Running            0          4d1h
nginx-deployment-66cb59b984-thfck    1/1     Running            0          4d1h

# 為了不影響後面的學習,切回admin賬戶
[root@master pki]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".      

準入控制

通過了前面的認證和授權之後,還需要經過準入控制處理通過之後,apiserver才會處理這個請求。

準入控制是一個可配置的控制器清單,可以通過在Api-Server上通過指令行設定選擇執行哪些準入控制器:

--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,
                      DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds      

隻有當所有的準入控制器都檢查通過之後,apiserver才執行該請求,否則傳回拒絕。

目前可配置的Admission Control準入控制如下:

- AlwaysAdmit:允許所有請求
- AlwaysDeny:禁止所有請求,一般用于測試
- AlwaysPullImages:在啟動容器之前總去下載下傳鏡像
- DenyExecOnPrivileged:它會攔截所有想在Privileged Container上執行指令的請求
- ImagePolicyWebhook:這個插件将允許後端的一個Webhook程式來完成admission controller的功能。
- Service Account:實作ServiceAccount實作了自動化
- SecurityContextDeny:這個插件将使用SecurityContext的Pod中的定義全部失效
- ResourceQuota:用于資源配額管理目的,觀察所有請求,確定在namespace上的配額不會超标
- LimitRanger:用于資源限制管理,作用于namespace上,確定對Pod進行資源限制
- InitialResources:為未設定資源請求與限制的Pod,根據其鏡像的曆史資源的使用情況進行設定
- NamespaceLifecycle:如果嘗試在一個不存在的namespace中建立資源對象,則該建立請求将被拒絕。當删除一個namespace時,系統将會删除該namespace中所有對象。
- DefaultStorageClass:為了實作共享存儲的動态供應,為未指定StorageClass或PV的PVC嘗試比對預設的StorageClass,盡可能減少使用者在申請PVC時所需了解的後端存儲細節
- DefaultTolerationSeconds:這個插件為那些沒有設定forgiveness tolerations并具有notready:NoExecute和unreachable:NoExecute兩種taints的Pod設定預設的“容忍”時間,為5min
- PodSecurityPolicy:這個插件用于在建立或修改Pod時決定是否根據Pod的security context和可用的PodSecurityPolicy對Pod的安全政策進行控制      

四、DashBoard

之前在kubernetes中完成的所有操作都是通過指令行工具kubectl完成的。其實,為了提供更豐富的使用者體驗,kubernetes還開發了一個基于web的使用者界面(Dashboard)。使用者可以使用Dashboard部署容器化的應用,還可以監控應用的狀态,執行故障排查以及管理kubernetes中各種資源。

部署Dashboard

  1. 下載下傳yaml,并運作Dashboard
# 下載下傳yaml
[root@master ~]# wget  https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml

# 修改kubernetes-dashboard的Service類型
kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  type: NodePort  # 新增
  ports:
    - port: 443
      targetPort: 8443
      nodePort: 30009  # 新增
  selector:
    k8s-app: kubernetes-dashboard

# 部署
[root@master ~]# kubectl create -f recommended.yaml

# 檢視namespace下的kubernetes-dashboard下的資源
[root@master ~]# kubectl get pod,svc -n kubernetes-dashboard
NAME                                            READY   STATUS    RESTARTS   AGE
pod/dashboard-metrics-scraper-c79c65bb7-zwfvw   1/1     Running   0          111s
pod/kubernetes-dashboard-56484d4c5-z95z5        1/1     Running   0          111s

NAME                               TYPE       CLUSTER-IP      EXTERNAL-IP  PORT(S)         AGE
service/dashboard-metrics-scraper  ClusterIP  10.96.89.218    <none>       8000/TCP        111s
service/kubernetes-dashboard       NodePort   10.104.178.171  <none>       443:30009/TCP   111s      
2)建立通路賬戶,擷取token
# 建立賬号
[root@master-1 ~]# kubectl create serviceaccount dashboard-admin -n kubernetes-dashboard

# 授權
[root@master-1 ~]# kubectl create clusterrolebinding dashboard-admin-rb --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:dashboard-admin

# 擷取賬号token
[root@master ~]#  kubectl get secrets -n kubernetes-dashboard | grep dashboard-admin
dashboard-admin-token-xbqhh        kubernetes.io/service-account-token   3      2m35s

[root@master ~]# kubectl describe secrets dashboard-admin-token-xbqhh -n kubernetes-dashboard
Name:         dashboard-admin-token-xbqhh
Namespace:    kubernetes-dashboard
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: dashboard-admin
              kubernetes.io/service-account.uid: 95d84d80-be7a-4d10-a2e0-68f90222d039

Type:  kubernetes.io/service-account-token

Data
====
namespace:  20 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6ImJrYkF4bW5XcDhWcmNGUGJtek5NODFuSXl1aWptMmU2M3o4LTY5a2FKS2cifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkYXNoYm9hcmQtYWRtaW4tdG9rZW4teGJxaGgiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGFzaGJvYXJkLWFkbWluIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiOTVkODRkODAtYmU3YS00ZDEwLWEyZTAtNjhmOTAyMjJkMDM5Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmVybmV0ZXMtZGFzaGJvYXJkOmRhc2hib2FyZC1hZG1pbiJ9.NAl7e8ZfWWdDoPxkqzJzTB46sK9E8iuJYnUI9vnBaY3Jts7T1g1msjsBnbxzQSYgAG--cV0WYxjndzJY_UWCwaGPrQrt_GunxmOK9AUnzURqm55GR2RXIZtjsWVP2EBatsDgHRmuUbQvTFOvdJB4x3nXcYLN2opAaMqg3rnU2rr-A8zCrIuX_eca12wIp_QiuP3SF-tzpdLpsyRfegTJZl6YnSGyaVkC9id-cxZRb307qdCfXPfCHR_2rt5FVfxARgg_C0e3eFHaaYQO7CitxsnIoIXpOFNAR8aUrmopJyODQIPqBWUehb7FhlU1DCduHnIIXVC_UICZ-MKYewBDLw
ca.crt:     1025 bytes      

3)通過浏覽器通路Dashboard的UI

在登入頁面上輸入上面的token

4@Kubernetes(k8s)service和Ingress的使用資料存儲

出現下面的頁面代表成功

4@Kubernetes(k8s)service和Ingress的使用資料存儲

使用DashBoard

示範DashBoard的使用

檢視

選擇指定的命名空間​

​dev​

​​,然後點選​

​Deployments​

​,檢視dev空間下的所有deployment
4@Kubernetes(k8s)service和Ingress的使用資料存儲

擴縮容

在​

​Deployment​

​​上點選​

​規模​

​​,然後指定​

​目标副本數量​

​,點選确定
4@Kubernetes(k8s)service和Ingress的使用資料存儲

編輯

在​

​Deployment​

​​上點選​

​編輯​

​​,然後修改​

​yaml檔案​

​,點選确定
4@Kubernetes(k8s)service和Ingress的使用資料存儲

檢視Pod

點選​

​Pods​

​, 檢視pods清單
4@Kubernetes(k8s)service和Ingress的使用資料存儲

操作Pod

繼續閱讀