Lắp ráp và triển khai động các hình ảnh Docker với werf bằng cách sử dụng ví dụ về trang tài liệu được phiên bản

Chúng tôi đã nhiều lần nói về công cụ GitOps của mình. người sói, và lần này chúng tôi muốn chia sẻ kinh nghiệm của mình trong việc lắp ráp trang web với tài liệu của chính dự án - werf.io (phiên bản tiếng Nga của nó là vi.werf.io). Đây là một trang web tĩnh thông thường, nhưng việc lắp ráp nó thú vị ở chỗ nó được xây dựng bằng cách sử dụng một số hiện vật động.

Lắp ráp và triển khai động các hình ảnh Docker với werf bằng cách sử dụng ví dụ về trang tài liệu được phiên bản

Đi sâu vào các sắc thái của cấu trúc trang web: tạo menu chung cho tất cả các phiên bản, các trang có thông tin về bản phát hành, v.v. - chúng tôi sẽ không. Thay vào đó, hãy tập trung vào các vấn đề và tính năng của lắp ráp động và một chút vào các quy trình CI/CD đi kèm.

Giới thiệu: cách hoạt động của trang web

Để bắt đầu, tài liệu werf được lưu trữ cùng với mã của nó. Điều này đặt ra một số yêu cầu phát triển nhất định thường nằm ngoài phạm vi của bài viết này, nhưng ở mức tối thiểu có thể nói rằng:

  • Các chức năng werf mới không được phát hành mà không cập nhật tài liệu và ngược lại, bất kỳ thay đổi nào trong tài liệu đều ngụ ý việc phát hành phiên bản mới của werf;
  • Dự án có sự phát triển khá chuyên sâu: các phiên bản mới có thể được phát hành nhiều lần trong ngày;
  • Bất kỳ thao tác thủ công nào để triển khai một trang web với phiên bản tài liệu mới ít nhất cũng tẻ nhạt;
  • Dự án áp dụng cách tiếp cận ngữ nghĩa phiên bản, với 5 kênh ổn định. Quá trình phát hành bao gồm việc chuyển các phiên bản tuần tự qua các kênh theo thứ tự tăng độ ổn định: từ alpha đến rock-solid;
  • Trang web có phiên bản tiếng Nga, phiên bản “sống và phát triển” (tức là nội dung được cập nhật) song song với phiên bản chính (tức là tiếng Anh).

Để che giấu tất cả “nhà bếp bên trong” này với người dùng, chúng tôi đã cung cấp cho anh ấy thứ gì đó “chỉ hoạt động” công cụ cài đặt và cập nhật werf riêng biệt - multiwerf. Bạn chỉ cần chỉ định số phát hành và kênh ổn định mà bạn đã sẵn sàng sử dụng, multiwerf sẽ kiểm tra xem có phiên bản mới trên kênh hay không và tải xuống nếu cần.

Trong menu chọn phiên bản trên trang web, các phiên bản mới nhất của werf đều có sẵn ở mỗi kênh. Theo mặc định, theo địa chỉ werf.io/documentation phiên bản của kênh ổn định nhất cho bản phát hành mới nhất sẽ mở ra - kênh này cũng được các công cụ tìm kiếm lập chỉ mục. Tài liệu cho kênh có sẵn tại các địa chỉ riêng biệt (ví dụ: werf.io/v1.0-beta/documentation cho phiên bản beta 1.0).

Tổng cộng, trang web có sẵn các phiên bản sau:

  1. root (mở theo mặc định),
  2. cho mỗi kênh cập nhật đang hoạt động của mỗi bản phát hành (ví dụ: werf.io/v1.0-beta).

Nói chung, để tạo một phiên bản cụ thể của một trang web, chỉ cần biên dịch nó bằng cách sử dụng Jekyllbằng cách chạy trong thư mục /docs kho lưu trữ werf lệnh tương ứng (jekyll build), sau khi chuyển sang thẻ Git của phiên bản được yêu cầu.

Nó chỉ còn lại để thêm rằng:

  • bản thân tiện ích (werf) được sử dụng để lắp ráp;
  • Các quy trình CI/CD được xây dựng trên nền tảng GitLab CI;
  • và tất nhiên tất cả điều này đều chạy trong Kubernetes.

nhiệm vụ

Bây giờ, hãy xây dựng các nhiệm vụ có tính đến tất cả các chi tiết cụ thể được mô tả:

  1. Sau khi thay đổi phiên bản werf trên bất kỳ kênh cập nhật nào tài liệu trên trang web sẽ được cập nhật tự động.
  2. Để phát triển, đôi khi bạn cần có khả năng xem phiên bản xem trước của trang web.

Trang web phải được biên dịch lại sau khi thay đổi phiên bản trên bất kỳ kênh nào từ thẻ Git tương ứng, nhưng trong quá trình xây dựng hình ảnh chúng ta sẽ có được các tính năng sau:

  • Do danh sách phiên bản trên các kênh thay đổi nên chỉ cần xây dựng lại tài liệu cho các kênh có phiên bản đã thay đổi. Rốt cuộc, việc xây dựng lại mọi thứ một lần nữa không hề tốt đẹp chút nào.
  • Tập hợp các kênh phát hành có thể thay đổi. Ví dụ: tại một số thời điểm, có thể không có phiên bản trên các kênh ổn định hơn bản phát hành 1.1 truy cập sớm, nhưng theo thời gian chúng sẽ xuất hiện - trong trường hợp này, bạn có nên thay đổi cụm theo cách thủ công không?

Nó chỉ ra rằng lắp ráp phụ thuộc vào việc thay đổi dữ liệu bên ngoài.

Thực hiện

Chọn một cách tiếp cận

Ngoài ra, bạn có thể chạy từng phiên bản được yêu cầu dưới dạng một nhóm riêng biệt trong Kubernetes. Tùy chọn này ngụ ý số lượng đối tượng lớn hơn trong cụm, sẽ tăng lên cùng với sự gia tăng số lượng bản phát hành werf ổn định. Và điều này hàm ý việc bảo trì phức tạp hơn: mỗi phiên bản có máy chủ HTTP riêng và có tải nhỏ. Tất nhiên, điều này cũng đòi hỏi chi phí tài nguyên lớn hơn.

Chúng ta đã đi cùng một con đường tập hợp tất cả các phiên bản cần thiết trong một hình ảnh. Các số liệu thống kê đã biên dịch của tất cả các phiên bản của trang web được đặt trong một vùng chứa NGINX và lưu lượng truy cập đến Triển khai tương ứng sẽ thông qua NGINX Ingress. Cấu trúc đơn giản - một ứng dụng không trạng thái - cho phép bạn dễ dàng mở rộng quy mô Triển khai (tùy thuộc vào tải) bằng chính Kubernetes.

Nói chính xác hơn, chúng tôi đang thu thập hai hình ảnh: một cho mạch sản xuất, hình thứ hai là một hình ảnh bổ sung cho mạch phát triển. Hình ảnh bổ sung chỉ được sử dụng (khởi chạy) trên mạch phát triển cùng với hình ảnh chính và chứa phiên bản của trang web từ cam kết đánh giá và việc định tuyến giữa chúng được thực hiện bằng cách sử dụng tài nguyên Ingress.

werf vs git clone và hiện vật

Như đã đề cập, để tạo số liệu thống kê trang web cho một phiên bản tài liệu cụ thể, bạn cần xây dựng bằng cách chuyển sang thẻ kho lưu trữ thích hợp. Bạn cũng có thể thực hiện việc này bằng cách sao chép kho lưu trữ mỗi khi xây dựng, chọn các thẻ thích hợp từ danh sách. Tuy nhiên, đây là một hoạt động khá tốn nhiều tài nguyên và hơn nữa, đòi hỏi phải viết các hướng dẫn không tầm thường... Một nhược điểm nghiêm trọng khác là với cách tiếp cận này không có cách nào để lưu vào bộ đệm một cái gì đó trong quá trình lắp ráp.

Ở đây chính tiện ích werf đã hỗ trợ chúng ta, thực hiện bộ nhớ đệm thông minh và cho phép bạn sử dụng kho lưu trữ bên ngoài. Sử dụng werf để thêm mã từ kho lưu trữ sẽ tăng tốc đáng kể quá trình xây dựng, bởi vì về cơ bản, werf sao chép kho lưu trữ một lần và sau đó thực thi chỉ fetch Nếu cần. Ngoài ra, khi thêm dữ liệu từ kho lưu trữ, chúng ta chỉ có thể chọn các thư mục cần thiết (trong trường hợp của chúng ta đây là thư mục docs), điều này sẽ làm giảm đáng kể lượng dữ liệu được thêm vào.

Vì Jekyll là một công cụ được thiết kế để biên dịch dữ liệu tĩnh và không cần thiết trong hình ảnh cuối cùng nên sẽ rất hợp lý khi biên dịch trong hiện vật của người sói, và vào hình ảnh cuối cùng chỉ nhập kết quả biên dịch.

Chúng tôi viết werf.yaml

Vì vậy, chúng tôi quyết định sẽ biên dịch từng phiên bản trong một tạo phẩm werf riêng biệt. Tuy nhiên, chúng tôi chúng tôi không biết sẽ có bao nhiêu hiện vật trong quá trình lắp ráp, vì vậy chúng tôi không thể viết cấu hình bản dựng cố định (nói đúng ra thì chúng tôi vẫn có thể, nhưng nó sẽ không hoàn toàn hiệu quả).

werf cho phép bạn sử dụng Đi mẫu trong tập tin cấu hình của bạn (werf.yaml), và điều này làm cho nó có thể tạo cấu hình nhanh chóng tùy thuộc vào dữ liệu bên ngoài (những gì bạn cần!). Dữ liệu bên ngoài trong trường hợp của chúng tôi là thông tin về các phiên bản và bản phát hành, trên cơ sở đó chúng tôi thu thập số lượng hiện vật cần thiết và kết quả là chúng tôi thu được hai hình ảnh: werf-doc и werf-dev để chạy trên các mạch khác nhau.

Dữ liệu bên ngoài được truyền qua các biến môi trường. Đây là thành phần của họ:

  • RELEASES — một dòng có danh sách các bản phát hành và phiên bản hiện tại tương ứng của werf, dưới dạng danh sách các giá trị được phân tách bằng dấu cách ở định dạng <НОМЕР_РЕЛИЗА>%<НОМЕР_ВЕРСИИ>. Thí dụ: 1.0%v1.0.4-beta.20
  • CHANNELS — một dòng có danh sách các kênh và phiên bản hiện tại tương ứng của werf, ở dạng danh sách các giá trị được phân tách bằng dấu cách ở định dạng <КАНАЛ>%<НОМЕР_ВЕРСИИ>. Thí dụ: 1.0-beta%v1.0.4-beta.20 1.0-alpha%v1.0.5-alpha.22
  • ROOT_VERSION — phiên bản phát hành werf được hiển thị theo mặc định trên trang web (không phải lúc nào cũng cần hiển thị tài liệu theo số phát hành cao nhất). Ví dụ: v1.0.4-beta.20
  • REVIEW_SHA — hàm băm của cam kết đánh giá mà từ đó bạn cần xây dựng phiên bản cho vòng lặp thử nghiệm.

Các biến này sẽ được điền vào quy trình GitLab CI và cách viết chính xác bên dưới.

Trước hết, để thuận tiện, chúng tôi định nghĩa ở werf.yaml Đi tới các biến mẫu, gán cho chúng các giá trị từ các biến môi trường:

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

Mô tả về tạo phẩm để biên dịch phiên bản tĩnh của trang web nhìn chung giống nhau cho tất cả các trường hợp chúng tôi cần (bao gồm cả việc tạo phiên bản gốc cũng như phiên bản cho mạch phát triển). Do đó, chúng ta sẽ chuyển nó vào một khối riêng bằng hàm define - để tái sử dụng tiếp theo bằng cách sử dụng include. Chúng tôi sẽ chuyển các đối số sau vào mẫu:

  • Version - phiên bản được tạo (tên thẻ);
  • Channel - tên của kênh cập nhật mà tạo phẩm được tạo ra;
  • Commit — hàm băm cam kết, nếu tạo phẩm được tạo ra cho một cam kết đánh giá;
  • định nghĩa bài văn.

Mô tả mẫu tạo tác

{{- 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 }}

Tên hiện vật phải là duy nhất. Chúng ta có thể đạt được điều này, ví dụ, bằng cách thêm tên kênh (giá trị của biến .Channel) làm hậu tố cho tên của hiện vật: artifact: doc-{{ .Channel }}. Nhưng bạn cần hiểu rằng khi nhập từ hiện vật, bạn sẽ cần phải tham chiếu đến những cái tên giống nhau.

Khi mô tả một tạo phẩm, tính năng werf sau đây được sử dụng: gắn. Gắn kết chỉ ra thư mục dịch vụ build_dir cho phép bạn lưu bộ đệm Jekyll giữa các lần chạy đường ống, điều này tăng tốc đáng kể việc lắp ráp lại.

Bạn cũng có thể nhận thấy việc sử dụng tập tin releases.yml là tệp YAML có dữ liệu phát hành được yêu cầu từ Github.com (một hiện vật thu được khi thực hiện một đường ống). Nó cần thiết khi biên soạn trang web, nhưng trong bối cảnh của bài viết, nó rất thú vị đối với chúng tôi vì nó phụ thuộc vào trạng thái của nó lắp ráp lại chỉ một hiện vật — một tạo phẩm của phiên bản gốc của trang web (không cần thiết trong các tạo phẩm khác).

Điều này được thực hiện bằng cách sử dụng câu lệnh điều kiện if Đi mẫu và thiết kế {{ $Root.Files.Get "releases.yml" | sha256sum }} trong giai đoạn giai đoạn. Nó hoạt động như sau: khi xây dựng một tạo phẩm cho phiên bản gốc (biến .Channel bằng root) hàm băm tập tin releases.yml ảnh hưởng đến chữ ký của toàn bộ giai đoạn, vì nó là một phần tên của tác vụ Ansible (tham số name). Như vậy, khi thay đổi nội dung tập tin releases.yml hiện vật tương ứng sẽ được tập hợp lại.

Ngoài ra, hãy chú ý khi làm việc với kho lưu trữ bên ngoài. Trong hình ảnh của một hiện vật từ kho lưu trữ werf, chỉ có thư mục được thêm vào /docsvà tùy thuộc vào các tham số được truyền, dữ liệu của thẻ bắt buộc hoặc cam kết đánh giá sẽ được thêm ngay lập tức.

Để sử dụng mẫu tạo phẩm nhằm tạo mô tả về tạo phẩm của các phiên bản kênh và bản phát hành được chuyển giao, chúng tôi tổ chức một vòng lặp trên biến .WerfVersions в werf.yaml:

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

Bởi vì vòng lặp sẽ tạo ra một số tạo phẩm (chúng tôi hy vọng như vậy), cần phải tính đến dấu phân cách giữa chúng - trình tự --- (Để biết thêm thông tin về cú pháp tệp cấu hình, xem tài liệu). Như đã định nghĩa trước đó, khi gọi một mẫu trong vòng lặp, chúng tôi chuyển các tham số phiên bản, URL và ngữ cảnh gốc.

Tương tự, nhưng không có vòng lặp, chúng tôi gọi mẫu tạo phẩm cho “trường hợp đặc biệt”: cho phiên bản gốc, cũng như phiên bản từ cam kết đánh giá:

{{ 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 }}

Xin lưu ý rằng tạo phẩm cho cam kết đánh giá sẽ chỉ được tạo nếu biến được đặt .WerfReviewCommit.

Các hiện vật đã sẵn sàng - đã đến lúc bắt đầu nhập!

Hình ảnh cuối cùng, được thiết kế để chạy trên Kubernetes, là NGINX thông thường có thêm tệp cấu hình máy chủ nginx.conf và tĩnh từ các đồ tạo tác. Ngoài tạo phẩm của phiên bản gốc của trang web, chúng ta cần lặp lại vòng lặp trên biến .WerfVersions để nhập các tạo phẩm của kênh và phiên bản phát hành + tuân theo quy tắc đặt tên tạo phẩm mà chúng tôi đã áp dụng trước đó. Vì mỗi tạo phẩm lưu trữ các phiên bản của trang web cho hai ngôn ngữ nên chúng tôi nhập chúng vào những vị trí do cấu hình cung cấp.

Mô tả hình ảnh cuối cùng 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 -}}

Hình ảnh bổ sung, cùng với hình ảnh chính, được khởi chạy trên mạch phát triển, chỉ chứa hai phiên bản của trang web: phiên bản từ cam kết đánh giá và phiên bản gốc của trang web (có nội dung chung và, nếu bạn nhớ , giải phóng dữ liệu). Do đó, hình ảnh bổ sung sẽ chỉ khác với hình ảnh chính ở phần nhập (và tất nhiên, ở tên):

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 }}

Như đã lưu ý ở trên, tạo phẩm cho cam kết đánh giá sẽ chỉ được tạo khi biến môi trường đã đặt được chạy REVIEW_SHA. Có thể không tạo được hình ảnh werf-dev nếu không có biến môi trường REVIEW_SHA, nhưng để dọn dẹp theo chính sách Hình ảnh Docker trong werf hoạt động cho hình ảnh werf-dev, chúng tôi sẽ chỉ xây dựng nó bằng tạo phẩm phiên bản gốc (dù sao thì nó cũng đã được tạo rồi), để đơn giản hóa cấu trúc quy trình.

Việc lắp ráp đã sẵn sàng! Hãy chuyển sang CI/CD và các sắc thái quan trọng.

Quy trình trong GitLab CI và các tính năng của bản dựng động

Khi chạy bản dựng, chúng ta cần đặt các biến môi trường được sử dụng trong werf.yaml. Điều này không áp dụng cho biến REVIEW_SHA mà chúng ta sẽ đặt khi gọi đường dẫn từ hook GitHub.

Chúng tôi sẽ tạo dữ liệu bên ngoài cần thiết trong tập lệnh Bash generate_artifacts, sẽ tạo ra hai tạo phẩm đường ống GitLab:

  • tập tin releases.yml với dữ liệu phát hành,
  • tập tin common_envs.sh, chứa các biến môi trường sẽ được xuất.

Nội dung tập tin generate_artifacts bạn sẽ tìm thấy trong chúng tôi kho lưu trữ với các ví dụ. Bản thân việc thu thập dữ liệu không phải là chủ đề của bài viết mà là tập tin common_envs.sh là quan trọng đối với chúng tôi, bởi vì công việc của werf phụ thuộc vào nó. Một ví dụ về nội dung của nó:

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'

Bạn có thể sử dụng đầu ra của tập lệnh như vậy, ví dụ: sử dụng hàm Bash source.

Bây giờ đến phần thú vị. Để cả quá trình xây dựng và triển khai ứng dụng hoạt động chính xác, cần phải đảm bảo rằng werf.yaml đã như nhau ít nhất trong một đường ống. Nếu điều kiện này không được đáp ứng thì chữ ký của các giai đoạn mà chúng tôi tính toán trong quá trình lắp ráp và, chẳng hạn như triển khai, sẽ khác nhau. Điều này sẽ dẫn đến lỗi triển khai, bởi vì... hình ảnh cần thiết để triển khai sẽ bị thiếu.

Nói cách khác, nếu trong quá trình lắp ráp hình ảnh trang web, thông tin về các bản phát hành và phiên bản giống nhau và tại thời điểm triển khai, một phiên bản mới được phát hành và các biến môi trường có các giá trị khác nhau thì quá trình triển khai sẽ thất bại kèm theo lỗi: Rốt cuộc thì tạo tác của phiên bản mới vẫn chưa được chế tạo.

Nếu thế hệ werf.yaml phụ thuộc vào dữ liệu bên ngoài (ví dụ: danh sách các phiên bản hiện tại, như trong trường hợp của chúng tôi), thì thành phần và giá trị của dữ liệu đó phải được ghi lại trong quy trình. Điều này đặc biệt quan trọng nếu các thông số bên ngoài thay đổi khá thường xuyên.

Chúng tôi sẽ nhận và ghi dữ liệu bên ngoài ở giai đoạn đầu tiên của quy trình trong GitLab (Tạo trước) và truyền chúng tiếp theo dưới dạng Tạo phẩm CI của GitLab. Điều này sẽ cho phép bạn chạy và khởi động lại các công việc quy trình (xây dựng, triển khai, dọn dẹp) với cùng cấu hình trong werf.yaml.

Nội dung sân khấu Tạo trước tập tin .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

Sau khi thu thập được dữ liệu bên ngoài trong tạo phẩm, bạn có thể xây dựng và triển khai bằng cách sử dụng các giai đoạn quy trình GitLab CI tiêu chuẩn: Xây dựng và Triển khai. Chúng tôi tự khởi chạy quy trình bằng cách sử dụng các hook từ kho lưu trữ GitHub của werf (tức là khi có thay đổi trong kho lưu trữ GitHub). Dữ liệu cho chúng có thể được tìm thấy trong thuộc tính dự án GitLab trong phần Cài đặt CI/CD -> Trình kích hoạt đường ống, sau đó tạo Webhook tương ứng trong GitHub (Cài đặt -> Webhook).

Giai đoạn xây dựng sẽ trông như thế này:

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 sẽ thêm hai tạo phẩm từ giai đoạn này sang giai đoạn xây dựng Tạo trước, vì vậy chúng tôi xuất các biến có dữ liệu đầu vào đã được chuẩn bị sẵn bằng cách sử dụng cấu trúc source common_envs.sh. Chúng tôi bắt đầu giai đoạn xây dựng trong mọi trường hợp, ngoại trừ việc khởi chạy quy trình theo lịch trình. Theo lịch trình, chúng tôi sẽ chạy đường ống để làm sạch - trong trường hợp này không cần thực hiện lắp ráp.

Ở giai đoạn triển khai, chúng tôi sẽ mô tả hai nhiệm vụ - riêng biệt để triển khai cho mạch sản xuất và mạch phát triển, sử dụng mẫu 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

Về cơ bản, các tác vụ chỉ khác nhau ở việc chỉ ra bối cảnh cụm mà werf sẽ thực hiện triển khai (WERF_KUBE_CONTEXT) và thiết lập các biến môi trường vòng lặp (environment.name и environment.url), sau đó được sử dụng trong các mẫu biểu đồ Helm. Chúng tôi sẽ không cung cấp nội dung của các mẫu, bởi vì... không có gì thú vị ở chủ đề được đề cập, nhưng bạn có thể tìm thấy chúng trong kho lưu trữ bài viết.

Liên lạc cuối cùng

Vì các phiên bản werf được phát hành khá thường xuyên nên các image mới sẽ được xây dựng thường xuyên và Docker Register sẽ không ngừng phát triển. Do đó, bắt buộc phải cấu hình dọn dẹp hình ảnh tự động dựa trên các chính sách. Nó rất dễ làm.

Để thực hiện bạn sẽ cần:

  • Thêm bước làm sạch vào .gitlab-ci.yml;
  • Thêm việc thực hiện định kỳ nhiệm vụ dọn dẹp;
  • Thiết lập biến môi trường bằng mã thông báo truy cập ghi.

Thêm một giai đoạn làm sạch vào .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

Chúng tôi đã thấy gần như tất cả những điều này cao hơn một chút - chỉ để làm sạch nó, trước tiên bạn cần đăng nhập vào Docker Đăng ký bằng mã thông báo có quyền xóa hình ảnh trong Docker Đăng ký (mã thông báo tác vụ GitLab CI được cấp tự động không có quyền đó). Mã thông báo phải được tạo trước trong GitLab và giá trị của nó phải được chỉ định trong biến môi trường WERF_IMAGES_CLEANUP_PASSWORD dự án (Cài đặt CI/CD -> Biến).

Việc thêm một công việc dọn dẹp với lịch trình yêu cầu được thực hiện trong CI/CD ->
Lịch
.

Vậy là xong: một dự án trong Docker Register sẽ không còn liên tục phát triển từ những image không được sử dụng nữa.

Ở cuối phần thực hành, hãy để tôi nhắc bạn rằng danh sách đầy đủ từ bài viết có sẵn trong đi:

Kết quả

  1. Chúng tôi đã nhận được cấu trúc tập hợp logic: một tạo phẩm cho mỗi phiên bản.
  2. Việc lắp ráp là phổ biến và không yêu cầu thay đổi thủ công khi phiên bản mới của werf được phát hành: tài liệu trên trang web được cập nhật tự động.
  3. Hai hình ảnh được ghép lại cho các đường viền khác nhau.
  4. Nó hoạt động nhanh chóng, bởi vì Bộ nhớ đệm được sử dụng nhiều nhất có thể - khi một phiên bản mới của werf được phát hành hoặc hook GitHub được gọi để cam kết đánh giá, chỉ tạo phẩm tương ứng với phiên bản đã thay đổi mới được xây dựng lại.
  5. Không cần phải suy nghĩ đến việc xóa các image không sử dụng: việc dọn dẹp theo chính sách của werf sẽ giữ cho Docker Docker luôn ngăn nắp.

Những phát hiện

  • Sử dụng werf cho phép tập hợp hoạt động nhanh chóng do bộ nhớ đệm của cả bản thân tập hợp và bộ nhớ đệm khi làm việc với các kho lưu trữ bên ngoài.
  • Làm việc với các kho lưu trữ Git bên ngoài giúp loại bỏ nhu cầu sao chép toàn bộ kho lưu trữ mỗi lần hoặc phát minh lại bánh xe bằng logic tối ưu hóa phức tạp. werf sử dụng bộ nhớ đệm và chỉ thực hiện sao chép một lần, sau đó sử dụng fetch và chỉ khi cần thiết.
  • Khả năng sử dụng mẫu Go trong tệp cấu hình bản dựng werf.yaml cho phép bạn mô tả một tổ hợp có kết quả phụ thuộc vào dữ liệu bên ngoài.
  • Việc sử dụng mount trong werf sẽ tăng tốc đáng kể việc thu thập các thành phần lạ - do bộ đệm, vốn phổ biến đối với tất cả các đường ống.
  • werf giúp dễ dàng định cấu hình dọn dẹp, điều này đặc biệt quan trọng khi xây dựng động.

PS

Đọc thêm trên blog của chúng tôi:

Nguồn: www.habr.com

Thêm một lời nhận xét