میرور ستون؛ راهکار کمکی برای دریافت ایمیج از رجیستری‌های پابلیک در کوبرنتیز ستون

می‌دانیم برای دریافت Image‌ها در کوبرنتیز از راهکارهای کمکی مختلفی مانند Container Registry Mirror و Proxy استفاده می‌شود. در صورت نیاز به تغییر این تنظیمات در ماشین‌های کارگر (Worker) در نودپول‌های فعلی، بدون تاثیر پذیرفتن پادهای در حال اجرا، برای کوبرنتیز نسخه‌ی ۱.۲۴ و نسخه‌های به‌روزتر، امکان انجام وجود دارد که در این مستند روش انجام آن بیان می‌شود.

به دلایل امنیتی، IP های ماشین‌های Worker، تنها از داخل Subnet مربوط به کلاستر قابل دسترسی است. در نتیجه برای اتصال ssh به ماشین‌های کارگر (Worker Node) و تغییر پیکربندی containerd نیاز داریم یک ماشین کامپیوت دارای ExternalIP در داخل آن Subnet بسازیم. معمولا از این ماشین با نام Bastion یاد می‌شود. این ماشین نیاز به ریسورس زیادی ندارد و با حداقل ریسورس (مثلا از نوع b2) قابل استفاده است.

نکات مهم

  • سابنت مربوط به کلاستر کوبرنتیز، در صفحه‌ی مشخصات کلاستر در پنل قابل مشاهده است.
  • برای دریافت IP ماشین‌های کارگر (worker) مورد نظر می‌توانید از دستور kubectl get nodes -owide استفاده نمایید.

تغییر تنظیمات میرور در کوبرنتیز ستون

برای راحتی کار می‌توانید از Ansible مشابه نمونه‌ای که در انتهای این مستند آمده است، استفاده کنید. این انسیبل، در صورتی که آن را در فایلی با نام playbook.yml ذخیره کرده باشید؛ با دستوری مشابه زیر قابل اجرا است.

ansible-playbook playbook.yml --inventory "WORKER_IP_2,WORKER_IP_1" --extra-vars="mirror_url=MY_MIRROR_URL_1 default_mirror_url=MY_MIRROR_URL_2" -u cluster-admin --ssh-common-args='-o ProxyJump="BASTION_USERNAME@BASTION_IP"'

نکات

  • در پارامتر inventory، لیست IP ماشین‌های کارگری که می‌خواهید تنظیمات روی آن اعمال شود را وارد نمایید.
  • در پارامتر mirror_url و default_mirror_url آدرس میرور مورد نظرتان را وارد نمایید.
  • در پارامتر ProxyJump نیاز است username و IP ماشین Bastion خود را وارد نمایید.

یک مثال از دستور مشابه با مقادیر وارد شده:

ansible-playbook playbook.yml --inventory "10.0.0.210,10.0.0.89" --extra-vars="mirror_url=https://mirror.registry.platform.ske.sotoon.ir default_mirror_url=https://mirror.registry.platform.ske.sotoon.ir" -u cluster-admin --ssh-common-args='-o ProxyJump="compute@87.247.184.136"'

محتوای فایل playbook.yml می‌تواند مطابق مثال زیر باشد. در این playbook، آدرس دو Mirror یکی برای رجیستری‌های عمومی (Public Registry) پراستفاده و یکی به عنوان میرور پیش‌فرض (Default Mirror) تنظیم می‌شود. میرور کمکی ستون با آدرس https://mirror.registry.platform.ske.sotoon.ir نیز برای رجیستری‌های معروف مشخص شده در کد تنظیم می‌شود.

توجه

۱. در حال حاضر راهکار میرور ستون تنها برای رجیستری‌های معروف زیر قابل استفاده است و تضمینی برای پشتیبانی رجیستری‌های دیگر نمی‌دهد.

  • docker.io
  • ghcr.io
  • gcr.io
  • quay.io
  • registry.k8s.io

۲. راهکار میرور ستون، تنها امکان دریافت ایمیج‌های عمومی (Public Images) را از طریق رجیستری‌های عمومی (Public Registries) می‌دهد و در صورت تنظیم کردن Authentication روی یک ایمیج در رجیستری عمومی، امکان دریافت آن از طریق میرور ستون وجود ندارد. مثلا اگر ایمیج اپلیکیشن خود را روی ghcr.io قرار داده‌اید (Push) و روی آن Authentication تنظیم کرده‌اید، میرور ستون آن را پشتیبانی نمی‌کند. برای حل این مساله می‌توانید از رجیستری‌های تحریم‌نشده استفاده کنید که نیازمند میرور نباشند یا ایمیج مورد نظر را با در نظر گرفتن موارد امنیتی عمومی کنید.

۳. راهکار کمکی دریافت ایمیج از رجیستری‌های عمومی (Public Registry) به عنوان یک محصول کمکی رایگان (Best Effort)، تنها در سرویس کوبرنتیز ستون، ارائه می‌شود و تضمین عملکردی (SLA) روی آن قابل تعریف نیست چرا که مساله‌ی نوع و پروتکل‌های انواع محدودیت‌ها و تحریم‌هایی که از سوی رجیستری‌های عمومی روی IPهای ایران اعمال می‌شود، قابل کنترل نیست.

نکته

محیط اجرایی Containerd به ازای هر رجیستری عمومی یا اصطلاحا Namespace، می‌تواند از لیستی از Mirror ها استفاده کند. در نتیجه می‌توانید برای هر namespace چندین میرور متفاوت تنظیم نمایید تا در صورت بروز مشکل در یکی، همچنان کلاستر در دریافت ایمیج‌ها دچار مشکل نشود. مثلا برای docker.io می‌توانید در کنار میرور ستون، میرورهای مد نظر خود را نیز اضافه کنید.

# contents of playbook.yml file
- hosts: all
  tasks:
    - name: Check the containerd configuration. If there are already mirror configurations, do NOT proceed with the playbook
      command: crictl info
      register: crictl_output
      changed_when: false
      failed_when: "'mirrors' in crictl_output.stdout"
 
    - name: Check for the existence of the /etc/containerd/certs.d directory
      stat:
        path: /etc/containerd/certs.d
      register: certs_d_dir
 
    - name: Check for the registry.mirrors phrase in /etc/containerd/config.toml
      slurp:
        src: /etc/containerd/config.toml
      register: config_toml
 
    - name: Fail if /etc/containerd/certs.d exists or registry.mirrors is found, the playbook considers both are not set before.
      fail:
        msg: "Either /etc/containerd/certs.d exists or 'registry.mirrors' is present in /etc/containerd/config.toml."
      when: certs_d_dir.stat.exists or ('registry.mirrors' in config_toml.content | b64decode)
 
    - name: Set containerd daemon configuration for mirrors
      blockinfile:
        path: /etc/containerd/config.toml
        create: yes
        block: |
          #StartSKEMirrorConfig
          [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
            endpoint = ["{{ mirror_url }}", "https://mirror.registry.platform.ske.sotoon.ir"]
          [plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"]
            endpoint = ["{{ mirror_url }}", "https://mirror.registry.platform.ske.sotoon.ir"]
          [plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
            endpoint = ["{{ mirror_url }}", "https://mirror.registry.platform.ske.sotoon.ir"]
          [plugins."io.containerd.grpc.v1.cri".registry.mirrors."ghcr.io"]
            endpoint = ["{{ mirror_url }}", "https://mirror.registry.platform.ske.sotoon.ir"]
          [plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"]
            endpoint = ["{{ mirror_url }}", "https://mirror.registry.platform.ske.sotoon.ir"]
          [plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.io"]
            endpoint = ["{{ mirror_url }}", "https://mirror.registry.platform.ske.sotoon.ir"]
          [plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.k8s.io"]
            endpoint = ["{{ mirror_url }}", "https://mirror.registry.platform.ske.sotoon.ir"]
          # Note: Containerd does NOT fallback to the default mirror for namespaces defined like above.
          [plugins."io.containerd.grpc.v1.cri".registry.mirrors."*"]
            endpoint = ["{{ default_mirror_url }}"]
          #EndSKEMirrorConfig
      become: yes
 
    - name: Restart containerd on node
      systemd:
        name: containerd
        state: restarted
        daemon_reload: true
      become: yes

دو کامنت #StartSKEMirrorConfig و #EndSKEMirrorConfig برای سهولت تغییر این تنظیمات توسط پشتیبانی ستون به درخواست کاربر است، توصیه می‌شود آن را حذف نکنید.