K8S Ingress 之 traefik-ingress-controller

文本先说一下背景,再谈一下组件关系,然后看看怎么实施配置部署。

一、需求背景

在上篇 K8S HelloWord 一文中,我们已经实现了对 web 服务的部署和正常外部访问,但是你可能发现了,我们使用的端口是30001,采用了NodePort方式映射并固定了30001端口,使其可以固定对外提供服务。
但是,该端口默认范围是30000~32767,并且我们的web服务一般都是80、443端口对外,因此我们产生了如下几点需求和疑问:
1、如果想暴露80、443端口,你可以修改k8s apiserver的参数将端口设置为80~xxxx,但是不推荐这样做,因为k8s在一些场景需求的时候会自动在端口范围内生成一个端口使用,如果我们的端口访问包含了常用端口,可能会给其他本地服务带来麻烦。
2、如果你的系统服务增多,需要暴露更多的web服务的时候,那么也同样需要设置固定更多的NodePort端口,为了避免端口冲突你还要对使用的端口进行整理维护。
3、一个系统对外暴露的端口增多,就好比我们的园区开了更多的门一样,任何一个门有安全问题,都会导致整个园区产生安全风险,我们的系统同样如此。当这个问题在实现了下面第4点后就不是问题了。
4、还有一个最重要的是,我们是web服务,怎么能少了https证书呢。所以依然需要在增加一个独立的nginx、traefik等组件来配置证书。
针对如上问题,我们总是需要一个方向代理服务的。既然需要单独管理维护一个,不如用 k8s 为了提供了的ingress控制器方案,完美解决问题。

二、主要组件关系

Service: 后端真实服务的抽象,一个 Service 可以代表多个相同的后端服务,向下对应多个 Pod。
Ingress: 反向代理规则,用来规定 HTTP/S 请求应该被转发到哪个 Service 上,根据根据请求中不同的 Host 和 url 路径让请求落到不同的 Service 上。
Ingress Controller: 它是一个反向代理程序,也是一个具体的 Pod,它负责解析 Ingress 的反向代理规则,如果 Ingress 有增删改的变动,所有的 Ingress Controller 都会及时更新自己相应的转发规则,当 Ingress Controller 收到请求后就会根据这些规则将请求转发到对应的 Service。
Kubernetes 并没有自带 Ingress Controller,它只是一种标准,具体实现有多种,需要自己单独安装,常用的是 Nginx Ingress Controller 和 Traefik Ingress Controller。 所以 Ingress 是一种转发规则的抽象,Ingress Controller 的实现需要根据这些 Ingress 规则来将请求转发到对应的 Service,我画了一张图来描述它们之间的关系,然后本文也实现一个该图的实例:
K8S Ingress 之 traefik-ingress-controller_第1张图片

三、实施部署

本例使用的 traefik-controller 版本为 traefik:1.7.20,现在官方最新版是 2.x 了,因为时间问题就直接拿本地 1.7.20 版本的配置来写文了,注意本文在上篇文章 K8S HelloWorld 的基础上配置。
1、文件 traefik.yml

---
apiVersion: v1
kind: Namespace
metadata:
  name: traefik-ingress-controller
---
# Source: traefik/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: traefik-ingress
  labels:
    app: traefik
  namespace: traefik-ingress-controller
data:
  traefik.toml: |
    logLevel = "info"
    defaultEntryPoints = ["http", "https"]
    [entryPoints]
      [entryPoints.http]
      address = ":80"
      compress = true
      [entryPoints.https]
      address = ":443"
      compress = true
        [entryPoints.https.tls]
    [ping]
    entryPoint = "http"
    [kubernetes]
    [traefikLog]
      format = "json"

---
# Source: traefik/templates/rbac.yaml
kind: ServiceAccount
apiVersion: v1
metadata:
  name: traefik-ingress
  namespace: traefik-ingress-controller
---
# Source: traefik/templates/rbac.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: traefik-ingress
rules:
  - apiGroups:
      - ""
    resources:
      - pods
      - services
      - endpoints
      - secrets
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
    resources:
      - ingresses/status
    verbs:
      - update
---
# Source: traefik/templates/rbac.yaml
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: traefik-ingress
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: traefik-ingress
subjects:
- kind: ServiceAccount
  name: traefik-ingress
  namespace: traefik-ingress-controller
---
# Source: traefik/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: traefik-ingress
  labels:
    app: traefik
  namespace: traefik-ingress-controller
spec:
  replicas: 1
  selector:
    matchLabels:
      app: traefik
  template:
    metadata:
      labels:
        app: traefik
    spec:
      hostNetwork: true
      serviceAccountName: traefik-ingress
      terminationGracePeriodSeconds: 60
      containers:
      - image: traefik:1.7.20
        name: traefik-ingress
        readinessProbe:
          httpGet:
            path: /ping
            port: "http"
          failureThreshold: 1
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 2
        livenessProbe:
          httpGet:
            path: /ping
            port: "http"
          failureThreshold: 3
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 2
        volumeMounts:
        - mountPath: /config
          name: config
        ports:
        - name: http
          containerPort: 80
          protocol: TCP
        - name: https
          containerPort: 443
          protocol: TCP
        args:
        - --configfile=/config/traefik.toml

      volumes:
      - name: config
        configMap:
          name: traefik-ingress

2、文件 ingress-traefik.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: traefik-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  tls:
  - hosts:
    - shanhy-k8s.com
    - "*.shanhy-k8s.com"
    secretName: ingress-secret
  rules:
  - host: www.shanhy-k8s.com
    http:
      paths:
      - path: /
        backend:
          serviceName: helloworld-nodejs
          servicePort: 20001

3、https 证书的生成

# 生成证书key
openssl genrsa -out ingress-key.pem 2048 
# 生成证书
openssl req -new -x509 -key ingress-key.pem -out ingress.pem -subj /C=CN/ST=BeiJing/L=BeiJing/O=Shanhy/OU=Shanhy/CN=www.shanhy-k8s.com  -days 3650
# 查看证书信息
openssl x509 -in ingress.pem -text -noout

4、k8s 创建 secret

kubectl create secret tls ingress-secret --key cert/ingress-key.pem --cert cert/ingress.pem 

5、运行

kubectl apply -f traefik.yml
kubectl apply -f ingress-traefik.yaml
# 查看运行结果
[root@server1 k8s]# kubectl get svc
NAME                TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)     AGE
helloworld-nodejs   ClusterIP   10.96.0.246           20001/TCP   45h
kubernetes          ClusterIP   10.96.0.1             443/TCP     3d2h
[root@server1 k8s]# kubectl get ingress
NAME              HOSTS                ADDRESS   PORTS     AGE
traefik-ingress   www.shanhy-k8s.com             80, 443   108m
[root@server1 k8s]# kubectl get pod -A
NAMESPACE                    NAME                                 READY   STATUS    RESTARTS   AGE
default                      helloworld-nodejs-5dfb48565d-4snbs   1/1     Running   0          2d15h
default                      helloworld-nodejs-5dfb48565d-rxbcv   1/1     Running   0          2d15h
default                      helloworld-nodejs-5dfb48565d-tp2qw   1/1     Running   0          2d15h
traefik-ingress-controller   traefik-ingress-558868f4db-swkr6     1/1     Running   0          4h12m
[root@server1 k8s]# kubectl get secret
NAME                  TYPE                                  DATA   AGE
default-token-wlmkn   kubernetes.io/service-account-token   3      23h
ingress-secret        kubernetes.io/tls 

6、访问验证
在你电脑的C:\Windows\System32\drivers\etc\hosts中添加192.168.1.65 www.shanhy-k8s.com
然后打开浏览器访问 http(s)://www.shanhy-k8s.com 可以看到输出结果 HelloWorld。

本文实例还有一个小结论:ingressservicepodsecret 都必须要在同一个 namespace 中,对 ingress-controllernamespace 没有要求。


相关资料:
https://github.com/containous/traefik
https://traefik.cn/
https://docs.traefik.io/user-guides/crd-acme/


(END)

你可能感兴趣的:(Kubernetes)