Ingress原理
node
在K8S中,暴露一個http服務通常有兩種方式,一是經過Service暴露端口的方式讓外部以及集羣內部的node來訪問到http相關頁面內容,二是經過Ingress負載均衡的方式,將由外部網絡域名訪問經過Ingress的Nginx節點反代到後端指定Service下的Pod節點中的http服務。nginx
Service的模式結構以下:git
service -> label selector -> pods
github
31217 -> app1 selector -> app1 1234
web
31218 -> app2 selector -> app2 3456
docker
31218 -> app2 selector -> app2 4567apache
訪問流程:json
【PREROUTING鏈】 -m comment --comment "kubernetes service portals" -j KUBE-SERVICES 【KUBE-SERVICES鏈】 -d 10.16.0.10/32 -p udp -m comment --comment "kube-system/kube-dns:dns cluster IP" -m udp --dport 53 -j KUBE-SVC-TCOU7JCQXEZGVUNU 【KUBE-SVC-TCOU7JCQXEZGVUNU鏈】 -m comment --comment "kube-system/kube-dns:dns" -j KUBE-SEP-L5MHPWJPDKD7XIFG 【KUBE-SEP-L5MHPWJPDKD7XIFG鏈】 -p udp -m comment --comment "kube-system/kube-dns:dns" -m udp -j DNAT --to-destination 10.0.0.46:53
注意:目前有三種訪問方式後端
①名稱空間,經過kube-proxyapi
②iptables,不須要直接經過kube-proxy因此效率更高
③經過ipvs進行,效率是最高的
目前默認使用的是②
用戶經過訪問由service層生成的ClusterIP以及隨機端口,訪問到由該service指定的惟一標誌label,指向內部挑選出來的Pod節點
向service ip 10.16.0.10:53發送udp請求,查找路由表,把數據包轉發給網橋docker0,在數據包進入docker0網橋時,數據包通過
PREROUTING鏈,而後跳至KUBE-SERVICES鏈,KUBE-SERVICES鏈中一條匹配此數據包的規則,跳至KUBE-SVC-*鏈KUBE-SVC-*
不作任何操做,跳至KUBE-SEP-*鏈KUBE-SEP-*裏對此數據包做了DNAT到10.0.0.46:53,其中10.0.0.46即爲kube-dns的pod ip
查找與10.0.0.46匹配的路由,轉發數據包到flannel.1,再交由flanneld進程進行封裝轉發出去。
Ingress模式結構以下:
ingress -> service -> label selector -> pods
www.app1.com -> app1-service -> app1 selector -> app1 1234
80 -> www.app2.com -> app2-service -> app2 selector -> app2 3456
www.app3.com -> app3-service -> app3 selector -> app3 4567
Ingress負載均衡由三種組件組成
①Nginx
②Ingress Controller
③Ingress
Nginx用於對外提供訪問,內部記錄了由Ingress Controller向kube-apiserver拿到的實時的service的endpoint到nginx配置文件中,
關聯的Service下的Pod節點的IP,端口信息,讓Nginx在訪問域名時可以反代到指定Service下屬的Pod節點上。Ingress則是用於在
Nginx中生成虛擬主機的配置端,如指定Service下屬的Pod節點的upstream上下文等配置信息。
Ingress負載均衡實現
基於http:
部署Ingress基本環境
Master節點上配置
官方文檔:https://github.com/kubernetes/ingress-nginx/tree/master/deploy
下載yaml文件
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/namespace.yaml | kubectl apply -f -
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/default-backend.yaml | kubectl apply -f -
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/tcp-services-configmap.yaml | kubectl apply -f -
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/udp-services-configmap.yaml | kubectl apply -f -
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/rbac.yaml | kubectl apply -f -
namespace.yaml:建立一個網絡名稱空間供Ingress使用
default-backend.yaml:建立一個在Nginx默認的虛擬主機配置。
tcp-services-configmap.yaml:使得Nginx能代理tcp,存放tcp四層負載均衡配置。
udp-services-configmap.yaml:使得Nginx能代理udp,存放udp四層負載均衡配置。
rbac.yaml:啓用rbac角色,將角色綁定到指定的 ServiceAccount。
啓用Ingress配置的yaml,default-backend.yaml須要更改鏡像爲國內鏡像
# kubectl create -f namespace.yaml
# kubectl create -f default-backend.yaml
# kubectl create -f tcp-services-configmap.yaml
# kubectl create -f udp-services-configmap.yaml
# kubectl create -f rbac.yaml
建立nginx,Ingress-controller
編輯yaml文件
[root@node-1 ingress]# cat deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
spec:
replicas: 1
selector:
matchLabels:
app: ingress-nginx
template:
metadata:
labels:
app: ingress-nginx
annotations:
prometheus.io/port: '10254'
prometheus.io/scrape: 'true'
spec:
serviceAccountName: nginx-ingress-serviceaccount
hostNetwork: true
containers:
- name: nginx-ingress-controller
image: lizhenliang/nginx-ingress-controller:0.9.0
args:
- /nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services
# - --annotations-prefix=nginx.ingress.kubernetes.io
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
啓用nginx-ingress-controller:kubectl create -f deployment.yaml
查看:
建立ingress配置文件,用於定義Ingress中須要的關聯Service,在這裏我建立兩個web服務,nginx與apache
# kubectl run --image=nginx:1.10 nginx --replicas=1 #定義deployment
# kubectl expose deployment nginx --port=80 #定義service,暴露端口
# kubectl run --image=httpd httpd --replicas=1
# kubectl expose deployment httpd --port=80
指定Ingress中須要關聯的service
[root@node-1 ingress]# cat ingress-test.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: http-test
spec:
rules:
- host: nginx-wjq.com
http:
paths:
- backend:
serviceName: nginx
servicePort: 80
- host: httpd-wjq.com
http:
paths:
- backend:
serviceName: httpd
servicePort: 80
#kubectl create -f ingress-test.yaml
這個時候查看nginx-ingress-controller的pod就會發現Ingress組件已經自動同步了相關的虛擬主機配置,ingress-controller去獲取到了Service後端的Pod
一下是建立了nginx,httpd的service後,自動同步到nginx中的配置
同步了httpd-wjq.com域名的虛擬主機在nginx中
同步了nginx-wjq.com域名的虛擬主機在nginx中
查看ingress-controller在哪一個pod主機上,就能夠經過那個主機對外的物理IP訪問到Nginx從而訪問到對應域名service的Pod應用
能夠配置ingress-controller在兩個node物理主機上,修改replicas爲2
[root@node-1 ingress]# kubectl edit deployment nginx-ingress-controller -n ingress-nginx -o yaml
瀏覽器訪問
須要在本地物理機的host文件中添加域名解析
192.168.175.130 nginx-wjq.com
192.168.175.130 httpd-wjq.com
基於https:
建立密鑰對:
使用cfssl建立私人CA
# cfssl print-defaults csr > ca-csr.json ##建立默認的csr json文件
修改ca-csr.json
[root@node-1 https]# cat ca-csr.json
{
"CN": "wujunqi", ##CA名稱
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "shenzhen",
"ST": "shenzhen"
}
]
}
建立私人CA參數,有效期之類的,默認是一年,無需修改
# cfssl print-defaults config > ca-config.json
生成CA密鑰對:
# cfssl gencert --initca ca-csr.json | cfssljson -bare ca
建立出ca.pem以及ca-key.pem
再根據兩個密鑰對建立出針對於域名的相關密鑰證書
在建立一個證書請求文件,針對於某一訪問域名
# cfssl print-defaults csr > server-csr.json
# cat server-csr.json
[root@node-1 https]# cat server-csr.json
{
"CN": "www.wujunqi.com",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "shenzhen",
"ST": "shenzhen"
}
]
}
由私人CA針對該證書請求文件建立對應的密鑰對
# cfssl gencert -ca=ca.pem -ca-key=ca-key.pem --config=ca-config.json --prefile=www server-csr.json | cfssljson -bare server
至此,須要的密鑰建立完成
建立在集羣中使用的TLS
# kubectl create secret tls wujunqi-https --key server-key.pem --cert server.pem
查看tls
# kubectl get secret
建立Ingress使用TLS進行訪問,指定Service,讓ingress-controller關聯到Service後端的Pod
[root@node-1 ingress]# cat https.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: https-test
spec:
tls:
- hosts:
- www.wujunqi.com
secretName: wujunqi-https
rules:
- host: www.wujunqi.com
http:
paths:
- backend:
serviceName: nginx
servicePort: 80
建立Ingress:
# kubectl create -f https.yaml
查看Ingress:
這時候就能夠進行訪問了,將物理主機的host文件中添加域名解析
192.168.175.130 www.wujunqi.com