k8s

kubernetes之ingress controller

kubernetes之ingress controller

Posted by ysy on March 10, 2020

##前言

当我们想要内部的集群暴露给外部可以访问时,可以使用NodeIP类型的服务把应用暴露给外部用户使用,但是当应用越来越多,以及需要使用七层负载均衡https,NodeIP类型就不适合,所以k8s就提供了一个模块-ingress

Ingres与NodeIP对比

NodeIP优缺点

优点:
1、结构简单,容易理解
缺点:
1、一个app需要占用一个主机端口,管理紊乱,数据较多不适合
2、L4(TCP/UDP)转发,无法根据http path进行转发

Ingress优缺点

优点:
1、可以实现7层识别,了一跟觉url header、path进行转发
2、方便卸载https
缺点:
1、复杂度提升
2、加了一层解析

Ingress实现

实现 Ingress是一个模块,现在可以实现的方式有很多,例如ingress-nginxtraefik,这里是使用的 ingress-nginx, git地址

第一步

需要拉取ingress代码,并且进入文件夹 ingress-nginx->deploy->static,最后直接生成该文件夹下的所有配置(先生成命名空间文件),其中包括ingress的命名空间等

kubectl apply -f namespace.yaml
kubectl apply -f ./

查看一下 kubectl get ns

NAME              STATUS   AGE
default           Active   45h
ingress-nginx     Active   16h
kube-node-lease   Active   45h
kube-public       Active   45h
kube-system       Active   45h

第二步 创建pods与svc

这里的服务并不是为了通过ingress调用服务,而是ingress通过服务来获取pods的更新(添加-删除-重建),当pods更新时候,service会把更新信息同步到ingress上,由ingress直接找到pods,这样会减少一层service解析

首先,编写pods与service的yaml, deploy-demo.yaml

apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: default
spec:
  selector:
    app: myapp
    release: canary
  ports:
  - name: http
    targetPort: 80
    port: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      release: canary
  template:
    metadata:
      labels:
        app: myapp
        release: canary
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v2
        ports:
        - name: http
          containerPort: 80

执行yaml文件

kubectl apply -f deploy-demo.yaml

查看service与pods

NAME                             READY   STATUS    RESTARTS   AGE
myapp-deploy-798dc9b584-dq5gd    1/1     Running   0          22h
myapp-deploy-798dc9b584-f9pjw    1/1     Running   0          22h
myapp-deploy-798dc9b584-whnp9    1/1     Running   0          22h

NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP             2d5h
myapp        ClusterIP   10.96.232.187   <none>        80/TCP              22h
第三步 添加与pods的server相关联的ingress

首先,编写ingress的yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-myapp
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - host: myapp.magedu.com
    http:
      paths:
      - path:
        backend:
          serviceName: myapp
          servicePort: 80

注意:

1、metadata的annotations一定要标明是nginx,要不然会有问题

2、ingress的namespace要与所属的pods在同一个

3、host指向的域名是我们刚才pod的域名,一会要在hosts文件指定一下

第四步 创建ingress的svc

因为ingress实际上也相当于一个pod,所以也要有一个service与外部通信

这个官网上有执行的代码

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml

也可以下载下来查看一下yaml文件

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml

文件内容我们增加一个了一个nodePort

apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  type: NodePort
  ports:
    - name: http
      port: 80
      targetPort: 80
      protocol: TCP
      nodePort: 30080
    - name: https
      port: 443
      targetPort: 443
      protocol: TCP
      nodePort: 30443
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---

这里我们使用的namespace是ingress-nginx

并且添加了nodePort为30080与30443

执行一下yaml文件并查看service

kubectl get svc -n ingress-nginx

NAME            TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx   NodePort   10.96.252.14   <none>        80:30080/TCP,443:30443/TCP   3d17h
第五步 hosts中添加域名并访问
172.17.0.1 myapp.magedu.com

curl myapp.magedu.com:30080
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>

这个输出说明ingress-nginx布置成功了

Ingress卸载https

当需要使用https来进行通信时,因为iptables和ipvs是工作在4层的,所以没有办法对7层https进行解析,如果需要提供https服务(需要在后端提供服务的pod上配置ssl证书,这样一来在kubernetes内部也是通过https进行访问)就比较麻烦,这个时候就需要用ingress 来卸载https

第一步 生成证书与secret

因为是本地测试,所以可以生成一个简单的证书

openssl genrsa -out tls.key 2048

openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=BeiJing/L=BeiJing/O=DevOps/CN=tomcat-magedu.com

注意:这里的CN一定要与我们要访问的域名相同

生成完证书之后,生成一个secret

kubectl create secret tls tomcat-ingress-secret --cert=tls.crt --key=tls.key

可以查看secret

kubectl get secret

NAME                    TYPE                                  DATA   AGE
default-token-vmbjv     kubernetes.io/service-account-token   3      5d23h
tomcat-ingress-secret   kubernetes.io/tls                     2      125m
第二步 生成带有rules的ingress

编写yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-tomcat-tls
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  tls:
  - hosts:
    - tomcat.magedu.com
    secretName: tomcat-ingress-secret
  rules:
  - host: tomcat.magedu.com
    http:
      paths:
      - path:
        backend:
          serviceName: tomcat
          servicePort: 8080

rules包括hosts列表和刚才生成的sccret名称

然后生成该ingress

kubectl create -f ingress-tomcat-tls.yaml

因为我们前面的ingress的svc指定的30443端口会请求443端口,所以我们访问一下

curl https://tomcat.magedu.com:30443 --insecure

因为我们的证书不受信任,所以加上–insecure,最后访问成功,设置成功。