Kubit logoکوبیت

مهاجرت Pack بین نسخه‌های چارت هلم

مهاجرت Pack یا Pack Migration به نویسندهٔ چارت اجازه می‌دهد مانیفست پک‌های موجود را هنگام تغییر ساختار values، vars یا نسخهٔ چارت تبدیل کند. با این قابلیت، انتخاب‌های کاربر در ارتقا حفظ می‌شوند و لازم نیست مانیفست هر Pack دستی بازنویسی شود.

این صفحه مرجع ساخت و آزمون pack-migrations.yaml است. برای آشنایی با سایر فایل‌ها و قابلیت‌های اختصاصی چارت، قابلیت‌های Pack در چارت هلم را بخوانید.

تعریف مهاجرت با pack-migrations.yaml

فایل pack-migrations.yaml تبدیل مانیفست Pack را هنگام تغییر ساختار values، vars یا نسخهٔ چارت تعریف می‌کند. این فایل باید با همین نام در ریشهٔ چارت و کنار Chart.yaml قرار بگیرد.

Pack Operator فایل migration را از چارت مقصد می‌خواند. بنابراین هر نسخهٔ منتشرشده باید زنجیرهٔ کامل migration از همهٔ نسخه‌های قدیمی پشتیبانی‌شده تا نسخهٔ مقصد را در خود داشته باشد. کاربری که چند نسخه را رد کرده است نباید مجبور شود چارت‌های میانی را جداگانه نصب کند.

migrations:
  - repo: kubit-paas
    chart: redis
    from_version: '>=0.1.0, <0.2.0'
    to_version: '~=0.2.0'
    context:
      metrics_default: true
    steps:
      - set:
          values: !var pack.spec.values
          values.metrics.enabled: !default-var metrics_default

      - if: values.password
        set:
          values.auth.password: !pop values.password

      - reorder:
          values:
            - auth
            - metrics
فیلدالزامیکاربرد
repoبلهنام منبع repository در spec.chart.repository.name
chartبلهنام چارت در spec.chart.name
from_versionبلهنسخه یا محدودیت نسخهٔ مبدأ
to_versionبلهمحدودیت نسخه‌ای که روی مانیفست نتیجه نوشته می‌شود
stepsبلهفهرست مرتب‌شدهٔ تبدیل‌ها؛ در صورت نبود تبدیل، فهرست خالی
contextخیرمتغیرهای موقت اولیه برای stepها و عبارت‌های Jinja

مقدار repo نام منبع repository است، نه URL آن. تطبیق repo و chart دقیق است و wildcard ندارد. اگر مانیفست Pack فیلد spec.chart.version نداشته باشد، هیچ migration با آن منطبق نمی‌شود.

انتخاب و زنجیره‌کردن نسخه‌ها

from_version از مقایسه‌های semantic version پشتیبانی می‌کند:

نمونهنسخه‌های منطبق
‎'<2.0.0'‎نسخه‌های کوچک‌تر از 2.0.0
‎'>=2.0.0, <2.3.0'‎نسخه‌های 2.0.0 تا قبل از 2.3.0
‎'~=2.3.0'‎نسخه‌های 2.3.x؛ از 2.3.0 تا قبل از 2.4.0
‎'<v1.19.4'‎نسخه‌های کوچک‌تر از 1.19.4 با پیشوند v

عبارت نسخه را داخل کوتیشن بنویسید، به‌ویژه وقتی با ‎<‎ یا ‎>‎ شروع می‌شود. چند شرط جداشده با ویرگول هم‌زمان اعمال می‌شوند.

پیش از اجرای هر migration، اپراتور spec.chart.version را برابر to_version می‌کند. سپس migrationهای بعدی با نسخهٔ تازه بررسی می‌شوند؛ در نتیجه چند entry می‌توانند یک زنجیرهٔ ارتقا بسازند. برای نمونه:

migrations:
  - repo: kubit-paas
    chart: redis
    from_version: '<0.3.0'
    to_version: '~=0.3.0'
    steps: []

  - repo: kubit-paas
    chart: redis
    from_version: '>=0.3.0, <0.5.0'
    to_version: '~=0.5.0'
    steps: []

در این نمونه، Pack نسخهٔ 0.2.0 ابتدا به شاخهٔ 0.3 و سپس به شاخهٔ 0.5 می‌رسد. to_version یک entry نباید دوباره با from_version همان entry منطبق شود؛ وگرنه ممکن است در اجرای بعدی دوباره اعمال شود.

ترتیب ظاهری entryها در فایل معیار قطعی اجرا نیست. اپراتور آن‌ها را بر اساس نام repository، نام چارت و شکل پاک‌سازی‌شدهٔ from_version مرتب می‌کند. در زنجیره‌هایی مانند 1.9 و 1.10، ترتیب مؤثر را با اجرای واقعی migration بررسی کنید.

مسیرها و context مهاجرت

مسیرها با نقطه از هم جدا می‌شوند؛ برای نمونه pack.spec.values.service.port. context هر entry مستقل است و این مقدارها را دارد:

ناممقدار
packمانیفست کامل و قابل تغییر Pack
trueمقدار boolean برابر true
falseمقدار boolean برابر false
nullمقدار تهی
کلیدهای contextمتغیرهای موقت تعریف‌شده در همان entry

برای ساده‌کردن مسیرهای طولانی، در ابتدای migration alias بسازید:

- set:
    chart: !var pack.spec.chart
    values: !var pack.spec.values
    chart.autoUpgrade: !default-var true

Mapping یا list خوانده‌شده با ‎!var‎ به همان دادهٔ اصلی اشاره می‌کند؛ بنابراین تغییر values.service.port در نمونهٔ بالا داخل pack.spec.values باقی می‌ماند. متغیر موقت سطح اول مانند old_port در خروجی Pack نوشته نمی‌شود و میان entryها نیز باقی نمی‌ماند.

خواندن مسیر ناموجود مقدار تهی برمی‌گرداند. نوشتن یک مسیر، mappingهای میانی ناموجود را می‌سازد؛ اما نوشتن مقدار تهی نادیده گرفته می‌شود.

اگر کلید mapping نقطهٔ واقعی دارد، نقطه را با ‎\.‎ escape و کل مسیر را با کوتیشن تکی بنویسید:

- set:
    copied: !var 'values.annotations.example\.com/key'
    'values.annotations.example\.com/key': enabled

بخش عددی مسیر، index یک list نیست. برای خواندن یا تغییر عضو list از item_in_list استفاده کنید.

عملیات migration

هر عضو steps یک step است. در یک step، عملیات همیشه با ترتیب زیر اجرا می‌شوند؛ حتی اگر ترتیب کلیدها در YAML متفاوت باشد:

  1. شرط if یا شاخهٔ else
  2. یافتن عضو با item_in_list
  3. مقداردهی با set
  4. اجرای steps تو در تو
  5. مرتب‌سازی با reorder

برای خوانایی، هر step را کوچک نگه دارید. ترکیب چند عملیات زمانی مفید است که به همین ترتیب ثابت نیاز داشته باشند؛ برای نمونه ابتدا عضو list پیدا شود و سپس set آن را تغییر دهد.

tagهای set

tagرفتار
‎!default‎فقط در صورت نبودن کلید مقصد، مقدار ثابت را می‌نویسد
‎!default-var‎فقط در صورت نبودن مقصد، مقدار یک مسیر از context را می‌نویسد
‎!var‎مقدار یک مسیر از context را بدون حذف منبع می‌خواند
‎!pop‎مقدار مسیر مبدأ را حذف و به مقصد منتقل می‌کند
‎!pop-empty‎فقط مبدأ falsey را حذف می‌کند و برای پاک‌سازی mappingهای خالی مناسب است
‎!merge‎mapping منبع را به‌صورت بازگشتی با mapping مقصد ادغام می‌کند
‎!jinja‎مقدار را با context migration رندر می‌کند و نوع بومی را نگه می‌دارد

مقدار بدون tag مقصد را بازنویسی می‌کند. برای حفظ انتخاب کاربر، کلید قدیمی را با ‎!pop‎ بخوانید و مقصد را با ‎!default-var‎ مقدار دهید. از ‎!default‎ برای پیش‌فرض تازه‌ای استفاده کنید که نباید مقدار موجود را بازنویسی کند؛ حتی اگر مقدار موجود false، صفر یا تهی باشد.

‎!pop-empty‎ ابزار انتقال داده نیست. این tag فقط مقدار falsey مانند mapping یا list خالی را حذف می‌کند و وقتی چیزی حذف نشود، مقدار false در مقصد می‌گذارد. آن را با نام موقت استفاده و پاک‌سازی را از عمیق‌ترین مسیر به والدها انجام دهید:

- set:
    _: !pop values.deprecatedOption
    _1: !pop-empty values.legacy.child
    _2: !pop-empty values.legacy

برای ‎!merge‎، منبع و مقصد باید mapping باشند. اگر ممکن است مقصد وجود نداشته باشد، ابتدا آن را با ‎!default‎ بسازید.

‎!jinja‎ می‌تواند boolean، عدد، list یا mapping تولید کند. برای مسیر اختیاری از filter default یا شکل کوتاه آن، d، استفاده کنید؛ دسترسی مستقیم به متغیر تعریف‌نشده migration را با خطا متوقف می‌کند.

شرط‌ها و stepهای تو در تو

شرط ساده، مقدار یک مسیر را به boolean تبدیل می‌کند. ‎!not‎ نتیجهٔ مسیر را معکوس می‌کند و ‎!jinja‎ برای مقایسه یا شرط ترکیبی است:

- if: values.ingress.enabled
  set:
    values.ingress.className: !default nginx

- if: !not values.persistence.enabled
  set:
    _: !pop values.persistence

- if: !jinja '{{ values.mode | d("standard") == "legacy" }}'
  steps:
    - set:
        values.mode: standard
  else:
    - set:
        values.mode: !default standard

else باید کنار if باشد و فهرستی از stepها بگیرد. وقتی شرط برقرار نباشد، فقط stepهای else اجرا می‌شوند و سایر عملیات همان step بیرونی نادیده گرفته می‌شوند.

تغییر اعضای list با item_in_list

item_in_list یک mapping را در list با key و value یا با index پیدا می‌کند. عضو پیدا‌شده یا ساخته‌شده در متغیر موقت var قرار می‌گیرد:

- set:
    values.service.ports: !default []

- item_in_list:
    list: values.service.ports
    key: name
    value: http
    create: true
    var: http_port
  set:
    http_port.port: !default 6379
    http_port.protocol: !default TCP

پیش از item_in_list خود list را با ‎!default []‎ بسازید. در غیر این صورت، عضو تازه ممکن است به list موقتی افزوده شود که به Pack متصل نیست.

key و index هم‌زمان مجاز نیستند. index خارج از محدوده خطا می‌دهد. بدون create: true، اگر عضوی پیدا نشود var مقدار نمی‌گیرد؛ بنابراین stepهای بعدی را با if محافظت کنید. مقدار value فقط می‌تواند ثابت، ‎!var‎ یا ‎!pop‎ باشد.

محل مجاز tagها

هر tag در همهٔ بخش‌ها معتبر نیست:

مقدار یا tagمقدار setشرط ifitem_in_list.value
مقدار سادهٔ YAMLبلهفقط مسیربله
‎!var‎بلهخیربله
‎!pop‎بلهخیربله
‎!pop-empty‎بلهخیرخیر
‎!default‎بلهخیرخیر
‎!default-var‎بلهخیرخیر
‎!merge‎بلهخیرخیر
‎!jinja‎بلهبلهخیر
‎!not‎خیربلهخیر

مرتب‌کردن خروجی با reorder

reorder کلیدهای نام‌برده را با ترتیب تعیین‌شده به ابتدای یک mapping موجود می‌آورد. سایر کلیدها بعد از آن‌ها باقی می‌مانند. این عملیات فقط خوانایی YAML خروجی را تغییر می‌دهد و روی رفتار Helm اثر ندارد.

- reorder:
    pack.spec.values:
      - global
      - service
      - ingress
    pack.spec.values.service:
      - enabled
      - type
      - ports

خطاهای رایج در pack-migrations.yaml

خطانتیجه یا روش درست
قراردادن URL مخزن در repomigration منطبق نمی‌شود؛ نام spec.chart.repository.name را بنویسید
نگه‌داشتن فقط آخرین migration افزایشیPackهایی که چند نسخه را رد کرده‌اند مسیر کامل ندارند
تنظیم دوبارهٔ spec.chart.version در stepزائد است؛ اپراتور پیش از stepها to_version را اعمال می‌کند
استفاده از ‎!pop‎ برای پیش‌فرض تازهنبود مبدأ چیزی تولید نمی‌کند؛ از ‎!default‎ یا ‎!default-var‎ استفاده کنید
استفاده از ‎!pop-empty‎ برای انتقالمقدار truthy باقی می‌ماند؛ این tag را فقط برای پاک‌سازی استفاده کنید
استفاده از Jinja بدون ‎!jinja‎عبارت Jinja به‌صورت متن ساده ذخیره می‌شود
فرض‌کردن ترتیب فایل به‌عنوان ترتیب اجراrangeها و زنجیره را با موتور واقعی migration آزمایش کنید

آزمون migration پیش از انتشار

kubit pack migrate -f redis.pack.yaml \
  --local-chartpath ./redis

خروجی، مانیفست مهاجرت‌یافته را در stdout نشان می‌دهد. آن را با ورودی مقایسه و مطمئن شوید فقط نسخه و مسیرهای مورد انتظار تغییر کرده‌اند. خروجی نرمال‌سازی می‌شود و ممکن است spec.managed: true را حذف کند؛ نبودن spec.managed معادل true است.

برای هر مسیر migration دست‌کم این حالت‌ها را بررسی کنید:

  1. قدیمی‌ترین نسخهٔ پشتیبانی‌شده و مرز ابتدا و انتهای هر from_version
  2. یک Pack پیش از هر migration میانی و یک Pack که کل زنجیره را طی می‌کند
  3. مقدارهای سفارشی کاربر، false، صفر، مقدار خالی و فیلد اختیاری ناموجود
  4. عضو موجود و ناموجود list و index نامعتبر
  5. اجرای دوبارهٔ migration؛ اجرای دوم نباید تغییر اختصاصی تازه‌ای ایجاد کند
  6. رندر یا diff چارت مقصد با مانیفست مهاجرت‌یافته

علاوه بر diff متنی YAML، تغییر معنایی values را نیز بازبینی کنید. مرتب‌سازی فیلدها و پاک‌سازی metadata ممکن است در خروجی دیده شود، حتی اگر مستقیماً در stepها تعریف نشده باشد.

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

kubit pack migrate -f redis.pack.yaml \
  --local-chartpath ./redis \
  --inline

‎--inline‎ فایل ورودی را تغییر می‌دهد. نسخهٔ قبلی را در گیت نگه دارید و پیش از اجرا مطمئن شوید مسیر فایل درست است. برای انتخاب نسخهٔ مقصد یا اجرای migration روی Pack موجود در کلاستر، مرجع دستور pack migrate را ببینید.

در ارتقای خودکار، Pack Operator ابتدا migration منطبق را بررسی می‌کند. اگر migration تغییر معتبر ایجاد کند، مانیفست Pack با نتیجه جایگزین می‌شود. اگر migration منطبق نباشد یا اجرای آن خطا بدهد، مسیر عادی ارتقای خودکار ادامه پیدا می‌کند؛ بنابراین خطای migration تضمین نمی‌کند که ارتقا متوقف شود.

مسیرهای مرتبط

مهاجرت Pack بین نسخه‌های چارت هلم | مستندات | کوبیت