去年整理过一篇《Kubernetes Ingress实战》,经过这一年的发展Kubernetes的Ingress发生了很大的变化,原来的文章很多地方都不适用了。因此决定结合我们目前的使用情况重新写几篇Kubernetes Ingress相关的分享,内容是比较入门和初级的实操,请高手勿喷。

1.在k8s集群中部署一个简单的http服务

部署一个简单的http服务到Kubernetes集群中,这里使用的http-svc.yaml这个官方的例子,注意其中的镜像是gcr.io/google_containers/echoserver:1.8。 一般我们线上环境的服务是部署到指定的namespace中的,因为这个http-svc.yaml中使用的是default的namespace,所以这里我们对其做一下修改,将其部署到我们集群中已经存在的名称为test的namespace中:

 1apiVersion: extensions/v1beta1
 2kind: Deployment
 3metadata:
 4  name: http-svc
 5  namespace: test
 6spec:
 7  replicas: 1
 8  selector:
 9    matchLabels:
10      app: http-svc
11  template:
12    metadata:
13      labels:
14        app: http-svc
15    spec:
16      containers:
17      - name: http-svc
18        image: gcr.io/google_containers/echoserver:1.8
19        ports:
20        - containerPort: 8080
21        env:
22          - name: NODE_NAME
23            valueFrom:
24              fieldRef:
25                fieldPath: spec.nodeName
26          - name: POD_NAME
27            valueFrom:
28              fieldRef:
29                fieldPath: metadata.name
30          - name: POD_NAMESPACE
31            valueFrom:
32              fieldRef:
33                fieldPath: metadata.namespace
34          - name: POD_IP
35            valueFrom:
36              fieldRef:
37                fieldPath: status.podIP
38
39---
40
41apiVersion: v1
42kind: Service
43metadata:
44  name: http-svc
45  namespace: test
46  labels:
47    app: http-svc
48spec:
49  ports:
50  - port: 80
51    targetPort: 8080
52    protocol: TCP
53    name: http
54  selector:
55    app: http-svc
1kubectl create -f http-svc.yaml
2
3
4kubectl get svc,po -n test
5NAME           TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
6svc/http-svc   ClusterIP   10.96.6.97   <none>        80/TCP    35s
7
8NAME                           READY     STATUS    RESTARTS   AGE
9po/http-svc-6d686cfdfc-lw578   1/1       Running   0          36s

2.使用Ingress将HTTP服务暴露到集群外

可以看出已经在Kubernetes集群的test namespace部署了一个http-svc的服务,但是只能在集群内部访问。下面为这个服务创建一个ingress将其暴露到集群外部。

先看以子路径path的形式暴露http-svc.ingress.yaml:

 1apiVersion: extensions/v1beta1
 2kind: Ingress
 3metadata:
 4  name: http-svc
 5  namespace: test
 6  annotations:
 7    nginx.ingress.kubernetes.io/ssl-redirect: "false"
 8spec:
 9  rules:
10  - http:
11      paths:
12      - path: /http-svc
13        backend:
14          serviceName: http-svc
15          servicePort: 80
1kubectl create -f http-svc.ingress.yaml
2ingress "http-svc" created
3
4kubectl get ingress -n test
5NAME       HOSTS     ADDRESS            PORTS     AGE
6http-svc   *         192.168.1.101,1...   80        1m

从集群外部访问:

 1 curl 192.168.1.101/http-svc
 2
 3Hostname: http-svc-6d686cfdfc-lw578
 4
 5Pod Information:
 6        node name:      node7
 7        pod name:       http-svc-6d686cfdfc-lw578
 8        pod namespace:  test
 9        pod IP: 10.244.6.120
10
11Server values:
12        server_version=nginx: 1.13.3 - lua: 10008
13
14Request Information:
15        client_address=10.244.1.143
16        method=GET
17        real path=/http-svc
18        query=
19        request_version=1.1
20        request_uri=http://192.168.1.101:8080/http-svc
21
22Request Headers:
23        accept=*/*
24        connection=close
25        host=192.168.1.3
26        user-agent=curl/7.29.0
27        x-forwarded-for=10.244.2.0
28        x-forwarded-host=192.168.1.101
29        x-forwarded-port=80
30        x-forwarded-proto=http
31        x-original-uri=/http-svc
32        x-real-ip=10.244.2.0
33        x-request-id=eea64169a57e0d3cd5cfe7b083559809
34        x-scheme=http
35
36Request Body:
37        -no body in request-

下面改为以域名(nginx虚拟主机)的形式暴露http-svc这个服务:

 1apiVersion: extensions/v1beta1
 2kind: Ingress
 3metadata:
 4  name: http-svc
 5  namespace: test
 6  annotations:
 7    nginx.ingress.kubernetes.io/ssl-redirect: "false"
 8spec:
 9  rules:
10  - host: http-svc.frognew.com
11    http:
12      paths:
13      - path: /
14        backend:
15          serviceName: http-svc
16          servicePort: 80
1kubectl apply -f http-svc.ingress.yaml
2ingress "http-svc" configured
3
4kubectl get ingress -n test
5NAME       HOSTS                         ADDRESS            PORTS     AGE
6http-svc   http-svc.frognew.com   192.168.1.101,1...   80        15m
 1curl 192.168.1.101 -H "Host: http-svc.frognew.com"
 2
 3Hostname: http-svc-6d686cfdfc-lw578
 4
 5Pod Information:
 6	node name:	node7
 7	pod name:	http-svc-6d686cfdfc-lw578
 8	pod namespace:	test
 9	pod IP:	10.244.4.120
10......

如果一个Kubernetes集群中有很多http服务需要暴露到集群外边的时,如果使用NodePort的形式,每个节点上都会监听大量的NodePort,而使用ingress,可以避免这种情况。 例如对于Kubernetes Dashoboard之前是以NodePort对外暴露的:

 1kind: Service
 2apiVersion: v1
 3metadata:
 4  labels:
 5    k8s-app: kubernetes-dashboard
 6  name: kubernetes-dashboard
 7  namespace: kube-system
 8spec:
 9  type: NodePort
10  ports:
11    - port: 443
12      targetPort: 8443
13      nodePort: 30001
14  selector:
15    k8s-app: kubernetes-dashboard

将Service的type修改为ClusterIp,并去掉指定的NodePort:

 1kind: Service
 2apiVersion: v1
 3metadata:
 4  labels:
 5    k8s-app: kubernetes-dashboard
 6  name: kubernetes-dashboard
 7  namespace: kube-system
 8spec:
 9  type: ClusterIP
10  ports:
11    - port: 443
12      targetPort: 8443
13  selector:
14    k8s-app: kubernetes-dashboard

并创建Ingress:

 1apiVersion: extensions/v1beta1
 2kind: Ingress
 3metadata:
 4  name: kubernetes-dashboard
 5  namespace: kube-system
 6  annotations:
 7    nginx.ingress.kubernetes.io/ssl-redirect: "false"
 8    nginx.ingress.kubernetes.io/secure-backends: "true"
 9spec:
10  rules:
11  - host: k8s.frognew.com
12    http:
13      paths:
14      - path: /
15        backend:
16          serviceName: kubernetes-dashboard
17          servicePort: 443

注意因为Service kubernetes-dashboard启用了https,所以是secure backend,在创建Ingress时需要用annotation指定nginx.ingress.kubernetes.io/secure-backends: "true"。 (更新:ingress-nginx更新的版本中改用nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"代替nginx.ingress.kubernetes.io/secure-backends: "true")

另外虽然在集群内部kubernetes-dashboard是https,而这里我们创建的ingress是http的暴露在80端口上,关于在ingress上开启https后边我们单独介绍。

1curl http://192.168.1.101 -H "Host: k8s.frognew.com"
2 <!doctype html> <html ng-app="kubernetesDashboard"> <head> <meta charset="utf-8"> <title ng-controller="kdTitle as $ctrl" ng-bind="$ctrl.title()"></title> ......

参考