kubernetes部署Ingress訪問代理與負載均衡器

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

   image.png

  一、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

      看個簡單的圖方便理解:後端

              image.png

   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

到這裏就已經部署完成了,配置好域名後,就能夠用此域名來訪問了:

  image.png

 

  部署完成了,如今看下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訪問的, 之後再寫。

相關文章
相關標籤/搜索