Kubernetes Ingress实战(一):在Kubernetes集群中部署NGINX Ingress Controller
2018-06-06
去年整理过一篇《Kubernetes Ingress实战》,经过这一年的发展Kubernetes的Ingress发生了很大的变化,原来的文章很多地方都不适用了。因此决定结合我们目前的使用情况重新写几篇Kubernetes Ingress相关的分享,内容是比较入门和初级的实操,请高手勿喷。
- Kubernetes Ingress实战(一):在Kubernetes集群中部署NGINX Ingress Controller
- Kubernetes Ingress实战(二):使用Ingress将第一个HTTP服务暴露到集群外部
- Kubernetes Ingress实战(三):使用Ingress将gRPC服务暴露到Kubernetes集群外部
- Kubernetes Ingress实战(四):Bare metal环境下Kubernetes Ingress边缘节点的高可用
- Kubernetes Ingress实战(五):Bare metal环境下Kubernetes Ingress边缘节点的高可用(基于IPVS)
- Kubernetes Ingress实战(六):Bare metal环境下Kubernetes Ingress边缘节点的高可用,Ingress Controller使用hostNetwork
Ingress是一种Kubernetes资源,借助Nginx、Haproxy或云厂商的负载均衡器将Kubernetes集群内的Service暴露到集群外。因为我们的Kubernetes集群是采以Bare-metal部署的,所以这个系列将主要介绍ingress-nginx。
下面将ingress-nginx部署到用于测试的Kubernetes集群中,这里使用的Kubernetes的版本是1.9.8。
1.创建namespace #
首先创建名称为ingress-nginx的namespace,ingress-nginx的相关组件的都将在这个namespace下。
namespace.yaml的内容如下:
1---
2
3apiVersion: v1
4kind: Namespace
5metadata:
6 name: ingress-nginx
1kubectl create -f namespace.yaml
2.部署default backend #
下面来创建default-http-backend
的Deployment和Service.
default-backend.yaml的内容如下:
1---
2
3apiVersion: extensions/v1beta1
4kind: Deployment
5metadata:
6 name: default-http-backend
7 labels:
8 app: default-http-backend
9 namespace: ingress-nginx
10spec:
11 replicas: 1
12 selector:
13 matchLabels:
14 app: default-http-backend
15 template:
16 metadata:
17 labels:
18 app: default-http-backend
19 spec:
20 terminationGracePeriodSeconds: 60
21 containers:
22 - name: default-http-backend
23 # Any image is permissible as long as:
24 # 1. It serves a 404 page at /
25 # 2. It serves 200 on a /healthz endpoint
26 image: gcr.io/google_containers/defaultbackend:1.4
27 livenessProbe:
28 httpGet:
29 path: /healthz
30 port: 8080
31 scheme: HTTP
32 initialDelaySeconds: 30
33 timeoutSeconds: 5
34 ports:
35 - containerPort: 8080
36 resources:
37 limits:
38 cpu: 10m
39 memory: 20Mi
40 requests:
41 cpu: 10m
42 memory: 20Mi
43---
44
45apiVersion: v1
46kind: Service
47metadata:
48 name: default-http-backend
49 namespace: ingress-nginx
50 labels:
51 app: default-http-backend
52spec:
53 ports:
54 - port: 80
55 targetPort: 8080
56 selector:
57 app: default-http-backend
需要注意
gcr.io/google_containers/defaultbackend:1.4
这个镜像在gcr上,由于某些已知的原因,最好将此镜像放到本地Kubernetes集群的私有镜像仓库中
1kubectl apply -f default-backend.yaml
2deployment "default-http-backend" created
3service "default-http-backend" created
确认default-http-backend
的Service和Pod被创建,并且Pod处于Running状态。
1kubectl get svc,deploy,pod -n ingress-nginx
2NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
3svc/default-http-backend ClusterIP 10.111.47.113 <none> 80/TCP 1m
4
5NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
6deploy/default-http-backend 1 1 1 1 1m
7
8NAME READY STATUS RESTARTS AGE
9po/default-http-backend-64985b4bcb-9pn7s 1/1 Running 0 1m
default-http-backend
从名称上来看即默认的后端,当集群外部的请求通过ingress进入到集群内部时,如果无法负载到相关后端的Service上,这种未知的请求将会被负载到这个默认的后端上。
3.创建ConfigMap #
接下来创建nginx-configuration
、tcp-services
、udp-services
三个ConfigMap:
1kubectl get deployment,pod -n ingress-nginx
2NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
3deploy/default-http-backend 1 1 1 1 1h
4deploy/nginx-ingress-controller 2 2 2 2 2m
5
6NAME READY STATUS RESTARTS AGE
7po/default-http-backend-64985b4bcb-9pn7s 1/1 Running 0 1h
8po/nginx-ingress-controller-7f9d776bff-5k28n 1/1 Running 0 2m
9po/nginx-ingress-controller-7f9d776bff-rwls2 1/1 Running 0 2m
10---
11
12kind: ConfigMap
13apiVersion: v1
14metadata:
15 name: nginx-configuration
16 namespace: ingress-nginx
17 labels:
18 app: ingress-nginx
1---
2
3kind: ConfigMap
4apiVersion: v1
5metadata:
6 name: tcp-services
7 namespace: ingress-nginx
1---
2
3kind: ConfigMap
4apiVersion: v1
5metadata:
6 name: udp-services
7 namespace: ingress-nginx
1kubectl apply -f configmap.yaml
2kubectl apply -f tcp-services-configmap.yaml
3kubectl apply -f udp-services-configmap.yaml
4
5kubectl get cm -n ingress-nginx
6NAME DATA AGE
7nginx-configuration 0 59s
8tcp-services 0 51s
9udp-services 0 45s
4.创建ServiceAccount并进行授权 #
接下来创建ServiceAccount nginx-ingress-serviceaccount
,并创建相关的ClusterRole, Role, ClusterRoleBinding, RoleBinding以对其进行授权:
1---
2
3apiVersion: v1
4kind: ServiceAccount
5metadata:
6 name: nginx-ingress-serviceaccount
7 namespace: ingress-nginx
8
9---
10
11apiVersion: rbac.authorization.k8s.io/v1beta1
12kind: ClusterRole
13metadata:
14 name: nginx-ingress-clusterrole
15rules:
16 - apiGroups:
17 - ""
18 resources:
19 - configmaps
20 - endpoints
21 - nodes
22 - pods
23 - secrets
24 verbs:
25 - list
26 - watch
27 - apiGroups:
28 - ""
29 resources:
30 - nodes
31 verbs:
32 - get
33 - apiGroups:
34 - ""
35 resources:
36 - services
37 verbs:
38 - get
39 - list
40 - watch
41 - apiGroups:
42 - "extensions"
43 resources:
44 - ingresses
45 verbs:
46 - get
47 - list
48 - watch
49 - apiGroups:
50 - ""
51 resources:
52 - events
53 verbs:
54 - create
55 - patch
56 - apiGroups:
57 - "extensions"
58 resources:
59 - ingresses/status
60 verbs:
61 - update
62
63---
64
65apiVersion: rbac.authorization.k8s.io/v1beta1
66kind: Role
67metadata:
68 name: nginx-ingress-role
69 namespace: ingress-nginx
70rules:
71 - apiGroups:
72 - ""
73 resources:
74 - configmaps
75 - pods
76 - secrets
77 - namespaces
78 verbs:
79 - get
80 - apiGroups:
81 - ""
82 resources:
83 - configmaps
84 resourceNames:
85 # Defaults to "<election-id>-<ingress-class>"
86 # Here: "<ingress-controller-leader>-<nginx>"
87 # This has to be adapted if you change either parameter
88 # when launching the nginx-ingress-controller.
89 - "ingress-controller-leader-nginx"
90 verbs:
91 - get
92 - update
93 - apiGroups:
94 - ""
95 resources:
96 - configmaps
97 verbs:
98 - create
99 - apiGroups:
100 - ""
101 resources:
102 - endpoints
103 verbs:
104 - get
105
106---
107
108apiVersion: rbac.authorization.k8s.io/v1beta1
109kind: RoleBinding
110metadata:
111 name: nginx-ingress-role-nisa-binding
112 namespace: ingress-nginx
113roleRef:
114 apiGroup: rbac.authorization.k8s.io
115 kind: Role
116 name: nginx-ingress-role
117subjects:
118 - kind: ServiceAccount
119 name: nginx-ingress-serviceaccount
120 namespace: ingress-nginx
121
122---
123
124apiVersion: rbac.authorization.k8s.io/v1beta1
125kind: ClusterRoleBinding
126metadata:
127 name: nginx-ingress-clusterrole-nisa-binding
128roleRef:
129 apiGroup: rbac.authorization.k8s.io
130 kind: ClusterRole
131 name: nginx-ingress-clusterrole
132subjects:
133 - kind: ServiceAccount
134 name: nginx-ingress-serviceaccount
135 namespace: ingress-nginx
1kubectl apply -f rbac.yaml
2serviceaccount "nginx-ingress-serviceaccount" created
3clusterrole "nginx-ingress-clusterrole" created
4role "nginx-ingress-role" created
5rolebinding "nginx-ingress-role-nisa-binding" created
6clusterrolebinding "nginx-ingress-clusterrole-nisa-binding" created
5.部署nginx-ingress-controller #
下面部署关键组件nginx-ingress-controller
这个ingress controller,前面提到Ingress是一种Kubernetes资源,借助Nginx、Haproxy或云厂商的负载均衡器将Kubernetes集群内的Service暴露到集群外
,nginx-ingress-controller
就是这个负载均衡器。
1---
2
3apiVersion: extensions/v1beta1
4kind: Deployment
5metadata:
6 name: nginx-ingress-controller
7 namespace: ingress-nginx
8spec:
9 replicas: 2
10 selector:
11 matchLabels:
12 app: ingress-nginx
13 template:
14 metadata:
15 labels:
16 app: ingress-nginx
17 annotations:
18 prometheus.io/port: '10254'
19 prometheus.io/scrape: 'true'
20 spec:
21 serviceAccountName: nginx-ingress-serviceaccount
22 affinity:
23 nodeAffinity:
24 requiredDuringSchedulingIgnoredDuringExecution:
25 nodeSelectorTerms:
26 - matchExpressions:
27 - key: kubernetes.io/hostname
28 operator: In
29 values:
30 - node1
31 - node2
32 containers:
33 - name: nginx-ingress-controller
34 image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.15.0
35 args:
36 - /nginx-ingress-controller
37 - --default-backend-service=$(POD_NAMESPACE)/default-http-backend
38 - --configmap=$(POD_NAMESPACE)/nginx-configuration
39 - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
40 - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
41 - --publish-service=$(POD_NAMESPACE)/ingress-nginx
42 - --annotations-prefix=nginx.ingress.kubernetes.io
43 env:
44 - name: POD_NAME
45 valueFrom:
46 fieldRef:
47 fieldPath: metadata.name
48 - name: POD_NAMESPACE
49 valueFrom:
50 fieldRef:
51 fieldPath: metadata.namespace
52 ports:
53 - name: http
54 containerPort: 80
55 - name: https
56 containerPort: 443
57 livenessProbe:
58 failureThreshold: 3
59 httpGet:
60 path: /healthz
61 port: 10254
62 scheme: HTTP
63 initialDelaySeconds: 10
64 periodSeconds: 10
65 successThreshold: 1
66 timeoutSeconds: 1
67 readinessProbe:
68 failureThreshold: 3
69 httpGet:
70 path: /healthz
71 port: 10254
72 scheme: HTTP
73 periodSeconds: 10
74 successThreshold: 1
75 timeoutSeconds: 1
76 securityContext:
77 runAsNonRoot: false
1kubectl apply -f nginx-ingress-controller.yaml
2deployment "nginx-ingress-controller" created
注意这里我们使用Kubernetes Pod调度的Node亲和性特性,将
nginx-ingress-controller
的两个Pod实例固定调度到node1和node2两个节点上。
6.将nginx-ingress-controller暴露到Kubernetes集群外 #
再看前面提到的Ingress是一种Kubernetes资源,借助Nginx、Haproxy或云厂商的负载均衡器将Kubernetes集群内的Service暴露到集群外
,nginx-ingress-controller
就是这个负载均衡器。所以我们还需要创建为nginx-ingress-controller
创建一个Service并暴露到集群外边(ps: 这个有点先有鸡还是先有蛋的意思)。
因为我们的Kubernetes集群是采以Bare-metal部署的,这里使用ExternalIP的形式创建一个ingress-nginx
的Service,ingress-nginx.svc.yaml如下:
1apiVersion: v1
2kind: Service
3metadata:
4 name: ingress-nginx
5 namespace: ingress-nginx
6spec:
7 externalIPs:
8 - 192.168.1.101
9 - 192.168.1.102
10 ports:
11 - name: http
12 port: 80
13 targetPort: 80
14 protocol: TCP
15 - name: https
16 port: 443
17 targetPort: 443
18 protocol: TCP
19 selector:
20 app: ingress-nginx
其中192.168.1.101, 192.168.1.102分别对应node1和node2两个k8s node的ip。
1kubectl apply -f ingress-nginx.svc.yaml
2service "ingress-nginx" created
1kubectl get svc -n ingress-nginx
2NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
3default-http-backend ClusterIP 10.111.47.113 <none> 80/TCP 1h
4ingress-nginx ClusterIP 10.96.122.13 192.168.1.101,192.168.1.102 80/TCP,443/TCP 55s
可以看出通过192.168.1.101,192.168.1.102:80/443将nginx-ingress-controller
的nginx的80和443端口暴露到集群外边。
分别请求这两个ExternalIP:
1curl 192.168.1.101:80
2default backend - 404
3
4curl 192.168.1.102:80
5default backend - 404
因为我们还没有在Kubernetes集群中创建ingress资源,所以直接对这两个ExternalIP的请求被负载到了default backend上。
分别在node1和node2上查看:
1netstat -nltp | grep kube-proxy | grep 80
2tcp 0 0 192.168.1.101:80 0.0.0.0:* LISTEN 2748840/kube-proxy
3
4netstat -nltp | grep kube-proxy | grep 80
5tcp 0 0 192.168.1.102:80 0.0.0.0:* LISTEN 2989745/kube-proxy
可以看到ExternalIP的Service也是通过kube-proxy对外暴露的。这里的192.168.1.101和192.168.1.102是两个内网ip。 实际中需要将边缘路由器或全局统一接入层的负载均衡器将到达公网ip的外网流量转发到内网ip上,外部通过域名访问集群中将会以ingress暴露的所有服务。 至于如何创建ingress,将会在下一篇中介绍。
到此为止,我们已经将nginx-ingress-controller
部署到了Kubernetes集群中。