《kubernetes + .net core 》dev ops部分
阿新 • • 發佈:2020-10-03
[TOC]
# 1.kubernetes 預備知識
kubernetes是一個用go語言寫的容器編排框架,常與docker搭配使用。
kubernetes是谷歌內部的容器編排框架的開源實現。可以用來方便的管理容器叢集。具有很多 優點,要了解這些優點,需要先來了解一下kubernetes中的叢集資源。這裡指的是kubernetes裡的原生的資源,kubernetes也支援自定義的資源。
## 1.1 叢集資源
不區分名稱空間
+ cluster role
+ namespace
+ node
+ persistent volume
+ storage class
### 1.1.1 role
+ 普通角色 role
+ 叢集角色 culster role
群集預設採用`RBAC(role base access control)`進行叢集資源的訪問控制,可以將角色作用於`使用者user`或`服務service`,限制它們訪問群集資源的許可權範圍。
其中角色又區分為 `叢集角色 cluster role` 和`普通的角色 role` ,他們的區別是可以作用的範圍不一致。
普通角色必有名稱空間限制,只能作用於與它同名稱空間的使用者或服務。
叢集角色沒有名稱空間限制,可以用於所有名稱空間的使用者或服務。下面的目錄中會詳細介紹。先在這裡提一下
### 1.1.2 namespace
不指定時預設作用default名稱空間,服務在跨名稱空間訪問其他服務時 域名需要加上名稱空間後輟才能訪問
### 1.1.3 node
+ 主節點 master
+ 工作節點 none
+ 邊緣節點 none
是一個包含作業系統的機器,作業系統可以是Linux也可以是windwos,可以是實體機也可以是虛擬機器,其中的區別下面的其他目錄會詳細說明
### 1.1.4 persistent volume
持久卷 ,支援的型別很多,包括谷歌 亞馬遜 阿里云云服務提供商的各種儲存.
由於我們的專案一般是用於區域網內的,所以這裡我著重介紹`nfs(network file system)`
### 1.1.5 storage class
儲存類,用於根據pvc 自動建立/自動掛載/自動回收 對應的nfs目錄前
## 1.2 工作量資源 (消耗cpu ram)
+ pod
+ job
+ cron job
+ replica set
+ deployment
+ daemon set
+ statefull set
### 1.2.1 pod
工作量的最小單位是pod 其他的型別的工作量都是控制Pod的。
pod相當於docker 中的docker composite,可以由單個或多個容器組成,每個pod有自己的docker網路,pod裡的container處於同個區域網中。
其他的控制器都有一個pod template,用於建立Pod
### 1.2.2 job
工作,一但應用到叢集將會建立一個pod做一些工作,具體的工作內容由Pod的實現決定,工作完成後Pod自動終結。
### 1.2.3 cron job
定時工作任務,一但應用到叢集,叢集將會定時建立pod 做一些工作,工作完成後pod自動終結
### 1.2.4 replica set
複製集或稱為副本集,一但應用到叢集,會建立相n個相同的 pod,並且會維護這個pod的數量,如果有pod異常終結,replica set會建立一個新的Pod 以維護使用者指定的數量
### 1.2.5 deplyoment
deplyoment常用來建立無狀態的應用叢集。
部署,deplyoment依賴於replicaset ,它支援滾動更新,滾動更新的原理是,在原有的一個replica set的基礎上建立一個新版本的replica set ,
舊版本的replicaset 逐個減少 ,新版本的replicaset逐個新增, 可以設定一個引數指定滾動更新時要保持的最小可用pod數量。
### 1.2.6 daemon set
守護程序集 ,顧名思義,他的作用就是維護某個作業系統(node)的某個程序(pod)始終工作。當一個dameon set被應用到k8s叢集,所有它指定的節點上都會建立某個pod
比如日誌採集器 一個節點上有一個,用daemon set就十分應景。
### 1.2.7 stateful set
stateful set常用於建立有狀態的服務叢集,它具有以下特點
+ 穩定的唯一網路識別符號
+ 穩定,持久的儲存
+ 有序,順暢的部署和擴充套件
+ 有序的自動滾動更新
舉個例子,你有一個容器需要存資料,比如mysql容器,這時你用deplyoment就不合適,因為多個mysql例項各自應該有自己的儲存,DNS名稱。
這個時候就應該使用statefull set。它原理是建立無頭服務(沒有叢集ip的服務)和有序號的Pod,並把這個無頭服務的域名+有序號的主機名(pod名稱),獲得唯一的DNS名稱
比如設定stateful set的名稱為web,redplica=2,則會有序的建立兩個Pod:web-0 web-1,當web-0就緒後才會建立web-1,如果是擴容時也是這樣的,而收容的時候順序而是反過來的,會從序號大的Pod開始刪除多餘的Pod
如果把一個名稱為nginx的無頭服務指向這個statufulset,則web-0的dns名稱應該為 web-0.nginx
並且 stateful set會為這兩個Pod建立各自的pvc,由於pod的名稱是唯一的,所以故障重建Pod時,可以把新的Pod關聯到原有的儲存捲上
## 1.3 儲存和配置資源 (消耗儲存)
+ config map
+ secret map
+ persistent volume claim
### 1.3.1 config map
ConfigMap 允許你將配置檔案與映象檔案分離,以使容器化的應用程式具有可移植性。
+ 如何建立
+ 如何使用
建立:
```bash
# 從資料夾建立(資料夾裡的文字檔案將會被建立成config map
kubectl create configmap my-config --from-file=path/to/bar
# 從檔案建立
kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt
# 從字串建立
kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2
# 從鍵值文字建立
kubectl create configmap my-config --from-file=path/to/bar
# 從env檔案建立
kubectl create configmap my-config --from-env-file=path/to/bar.env
```
使用:
+ 作為pod的環境變數
+ 作為儲存卷掛載到Pod
### 1.3.2 secrets
Secret 是一種包含少量敏感資訊例如密碼、令牌或金鑰的物件。 這樣的資訊可能會被放在 Pod 規約中或者映象中。 使用者可以建立 Secret,同時系統也建立了一些 Secret。
### 1.3.3 pvc
+ 由叢集管理員管理
+ 由storage class管理
如果由叢集管理員管理,由開發人員應向叢集管理員申請Pv ,叢集管理員要手動的建立Pv,pvc,把pvc給開發人員,開發人員手動掛載pvc到pod
如果由storage class管理,則叢集管理員只要建立一個provider, 之後provider會自動監視叢集中的Pvc 和pod ,自動建立pv和掛載
# 2.kubernetes node 元件
kubernetes叢集中,至少要有一個主節點,主節點應該有以下元件
+ kubelet
+ kuber-proxy
+ cni網路外掛
+ etcd
+ kube-apiserver
+ coreDNS
+ kube-controller-manager
+ kube-schedule
普通節點的元件
+ kubelet
+ kube-proxy
+ cni網路外掛
## 2.1 kubectl
kubernetes節點代理元件,每個node上都需要有,他不是Kubernetes建立的容器,所以在叢集中查不到。
他的主要做的工作是
1.向kube api以hostname為名註冊節點
2.監視pod執行引數,使Pod以引數預期的狀態執行,所以Pod有異常通常都能查詢Kubelet的日誌來排查錯誤
## 2.2 kube-proxy
kubernetes 的服務相關的元件,每個Node上都需要有,除了無頭服務,其他所有服務都由他處理流量
k8s叢集在初始化的時候,會指定服務網段和pod網段,其中服務網段的ip都是虛擬Ip
他主要做的工作是:
監視叢集的服務,如果服務滿足某些條件,則通過ipvs 把這個服務的流量轉發到各個後端Pod (cluster ip)
## 2.3 cni網路外掛
cni: container network interface
k8s稱之為視窗編排叢集,他的核心思想是把不同的容器網路聯合起來,使所有的pod都在一個扁平的網路裡,可以互換訪問
為達這個目的就需要容器網路外掛,下面介紹一下主流的cni外掛,並大致說明一下優劣
+ flannel
+ calico
+ 其他
### 2.3.1 flannel
![Flannel](flannel.png)
![Flannel](https://img2020.cnblogs.com/blog/1251880/202010/1251880-20201002231937972-904314969.png)
flanel是橋接模式的代表外掛,
他的工作原理是用daemonset在每個節點上部署flannel外掛,外掛設定容器網路並把容器網路資訊通過 kube api儲存到etcd中 。
這樣就確保不會重複註冊網段了,與不同node上的Pod通過 kube-proxy打包 發給其他Node的kuber proxy,kuber proxy再拆包,發給pod
以達到跨node的扁平網路訪問. 這種方式也稱vxlan 或overlay
優點:
+ 網路協議簡單,容易分析。
+ 社群規模比較大,成功案例比較多,資料比較全面,入門比較簡單
缺點:
+ 由於有打包 拆包, 所以通訊效率比較低下
+ 不支援網路策略
### 2.3.2 calico
calico 是閘道器模式的代表外掛。 它主要由以下幾部分構成
它基於邊界閘道器協議 BGP(border gateway protocol)
他的工作原理是用daemonset在每個節點上部署calico node, 來構成扁平化容器網路
calico node由以下幾個元件
+ felix
+ confid
+ BIRD(BGP Internet route daemon)
felix 負責編寫路由和訪問控制列表
confid 用於把 felix生成的資料記錄到etcd,用於持久化規則
BIRD 用於廣播felix寫到系統核心的路由規則和訪問控制列表acl和calico的網路
當叢集規模比較大的時候還可以可選的安裝 BGP Rotue Reflector(BIRD) 和 Typha
前者用於快速廣播協議,後者用於直接與ETCD通訊,減小 kubeapi的壓力
優點:
+ pod跨node的網路流量 直接進系統核心 走路由表,效率極高
+ 支援網路策略
缺點:
+ 跨node的資料包經過DNAT和SNAT後,分析網路封包會比較複雜
+ 部署也比較複雜
![Calico](calico.png)
![Calico](https://img2020.cnblogs.com/blog/1251880/202010/1251880-20201002232017953-239635186.png)
## 2.4 etcd
etc distributed ,一款使用go語言編寫的基於raft共識演算法的分散式KV快取框架 ,
不像redis重效能,而像zookeeper 一樣重資料一致性
特點是有較高的寫入效能
![Etcd Disk](etcd-disk.png)
![](https://img2020.cnblogs.com/blog/1251880/202010/1251880-20201002232044474-242283761.png)
![Etcd Network](etcd-network.png)
![](https://img2020.cnblogs.com/blog/1251880/202010/1251880-20201002232101087-1286058960.png)
![Etcd Cpu](etcd-cpu.png)
![](https://img2020.cnblogs.com/blog/1251880/202010/1251880-20201002232124910-1435955004.png)
![Etcd Memory](etcd-memory.png)
![](https://img2020.cnblogs.com/blog/1251880/202010/1251880-20201002232135694-1463631331.png)
![Etcd Throughput](etcd-throughput.png)
![](https://img2020.cnblogs.com/blog/1251880/202010/1251880-20201002232159753-168930121.png)
![Etcd Latency Distribution](etcd-latencyDistribution.png)
![](https://img2020.cnblogs.com/blog/1251880/202010/1251880-20201002232211642-1452309483.png)
## 2.5 kube-apiserver
k8s 暴露給外部的web api,用於叢集的互動 有各種語言的api client開源專案 ,程式設計師也可以在程式中引用,監視一些叢集資源
## 2.6 coreDNS
用於叢集中的service 和 pod的域名解析,
也可以配置對叢集外的域名應該用哪個DNS解析
## 2.7 kube-controller-manager
用於 各種控制器(消耗cpu ram)的管理
## 2.8 kube-schedule
用於 管理控制 Pod排程相關
# 3.叢集的高可用
+ 分散式共識演算法 Raft
+ keepalived
+ haproxy
![File](file.png)
![](https://img2020.cnblogs.com/blog/1251880/202010/1251880-20201002232228097-232852967.png)
## 3.1 etcd的raft演算法
[raft](http://thesecretlivesofdata.com/raft/)
raft是etcd的共識演算法,kubernetes用etcd來儲存叢集的配置。config map /secret都是基於etcd。
理解raft共識演算法可以知道
+ 為什麼高可用叢集主節點是3個 5個 7個 而不是 2個 4個 6個
+ kubernetes的主節點發生單點故障的時候, 儲存的行為會有什麼改變
## 3.2 keepalived
在高可用環境, keepalived用於虛擬ip的選舉,一旦持有虛擬Ip的節點發生故障,其他的主節點會選擇出新的主節點持有虛擬ip。並且可以配置smtp資訊,當節點故障的時候發郵件通知相關的責任人
```bash
onfiguration File for keepalived
global_defs {
notification_email {
[email protected]
}
notification_email_from [email protected]
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_1
}
vrrp_instance VI_1 {
state MASTER
interface eth0
lvs_sync_daemon_inteface eth0
virtual_router_id 79
advert_int 1
priority 100 #權重 m1 100 m2 90 m3 80
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.44.200/24 dev eth0
}
}
```
## 3.3 haproxy
每個主節點都部署了haproxy代理kube api埠, 所以當它持有虛擬ip的時候,會把所有對kube api的請求負載均衡到所有的主節點上。
```bash
global
chroot /var/lib/haproxy
daemon
group haproxy
user haproxy
log 127.0.0.1:514 local0 warning
pidfile /var/lib/haproxy.pid
maxconn 20000
spread-checks 3
nbproc 8
defaults
log global
mode tcp
retries 3
option redispatch
listen https-apiserver
bind *:8443
mode tcp
balance roundrobin
timeout server 900s
timeout connect 15s
server m1 192.168.44.201:6443 check port 6443 inter 5000 fall 5
server m2 192.168.44.202:6443 check port 6443 inter 5000 fall 5
server m3 192.168.44.203:6443 check port 6443 inter 5000 fall 5
```
# 4 認證/授權
## 4.1 authentication
kubernetes叢集中的認證物件分為
1. 使用者
2. 服務
除此之外,還有一些其他的非kubernetes叢集管理的服務會需要訪問叢集資源的情況
但是這個暫時不實踐,因為haoyun目前不會使用到這種情況
### 4.1.1 使用者
使用者不是kuebrnetes 的資源,所以單獨拎出來講。
#### 4.1.1.1 檢視使用者
master node在加入叢集時,會提示我們手動複製預設的管理員使用者到 `$HOME/.kube `資料夾
所以檢視 $HOME/.kube/config檔案可以知道叢集 使用者 認證上下文
```bash
[root@www .kube]# cat config
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZ...#略
server: https://www.haoyun.vip:8443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: LS0tLS1CRUdJTiBDR...#略
client-key-data: LS0tLS1CRUdJTiBS..#.略
```
#### 4.1.1.2 新增使用者
建立1使用者,並進入使用者資料夾
```bash
[root@www .kube]# useradd hbb && cd /home/hbb
```
建立私鑰
```bash
[root@www hbb]# openssl genrsa -out hbb_privateKey.key 2048
Generating RSA private key, 2048 bit long modulus
............................................................+++
.............................................................................................................................................................+++
e is 65537 (0x10001)
```
建立x.509證書籤名請求 (CSR) ,CN會被識別為使用者名稱 O會被識別為組
```bash
openssl req -new -key hbb_privateKey.key \
-out hbb.csr \
-subj "/CN=hbb/O=hbbGroup1/O=hbbGroup2"
#O可以省略也可以寫多個
```
為CSR簽入kubernetes 的證書和證書公鑰,生成證書
```bash
openssl x509 -req -in hbb.csr \
-CA /etc/kubernetes/pki/ca.crt \
-CAkey /etc/kubernetes/pki/ca.key \
-CAcreateserial \
-out hbb.crt -days 50000
#證書有效天數 50000天
```
建立證書目錄 ,存入把公鑰(hbb.crt)和私鑰(hbb_private.key) 放進去
```bash
[root@www hbb]# mkdir .certs
[root@www hbb]# cd .certs/
[root@www .certs]# mv ../hbb_privateKey.key ../hbb.crt .
[root@www .certs]# ll
total 8
-rw-r--r--. 1 root root 940 Sep 5 15:41 hbb.csr
-rw-r--r--. 1 root root 1679 Sep 5 15:29 hbb_privateKey.key
```
建立叢集使用者
```bash
kubectl config set-credentials hbb \
--client-certificate=/home/hbb/.certs/hbb.crt \
--client-key=/home/hbb/.certs/jean_privatekey.key
```
建立使用者上下文
```bash
kubectl config set-context hbb-context \
--cluster=kubernetes --user=hbb
```
這時原有的config檔案裡就多了Hbb這個使用者了
```yaml
users:
- name: hbb
user:
client-certificate: /home/hbb/.certs/hbb.crt
client-key: /home/hbb/.certs/hbb_privatekey.key
```
複製 原有的.kube/config檔案到hbb使用者資料夾 ,在副本上刪除kubernetes-admin的上下文和使用者資訊。
```bash
[root@www .kube]# mkdir /home/hbb/.kube
[root@www .kube]# cp config /home/hbb/.kube/
[root@www .kube]# cd /home/hbb/.kube
[root@www .kube]# vim config
[root@www .kube]# cat config
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJU...#略
server: https://www.haoyun.vip:8443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: hbb
name: hbb-context
current-context: hbb-context
kind: Config
preferences: {}
users:
- name: hbb
user:
client-certificate: /home/hbb/.certs/hbb.crt
client-key: /home/hbb/.certs/hbb_privateKey.key
```
之後把hbb使用者資料夾授權給hbb使用者
```bash
[root@www .kube]# chown -R hbb: /home/hbb/
#-R 遞迴資料夾
#hbb: 只設置了使用者沒有設定組
```
這樣就建立一個使用者了,此時退出root使用者,使用hbb使用者登上去,預設就是使用Hbb的user去訪問叢集
但是這時還沒有給hbb授權,所以基本上什麼操作都執行不了,因為沒有許可權
```bash
[hbb@www .certs]$ kubectl get pod -A
Error from server (Forbidden): pods is forbidden: User "hbb" cannot list resource "pods" in API group "" at the cluster scope
```
## 4.2 authorization (RBAC)
[官方文件](https://kubernetes.io/zh/docs/reference/access-authn-authz/rbac/)
相關的kubernetes 資源
+ namespace
+ roles/clusterRoles
+ rolebindings/clusterRolebindings
### 4.2.1 namespace
roles和rolebindings 如果要建立關聯,他們必須是同一個名稱空間內。
clusterRoles和clusterRolebindings 沒有名稱空間的限制,它們的規則作用於叢集範圍
### 4.2.2 roles/clusterRoles
在 RBAC API 中,一個角色包含一組相關許可權的規則。許可權是純粹累加的(不存在拒絕某操作的規則)。 角色可以用 `Role` 來定義到某個名稱空間上, 或者用 `ClusterRole` 來定義到整個叢集作用域。
一個 `Role` 只可以用來對某一名稱空間中的資源賦予訪問許可權。 下面的 `Role` 示例定義到名稱為 "default" 的名稱空間,可以用來授予對該名稱空間中的 Pods 的讀取許可權:
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default #如果是clusterRoles 則沒刪除這一行
name: pod-reader
rules:
- apiGroups: [""] # "" 指定 API 組
resources: ["pods","pods/log"] #子資源
verbs: ["get", "watch", "list"]
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["my-configmap"] #具體名稱的資源
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
#下面這個只有clusterRoles 才可以使用
- nonResourceURLs: ["/healthz", "/healthz/*"] # '*' 在 nonResourceURL 中的意思是字尾全域性匹配。
verbs: ["get", "post"]
```
clusterRoles比 roles 多出以下的能力
- 叢集範圍資源 (比如 nodes)
- 非資源端點(比如 "/healthz")
- 跨名稱空間訪問的有名字空間作用域的資源(如 get pods --all-namespaces)
### 4.2.3 rolebindings/clusterRolebindings
rolebindings也可以使用ClusterRoles,會將裡面的資源的作用域限定到rolebindings的名稱空間範圍內。
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
- kind: User #使用者
name: jane
apiGroup: rbac.authorization.k8s.io
- kind: Group #使用者組
name: "frontend-admins"
apiGroup: rbac.authorization.k8s.io
- kind: ServiceAccount #服務帳戶
name: default
namespace: kube-system
- kind: Group # 所有myNamespace名稱空間下的服務
name: system:serviceaccounts:myNamespace
apiGroup: rbac.authorization.k8s.io
- kind: Group #所有名稱空間的所有服務
name: system:serviceaccounts
apiGroup: rbac.authorization.k8s.io
- kind: Group #所有認證過的使用者
name: system:authenticated
apiGroup: rbac.authorization.k8s.io
- kind: Group #所有未誰的使用者
name: system:authenticated
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role #可以是叢集名角或普通的角色
name: pod-reader
apiGroup: rbac.authorization.k8s.io
```
# 5.服務
[官方文件](https://kubernetes.io/zh/docs/concepts/services-networking/service/#publishing-services-service-types)
服務是微服務抽象,常用於通過選擇符訪問一組Pod, 也可以訪問其他物件,
+ 叢集外部的服務
+ 其他名稱空間的服務
上面這兩種情況,服務的選擇符可以省略。
## 5.1 代理模式
kubernetes v1.0時使用使用者空間代理 (userspace)
v1.1添加了iptable代理模式,
v1.2預設使用iptables代理模式
v1.11新增ipvs 模式
當Node上不支援ipvs會回退使用iptables模式
### 5.1.1 userSpace模式
![Userspace](userspace.png)
![](https://img2020.cnblogs.com/blog/1251880/202010/1251880-20201002232257642-297210052.png)
每個結點上部署kube-proxy ,它會監視主結點的apiserver對service 和 endpoints的增刪改
為每個server隨機開一個埠,並寫入叢集Ip寫入iptables,把對叢集服務的叢集Ip的流量 轉發到這個隨機的埠上 ,
然後再轉發到後端的Pod上, 一般是採用輪詢的規則,根據服務上的sessionAnfinity來設定連線的親和性
### 5.1.2 iptables模式
![Iptables](iptables.png)
![](https://img2020.cnblogs.com/blog/1251880/202010/1251880-20201002232308177-729857245.png)
與userspace的區別是 不僅把service寫入Iptables,同時把endpoints也寫入了iptables,
所以不用在核心空間和使用者空間之間來回切換,效能提升
### 5.1.3 ipvs
![Ipvs](ipvs.png)
![](https://img2020.cnblogs.com/blog/1251880/202010/1251880-20201002232321121-1059772709.png)
ipvs(ip virtrual server)和iptables都是基於netfilter ,但ipvs以雜湊表做為基礎資料結構,並工作在核心空間
相比iptables,所以他有更好的效能,也支援更多的負載均衡演算法
+ rr: round-robin 輪詢
+ lc: least connection (smallest number of open connections) 最少連線
+ dh: destination hashing 目標雜湊
+ sh: source hashing 源雜湊
+ sed: shortest expected delay 最低延遲
+ nq: never queue 不排隊
如果需要粘性會話,可以在服務中設定
service.spec.sessionAffinity 為 clusterip ,預設是none
service.spec.sessionAffinityConfig.clientIP.timeoutSeconds 可以調整會話最長時間,預設是10800秒
## 5.2 服務發現
服務可以通過環境變數和DNS的方式來發現服務,推薦的做法是通過DNS
### 5.2.1 通過環境變數
一個名稱為 "redis-master" 的 Service 暴露了 TCP 埠 6379, 同時給它分配了 Cluster IP 地址 10.0.0.11 ,
這個 Service 生成了如下環境變數:
```bash
REDIS_MASTER_SERVICE_HOST=10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11
```
如果需要在pod中使用這些環境變數,需要在啟動pod之前先啟動服務。
### 5.2.2 通過DNS
服務直接用服務名稱為域名,
Pod會在服務之前加上ip為域名
例如在名稱空間 hbb下有服務 hbb-api, 服務指向的後端pod Ip地址是10-244-6-27.,則會有dns記錄
```bash
# 服務
hscadaexapi.hbb.svc.cluster.local
```
```bash
# pod
10-244-6-27.hscadaexapi.hbb.svc.cluster.local
```
dns應該儘可能使用,最好不要使用環境變數的方式
## 5.3 服務型別
+ clusterip 叢集IP
+ nodeport 結點IP
+ loadbalance 外部負載均衡器
+ external ip 外部IP
+ none 無頭服務(有狀態服務)
+ externalname 外部服務
### 5.3.1 clusterip 叢集IP
虛擬的ip ,通常指向一組pod (真實ip)
```yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
- name: https
protocol: TCP
port: 443
targetPort: 9377
```
### 5.3.2 nodeport 結點IP
每個主結點上的具體埠,通常把 node ip+埠 轉發到 一組pod(真實ip)
```yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
app: MyApp
ports:
# 預設情況下,為了方便起見,`targetPort` 被設定為與 `port` 欄位相同的值。
- port: 80
targetPort: 80
# 可選欄位
# 預設情況下,為了方便起見,Kubernetes 控制平面會從某個範圍內分配一個埠號(預設:30000-32767)
nodePort: 30007
```
### 5.3.3 loadbalance 外部負載均衡器
通常把 外部流量 轉發到 一組pod(真實ip) ,外部ip一般是在雙網絡卡的邊緣節點上
```yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
clusterIP: 10.0.171.239
loadBalancerIP: 78.11.24.19
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 146.148.47.155
```
### 5.3.4 external IP
將外部的流量引入服務 ,這種外部Ip 不由叢集管理,由由叢集管理員維護
```yaml
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
externalIPs:
- 80.11.12.10
```
### 5.3.5 none 無頭服務(有狀態服務)
kube-proxy元件不對無頭服務進行代理,無頭服務 加上序號 指向 Pod,固定搭配,
所以即使 服務的pod掛了, 重啟來的服務的 域名也不會換一個,用於有狀態的服務。
後面講到Pod控制器statefulset會再細講
### 5.3.6 externalname 外部服務
kube-proxy元件不會對外部服務進行代理則是對映到dns 用於描述一個叢集外部的服務,有解耦合的作用,
所以它和無頭服務一樣沒有選擇器,他也不由叢集管理,而是由叢集管理員維護
```yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
```
## 5.4 叢集入口 ingress
由於iptables代理模組或亦 ipvs代理模式都是4層負載均衡,無法對7層協議進行負載均衡,所以對於外部的流量 ,常使用入口資源來進行負載均衡,把外部的流量均衡到服務上
+ ingress contorller
+ ingress 資源
### 5.4.1 ingress controller
ingress controller 是負載均衡器例項,一個叢集中可以部署多個, 每個又可以自為一個負載均衡叢集
在建立ingress資源的時候,可以用 註解Annotations:來指定要使用哪個ingress controller
````yaml
kubernetes.io/ingress.class: nginx
````
這個nginx是controller容器啟動時 用命令列的方式指定的
```bash
Args:
/nginx-ingress-controller
--default-backend-service=kube-system/my-nginx-ingress-default-backend
--election-id=ingress-controller-leader
--ingress-class=nginx
```
### 5.4.2 ingress 資源
[Ingress](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#ingress-v1beta1-networking-k8s-io) 公開了從叢集外部到叢集內服務的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 資源上定義的規則控制。
可以將 Ingress 配置為服務提供外部可訪問的 URL、負載均衡流量、終止 SSL/TLS,以及提供基於名稱的虛擬主機等能力。 Ingress 控制器 通常負責通過負載均衡器來實現 Ingress,儘管它也可以配置邊緣路由器或其他前端來幫助處理流量。
Ingress 不會公開任意埠或協議。 將 HTTP 和 HTTPS 以外的服務公開到 Internet 時,通常使用 Service.Type=NodePort 或 Service.Type=LoadBalancer 型別的服務
#### 5.4.2.1 捕獲重寫Path 轉發
```yaml
`apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /testpath
pathType: Prefix
backend:
serviceName: test
servicePort: 80
```
#### 5.4.2.2 基於主機域名轉發
```yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: service1
servicePort: 80
- host: bar.foo.com
http:
paths:
- backend:
serviceName: service2
servicePort: 80
```
# 6.配置和儲存
+ config map
+ secrets
+ nfs persistent volume
+ empty/hostpath
## 6.1 config map
ConfigMap 允許你將配置檔案與映象檔案分離,以使容器化的應用程式具有可移植性。
### 6.1.1 建立config map
```bash
# 從資料夾建立(資料夾裡的文字檔案將會被建立成config map
kubectl create configmap my-config --from-file=path/to/bar
# 從檔案建立
kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt
# 從字串建立
kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2
# 從鍵值文字建立
kubectl create configmap my-config --from-file=path/to/bar
# 從env檔案建立
kubectl create configmap my-config --from-env-file=path/to/bar.env
```
### 6.1.2 使用config map
+ 作為pod的環境變數
+ 作為儲存卷掛載到Pod
#### 6.1.2.1 作為pod的環境變數
建立1個config map 配置檔案,在default名稱空間裡
```bash
kubectl create configmap hbb-config --from-literal=key1=aaa --from-literal=key2=bbb
```
建立一個pod ,使用busybox映象,並把上面的cm 載入到環境變數,在pod 的container裡面加上
```yaml
containers:
- name: busybox
image: busybox:1.28
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
env:
- name: HBBKEY1
valueFrom:
configMapKeyRef:
name: hbb-config
key: key1
- name: HBBKEY2
valueFrom:
configMapKeyRef:
name: hbb-config
key: key2
```
簡易寫法,載入所有hbb-config裡的key value
````yaml
containers:
- name: busybox
image: busybox:1.28
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
envFrom:
- configMapRef:
name: hbb-config
````
經測試,如果修改了config map ,Pod的環境變數是不會自動更新的,除非刪除pod重新建立
#### 6.1.2.2 作為儲存卷掛載到pod
```yaml
containers:
- name: busybox
image: busybox:1.28
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
volumeMounts:
- name: hbb-cm-volume
mountPath: /etc/config
volumes:
- name: hbb-cm-volume
configMap:
name: hbb-config
```
經驗證,修改config map後,去檢視掛載上去的卷,檔案中的值也隨之發生了改變,所以這種方式是比較好的方式。
## 6.2 secrets
Secret 是一種包含少量敏感資訊例如密碼、令牌或金鑰的物件。 這樣的資訊可能會被放在 Pod 規約中或者映象中。 使用者可以建立 Secret,同時系統也建立了一些 Secret。
+ 建立secret
+ 驗證 secret
+ 使用 secret
### 6.2.1 建立secrets
+ 通過檔案生成
+ 通過字串生成
+ 手動建立
+ 通過stringData 應用時加密明文secret
+ 檢視驗證
#### 6.2.1.1 通過檔案生成
```bash
#生成檔案
echo -n 'admin' > ./username.txt
echo -n '1f2d1e2e67df' > ./password.txt
#從檔案生成
kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt
```
預設的鍵名就是檔名,如果要另外指定可以--from-file=[key=]source,密碼也是如此
```bash
#從檔案生成
kubectl create secret generic db-user-pass --from-file=hbb-key=./username.txt --from-file=hbb-pas=./password.txt
```
#### 6.2.1.2 通過字串生成
說明:特殊字元(例如 `$`、`*`、`*`、`=` 和 `!`)可能會被 sell轉義,所以要用''括起來
```bash
kubectl create secret generic dev-db-secret \
--from-literal=username=devuser \
--from-literal=password='S!B\*d$zDsb='
```
#### 6.2.1.3 手動建立 secret
加密使用者名稱admin和密碼password
```bash
[root@www ~]# echo -n 'admin' | base64 ; echo -n 'password' |base64
YWRtaW4=
cGFzc3dvcmQ=
```
建立一個mysecret.yaml
```yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
```
用kubectl 建立
```bash
kubectl apply -f ./mysecret.yaml
```
#### 6.2.1.4 通過stringData 應用時加密明文
建立1個 mysecret.yaml
```yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
stringData:
config.yaml: |-
apiUrl: "https://my.api.com/api/v1"
username: hbb
password: hbb-password
```
執行
```bash
kubectl apply -f ./mysecret.yaml
```
將會建立 一個mysecret 資源,裡面有一個config.yaml的key,它的value是一個加密的字串。
注: mysecret.yaml第7行的|- 的意思是:將下面三行字串組合起來,替換右邊的縮排(空格和換行)成一個換行符。
這種方式的好處是,可以和helm一起使用,helm使用go 的模版,可以配置明文的字元
### 6.2.2 檢視驗證secret
```bash
[root@www ~]# kubectl describe secret/dev-db-secret
Name: dev-db-secret
Namespace: default
Labels: