راه اندازی Gitlab CI/CD از صفر تا صد

این روز ها با داغ شدن فضای startup ها خیلی از developer ها دور هم جمع شدند و دارند روی یک ایده کار میکنند تا در نهایت به یک اپلیکیشن برسند . یکی از معضلاتی که سال ها پیش برای developer هایی که به صورت تیمی کار می کردند وجود داشت این بود که مدیریت source پروژه کار بسیار سختی بود و حتی source ها رو با flash جا به جا میکردند اما با بالا رفتن سرعت اینترنت و رشد تکنولوژی ، source control ها مطرح شدند و همون طور که امروز نگاه میکنیم سایت هایی مثل Gitlab و Github این روزها با استفاده از version control گیت (git) به راحتی این مشکل رو برای همه حل کردند ، مخصوصا این روز ها که Github هم با اضافه کردن امکان ساخت private repository برای کاربران غیر premium فضای کار رو رقابتی تر کرده و developer ها در هرجای دنیا میتونن بدون هیچ مشکلی source ها رو در اختیار داشته باشن و روشون کار کنند بدون اینکه هیچ نگرانی وجود داشته باشه.

اما یکی دیگه از مشکلات تیم ها روند نسخه گذاری هست که یه جورایی کار روتین و وقت گیری محسوب میشه . اینجاست که کمپانی های بزرگ به این فکر افتادن که چجوری میشه روال نسخه گذاری رو راحت تر کرد ، که اینجا نقطه تولد Continuous Integration and Continuous Delivery یا همون CI/CD هست.

در واقع CI/CD میاد source و روال build شما رو با هم integrate می کنه و در نهایت اون رو به محیط production شما deliver می کنه

به زبان ساده اگر بخوام بگم CI/CD روال نسخه گذاری رو automatic میکنه . فرض کنید اپلیکیشنی دارید که به تازگی بالا اومده و یک سری مشتری دارن باهاش کار میکنند . حالا اگه روال نسخه گذاریتون وقت گیر باشه و یه باگی هم توی سیستم به وجود بیاد ، چقدر روال توسعه و پشتیبانی سیستم برای رفع مشکلات به وجود آمده میتونه ترسناک باشه

یا این طور در نظر بگیرید که اون نفری از تیمتون که عملیات نسخه گذاری رو بلد بوده و همیشه انجام میداده نیست و شما هم بهش دسترسی ندارید حالا باید چی کار کنیم؟

با استفاده از CI/CD به راحتی میتونید این کار رو انجام بدید . فرض کنید مشکل رو درست کنید و commit کنید و تنها برای نسخه گذاری ، داخل source control خودتون login کنید و یک دکمه رو فشار بدید و چند دقیقه بعدش اپلیکیشنتون با آخرین تغییرات روی سرور آماده بهره برداری باشه

توی این نوشته من نحوه راه اندازی gitlab Ci/CD ، روی یک پروژه جاوایی رو آموزش میدم و امیدوارم که بتونید ازش استفاده کنید

توجه : برای متوجه شدن مفاهیم این متن ، آشنایی با داکر و مفاهیم آن الزامی است و برای کمک میتونید به این پست مراجعه کنید

آشنایی با Docker از نصب تا راه اندازی

با یک مثال سعی میکنم مفاهیم رو شفاف تر توضیح بدم تا بهتر متوجه بشید.



مثال

من یک اپلیکیشن جاوایی دارم که در نهایت قراره یک war فایل بشه . پس اولین قدم ما ، ساختن یک image داکری از روی war فالمون محسوب میشه.

قطعا اپلیکیشن ما یک دیتابیس داره که به کمکش داریم اطلاعات مورد نیازمون رو در اون ذخیره میکنیم. من توی این مثال از دیتابیس mysql استفاده میکنم ، پس قدم بعدی ساخت یک image از دیتابیس محسوب میشه که این بخش هم کار راحتی هست و خود mysql توی dockerhub ایمیج و نحوه استفاده اش رو قرار داده که لینک اش رو اینجا قرار میدم

ایمیج mysql

حالا برای اجرا کردن این image های ساخته شده نیازمند یک فایل docker-compose.yml هستیم که بتونیم داخل اون image های اپلیکیشن و دیتابیسی که ساختیم رو اجرا کنیم.

بهتر این است که خود mysql هم توی یک mysql-compse.yml ای باشه به صورت جداگانه و توی docker-compose اصلی مون docker-compose مربوط به mysql رو extend کنیم ، که در ادامه نحوه این کار رو توضیح میدم.

پس همون طور که گفتم دو تا container خواهیم داشت یکی برای application اصلی و یکی هم برای mysql


حالا اینطور در نظر بگیرید که اگر به دنبال build کردن اپ خودتون باشید ، قطعا باید آخرین نسخه اپلیکیشن رو از سورس کنترل خودمون که کدها رو اونجا کامیت کردیم ، دریافت کنیم.

پس در ادامه به این شکل میریم جلو که شما از gitlab به عنوان source control استفاده میکنید و یه سرور cloud یا vps هم گرفتید که میخواین اپکلیکیشن خودتون رو اونجا اجرا کنید.

اگر بخوام دقیق تر بگم باید دستور docker-compose up -d که از روی یک image یک container میسازده و اون رو start میکنه باید توی سرورمون اجرا بشه . پس اولین سوالی که مطرح میشه اینه که سرورمون قراره این ایمیج رو از کجا بیاره ؟

در واقع همون طور که وقتی میخوایم یه داکر ایمیج از روی mysql بسازیم ، اون رو از dockerhub میگیریم یا اصطلاحا pull کنیم. اینجا هم باید بپذیریم که image مربوط به اپلیکیشن ما باید یه جایی push بشه تا ما روی سرورمون بتونیم اون رو pull کنیم و اجراش کنیم.

توضیحات بالا سناریو کلی بود که برای انجام automatic نسخه گذاری باید انجام بدیم


برمیگردیم به gitlab که source countrol ماست . gitlab میگه که من میتونم به شما CI/CD ارائه بدم و در قالب یک سری stage بیام source شما رو بخونم و بسته به نوع پروژه ، مثلا اگر جاوایی هست با maven بیلد رو انجام بدم .

خود گیت لب برای اینکه بتونه این کار رو انجام بده داره از مکانیزم داکر استفاده میکنه ، یعنی داخل خودش یک سری container های داکری رو داره اجرا میکنه

پس برای اینکار از یک فایل به اسم 'gitlab-ci.yml.' استفاده میکنه که در اون stage های مختلف رو میخونه و اجرا میکنه .

این stage ها در واقع مراحل انجام کار هستند مثلا اولین مرحله build کردن ، دومین مرحله ساخت image و سومین مرحله اجرا ، روی سرور ما است.

مکانیزم گیت لب به این شکل هست که وقتی یک stage اجرا میشه و complete میشه همه چیزش پاک میشه یعنی یه جورایی هر stage یک temp محسوب میشه. که در ادامه میگم که این به چه معنی هست و برای ارتباط برقرار کردن بین این stage ها و دل و بدل کردن دیتا چه کار هایی رو باید انجام بدیم.


پایپ لاین ها (Pipelines)
یک pipeline مجموعه ای از job هایی هست که در قالب چندین stage اجرا میشن و از طریق منو pipeline قابل دسترسی هستند. اگر تمامی job ها با موفقیت اجرا بشن ، pipeline به stage بعدی میره اما اگه یکی از job ها fail بشه ، pipeline همونجا متوقف میشه

در عکس زیر عکس یک pipeline رو مشاهده میکنید که متشکل از چهار stage هست که هر کدوم حداقل یکی یا بیش از یک job دارن




لایبراری

اگر library ندارید لازم به خوندن این بخش نیست

خب بزارین قبل شروع ساختار پروژه رو باز کنم . فرض کنید که ما یک library داریم که یک پروژه maven ای هست و کانفیگ های اصلی پروژمون و یک سری مدل های base که ممکنه توی تمامی اپ هامون مشترک باشه رو اونجا قرار دادیم . مثل تنظیمات spring boot و spring security و مدل هایی مثل user و …

خب تا قبل از این چی کار میکردیم ؟

لایبراریمون رو با maven goal زیر اجرا میکردیم تا بره و توی پوشه m2. قرار بگیره و اون رو به عنوان یک dependency به فایل pom.xml پروژه مون اضافه میکردیم تا ازش استفاده کنیم.

clean package install

اما حالا که قراره تمام این کار ها رو gitlab برامون انجام بده پس باید لایبراریمون رو توی یک maven repository که به صورت private باشه قرار بدیم تا gitlab هم بتونه به اون دسترسی داشته باشه.

پس توی پروژه لایبراریمون یه فایل gitlab-ci.yml. داریم که تنها یک stage داره و اون هم build هست و قراره که وقتی تغییری روی library انجام میدیم و کامیت میکنیم ، gitlab اون رو build کنه و روی mymavenrepo که یک maven repository شخصی به ما ارائه میده deploy کنه.

پس میریم توی mymavenrepo یک اکانت درست میکنم. برای اینکه بتونیم توی یه repository عملیات deploy انجام بدیم باید یه url و یک user,pass داشته باشیم تا ازش استفاده کنیم

حالا برای بیلد کردن پروژه نیازمند maven هستم و اینجا هم base image من maven ای هست و دستورات maven رو میشناسه .

حالا میخوام deploy کنم ولی سوال اینجاست که به کدوم آدرس؟

یا باید برم داخل pom.xml بزارم یا توی settings.xml مربوط به m2 توی maven

اما بحث اینجاست که m2 باید توی محیط اجرا باشه ( یعنی توی سرورم ) پس میتونم کنار source خودم یه directory بسازم به اسم m2. و به maven از طریق settings.xml میگم که دایرکتوری maven من اینجاست . در واقع من آدرس default رو تغییر میدم به این دایرکتوی که تو روت پروژه ام ساختم.

Settings.xml

<settings>
    <profiles>
        <profile>
            <id>myMavenRepoRead</id>
            <activation>
                <property>
                    <name>!doNotUseMyMavenRepo</name>
                </property>
            </activation>
            <properties>
                <myMavenRepoReadUrl>https://mymavenrepo.com/repo/sampleUrl/</myMavenRepoReadUrl>
            </properties>
        </profile>
        <profile>
            <id>myMavenRepoWrite</id>
            <activation>
                <property>
                    <name>!doNotUseMyMavenRepo</name>
                </property>
            </activation>
            <properties>
                <myMavenRepoWriteUrl>https://mymavenrepo.com/repo/sampleUrl/</myMavenRepoWriteUrl>
            </properties>
        </profile>
    </profiles>

    <servers>
        <server>
            <id>myMavenRepoRead</id>
            <username>test</username>
            <password>test</password>
        </server>
        <server>
            <id>myMavenRepoWrite</id>
            <username>test</username>
            <password>test</password>
        </server>
    </servers>
</settings>

حالا برای اجرا کردن دستورات maven یا باید بریم اون رو توی ماشینمون نصب و config کنیم ، یا میتونیم دو تا فایل mvnw.sh و bat رو به root پروژه اضافه کنیم.

کار این دو فایل این هست که دستورات maven رو میشناسند ، پس این دو تا فایل هم به root پروژه library اضافه میکنیم که این نگرانی رو نداشته باشیم که توی ماشینمون maven نصب هست یا نه

خب پس حالا باید library رو بیلد کنیم که در نهایت میشه یه jar file و اون رو توی mavenrepo که بالاتر گفتم قرار میده و میتونیم ازش استفاده کنیم.

این هم کد مربوط به gitlab-ci.yml. فریم ورک

.gitlab-ci.yml

image: maven:latest

variables:
  MAVEN_CLI_OPTS: "-s .m2/settings.xml --batch-mode"
  MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"

cache:
  paths:
    - .m2/repository/
#    - target/

build:
  stage: build
  when: manual
  script:
    - mvn $MAVEN_CLI_OPTS deploy

وقتی when:manual رو مینویسیم این قابلیت رو به شما میده که برید داخل gitlab و از منوی CI/CD>Pipelines خودتون به صورت دستی دکمه استارت رو بزنید ، که توی عکس زیر مشخصه

خب الان مرحله library تموم شد پس میرسیم به اپلیکیشن خودمون . خب قطعا توی اولین مرحله build به dependency لایبراری که ساختیم ، نیاز داریم ، پس باید بهش بفهمونم که باید از کجا dependency پروژه رو بگیره

پس توی پروژه مون دوباره دایرکتوری m2. و settings.xml رو قرار میدم تا متوجه بشه که از کجا باید dependency رو دانلود کنه.

بخش مربوط به library تموم شد میتونید از اینجا به بعد رو ادامه بدید

استیج ها


حالا برمیگردیم روی اپ خودمون ، که در اینجا ما قرار بود ۳ تا stage داشته باشیم

  1. Build
  2. Build docker image
  3. Deploy

یه نکته ای که باید بدونیم اینه که gitlab به ازای هر کدوم از این stage ها یک container میسازه ، یعنی توی مثال ما ، ۳ تا container داریم که به ترتیب اجرا میشن.

همونطور که بالا تر گفتم هر کدوم از این container های داکری وقتی کارشون تموم میشه dispose میشن و ما دیگه بهشون دسترسی نداریم.

پس سوال اصلی اینجاست که ما توی stage اول که داریم پروژه رو build میکنیم و به یک war file میرسیم و بعدش قراره توی stage دوم از روش یه docker image بسازیم ، چجوری قراره توی stage دوم از war فایلی که توی stage اول ساخته شده استفاده کنیم ؟ اون که dispose شده ؟؟؟

اینجا gitlab از یک مفهوم به اسم artifact استفاده میکنه و میگه اگر قراره بین این stage ها فایلی رد و بدل بشه باید از طریق artifact به من بگی

نحوه کارش اینجوری هست که gitlab برای خودش یک دایرکتوری داره که artifact ها رو به ازای jobId ها store میکنه و قبل از اینکه کار stage تموم بشه توی log میبینید که میزنه upload artifact و بعد از success شدن stage میبیند که وقتی میخواد stage بعدی رو شروع کنه اول میزنه download artifact و بعد ادامه مراحل رو پیش میگیره.


استیج اول (build)

بخش اول فایل gitlab-ci.yml.

.gitlab-ci.yml

image: openjdk:8-jdk-alpine

variables:
    DOCKER_HOST: tcp://docker:2375
    MAVEN_CLI_OPTS: "-s .m2/settings.xml --batch-mode"
    MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"

services:
  - docker:dind

stages:
  - build
  - build-image
  - deploy-ssh


build:
  stage: build
  when: manual
  before_script:
  - apk update
  - apk add --nocache git
  - apk add --update nodejs nodejs-npm && node -v
  - apk add maven && mvn --version
  - npm install -g yarn
  - yarn --version
  - npm install -g @angular/[email protected]
  script:
        - './mvnw  $MAVEN_CLI_OPTS package '
  only:
    - master
  artifacts:
    expire_in: 10 mins 0 sec
    paths:
        - target/app.war
        - target/Dockerfile
  • خب من از openjdk alpine به عنوان base image استفاده کردم که خودش یک لینوکس light weight داره و jdk روش کانفیگ شده که دستور java -jar رو برای اجرای پروژه بشناسه
  • توی بخش variables متغیر های مربوط به maven و docker host رو اضافه کردم که بسته به نوع تکنولوژی ها و زبان برنامه نویسی که استفاده میکنید این کانفیگ ها میتونه متفاوت باشه
  • توی بخش services گفتم که از سرویس docker in docker استفاده کنه چون در حقیقت این container هایی که داره توسط gitlab ساخته میشه باید وقتی اجرا میشن و میان بالا به صورت پیشفرض docker داخل container اش نصب باشه تا بتونن دستوراتی مثل docker-compose up رو اجرا کنند
  • توی بخش stages ابتدا مشخص میکنیم که چند تا stage داریم که در اینجا ۳ تا هست و بعد به ترتیب اسم stage ها رو میگیم و مشخص میکنیم که توی هر stage باید چه کاری رو انجام بده.

خب در ابتدا stage : build رو توضیح میدم.

توی قسمت beforeScripts میتونم بگم که قبل از اینکه script من رو اجرا کنی یه سری کار ها رو انجام بده که در اینجا من node رو update کردم و yarn رو نصب کردم چون فریم ورک UI که استفاده میکردم angular بوده

  • توی بخش script گفتم که دستور maven build رو اجرا کنه تا war فایل پروژه ام ساخته بشه
  • توی قسمت only گفتم که دستور رو روی کدوم branch ای که روی گیت لب دارم اجرا کنه
  • توی قسمت artifacts توی بخش expire_in گفتم که حداکثر زمانی که این container اجازه داره زنده بمونه چقدره
  • و در نهایت توی قسمت paths بهش گفتم که دو فایل app.war و Dockerfile رو از مسیر های که مشخص کردم بردار و به عنوان artifact به stage بعدی بفرست

استیج دوم (build-image)

حالا وقتشه که از war file ای که ساختیم یک docker image بسازیم

شاید بپرسید که چرا باید این کار رو بکنیم

در جواب چرا باید بگم که راحتی کار کردن با docker

بزارید با یه مثال بهتر توضیح بدم فرض کنید که یه سرور لینوکسی گرفتین و میخواین روش یه war file رو اجرا کنید. اولین کار به روش سنتی اینه که روی لینوکس jdk نصب کنید بعد براش java home ست کنید و کلی داستانای دیگه یا مثلا قراره یه mysql نصب کنید که کار طاقت فرسایی محسوب میشه.

اما با داکر شما فقط کافیه که روی سرورتون یک بار داکر رو نصب کنید و دیگه همه این ها رو با دستورات کوتاهی از docker hub بگیرید (pull کنید) و استفاده کنید

خب در مرحله بعد سوال اینجاست که image ای که از روی war فایل من ساخته میشه باید کجا آپلود بشه تا توی سرورم بتونم اون رو pull کنم و از روش یه container بسازم و اجراش کنم؟

برای اینکار خود gitlab دارای یک docker registery مثل docker hub هست و image شما رو اونجا آپلود میکنه و توسط یک آدرس و user/pass گیت لب با اون ارتباط برقرار میکنید و اون رو pull میکنید

خب برای ساخت image از war file پروژه اول نیاز یه یک DockerFile هست

Dockerfile

FROM openjdk:8-jre-alpine
ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \
    JHIPSTER_SLEEP=0 \
    JAVA_OPTS=""
    
ADD *.war /app.war

EXPOSE 8080
CMD echo "The application will start in ${JHIPSTER_SLEEP}s..." && \
    sleep ${JHIPSTER_SLEEP} && \
    java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar /app.war

توی این فایل گفتم که base image من openjdk هست و یه سری متغیر داشتم که توی ENV مشخص کردم که میخواستم توی اجرا این متغیر ها رو بشناسه

توی add گفتم که war file من رو کپی کن توی root ایمیجی که داری میسازی و port 8080 رو هم باز کن برام و در نهایت این war فایل رو با دستور java -jar اجرا کن

بعد از اینکه image ما ساخته شد برای اینکه بتونیم اجراش کنیم نیاز به یه فایل docker-compose.yml داریم

Mysql.yml

version: '2'
services:
  mysql:
    image: mysql:5.7.22
    volumes:
      - /Users/hostDirectoryUrl/:/var/lib/mysql/
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=testDB
    ports:
      - 3306:3306
    command: mysqld --lower_case_table_names=1 --skip-ssl --character_set_server=utf8 --explicit_defaults_for_timestamp
  • اینجا گفتیم که base image ما mysql هست و توی volume گفتیم که آدرس var/lib/mysql که دیتا هامون داره اونجا ذخیره میشه رو توی سرورمون به یه آدرسی volume کنه تا هر بار که container ما stop میشه به هر دلیلی ، دیتا های DB رو از دست ندیم و وقتی دوباره container رو start میکنیم ، دیتا ها سر جای خودش باشه
  • توی environment رمز عبور دیتابیس رو دادم و گفتم که وقتی یک container میسازی از این دیتابیس ، یک دیتابیس به اسم testDB هم توش بساز
  • توی قسمت port گفتم که پورت default دیتابیس که 3306 هست رو به پورت 3306 توی سرور من (هاست من) map کن تا از این طریق به دیتابیس ام دسترسی داشته باشم
  • و در نهایت یک سری تنظیمات utf-8 و اینکه نام جداول با نام کوچیک باشه و …

docker-compose.yml

version: '2'
services:
    myApplication:
        image: registry.gitlab.com/testProject/testApp:latest
        environment:
          - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/testDB?useUnicode=yes&characterEncoding=UTF-8&characterSetResults=UTF-8&useSSL=false
          - JHIPSTER_SLEEP=120 # gives time for the database to boot before the application
        ports:
            - 80:8087
    mysql:
      extends:
        file: mysql.yml
        service: mysql
  • اینجا توی docker-compose اصلی هم گفتم که base image من اون image ای هست که بالاتر ساختیم و توی gitlab-registery آپلودش کردیم.
  • توی environments مهم ترین متغیری که استفاده شده spring_datasource_url هست که درواقع کارش اینه که کانتینر mysql رو که بالا ساختیم رو به کانتینر app ما وصل میکنه و اجازه میده که app ما توی پورت 3306 بتونه به دیتابیس ما دسترسی داشته باشه . در واقع یه راه ارتباطی بین کانتینر دیتابیس و کانتینر اپلیکیشن ایجاد میکنه
برمیگردیم به تنظیمات stage دوم
build-image:
  image: docker:latest
  stage: build-image
  when: manual
  script:
        - cd target
        - docker login registry.gitlab.com -u "yourGitlabUsername" -p "yourPrivateKey"
        - docker build --pull -t registry.gitlab.com/testProject/testApp:latest .
        - docker push registry.gitlab.com/testProject/testApp:latest
  only:
    - master
  artifacts:
    expire_in: 10 mins 0 sec
    paths:
        - target/app.war
        - target/Dockerfile
  • اینجا گفتیم که توی استیج build-image اول برو به مسیر target
  • بعد لاگین کن توی gitlab registery با username و key که gitlab در اختیارتون میزاره
برای گرفتن این token روی اکانتتون توی gitlab کلیک کنید و برید توی settings و بعد به قسمت access tokens برید و برای خودتون یه token جدید بسازید در نهایت یه کدی بهتون میده که ازش میتونید اینجا استفاده کنید

لینک راهنما برای ساخت private key

بعد image رو میسازه و درنهایت push میکنه توی gitlab registery و دوباره دو تا فایل war , Dockerfile رو میفرسته به stage بعدی


استیج سوم (deploy)

خب حالا میریم سراغ سرورمون اولین کاری که باید انجام بدیم اینه که باید روش docker نصب کنیم که این کار رو انجام میدیم

در مرحله بعد باید به یک شکلی وصل بشیم به gitlab و اون image ای که برامون ساخته رو بگیریم یا اصطلاحا pull کنیم.

خب برای اینکه درگیر مسائل versioning توی image نشیم بهترین کار اینه که توی این مرحله بگیم که اول برو image فعلی که روی سرور ازش یه container ساخته بودیم رو پاک کنیم

پس مراحل میشه به شکل زیر

  1. لاگین کنم به gitlab
  2. کانتینر فعلی روی سرور رو پاک کنم
  3. ایمیج فعلی روی سرور رو پاک کنم
  4. دوباره ایمیج جدید رو دانلود کنم
  5. و توسط docker-compose.yml اجراش کنم

حالا توی مرحله deploy اجرای دستور docker-compose up -d باید داخل سرور من اجرا بشه پس باید با یه مکانیزمی به gitlab بفهمونیم که وصل شو به سرور من و این دستور رو اونجا برای من اجرا کن

گیت لب یک امکان داره به اسم gitlab runner که درواقع میگه میتونی یه agent هایی برای من توی ماشینت نصب کنی و اون رو به من بشناسونی و بگی از جایی که من هستم (منظور داخل stage هست) به کدوم agent وصل بشم و دستوراتت رو اجرا کنم.

پس برمیگردیم دوباره به سرور خودمون و اونجا gitlab runner رو نصب میکنیم که نحوه نصب اش رو اینجا قرار میدم

آموزش نصب gitlab runner

بعد از نصب حالا باید وصل بشیم به gitlab runner که نحوه انجام این کار در لینک زیر هست ولی من خلاصه ای از اون رو در پایین توضیح میدم.

نحوه ساخت یک runner و وصل شدن به اون

  • در اونجا میگیم gitlab-runner register
  • بعد باید token مربوط به runner ای که ساختیم رو بهش بدیم
  • بعد میپرسه از چه نوعی هست که ما چون قراره فقط یه ssh بزنیم به ماشینمون ، پس نوع runner رو shell در نظر میگیریم.چون اینا همه دارن توی ماشین ما اجرا میشه و توی سرور ما هم همون طور که بالاتر گفتیم docker نصب هست ، پس در واقع فقط قراره یه سری shell script برای ما اجرا کنه
  • حالا gitlab-ci باید از یه جایی بفهمه که چجوری بره این stage رو حتما تو ماشین من اجرا کنه ، اینجا جایی که من وقتی داشتم runner تعریف میکردم یه tag بهش دادم (یعنی یک اسم برای runner ام تعریف کردم) تا از طریق اون tag گیت لب این مسئله رو متوجه بشه

این هم کد مربوط به stage سوم

deploy-ssh:
  stage: deploy-ssh
  when: manual
  script:
        - sudo docker login registry.gitlab.com -u "yourGitlabUsername" -p "yourPrivateKey"
        - sudo docker rm -f yourApplicationContainerName || true
        - sudo docker rmi registry.gitlab.com/testProject/testApp || true
        - sudo docker-compose  -f /usr/testProject/docker-compose.yml up -d || true
  only:
    - master
  tags:
    - testTagName

اگر براتون سوال شده که فایل docker-compose.yml از کجا پیداش شد باید بگم که توی فایل pom.xml پروژه ام تعریف کردم که هرچی فایل yml زیر پوشه rousource ام وجود داره رو موقع build کردن به زیر پوشه target کپی کنه .

اگر همه چیز به درستی config شده باشه به راحتی عملیات نسخه گذاریتون انجام میشه و دیگه لازم نیست نگران هیچ چیز باشید

امیدوارم این مطلب براتون مفید بوده باشه

در نهایت اگر به دنبال درک بهتر این مسائل هستید میتونید به لینک های زیر مراجعه کنید و همچنین اگر پروژه شما هم جاوایی هست ، برای کمک میتونید به jhipster هم سر بزنید

https://docs.gitlab.com/ee/ci/quick_start/

https://docs.gitlab.com/ee/ci/yaml

https://docs.gitlab.com/runner/install/linux-manually.html

https://docs.gitlab.com/runner/register/

https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html