kubernetes部署Ingress訪問代理與負載均衡器
==============================================================================node
Kubernetes中的pod都有獨立的內部IP(外部不可訪問),經過Service能夠對多個pod進行負載均衡和故障轉移,Service能夠具備ClusterIP、NodeIP或LoadBanlancer模式。目前,ClusterIP只能內部訪問,需經過kubectl proxy代理出來,NodeIP是跟Node綁定的、遷移性差,LoadBanlancer的每一個服務都有獨立的IP地址,管理、使用不便。有沒有一個固定的獨立IP、自動節點漂移的解決方案呢?之前這樣的功能基本上都用Nginx來實現,如今Kubernetes有一個作好了的服務,也是基於Nginx的,就是Ingress。nginx
==============================================================================git
如何訪問K8S中的服務:github
一、Ingress介紹
Kubernetes 暴露服務的方式目前只有三種:LoadBlancer Service、NodePort Service、Ingress;前兩種估計都應該很熟悉,下面詳細的瞭解下這個 Ingressweb
Ingress由兩部分組成:Ingress Controller 和 Ingress 服務。docker
Ingress Contronler 經過與 Kubernetes API 交互,動態的去感知集羣中 Ingress 規則變化,而後讀取它,按照自定義的規則,規則就是寫明瞭哪一個域名對應哪一個service,生成一段 Nginx 配置,再寫到 Nginx-ingress-control的 Pod 裏,這個 Ingress Contronler 的pod裏面運行着一個nginx服務,控制器會把生成的nginx配置寫入/etc/nginx.conf文件中,而後 reload 一下 使用配置生效。以此來達到域名分配置及動態更新的問題。ubuntu
看個簡單的圖方便理解:後端
ingress控制器有兩種:nginx和haproxy 這裏是以nginx爲講解。api
二、部署一個Nginx Ingress
ingress的部署文件在github Ingress 倉庫找到. 針對官方配置咱們單獨添加了 nodeselector 指定,綁定LB地址 以方便DNS 作解析。網絡
主要用到的文件:
1 2 3 4 5 6 7 8 |
$ ls default-backend.yaml jenkins-ingress.yml nginx-ingress-controller-rbac.yml nginx-ingress-controller.yaml - - - default-backend.yaml:這是官方要求必需要給的默認後端,提供404頁面的。它還提供了一個http檢測功能,檢測nginx-ingress-controll健康狀態的,經過每隔必定時間訪問nginx-ingress-controll的 /healthz 頁面,如是沒有響應就 返回404之類的錯誤碼。 nginx-ingress-controller-rbac.yml:這ingress的RBAC受權文件 nginx-ingress-controller.yaml:這是控制器的部署文件。 jenkins-ingress.yml:這是Ingress服務文件,這個能夠是任意web程序,裏面配置域名與service的對應關係,Ingress稱之爲規則。 |
第一個是要部署RBAC文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
cat nginx-ingress-controller-rbac.yml #apiVersion: v1 #kind: Namespace #metadata: #這裏是建立一個namespace,由於此namespace早有了就不用再建立了 # name: kube-system --- apiVersion: v1 kind: ServiceAccount metadata: name: nginx-ingress-serviceaccount #建立一個serveerAcount namespace: kube-system --- apiVersion: rbac.authorization.k8s.io /v1beta1 kind: ClusterRole metadata: name: nginx-ingress-clusterrole #這個ServiceAcount所綁定的集羣角色 rules: - apiGroups: - "" resources: #此集羣角色的權限,它能操做的API資源 - configmaps - endpoints - nodes - pods - secrets verbs: - list - watch - apiGroups: - "" resources: - nodes verbs: - get - apiGroups: - "" resources: - services verbs: - get - list - watch - apiGroups: - "extensions" resources: - ingresses verbs: - get - list - watch - apiGroups: - "" resources: - events verbs: - create - patch - apiGroups: - "extensions" resources: - ingresses /status verbs: - update --- apiVersion: rbac.authorization.k8s.io /v1beta1 kind: Role metadata: name: nginx-ingress-role #這是一個角色,而非集羣角色 namespace: kube-system rules: #角色的權限 - apiGroups: - "" resources: - configmaps - pods - secrets - namespaces verbs: - get - apiGroups: - "" resources: - configmaps resourceNames: # Defaults to "<election-id>-<ingress-class>" # Here: "<ingress-controller-leader>-<nginx>" # This has to be adapted if you change either parameter # when launching the nginx-ingress-controller. - "ingress-controller-leader-nginx" verbs: - get - update - apiGroups: - "" resources: - configmaps verbs: - create - apiGroups: - "" resources: - endpoints verbs: - get - create - update --- apiVersion: rbac.authorization.k8s.io /v1beta1 kind: RoleBinding #角色綁定 metadata: name: nginx-ingress-role-nisa-binding namespace: kube-system roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: nginx-ingress-role subjects: - kind: ServiceAccount name: nginx-ingress-serviceaccount #綁定在這個用戶 namespace: kube-system --- apiVersion: rbac.authorization.k8s.io /v1beta1 kind: ClusterRoleBinding #集羣綁定 metadata: name: nginx-ingress-clusterrole-nisa-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: nginx-ingress-clusterrole subjects: - kind: ServiceAccount name: nginx-ingress-serviceaccount #集羣綁定到這個serviceacount namespace: kube-system #集羣角色是能夠跨namespace,可是這裏只指明給這個namespce來使用 |
建立:
1 2 3 4 5 6 |
$ kubectl create -f nginx-ingress-controller-rbac.yml serviceaccount "nginx-ingress-serviceaccount" created clusterrole "nginx-ingress-clusterrole" created role "nginx-ingress-role" created rolebinding "nginx-ingress-role-nisa-binding" created clusterrolebinding "nginx-ingress-clusterrole-nisa-binding" created |
RBAC建立完後,就建立default backend服務:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
$ cat default-backend.yaml apiVersion: extensions /v1beta1 kind: Deployment metadata: name: default-http-backend labels: k8s-app: default-http-backend namespace: kube-system spec: replicas: 1 template: metadata: labels: k8s-app: default-http-backend spec: terminationGracePeriodSeconds: 60 containers: - name: default-http-backend # Any image is permissable as long as: # 1. It serves a 404 page at / # 2. It serves 200 on a /healthz endpoint image: gcr.io /google_containers/defaultbackend :1.0 livenessProbe: httpGet: path: /healthz #這個URI是 nginx-ingress-controller中nginx裏配置好的localtion port: 8080 scheme: HTTP initialDelaySeconds: 30 #30s檢測一次/healthz timeoutSeconds: 5 ports: - containerPort: 8080 resources: limits: cpu: 10m memory: 20Mi requests: cpu: 10m memory: 20Mi nodeSelector: #指定調度到些Node, 以便後面DNS解析 kubernetes.io /hostname : 10.3.1.17 --- apiVersion: v1 kind: Service #爲default backend 建立一個service metadata: name: default-http-backend namespace: kube-system labels: k8s-app: default-http-backend spec: ports: - port: 80 targetPort: 8080 selector: k8s-app: default-http-backend |
建立:
1 2 3 |
$ kubectl create -f default-backend.yaml deployment "default-http-backend" created service "default-http-backend" created |
建立以後查看:
1 2 3 4 5 6 7 8 9 10 11 |
root@ubuntu15: /data/ingress # kubectl get rs,pod,svc -n kube-system NAME DESIRED CURRENT READY AGE rs /default-http-backend-857b544d94 1 1 1 1m NAME READY STATUS RESTARTS AGE po /default-http-backend-857b544d94-bwgjd 1 /1 Running 0 1m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc /default-http-backend ClusterIP 10.254.208.144 <none> 80 /TCP 1m |
建立好default backend後就要建立nginx-ingress-controller了:
$ cat nginx-ingress-controller.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-ingress-controller
labels:
k8s-app: nginx-ingress-controller
namespace: kube-system
spec:
replicas: 1
template:
metadata:
labels:
k8s-app: nginx-ingress-controller
spec:
# hostNetwork makes it possible to use ipv6 and to preserve the source IP correctly regardless of docker configuration
# however, it is not a hard dependency of the nginx-ingress-controller itself and it may cause issues if port 10254 already is taken on the host
# that said, since hostPort is broken on CNI (https://github.com/kubernetes/kubernetes/issues/31307) we have to use hostNetwork where CNI is used
# like with kubeadm
# hostNetwork: true #註釋表示不使用宿主機的80口,
terminationGracePeriodSeconds: 60
hostNetwork: true #表示容器使用和宿主機同樣的網絡
serviceAccountName: nginx-ingress-serviceaccount #引用前面建立的serviceacount
containers:
- image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.1 #容器使用的鏡像
name: nginx-ingress-controller #容器名
readinessProbe: #啓動這個服務時要驗證/healthz 端口10254會在運行的node上監聽。
httpGet:
path: /healthz
port: 10254
scheme: HTTP
livenessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10 #每隔10作健康檢查
timeoutSeconds: 1
ports:
- containerPort: 80
hostPort: 80 #80映射到80
- containerPort: 443
hostPort: 443
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
args:
- /nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend
# - --default-ssl-certificate=$(POD_NAMESPACE)/ingress-secret #這是啓用Https時用的
nodeSelector: #指明運行在哪,此IP要和default backend是同一個IP
kubernetes.io/hostname: 10.3.1.17 #上面映射到了hostport80,確保此IP80,443沒有佔用.
這個控制器就是一個deployment ,裏面運行一個容器gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.1 ,有點像nginx容器,如今建立:
1 2 |
$ kubectl create -f nginx-ingress-controller.yaml deployment "nginx-ingress-controller" created |
1 2 3 4 5 6 7 8 9 10 11 |
root@ubuntu15: /data/ingress # kubectl get rs,pod,svc -n kube-system NAME DESIRED CURRENT READY AGE rs /default-http-backend-857b544d94 1 1 1 12m rs /nginx-ingress-controller-8576d4545d 1 1 0 27s NAME READY STATUS RESTARTS AGE po /default-http-backend-857b544d94-bwgjd 1 /1 Running 0 12m po /nginx-ingress-controller-8576d4545d-9tjnv 0 /1 ContainerCreating 0 27s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc /default-http-backend ClusterIP 10.254.208.144 <none> 80 /TCP 12m |
如今ingress controller 控制器已部署好了,那麼如何使用了,那就要寫一個ingress規則了,此處就以已存在的jenkins服務爲例,配置如何使用域名訪問這個service:
|
$ kubectl get svc,ep NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc /jenkinsservice NodePort 10.254.70.47 <none> 8080:30002 /TCP 3h NAME ENDPOINTS AGE ep /jenkinsservice 172.30.10.15:8080,172.30.11.7:8080 3h |
如今寫個jenkins service的Ingress 規則:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$ cat jenkins-ingress.yml apiVersion: extensions /v1beta1 kind: Ingress metadata: name: jenkins-ingress namespace: default #服務在哪一個空間內就寫哪一個空間 annotations: kubernetes.io /ingress .class: "nginx" spec: rules: - host: ingress.jenkins.com #此service的訪問域名 http: paths: - backend: serviceName: jenkinsservice servicePort: 8080 |
建立它:
$ kubectl create -f jenkins-ingress.yml
ingress "jenkins-ingress" created
$ kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
jenkins-ingress ingress.jenkins.com 80 10s
到這裏就已經部署完成了,配置好域名後,就能夠用此域名來訪問了:
部署完成了,如今看下nginx-ingress-controller 裏nginx配置文件發生了哪些變化:
upstream default-jenkinsservice-8080 {
least_conn;
server 172.30.10.15:8080 max_fails=0 fail_timeout=0;
server 172.30.11.7:8080 max_fails=0 fail_timeout=0;
}
upstream upstream-default-backend {
least_conn;
server 172.30.11.6:8080 max_fails=0 fail_timeout=0;
}
server {
server_name ingress.jenkins.com;
listen [::]:80;
location / {
...
proxy_pass http://default-jenkinsservice-8080;
...
}
}
這些配置都是ingress-controller 自已寫入的,動態更新就是它能經過K8S API感知到service的endpoint 發生了變化,而後修改nginx配置並執行reload.
至此,部署完成。
Ingress還有不少部署方式,好比配置https訪問的, 之後再寫。