k8s安装traefik ingress

kubernetes 集群外部如果想要访问集群内部,需要通过 NodePort 类型的 service。而 service 的三种调度模型都工作在四层,对于 https 这样的七层协议无从下手,证书、私钥啥的你根本无处配置。kubernetes 的解决方案是,加一个中间层。用户请求不会直接到达 service,而是会先到达一个 pod,而由于 pod 和 pod 之间处于同一个网络,所以这个 pod 直接对后端 pod 进行负载均衡,而不再经过 service。

但是 pod 如何接入外部流量?所以它的前面还需要 service,且必须是 NodePort 类型。而为了高可用,每个节点上都会启动这个端口,所以前端还需要一个负载均衡器,用于将请求调度到每个节点。但是这样调度 n 次性能损耗十分严重。前面提到过,pod 可以共享节点的网络名称空间,因此,pod 可以直接监听节点的端口,用于接收外部请求,然后负载均衡到后端 pod 之上。为了高可用,这个 pod 可以运行为 DaemonSet,且可以只运行在有限的节点上。

这个 pod 在 kubernetes 被称为 ingress controller。ingress 作为一个 pod,运行的容器可以是 nginx、traefik、envoy 等。但是 pod ip 和数量是随时变化的,nginx 这样的产品如何能够知道呢?这还得借助于 service,一个 nginx 中的 upstream 对应一个 service。而这个 service 并不进行负载均衡,还是用来筛选的,筛选出的 pod 会作为 nginx 的配置文件。但是 service 监控到的 pod 的变化如何反应到 nginx 呢?

这就需要 ingress 资源,kubernetes 存在一种 ingress 的资源,它不同于 ingress controller。ingress 资源可以获得 service 的结果,并且反应到 nginx 这样的负载均衡器的配置文件中,并且还能通知其进行重载配置文件。这就体现出 nginx 的局限性了,因为它配置文件一更改就得重载配置文件,所以这里我选择使用 traefik,它就是为 docker 而生。

我们的做法是,首先部署一个 ingress controller 类型的 pod,然后选择是通过基于不同的域名或者不同的 URL,关联到不同的 service。而后通过 ingress 来监控 service 的变化,最终形成相应的配置文件。

为了简单,我们会将 traefik 安装到 default 名称空间。

通过该系列的前面文章,相信你现在也有了泛域名证书,因此 traefik 会开启 https 支持。当然,你也可以选择 http,跟着往下走也不会有问题。

创建配置文件

如果不需要为 traefik 开启 https,这一节可以跳过。

由于我们要提供 https,因此 traefik 需要监听 443 端口,并且需要将我们的证书提供给它。这样一来,我们需要将 https 证书挂载进 traefik 容器中,并在配置文件中指定它的位置。

这里的解决方法是,将证书创建为 secret,挂载进容器中。同时创建 traefik 配置文件,在其中指定证书的位置、开启 443,并将对 80 端口的访问直接转发到 443,然后将该配置文件创建为 configMap,将其挂载到容器中。

首先创建 secret:

kubectl create secret tls ntpstat.com --cert=/etc/cert/ntpstat.com.crt --key=/etc/cert/ntpstat.com.key
复制代码

接着创建 traefik 配置文件:

mkdir -p /usr/local/kuberneters/manifests/trafik
cd /usr/local/kuberneters/manifests/trafik
vim traefik.toml
复制代码

以下是文件的内容:

defaultEntryPoints = ["http","https"]
[kubernetes]
[entryPoints]
  [entryPoints.http]
  address = ":80"
    [entryPoints.http.redirect]
      entryPoint = "https"
  [entryPoints.https]
  address = ":443"
    [entryPoints.https.tls]
      [[entryPoints.https.tls.certificates]]
      CertFile = "/ssl/tls.crt"
      KeyFile = "/ssl/tls.key"
复制代码

将其创建为 configMap:

kubectl create configmap traefik-config --from-file=traefik.toml
复制代码

创建 clusterRoleBinding

部署之前先创建 clusterRoleBinding,它的作用是将下面列出的权限授予给 traefik-ingress-controller 这个 ServiceAccount,然后 pod 就由这个用户启动。这样一来,pod 就拥有这些权限了。

# cd /usr/local/kuberneters/manifests/trafik
# vim clusterRoleBinding.yml
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: traefik-ingress-controller
rules:
  - apiGroups:
      - ""
    resources:
      - services
      - endpoints
      - secrets
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: traefik-ingress-controller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: traefik-ingress-controller
subjects:
  - kind: ServiceAccount
    name: traefik-ingress-controller
    namespace: default
复制代码

你如果觉得 ClusterRoleBinding 范围太广,也可以使用 RoleBinding,1.5 版本后,traefik 支持每个名称空间级 RoleBinding。因为我们都在 default 名称空间使用,其实可以使用 RoleBinding 的,这里就不纠结了。

kubectl apply -f clusterRoleBinding.yml
复制代码

部署 traefik

traefik 可以部署为 Deployment 和 DaemonSet 两种模式,如果使用官方提供的 deployment 的安装方式,traefik pod 的 80/443/8080 端口会通过 NodePort 的方式暴露出来,也就是说你无法通过节点的 ip + 80 端口进行访问,因此你前面还得给它加上一个负载均衡器,这种做法就有些反人类了,访问 traefik 这个负载均衡器还得在前面加上一个负载均衡器不是扯淡么。

而官方的 DaemonSet 就不存在这样的问题了,它使用的是 NET_BIND_SERVICE 这样一个 capabilities,意思是可以直接使用宿主机网络名称空间的端口。使用它之后,你在宿主机上看不到它监听了 80 端口,但是你却可以直接访问,而不是 Deployment 这样的 NodePort 方式。但是 DaemonSet 的缺点也很明显,你的 node 节点数量越多,就越消耗资源。

有没有两全其美的方法呢?那肯定是有的,无论你使用 Deployment 还是 DaemonSet,只要都使用 NET_BIND_SERVICE,然后定义好节点标签就能让 pod 只运行在特定的节点上,然后域名解析指向这些节点就行。

当然前提是这些节点的 80/443 都没有被占用。不过这里就不指定亲和性了,我会使用 Deployment + NET_BIND_SERVICE 进行部署,之所以不使用 DaemonSet,是因为官方的 DaemonSet 已经能够满足需求了。

在部署之前,我们先创建一个名为 nexus-pull 的 secret,这个用于 nexus pull 镜像时的认证。关于 nexus 的搭建,可以查看我的上一篇文章:

kubectl create secret docker-registry nexus-pull --docker-username=admin --docker-password="admin123" --docker-server="registry.ntpstat.com:2222"
复制代码

创建 deployment.yml:

# vim /usr/local/kuberneters/manifests/traefik/deployment.yml
---
# 创建一个 serviceaccount 用于启动 pod,并且拥有 clusterrole 的权限
apiVersion: v1
kind: ServiceAccount
metadata:
  name: traefik-ingress-controller
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: traefik-ingress-controller
  labels:
    k8s-app: traefik-ingress-lb
spec:
  # 两副本
  replicas: 2
  selector:
    matchLabels:
      k8s-app: traefik-ingress-lb
  template:
    metadata:
      labels:
        k8s-app: traefik-ingress-lb
        name: traefik-ingress-lb
    spec:
      serviceAccountName: traefik-ingress-controller
      terminationGracePeriodSeconds: 60
      # 证书和配置文件
      volumes:
        - name: ssl
          secret:
            secretName: ntpstat.com
        - name: conf
          configMap:
            name: traefik-config
      imagePullSecrets:
        - name: nexus-pull
      containers:
        - image: registry.ntpstat.com:2222/traefik
          name: traefik-ingress-lb
          volumeMounts:
            - mountPath: /ssl
              name: ssl
            - mountPath: /conf
              name: conf
          ports:
            - name: http
              containerPort: 80
              # 需要指定 hostPort
              hostPort: 80
            - name: https
              containerPort: 443
              hostPort: 443
            - name: admin
              containerPort: 8080
              hostPort: 8080
          securityContext:
            capabilities:
              drop:
                - ALL
              add:
                - NET_BIND_SERVICE
          args:
            - --api
            - --kubernetes
            - --logLevel=INFO
            # 指定配置文件位置
            - --configFile=/conf/traefik.toml
---
kind: Service
apiVersion: v1
metadata:
  name: traefik-ingress-service
spec:
  selector:
    k8s-app: traefik-ingress-lb
  ports:
    - protocol: TCP
      port: 80
      name: web
    - protocol: TCP
      port: 8080
      name: admin
    - protocol: TCP
      port: 443
      name: https
复制代码

部署:

# kubectl apply -f deployment.yml
serviceaccount/traefik-ingress-controller created
deployment.extensions/traefik-ingress-controller created
service/traefik-ingress-service created
复制代码

查看 pod 是否运行:

kubectl get pod -o wide
复制代码

运行 ok 之后,你可以直接使用 curl 来访问节点的 ip:

# curl NODE_IP
Found
复制代码

出现 Found 表示部署成功了。

验证 traefik

如果你觉得使用 curl 命令不够直观的话,你还可以通过部署 traefik ui 来验证 traefik 已经部署成功。traefik ui 是 traefik 内部的功能,我们现在只需要添加规则开启它而已。

我们准备通过主机名的方式来访问它,所以我们接下来做的就是定义基于域名的虚拟主机。

# vim ui.yml
---
apiVersion: v1
kind: Service
metadata:
  name: traefik-web-ui
spec:
  selector:
    k8s-app: traefik-ingress-lb
  ports:
    - name: web
      port: 80
      targetPort: 8080
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: traefik-web-ui
spec:
  rules:
    - host: traefik.ntpstat.com
      http:
        paths:
          - path: /
            backend:
              serviceName: traefik-web-ui
              servicePort: web
  tls:
    - hosts:
        - traefik.ntpstat.com
      secretName: ntpstat.com
复制代码

然后你可以在添加 hosts 之后在浏览器上直接访问 traefik.ntpstat.com 就可以看到它的 web 界面了,并且会自动跳转到 https。

你可能感兴趣的:(ui,开发工具,后端)