<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>پست‌های انتشارات شرکت بهاران</title>
        <link>https://virgool.io/baharan-co/feed</link>
        <description>شرکت بهاران</description>
        <language>fa</language>
        <pubDate>2026-06-16 13:17:42</pubDate>
        <image>
            <url>https://files.virgool.io/upload/publication/5tagm5lbg2vf/pfblyn.png</url>
            <title>شرکت بهاران</title>
            <link>https://virgool.io/baharan-co</link>
        </image>

                    <item>
                <title>راه اندازی Gitlab CI/CD از صفر تا صد</title>
                <link>https://virgool.io/baharan-co/%D8%B1%D8%A7%D9%87-%D8%A7%D9%86%D8%AF%D8%A7%D8%B2%DB%8C-gitlab-cicd-%D8%A7%D8%B2-%D8%B5%D9%81%D8%B1-%D8%AA%D8%A7-%D8%B5%D8%AF-y7i07ifluivr</link>
                <description>این روز ها با داغ شدن فضای 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 های داکری رو داره اجرا میکنه پس برای اینکار از یک فایل به اسم &#x27;gitlab-ci.yml.&#x27; استفاده میکنه که در اون 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&lt;settings&gt;
    &lt;profiles&gt;
        &lt;profile&gt;
            &lt;id&gt;myMavenRepoRead&lt;/id&gt;
            &lt;activation&gt;
                &lt;property&gt;
                    &lt;name&gt;!doNotUseMyMavenRepo&lt;/name&gt;
                &lt;/property&gt;
            &lt;/activation&gt;
            &lt;properties&gt;
                &lt;myMavenRepoReadUrl&gt;https://mymavenrepo.com/repo/sampleUrl/&lt;/myMavenRepoReadUrl&gt;
            &lt;/properties&gt;
        &lt;/profile&gt;
        &lt;profile&gt;
            &lt;id&gt;myMavenRepoWrite&lt;/id&gt;
            &lt;activation&gt;
                &lt;property&gt;
                    &lt;name&gt;!doNotUseMyMavenRepo&lt;/name&gt;
                &lt;/property&gt;
            &lt;/activation&gt;
            &lt;properties&gt;
                &lt;myMavenRepoWriteUrl&gt;https://mymavenrepo.com/repo/sampleUrl/&lt;/myMavenRepoWriteUrl&gt;
            &lt;/properties&gt;
        &lt;/profile&gt;
    &lt;/profiles&gt;

    &lt;servers&gt;
        &lt;server&gt;
            &lt;id&gt;myMavenRepoRead&lt;/id&gt;
            &lt;username&gt;test&lt;/username&gt;
            &lt;password&gt;test&lt;/password&gt;
        &lt;/server&gt;
        &lt;server&gt;
            &lt;id&gt;myMavenRepoWrite&lt;/id&gt;
            &lt;username&gt;test&lt;/username&gt;
            &lt;password&gt;test&lt;/password&gt;
        &lt;/server&gt;
    &lt;/servers&gt;
&lt;/settings&gt;حالا برای اجرا کردن دستورات maven یا باید بریم اون رو توی ماشینمون نصب و config کنیم ، یا میتونیم دو تا فایل mvnw.sh و bat رو به root پروژه اضافه کنیم.کار این دو فایل این هست که دستورات maven رو میشناسند ، پس این دو تا فایل هم به root پروژه library اضافه میکنیم که این نگرانی رو نداشته باشیم که توی ماشینمون maven نصب هست یا نهخب پس حالا باید library رو بیلد کنیم که در نهایت میشه یه jar file و اون رو توی mavenrepo که بالاتر گفتم قرار میده و میتونیم ازش استفاده کنیم.این هم کد مربوط به gitlab-ci.yml. فریم ورک.gitlab-ci.ymlimage: maven:latest

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

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

build:
  stage: build
  when: manual
  script:
    - mvn $MAVEN_CLI_OPTS deploy
وقتی when:manual رو مینویسیم این قابلیت رو به شما میده که برید داخل gitlab و از منوی CI/CD&gt;Pipelines خودتون به صورت دستی دکمه استارت رو بزنید ، که توی عکس زیر مشخصهخب الان مرحله library تموم شد پس میرسیم به اپلیکیشن خودمون . خب قطعا توی اولین مرحله build  به dependency لایبراری که ساختیم ،  نیاز داریم ، پس باید بهش بفهمونم که باید از کجا dependency پروژه رو بگیرهپس توی پروژه مون دوباره دایرکتوری m2. و settings.xml رو قرار میدم تا متوجه بشه که از کجا باید dependency رو دانلود کنه.بخش مربوط به library تموم شد میتونید از اینجا به بعد رو ادامه بدیداستیج هاحالا برمیگردیم روی اپ خودمون ، که در اینجا ما قرار بود ۳ تا stage  داشته باشیم BuildBuild docker imageDeployیه نکته ای که باید بدونیم اینه که 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.ymlimage: openjdk:8-jdk-alpine

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

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 &amp;&amp; node -v
  - apk add maven &amp;&amp; mvn --version
  - npm install -g yarn
  - yarn --version
  - npm install -g @angular/cli@1.7.3
  script:
        - &#039;./mvnw  $MAVEN_CLI_OPTS package &#039;
  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 هستDockerfileFROM openjdk:8-jre-alpine
ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \
    JHIPSTER_SLEEP=0 \
    JAVA_OPTS=&quot;&quot;
    
ADD *.war /app.war

EXPOSE 8080
CMD echo &quot;The application will start in ${JHIPSTER_SLEEP}s...&quot; &amp;&amp; \
    sleep ${JHIPSTER_SLEEP} &amp;&amp; \
    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.ymlversion: &#039;2&#039;
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.ymlversion: &#039;2&#039;
services:
    myApplication:
        image: registry.gitlab.com/testProject/testApp:latest
        environment:
          - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/testDB?useUnicode=yes&amp;characterEncoding=UTF-8&amp;characterSetResults=UTF-8&amp;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 &quot;yourGitlabUsername&quot; -p &quot;yourPrivateKey&quot;
        - 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 ساخته بودیم رو پاک کنیم پس مراحل میشه به شکل زیرلاگین کنم به gitlabکانتینر فعلی روی سرور رو پاک کنمایمیج فعلی روی سرور رو پاک کنمدوباره ایمیج جدید رو دانلود کنمو توسط 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 &quot;yourGitlabUsername&quot; -p &quot;yourPrivateKey&quot;
        - 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/yamlhttps://docs.gitlab.com/runner/install/linux-manually.htmlhttps://docs.gitlab.com/runner/register/https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html</description>
                <category>شرکت بهاران</category>
                <author>mandi.nariman</author>
                <pubDate>Thu, 17 Jan 2019 16:20:57 +0330</pubDate>
            </item>
                    <item>
                <title>چگونه در هایبرنت cast رو به پائین انجام دهیم؟!</title>
                <link>https://virgool.io/baharan-co/%DA%86%DA%AF%D9%88%D9%86%D9%87-%D8%AF%D8%B1-%D9%87%D8%A7%DB%8C%D8%A8%D8%B1%D9%86%D8%AA-cast-%D8%B1%D9%88-%D8%A8%D9%87-%D9%BE%D8%A7%D8%A6%DB%8C%D9%86-%D8%A7%D9%86%D8%AC%D8%A7%D9%85-%D8%AF%D9%87%DB%8C%D9%85-qrdxohr2uify</link>
                <description>فرض کنید که تو دامنه مدل ما رابطه وراثت وجود داره و میخواهیم در یک کوئری هایبرنت کلاس پدر رو به کلاس های فرزند cast کنیم، اما چگونه؟در JPA 2.1 عملگر TREAT معرفی شد تا با استفاده از اون بتونیم عملیات cast رو به پائین رو انجام بدیم!فرض کنید که دامنه مدل های ما مربوط به نویسنده (Author) و انتشارات(Publication) است که انتشارات می تونه انواع مختلفی مثل کتاب(Book) و پست وبلاگ(BlogPost) داشته باشد. همونطور که مشخص هست تو این دامنه مدلها، کلاس انتشارات میتونه کلاس پدر و کتاب و پست و وبلاگ میتونن کلاس فرزند باشند.دامنه مدل های نویسنده و انتشارات حالا میخوام با اجرای یک کوئری و با استفاده از عملگر TREAT نویسندگانی که کتابی دارند که در ISBN آن عبارت 123 وجود دارد را پیدا کنیم.List&lt;Object[]&gt; result = em.createQuery( &quot;SELECT a, p
FROM Author a
JOIN a.publications p
WHERE treat(p AS Book).isbnNumber LIKE &#039;%123%&#039;&quot;).getResultList();البته از عملگر TREAT در قسمت select هم می تونیم استفاده کنیم. مثلا فرض کنید میخوایم محتوای پستهای یک نویسنده رو select کنیم:List&lt;String&gt; result = em.createQuery( &quot;SELECT treat(p AS Publication).postContent
FROM Author a
JOIN a.publications p
WHERE a.id = 1&quot;).getResultList();</description>
                <category>شرکت بهاران</category>
                <author>رسول غفاری</author>
                <pubDate>Thu, 27 Dec 2018 10:29:55 +0330</pubDate>
            </item>
                    <item>
                <title>نحوه استفاده از schema و catalog به صورت عمومی در کوئری های SQL و HQL</title>
                <link>https://virgool.io/baharan-co/%D9%86%D8%AD%D9%88%D9%87-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-schema-%D9%88-catalog-%D8%A8%D9%87-%D8%B5%D9%88%D8%B1%D8%AA-%D8%B9%D9%85%D9%88%D9%85%DB%8C-%D8%AF%D8%B1-%DA%A9%D9%88%D8%A6%D8%B1%DB%8C-%D9%87%D8%A7%DB%8C-sql-%D9%88-hql-aauoqmyhbnxo</link>
                <description>زمانی که ساختار پایگاه داده شما به صورتی است که از چندین شما استفاده می کنید، می توانید با استفاده از hibernate.default_schema در فایل مربوط به تنظیمات Hibernate از یک شمای کلی به عنوان شمای عمومی استفاده کنید:&lt;property name=&quot;hibernate.default_schema&quot; value=&quot;forum&quot;/&gt;هایبرنت با استفاده از کد فوق، در جاهایی که قصد اجرای کوئری HQL را دارید، شما مورد نظر را در تبدیل کوئری از HQL به SQL استفاده می کند. به مثال زیر توجه کنید:@Entity(name = &quot;Event&quot;)
@Table(name = &quot;event&quot;)
public class Event { 
    @Id
    @GeneratedValue
    private long id;

    private String name;
    
    @Column(name = &quot;created_on&quot;)
    private Timestamp createdOn;

    //Getters and setters omitted for brevity
}اگر قصد اجرای یک کوئری به صورت زیر داشته باشیم:List&lt;Event&gt; events = entityManager.createQuery(
    &quot;select e &quot; +
    &quot;from Event e &quot; +
    &quot;where e.createdOn &gt; :timestamp&quot;, Event.class)
    .setParameter(&quot;timestamp&quot;, Timestamp.valueOf(LocalDateTime.now().minusMonths(1)))
   .getResultList();هایبرنت با استفاده از تنظیمات تعریف شده نام شما را در کوئری SQL ای که تولید می کند، قرار می دهد. یعنی کوئری چیزی مشابه زیر می شود:SELECT e.id AS id1_0_,
       e.created_on AS created_2_0_,
       e.name AS name3_0_
FROM   forum.event e
WHERE  e.created_on &gt; &#039;2016-09-26 17:22:11.191&#039;اما اگر درجایی قصد اجرای کوئری به زبان SQL داشته باشیم باید چه کنیم؟ اگر کوئری را به شکل زیر تعریف کنیم:@NamedNativeQuery(
    name = &quot;past_30_days_events&quot;,
    query =
        &quot;select * &quot; +
        &quot;from event&quot; +
        &quot;where age(created_on) &gt; &#039;30 days&#039;&quot;,
    resultClass = Event.class
)و برای اجرای آن به صورت زیر عمل کنیم:List&lt;Event&gt; events = entityManager.createNamedQuery(&quot;past_30_days_events&quot;).getResultList();با خطای زیر مواجه خواهیم شد:javax.persistence.PersistenceException:
Caused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
Caused by: org.postgresql.util.PSQLException: ERROR: relation &quot;event&quot; does not existبرای حل این مشکل یک راه حل وجود دارد، اینکه هرجا که قصد اجرای کوئری های SQL را داریم، مستقیما به شما مورد نظر اشاره کنیم. یک راه حل هم این هست که این کار به هایبرنت بسپاریم. برای این کار کافی است به شکل زیر عمل کنیم:@NamedNativeQuery(
    name = &quot;past_30_days_events&quot;,
    query =
        &quot;select * &quot; +
        &quot;from {h-schema}event &quot; +
        &quot;where age(created_on) &gt; &#039;30 days&#039;&quot;,
        resultClass = Event.class
)با اینکار هایبرنت هنگام تولید کوئری SQL نام شما را به صورت اتوماتیک تولید می کند:SELECT * FROM
forum.event
WHERE  age(created_on) &gt; &#039;30 days&#039;بسیار عالی!!!نتیجه گیریاستفاده از شمای پیش فرض کار بسیار راحت می کند و تنها کافی این شما را در &#x60;hibernate.default_schema&#x60; مشخص کنیم. با اینکار کوئری های HQL به راحتی با شمای پیش فرض اجرا می شوند و برای کوئری های SQL نیز بایستی از ‍&#x60;{h-schema}&#x60; استفاده کنیم.</description>
                <category>شرکت بهاران</category>
                <author>رسول غفاری</author>
                <pubDate>Wed, 19 Dec 2018 21:01:39 +0330</pubDate>
            </item>
                    <item>
                <title>مشخصه های اصلی یک تراکنش ( ACID )</title>
                <link>https://virgool.io/baharan-co/%D9%85%D8%B4%D8%AE%D8%B5%D9%87-%D9%87%D8%A7%DB%8C-%D8%A7%D8%B5%D9%84%DB%8C-%DB%8C%DA%A9-%D8%AA%D8%B1%D8%A7%DA%A9%D9%86%D8%B4-acid-eflnyz1zrdyx</link>
                <description>تا حالا به این مساله فکر کردید که وقتی در مورد یک تراکنش صحبت می کنیم مشخصه های اصلی اون چه چیزهایی هستند ؟ یکی از مفاهیم مهم در سامانه های اطلاعاتی انجام یک تراکنش است . همه برنامه نویس هایی که در حال توسعه سامانه های اطلاعاتی هستند باید در مورد تراکنش و مشخصه های اصلی اون اطلاعات و آگاهی کامل داشته باشند . اصلا تعریف تراکنش چی هست ؟ یک تراکنش مجموعه ای از عملیات خواندن / نوشتن در سطح پایگاه داده است که تمامی این عملیات با هم ، دقت کنید همه با هم ، یا به موفقیت می رسند و یا در صورت خطا هیچ کدام از آن ها اجرا نمی شود .هر تراکنش برای اینکه نگرانی های ما رو در مورد امنیت و ثبات اطلاعات تامین کنه باید ۴ تا مشخصه داشته باشه : Atomicity ConsistencyIsolationDurability اتمیک بودن ( Atomicity )این ویژگی در تراکنش ها به همه یا هیچ  ( All or nothing ) معروف است ، در واقع تراکنش در صورتی موفق است که تمام دستوراتی که در آن اجرا می شوند موفق باشند و بر اساس این قاعده دیتابیس باید قادر باشد که در صورت عدم موفقیت دستور n ام ، تمامی دستورات قبلی را رول بک کند . توی این عکس دو تا تراکنش نشون داده شده اولی سه تا عملیات جمع رو انجام داده و هر سه موفق بودند و تراکنش با موفقیت به پایان رسیده و در تراکنش دوم عملیات تفریقی که انجام شده منجر به منفی شدن متغیر X شده و تراکنش به طور کلی حتی با موفق بودن عملیاتی که بر روی متغیر Z انجام شده به حالت قبلی برگردانده ( RollBack ) شده است . ثبات ( Consistency )یک تراکنش در واقع بایستی در هنگام تغییر وضعیت ، اطلاعات را از یک وضعیت صحیح به یک وضعیت صحیح دیگر ببرد .در این تغییر وضعیت دیتابیس هم سعی می کند که هیچ کدام از کلید ها و نوع های داده ای و Trigger ها نباید نقض شوند . برای درک بهتر مساله تصویری که برای توضیح ثبات (‌Atomicity) گذاشتم رو تکرار می کنم : در سطح دیتابیس به کمک یک  check constraint سعی شده از منفی شدن متغیر X جلوگیری بشه و  این اتفاق توی تراکنش موجب نقص این قاعده شده که دیتابیس از انجام ادامه کار جلوگیری کرده است . محرمانگی ( Isolation )مهم ترین مشخصه ی  یک تراکنش سطح محرمانگی آن است . ما می دونیم که اگر تنها یک کاربر به طور همزمان از دیتابیس استفاده کند نگرانی در مورد احتمال ایجاد مغایرت و آنومالی در اطلاعات نخواهیم داشت و اگر اجازه استفاده همزمان به کاربران جهت دسترسی به دیتابیس بدیم کارایی سیستم رو افزایش دادیم ، کاربر شماره یک با جدول یک کار می کند و کاربر شماره دو با جدول دو . اما دسترسی همزمان معضلاتی رو هم ایجاد می کند که دیتابیس بایستی جهت حل این موضوعات مسائل مختلفی در تراکنش ها مدیریت کند. سطح دسترسی یک تراکنش به تغییرات تراکنش های همزمان با خودش رو سطح محرمانگی اون تراکنش تلقی می کنند . دیتابیس این توهم رو برای ما ایجاد می کند که اگر دو کاربر به صورت همزمان و در یک لحظه به اطلاعات یک جدول جهت انجام تراکنش نیاز دارند ، این دو تراکنش قطعا پشت سر هم و یکی پس از دیگری اجرا می شوند و همزمان اجرا نخواهند شد .سطوح مختلف این سطح محرمانگی در دسترسی تراکنش ها به تغییرات یکدیگر بسیار مهم است . برای درک بهتر در نظر بگیرید که تراکنش شماره یک در حال بازیابی کارمندان یک سازمان برای به روز رسانی حقوق آنهاست ، دقیقا در همان لحظه در بخش نیرو انسانی و به واسطه تراکنش دوم فرد جدیدی به سازمان اضافه می شود آیا تراکنش اول بایستی به اطلاعات این فرد جدید دسترسی داشته باشد ؟ دیتابیس با مدیریت سطوح محرمانگی و با توجه به کسب و کار شما اجازه ی جدا سازی این تراکنش ها به نحوی که به اطلاعات یکدیگر دسترسی نداشته باشند دارد ، همین طور در طرف مقابل امکان ایجاد دسترسی را نیز در اختیار شما قرار داده است . دوام یا ماندگاری ( Durability ) یک تراکنش صحیح وقتی به پایان می رسد و با موفقیت در دیتابیس ثبت می شود، فقط توسط یک تراکنش صحیح دیگر قابل تغییر هست و در هیچ شرایطی از دیتابیس پاک نخواهد شد ،  همین طور این تراکنش هیچ کدام از قوانین را نقض نکرده است . در نظر بگیرید که شما در یک سیستم خرید بلیط هواپیما اقدام به خرید یک بلیط می کنید و عملیات پرداخت بانکی را انجام می دهید و اطلاعات مربوط به صندلی خود را چاپ می کنید ، دقیقا لحظه ای بعد از پرینت شما سامانه فروش بلیط هواپیما مربوط به خط هوایی مورد نظر دچار نقص فنی شده و از دسترس خارج می شود ، اطلاعات بلیط شما بعد از در دسترس قرار گرفتن مجدد این سامانه باید در دیتابیس حفظ شده باشد و توسط فرد دیگری قابل خریداری نباشد. مفاهیمی که در مورد ‌ACID توضیح دادم موضوع تازه ای نیست و Jim Gray خیلی وقت پیش از این که من به دنیا بیام تو این مقاله این موضوعات رو مطرح کرده بود ، من فقط سعی کردم مطالبی رو که حس می کنم تو این حوزه وقت گذاشتم و مطالعه کردم آروم آروم یه جایی جمع و منتشر کنم که شاید به درد بقیه برنامه نویس ها هم بخوره . امیدوارم که تنبلی نکنم و ادامه این موضوعات رو هم همین جا تو ویرگول بنویسم . </description>
                <category>شرکت بهاران</category>
                <author>محمد میرزائیان</author>
                <pubDate>Fri, 14 Dec 2018 02:39:26 +0330</pubDate>
            </item>
                    <item>
                <title>Angular 5 HttpInterceptor : show and hide loader</title>
                <link>https://virgool.io/baharan-co/angular-5-httpinterceptor-show-and-hide-loader-sww9adets54a</link>
                <description>اگر از افرادی باشید که در حال کار کردن روی یک پروژه انگیولاری هستند ، به احتمال زیاد به این مسئله برخوردین که بخواین در زمانی که سرور قرار جواب request های کاربر را بده ، یک loader نمایش بدین تا هم کاربر نتونه روی جای دیگه ای در صفحه کلیک کنه و هم حسی را به کاربر تلقین کنید که کار شما در حال انجام شدنه و تا چند ثانیه دیگه نتیجه مورد نظر خودتون رو میگیرید.مدت ها بود که به این مسئله فکر میکردم و میخواستم یک interceptor روی HTTP انگیولار بنویسم. پروژه ام روی انگیولار ۵ بود اما هنوز وقت نکرده بودم که پروژه ام رو از HTTP به HTTP Client ببرم و این خودش یک مشکل بزرگ بود و نوشتن interceptor روی HTTP تقریبا یک کار سخت و طاقت فرسا بود ، چون خود انگیولار براش این امکان را پیاده سازی نکرده بود و افرادی هم که این کار را کرده بودند با هزار trick این کار را انجام داده بودن و ظاهر جالبی نداشت و از اون طرف لایبراری های آماده ای هم که توی گیت هاب وجود داشت هیچ کدوم جواب گوی نیاز من نبودند. پس تصمیم گرفتم در مرحله اول پروژه را به HTTP Client ببرم چون نوشتن interceptor بر روی آن بسیار کار راحتی بود و خود انگیولار روش درست این کار رو recommend کرده بود .در ابتدا میخواستم خودم یک interceptor بنویسم و درون اون از یک لودر استفاده کنم که به محض اینکه request ها زده میشه اون لودر را نمایش بدم که با یک library خوب به اسم ng-http-loader آشنا شدم که اصلا نیازی به نوشتن interceptor هم نداشت و در واقع با استفاده ازش خودش این کار را براتون انجام میداد.میتونید demo این لایبراری را اینجا مشاهده کنیددر اینجا نحوه استفاده از این library  و مشکلی که خودم روی انگیولار ۵ باهاش داشتم و حل شد را براتون توضیح میدم و لینک github اش را در اینجا قرار میدممرحله اولاگر از انگیولار ۵ استفاده میکنید آخرین ورژن سازگار باهاش ۰.۹.۱ هست پس باید خط زیر را در فایل package.json پروژتون قرار بدین . باز هم تاکید میکنم که این لایبراری تنها در صورتی روی request هاتون کار میکنه که از HTTPClientModule استفاده کرده باشین.&quot;ng-http-loader&quot;:&quot;0.9.1&quot;,و بعدش یک بار npm install یا yarn install را بسته به package manager ای که استفاده میکنید را اجرا کنید تا فایل هاش به پوشه node_modules اضافه بشهمرحله دومداخل app.module تون در قسمت import کافیه که NgHttpLoaderModule را import کنید و در قطعه کد زیر به محلی که این ماژول را  import کردیم دقت کنید(منظورم آدرسش از پوشه node_modules هست).چون دقیقا اینجا نقطه ای بود که خودم مشکل داشتم و با سوالی که توی issue های پروژه زدم متوجه این نکته شدم و دوستان عزیز زحمت کشیدن و فایل readme مخصوص به این ورژن را (که سازگار با انگیولار ۵ بود) برام ارسال کردن که لینکش را اینجا قرار میدمقسمت هایی که باید شما به پروژتون اضافه کنید را با * نشانه گذاری کردمimport { BrowserModule } from &#039;@angular/platform-browser&#039;;
import { NgModule } from &#039;@angular/core&#039;;
[...]
import { AppComponent } from &#039;./app.component&#039;;
import { HttpClientModule } from &#039;@angular/common/http&#039;; &lt;============
import { NgHttpLoaderModule } from &#039;ng-http-loader/ng-http-loader.module&#039;; //******

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule, &lt;============ (Perform http requests with this module)
    NgHttpLoaderModule, //کافیه که این را اضافه کنید****
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }مرحله سومدر این مرحله کافیه که از&lt;spinner&gt; &lt;/spinner&gt; در app.component.html خود استفاده کنید و تمام ، مانند کد زیرimport {Component, OnInit, ViewContainerRef} from &#039;@angular/core&#039;;
import {LayoutService} from &quot;./shared/layout/layout.service&quot;;
import {Spinkit} from &#039;ng-http-loader/spinkits&#039;;

@Component({
    selector: &#039;app-root&#039;,
    template: `&lt;router-outlet&gt;&lt;/router-outlet&gt;
                &lt;spinner 
                    [backgroundColor]=&quot;&#039;#232f3e&#039;&quot;
                    [spinner]=&quot;spinkit.skThreeBounce&quot;
                    [debounceDelay]=&quot;10&quot;&gt;
                &lt;/spinner&gt;`
})
export class AppComponent implements OnInit {
    public title = &#039;app works!&#039;;
    public spinkit = Spinkit;
    
    public constructor(private viewContainerRef: ViewContainerRef,
                       private layoutService: LayoutService,
                       private http: HttpClient,) {
    }

    ngOnInit() {
    }
}
همینطور ثابت Spinkit را از آدرسی که در بالا مشخص شده ، import کنید تا بتونید شکل لودری که مشاهده میکنید را عوض کنید و همچنین یک سری property های دیگه هم داره که متونید آنها را تغییر بدید مثل عوض کردن رنگ و غیره امیدوارم که به کارتون بیاد.</description>
                <category>شرکت بهاران</category>
                <author>mandi.nariman</author>
                <pubDate>Thu, 12 Jul 2018 17:21:04 +0430</pubDate>
            </item>
                    <item>
                <title>آشنایی با Docker از نصب تا راه اندازی</title>
                <link>https://virgool.io/baharan-co/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-docker-%D8%A7%D8%B2-%D9%86%D8%B5%D8%A8-%D8%AA%D8%A7-%D8%B1%D8%A7%D9%87-%D8%A7%D9%86%D8%AF%D8%A7%D8%B2%DB%8C-ifn7wh4qiwjf</link>
                <description>آشنایی به زبان ساده  اولین نکته که باید مورد توجه قرار بگیره اینه که داکر هم مثل بقیه تکنولوژی ها تا وقتی که ازش دوریم خیلی سخت به نظر میاد اما وقتی شروع به کار کردن و مطالعه میکنیم ، میبینیم که چقدر ابزار کاربردی و راحتی است که در ادامه سعی دارم تمام سوالاتی که در ابتدا برای خودم مطرح بود رو در اینجا مطرح کنم و بهشون پاسخ بدم و در نهایت هم به عنوان یک مثال کاربردی نحوه بردن جئوسرور روی داکر که برای لود نقشه ها ، در فرمت های مختلف در سیستم جی آی اسی استفاده میشه رو باهم انجام بدیم.مشکلی که docker سعی میکند حل کند چیست ؟مشخصا داکر مشکلات زیادی را حل میکند اما یکی از مهم ترین آن ها improve consistency (بهبود ثبات یا استقرار ) میباشد وقتی گروهی از افراد روی یک پروژه کار میکنند ، میتونه تفاوت هایی در سیستم عامل ها و تنظیمات وجود داشته باشه که باعث بروز یک سری از مشکلات بشه و همچنین ممکنه در بالا آوردن اپلیکیشن روی کامپیوتر خودمون و محیط production (عملیاتی ) هم تناقضاتی وجود داشته باشه .تمامی اینها شما رو از حل کردن مشکلات اصلی که در حقیقت build کردن پروژه تون هست دور میکنه.چگونه docker کمک میکند تا مشکل بالا را حل کنیم؟داکر یه چیزی داره به عنوان container که مانند ماشین های مجازی لینوکس هستند با این تفاوت که اونها خیلی کارآمد تر هستند و منابع کمتری مصرف میکنند و اپلیکیشن شما رو در یک محیط (container) ایزوله و پایدار اجرا میکنه.کانتینر (container) که اپلیکیشن شما رو داخل خودش داره متونه روی ویندوز ، مک او اس و لینوکس اجرا بشه و همین قضیه مشکل دولوپر های مختلف با سیستم های عامل متفاوت را حل میکند.قابلیت docker برای ساحت و نگهداری محیطی استوار باعث portable شدن اپلیکیشن شما میشه.اما این container ها رو باید از کجا پیدا کرد ؟داکر یه جایی داره که شما میتونید خیلی از این container ها رو اونجا پیدا کنید و ازشون استفاده کنید به نام docker hub  که در زیر آدرس اون رو قرار میدم . البته توجه داشته باشید که داکر به آی پی ایران سرویس نمیده و برای نصب کردن و استفاده از docker hub باید از وی پی ان استفاده کنید.https://hub.docker.comتا زمانی که شما container مورد نظر خودتون رو بسازید میتونید از اینجا موارد مشابه ای رو پیدا کنید و سرعت ساخت اپلیکیشنتون رو بالاتر ببرید.نمونه هایی از container هایی که میتونید از داکر هاب  دانلود و استفاده کنید را در زیر نمایش میدهیمNode.js , MySQL , Ubuntoچگونه باید اپلیکیشن خودمون رو به یک container اضافه کنیم ؟زمانی که شما container مورد نظر خودتون رو پیدا کردید قطعا میخواهید اون رو customize کنید و dependency های خودتون رو بهش اضافه کنید . اینجا جاییه که Dockerfile میاد سر کار.داکر فایل (Dockerfile) به طور خلاصه توضیح میده که شما از داکر میخواین چطور برای بار اول container اتون رو بالا بیاره به عنوان مثال یک نمونه از Dockerfile رو در زیر براتون قرار میدم.# Use the official Node.js runtime as a base image
 FROM node:alpine# Set the directory of my web application to /app
 WORKDIR /app# Copy over my project’s directory into the container /app folder
 Add . /app# Install all the dependencies for my web application
 RUN yarn install# Make the port 3000 accessible outside of Docker
 EXPOSE 3000# Execute the command yarn start
 CMD [&quot;yarn&quot;, &quot;start&quot;]
این Dockerfile هر وقت که یک instance ازش ساخته بشه اجرا میشه . هنوز برای ساخت یک container شما نیازمند docker image هستید . هر وقت شما یک Image بسازید متوانید از روی اون به هر تعدادی که دلتون میخواد container  بسازید.در حقیقت شما از داکر هاب ایمیج های داکری آماده را دانلود میکنید که میتوانید به کمک آن ها هر تعداد container ای که لازم دارید را بسازید . همچنین میتوانید تنظیمات شخصی خود را بر روی کانتینری که ساخته اید اعمال کنید و دوباره از آن container یک Image جدید بسازید تا برای ساخت کانتینر هر بار نیازمند انجام تنظیمات قبلی نباشید و container های خودتون رو بر اساس Image جدیدی که ساخته اید ، تولید کنید.آیا من فقط به یک container برای کل اپلیکیشنم نیاز دارم ؟وقتی قابلیت ساخت کانتینر های مختلف وجود داره یک best practice اینه که بخش های مختلف اپلیکیشنمون رو ایزوله کنیم به container های مختلفبرا مثال فرض کنید یه وب اپلیکیشن که به یک دیتابیس و یک وب سرور پایتون نیازمنده به دو تا container نیازمنده . یکیش برای سرور پایتون و یکیشم برای دیتابیس شاید بپرسید چرا ؟ چون اداره اپلیکیشنتون رو ماژولار تر میکنه و اینکه وقتی در آینده اپلیکیشنتون رشد کنه یا گیر های ترافیکی داشته باشه شما میتوانید از چند تا instance از pyton server برای مدیریت ترافیک استفاده کنید.آیا مدیریت کردن چند تا container به صورت همزمان کار سختی نیست ؟دقیقا اینجا جاییه که داکر یه ابزار دیگه رو معرفی میکنه به عنوان docker compose . این ابزار به شما این امکان رو میده که میتونید کانفیگ container هایی که به هم مرتبط هستند رو در یک فایل yml مشخص کنید . یه فایل Docker-compose.yml به شکل زیر استversion: &#039;2&#039;
services:
  server:
    build: .
    ports:
     - &quot;3000:3000&quot;
    volumes:
     - .:/app
  database:
    image: &quot;mariadb:10.3&quot;
    environment:
     - MYSQL_ROOT_PASSWORD=MyPassword
     - MYSQL_DATABASE=MyDatabase
    ports:
     - &quot;3306:3306&quot;همین طور که در بالا مشاهده میکنید ما دو تا سرویس (container) داریم یکی به اسم server و یکی به اسم database که در اون متغیر ها و پورت ها و volume ها رو تعریف کردیم . وقتی فایل Docker-compose آماده میشه ، مدیریت گروهی از container ها که مربوط به یک اپلیکیشن هستند خیلی ساده میشه.ابزار هایی که بهتر است بشناسیدابزار Kitematic : به شما این امکان رو میده تا کانتینر های خودتون رو در یک محیط ویژوالی مدیریت کنید . شاید برای اولش که یک مقدار با محیط CLI آشنا نشدید گزینه خوبی باشهابزار Docker Swarm : وقتی اپلیکیشن شما بزرگ میشه شما ممکنه بخواین که چند تا container داشته باشین تا traffic شما رو هندل کنند. این ابزار باعث میشه مدیریت گروهی از container ها (clusters) در یک زمان ، کار ساده تری بشه  ساختار Docker داکر ساختاری server base داره و به زبان ساده این طور عمل میکنه که client دستورش رو به docker client میده و اون هم از طریق Docker Deamon(Dockerd) اجراش میکنه داکر شامل سه کامپوننت هست 1. Image2. Container3. RegisteriesDocker Imageبسته نرم افزاری هست که docker رو اجرا میکنه (اصولا container) ، image شامل تمامی فایل ها و library هایی است که برای اجرام نرم افزار به اون نیاز داریم و هر کسی میتونه image شخصی خودش رو از طریق Docker Client CLI بسازه . Docker Containerدر حقیقت یک instance از image هستند و نکته اینجاست که آنها نسبت یه host system کاملا ایزوله و مستقل از منابع نرم افزاری هستند.Docker Registeriesیک پلتفرمی هست که میزبان image های کاربران میباشد. هر کسی میتوه image های مورد نظرش رو push یا download کنه و حتی میتونید برای خودتون یا سازمانتون یک private registery تولید کنید.Docker Deamonاز هسته لینوکس استفاده میکنه و شاید به شما این باور رو بده که نمیشه روی OS های دیگه اجراش کرد اما به همین خاطر تیم docker ابزاری آماده کرده به عنوان Boot2Docker که شامل package های یک linux سبک هست که تمامی نیازمندی های Dockerd رو داره و به نحوی linuxVM داره در بالاترین سطح OS شما اجرا میشه تا Docker کارش رو انجام بده  نصب Docker CE (Community Edition)  در این بخش ما طریقه نصب داکر بر روی سیستم عامل ubunto را آموزش میدهیم  توجه داشته باشید که با توجه به لینک نصب میتوانید نحوه نصب بر روی تمامی سیستم عامل ها را مشاهده کنید.در اینجا ما نحوه نصب Docker CE از طریق repository را توضیح میدهیمنصب Repository1. در ابتدا پکیج apt رو آپدیت کنید$ sudo apt-get update2. نصب پکیج هایی که به شما اجازه میده از طریق HTTPS به repository  دسترسی داشته باشد و ازش استفاده کنید$ sudo apt-get install \    apt-transport-https \    ca-certificates \    curl \    software-properties-common3. اضافه کردن GPG Key رسمی داکر$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add –4.     از دستور زیر برای استفاده از stable repositories استفاده کنید$ sudo add-apt-repository \   &quot;deb [arch=amd64] https://download.docker.com/linux/ubuntu \   $(lsb_release -cs) \   stable&quot;نصب Docker CE1. دوباره پکیج apt  را آپدیت کنید$ sudo apt-get update2. آخرین نسخه Docker CE را نصب کنید$ sudo apt-get install docker-ceدستور بالا خودش آخرین ورژن رو میگیره ولی اگر بخواهیم ورژن خاصی رو نصب کنیم هم میتونیم از روش زیر استفاده کنیم$ apt-cache madison docker-ce        Result : docker-ce | 18.03.0~ce-0~ubuntu | https://download.docker.com/linux/ubuntu xenial/stable amd64 Packagesبا دستور بالا میتونیم ورژن های موجود docker رو ببینیم و با دستور زیر آن را نصب کنیمsudo apt-get install docker-ce=&lt;VERSION&gt;برای اینکه متوجه بشیم که Docker CE درست نصب شده ایمیج زیر را اجرا میکنیم$ sudo docker run hello-worldاین دستور در ducker hub به دنبال ایمیج hello-world  میگرده و در صورتی که در آنجا وجود داشته باشه آخرین ورژن اش رو دانلود میکنهنصب Geoserver  به کمک dockerنیاز به اجرای جئوسرور در محیط لینوکس و سختی نصب پلاگین هایی مانند gdal که برای لود عکس هایی با فرمت ecw استفاده میشود باعث شد تا برای اجرای جئوسرور ، از Docker کمک بگیرم در ادامه سعی میکنیم کلیه دستورات docker و linux و همچنین توضیحات تکمیلی را در قالب نصب و ساخت ایمیج جئوسرور دلخواهمان ، توضیح و بررسی کنمهدف از ساخت docker image برای جئوسرور چیست؟قطعا همان طور که در ابتدای این مقاله گفته شد ، سادگی و قابل حمل بودن و سرعت deploy توسط docker باعث شد برای سهولت کار جئوسرور را تبدیل به یک docker image  کنییم . برای مثال ما میخواستیم جئوسرورمان دارای دو پلاگین oracle و GDAL باشد که به صورت پیش فرض بر روی جئوسرور نصب نیستند و نصب آن ها بر روی سیستم عامل های مختلف دارای پیچیدگی های مختلفی هست اما با انجام کلیه این تنظیمات و ساخت یک docker image ، دیگه نیازی نیست که هر بار تنظیمات را انجام دهیم و با ساخت هر container از ایمیج جئوسرور تنظیمات ما به صورت پیشفرض در جئوسرور اعمال میشوند.در صورت تغییر در تنظیمات ، اضافه کردن لایه ها ، استایل ها ، تنظیمات cache نقشه و ... آیا هربار که container ما پاک شود و دوباره راه اندازی شود ، اطلاعات از بین میرود ؟جواب منفی است ، در docker امکان volume کردن یا به زبان ساده تر امکان شنود کردن اتفاقاتی که در container در حال رخ دادن است وجود دارد و ما میتوانیم با استفاده از این قابلیت اتفاقات مورد نظرمون را شنود کنیم و در host خودمون نگه داریم . به عنوان مثال در ایمیج جئوسرور ، ما کلیه محتویات پوشه data_dir را که شامل کلیه تنظیمات و تغییرات جئوسرور هست را از طریق volume (( که در ادامه توضیح خواهیم داد)) در هاست خود ذخیره میکنیم تا هربار که یک instance جدید ساخته میشود آخرین تغییرات در جئوسرور وجود داشته باشد و نیازی به دوباره کاری برای بارگزاری اطلاعات جئوسرور نباشد. مرحله اول اولین مسئله ای که باید به آن دقت کرد این است که قبل از تلاش برای ساختن یک ایمیج از صفر تا صد بهتر است که سری به dockerhub بزنیم. چون در بیشتر مواقع مواردی مشابه به تنظیماتی که در نظر شما وجود دارد را میتوان از آنجا پیدا کرد با همین رویکرد ما توانستیم با جستجوی geoserver در ایمیج ها و بررسی امکانات آنها یکی را انتخاب کنیم تا به عنوان اولین قدم روی آن کار کنیم تا در نهایت base image خود را آماده کنیمwinsent/geoserverایمیج انتخابی ما که آدرسش در اسم ایمیج لینک شده است ، ایمیج winsent بود چون به صورت پیشفرض دارای پلاگین GDAL بود که البته برای این کار باید چند مرحله انجام میدادیمبا بررسی repository ایمیج و دانلود source آن متوجه شدیم برای اینکه بخواهیم ایمیجی با پلاگین از قبل آماده شده GDAL داشته باشیم باید از روی Dockerfile موجود در پوشه ورژن 2.12  و پوشه libecw یک ایمیج تهیه کنیم.در ابتدا برای اینکه اگر کاربر ادمین نباشید و نخواهید هر بار دستور sudo را قبل از دستورات docker بیاورید میتوانید از کد زیر در terminal  استفاده کنید. بعد از enter کردن رمز عبور یوزر خود را تایپ کنید و enter کنید حالا شما به عنوان یوزر ادمین شناخته شده اید$ sudo –iنحوه ساخت یک Docker Image از روی Dockerfile$ docker build –t imageName .توجه : در انتها بعد از اسم ایمیج باید یک space زده و ].[ را بگذارید تا دستور عمل کند. البته در دستور بالا چون دقیقا اسم فایل Dockefile بوده ما اسم فایل را نیاوردیم ولی اگر اسم Dockerfile  امون فرق میکنه دستور به شکل زیر میشه$ docker build -f dockerfileName -t imageName .بعد از ساخته شدن image یکسری دستورات لازمه را مرور میکنیم نحوه pull کردن یک image از docker hub$ docker pull image_nameدیدن لیستی از همه Image های داکری که روی هاست قرار دارد$ docker imagesحذف docker imageوقتی دستور docker images رو اجرا میکنیم کل اطلاعات ایمیج شامل Id ، نام و ... رو به ما نشون میده$ docker rmi &lt;imageId&gt;ساخت یک container از روی imageبرای این منظور از دستور زیر استفاده میکنیم $ docker run –d –p 8087:8080 –v path/to/host:/opt/geoserver/data_dir &lt;imageName&gt;-d یعنی container رو در background اجرا کنه -p 8087:8080 یعنی پورت 8080 در container رو به پورت 8087 در هاست خودتون مپ میکنه . یعنی برای دسترسی بهش کافیه توی هاست خودتون از آدرس زیر استفاده کنید127.0.0.1:8087/geoserver-v وظیفه volume کردن را بر عهده دارد یعنی محتویات داخل پوشه /opt/geoserver/data_dir که در container قرار دارد را میریزه داخل مسیر سمت چپی که در هاست شماست.نمایش لیست تمامی container های فعال$ docker psنمایش لیست تمامی container های فعال و غیر فعال$ docker ps –aحذف container$ docker rm &lt;containerName/Id&gt;Stop و start کردن container ها $ docker stop/start &lt;container Name/Id&gt;Stop کردن همه container ها به صورت دسته جمعی و حذف آنهاروش اول$ dcoker stop $(docker ps –a –q )$ docker rm $(docker ps –a –q)$ docker ps –a –q این دستور id (-q) همه کانتینر ها (-a) را بر میگردونهروش دوم $ docker rm –f $(docker ps –a –q)-f به معنی force یا اجبار میباشد ، پس بدون نیاز به stop کردن خودش اول stop  میکنه همه container  ها را و بعد پاکشون میکنهدستور رفتن به داخل container$ docker exec –it &lt;containerName/Id&gt; /bin/bashخروج از یک container بدون stop شدنCtrl + dحالا که container ما ساخته شده میخواهیم پلاگین های oracle را هم بهش اضافه کنیم . برای این منظور باید jar فایل های oracle و ojdbc را در مسیر زیر داخل container کپی کنیم$ docker cp ojdbc.jar myContainer:/opt/geoserver/webapps/geoserver/WEB-INF/lib/حالا که این کار را انجام دادیم پلاگین های ما اضافه میشوند و در حقیقت base image ما ساخته شده است به همین منظور از container موجود یکImage میسازیم تا همیشه از آن استفاده کنیمساخت Docker Image از روی Container$ docker commit &lt;container_id&gt; &lt;container_name&gt;:&lt;tag_version&gt;مثال :$ docker commit 2fg4805485ad sample/geoserver:1.0.0اگر :tag_version رو نگذاریم خودش latest در نظر میگیره اعداد 2fg4805485ad به معنی id کانتینر مورد نظر استبرای نگهداری Image خودمون یک tar فایل ازش میسازیم  تا هرجایی که میخواهیم ازش استفاده کنیم اون رو لود کنیمساخت tar فایل از imge$ docker save &lt;image_name&gt; yourImageName.tarمثال:$ docker save sample/geoserver:1.1.0 sample-geoserver.tarلود کردن tarFileحالا برای لود کردن این Image باید از دستور زیر استفاده کرد$ docker load tarFileAddressتوجه : در volume ای که در هاست خود داریم باید پوشه ای به نام data بسازیم و فایل های ecw را درون آن پوشه بارگذاری کنیم . این باگ پلاگین GDAL میباشد که حتما باید دیتا های رستری آن داخل پوشه data در مسیر geoserver_data_dir باشداستفاده از docker composeبرای راحتی کار میتوانیم برای ساخت container از فایل dockerCompose.yml استفاده کنیمبه عنوان مثال فایل dockerCompse جئوسرورversion: &#039;2&#039;
services:
  app:
    image: &quot;sample/geoserver:1.0.0&quot;
    ports:
     - &quot;8080:8080&quot;    volumes:-   /home/nariman/Desktop/…/geoserverData:/opt/geoserver/data_dirالبته برای استفاده از docker compose باید آن را به صورت جداگانه نصب کنید که این لینک توضیح داده شده و نیازمند چند دستور استsudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-composesudo chmod +x /usr/local/bin/docker-composeبرای اجرا کردن از طریق docker compose کافیه به مسیری که فایل در اون قرا داره برید و دستور زیر را اجرا کنید$ docker-compose –f dockerComposefile.yml up -d </description>
                <category>شرکت بهاران</category>
                <author>mandi.nariman</author>
                <pubDate>Thu, 14 Jun 2018 16:41:47 +0430</pubDate>
            </item>
                    <item>
                <title>معرفی مطالب جالب برنامه نویسی -۴:Serverless</title>
                <link>https://virgool.io/baharan-co/serverless-xsf4h9udypgb</link>
                <description>تو این پست قصد دارم یک سری لینک با محوریت موضوعات FAAS ,Serverless به شما معرفی کنم. نمیدونم تا چه اندازه ای با این دو رویکرد آشنایی دارید . این معماری از پر اهمیت ترین موضوعاتی که در سال ۲۰۱۸ در حال پیگیری و اجرا است .این معماری سعی داره رویکرد جدیدی در اجرای نرم افزارهای ایجاد کنه و بعد از تحولی که الگوی معماری ماکروسرویس در سالهای گذشته ایجاد کردند.تاثیر گذاری و تحول جدیدی در نحوه توسعه و اجرای سامانه های بزرگ ایجاد کنه . بنابراین نیاز است که اطلاعات خوبی در این موضوع داشته باشیم .در ادامه یک سری منابع مفید در این حوزه معرفی می کنیم“Serverless will fundamentally change how we build business around technology and how you code.”Serverless architectures refer to applications that significantly depend on third-party services (knows as Backend as a Service or &quot;BaaS&quot;) or on custom code that&#x27;s run in ephemeral containers (Function as a Service or &quot;FaaS&quot;), the best known vendor host of which currently is AWS Lambda. By using these ideas, and by moving much behavior to the front end, such architectures remove the need for the traditional &#x27;always on&#x27; server system sitting behind an application. Depending on the circumstances, such systems can significantly reduce operational cost and complexity at a cost of vendor dependencies and (at the moment) immaturity of supporting services.لینک ۱ : یه مقاله عالی در مورد Serverless Architectures  در سایت مارتین فاولر . در صورتی که علاقه مند به دنیای FAAS ,Serverless هستید حتما این مقاله رو بخونید.ترجمه فارسی رو هم میتونید اینجا مطالعه کنیدلینک ۴: ارام آرام باید خودمون رو برای اتفاقای خوب در سال ۲۰۱۸ در حوزه FAAS آماده کنیم .اسپرینگ هم طرفدارهاشو تو این موضوع حسابی خوشحال خواهد کرد. این مقاله  یه سری قابلیت در مورد این ویژگی رو در اسپرینگ  معرفی میکنه .لینک ۳ : یکی از محصولات اپن سورس برای این معماری apache openwhisk هست این پروژه سعی داره تمام قابلتیهای این معماری رو پیاده سازی کنه . این مقاله روال اجرا و فراخوانی را در این معماری نشان می دهد . عکس پایین فلوی اجرا را نشان میدهد. The internal flow of processing لینک ۴: دوتا پروژه متن باز در این حوزه وجود دارد ، openfaas و openwhisk لینک ۵ : یه ریپازیتوری خوب در گیت که تمامی پروژه های این حوزه رو معرفی میکنه </description>
                <category>شرکت بهاران</category>
                <author>علی اکبر عزیزخانی</author>
                <pubDate>Thu, 03 May 2018 22:53:21 +0430</pubDate>
            </item>
                    <item>
                <title>معرفی مطالب جالب برنامه نویسی -۳</title>
                <link>https://virgool.io/baharan-co/link3-ipnumzl3g9rf</link>
                <description>این پست با محوریت ویژگی های جدید spring-boot-2 ویژگی هایی که داره و موضوعات مرتبط ارسال میشه. تو دو ماه گذشته بالاخره تیم اسپرینگ نسخه نهایی رو ارایه داد و تمامی فریم های مربوطه در تلاش هستن که به این نسخه خودشون رو ارتقا بدن مخصوصا پروژه دوست داشتنی ما Jhipster یک لینک هم از ویژگی های جدید نسخه بتای هیپستر رو هم گذاشتم تا لذتش رو ببرید .چند تا از ویژگی های جدید ورژن ۲ پروژه اسپرینگ بوت کم کردن کدهای مورد نیاز برای Autoconfiguration یک سری قابلتهای خوب برای Production-readyیک سری قابلیتهای خوب برای تست عدم پشتیبانی از جاوا ۷ و کمترپشتیبانی از جاوا ۹حداقل ورژن تامکت 8.5حداقل ورژن هایبرنت 5.2ساده سازی ایجاد تنظیمات برای حوزه امنیت پشتیبانی از Reactive و WebFluxلینک ۱ :http://dolszewski.com/spring/feature-toggle-spring-boot/لینک ۲ :https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Migration-Guideلینک ۳ : http://www.baeldung.com/new-spring-boot-2لینک ۴ : http://therealdanvega.com/blog/2018/03/01/what-is-new-spring-boot-2لینک ۵: https://www.infoq.com/presentations/spring-boot-2اینم قابلیتهای ورژن بتای هیپستر https://www.jhipster.tech/2018/04/03/jhipster-release-5.0.0-beta.0.html</description>
                <category>شرکت بهاران</category>
                <author>علی اکبر عزیزخانی</author>
                <pubDate>Sun, 08 Apr 2018 21:49:31 +0430</pubDate>
            </item>
                    <item>
                <title>معرفی مطالب جالب برنامه نویسی -۲</title>
                <link>https://virgool.io/baharan-co/link2-v2jteonu5mmt</link>
                <description>هفته دوم هم رسید و سعی میکنم هر هفته یک سری لینک از موضوعات جدید براتون به اشتراک بگذارم امیدوارم این سری هم لینک های جالبی براتون به اشتراک گذاشته باشم.مطلب هفته بعد موضوع معرفی قابلیت های جدید spring-boot-2 و مطالب مربوطه هست. اگر کسی لینک و مطلب جالبی را در این موضوع داره به پست الکترونیک من ارسال کنه لینک ۱ sonarcloud.io :شاید خیلی از برنامه نویس های جاوا با این ابزار یا فریم ورک آشنایی داشته باشن سونار با تحلیل کد شما اطلاعات خیلی خوبی به شما میده مثل :پیچیدگی کد.بدهی فنی شما و.. .سونار به تازگی این خدمات رو به صورت انلاین و رایگان برای پروژه های اپن سورس ارایه کرده .این هم روش استفاده با Mavenلینک ۲ rangle :بی شک یکی از بهترین منابع اموزشی برای انگیولار واقعا موضوعات رو عمیق و کاربردی توضیح داده .من که لذت بردملینک ۳ ng2-file-upload :یه لایبری خوب واسه اپلود فایل و عکس تو انگیولار ۲ به بعد . به نظرم خوب و ساده است و خیلی کار را بنداز. اگه نیاز داشتید عکس اپلود شده رو نشون بدید . با این دایرکتیو به راحتی میتونید به این نیاز هم برسید لینک ۴ Java Duration:چند مثال قابل فهم برای استفاده از ابجکت Duration , .. تو جاوالینک ۵ How to map entity attributes of type java.time.Duration: یه ویدیو ساده برای اعمال قابلیت استفاده از این ابجکت و تایپ تو هایبرنت </description>
                <category>شرکت بهاران</category>
                <author>علی اکبر عزیزخانی</author>
                <pubDate>Fri, 30 Mar 2018 21:17:13 +0430</pubDate>
            </item>
                    <item>
                <title>معرفی مطالب جالب برنامه نویسی -۱</title>
                <link>https://virgool.io/baharan-co/link-1-ijxafmga2xt5</link>
                <description>یکی از روش های به اشتراک گذاری معروف معرفی لینک های جالب هست . من خودم سالها با این روش و دنبال کردن این پست ها از اخبار و مطالب جدید لذت بردم و خیلی چیزها یاد گرفتم و یادمیگیرم .به خودم گفتم شاید خوب باشه این کار رو این جا شروع کنم و دوستان هم با ارسال مطالب جدید در برنامه نویسی مخصوصا دنیای جاوا و وب کمک کنن تا با اشتراک گذاری به رشد همدیگه کمک کنیم .لینک ۱ IntelliJ IDEA shortcuts for Eclipse users  :معرفی یه سایت خوب برای نگاشت کیبور Eclipse به Intellij . تو چند سال اخیر روند رو به رشد Eclipse شدیدا رو به افول بوده و خیلی از برنامه نویسهای جاوا به Intellij مهاجرت کردن  .  بزرگترین نگرانی این دوستان از بین رفتن ShortKey است که یکی از مهمترین موضوعات در سرعت کد نویسی به حساب میباد . لینک زیر سعی کرده تو یه جدول کمک کنه که راحت تر این مهاجرت رو انجام بدید . البته اگه دوست داشته باشید با همون شورت کی های Eclipse هم کار رو ادامه بدید مشکلی نداره و Intellij این امکان رو فراهم کرده ولی بهتر اینه که کلا به همه چی Eclipse خداحافظی کنید .لینک ۲ Catalog of 312 Angular 2+ components &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; libraries :معرفی یه سایت برای معرفی کامپوننتهای انگیولار به نظرم جالب بودلینک ۳ Jason Watmore:یه وبلاگ پر از پست های قشنگ در مورد انگیولار لینک ۴ Declarative, template-driven SweetAlert2 integration for Angular : پیاده سازی لایبری معروف SweetAlert برای انگیولار لینک ۵ ngx-datatable : یه لایبری خوب برای گرید به نظر قابلیتهای خوبی داره مخصوصا تو تمپلیتینگ  که باعث میشه دست برنامه نویس خیلی باز باشه</description>
                <category>شرکت بهاران</category>
                <author>علی اکبر عزیزخانی</author>
                <pubDate>Sat, 24 Mar 2018 13:51:40 +0430</pubDate>
            </item>
                    <item>
                <title>تجربه های Jhipster قسمت اول</title>
                <link>https://virgool.io/baharan-co/%D8%AA%D8%AC%D8%B1%D8%A8%D9%87-%D9%87%D8%A7%DB%8C-jhipster-%D9%82%D8%B3%D9%85%D8%AA-%D8%A7%D9%88%D9%84-xaefbdal7kzu</link>
                <description> تجربه هیپستر یکی از موضوعات جالبی که تو این چند سال با آن برخورد کردم Jhipster بود . من خیلی روی استاندارد بودن رویکرد فنی که انتخاب میکنم حساس هستم .همیشه وقتی سعی دارم مشکلی رو حل کنم یا کار جدیدی را انجام بدم اول سعی میکنم مثل همه دنبال بهترین تجربه و استایل انجام اون کار باشم تا حسابی راضی بشم که کار رو درست انجام دادم  . معمولا پاسخ به این حساسیت خیلی ساده نیست .چون امکان داره روش های متنوعی رو پیدا کنی .حالا در نظر بگیرید که بخواهید در یک چالش فنی با ۱۰ تا چیز جدید رودرو بشی در این صورت ببینید چه اتفاقی خواهد افتاد . من تو سال ۲۰۱۵ با Jhipster اشنا شدم .یک پروژه عالی که به نظرم جمع شده از بهترین تجارب Full Stack است. از Front بگیر تا  Backend خیلی برای من جذاب و هیجان انگیر بود.باعث شد خیلی روشهای خوب را ازاین تکنولوژی یاد بگیرم و تقریبا هر جا که با مشکلی بر میخورد میکنم به اون رجوع میکنم و خیلی چیزها را از اون یاد گرفتم.ولی ای کاش یک چالش تو اون بهتر در نظر گرفته می شد . اگه تجربه کار کردن با جاوا و مخصوصا Spring رو داشته باشید قطعا میدونید باید یه مجموعه تنظیمات انجام بدید تا پروژه شما درست کار کنه و کافی یک مرحله رو درست انجام ندید قطعا پروژه استارت نمیشه . البته این مشکل با اضافه شدن پروژه Boot خیلی بهتر و کاملتر شده است .من اخرین تجربه ای که داشتم رو براتون بگم .من رو پروژه ای کار میکنم که احراز هویت آن بر اساس توکن میباشد . تصمیم گرفتیم به این پروژه یک ماژول ساده چت اضافه کنیم که مشتریان بتونن با هم چت کنن برای این موضوع نیاز داشتم که از تکنولوژی WebSocket استفاده کنم برای اینکار نیاز داشتم تنظیماتی رو به پروژه اضافه کنم شروع کردم به انجام این کار و کار درست پیش رفت و همه چی درست پیش میرفت تا این که دیدم با این حال که کاربر احراز هویت کرده بود ولی کاربر رو ناشناس نشون میداد بعد از چند ساعت متوجه شدم که باید در اولین کانکشن به وب سوکت توکن JWT رو هم ارسال کنم بنابراین نیاز بود اول SockJs رو به روز میکردم تا امکان ارسال پارامتر رو در حین ارتباط ارسال کنم var wrappedSocket = {
             init: function (url) {
   var authToken = AuthServerProvider.getToken();
                 if(authToken){
                     url += &#039;?access_token=&#039; + authToken;
                 }
                 stompClient = Stomp.over(new SockJS(url));
             },
             connect: function (successCallback, errorCallback) {
                 stompClient.connect({}, function (frame) {
                     $rootScope.$apply(function () {
                         successCallback(frame);
                     });
                 }, function (error) {
                     $rootScope.$apply(function () {
                         errorCallback(error);
                     });
                 });
             }      
   }از طرفی باید در فیلتر هم این موضوع رو اضافه میکردم که هم بتونم اطلاعات رو از هدر بخونم هم از پارامتر مثل کد زیر      private String resolveToken(HttpServletRequest request){ 
         String bearerToken = request.getHeader(JWTConfigurer.AUTHORIZATION_HEADER);
         if (StringUtils.hasText(bearerToken) &amp;&amp; bearerToken.startsWith(&quot;Bearer &quot;)) {
             return bearerToken.substring(7, bearerToken.length());
         }
   String jwt = request.getParameter(JWTConfigurer.AUTHORIZATION_TOKEN);
         if (StringUtils.hasText(jwt)) {
             return jwt;
         }
         return null;
     }بنابراین این دو تا تنظیم کلید حل این مشکل بود بعد از کلی فکر کردن و کمک کردن از Jhipster این مشکل رو حل کردم و دیدم اره هیپستر هم همین کارو انجام داده .&quot;یه نکته یادم نره من تقریبا هر کاری رو شروع میکنم خودم شروع کنم و بعد اگه مشکل برخورد کردم سراغ Jhipster میرم فکر میکنم این جوری دقیق تر و عمیق تر مطلب رو یاد میگیرم و کل پروژه رو بر مبنای Jhipster نمیرم &quot; اولین چیزی که به ذهنم رسید اینه. خوب آیا این ترفندها رو Jhipster جایی نوشته مگه کسی که این تجربه ها رو داخل Genrator هیپستر قرار داده قبلا با این مشکل رو درو نشده بوده . شاید اگه این ترفندها جایی بود باعث میشد من زودتر این مشکل رو پیدا کنم .سوالم اینه چرا جایی وجود نداره که این ترفندها توش قرار داده شده باشه </description>
                <category>شرکت بهاران</category>
                <author>علی اکبر عزیزخانی</author>
                <pubDate>Sat, 03 Mar 2018 20:51:57 +0330</pubDate>
            </item>
                    <item>
                <title>اعمال دسترسی بر روی داده ها با استفاده از Hibernate Filter</title>
                <link>https://virgool.io/baharan-co/%D9%BE%DB%8C%D8%B4-%D9%86%D9%88%DB%8C%D8%B3-%D8%A7%D8%B9%D9%85%D8%A7%D9%84-%D8%AF%D8%B3%D8%AA%D8%B1%D8%B3%DB%8C-%D8%A8%D8%B1-%D8%B1%D9%88%DB%8C-%D8%AF%D8%A7%D8%AF%D9%87-%D9%87%D8%A7-%D8%A8%D8%A7-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-hibernate-filter-lnti2hzfegla</link>
                <description> یکی از موضوعاتی که تو اغلب سامانه های نرم افزاری قطعا با اون برخواهید خورد دسترسی کاربران به داده ها است . تقریبا ۶ سال است که از یه تجربه خوب در اعمال Authotization کاربرهای درسامانه های تولیدی شرکت خودمون استفاده میکنم گفتم شاید با درمیان قرار دادن اون بتونم از نظرات شما ها استفاده کنم . ما در شرکت خودمون سامانه هایی را تولید میکنیم که در این سامانه ها کاربرانی با نقشهای متفاوتی مشغول به استفاده از سامانه هستند که هر کدوم از این سامانه ها بر اساس منطق دسترسی مشخصی داده مورد نظر خود را مشاهده میکنند . برای مثال در نظر بگیرید که سازمانی داریم که به منظور مدیریت پرسنل خود از سامانه نرم افزاری ما استفاده میکند . این سازمان دارای ساختار بسیار بزرگ میباشد . و کاربرانی در این سامانه با نقش منابع انسانی باید اطلاعات پرسنلی را به روز نگه دارند . از طرفی نقش مدیر کل منابع انسانی باید بتواند تمامی اطاعات پرسنل در این سازمان را مشاهده نماید . برای انجام این مساله به این روش عمل کردیم در ابتدا نیاز داشتیم هر کاربر سطح دسترسی خود به ساختار سازمان را مشخص نماید بنابراین به کلاس دیاگرام زیر رسیدیمبنابراین هر کاربر سامانه به یک سازمان مورد نظر دسترسی دارد .بر اساسا شکل بالا هر پرسنل در یک سازمان مشغول به کار میباشد .بنابراین لازم است هر کاربر کارمند مورد نظر خود را مشاهده نماید در این جا لازم به ذکر است که سامانه های پیاده سازی شده برای persist کردن اطلاعات در جداول از Hibernate استفاده میکند بنابراین کلاس های مورد نظر به شکل زیر تنظیم شده است .الگوی پیاده سازی برای لایه های همان لایه های استاندارد هست در نظر بگیریدی که برای خواندن داده ها کارمندان باید چه متدهای نوشته شودpublic interface EmployeeRepositoy {Employee findById(Long id,);List&lt;Employee&gt; findByOrganizationId(Long orgId);List&lt;Employee&gt; allEmployee();}همانجوری که متدهای بالا را مشاهده میکنیم قرار است لیست یا یک کارمند به عنوان خروجی برگردانده شود در صورتی که نیاز باشد برای برای این متدهای یک hql معادل نوشته شود قطعا دارای شکل زیر خواهد بود @Query(“select e from Employee e where e.organizationStructure.id in (select os.id from User u join u.organizationStructures os where u.id=?#{ principal?.id })”)Employee findById(Long id);در صورتی که دقت کرده باشید بخش زیر در تمامی query ها تکرار شده است e.organizationStructure.id in (select os.id from User u join u.organizationStructures os where u.id=?#{ principal?.id })شاید همه مثالها مثل کلاس بالا دارای سه متد نباشد . امکان دارد کلاسی باشد که دارای متدهای زیادی باشد . سوال اول این است . به چه روشی این موضوع را حل کرد روش های زیر به نظر می رسد قابل انجام باشد یک: استفاده از @Where  این روش دارای مشکلات و خوبی های هست . این روش به صورت اجبار در تمامی query این فیلتر را اضافه میکند شاید نیاز باشد این فیلتر در همه حالتها اجرا نشود این روش این امکان را ندارد . مشکل دیگر عدم امکان استفاده از پارامتر در این روش هست . شاید نیاز باشد برای اعمال این منطق پارامترهایی ارسال گردد که این روش این امکان را نمیدهد . خوبی این روش این است که نیازی به فعال و غیر فعال کردن نیست و به راحتی اعمال خوهد شد دو: تعریف یه متغیر در سطح کلاس و concat کردن با query مشکل این روش این است که این امکان دارد برنامه نویس به هر دلیلی فراموش کند که این clause را به query خود concat کند . مشکل دیگر این است که این احتمال وجود دارد که در کلاس دیگری برنامه نویس روی این model یک query را اجرا نماید .در این حالت تضمینی نیست که این فیلتر اعمال شود سه: استفاده از @Filter به نظر این روش یکی از مطمین ترین روشها باشد .با استفاده از امکانی که Hibernate در اختیار ما قرار میدهد میتوان با تعریف یک فیلتر و فعال کردن ان در سطح session مطمین شد که تمامی query هایی که اجرا میشود در صورتی که دارای پیاده سازی این فیلتر در سطح مدل باشد این فیلتر در سطح آن مدل اعمال خواهد شد برای مثال </description>
                <category>شرکت بهاران</category>
                <author>علی اکبر عزیزخانی</author>
                <pubDate>Sat, 03 Mar 2018 20:49:58 +0330</pubDate>
            </item>
            </channel>
</rss>