مونتاژ دینامیک و استقرار تصاویر Docker با werf با استفاده از مثال یک سایت اسناد نسخه‌سازی شده

ما قبلاً بیش از یک بار در مورد ابزار GitOps خود صحبت کرده ایم. ورفو این بار می خواهیم تجربه خود را در مونتاژ سایت با مستندات خود پروژه به اشتراک بگذاریم - werf.io (نسخه روسی آن است en.werf.io). این یک سایت ثابت معمولی است، اما مونتاژ آن از این جهت جالب است که با استفاده از تعداد پویا از مصنوعات ساخته شده است.

مونتاژ دینامیک و استقرار تصاویر Docker با werf با استفاده از مثال یک سایت اسناد نسخه‌سازی شده

به تفاوت های ظریف ساختار سایت بروید: ایجاد یک منوی مشترک برای همه نسخه ها، صفحات حاوی اطلاعات در مورد نسخه ها و غیره. - ما نخواهیم. در عوض، بیایید روی مسائل و ویژگی های مونتاژ پویا و کمی روی فرآیندهای CI/CD همراه تمرکز کنیم.

مقدمه: نحوه کار سایت

برای شروع، اسناد werf همراه با کد آن ذخیره می شود. این امر الزامات توسعه خاصی را تحمیل می کند که عموماً خارج از محدوده این مقاله است، اما حداقل می توان گفت:

  • توابع جدید werf نباید بدون به‌روزرسانی مستندات منتشر شوند و برعکس، هر گونه تغییر در اسناد به معنای انتشار نسخه جدیدی از werf است.
  • این پروژه توسعه نسبتاً فشرده ای دارد: نسخه های جدید را می توان چندین بار در روز منتشر کرد.
  • هرگونه عملیات دستی برای استقرار یک سایت با نسخه جدید اسناد حداقل خسته کننده است.
  • این پروژه یک رویکرد معنایی را اتخاذ می کند نسخه سازیدارای 5 کانال پایداری فرآیند انتشار شامل عبور متوالی نسخه ها از طریق کانال ها به منظور افزایش پایداری است: از آلفا به سنگ جامد.
  • این سایت دارای نسخه روسی زبان است که به موازات نسخه اصلی (یعنی انگلیسی زبان) "زندگی و توسعه می یابد" (یعنی محتوای آن به روز می شود).

برای مخفی کردن تمام این «آشپزخانه داخلی» از کاربر، ارائه چیزی که «فقط کار می‌کند»، به او پیشنهاد دادیم ابزار نصب و به روز رسانی werf جداگانه - آیا چند وجهی. فقط باید شماره انتشار و کانال پایداری را که آماده استفاده هستید مشخص کنید و multiwerf بررسی می کند که آیا نسخه جدیدی در کانال وجود دارد یا خیر و در صورت لزوم آن را دانلود می کند.

در منوی انتخاب نسخه در وب سایت، آخرین نسخه های werf در هر کانال موجود است. به طور پیش فرض، با آدرس werf.io/documentation نسخه پایدارترین کانال برای آخرین نسخه باز می شود - همچنین توسط موتورهای جستجو نمایه می شود. اسناد مربوط به کانال در آدرس های جداگانه موجود است (به عنوان مثال، werf.io/v1.0-beta/documentation برای نسخه بتا 1.0).

در مجموع، این سایت دارای نسخه های زیر است:

  1. root (به طور پیش فرض باز می شود)
  2. برای هر کانال به‌روزرسانی فعال هر نسخه (به عنوان مثال، werf.io/v1.0-beta).

برای تولید یک نسخه خاص از یک سایت، به طور کلی، کافی است آن را با استفاده از آن کامپایل کنید جکیلبا اجرا در دایرکتوری /docs دستور مربوط به مخزن werf (jekyll build، پس از جابجایی به تگ Git نسخه مورد نیاز.

فقط باید اضافه کرد که:

  • خود ابزار (werf) برای مونتاژ استفاده می شود.
  • فرآیندهای CI/CD بر اساس GitLab CI ساخته شده اند.
  • و همه اینها، البته، در Kubernetes اجرا می شود.

وظایف

اکنون بیایید وظایفی را فرموله کنیم که تمام مشخصات توصیف شده را در نظر بگیرد:

  1. پس از تغییر نسخه werf در هر کانال به روز رسانی اسناد موجود در سایت باید به طور خودکار به روز شوند.
  2. برای توسعه باید گاهی اوقات بتوانید مشاهده نسخه های پیش نمایش سایت.

سایت باید پس از تغییر نسخه در هر کانال از تگ های Git مربوطه دوباره کامپایل شود، اما در روند ساخت تصویر ویژگی های زیر را دریافت خواهیم کرد:

  • از آنجایی که لیست نسخه‌های کانال‌ها تغییر می‌کند، فقط لازم است اسناد کانال‌هایی را که نسخه در آن‌ها تغییر کرده، بازسازی کنید. به هر حال، بازسازی دوباره همه چیز خیلی خوب نیست.
  • ممکن است مجموعه کانال‌ها برای انتشار تغییر کند. به عنوان مثال، در برخی از زمان‌ها، ممکن است نسخه‌ای در کانال‌ها وجود نداشته باشد که پایدارتر از نسخه 1.1 با دسترسی اولیه باشد، اما به مرور زمان ظاهر می‌شوند - در این مورد، آیا نباید مونتاژ را به صورت دستی تغییر دهید؟

معلوم است که مونتاژ به تغییر داده های خارجی بستگی دارد.

اجرا

انتخاب یک رویکرد

از طرف دیگر، می توانید هر نسخه مورد نیاز را به عنوان یک پاد جداگانه در Kubernetes اجرا کنید. این گزینه شامل تعداد بیشتری از اشیاء در خوشه است که با افزایش تعداد انتشارات پایدار ورف رشد خواهند کرد. و این به نوبه خود مستلزم تعمیر و نگهداری پیچیده تر است: هر نسخه دارای سرور HTTP خاص خود و با بار کمی است. البته این امر مستلزم هزینه های منابع بیشتر نیز می باشد.

ما هم همین مسیر را طی کردیم مونتاژ تمام نسخه های لازم در یک تصویر. استاتیک کامپایل شده تمامی نسخه های سایت در یک ظرف با NGINX قرار دارد و ترافیک به Deployment مربوطه از طریق NGINX Ingress می آید. یک ساختار ساده - یک برنامه کاربردی بدون حالت - به شما امکان می دهد به راحتی Deployment را (بسته به بار) با استفاده از خود Kubernetes مقیاس کنید.

برای دقیق تر، ما دو تصویر را جمع آوری می کنیم: یکی برای مدار تولید، دومی یک تصویر اضافی برای مدار توسعه دهنده است. تصویر اضافی فقط در مدار dev همراه با اصلی استفاده می شود (راه اندازی می شود) و حاوی نسخه سایت از commit بررسی است و مسیریابی بین آنها با استفاده از منابع Ingress انجام می شود.

کلون و آرتیفکت werf vs git

همانطور که قبلا ذکر شد، برای ایجاد استاتیک سایت برای یک نسخه خاص از اسناد، باید با جابجایی به تگ مخزن مناسب، ساخت را انجام دهید. همچنین می توانید این کار را با شبیه سازی مخزن در هر بار ساختن، انتخاب تگ های مناسب از یک لیست انجام دهید. با این حال، این یک عملیات نسبتاً فشرده منابع است و علاوه بر این، نیاز به نوشتن دستورالعمل‌های غیر ضروری دارد... یکی دیگر از معایب جدی این است که با این رویکرد هیچ راهی برای ذخیره کردن چیزی در طول مونتاژ وجود ندارد.

در اینجا خود ابزار werf به کمک ما می آید و اجرا می کند ذخیره سازی هوشمند و به شما اجازه استفاده می دهد مخازن خارجی. استفاده از werf برای افزودن کد از مخزن به میزان قابل توجهی سرعت ساخت را افزایش می دهد، زیرا werf اساسا یک بار مخزن را شبیه سازی می کند و سپس اجرا می کند تنها fetch در صورت لزوم علاوه بر این، هنگام اضافه کردن داده ها از مخزن، ما می توانیم فقط دایرکتوری های لازم را انتخاب کنیم (در مورد ما این دایرکتوری است docs) که میزان داده های اضافه شده را به میزان قابل توجهی کاهش می دهد.

از آنجایی که Jekyll ابزاری است که برای کامپایل داده های ثابت طراحی شده است و در تصویر نهایی مورد نیاز نیست، منطقی است که در آن کامپایل شود. مصنوع werf، و به تصویر نهایی فقط نتیجه کامپایل را وارد کنید.

ما werf.yaml می نویسیم

بنابراین، ما تصمیم گرفتیم که هر نسخه را در یک artifact جداگانه کامپایل کنیم. با این حال ما ما نمی دانیم که در طول مونتاژ چند مورد از این مصنوعات وجود خواهد داشت، بنابراین ما نمی توانیم یک پیکربندی ساخت ثابت بنویسیم (به طور دقیق، هنوز هم می توانیم، اما کاملاً مؤثر نخواهد بود).

werf به شما امکان استفاده را می دهد برو قالب ها در فایل پیکربندی شما (werf.yaml) و این امکان را فراهم می کند ایجاد پیکربندی در پرواز بسته به داده های خارجی (آنچه شما نیاز دارید!). داده های خارجی در مورد ما اطلاعاتی در مورد نسخه ها و نسخه ها است که بر اساس آنها تعداد مورد نیاز مصنوعات را جمع آوری می کنیم و در نتیجه دو تصویر به دست می آوریم: werf-doc и werf-dev برای اجرا در مدارهای مختلف

داده های خارجی از طریق متغیرهای محیطی منتقل می شوند. در اینجا ترکیب آنها است:

  • RELEASES - یک خط با لیستی از نسخه های منتشر شده و نسخه فعلی متناظر werf، در قالب یک لیست مقادیر جدا شده با فاصله در قالب <НОМЕР_РЕЛИЗА>%<НОМЕР_ВЕРСИИ>... مثال: 1.0%v1.0.4-beta.20
  • CHANNELS - یک خط با لیستی از کانال ها و نسخه فعلی متناظر werf، در قالب یک لیست مقادیر جدا شده با فاصله در قالب <КАНАЛ>%<НОМЕР_ВЕРСИИ>... مثال: 1.0-beta%v1.0.4-beta.20 1.0-alpha%v1.0.5-alpha.22
  • ROOT_VERSION — نسخه انتشاری werf به طور پیش فرض در سایت نمایش داده شود (همیشه لازم نیست مستندات با بالاترین شماره انتشار نمایش داده شود). مثال: v1.0.4-beta.20
  • REVIEW_SHA - هش commit بررسی که باید از آن نسخه را برای حلقه تست بسازید.

این متغیرها در خط لوله GitLab CI پر می شوند و دقیقاً چگونه در زیر نوشته شده است.

اول از همه، برای راحتی، ما در تعریف می کنیم werf.yaml به متغیرهای قالب بروید و از متغیرهای محیطی مقادیری به آنها اختصاص دهید:

{{ $_ := set . "WerfVersions" (cat (env "CHANNELS") (env "RELEASES") | splitList " ") }}
{{ $Root := . }}
{{ $_ := set . "WerfRootVersion" (env "ROOT_VERSION") }}
{{ $_ := set . "WerfReviewCommit" (env "REVIEW_SHA") }}

توضیحات آرتیفکت برای کامپایل نسخه استاتیک سایت به طور کلی برای همه مواردی که نیاز داریم یکسان است (از جمله تولید نسخه root و همچنین نسخه برای مدار توسعه). بنابراین، با استفاده از تابع آن را به یک بلوک جداگانه منتقل می کنیم define - برای استفاده مجدد بعدی include. آرگومان های زیر را به قالب ارسال می کنیم:

  • Version - نسخه تولید شده (نام برچسب)؛
  • Channel - نام کانال به روز رسانی که آرتیفکت برای آن تولید شده است.
  • Commit - commit هش، اگر مصنوع برای یک commit بررسی ایجاد شده باشد.
  • متن نوشته.

توضیحات الگوی مصنوع

{{- define "doc_artifact" -}}
{{- $Root := index . "Root" -}}
artifact: doc-{{ .Channel }}
from: jekyll/builder:3
mount:
- from: build_dir
  to: /usr/local/bundle
ansible:
  install:
  - shell: |
      export PATH=/usr/jekyll/bin/:$PATH
  - name: "Install Dependencies"
    shell: bundle install
    args:
      executable: /bin/bash
      chdir: /app/docs
  beforeSetup:
{{- if .Commit }}
  - shell: echo "Review SHA - {{ .Commit }}."
{{- end }}
{{- if eq .Channel "root" }}
  - name: "releases.yml HASH: {{ $Root.Files.Get "releases.yml" | sha256sum }}"
    copy:
      content: |
{{ $Root.Files.Get "releases.yml" | indent 8 }}
      dest:  /app/docs/_data/releases.yml
{{- else }}
  - file:
      path: /app/docs/_data/releases.yml
      state: touch
{{- end }}
  - file:
      path: "{{`{{ item }}`}}"
      state: directory
      mode: 0777
    with_items:
    - /app/main_site/
    - /app/ru_site/
  - file:
      dest: /app/docs/pages_ru/cli
      state: link
      src: /app/docs/pages/cli
  - shell: |
      echo -e "werfVersion: {{ .Version }}nwerfChannel: {{ .Channel }}" > /tmp/_config_additional.yml
      export PATH=/usr/jekyll/bin/:$PATH
{{- if and (ne .Version "review") (ne .Channel "root") }}
{{- $_ := set . "BaseURL" ( printf "v%s" .Channel ) }}
{{- else if ne .Channel "root" }}
{{- $_ := set . "BaseURL" .Channel }}
{{- end }}
      jekyll build -s /app/docs  -d /app/_main_site/{{ if .BaseURL }} --baseurl /{{ .BaseURL }}{{ end }} --config /app/docs/_config.yml,/tmp/_config_additional.yml
      jekyll build -s /app/docs  -d /app/_ru_site/{{ if .BaseURL }} --baseurl /{{ .BaseURL }}{{ end }} --config /app/docs/_config.yml,/app/docs/_config_ru.yml,/tmp/_config_additional.yml
    args:
      executable: /bin/bash
      chdir: /app/docs
git:
- url: https://github.com/flant/werf.git
  to: /app/
  owner: jekyll
  group: jekyll
{{- if .Commit }}
  commit: {{ .Commit }}
{{- else }}
  tag: {{ .Version }}
{{- end }}
  stageDependencies:
    install: ['docs/Gemfile','docs/Gemfile.lock']
    beforeSetup: '**/*'
  includePaths: 'docs'
  excludePaths: '**/*.sh'
{{- end }}

نام مصنوع باید منحصر به فرد باشد. برای مثال می‌توانیم با افزودن نام کانال (مقدار متغیر .Channel) به عنوان پسوند نام مصنوع: artifact: doc-{{ .Channel }}. اما باید بدانید که هنگام وارد کردن از مصنوعات، باید به همان نام ها مراجعه کنید.

هنگام توصیف یک مصنوع، از ویژگی werf زیر استفاده می شود: نصب. نصب دایرکتوری سرویس را نشان می دهد build_dir به شما اجازه می دهد تا کش جکیل را بین اجرای خط لوله ذخیره کنید، که به طور قابل توجهی سرعت مونتاژ مجدد را افزایش می دهد.

ممکن است شما نیز متوجه استفاده از فایل شده باشید releases.yml یک فایل YAML با داده های انتشار درخواست شده است github.com (مصنوعی که هنگام اجرای خط لوله به دست می آید). هنگام کامپایل سایت مورد نیاز است، اما در زمینه مقاله برای ما جالب است زیرا به وضعیت آن بستگی دارد مونتاژ مجدد تنها یک مصنوع - یک مصنوع از نسخه اصلی سایت (در سایر مصنوعات مورد نیاز نیست).

این با استفاده از دستور شرطی اجرا می شود if برو قالب ها و طرح ها {{ $Root.Files.Get "releases.yml" | sha256sum }} در مرحله مراحل. این کار به شرح زیر است: هنگام ساخت یک مصنوع برای نسخه ریشه (متغیر .Channel برابر است با root) هش فایل releases.yml روی امضای کل مرحله تأثیر می گذارد، زیرا بخشی از نام وظیفه Ansible است (پارامتر name). بنابراین، هنگام تغییر محتوا فایل releases.yml مصنوع مربوطه دوباره مونتاژ خواهد شد.

لطفا به کار با یک مخزن خارجی نیز توجه کنید. در تصویر یک مصنوع از مخزن werf، فقط دایرکتوری اضافه می شود /docsو بسته به پارامترهای پاس شده، داده های تگ یا commit مورد نیاز بلافاصله اضافه می شود.

برای استفاده از الگوی مصنوع برای ایجاد توصیفی از مصنوع نسخه‌های انتقال یافته کانال‌ها و نسخه‌ها، یک حلقه روی متغیر سازماندهی می‌کنیم. .WerfVersions в werf.yaml:

{{ range .WerfVersions -}}
{{ $VersionsDict := splitn "%" 2 . -}}
{{ dict "Version" $VersionsDict._1 "Channel" $VersionsDict._0 "Root" $Root | include "doc_artifact" }}
---
{{ end -}}

زیرا حلقه چندین مصنوع تولید می کند (ما امیدواریم که چنین باشد)، لازم است جداکننده بین آنها - دنباله را در نظر بگیریم --- (برای اطلاعات بیشتر در مورد نحو فایل پیکربندی، رجوع کنید به مستندات). همانطور که قبلاً تعریف شد، هنگام فراخوانی یک الگو در یک حلقه، پارامترهای نسخه، URL و زمینه ریشه را ارسال می کنیم.

به طور مشابه، اما بدون حلقه، ما الگوی مصنوع را برای "موردهای خاص" می نامیم: برای نسخه ریشه، و همچنین نسخه از commit بررسی:

{{ dict "Version" .WerfRootVersion "Channel" "root" "Root" $Root  | include "doc_artifact" }}
---
{{- if .WerfReviewCommit }}
{{ dict "Version" "review" "Channel" "review" "Commit" .WerfReviewCommit "Root" $Root  | include "doc_artifact" }}
{{- end }}

لطفاً توجه داشته باشید که آرتیفکت برای commit بررسی تنها در صورتی ساخته می‌شود که متغیر تنظیم شده باشد .WerfReviewCommit.

مصنوعات آماده هستند - زمان شروع واردات است!

تصویر نهایی که برای اجرا در Kubernetes طراحی شده است، یک NGINX معمولی است که یک فایل پیکربندی سرور اضافه شده است. nginx.conf و ایستا از مصنوعات. علاوه بر آرتیفکت نسخه ریشه سایت، باید حلقه را روی متغیر تکرار کنیم .WerfVersions برای وارد کردن مصنوعات نسخه‌های کانال و انتشار + قانون نام‌گذاری مصنوع را که قبلاً اتخاذ کردیم، دنبال کنید. از آنجایی که هر مصنوع نسخه‌هایی از سایت را برای دو زبان ذخیره می‌کند، ما آنها را به مکان‌های ارائه‌شده توسط پیکربندی وارد می‌کنیم.

شرح تصویر نهایی werf-doc

image: werf-doc
from: nginx:stable-alpine
ansible:
  setup:
  - name: "Setup /etc/nginx/nginx.conf"
    copy:
      content: |
{{ .Files.Get ".werf/nginx.conf" | indent 8 }}
      dest: /etc/nginx/nginx.conf
  - file:
      path: "{{`{{ item }}`}}"
      state: directory
      mode: 0777
    with_items:
    - /app/main_site/assets
    - /app/ru_site/assets
import:
- artifact: doc-root
  add: /app/_main_site
  to: /app/main_site
  before: setup
- artifact: doc-root
  add: /app/_ru_site
  to: /app/ru_site
  before: setup
{{ range .WerfVersions -}}
{{ $VersionsDict := splitn "%" 2 . -}}
{{ $Channel := $VersionsDict._0 -}}
{{ $Version := $VersionsDict._1 -}}
- artifact: doc-{{ $Channel }}
  add: /app/_main_site
  to: /app/main_site/v{{ $Channel }}
  before: setup
{{ end -}}
{{ range .WerfVersions -}}
{{ $VersionsDict := splitn "%" 2 . -}}
{{ $Channel := $VersionsDict._0 -}}
{{ $Version := $VersionsDict._1 -}}
- artifact: doc-{{ $Channel }}
  add: /app/_ru_site
  to: /app/ru_site/v{{ $Channel }}
  before: setup
{{ end -}}

تصویر اضافی، که همراه با تصویر اصلی، در مدار توسعه‌دهنده راه‌اندازی می‌شود، تنها شامل دو نسخه از سایت است: نسخه مربوط به بررسی commit و نسخه اصلی سایت (دارایی‌های عمومی وجود دارد و اگر به خاطر دارید ، انتشار داده ها). بنابراین، تصویر اضافی تنها در بخش واردات (و البته در نام) با تصویر اصلی متفاوت است:

image: werf-dev
...
import:
- artifact: doc-root
  add: /app/_main_site
  to: /app/main_site
  before: setup
- artifact: doc-root
  add: /app/_ru_site
  to: /app/ru_site
  before: setup
{{- if .WerfReviewCommit  }}
- artifact: doc-review
  add: /app/_main_site
  to: /app/main_site/review
  before: setup
- artifact: doc-review
  add: /app/_ru_site
  to: /app/ru_site/review
  before: setup
{{- end }}

همانطور که در بالا ذکر شد، مصنوع برای commit بررسی تنها زمانی تولید می شود که متغیر محیطی تنظیم شده اجرا شود. REVIEW_SHA. اگر متغیر محیطی وجود نداشته باشد، ممکن است اصلاً تصویر werf-dev تولید نشود REVIEW_SHA، اما به منظور تمیز کردن توسط سیاست ها تصاویر Docker در werf برای تصویر werf-dev کار می‌کنند، ما آن را تنها با مصنوع نسخه ریشه ساخته می‌کنیم (به هر حال قبلاً ساخته شده است)، تا ساختار خط لوله را ساده کنیم.

مجلس آماده است! بیایید به سراغ CI/CD و نکات ظریف مهم برویم.

خط لوله در GitLab CI و ویژگی های ساخت پویا

هنگام اجرای بیلد باید متغیرهای محیطی مورد استفاده در آن را تنظیم کنیم werf.yaml. این در مورد متغیر REVIEW_SHA که هنگام فراخوانی خط لوله از قلاب GitHub تنظیم می کنیم، صدق نمی کند.

ما داده های خارجی لازم را در یک اسکریپت Bash تولید می کنیم generate_artifacts، که دو آرتیفکت خط لوله GitLab ایجاد می کند:

  • فایل releases.yml با داده های انتشار،
  • فایل common_envs.sh، حاوی متغیرهای محیطی است که باید صادر شوند.

محتویات فایل generate_artifacts در ما پیدا خواهید کرد مخازن با مثال. دریافت خود داده موضوع مقاله نیست، بلکه فایل است common_envs.sh برای ما مهم است، زیرا کار ورف به آن بستگی دارد. نمونه ای از محتوای آن:

export RELEASES='1.0%v1.0.6-4'
export CHANNELS='1.0-alpha%v1.0.7-1 1.0-beta%v1.0.7-1 1.0-ea%v1.0.6-4 1.0-stable%v1.0.6-4 1.0-rock-solid%v1.0.6-4'
export ROOT_VERSION='v1.0.6-4'

می توانید از خروجی چنین اسکریپتی استفاده کنید، برای مثال با استفاده از تابع Bash source.

الان قسمت خوبش شروع میشود. برای اینکه هم ساخت و هم استقرار برنامه به درستی کار کند، لازم است از آن اطمینان حاصل شود werf.yaml بود همان کمترین در یک خط لوله. اگر این شرط رعایت نشود، امضای مراحلی که ورف در هنگام مونتاژ و مثلاً استقرار محاسبه می کند، متفاوت خواهد بود. این منجر به خطای استقرار می شود، زیرا ... تصویر مورد نیاز برای استقرار از بین خواهد رفت.

به عبارت دیگر، اگر در هنگام اسمبلی تصویر سایت، اطلاعات مربوط به نسخه‌ها و نسخه‌ها یکسان باشد و در زمان استقرار نسخه جدیدی منتشر شود و متغیرهای محیطی مقادیر متفاوتی داشته باشند، در این صورت استقرار با یک خطا ناموفق خواهد بود: پس از همه، مصنوع نسخه جدید هنوز ساخته نشده است.

اگر نسل werf.yaml به داده های خارجی بستگی دارد (به عنوان مثال، لیستی از نسخه های فعلی، مانند مورد ما)، سپس ترکیب و مقادیر چنین داده هایی باید در خط لوله ثبت شود. این امر به ویژه در صورتی مهم است که پارامترهای خارجی اغلب تغییر کنند.

خواهیم کرد دریافت و ثبت داده های خارجی در مرحله اول خط لوله در GitLab (پیش ساخت) و آنها را بیشتر در فرم انتقال دهید مصنوع GitLab CI. این به شما امکان می دهد تا کارهای خط لوله (ساخت، استقرار، پاکسازی) را با همان پیکربندی اجرا و راه اندازی مجدد کنید. werf.yaml.

محتویات صحنه پیش ساخت فایل .gitlab-ci.yml:

Prebuild:
  stage: prebuild
  script:
    - bash ./generate_artifacts 1> common_envs.sh
    - cat ./common_envs.sh
  artifacts:
    paths:
      - releases.yml
      - common_envs.sh
    expire_in: 2 week

پس از گرفتن داده های خارجی موجود در آرتیفکت، می توانید با استفاده از مراحل استاندارد خط لوله GitLab CI بسازید و استقرار دهید: Build و Deploy. ما خود خط لوله را با استفاده از قلاب هایی از مخزن werf GitHub راه اندازی می کنیم (یعنی زمانی که تغییراتی در مخزن GitHub وجود دارد). داده های مربوط به آنها را می توان در ویژگی های پروژه GitLab در بخش یافت تنظیمات CI/CD -> محرک های خط لولهو سپس Webhook مربوطه را در GitHub ایجاد کنید (تنظیمات -> Webhooks).

مرحله ساخت به شکل زیر خواهد بود:

Build:
  stage: build
  script:
    - type multiwerf && . $(multiwerf use 1.0 alpha --as-file)
    - type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
    - source common_envs.sh
    - werf build-and-publish --stages-storage :local
  except:
    refs:
      - schedules
  dependencies:
    - Prebuild

GitLab دو آرتیفکت از مرحله به مرحله ساخت اضافه می کند پیش ساخت، بنابراین ما متغیرها را با داده های ورودی آماده شده با استفاده از ساختار صادر می کنیم source common_envs.sh. مرحله ساخت را در همه موارد به جز راه اندازی خط لوله طبق برنامه شروع می کنیم. طبق برنامه، ما یک خط لوله را برای تمیز کردن اجرا خواهیم کرد - در این مورد نیازی به مونتاژ نیست.

در مرحله استقرار، ما دو کار را به طور جداگانه برای استقرار در مدارهای تولید و توسعه با استفاده از یک الگوی YAML شرح خواهیم داد:

.base_deploy: &base_deploy
  stage: deploy
  script:
    - type multiwerf && . $(multiwerf use 1.0 alpha --as-file)
    - type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
    - source common_envs.sh
    - werf deploy --stages-storage :local
  dependencies:
    - Prebuild
  except:
    refs:
      - schedules

Deploy to Production:
  <<: *base_deploy
  variables:
    WERF_KUBE_CONTEXT: prod
  environment:
    name: production
    url: werf.io
  only:
    refs:
      - master
  except:
    variables:
      - $REVIEW_SHA
    refs:
      - schedules

Deploy to Test:
  <<: *base_deploy
  variables:
    WERF_KUBE_CONTEXT: dev
  environment:
    name: test
    url: werf.test.flant.com
  except:
    refs:
      - schedules
  only:
    variables:
      - $REVIEW_SHA

وظایف اساساً تنها در نشان دادن زمینه خوشه‌ای که werf باید در آن استقرار را انجام دهد متفاوت است.WERF_KUBE_CONTEXT، و تنظیم متغیرهای محیط حلقه (environment.name и environment.url) که سپس در قالب های نمودار Helm استفاده می شوند. ما محتویات قالب ها را ارائه نمی دهیم، زیرا ... هیچ چیز جالبی برای موضوع مورد نظر وجود ندارد، اما می توانید آنها را در آن پیدا کنید مخازن مقاله.

لمس نهایی

از آنجایی که نسخه‌های werf اغلب منتشر می‌شوند، تصاویر جدید اغلب ساخته می‌شوند و Docker Registry دائماً رشد می‌کند. بنابراین، پیکربندی پاکسازی خودکار تصویر بر اساس سیاست ها ضروری است. انجام آن بسیار آسان است.

برای پیاده سازی شما نیاز دارید:

  • یک مرحله تمیز کردن را اضافه کنید .gitlab-ci.yml;
  • اضافه کردن اجرای دوره ای یک کار تمیز کردن؛
  • یک متغیر محیطی را با یک نشانه دسترسی نوشتن تنظیم کنید.

افزودن مرحله نظافت به .gitlab-ci.yml:

Cleanup:
  stage: cleanup
  script:
    - type multiwerf && . $(multiwerf use 1.0 alpha --as-file)
    - type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
    - source common_envs.sh
    - docker login -u nobody -p ${WERF_IMAGES_CLEANUP_PASSWORD} ${WERF_IMAGES_REPO}
    - werf cleanup --stages-storage :local
  only:
    refs:
      - schedules

ما قبلاً تقریباً همه اینها را کمی بالاتر دیده ایم - فقط برای پاک کردن آن باید ابتدا با یک توکن وارد رجیستری Docker شوید که حق حذف تصاویر در رجیستری Docker را دارد (توکن وظیفه GitLab CI که به طور خودکار صادر می شود این کار را نمی کند. چنین حقوقی دارند). توکن باید از قبل در GitLab ایجاد شود و مقدار آن در متغیر محیطی مشخص شود WERF_IMAGES_CLEANUP_PASSWORD پروژه (تنظیمات CI/CD -> متغیرها).

اضافه کردن یک کار تمیز کردن با برنامه زمانی مورد نیاز در انجام می شود CI/CD ->
برنامه
.

تمام: یک پروژه در رجیستری Docker دیگر دائماً از تصاویر استفاده نشده رشد نمی کند.

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

نتیجه

  1. ما یک ساختار مونتاژ منطقی دریافت کردیم: یک مصنوع در هر نسخه.
  2. مونتاژ جهانی است و هنگام انتشار نسخه های جدید werf نیازی به تغییرات دستی ندارد: اسناد موجود در وب سایت به طور خودکار به روز می شوند.
  3. دو تصویر برای خطوط مختلف مونتاژ می شوند.
  4. به سرعت کار می کند، زیرا تا جایی که ممکن است از حافظه پنهان استفاده می شود - زمانی که یک نسخه جدید از werf منتشر می شود یا یک قلاب GitHub برای بررسی commit فراخوانی می شود، فقط مصنوع مربوطه با نسخه تغییر یافته بازسازی می شود.
  5. نیازی نیست در مورد حذف تصاویر استفاده نشده فکر کنید: تمیز کردن طبق سیاست‌های werf باعث می‌شود رجیستری Docker مرتب شود.

یافته ها

  • استفاده از werf به اسمبلی این امکان را می دهد که به دلیل ذخیره سازی خود اسمبلی و ذخیره سازی هنگام کار با مخازن خارجی، سریع کار کند.
  • کار با مخازن Git خارجی نیاز به شبیه سازی کل مخزن هر بار یا اختراع مجدد چرخ با منطق بهینه سازی پیچیده را از بین می برد. werf از کش استفاده می کند و کلونینگ را فقط یک بار انجام می دهد و سپس استفاده می کند fetch و فقط در صورت لزوم
  • امکان استفاده از قالب های Go در فایل پیکربندی ساخت werf.yaml به شما امکان می دهد مجموعه ای را توصیف کنید که نتیجه آن به داده های خارجی بستگی دارد.
  • استفاده از mount در werf به طور قابل توجهی سرعت جمع آوری مصنوعات را افزایش می دهد - به دلیل وجود حافظه پنهان که در همه خطوط لوله مشترک است.
  • werf پیکربندی پاکسازی را آسان می کند، که به ویژه هنگام ساختن به صورت پویا مهم است.

PS

در وبلاگ ما نیز بخوانید:

منبع: www.habr.com

اضافه کردن نظر