در آموزش قبلی یاد گرفتیم که چطور یک کلاستر K8S درست کنیم. این کلاستر میتونه ترکیبی از ماشین های مجازی ، سرور های فیزیکی یا حتی یک شبیه سازی با minikube باشه. حالا که کلاستر ما آماده است ، قبل از استقرار سرویس هامون نیازه تا مواردی رو برای بهبود کار با کلاستر پیاده سازی کنیم

درگیری ها با دنیای خارج

به صورت پیش فرض ، کوبرنتیز شبکه بسته ای رو برای شما تشکیل میده که تا وقتی درون اون باشید هیچ مشکلی وجود نداره. با راه های مختلف هم میتونید به منابع دسترسی داشته باشید و هرکار خواستید انجام بدید. ولی وقتی صحبت از دسترسی های خارج از کلاستر میشه ، بحث فرق داره. اینجا با دو مبحث Ingress و Egress برخورد می کنیم :

  • Ingress : انتقال ترافیک اینترنت به کوبرنتیز
  • Egress : فرستادن ترافیک به اینترنت

انتقال ترافیک به داخل کلاستر عمل پیچیده ای محسوب میشه و بسته به مدل شبکه ای که پیاده سازی کردید از دو طریق Load Balancer و Ingress Controller انجام میشه.

در حال حاضر Ingress Controller های زیادی برای کوبرنتیز وجود داره که در این جدول میتونید معروف ترین ها رو مشاهده کرده و باهم مقایسه کنید :

Kubernetes Ingress controllers comparison (upd′2020)
Sheet1 <a href=“https://medium.com/flant-com/comparing-ingress-controllers-for-kubernetes-9b397483b46b”>full article</a>,Kubernetes Ingress,NGINX Ingress,Kong Ingress,Traefik,HAproxy,Voyager,Contour,Istio Ingress,Ambassador,Gloo,Skipper Protocols,http/https, http2, grpc, tcp/udp (partial),http/h...

در این مطلب کار با Traefik رو بهتون آموزش میدم. در خیلی موارد اگر از کسی در مورد Reverse Proxy , Load Balancer و Ingress Controller بپرسید اولین چیزی که به شما معرفی میکنه Nginx هست. ابزار خوب و قدرتمند که خودش هم اثبات کرده. ولی وقتشه کمی این انحصار رو کنار بذاریم و ابزار های دیگه هم آزمایش کنیم.

دقیقا Traefik چی میکنه ؟

یکی از مواردی که traefik رو برام به یک ابزار همیشگی تبدیل کرده ، سادگی در استفاده است. برعکس باقی کتابخانه های این حوزه که به ازای هر سرویس باید تنظیمات جدیدی اعمال کنید تا عملیات مورد نظر مثل Proxy یا Load-Balancing انجام بشه ، اینجا نیاز به چنین کاری نیست. شما یک بار Traefik رو اجرا می کنید و هنگام استقرار سرویس ها تنظیمات مربوطه رو همونجا اعمال می کنید. اگر با Docker سر و کار داشته باشید از Label و در K8S هم از annotation ها استفاده می کنیم.

اگر پیاده سازی Ingress با کتابخانه های دیگه رو تجربه کرده باشید میدونید که ما همیشه به یک Ingress Route نیاز داریم. حالا Traefik کار رو بازهم برای ما ساده تر کرده و از نسخه 2.2 به بعد فقط کافیه از یک annotation ساده استفاده کرد.

در ادامه بیشتر با روند کارش آشنا میشید

نصب Traefik

آموزش های زیادی برای نصب Traefik وجود داره. برای مثال شما میتونید خیلی راحت از Helm استفاده کنید ( روشی که خود Traefik هم تو مستنداتش ذکر کرده ). یا اینکه خودتون همه چیز رو مدیریت کنید. به علت اینکه ساختار این پیاده سازی واضح تر باشه با روش دوم ادامه میدیم و همه چیز رو خودمون مستقر می کنیم.

CRD / Roles

در اولین مرحله لازمه تا یکسری CRD برای مواردی مانند سرویس ها ، مسیر های TCP ، TLS و ... داشته باشیم. همچنین یک ClusterRole با سطوح دسترسی مختلف تعریف می کنیم. برای تمام این مباحث فایلی با نام rbac.yml و محتوای زیر آماده کنید :

---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: ingressroutes.traefik.containo.us

spec:
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: IngressRoute
    plural: ingressroutes
    singular: ingressroute
  scope: Namespaced

---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: ingressroutetcps.traefik.containo.us

spec:
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: IngressRouteTCP
    plural: ingressroutetcps
    singular: ingressroutetcp
  scope: Namespaced

---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: middlewares.traefik.containo.us

spec:
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: Middleware
    plural: middlewares
    singular: middleware
  scope: Namespaced

---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: tlsoptions.traefik.containo.us

spec:
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: TLSOption
    plural: tlsoptions
    singular: tlsoption
  scope: Namespaced

---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: traefikservices.traefik.containo.us

spec:
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: TraefikService
    plural: traefikservices
    singular: traefikservice
  scope: Namespaced


---
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
  - apiGroups:
      - extensions
    resources:
      - ingresses/status
    verbs:
      - update
  - apiGroups:
      - traefik.containo.us
    resources:
      - middlewares
      - ingressroutes
      - traefikservices
      - ingressroutetcps
      - ingressrouteudps
      - tlsoptions
      - tlsstores
    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
    namespace: kube-system

این فایل را با استفاده از دستور زیر ، اعمال کنید :

kubectl create -f rbac.yml

Deployment

در ادامه لازمه تا Pod اصلی مربوط به Traefik را آماده کنیم. این کار از طریق یک Deployment انجام میشه. فایلی با نام deployment.yml و محتوای زیر آماده کنید :

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: traefik
    release: traefik
  name: traefik
  namespace: kube-system

spec:
  replicas: 1
  selector:
    matchLabels:
      app: traefik
      release: traefik
  template:
    metadata:
      labels:
        app: traefik
        release: traefik
    spec:
      containers:
      - args:
        - --api
        - --api.insecure
        - --api.dashboard=true
        - --accesslog
        - --global.checknewversion=true
        - --entryPoints.traefik.address=:8100
        - --entryPoints.web.address=:80
        - --entryPoints.websecure.address=:443
        - --ping=true
        - --providers.kubernetescrd=true
        - --providers.kubernetesingress=true
        - --log.level=INFO
        - --serversTransport.insecureSkipVerify=true
        image: traefik:2.2.5
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /ping
            port: 8100
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 2
        name: traefik
        ports:
        - containerPort: 8100
          name: admin
          protocol: TCP
        - containerPort: 80
          name: web
          protocol: TCP
        - containerPort: 443
          name: websecure
          protocol: TCP
        readinessProbe:
          failureThreshold: 1
          httpGet:
            path: /ping
            port: 8100
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 2
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      serviceAccount: traefik
      serviceAccountName: traefik
      terminationGracePeriodSeconds: 60

اینجا موارد مهمی هست که باید بهش توجه داشته باشید.

  • تمامی موارد در فضانام kube-system اعمال میشه
  • برای استفاده از قابلیت جدید نسخه 2.2 که در بالا توضیح دادم ، گزینه های providers.kubernetescrd و providers.kubernetesingress باید فعال شوند
  • پورت 8100 را برای مواردی مانند API, Dashboard و HealthCheck تنظیم می کنیم

این فایل را با استفاده از دستور زیر ، اعمال کرده و صبر کنید تا Pod مربوطه ساخته شود :

kubectl create -f deployment.yml

Service

حالا برای دسترسی به Entrypoint ها ، داشبورد و موارد دیگه باید سرویسی برای Traefik تعریف کنیم. فایلی با نام service.yml و محتوای زیر آماده کنید :

# ServiceAccount
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: traefik
  namespace: kube-system

# Service
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: traefik
    release: traefik
  name: traefik
  namespace: kube-system
spec:
  externalIPs:
  - '<Cluster-IP>'
  externalTrafficPolicy: Cluster
  ports:
  - name: web
    nodePort: 31909
    port: 80
    protocol: TCP
    targetPort: 80
  - name: websecure
    nodePort: 30584
    port: 443
    protocol: TCP
    targetPort: 443
  - name: admin
    nodePort: 32316
    port: 8100
    protocol: TCP
    targetPort: 8100
  selector:
    app: traefik
    release: traefik
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer: {}

به این موارد توجه کنید :

  • در قسمت <Cluster-IP> حتما آدرس آی پی کلاستر خودتون رو وارد کنید ( آدرس Manager/Master Node )
  • به صورت پیش فرض تمامی پورت ها به صورت NodePort تنظیم شدن. این مورد برای محیط توسعه است و میتونید چنین روشی رو انجام ندید
  • این سرویس به عنوان LoadBalander عمل می کنه

سرویس مورد نظر هم با استفاده از دستور زیر اعمل کنید :

kubectl create -f service.yml

دسترسی به داشبورد

حالا که همه چیز آماده است ، راه های مختلفی برای دسترسی به داشبورد اصلی Traefik و مشاهده وضعیت سیستم وجود داره. برای مثال میتونید از پورت تعریف شده در قسمت قبل استفاده کنیم. در این فایل پورت 32316 با نام admin مخصوص دسترسی به داشبورد قرار داده شده است که در این صورت با این آدرس میشه به داشبورد دسترسی داشت :

http://<Cluster-IP>:32316/dashboard

اما حالا که Traefik داریم استفاده از چنین روشی منطقی نیست. ما تمام این کار ها رو کردیم تا دسترسی به درون کوبرنتیز ساده تر باشه و از طریق یک دامنه همه چیز انجام بشه. پس به عنوان اولین سرویس ، از Traefik برای دسترسی به داشبورد خودش استفاده می کنیم.

تنظیم سرویس ها

برای اینکه دامنه های خودمون رو به سرویس مربوطه متصل کنیم فقط کافیه یک Ingress ساده و مختصر تعریف کنیم. برای مثال چنین فایلی رو در نظر بگیرید :

---
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
  name: traefik
  namespace: kube-system
  annotations:
    traefik.ingress.kubernetes.io/router.entrypoints: web, websecure
spec:
  rules:
  - host: traefik.k8s
    http:
      paths:
      - path: /
        backend:
          serviceName: traefik
          servicePort: 8100

در اینجا همانطور که قبلا هم گفته بودم ، بحث معرفی سرویس به Traefik از طریق یک annotation ساده انجام میشه :

annotations:
    traefik.ingress.kubernetes.io/router.entrypoints: web, websecure

اینجاست که نقاط ورودی رو مشخص می کنیم و Traefik به صورت خودکار سرویس رو شناسایی می کنه. در ادامه مسلما نیاز به تعریف دامنه خودمون داریم که این کار در قسمت host انجام میشه. اینجا من از دامنه traefik.k8s استفاده کردم.

در ادامه و قسمت backend باید نام و پورت سرویس وارد بشه که ما در اینجا از مقادیر traefik و 8100 استفاده می کنیم.

با اعمال چنین فایلی خیلی راحت اولین سرویس خودمون رو به Traefik معرفی می کنیم که درواقع داشبورد خودشه.

با مراجعه به آدرس http://traefik.k8s/dashboard داشبورد ما آماده است و اگر به انتهای صفحه مراجعه کنید Provider های مربوطه رو میبینید :

در قسمت سرویس ها هم میتونید مشاهده کنید که سرویس ما به درستی شناسایی شده

حالا دیگه همه چیز آماده است و به راحتی میتونید از Traefik برای سرویس های بعدی خودتون استفاده کنید. با مراجعه به پست بعدی ، یاد میگیرید که چطوری یک سرویس آزمایشی برای اولین بار در Kubernetes مستقر کنید. البته از روشی که همینجا توضیح داده شد استفاده میشه ولی مباحث Load-Balancing و ترکیب با Replication هم مورد آزمایش قرار داده میشه :

استقرار اولین سرویس در Kubernetes
در این پست توضیح ساده و ابتدایی در مورد استقرار یک پروژه اولیه در کلاستر Kubernetes داده شده که اگر در حال یادگیری چنین مباحثی هستید ، میتونه برای شما نقطه شروع خوبی باشه.

hatamiarash7/Kubernetes-Traefik
Deploy Traefik 2 in Kubernetes cluster - Ingress controller - hatamiarash7/Kubernetes-Traefik