
تا به حال با عباراتی مانند CI/CD – Continuous Integration, Continuous Delivery، Pipline، کامپایل، version control، containers و orchestration و برخورد کردهاید؟ اینها برخی از ابزارها و رویه های ضروری را که مهندسان DevOps استفاده می کنند. به عنوان مثال، ما مدام در مورد Kubernetes orchestrating می شنویم. می توانیم بفهمیم که احتمالاً چیزی را خودکار می کند، اما چگونه و چرا؟ در فرآیند Continuous Integration چه اتفاقی می افتد؟
در این مقاله، رمز و راز این اصطلاحات را روشن خواهیم کرد و برخی از ابزارها و رویه های ضروری را که مهندسان DevOps استفاده می کنند را نیز پوشش خواهیم داد. به طور خاص، به این خواهیم پرداخت که چرا آنها از این ابزارها استفاده می کنند. چه نوع مشکلاتی را با آنها حل می کنند.
مطلب “DevOps چیست؟” تصویر واضح تری از مسئولیت های یک مهندس DevOps ارائه میدهد.
سرورها و خدمات ابری
معمولاً هر کاری که یک مهندس DevOps انجام می دهد در برخی از سرورها یا سرویسهای ابری اتفاق می افتد. این ما را به اولین چیزی که یک مهندس DevOps باید بر آن مسلط باشد می رساند: سرورهای لینوکس. البته گاهی اوقات از سرورهای ویندوز نیز استفاده می شود، اما ما روی گزینه محبوب تر یعنی لینوکس تمرکز خواهیم کرد.
یک سرور لینوکس تقریباً همیشه از طریق دستورات مدیریت می شود. و این ممکن است در ابتدا کمی ترسناک به نظر برسد. اما اساساً فقط ما با سرور چت می کنیم و به آن می گوییم که می خواهیم چه کاری انجام دهد.
به عنوان مثال، برای ایجاد یک دایرکتوری جدید، به نام “JSCode”، باید تایپ کنیم:
mkdir JScode
برای کپی کردن فایلی به نام “app.js” در آن دایرکتوری، باید تایپ کنیم:
cp app.js JScode
می بینیم که این دستورات از کلمات انگلیسی مشتق شده اند، جایی که “mkdir” مخفف “make directory” و “cp” مخفف “copy” است. بنابراین یادگیری همه دستورات صحیح تقریباً مانند یادگیری یک زبان جدید است، زمان می برد، اما پیچیده نیست.
چیزهای دیگری که یک مهندس DevOps اغلب باید با آن تعامل داشته باشد، خدمات ابری است که توسط ارائهدهندگان خدمات به اصطلاح «رایانش ابری» ارائه میشود. چند نمونه از این ارائه دهندگان Amazon AWS، Google Cloud، DigitalOcean، Linode و Microsoft Azure هستند.
این شرکت ها صدها مولفه مختلف را ارائه می دهند که ما می توانیم آنها را به هم متصل کنیم تا چیزی بسازیم. به عنوان مثال، میتوانیم روی AWS برویم و از مؤلفهای استفاده کنیم که به ما امکان میدهد فایلها را ذخیره کنیم، بنابراین میتوانیم کد خود را در آنجا آپلود کنیم. و سپس می توانیم مؤلفه دیگری اضافه کنیم که به ما امکان می دهد آن کد را اجرا کنیم. بنابراین به جای اینکه آن را روی رایانه خود اجرا کنیم، آن را در فضای ابری، روی آن سرویسی که به تازگی راه اندازی کرده ایم اجرا می کنیم.
در مرحله بعد، میتوانیم مؤلفه سومی را اضافه کنیم که به ما امکان دسترسی به پایگاه داده را میدهد، بنابراین برنامه ما میتواند برخی از دادهها را نیز ذخیره کند. اساساً با بخشهای مختلفی که میتوانیم انتخاب کنیم مانند ایجاد یک ربات، در آن ابر است. به جز، این یک ربات نیست، بلکه بیشتر شبیه به نوعی ماشین است که از نرم افزار و سرور ساخته شده است: زیرساختی که شرکت ما برای اجرای تجارت خود به آن نیاز دارد.
برای راهاندازی و پیکربندی این مؤلفهها، اغلب از وبسایت ارائهدهنده رایانش ابری استفاده میکنیم. ما به رابط وب آنها دسترسی داریم و می توانیم از ماوس و صفحه کلید برای انتخاب آنچه می خواهیم راه اندازی کنیم و نحوه استفاده از آن استفاده کنیم.

ابزارهای اتوماسیون برای استقرار و پیکربندی سرورها
یک شرکت می تواند از صدها یا هزاران سرور استفاده کند. ورود به هر یک و پیکربندی دستی آن به سرعت تبدیل به یک کابوس می شود. حتی اگر چیز ساده ای باشد، مانند نصب یک برنامه. تصور کنید باید دستوری مانند زیر وارد کنیم:
sudo dnf install mariadb-server
ما وارد server-1 می شویم، این کار را انجام می دهیم و از سیستم خارج می شویم. سپس وارد server-2 می شویم، این کار را انجام می دهیم و از سیستم خارج می شویم. و به همین ترتیب، تا زمانی که به server-1000 برسیم. روز خیلی خسته کننده ای خواهد بود. واقع بینانه، پس از نصب آن برنامه، باید آن را نیز پیکربندی کنیم، که حتی زمانبرتر است.
بنابراین مهندسان Devops از ابزارهای اتوماسیون مانند Chef، Ansible، Puppet و Terraform میتوانند همه این اقدامات را در هر 1000 سرور بهطور همزمان انجام دهند. کاری که انسان برای انجام دستی به 50 ساعت نیاز دارد، اکنون می تواند در 3 دقیقه اتفاق بیفتد. و این ابزارهای اتوماسیون می توانند کارهای بیشتری انجام دهند. به عنوان مثال، ابزارهای اتوماسیون می توانند به طور خودکار یک سرور جدید راه اندازی و طبق دستورالعمل های ما پیکربندی و جایگزین سرور خراب شده کنند. بنابراین میتوانیم بهجای بیدار شدن در ساعت 3 صبح برای تعمیر لینوکس خراب، از خواب خود لذت ببریم.
کنترل منبع/نسخه
توسعه دهندگان تیم ما هر روز کد می نویسند. بنابراین پیگیری اینکه چه کسی چه چیزی را نوشته دشوار است. ناگفته نماند که نمی دانیم دیروز یا امروز چه چیزی تغییر کرده است. اما برنامهها یا سرویسهایی مانند Git، GitHub، GitLab و سایرین، همه این کارها را آسان میکنند.
به عنوان مثال، تصور کنید ما این خط را در جایی داریم، که یکی از توسعه دهندگان به نام محمد نوشت:
x = 1
یک ماه بعد، علی کد را تغییر می دهد به خط زیر:
x = 2
ابزارهای کنترل منبع/نسخه تاریخچه دقیقی از چنین تغییراتی را نگه می دارند. ردیابی خواهد شد که محمد نوشته “x = 1” و علی آن را به “x = 2” تغییر داده است. علاوه بر این، هر بار که از کد راضی هستیم، میتوانیم یک snapshot ایجاد کنیم. به عنوان مثال، پس از اینکه محمد “x = 1” را نوشت، می توانیم تصمیم بگیریم که همه کدهای ما اکنون آماده انتشار هستند. و ما می توانیم از این snapshot بگیریم و آن را نسخه 1.0.1 برنامه خود بنامیم. سپس بعد از اینکه علی کارش را تمام کرد، یک snapshot دیگر میسازیم و آن را نسخه 1.0.2 مینامیم.
اکنون می توانیم هر دو نسخه را به مشتریان خود تحویل دهیم. هنگامی که شخصی می خواهد نسخه 1.0.1 را دانلود کند، ابزار کنترل نسخه ما می تواند کد را دقیقاً همانطور که در آن لحظه در گذشته بود، ارائه دهد. به عنوان مثال، می داند که این نسخه قدیمی کد شامل آن خط “x = 1” است. و اگر کسی بخواهد نسخه 1.0.2 را دانلود کند، میداند که آن کد خط دیگری دارد، “x = 2”. و این کار را برای هزاران و هزاران خط انجام می دهد، بدون اینکه ما نگران آن باشیم یا به صورت دستی صدها کپی از کد خود را که در رایانه هایمان پراکنده شده اند ایجاد کنیم. دایرکتوری را تصور کنید که در آن فایل هایی مانند “app1.0.1.zip” تا “app1.0.68.zip” وجود دارد. نامرتب خواهد بود
کنترل نسخه همچنین به راحتی میتواند تغییرات را در هر زمان که لازم باشد بازگرداند. به عنوان مثال، اگر شخصی تغییرات تصادفی را در ساعت 10:33 صبح انجام دهد، میتوانیم تمام کد خود را دقیقاً به حالتی که در ساعت 10:32 صبح بود برگردانیم.
به طور خلاصه، ابزاری مانند Git اساساً همهی چیزهایی را که با کدهایی که توسعهدهندگان ما مینویسند و تغییر میدهند، اتفاق افتاده را ردیابی میکند. بنابراین کار کردن روی یک کد را برای بسیاری از افراد آسان میکند، حتی اگر چیزها را در مکانهای مختلف تغییر دهند. همه می دانند که دیگران چه کار می کنند و چرا. چون کنترل نسخه همچنین به افراد اجازه می دهد نظرات خود را در مورد دلیل ایجاد یک تغییر خاص بیان کنند.
یک مهندس DevOps بطور گسترده و روزانه از کنترل نسخه استفاده میکند.
CI/CD: یکپارچه سازی مداوم و تحویل مداوم
اکنون که همه این کدهای ارزشمند نوشته شده است، زمان آن رسیده که آن را قابل استفاده کنیم. و این کاری است که CI/CD: Continuous Integration and Continuous Delivery انجام می دهد. کد ما از مسیری عبور میکند که pipeline نامیده میشود. این به این دلیل است که مانند یک لوله است: اطلاعات از طریق آن، از یک سر به سر دیگر منتقل می شود. و در طول مسیر به روشهای مختلف دگرگون می شود.
در اینجا یک مثال ساده آورده شده است: پس از اینکه علی آن خط را اصلاح کرد و آن را به “x = 2” تغییر داد، pipeline ما می تواند کارهای زیر را انجام دهد:
- چند آزمایش نحوی را اجرا کند تا ببیند آیا کد هنوز معتبر است یا خیر.
- کد را کامپایل کند تا آن را به یک برنامه قابل استفاده تبدیل کند. به عنوان مثال، تمام این کدها، که به صورت متن نوشته شده اند، می توانند در یک برنامه تلفن، مانند یک برنامه اندروید، کامپایل شوند. ( کامپایل کردن در واقع تبدیل کد به محصول نهایی مانند یک برنامه، یک وب سایت یا هر چیزی که باید باشد، است.)
- سپس pipeline ما حتی میتواند بهطور خودکار این برنامه تلفن را به فروشگاه Google Play یا هر جایی که باید ارائه شود، تحویل دهد تا مشتریان ما بتوانند از آن استفاده کنند.
البته یک pipeline واقعی مراحل بسیار بیشتری دارد که توسط مهندسان DevOps طراحی میشود. اما به طور خلاصه، CI/CD در مورد این است: خودکار کردن همه این مراحل. به این ترتیب ما مجبور نیستیم هر بار که کسی تغییراتی در کد ایجاد می کند، به صورت دستی کامپایل یا کارهای دیگری انجام دهیم. و توسعه دهندگان مجبور نیستند منتظر بمانند تا یک انسان تغییرات خود را پردازش کند. سریع و به طور خودکار اتفاق می افتد. بنابراین زمان زیادی را هم برای مهندس DevOps و هم برای توسعه دهندگان صرفه جویی می کند.
برخی از ابزارهای که مهندسان DevOps برای ایجاد pipeline های CI/CD استفاده میکنند عبارتند از Jenkins، CircleCI، Travis CI، بهعلاوه دیگران.
Containers
با افزایش تعداد افرادی که روی یک کد کار می کردند، یک مشکل رایج اغلب در گذشته ظاهر می شد. هر چه محمد اصلاح میکرد، روی لپتاپش کار کرد. اما وقتی علی همان کد اصلاح شده را امتحان کرد، روی کامپیوتر او کار نمیکرد. این به این دلیل است که برنامه ها و یا سیستم عامل های نصب شده آنها به روش های کمی متفاوت پیکربندی شده اند. بنابراین در تیمهای توسعهدهنده، اغلب میشنویم که یک نفر شکایت میکند «این کار نمیکند» و دیگری پاسخ میدهد «برای من کار میکند…». این تنها یکی از دلایل متعددی است که کانتینرها اختراع شدند. و ابزاری به نام Docker محبوبترین راهحل کانتینری است.
امروزه کد در داخل چنین کانتینری آزمایش می شود. میتوانیم یک کانتینر را بهعنوان نوعی سیستمعامل بسیار بسیار کوچک در یک جعبه تصور کنیم که بهطور خاص برای پشتیبانی از برنامهای که میخواهیم به آن اضافه کنیم، پیکربندی شده است. این واقعاً یک سیستم عامل یا حداقل یک سیستم عامل کامل نیست، اما دارای برخی اجزای ضروری است که به کد یا برنامه ما اجازه اجرا شدن می دهد. همه می توانند این کانتینر یکسان را با همان اجزای ضروری داخل آن دانلود کنند. بنابراین اکنون مهم نیست که آن کانتینر را روی اوبونتو 20.04 اجرا کنیم یا اوبونتو 22.04، باید دقیقاً به همان روش، برای همه کار کند. کدی که در آنجا اجرا می کنیم دیگر به سیستم عامل ما اهمیت نمی دهد. هر آنچه را که نیاز دارد در جعبه کوچک خود دارد.
یکی دیگر از چیزهای جالب در مورد کانتینر این است که می توانیم آن را به راحتی به هر جایی که می خواهیم منتقل کنیم. محمد فقط میتواند کانتینر را به علی بدهد تا او نیز آن را آزمایش کند. هیچ چیزی نیاز به نصب مجدد یا پیکربندی مجدد ندارد.
بنابراین کانتینرها شبیه سازی یک برنامه خاص و تحویل آن به افراد زیادی را بسیار آسان می کنند. و ما مجبور نیستیم نسخه های مختلف برنامه خود را بسازیم، تا مطمئن شویم که روی ویندوز 8، ویندوز 10، ویندوز 11، اوبونتو 20.04، اوبونتو 22.04 و غیره کار می کند. به جای ساختن 5 نسخه از برنامه خود، یکی برای هر سیستم عامل، فقط یک نسخه می سازیم که در همه جا کار می کند. وقتی فقط یک نسخه داشته باشیم نگهداری کد آسان تر است. همچنین، دانلود و استفاده از برنامه ما برای افراد آسانتر است، زیرا آنها همه چیز مورد نیاز خود را برای قرار دادن در کانتینر که به تازگی کپی کرده اند دریافت می کنند.
کانتینرها همچنین اجرای برنامه ما را در سرورهایی که داریم آسان تر می کنند و نقش بسیار مهم و اساسی در کارهای روزانه یک مهندس DevOps دارند و این ما را به ابزار بعدی که باید کشف کنیم می رساند:
Container Orchestration
انقلاب کانتینر یک انقلاب دوم را آغاز کرد: container orchestration. اکنون که اپلیکیشنهایی را در داخل این جعبههای کوچک به نام کانتینر فشرده کردهایم، میتوانیم کارهای جالبی انجام دهیم.
بیایید این را تصور کنیم. شخصی می خواهد به ایمیل خود دسترسی داشته باشد. ما میتوانیم یک سرور داشته باشیم که به افراد اجازه میدهد به وبسایتی دسترسی داشته باشند تا بتوانند ایمیلهای خود را بخوانند. اما اگر آن سرور از کار بیفتد، هزاران نفر دسترسی به این سرویس را از دست خواهند داد. بنابراین ما می توانیم آن را به روش دیگری انجام دهیم.
هر بار که کسی میخواهد نامههایش را بخواند، یک کانتینر کوچک، مخصوص برای او راهاندازی میکنیم. ما به آنها اجازه می دهیم از خدمات ما استفاده کنند و وقتی آنها از سیستم خارج می شوند، فقط آن کانتینر را نابود می کنیم. چه منفعتی دارد؟ اگر این کانتینر بد کار کند، فقط یک مشتری با مشکل مواجه شده است. با ارائه یک کانتینر به هر مشتری، تا زمانی که سایرین به درستی کار کنند، خدمات دیگران به خوبی کار خواهد کرد. این یک معماری “microservice” است. ما از یک برنامه بزرگ در یک سرور بزرگ، که توسط هزاران نفر استفاده میشود، به هر مشتری که توسط کانتینر خودش سرویس میدهد، رسیدیم.
و در اینجا به ارکستراسیون می رسیم. ما اشاره کردیم که اگر یک کانتینر خراب شود، مشتری ما خدمات خود را از دست می دهد. اما با ارکستراسیون، این اتفاق نمی افتد. یک ابزار ارکستراسیون متوجه می شود که کانتینر خراب است، بنابراین به سرعت این کانتینر معیوب را از بین می برد و کانتینر جدیدی را راه اندازی می کند که به درستی کار می کند.
انجام این کار آسان است زیرا کانتینرها کوچک هستند و به راحتی میتوان آنها را بنا به تقاضا ایجاد کرد. مشتری که می خواهد ایمیل خود را بررسی کند متوجه می شود که دسترسی به آن 2 ثانیه بیشتر طول کشیده است. آنها متوجه نخواهند شد که چیزی خراب شده است و ما به سرعت کانتینر مورد استفاده آنها را در پشت صحنه تعویض کردیم. خیلی باحاله، اینطور نیست؟ اما چیزی باید این فرآیند را خودکار کند و این کار ابزارهای ارکستراسیون کانتینری مانند Kubernetes است.
با Kubernetes، چیزی شبیه به این اتفاق می افتد. ما به آن درباره حالتی میگوییم که میخواهیم به آن برسیم. به عنوان مثال، میتوانیم بگوییم: “سلام کوبرنتیز، من میخواهم 1000 عدد از این کانتینرها روی این 10 سرور اجرا شود. و حتماً آنها را به طور مساوی توزیع کن”. سپس کوبرنتیز اقدام به پیکربندی و راه اندازی کانتینرهای ما می کند. و حتی جالبتر اینکه به طور مداوم همه چیز را زیر نظر دارد تا مطمئن شود که این حالت حفظ می شود.
یک مثال: فرض کنیم که یک کانتینر خراب میشود و اکنون به جای 1000 کانتینر مورد نظر، 999 کانتینر در حال اجرا داریم. Kubernetes کانتینر خراب را حذف می کند و یکی را که درست کار می کند دوباره ایجاد می کند. کوبرنتیز در تلاش های خود برای حفظ این وضعیت حتی فراتر می رود. اگر یکی از سرورهای ما خراب شود چه؟ آن سرور می تواند 100 کانتینر ما را اجرا کند. خیلی بد است که تعداد زیادی را در یک زمان از دست بدهیم.
اما کوبرنتیز متوجه میشود سرور از کار افتاده است، بنابراین 100 کانتینر گم شده ما را در سرورهای دیگری که هنوز کار می کنند دوباره راه اندازی می کند. و آنها را به طور مساوی توزیع می کند تا هیچ سروری بیش از حد تحت فشار قرار نگیرد. علاوه بر این، ما حتی می توانیم سرورهای یدکی را به کوبرنتیز ارائه دهیم و اگر ببیند یکی از سرورها از کار افتاده است، می تواند آن کانتینرهایی که بر روی آن سرور بوده اند را به سرور یدکی ما منتقل کند.
بنابراین میتوانیم کوبرنتیز را نوعی هوش مصنوعی بدانیم. ما به آن می گوییم که می خواهیم ظروف ما چگونه کار کنند. پس از آن، کوبرنتیز به طور مداوم همه چیز را کنترل می کند و تمام تلاش خود را می کند تا کارها را دقیقاً همانطور که می خواهیم اجرا کند.
نتیجه
امیدواریم، این موارد را در خصوص کارهایی که افراد DevOps انجام میدهند کمی واضحتر کرده باشم. البته مهندسان Devops از ابزارهای زیادی استفاده می کنند. به عنوان مثال، آنها همچنین به نرم افزاری نیاز دارند که آنچه را که در حال وقوع است نظارت کند و هشدارهای مربوط به خطاها را ارسال کند. اما در این مقاله نگاهی انداختیم به کارهایی که آنها در بیشتر اوقات خود انجام می دهند. ابزارهایی که در اینجا صحبت کردیم معمولاً مهمترین ابزارهایی هستند که افرادی که میخواهد مهندس DevOps باشد، باید بداند.