YAML چیست و چه کاربردی دارد؟
YAML یک زبان برنامهنویسی محبوب است که برای خواندن و درک آسان طراحی شده است که میتوان از آن در ارتباط با سایر زبانهای برنامه نویسی هم استفاده کرد. به دلیل انعطاف پذیری و دسترسی، YAML توسط ابزار اتوماسیون Ansible برای ایجاد فرآیندهای اتوماسیون استفاده میشود. در این مطلب به معرفی کامل بخشهای مختلف یک فایل YAML خواهیم پرداخت.
YAML چیست؟
YAML یکی از محبوبترین زبانهای سریالسازی دادهها است. محبوبیت آن ناشی از سادگی است و اینکه برای انسان قابل خواندن و درک کردن میباشد. علاوه بر اینکه یک فرمت قدرتمند برای نوشتن فایلهای پیکربندی است در ماندگارسازی داده (data persistence)، پیام رسانی اینترنتی(internet messaging)، اشتراک گذاری دادههای بین زبانی(cross-language data sharing) و بسیاری موارد دیگر هم کاربرد دارد.
YAML مخفف YAML Ain’t Markup Language است و با توجه به انعطاف پذیری و دسترسی طراحی شده است، بنابراین با تمام زبانهای برنامه نویسی مدرن کار میکند و به طور گسترده برای به اشتراک گذاری دادههای متقابل (cross-data) استفاده می شود.
همه این عوامل به محبوبیت YAML به عنوان یک زبان پیکربندی در حیطه DevOps کمک می کند، جایی که به طور گسترده با ابزارهای شناخته شدهای مانند Kubernetes، Ansible، Terraform و بسیاری دیگر سر و کار داریم.
فایلهای YAML دارای پسوند yaml یا yml هستند.
یک فایل YAML معمولی چگونه است؟
سینتکس ابتدایی YAML
فرمت YAML در درجه اول از 3 نوع گره (node) استفاده میکند:
- Maps/Dictionaries (در YAML به آن mapping گفته میشود)
محتوای یک گره نگاشت، مجموعهای نامرتب از جفت گرههای key/value است، با این محدودیت که هر یک از کلیدها منحصر به فرد هستند. YAML هیچ محدودیت بیشتری برای گرهها قائل نیست.
- Arrays/Lists (در YAML به آن sequences گفته میشود):
محتوای یک گره دنباله یک سری مرتب شده از صفر یا بیشتر گره است که به طور خاص، یک دنباله ممکن است بیش از یک بار حاوی همان گره باشد. حتی می تواند خودش را هم نگه دارد.
- Literals (رشته ها، اعداد، بولین و غیره)
محتوای یک گره اسکالر (scalar) یک مبحث مبهم است که می تواند به صورت یک سری کاراکترهای یونیکد صفر یا بیشتر ارائه شود.
در ادامه بررسی میکنیم که موارد بالا کجای فایل نمونه YAML که قبلا دیدیم قرار دارد:
تورفتگی - Indentation
یک فایل YAML برای نشان دادن تودرتو به فضای خالی و تورفتگی متکی است. توجه داشته باشید که سلسله مراتب و تودرتو از طریق یک سبک تورفتگی شبیه پایتون قابل مشاهده است. توجه به این نکته ضروری است که کاراکتر tab را نمیتوان برای تورفتگی در فایل YAML استفاده کرد. فقط از space میتوان استفاده کرد. تعداد فضاهایی که برای تورفتگی استفاده میشود تا زمانی که یکدست باشند مهم نیست.
نقشه برداری - Mapping
از mapping برای مرتبط کردن جفت های key/value که مرتب نشدهاند استفاده میشود. نقشهها را میتوان با افزایش تورفتگی تودرتو کرد، یا با resolve نقشههای قبلی، نقشههای جدیدی در همان سطح ایجاد نمود.
دنباله ها - Sequences
دنبالهها در YAML با استفاده از خط فاصله (-) و space نمایش داده میشوند. آنها مرتب شدهاند و میتوانند با استفاده از تورفتگی در داخل map جاسازی شوند.
نکته: به یاد داشته باشید که ترتیب در دنبالهها مهم است اما در mapping مهم نیست.
Literals — رشته
حروف رشتهای نیازی به کوتیشن ندارند. کوتیشن فقط زمانی مهم است که حاوی مقداری باشد که ممکن است با یک کاراکتر خاص اشتباه گرفته شود.
در اینجا مثالی وجود دارد که در آن رشته به عنوان کاراکتر خاص & است.
- Folding Strings - رشتههای تاشو
رشتهها همچنین میتوانند در بلوکها نوشته شوند و بدون کاراکترهای خط جدید با استفاده از عملگر fold (علامت بزرگتر) تفسیر شوند.
قطعه YAML فوق به صورت زیر تفسیر میشود:
- Block strings – رشتههای بلاکی
رشتهها را میتوان با استفاده از کاراکتر بلوک (پایپ) به عنوان بلوک تفسیر کرد.
این با خطوط جدید (\n) به صورت زیر تفسیر می شود.
- Chomp characters - کاراکترهای برجسته
رشتههای چندخطی ممکن است با فاصلههای سفید(whitespaces) ختم شوند. از عملگرهای Preserve chomp(+) و strip chomp میتوان برای حفظ یا حذف فضاهای سفید استفاده کرد. آنها را میتوان با کاراکترهای block و pipe استفاده کرد.
- حفظ کاراکتر خط جدید
قطعه بالا در JSON به صورت زیر تفسیر می شود
- strip کاراکتر خط جدید
قطعه بالا در JSON به صورت زیر تفسیر می شود:
کامنت - Comments
فایل YAML برخلاف JSON از کامنت پشتیبانی می کند. کامنت با # شروع میشود.
سینتکس پیشرفته YAML
-
اسناد - Documents
اسنیپت YAML فوق که در بالا دیدیم یک سند(document) نامیده می شود. یک فایل YAML میتواند بیش از یک داکیومنت داشته باشد. هر داکیومنت را می توان به عنوان یک فایل YAML جداگانه تفسیر کرد که به این معنی است که چندین document میتوانند حاوی کلیدهای مشابه یا تکراری باشند که در یک داکیومنت مجاز نیستند.
ابتدای یک داکیومنت با سه خط فاصله نشان داده می شود —
یک فایل YAML با چندین داکیومنت به این شکل است که هر سند جدید با --- نشان داده می شود:
در نهایت، از سه نقطه برای پایان دادن به یک سند بدون شروع داکیومنت جدید استفاده می شود...
قبل از اینکه درباره YAML بیشتر یاد بگیریم، باید بگویم که میتوانید نوشتن یک فایل YAML را از طریق این لینک تمرین کرده و اعتبارسازی نمائید.
پس از تجربه کار با مفسر آنلاین YAML که گفته شد، زمان آن رسیده است که درباره schemaها و Tagها صحبت کنیم، پس با این مطلب از پارسدو همراه باشید:
-
اسکیما و تگ - Schemas and Tags
بیایید لحظهای در نظر بگیریم که YAML چگونه داکیومنت داده شده را تفسیر میکند. آیا لیترال اول توالی (sequence) یک رشته است یا یک بولین؟
اگر پاسخ دهید که اولین مورد در لیست یک بولین است، درست گفتهاید و اگر پاسخ دهید که یک رشته است باز هم درست میگویید! روش حل آن توسط اسکیمای YAML که تجزیه کننده پیاده سازی کرده است تعیین میشود. اما اسکیما دقیقا چیست؟
Schemas را میتوان بهعنوان روشی در نظر گرفت که تجزیهکننده گرهها (values) موجود در یک فایل YAML را حل یا درک میکند.
در اصل 3 اسکیمای پیش فرض وجود دارد:
- FailSafe Schema: فقط نقشهها، دنبالهها و رشتهها را درک میکند و تضمین میشود که برای هر فایل YAML کار کند.
- JSON schema: همه انواع پشتیبانی شده در JSON از جمله boolean، null، int و float و همچنین انواع موجود در اسکیمای FailSafe را درک میکند.
- Core schema: این اسکیما توسعهای از JSON schema است که آن را برای انسان بیشتر از انواع مشابه قابل خواندن میکند و اما در اشکال مختلف پشتیبانی میکند.
برای مثال: 1. null | Null | NULL همه به یک نوع نال resolve میشوند و true | True | TRUE همه به یک مقدار بولین resolve میشوند.
توجه: همچنین امکان ایجاد اسکیماهای سفارشی خود بر اساس schema پیش فرض بالا هم وجود دارد.
بنابراین اگر به سوال اصلی برگردیم، اگر تجزیه کننده(parser) فقط از schema اصلی (schema FailSafe) پشتیبانی کند، اولین مورد به عنوان یک رشته ارزیابی میشود، در غیر این صورت، به عنوان یک بولین در نظر گرفته خواهد شد.
یوال بعدی اینکه، اگر صراحتا بخواهیم یک مقدار به روشی خاص تجزیه شود چه؟
بیایید از همان مثال بگوییم که میخواهیم اولین مقدار واقعی بهجای یک بولین بهصورت رشتهای تجزیه شود، حتی زمانی که تجزیهکننده از JSON یا schema اصلی استفاده میکند.
این جایی است که tag وارد عمل میشود؛ تگها را می توان به عنوان types در YAML در نظر گرفت.
حتی اگر به صراحت tags/types را در هیچ یک از قطعههای YAML که تاکنون دیدهایم ذکر نکرده باشیم، آنها به طور خودکار توسط تجزیه کننده YAML استنباط میشوند. به عنوان مثال، نقشهها دارای tag/type به عنوان tag:yaml.org,2002:map ، دنبالهها عبارتند از tag:yaml.org,2002:seq و رشتهها عبارتند tag:yaml.org,2002:str
مثلا قطعه زیر کاملا درست کار میکند، حتی زمانی که برچسبها را مشخص میکنیم:
ما میتوانیم از این تگها برای تعیین صریح یک type استفاده کنیم. برای مثال، تنها کاری که باید انجام دهیم این است که type را به عنوان رشته مشخص کنیم، و تجزیه کننده YAML هم آن را به عنوان یک رشته تجزیه میکند.
-
Anchors and Alias
با تنظیمات زیاد، فایلهای پیکربندی میتوانند بسیار بزرگ شوند.
در فایلهای YAML برای جلوگیری از تکرار از anchor با علامت & و alias با علامت * استفاده میشود. هنگام نوشتن پیکربندیهای بزرگ در YAML، معمولا یک پیکربندی خاص تکرار میشود، برای مثال، پیکربندی vars برای هر سه سرویس در قطعه YAML زیر تکرار شده است:
همانطور که موارد بیشتر و بیشتری برای فایلهای پیکربندی بزرگ تکرار میشود، این کار خسته کننده هم خواهد شد؛ anchor و alias به ما امکان میدهند همان قطعه را بدون نیاز به تکرار هیچ گونه پیکربندی بازنویسی کنیم.
از anchors (&) برای تعریف یک قسمت از پیکربندی و alias برای اشاره به آن قطعه در بخش دیگری از پیکربندی استفاده میشود.
anchors و aliases به ما کمک کردند تا پیکربندی تکراری را کاهش دهیم.
اما پیکربندیها کاملا یکسان نیستند و اینجا و آنجا متفاوت خواهند بود به عنوان مثال، اگر همه سرویسهای فوق در نسخههای مختلف اجرا شوند چه میشود؟ آیا به این معنی است که ما باید دوباره بنویسیم و کل پیکربندی را دوباره تکرار کنیم؟
اینجاست که override (<<:) به کمک میآید و میتوانیم از alias استفاده کرده و تغییرات مورد نیاز خود را انجام دهیم.
در فایل های YAML کاراکترهای خاصی مانند { , } , [ , ] , , , & , * , # , ?, ، | , -- , < , > , = , ! , % , @ , \ و غیره وجود دارد اما اگر این کاراکترهای خاص در واقع بخشی از data/value باشند چه؟ چگونه از آنها فرار کنیم؟
کاراکترهای خاص را می توان به روش های مختلف اجرا کرد:
Entity Escapes
- space:
- colon:
- ampersand: &
Unicode Escapes
- space: "\u0020"
- single-quote: "\u0027"
- double quote: "\u0022"
Quoted Escapes
- دابل کوتیشن در یک سینگل کوتیشن :
‘YAML is the “best” configuration language’
- سینگل کوتیشن در دابل کوتیشن:
“Yes, the ‘best’ ”
مقایسه YAML با JSON
YAML چه تفاوتی با JSON دارد؟
قطعه کد زیر که از پیکربندی Kubernetes که در JSON نوشته شده است را بررسی کنید. به کاری که انجام می دهد توجه نکنید فقط فایل را مشاهده کنید:
شبیه فایل JSON خالص نیست؟ بیایید ببینیم آیا می توانیم آن را در تجزیه کننده YAML خود تایید کنیم یا خیر.
عجیب است که تجزیه کننده YAML فایل را نامعتبر گزارش نکرده است. آیا این به این معنی است که JSON نیز YAML است؟
YAML در واقع یک ابر مجموعه(superset) از JSON است. همه فایلهای JSON فایلهای YAML معتبر هستند، اما نه برعکس.
آیا می توانیم JSON و YAML را ترکیب کنیم؟ آیا پس از آن باز هم یک فایل YAML معتبر است؟ بیایید این فرضیه را آزمایش کنیم. اجازه دهید برخی از قطعه بالا را تغییر دهیم تا بیشتر شبیه YAML باشد که با آن آشنا هستیم.
توجه داشته باشید که دیگر {} root JSON wrapper وجود ندارد، فقط map در سطح root وجود دارد، اما بیشتر آن هنوز JSON است. یک بار دیگر فایل را در تجزیه کننده YAML اعتبار سنجی کنید. این یک فایل YAML معتبر است، اما وقتی میخواهیم آن را در تجزیهکننده JSON تایید کنیم، میگوید نامعتبر است. دلیلش این است که فایل دیگر JSON نیست، بلکه YAML است. این نشان می دهد که YAML در واقع یک superset (ابر مجموعه) JSON است.
YAML در کجا استفاده می شود؟
ما چیزهای زیادی در مورد YAML یاد گرفتیم و دیدیم که به عنوان یک زبان پیکربندی عالی عمل میکند؛ اجازه دهید آن را در عمل با برخی از معروف ترین ابزارها ببینیم.
-
Ansible - انسیبل
Playbooksهای Ansible برای خودکار کردن کارهای تکراری که اقدامات را به طور خودکار انجام میدهند استفاده میشود. playbooks در فرمت YAML بیان میشوند و هر عملی را که در playها تعریف شده است انجام میدهند.
Ansible یک ابزار خط فرمان، متنباز و مبتنی بر پایتون برای اتوماسیون فناوری اطلاعات است که توسط Redhat توسعه یافته است. انسیبل بسیاری از فرآیندهای دستی IT، از جمله تهیه، مدیریت پیکربندی، استقرار برنامهها و هماهنگسازی را خودکار میکند.
در اینجا یک playbook ساده Ansible وجود دارد که Nginx را نصب میکند، الگوی مشخص شده را برای جایگزینی صفحه فرود پیشفرض Nginx اعمال میکند و در نهایت دسترسی TCP را در پورت 80 فعال میکند.
-
Kubernetes - کوبرنتیس
Kubernetes که با نام K8s نیز شناخته میشود، یک سیستم متنباز برای خودکارسازی deployment، scaling و مدیریت برنامههای کاربردی کانتینری است.
Kubernetes بر اساس یک state مدل کار می کند که در آن سعی می کند از حالت فعلی به صورت اعلامی (declarative) به حالت مطلوب برسد. Kubernetes از فایلهای YAML برای تعریف object (آبجکت) در Kubernetes استفاده میکند، که برای ایجاد منابع کلاستر مانند pods، services و deployments اعمال میشود.
در اینجا یک فایل YAML است که یک deployment را توصیف می کند که Nginx را اجرا میکند.
مثال جالب در مورد YAML
YAML به عنوان یک زبان پیکربندی عالی عمل میکند، اما مهم است که هنگام استفاده از آن چالشهای خاص را هم در نظر داشته باشید.
مورد عجیب مشکل نروژ (Norway problem)
تصور کنید مخفف همه کشورهایی که در آن برف میبارد را لیست کنید
همه چیز خوب به نظر میرسد، درست است؟ اما وقتی سعی میکنید این فایل YAML را در پایتون بخوانید، می بینیم که NO به جای 'NO' که مخفف نروژ است False خوانده میشود!
چرا این اتفاق افتاده است!؟
schema اصلی که NULL | null را تفسیر میکند را به یاد دارید؟ به همین شکل این اسکیما FALSE | F | NO را هم تفسیر میکند به همین صورت به جای NO به عنوان یک رشته، آن را به عنوان یک بولین تفسیر مینماید که این مشکل را میتوان به راحتی با استفاده از NO در کوتیشن حل کرد.
برای جلوگیری از چنین غافلگیریهایی در کدنویسی، میتوان از StrictYAML استفاده کرد که بهطور پیشفرض همه چیز را به عنوان یک رشته تفسیر خواهد کرد.
خرید سرور مجازی لینوکس در پنج موقعیت جغرافیایی ایران، ترکیه، هلند، آلمان و آمریکا با قابلیت تحویل آنی در پارسدو فراهم است.
اگر تا اینجای مقاله همراه بودید تبریک میگویم. شما در مسیر تبدیل شدن به یک متخصص YAML هستیدو درک کدهاید که چقدر YAML جذاب و کاربردی است.
YAML زبان مهمی است که تقریبا در همه جاهایی که نوشتن پیکربندی مورد نیاز است، کاربرد دارد. ابزارهای Kubernetes، Ansible، docker-compose و ... نمونههای بسیار خوبی هستند.