بیش از یکسال پیش توسط دوست عزیزم برای استقرار یک اپلیکیشن با طراحی microservices در محیط عملیاتی دعوت شدم. کار توسعه میکروسرویسها خیلی قبلتر انجام شده بود و باید مراحلِ راهاندازی و استقرار انجام میشد. در این مطلب سعی دارم در مورد نحوه انتخاب ابزار برای استقرار این پروژه و طراحی فرآیند استقرار توضیحاتی ارائه کنم. از آنجا که تا حد امکان به زبان ساده به جزئیات پرداختم، گمان میکنم این نوشته برای افراد علاقمند و مطلع در حوزه ابزارهای DevOps مناسب باشد.
پرداختن به مزایا و معایب هر کدام از طراحیهای monolithic یا microservices موضوع این متن نیست اما برای درک بهتر موضوع تصور کنید اپلیکیشنی(تحت وب) در قالب یکی از framework های موجود توسعه داده شدهاست. برای استقرار این محصول همانگونه که رایج است از وب سرویسهایی مثل: tomcat, apache, nginx استفاده میشود. در این شرایط تمام بخشها، ماژولها یا قسمتهای مختلف در همان اپلیکیشن در نظر گرفته شده بصورتی که بعد از Build صرفاً کافی است artifact حاصل توسط وب سرویس اصطلاحاً serve شود. به عبارت دیگر در طراحی monolithic یک single unit توسعه و استقرار داده میشود.
در طراحی میکروسرویس مجموعهای از سرویسهای کوچک که هر کدام مرتبط با ماژول یا بخش خاصی از محصول نهایی هستند تولید میشوند. لزوماً نیازی به توسعه تمامی این سرویسها با یک زبان و یک تکنولوژی مشترک نیست. بنابراین به عبارت دیگر در طراحی میکروسرویس یک distributed سیستم وجود دارد. در چنین شرایطی هرکدام از میکروسرویسها درقالب کانتینر آماده و توسط یکی از ابزارهای مدیریت کانتینر (Orchestration Tools) استقرار داده میشود.
اما چرا container ؟! استفاده از کانتینر امکان portable شدن هر میکروسرویس، مصرف resource کمتر نسبت به VM، سرعت عمل بالا در delivery و deploy، قابلیت scale کردن یا افزایش تعداد instance هر میکروسرویس، امکان مدیریت بهتر و rollback سریعتر را فراهم میکند و Docker یکی از پرکاربردترین کانتینرها است. همانطور که قبلتر اشاره شد برای مدیریت کانتینرها به همراه تمام ویژگیهای ذکر شده نیاز به یک ابزار orchestration هست که علاوه بر مزایای گفته شده، مواردی مثل: load balancing, internal DNS, دسترسی پذیری بالاتر و ... را پوشش دهد. از ابزارهای مدیریت کانتینر به : Kubernetes, Docker Swarm, Rancher, Red Hat OpenShift میتوان اشاره کرد.
یکی از مراحل زیربنایی برای استفاده از میکروسرویسها در قالب کانتینر، آمادهسازی Dockerfile ها برای تولید docker image هر میکروسرویس است تا علاوه بر Build میکروسرویسها، docker image ها نیز آماده استفاده باشند. شاید مهمترین نکته در نوشتن Dockerfile توجه به حجم نهایی image هست که حتی الامکان باید کمترین مقدار ممکن باشد.
همیشه منابع آموزش Docker برای افرادی که تمایل به یادگیری این ابزار دارند مورد سوال بودهاست. به همین جهت در ادامه منابعی که تاکنون جهت آموزش داکر مورد استفاده اینجانب بودهاست را ذکر میکنم. بنابراین علاوه بر سایت docs.docker.com کتاب Mastering Docker انتشارات Packet برای درک مفاهیم پایه و کتاب Native Docker clustering with swarm از همین انتشارات منبع خوبی برای آموزش Docker Swarm است.
علاوه بر منابع فوق که معرفی شد استفاده از دورههای موجود در پلتفرمهای آموزشی آنلاین مثل udemy, coursera و cognitive class بسیار کاربردی است.
با توجه به توضیحات ارائه شده، از بین گزینههای موجود برای مدیریت کانتینر و با توجه به شرایط پروژه، Docker Swarm و Kubernetes جزو موارد اصلی در نظر گرفته شده بود.
برای این انتخاب نیاز به آشنایی با دیگر راهکارهای container orchestration است. در فصل اول کتاب Native Docker Clustring Swarm معرفی و مقایسه بسیار مناسبی از Kubernetes, DockerSwarm, CoreOSFleet, ApacheMesos موجود است که منجر به ایجاد دید مناسبی در این زمینه میشود. از طرفی با استفاده از کتاب Kubernetes Up&Running از انتشارات OREILY که یکی از منابع مناسب برای درک مفاهیم پایه کوبرنیتیز محسوب میشود، امکان دریافت نیازمندیهای لازم برای پیادهسازی یک پروژه توسط کوبرنیتیز میسر است.
در مجموع به گمان اینجانب و با در نظر گرفتن شرایط و محدودیتهای موجود در این پروژه برای انتخاب ابزار مدیریت کانتینر موراد زیر حائز اهمیت است.
درنهایت با در نظر گرفتن این موارد Docker Swarm انتخاب شد. انتخابی که به نظرم درستی آن با گذشت زمان بیشتر درحال مشخص شدن هست.
کتاب kubernetes in action از انتشارات manning هم یکی از بهترین و معروفترین کتاب ها برای کسانی هست که علاقه به یادگیری مفاهیم کوبرنیتیز دارند.
بعد از انتخاب ابزار مدیریت کانتینر و برای شروع و کانفیگ تمام ماشین ها از Ansible استفاده شد. اینکار باعث بوجود آمدن ویژگی Phoenix Server میشد. به عبارت دیگر یکپارچگی در تنظیم ماشینها، بالابردن سرعت عیب یابی، سرعت بالا در کانفیگ، ایجاد داکیومنت دقیق و همیشه آپدیت و باز تنظیم هر ماشین درصورت از دسترس خارج شدن و وقوع رخداد از ویژگیهای استفاده از Ansible محسوب میشود.
با توجه به شناخت از اپلیکیشن درحال توسعه و میزان stateless میکروسرویسها، نیاز بازدارندهای به پیادهسازی shared storage نبود ولی برای بعضی از سرویسهای زیرساختی این نیاز احساس میشد. برای این مورد ازNFS و در ادامه از GlusterFS به عنوان راهکار این موضوع استفاده شد.
بعد از راهاندازی Swarm و مشخص کردن تعداد Master ,Worker و Label زدن تمام ماشینها، نوبت به آماده سازی فایل docker-stack و deploy سرویسها بود که این روال باید بصورت خودکار انجام میشد. مراحل تولید فایلهای docker-compose و docker-stack متناسب با هر ورژن محصول توسط Python نوشته شد.
طبق طراحی که تیم توسعه انجام داده بود نیاز به استفاده از Apache Zookeeper به عنوان configuration management وجود داشت. این مورد میتوانست منجر به ایجاد single point of failure شود. بنابراین زوکیپر بصورت کلاستر کانفیگ شد و بگونهای constraint ها تنظیم شد که هر instance بر روی یک node مستقر شود.
شاید یکی از نیازهای اولیه هر Orchestration راهاندازی یک رجیستری برای نگهداری و مدیریت docker image ها و ورژن آنها باشد. نیاز به ابزاری بود که ویژگیهای داکر رجیستری، ورژن کنترل(که امکان استفاده از ویژگیهای Git فراهم باشد) و امکان ایجاد Pipeline برای طراحی و پیادهسازی CI/CD فراهم کند. همه این ویژگیها در گیت لب وجود دارد و از طرفی نحوه نصب و آپدیت آن با آماده کردن یک docker-compose فایل خیلی راحت وسریع است.
با تنظیم Gitlab CI/CD یک Pipeline کامل از مراحل: Build سورس کُد، آماده سازی فایلهای docker-compose و docker-stack، بیلد داکر ایمیجها و آپدیت داکر رجیستری با ورژنهای جدید و تهیه stack فایل برای rollback انجام شد. نتیجه اینکار ضریب اطمینان بالا به همراه سرعت در deploy ورژن جدید بود، بطوریکه شرایطی برای بوجود آمدن خطای انسانی در هنگام deploy یا rollback وجود نداشت.
با توضیحاتی که در مورد روال شکل گیری Orchestration و میکروسرویسها ارائه شد مشخص است که یکی از نیازهای مهم در چنین سیستمی با تعداد بالای سرویسها مانیتورینگ دقیق است و در غیر اینصورت باعث کُندی و سخت شدن فرآیند عیب یابی میشود. قبلا تجربه لذت بخش استفاده از Zabbix را داشتیم ولی برای محیطهای Orchestration ابزارهای مناسبتری نسبت به زبیکس وجود دارد. بنابراین Prometheus برای جمع آوری متریکها استفاده شد. استک مانیتورینگ شامل تعدادی سرویس است که منطبق بر نیاز هر محیط استفاده میشود مثل: Grafana, Alert manager, Caddy, cAdvisor. البته برای ارسال آلرتها از طریق پیامک نیاز به یک سرویس web-hook بود که دیتای مورد نیاز را آماده و توسط sms gateway ارسال کند. این سرویس با Python نوشته شد و در مجموعه مانیتورینگ قرار گرفت.
با توجه به اینکه لاگ تمامی سرویسها در Elasticsearch ذخیره میشد. در Grafana به عنوان Data Source اضافه و بنابراین مانیتورینگ و تنظیم Alert در Grafana با توجه به لاگ تمامی سرویسها انجام شد.
اوایل شروع پروژه portainer که یکی از داشبوردهای معروف Docker است، نصب شد ولی به دلیل کاربردی نبودن برای محیط عملیاتی، حذف شد.
در کل سه استک در Cluster Swarm بوجود آمد. یکی برای سرویسهای زیرساختی از قبیل زوکیپر، MQها و ...، استکِ میکروسرویسها و استکِ مانیتورینگ. و نهایتا فرآیند استقرار این محصول بصورت اتوماتیک مراحل زیر را شامل میشود:
بدیهی است در تمام مراحلی که توضیح داده شد نکات قابل نقدِ بسیاری وجود دارد. به همین جهت مشتاق شنیدن نظرات و بحث در مورد آنها هستم.