CircleCI چیست؟

CircleCI ابزاری می باشد که شما به راحتی می توانید جهت فرایند cicd پروژه خود از آن استفاده کنید و این امکان را به دولوپرها می‌دهد تا باگ‌ها را قبل از اینکه محصولاتشان به دست مشتری برسد شناسایی و برطرف کنند. در واقع، CircleCI یک سرویس کاربردی است که برای پروژه‌های کوچک که به صورت رایگان نیز می‌توان از آن استفاده کرد. بدین ترتیب عملیات test , deploy , build را می توان توسط این پلتفرم پیاده سازی کرد.

تا بدین لحظه که این مقاله نوشته شده است این ابزار با دو ورژن کنترل معروف bitbucket , github قابلیت تعامل و یکپارچه سازی را دارد و اگر از ورژن کنترل های دیگری مثل gitlab استفاده می کنید باید مخازن و ریپوزیتوری های خود را به یکی از آنها منتقل کنید.

قابلیت های کاربردی CircleCi:

1- رابط کاربر پسند:

جهت کانفیگ از زبان yaml استفاده می کند.

داکیومنت تقریبا کاملی ارایه کرده است.

در کمترین زمان ممکن می توانید عملیات build خود را آغاز کنید.

کار با circleci آسان است. من می توانم از مخازن خاص ، از step های خاص ، از job های خاص ، از workflow خاص ، به خروجی خاص دسترسی پیدا کنم. شکل زیر را ببینید.

circle1

۲- تنظیمات ساده و قابلیت ssh :

تمامی job ها را میتوان بر روی کانتینر های داکر یا ماشین مجازی در لینوکس یا mac یا ویندوز اجرا کنیم.

اگر یکی از job ها به مشکل بخورد می توانیم با فرایند ssh مجددا آن را تست کنیم و به آن job لاگین کنیم و جهت اشکال زدایی اون بپردازیم.

۳- هزینه:

شما در هر ماه حدود 1000 دقیقه build رایگان و یک ‘کانتینر’ بصورت رایگان دریافت می کنید.

۴-راه حل ابری و قابلیت استفاده از خود circleci:

دیگر زمان تلاش برای راه اندازی و مدیریت پروژه Jenkins یا GoCD شخصی خود گذشته است. پردازش یک پروژه به سادگی با افزودن آن پروژه بر روی CircleCI و نوشتن یک پرونده YAML انجام می شود. البته ، اگر به میزبانی خود نیاز دارید ، گزینه هایی نیز وجود دارد.

۵- قابلیت استفاده از API :

شما می توانید برای پروژه های خود از API های circleci جهت trigger job ها استفاده کنید. همچنین برای پارامترها و آرگومان ها نیز API ارایه می دهدو این قابلیت برای پروژه های بزرگ و اپلیکیشن های حجیم بسیار کاربردی می باشد.

۶- تجربه کاربری عالی:

من تصور نمی کنم که CircleCI هر طراح UI/UX را استخدام کرده باشد ، زیرا استفاده از این برنامه بسیار دلپذیر است. به خوبی کنترل می شود ، سریع است … ویژگی ها و تنظیمات گرافیکی هستند. همه چیز همان جایی است که انتظار دارید باشد ، حتی اگر قبلاً هرگز از آن استفاده نکرده باشید.

خب تا بدینجا توضیحاتی راجب circleci دادیم و حالا بپردازیم به پیاده سازی یک پروژه ساده با استفاده از CircleCi

ساخت اولین پروژه CircleCi :

قدم اول:

ایجاد یک ریپازیتوری جهت استفاده از circleci و تصمیم گیری جهت استفاده درست از فرایند Ci/Cd جهت پیاده سازی آن.

قدم دوم:

نوشتن اولین قسمت از کانفیگ هر پروژه ای که در circleci ایجاد میشود نیازمند این است که یک دایرکتوری circleci در روت پروژه ایجاد کنیم. سپس داخل آن پوشه فایلی با نام config.yml خواهیم داشت که پیکربندی اصلی circleci در آن قرار گرفته است. برای نمونه جهت ایجاد و پیکربندی مراحل زیر را می رویم:

git clone https://github.com/Static-Void-Academy/circleci-hello
cd circleci-hello
mkdir .circleci
touch .circleci/config.yml
nvim .circleci/config.yml # Replace nvim w/ whatever you use

همه circleci config ها با نام version آغاز می شود. زیرا در بعضی ورژن ها قابلیت های متفاوتی عرضه می شود. که تاکنون ورژن ۱ دیگر پشتیبانی نمیشود.

در ادامه ما مفهومی داریم تحت عنوان job که به عنوان parent-level در ساختار yaml استفاده میشود و تمامی دستورات دیگر در زیرمجموعه job تعریف می شوند. برای مثال ما یک job تحت عنوان build تعریف می کنیم.

version: 2
jobs:
 Build:

داخل build شما نیازمند این هستید که نوع excuter خود را مشخص نمایید. در circleci ما جهار نوع excuter داریم که شامل:

Within Docker images (docker)
Within a Linux virtual machine (VM) image (machine)
Within a macOS VM image (macOS)
Within a windows VM image (windows)

برای نمونه اگر بخواهیم اولین پروژه ساده خود را با زبان Go با excuter داکر پیاده سازی کنیم کانفیگ زیر را ایجاد می کنیم:

version: 2
jobs:
 build:
   docker:
     - image: circleci/golang:1.11.1
   working_directory: /go/src/github.com/Static-Void-Academy/circleci-hello

در داخل هر job ، مراحلی وجود دارد که شما تعریف می کنید. این دستورات تک خطی هستند که برای دستیابی به اهداف شما اجرا می شوند. بسیاری از job ها با بررسی کد شروع می شوند ، کاری که ما انجام خواهیم داد. پس از بررسی کد ، ما همچنین یک مرحله اجرای ساده را تعریف خواهیم کرد که به سادگی ‘hellow world’ را چاپ می کند. Step هایی که داخل job تعریف می شوند shell script ساده می باشند.

version: 2
jobs:
 build:
   docker:
     - image: circleci/golang:1.11.1
   working_directory: /go/src/github.com/Static-Void-Academy/circleci-hello
   steps:
     - checkout # Checks out the source code
     - run: echo "Hello World!"

حال همه چیز تمام است و پس از اعمال تغییرات فرایند cicd اجرا خواهد شد که در مرحله بعد خواهیم دید.

قدم سوم آغاز کار circleci:

به صفحه رسمی سایت circleci مراجعه کرده و ثبت نام میکنیم پس از ایجاد اکانت جهت متصل کردم ریپو خود به circleci همانند شکل زیر عمل میکنیم: circle2 برای نمونه ما از ورژن کنترل github جهت اعمال تغییرات استفاده می کنیم. پس از آن صفحه مطابق شکل زیر نمایان می شود که باید ریپوزیتوری که تغییرات را اعمال کردین جهت فرایند cicd به circleci بدهید. circle3 برای این پروژه چون ما از زبان Go و سیستم عامل لینوکس استفاده می کنیم مطابق شکل زیر عمل میکنیم: circle4 بعد از اینکه start build را در مرحله سوم بزنیم عملیات ما آغاز می شود و job ها اجرا میشوند که اگر به job ها برویم روند pipeline ها در صورت خطا یا موفق بودن را مشاهده خواهیم کرد. circle4 همانند شکل عملیات موفقیت آمیز بود و circleci ما به درستی کار کرد. اما این پروژه خیلی ساده بود و مفید نیست لذا بریم که قسمت های مهمی که circleci دارد را باهم بررسی کنیم.

قدم جهارم تغییرات config.yml و ایجاد یک artifact :

عموما وقتی از پروژه های بزرگ و پیچیده صحبت میکنیم. ما از job های زیادی برای انجام کارهای متفاوت استفاده می کنیم. با اینکه پروژه استفاده شده ما در مثال بالا ساده است لذا ما این کار را فقط برای نشان دادن عملکرد این فرآیند انجام می دهیم.

version: 2
jobs:
 build:
   docker:
     - image: circleci/golang:1.11.1
   working_directory: /go/src/github.com/Static-Void-Academy/circleci-hello
   steps:
     - checkout # Checks out the source code
     - run: go get -d ./...
     - run:
         name: Build the executable
         command: |
           echo "Other important command here as example"
           go build           
     - store_artifacts:
         path: ./circleci-hello # executable

با توجه به کانفیگ بالا اگر بخواهیم از شل اسکریپت در job خود استفاده کنیم با فرمت run: value آن را می نویسیم اما اگر مراحل پیچیده تری استفاده می کنید مطابق دستور بالا یک نام برای آن تعریف کرده و مراحل را در آن وارد می کنیم.

قدم پنجم تغییرات config.yml جهت اجرا چند job متفاوت:

در مثال های قبلی ما بر روی یک job کار می کردیم اما در پروژه هایی با مقیاس بزرگتر نیازمند استفاده از چند job هستیم که فرایند های متفاوت را مثل build , test , deploy را برای ما انجام دهد. طبق مثال زیر ما یک job جدید تحت عنوان test برای نمونه اضافه کردیم:

version: 2
jobs:
 build:
   docker:
     - image: circleci/golang:1.11.1
   working_directory: /go/src/github.com/Static-Void-Academy/circleci-hello
   steps:
     - checkout # Checks out the source code
     - run: go get -d ./...
     - run:
         name: Build the executable
         command: |
           echo "Other important command here as example"
           go build           
     - store_artifacts:
         path: ./circleci-hello # executable
 test:
   docker:
     - image: circleci/golang:1.11.1
   working_directory: /go/src/github.com/Static-Void-Academy/circleci-hello
   steps:
     - checkout # Checks out the source code
     - run: go get -d ./...
     - run: go test

شاید متوجه شده باشید … ما در حال تعریف دایرکتوری و داکر ایمیج مشترک جهت اتصال و کار برای هر دو job هستیم. آیا این کار بیهوده نیست؟

توجه: هر job که در کانفیگ فایل تعریف میکنیم در یک کانتینر جدید و متفاوت اجرا می شود حتی اگر هر دو job برای یک ریپازیتوری مشابه و Docker Image مشترک باشند.

اگر بخواهید فایل هایی را بین job ها به اشتراک بگذارید نیازمند استفاده از workspace ها هستید. شکل زیر را مشاهده کنید. circle6 جهت استفاده از این کار از persist_to_workspace در کانفیگ فایل استفاده میکنیم که خود شامل دو پارامتر root , paths می باشد که در root مسیر working_directory را مشخص می کنیم و در paths فایل یا الگو را مطابقت می دهیم.

طبق کانفیگ زیر ما از یک دایرکتوری مشترک بر روی دو job استفاده کردیم و بر روی یکی از job ها artifact را پیاده سازی کردیم.

version: 2
jobs:
 build:
   docker:
     - image: circleci/golang:1.11.1
   working_directory: /go/src/github.com/Static-Void-Academy/circleci-hello
   steps:
     - checkout # Checks out the source code
     - run: go get -d ./...
     - run:
         name: Build the executable
         command: |
           echo "Other important command here as example"
           go build           
     - persist_to_workspace:
         root: . # Persist current working directory
         paths: ./* # Glob. Will persist everything in folder
     - store_artifacts:
         path: ./circleci-hello # executable
test:
   docker:
     - image: circleci/golang:1.11.1
   working_directory: /go/src/github.com/Static-Void-Academy/circleci-hello
   steps:
     - attach_workspace:
         at: .
     - checkout # Checks out the source code
     - run: go get -d ./...
     - run: go test

مطابق دستورات بالا در مسیر ذکر شده باید فایل های مشترک را مشاهده خواهید کرد. اما موردی که هست فرایند build اجرا خواهد شد اما فرایند test اجرا نمیشود و عملا cicd دچار مشکل خواهد شد. علت چیست؟

توجه: به صورت پیش فرض circleci فقط به دنبال job با نام build می گردد و آن را اجرا میکند. اگر ما job دیگری تعریف کرده باشیم نیازمند این هستیم که این job را به circleci بفهمانیم پس با دستوری تحت عنوان workflows آشنا می شویم.

قدم ششم تعریف workflows بر روی تمامی job ها :

بیایید مجددا به دیاگرامی که قرار داده شده است نگاهی بیندازیم. circle6 همانند دیاگرام روند کاری job ها بدین صورت که اول عملیات build سپس test و درنهایت deploy صورت پذیرد را workflowes در circleci مدیریت می کند.

با اضافه کردن workflows در فایل کانفیگ شما می توانید روند اجرا job هارا تعیین کنید. برای نمونه داریم:

... # rest of file above
workflows:
 version: 2
 build_test:
   jobs:
     - build
     - test

در بالاترین قسمت version آن را مشخص میکنیم سپس در خط بعدی نامی برای workflows خود انتخاب میکنیم. در نهایت ترتیب اجرا job ها را مشخص میکنیم.

طبق کانفیگ بالا هر دو job به صورت موازی اجرا می شوند و فقط اولویت اجرا با job می باشد که بالاتر است. اما اگر بخواهیم مطابق دیاگرام job را اجرا کنیم به شرط اینکه job قبلی اجرا شده باشد از کانفیگ زیر در بخش workflows استفاده میکنیم.

... # rest of file above
workflows:
 version: 2
 build_test:
   jobs:
     - build
     - test:
         requires:
           - build

بدین ترتیب test job تا زمانیکه build job با موفقیت به اتمام نرسد اجرا نمی شود. بنابر این ساختار فایل کانفیگ ما بدین صورت خواهد شد.

version: 2
jobs:
 build:
   docker:
     - image: circleci/golang:1.11.1
   working_directory: /go/src/github.com/Static-Void-Academy/circleci-hello
   steps:
     - checkout # Checks out the source code
     - run: go get -d ./...
     - run:
         name: Build the executable
         command: |
           echo "Other important command here as example"
           go build           
     - persist_to_workspace:
         root: . # Persist current working directory
         paths: ./* # Glob. Will persist everything in folder
     - store_artifacts:
         path: ./circleci-hello # executable
test:
   docker:
     - image: circleci/golang:1.11.1
   working_directory: /go/src/github.com/Static-Void-Academy/circleci-hello
   steps:
     - attach_workspace:
         at: .
     - checkout # Checks out the source code
     - run: go get -d ./...
     - run: go test
workflows:
 version: 2
 build_test:
   jobs:
     - build
     - test:
         requires:
           - build

عملیات تمام است و حالا می توانید وضعیت job های خود را در circleci مشاهده کنید. circle7

منبع:

https://circleci.com