پیاده سازی Load Balancer با استفاده از Traefik

در مطلب قبل با استفاده از Nginx یک Load-balancing انجام دادیم و به ساده ترین روش پیاده سازیش کردیم. حالا توی این پست از ابزار دیگه ای به اسم Traefik برای این کار استفاده می کنیم.

پیاده سازی Load Balancer با استفاده از Traefik

Traefik یک reverse proxy و load balancer مدرن و کامله که به توسعه میکروسرویس ها خیلی کمک میکنه. از ویژگی های خوبش اینه که با Endpoint های مختلف سازگاری خوبی داره و میشه همه جا ازش استفاده کرد. برای مثال یک سرویس عادی رو باهاش مسیردهی کنید یا اینکه توی Docker یا K8S ازش استفاده کنید.

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

نصب

ما میتونیم Traefik رو به صورت های گوناگونی نصب کنیم که در این مطلب با Docker این کارو انجام میدیم. برای اجرا نیاز به فایل stack زیر داریم :

version: "3"

services:
  traefik:
    image: traefik:v2.2.1
    command:
      - "--log=true"
      - "--log.level=WARNING"
      - "--api=true"
      - "--api.debug=true"
      - "--api.dashboard=true"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.swarmmode=true"
      - "--providers.docker.exposedbydefault=false"
      - "--providers.docker.endpoint=unix:///var/run/docker.sock"
      - "--providers.docker.watch=true"
      - "--providers.docker.network=traefik"
      - "--entryPoints.web.address=:80"
    ports:
      - 80:80
      - 8080:8080
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - traefik
    deploy:
      mode: global
      restart_policy:
        condition: on-failure
      update_config:
        parallelism: 1
        delay: 10s
      placement:
        constraints: [node.role == manager]

networks:
  traefik:
    external: true

کانفیگ های داکر که نیاز به توضیح نداره فقط مباحث مهم مربوط به Traefik رو شرح میدم.

  • log : فعالسازی لاگ ها به صورت stdout
  • log.level : مشخص کردن حساسیت لاگ ها. برای مثال فقط هشدار ها و خطاها نمایش داده بشه
  • api : فعال کردن Dashboard
  • providers.docker : فعال کردن پشتیبانی از Docker
  • providers.docker.exposedbydefault : شناسایی خودکار تمامی سرویس ها. اگه این مورد فعال باشه Traefik به طور خودکار تمام Container های شما رو در نظر میگیره
  • providers.docker.network : شبکه تعریف شده برای Traefik
  • entryPoints.web.address : تعریف نقطه ورود پیشفرض برای HTTP. هر پورتی که اینجا تعریف بشه باید Expose هم بشه توی کانتینر

توجه کنید که این تنظیمات ابتدایی بوده و برای محیط Production مناسب نیست. برای مثال HTTPS و Metric ها فعال نیستن و تنظیمات SSL نیز تعریف نشده و ...

از اونجایی که Stack ها و Container های مختلفی داریم که هرکدوم شبکه های جداگانه ای هم دارن ، برای استفاده از Traefik باید شبکه جدید و یکپارچه ای ایجاد کنید که بعدا بتونیم سرویس های خودمون رو به Traefik متصل کنیم. پس قبل از اعمال کردن فایل بالا ، دستور زیر رو اجرا کرده و شبکه External جدید برای این کار بسازید :

docker network create --driver=overlay --attachable --scope=swarm traefik

حالا میتونیم Traefik رو نصب کنیم :

docker stack deploy -c stack.yml Traefik

استفاده

برای اینکه مطمئن بشید Traefik به درستی نصب شده به آدرس زیر برید و Dashboard براتون میاد :

http://localhost:8080/dashboard/

حالا باید سرویس های خودمون رو اجرا کنیم. برای این پست دیگه از سرویس قبلی استفاده نمیکنم ( اون بیشتر جنبه آموزشی داشت ). اینجا از پروژه who am i استفاده می کنم. سرویس خیلی خوبیه و همیشه برای تست میتونید ازش استفاده کنید. روی پورت 80 اجرا میشه و صفحه ای با جزئیات خیلی خوب در اختیار شما میذاره

برای مثال از گزینه های Hostname و IP میتونید برای تشخیص کانتینر ها استفاده کنید.

برای این مطلب ، کلاستر Docker Swarm با 4 Node در اختیار داریم و میخوایم سرویسی از whoami با 4 Replica ایجاد کنیم. برای این کار فایل stack زیر رو نیاز دارید :

version: "3"

services:
  whoami:
    image: containous/whoami
    deploy:
      labels:
        - "traefik.enable=true"
        - "traefik.docker.network=traefik"
        - "traefik.http.routers.whoami.rule=Host(`whoami.cluster`)"
        - "traefik.http.routers.whoami.entrypoints=web"
        - "traefik.http.routers.whoami.service=whoami"
        - "traefik.http.services.whoami.loadbalancer.server.port=80"
      mode: replicated
      replicas: 4
    networks:
      - traefik

networks:
  traefik:
    external: true

اتصال کانتینتر/سرویس از طریق Label ها انجام میشه و با چند مورد ساده می تونیم این کارو انجام بدیم.

توجه کنید که اگه در محیط Swarm این کارو انجام میدید ، حتما باید در قسمت Deploy لیبل هاتون رو تعریف کنید

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

موارد مهمی که وجود داره :

  • traefik.http.routers.whoami : اول از همه یک مسیریاب برای این سرویس ایجاد میشه و از اسم whoami براش استفاده میکنیم. تمام تنظیمات باید با همین عبارت شروع بشه.

  • rule=Host('whoami.cluster') : یک قانون جدید برای این مسیریاب تعریف میکنیم. درواقع شرط شناسایی سرویس به این صورت تعریف میشه که اینجا میگیم. برای مثال من تعریف کردم که اگر دامنه ( هاست ) ورودی به صورت whoami.cluster بود یعنی باید از سرویس فعلی استفاده کنی

  • entrypoints=web : تعیین میکنم که از کدام نقطه ورودی استفاده بشه. موقع نصب داکر این مورد تعریف شده

  • service=whoami : نام سرویس رو تعیین میکنم. در اکثر موارد این مورد اختیاریه و به صورت خودکار شناسایی میشه. ولی در مواردی هم باید جداگانه تنظیم کنید تا با باقی موارد تداخل نداشته باشه. برای مثال در شرایط عادی ممکنه نام سرویس و نام کانتینتر متفاوت باشه.

  • loadbalancer.server.port=80 : پورت مربوطه برای عملیات load-balancing رو تعیین میکنیم. برای مثال در اینجا ایمیج whoami از پورت 80 استفاده میکنه.

حالا سرویس خودمون رو ایجاد میکنیم :

docker stack deploy -c stack.yml WhoAmI

پس از اینکه تمام Replica ها ساخته شد با مراجعه به آدرس whoami.cluster و Refresh کردن میتونید ببینید که هر سری Traefik شما رو به یکی از کانتینر ها منتقل میکنه.

تنظیم مجدد Traefik

حالا که یاد گرفتید چطوری یک سرویس رو به Traefik متصل میکنیم ، چرا خودش رو هم تنظیم نکنیم ؟ برای اینکه سرویس Traefik رو هم از طریق URL کانفیگ کنیم ، فایل Stack مربوطه رو اینطوری تغییر بدید :

version: "3"

services:
  traefik:
    image: traefik:v2.2.1
    command:
      - "--log=true"
      - "--log.level=WARNING"
      - "--api=true"
      - "--api.debug=true"
      - "--api.dashboard=true"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.swarmmode=true"
      - "--providers.docker.exposedbydefault=false"
      - "--providers.docker.endpoint=unix:///var/run/docker.sock"
      - "--providers.docker.watch=true"
      - "--providers.docker.network=traefik"
      - "--entryPoints.web.address=:80"
    ports:
      - 80:80
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - traefik
    deploy:
      labels:
        - "traefik.enable=true"
        - "traefik.docker.network=traefik"
        # Dashboard
        - "traefik.http.routers.traefik.rule=Host(`traefik.cluster`)"
        - "traefik.http.routers.traefik.service=api@internal"
        - "traefik.http.routers.traefik.entrypoints=web"
        - "traefik.http.services.traefik.loadbalancer.server.port=8080"
      mode: global
      restart_policy:
        condition: on-failure
      update_config:
        parallelism: 1
        delay: 10s
      placement:
        constraints: [node.role == manager]

networks:
  traefik:
    external: true

اینجا برای بخش سرویس کار کمی متفاوته. به جای اینکه از نام سرویس استفاده کنیم ، عبارت api@internal تنظیم میشه که یعنی از api داخلی استفاده بشه که معادل همون داشبورد هست. برای پورت هم از 8080 استفاده میکنیم چون داشبورد به صورت پیشفرض روی این پورت کار میکنه.

حالا می تونید با مراجعه به این آدرس به همان صفحه قبل برید :

http://traefik.cluster/dashboard


چندتا نکته رو در نظر بگیرید :

  • در این مطلب برای بهتر نشون دادن موضوع از Docker Swarm استفاده کردم. برای شرایط عادی تنظیمات مشابه با کمی تغییر نیازه.
  • اگه میخواید تو محیط عادی تست کنید ، از اونجایی که به دامنه نیاز دارید باید دامنه های خودتون رو از طریق DNS Server یا فایل hosts سیستم عامل تنظیم کنید.
  • نام router و service ها حتما باید یکتا باشه