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,且能夠只運行在有限的節點上。node

這個 pod 在 kubernetes 被稱爲 ingress controller。ingress 做爲一個 pod,運行的容器能夠是 nginx、traefik、envoy 等。可是 pod ip 和數量是隨時變化的,nginx 這樣的產品如何可以知道呢?這還得藉助於 service,一個 nginx 中的 upstream 對應一個 service。而這個 service 並不進行負載均衡,仍是用來篩選的,篩選出的 pod 會做爲 nginx 的配置文件。可是 service 監控到的 pod 的變化如何反應到 nginx 呢?nginx

這就須要 ingress 資源,kubernetes 存在一種 ingress 的資源,它不一樣於 ingress controller。ingress 資源能夠得到 service 的結果,而且反應到 nginx 這樣的負載均衡器的配置文件中,而且還能通知其進行重載配置文件。這就體現出 nginx 的侷限性了,由於它配置文件一更改就得重載配置文件,因此這裏我選擇使用 traefik,它就是爲 docker 而生。web

咱們的作法是,首先部署一個 ingress controller 類型的 pod,而後選擇是經過基於不一樣的域名或者不一樣的 URL,關聯到不一樣的 service。然後經過 ingress 來監控 service 的變化,最終造成相應的配置文件。docker

爲了簡單,咱們會將 traefik 安裝到 default 名稱空間。vim

經過該系列的前面文章,相信你如今也有了泛域名證書,所以 traefik 會開啓 https 支持。固然,你也能夠選擇 http,跟着往下走也不會有問題。後端

建立配置文件

若是不須要爲 traefik 開啓 https,這一節能夠跳過。api

因爲咱們要提供 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。

相關文章
相關標籤/搜索