ΠžΠΏΠΈΡ‚Π²Π°ΠΌΠ΅ Π½ΠΎΠ²ΠΈ инструмСнти Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ ΠΈ автоматизация Π½Π° дСплоя Π² Kubernetes.

ΠžΠΏΠΈΡ‚Π²Π°ΠΌΠ΅ Π½ΠΎΠ²ΠΈ инструмСнти Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ ΠΈ автоматизация Π½Π° дСплоя Π² Kubernetes.

Π—Π΄Ρ€Π°Π²Π΅ΠΉΡ‚Π΅! НапослСдък излязоха ΠΌΠ½ΠΎΠ³ΠΎ страхотни инструмСнти Π·Π° автоматизация ΠΊΠ°ΠΊΡ‚ΠΎ Π·Π° създаванС Π½Π° Docker изобраТСния, Ρ‚Π°ΠΊΠ° ΠΈ Π·Π° внСдряванС Π² Kubernetes. Π’ Ρ‚Π°Π·ΠΈ Π²Ρ€ΡŠΠ·ΠΊΠ° Ρ€Π΅ΡˆΠΈΡ… Π΄Π° сС поиграя с GitLab, Π΄Π° Ρ€Π°Π·Π³Π»Π΅Π΄Π°ΠΌ Π²ΡŠΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΠΈΡ‚Π΅ ΠΌΡƒ ΠΈ, Ρ€Π°Π·Π±ΠΈΡ€Π° сС, Π΄Π° настроя ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½.

Π’Π΄ΡŠΡ…Π½ΠΎΠ²Π΅Π½ΠΈΠ΅Ρ‚ΠΎ Π·Π° Ρ‚Π°Π·ΠΈ Ρ€Π°Π±ΠΎΡ‚Π° Π΅ ΡƒΠ΅Π±ΡΠ°ΠΉΡ‚ΡŠΡ‚ kubernetes.io, ΠΊΠΎΠΉΡ‚ΠΎ сС Π³Π΅Π½Π΅Ρ€ΠΈΡ€Π° ΠΎΡ‚ ΠΈΠ·Ρ…ΠΎΠ΄Π½ΠΈ ΠΊΠΎΠ΄ΠΎΠ²Π΅ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π½ΠΎ, Π° Π·Π° всяко внСсСно исканС Π·Π° изтСглянС, Ρ€ΠΎΠ±ΠΎΡ‚ΡŠΡ‚ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π½ΠΎ Π³Π΅Π½Π΅Ρ€ΠΈΡ€Π° ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»Π½Π° вСрсия Π½Π° сайта с Π²Π°ΡˆΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ ΠΈ прСдоставя Π»ΠΈΠ½ΠΊ Π·Π° ΠΏΡ€Π΅Π³Π»Π΅Π΄.

ΠžΠΏΠΈΡ‚Π°Ρ… сС Π΄Π° изградя ΠΏΠΎΠ΄ΠΎΠ±Π΅Π½ процСс ΠΎΡ‚ Π½ΡƒΠ»Π°Ρ‚Π°, напълно Π±Π°Π·ΠΈΡ€Π°Π½ Π½Π° GitLab CI ΠΈ свободни инструмСнти, ΠΊΠΎΠΈΡ‚ΠΎ съм свикнал Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌ Π·Π° внСдряванС Π½Π° прилоТСния Π² Kubernetes. ДнСс, накрая, Ρ‰Π΅ Π²ΠΈ Ρ€Π°Π·ΠΊΠ°ΠΆΠ° Π·Π° тях ΠΏΠΎ-ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ.

Π’ статията Ρ‰Π΅ Π±ΡŠΠ΄Π°Ρ‚ Ρ€Π°Π·Π³Π»Π΅Π΄Π°Π½ΠΈ слСднитС инструмСнти:
Hugo, qbec, kaniko, git-crypt ΠΈ GitLab CI създаванС Π½Π° Π΄ΠΈΠ½Π°ΠΌΠΈΡ‡Π½ΠΈ срСди.

Π‘ΡŠΠ΄ΡŠΡ€ΠΆΠ°Π½ΠΈΠ΅

  1. Π—Π°ΠΏΠΎΠ·Π½Π°Π²Π°Π½Π΅ с Hugo
  2. ΠŸΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠ° Π½Π° Dockerfile
  3. Π—Π°ΠΏΠΎΠ·Π½Π°Π²Π°Π½Π΅ с kaniko
  4. Π—Π°ΠΏΠΎΠ·Π½Π°Π²Π°Π½Π΅ с qbec
  5. ВСстванС Π½Π° GitLab-runner с Kubernetes-executor
  6. ВнСдряванС Π½Π° Helm-Ρ‡Π°Ρ€Ρ‚ΠΈ с qbec
  7. Π—Π°ΠΏΠΎΠ·Π½Π°Π²Π°Π½Π΅ с git-crypt
  8. БъздаванС Π½Π° ΠΎΠ±Ρ€Π°Π· Π½Π° инструмСнтариум
  9. ΠΠ°ΡˆΠΈΡΡ‚ ΠΏΡŠΡ€Π²ΠΈ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ ΠΈ сборка Π½Π° изобраТСния ΠΏΠΎ Ρ‚Π°Π³ΠΎΠ²Π΅
  10. Автоматизация Π½Π° внСдряванСто
  11. АртСфакти ΠΈ сборка ΠΏΡ€ΠΈ push Π² master
  12. Π”ΠΈΠ½Π°ΠΌΠΈΡ‡ΠΊΠΈ срСдини
  13. ΠŸΡ€Π΅Π³Π»Π΅Π΄Π½ΠΈ прилоТСния

1. Π—Π°ΠΏΠΎΠ·Π½Π°Π²Π°Π½Π΅ с Hugo

ΠšΠ°Ρ‚ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π·Π° нашия ΠΏΡ€ΠΎΠ΅ΠΊΡ‚, Ρ‰Π΅ сС ΠΎΠΏΠΈΡ‚Π°ΠΌΠ΅ Π΄Π° създадСм сайт Π·Π° ΠΏΡƒΠ±Π»ΠΈΠΊΡƒΠ²Π°Π½Π΅ Π½Π° докумСнтация, Π±Π°Π·ΠΈΡ€Π°Π½ Π½Π° Hugo. Hugo Π΅ статичСн Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€ Π½Π° ΡΡŠΠ΄ΡŠΡ€ΠΆΠ°Π½ΠΈΠ΅.

Π—Π° Ρ‚Π΅Π·ΠΈ, ΠΊΠΎΠΈΡ‚ΠΎ Π½Π΅ са Π·Π°ΠΏΠΎΠ·Π½Π°Ρ‚ΠΈ със статичнитС Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€ΠΈ, Ρ‰Π΅ Ρ€Π°Π·ΠΊΠ°ΠΆΠ° ΠΌΠ°Π»ΠΊΠΎ ΠΏΠΎΠ²Π΅Ρ‡Π΅ Π·Π° тях. Π’ ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ ΠΎΠ±ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΈΡ‚Π΅ ΡƒΠ΅Π± ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠΈ с Π±Π°Π·Π° Π΄Π°Π½Π½ΠΈ ΠΈ PHP, ΠΊΠΎΠΈΡ‚ΠΎ Π³Π΅Π½Π΅Ρ€ΠΈΡ€Π°Ρ‚ страници Π½Π° Π»Π΅Ρ‚ΠΎ ΠΏΡ€ΠΈ заявка ΠΎΡ‚ потрСбитСля, статичнитС Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€ΠΈ работят ΠΌΠ°Π»ΠΊΠΎ ΠΏΠΎ-Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΎ. Π’Π΅ позволяват Π΄Π° сС Π²Π·Π΅ΠΌΠ°Ρ‚ ΠΈΠ·Ρ…ΠΎΠ΄Π½ΠΈ Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅, ΠΎΠ±ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΎ Π½Π°Π±ΠΎΡ€ ΠΎΡ‚ Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ Π² Markdown Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ ΠΈ шаблони, слСд ΠΊΠΎΠ΅Ρ‚ΠΎ Π΄Π° сС ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€Π°Ρ‚ Π² напълно Π³ΠΎΡ‚ΠΎΠ² сайт.

ВоСст, Π½Π° ΠΈΠ·Ρ…ΠΎΠ΄Π° Ρ‰Π΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ структура ΠΎΡ‚ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ ΠΈ Π½Π°Π±ΠΎΡ€ ΠΎΡ‚ Π³Π΅Π½Π΅Ρ€ΠΈΡ€Π°Π½ΠΈ HTML Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅, ΠΊΠΎΠΈΡ‚ΠΎ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ просто Π΄Π° ΠΊΠ°Ρ‡ΠΈΡ‚Π΅ Π½Π° всякакъв Π΅Π²Ρ‚ΠΈΠ½ хостинг ΠΈ Π΄Π° ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ Ρ€Π°Π±ΠΎΡ‚Π΅Ρ‰ сайт.

Hugo ΠΌΠΎΠΆΠ΅ Π΄Π° бъдС инсталиран Π»ΠΎΠΊΠ°Π»Π½ΠΎ ΠΈ Π΄Π° сС ΠΎΠΏΠΈΡ‚Π° Π² дСйствиС:

Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€Π°ΠΌΠ΅ Π½ΠΎΠ² сайт:

hugo new site docs.example.org

И Π΅Π΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ с Ρ‚ΠΎΠ²Π° ΠΈ Git Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ:

cd docs.example.org
git init

Π’ ΠΌΠΎΠΌΠ΅Π½Ρ‚Π° Π½Π°ΡˆΠΈΡΡ‚ сайт Π΅ напълно чист ΠΈ, Π·Π° Π΄Π° сС появи Π½Π΅Ρ‰ΠΎ Π½Π° Π½Π΅Π³ΠΎ, ΠΏΡŠΡ€Π²ΠΎ трябва Π΄Π° ΡΠ²ΡŠΡ€ΠΆΠ΅ΠΌ Ρ‚Π΅ΠΌΠ°, Ρ‚Π΅ΠΌΠ°Ρ‚Π° Π΅ просто Π½Π°Π±ΠΎΡ€ ΠΎΡ‚ шаблони ΠΈ Π·Π°Π΄Π°Π΄Π΅Π½ΠΈ ΠΏΡ€Π°Π²ΠΈΠ»Π°, ΠΏΠΎ ΠΊΠΎΠΈΡ‚ΠΎ сС Π³Π΅Π½Π΅Ρ€ΠΈΡ€Π° Π½Π°ΡˆΠΈΡΡ‚ сайт.

Π’Π΅ΠΌΠ°Ρ‚Π°, която Ρ‰Π΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅, Π΅ Learn, която, спорСд ΠΌΠ΅Π½, Π΅ Π½Π°ΠΉ-подходяща Π·Π° сайт с докумСнтация.

ΠžΡ‚Π΄Π΅Π»Π½ΠΎ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ заслуТава Ρ„Π°ΠΊΡ‚ΡŠΡ‚, Ρ‡Π΅ Π½Π΅ Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π΄Π° Π·Π°ΠΏΠ°Π·Π²Π°ΠΌΠ΅ Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅Ρ‚Π΅ Π½Π° Ρ‚Π΅ΠΌΠ°Ρ‚Π° Π² рСпозитория Π½Π° нашия ΠΏΡ€ΠΎΠ΅ΠΊΡ‚; вмСсто Ρ‚ΠΎΠ²Π° ΠΌΠΎΠΆΠ΅ΠΌ просто Π΄Π° я ΡΠ²ΡŠΡ€ΠΆΠ΅ΠΌ, ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΉΠΊΠΈ git submodule:

git submodule add https://github.com/matcornic/hugo-theme-learn themes/learn

По Ρ‚ΠΎΠ·ΠΈ Π½Π°Ρ‡ΠΈΠ½ Π² нашия Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ Ρ‰Π΅ сС Π½Π°ΠΌΠΈΡ€Π°Ρ‚ само Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅Ρ‚Π΅, ΠΊΠΎΠΈΡ‚ΠΎ са пряко ΡΠ²ΡŠΡ€Π·Π°Π½ΠΈ с нашия ΠΏΡ€ΠΎΠ΅ΠΊΡ‚, Π° ΡΠ²ΡŠΡ€Π·Π°Π½Π°Ρ‚Π° Ρ‚Π΅ΠΌΠ° Ρ‰Π΅ останС ΠΊΠ°Ρ‚ΠΎ Π»ΠΈΠ½ΠΊ към ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π΅Π½ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ ΠΈ ΠΊΠΎΠΌΠΈΡ‚ Π² Π½Π΅Π³ΠΎ, тоСст Π²ΠΈΠ½Π°Π³ΠΈ Ρ‰Π΅ ΠΌΠΎΠΆΠ΅ Π΄Π° бъдС ΠΈΠ·Ρ‚Π΅Π³Π»Π΅Π½Π° ΠΎΡ‚ оригиналния ΠΈΠ·Ρ‚ΠΎΡ‡Π½ΠΈΠΊ Π±Π΅Π· риск ΠΎΡ‚ Π½Π΅ΡΡŠΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΈ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ.

НСка ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈΠΌ конфигурацията config.toml:

baseURL = "http://docs.example.org/"
languageCode = "en-us"
title = "My Docs Site"
theme = "learn"

На Ρ‚ΠΎΠ·ΠΈ Π΅Ρ‚Π°ΠΏ ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° стартирамС:

hugo server

И Π½Π° адрСс http://localhost:1313/ ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ нашия новосъздадСн сайт, всички ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ, Π½Π°ΠΏΡ€Π°Π²Π΅Π½ΠΈ Π² дирСкторията, Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π½ΠΎ обновяват ΠΎΡ‚Π²ΠΎΡ€Π΅Π½Π°Ρ‚Π° страница Π² Π±Ρ€Π°ΡƒΠ·ΡŠΡ€Π°, ΠΌΠ½ΠΎΠ³ΠΎ ΡƒΠ΄ΠΎΠ±Π½ΠΎ!

НСка ΠΎΠΏΠΈΡ‚Π°ΠΌΠ΅ Π΄Π° създадСм Π·Π°Π³Π»Π°Π²Π½Π° страница Π² content/_index.md:

# My docs site

## Welcome to the docs!

You will be very smart :-)

Π‘ΠΊΡ€ΠΈΠ½ΡˆΠΎΡ‚ Π½Π° Ρ‚ΠΎΠΊΡƒ-Ρ‰ΠΎ ΡΡŠΠ·Π΄Π°Π΄Π΅Π½Π°Ρ‚Π° страница

ΠžΠΏΠΈΡ‚Π²Π°ΠΌΠ΅ Π½ΠΎΠ²ΠΈ инструмСнти Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ ΠΈ автоматизация Π½Π° дСплоя Π² Kubernetes.

Π—Π° Π³Π΅Π½Π΅Ρ€ΠΈΡ€Π°Π½Π΅ Π½Π° сайта Π΅ Π΄ΠΎΡΡ‚Π°Ρ‚ΡŠΡ‡Π½ΠΎ Π΄Π° стартирамС:

hugo

Π‘ΡŠΠ΄ΡŠΡ€ΠΆΠ°Π½ΠΈΠ΅Ρ‚ΠΎ Π½Π° дирСкторията public/ Ρ‰Π΅ прСдставлява вашия сайт.
Π”Π°, ΠΌΠ΅ΠΆΠ΄Ρƒ Π΄Ρ€ΡƒΠ³ΠΎΡ‚ΠΎ, Π½Π΅ΠΊΠ° Π²Π΅Π΄Π½Π°Π³Π° я Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π² .gitignore:

echo /public > .gitignore

НС забравяйтС Π΄Π° ΠΊΠΎΠΌΠΈΡ‚Π½Π΅ΠΌ Π½Π°ΡˆΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ:

git add .
git commit -m "New site created"

2. ΠŸΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠ° Π½Π° Dockerfile

Π’Ρ€Π΅ΠΌΠ΅ Π΅ Π΄Π° ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠΌ структурата Π½Π° нашия Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ. ОбикновСно ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌ Π½Π΅Ρ‰ΠΎ ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΎ:

.
β”œβ”€β”€ deploy
β”‚   β”œβ”€β”€ app1
β”‚   └── app2
└── dockerfiles
    β”œβ”€β”€ image1
    └── image2

  • dockerfiles/ ΡΡŠΠ΄ΡŠΡ€ΠΆΠ° Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ с Dockerfiles ΠΈ всичко Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ Π½Π° Π½Π°ΡˆΠΈΡ‚Π΅ docker-ΠΎΠ±Ρ€Π°Π·ΠΈ.
  • deploy/ ΡΡŠΠ΄ΡŠΡ€ΠΆΠ° Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ Π·Π° Π΄Π΅ΠΏΠ»ΠΎΠΉ Π½Π° Π½Π°ΡˆΠΈΡ‚Π΅ прилоТСния Π² Kubernetes.

По Ρ‚ΠΎΠ·ΠΈ Π½Π°Ρ‡ΠΈΠ½ Π½Π°ΡˆΠΈΡΡ‚ ΠΏΡŠΡ€Π²ΠΈ Dockerfile Ρ‰Π΅ създадСм ΠΏΠΎ ΠΏΡŠΡ‚Ρ dockerfiles/website/Dockerfile

FROM alpine:3.11 as builder
ARG HUGO_VERSION=0.62.0
RUN wget -O- https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_linux-64bit.tar.gz | tar -xz -C /usr/local/bin
ADD . /src
RUN hugo -s /src

FROM alpine:3.11
RUN apk add --no-cache darkhttpd
COPY --from=builder /src/public /var/www
ENTRYPOINT [ "/usr/bin/darkhttpd" ]
CMD [ "/var/www" ]

ΠšΠ°ΠΊΡ‚ΠΎ ΠΌΠΎΠΆΠ΅ Π΄Π° Π·Π°Π±Π΅Π»Π΅ΠΆΠΈΡ‚Π΅, Dockerfile ΡΡŠΠ΄ΡŠΡ€ΠΆΠ° Π΄Π²Π° FROM, Ρ‚Π°Π·ΠΈ Π²ΡŠΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ сС Π½Π°Ρ€ΠΈΡ‡Π° multi-stage build ΠΈ позволява ΠΈΠ·ΠΊΠ»ΡŽΡ‡Π²Π°Π½Π΅Ρ‚ΠΎ Π½Π° всичко Π½Π΅Π½ΡƒΠΆΠ½ΠΎ ΠΎΡ‚ финалния docker-ΠΎΠ±Ρ€Π°Π·.
По Ρ‚ΠΎΠ·ΠΈ Π½Π°Ρ‡ΠΈΠ½ финалният ΠΎΠ±Ρ€Π°Π· Ρ‰Π΅ ΡΡŠΠ΄ΡŠΡ€ΠΆΠ° само darkhttpd (Π»Π΅ΠΊ HTTP-сСрвСр) ΠΈ public/ ΡΡŠΠ΄ΡŠΡ€ΠΆΠ°Π½ΠΈΠ΅Ρ‚ΠΎ Π½Π° нашия статично Π³Π΅Π½Π΅Ρ€ΠΈΡ€Π°Π½ сайт.

НС забравяйтС Π΄Π° ΠΊΠΎΠΌΠΈΡ‚Π½Π΅ΠΌ Π½Π°ΡˆΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ:

git add dockerfiles/website
git commit -m "Add Dockerfile for website"

3. Π—Π°ΠΏΠΎΠ·Π½Π°Π²Π°Π½Π΅ с kaniko

ΠšΠ°Ρ‚ΠΎ сборщик Π½Π° docker ΠΎΠ±Ρ€Π°Π·ΠΈ Ρ€Π΅ΡˆΠΈΡ… Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌ kaniko, Ρ‚ΡŠΠΉ ΠΊΠ°Ρ‚ΠΎ Π·Π° Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚Π° ΠΌΡƒ Π½Π΅ Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌ docker Π΄Π΅ΠΌΠΎΠ½, Π° самата сборка ΠΌΠΎΠΆΠ΅ Π΄Π° сС ΠΈΠ·Π²ΡŠΡ€ΡˆΠ²Π° Π½Π° всяка машина ΠΈ ΠΊΠ΅ΡˆΡŠΡ‚ ΠΌΠΎΠΆΠ΅ Π΄Π° сС ΡΡŠΡ…Ρ€Π°Π½ΡΠ²Π° Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ Π² рСгистратурата, ΠΊΠ°Ρ‚ΠΎ ΠΏΠΎ Ρ‚ΠΎΠ·ΠΈ Π½Π°Ρ‡ΠΈΠ½ сС избягва нСобходимостта ΠΎΡ‚ ΠΏΡŠΠ»Π½ΠΎΡ†Π΅Π½Π΅Π½ пСрсистСнтСн склад.

Π—Π° Π΄Π° построитС ΠΎΠ±Ρ€Π°Π·, Π΅ Π΄ΠΎΡΡ‚Π°Ρ‚ΡŠΡ‡Π½ΠΎ Π΄Π° стартиратС ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π° с kaniko executor ΠΈ Π΄Π° ΠΌΡƒ ΠΏΡ€Π΅Π΄Π°Π΄Π΅Ρ‚Π΅ тСкущия контСкст Π½Π° сборката, Ρ‚ΠΎΠ²Π° ΠΌΠΎΠΆΠ΅ Π΄Π° сС Π½Π°ΠΏΡ€Π°Π²ΠΈ ΠΈ Π»ΠΎΠΊΠ°Π»Π½ΠΎ, Ρ‡Ρ€Π΅Π· docker:

docker run -ti --rm 
  -v $PWD:/workspace 
  -v ~/\.docker/config.json:/kaniko/.docker/config.json:ro 
  gcr.io/kaniko-project/executor:v0.15.0 
  --cache 
  --dockerfile=dockerfiles/website/Dockerfile 
  --destination=registry.gitlab.com/kvaps/docs.example.org/website:v0.0.1

КъдС registry.gitlab.com/kvaps/docs.example.org/website β€” ΠΈΠΌΠ΅Ρ‚ΠΎ Π½Π° вашия docker ΠΎΠ±Ρ€Π°Π·, слСд сборката Ρ‚ΠΎΠΉ Ρ‰Π΅ бъдС Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π½ΠΎ ΠΊΠ°Ρ‡Π΅Π½ Π² docker рСгистратурата.

ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚ΡŠΡ€ β€”cache позволява ΠΊΠ΅ΡˆΠΈΡ€Π°Π½Π΅ Π½Π° слоСвС Π² docker рСгистратурата, Π·Π° привСдСния ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Ρ‚Π΅ Ρ‰Π΅ Π±ΡŠΠ΄Π°Ρ‚ Π·Π°ΠΏΠ°Π·Π΅Π½ΠΈ Π² registry.gitlab.com/kvaps/docs.example.org/website/cache, Π½ΠΎ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° посочитС ΠΈ Π΄Ρ€ΡƒΠ³ ΠΏΡŠΡ‚ с ΠΏΠΎΠΌΠΎΡ‰Ρ‚Π° Π½Π° ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚ΡŠΡ€Π° β€”cache-repo.

Π‘ΠΊΡ€ΠΈΠ½ΡˆΠΎΡ‚ Π½Π° docker-registry

ΠžΠΏΠΈΡ‚Π²Π°ΠΌΠ΅ Π½ΠΎΠ²ΠΈ инструмСнти Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ ΠΈ автоматизация Π½Π° дСплоя Π² Kubernetes.

4. Π—Π°ΠΏΠΎΠ·Π½Π°Π²Π°Π½Π΅ с qbec

Qbec β€” Π΅ инструмСнт Π·Π° Ρ€Π°Π·Π³Ρ€ΡŠΡ‰Π°Π½Π΅, ΠΊΠΎΠΉΡ‚ΠΎ позволява Π΄Π΅ΠΊΠ»Π°Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎ Π΄Π° описватС манифСститС Π½Π° Π²Π°ΡˆΠ΅Ρ‚ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ Π΄Π° Π³ΠΈ Ρ€Π°Π·Π³Ρ€ΡŠΡ‰Π°Ρ‚Π΅ Π² Kubernetes. Π˜Π·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅Ρ‚ΠΎ Π½Π° Jsonnet ΠΊΠ°Ρ‚ΠΎ основСн синтаксис позволява Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»Π½ΠΎ опростяванС Π½Π° описаниСто Π½Π° различията Π·Π° няколко срСди ΠΈ ΠΏΠΎΡ‡Ρ‚ΠΈ напълно избягва повторяСмостта Π½Π° ΠΊΠΎΠ΄Π°.

Π’ΠΎΠ²Π° ΠΌΠΎΠΆΠ΅ Π΄Π° Π΅ особСно Π°ΠΊΡ‚ΡƒΠ°Π»Π½ΠΎ Π² случаитС, ΠΊΠΎΠ³Π°Ρ‚ΠΎ трябва Π΄Π° Ρ€Π°Π·Π³Ρ€ΡŠΡ‰Π°Ρ‚Π΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π² няколко ΠΊΠ»ΡŠΡΡ‚Π΅Ρ€Π° с Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈ ΠΈ искатС Π΄Π΅ΠΊΠ»Π°Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎ Π΄Π° Π³ΠΈ ΠΎΠΏΠΈΡˆΠ΅Ρ‚Π΅ Π² Git.

Qbec ΡΡŠΡ‰ΠΎ Ρ‚Π°ΠΊΠ° позволява Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΡ€Π°Π½Π΅ Π½Π° Helm-Ρ‡Π°Ρ€Ρ‚ΠΈ, ΠΏΡ€Π΅Π΄Π°Π²Π°ΠΉΠΊΠΈ ΠΈΠΌ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΈΡ‚Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈ ΠΈ слСд Ρ‚ΠΎΠ²Π° Π΄Π° сС Ρ€Π°Π±ΠΎΡ‚ΠΈ с тях Ρ‚ΠΎΡ‡Π½ΠΎ ΠΊΠ°Ρ‚ΠΎ с ΠΎΠ±ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΈ манифСсти, Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅Π»Π½ΠΎ Π²ΡŠΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚Ρ‚Π° Π·Π° Π½Π°Π»Π°Π³Π°Π½Π΅ Π½Π° Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ ΠΌΡƒΡ‚Π°Ρ†ΠΈΠΈ, Π° Ρ‚ΠΎΠ²Π°, ΠΎΡ‚ своя страна, позволява Π΄Π° сС ΠΈΠ·Π±Π΅Π³Π½Π΅ нСобходимостта ΠΎΡ‚ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π½Π° ChartMuseum. ВоСст, ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° ΡΡŠΡ…Ρ€Π°Π½ΡΠ²Π°Ρ‚Π΅ ΠΈ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΡ€Π°Ρ‚Π΅ Ρ‡Π°Ρ€Ρ‚ΠΎΠ²Π΅ Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ ΠΎΡ‚ git, ΠΊΡŠΠ΄Π΅Ρ‚ΠΎ ΠΈΠΌ Π΅ ΠΈ мястото.

ΠšΠ°ΠΊΡ‚ΠΎ спомСнах ΠΏΠΎ-Ρ€Π°Π½ΠΎ, всички Ρ€Π°Π·Π³Ρ€ΡŠΡ‰Π°Π½ΠΈΡ Ρ‰Π΅ Π±ΡŠΠ΄Π°Ρ‚ ΡΡŠΡ…Ρ€Π°Π½ΡΠ²Π°Π½ΠΈ Π² дирСкторията deploy/:

mkdir deploy
cd deploy

НСка ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€Π°ΠΌΠ΅ Π½Π°ΡˆΠ΅Ρ‚ΠΎ ΠΏΡŠΡ€Π²ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅:

qbec init website
cd website

Π‘Π΅Π³Π° структурата Π½Π° Π½Π°ΡˆΠ΅Ρ‚ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ·Π³Π»Π΅ΠΆΠ΄Π° Ρ‚Π°ΠΊΠ°:

.
β”œβ”€β”€ components
β”œβ”€β”€ environments
β”‚   β”œβ”€β”€ base.libsonnet
β”‚   └── default.libsonnet
β”œβ”€β”€ params.libsonnet
└── qbec.yaml

Π”Π° Ρ€Π°Π·Π³Π»Π΅Π΄Π°ΠΌΠ΅ Ρ„Π°ΠΉΠ»Π° qbec.yaml:

apiVersion: qbec.io/v1alpha1
kind: App
metadata:
  name: website
spec:
  environments:
    default:
      defaultNamespace: docs
      server: https://kubernetes.example.org:8443
  vars: {}

Π’ΡƒΠΊ Π½ΠΈ интСрСсува Π² прСдимствСни Ρ€Π΅Π΄ spec.environments, qbec Π²Π΅Ρ‡Π΅ Π΅ създал Π·Π° нас ΠΏΠΎΠ΄Ρ€Π°Π·Π±ΠΈΡ€Π°Ρ‰Π°Ρ‚Π° сС срСда ΠΈ Π΅ Π²Π·Π΅Π» адрСса Π½Π° ΡΡŠΡ€Π²ΡŠΡ€Π°, ΠΊΠ°ΠΊΡ‚ΠΎ ΠΈ namespace ΠΎΡ‚ нашия Ρ‚Π΅ΠΊΡƒΡ‰ kubeconfig.
Π‘Π΅Π³Π° ΠΏΡ€ΠΈ Π΄Π΅ΠΏΠ»ΠΎΠΉ Π² ΠΏΠΎ ΠΏΠΎΠ΄Ρ€Π°Π·Π±ΠΈΡ€Π°Π½Π΅ срСда, qbec Π²ΠΈΠ½Π°Π³ΠΈ Ρ‰Π΅ Π΄Π΅ΠΏΠ»ΠΎΠΉΠ²Π° само Π² ΡƒΠΊΠ°Π·Π°Π½ Kubernetes ΠΊΠ»ΡŠΡΡ‚Π΅Ρ€ ΠΈ Π² ΡƒΠΊΠ°Π·Π°Π½ namespace, тоСст Π²ΠΈΠ΅ Π²Π΅Ρ‡Π΅ няма Π΄Π° трябва Π΄Π° ΠΏΡ€Π΅Π²ΠΊΠ»ΡŽΡ‡Π²Π°Ρ‚Π΅ ΠΌΠ΅ΠΆΠ΄Ρƒ контСксти ΠΈ namespaces, Π·Π° Π΄Π° ΠΎΡΡŠΡ‰Π΅ΡΡ‚Π²ΠΈΡ‚Π΅ Π΄Π΅ΠΏΠ»ΠΎΠΉ.
Π’ случай Π½Π° нСобходимост, Π²ΠΈΠ½Π°Π³ΠΈ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π°ΠΊΡ‚ΡƒΠ°Π»ΠΈΠ·ΠΈΡ€Π°Ρ‚Π΅ настройкитС Π² Ρ‚ΠΎΠ·ΠΈ Ρ„Π°ΠΉΠ».

Всички ваши срСди са описани Π² qbec.yaml, ΠΈ Π² Ρ„Π°ΠΉΠ»Π° params.libsonnet, ΠΊΡŠΠ΄Π΅Ρ‚ΠΎ Π΅ посочСно ΠΎΡ‚ къдС Π΄Π° сС Π²Π·Π΅ΠΌΠ°Ρ‚ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈΡ‚Π΅ Π·Π° тях.

По-Π½Π°Ρ‚Π°Ρ‚ΡŠΠΊ Π²ΠΈΠΆΠ΄Π°ΠΌΠ΅ Π΄Π²Π΅ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ:

  • components/ β€” Ρ‚ΡƒΠΊ Ρ‰Π΅ сС ΡΡŠΡ…Ρ€Π°Π½ΡΠ²Π°Ρ‚ всички манифСсти Π·Π° Π½Π°ΡˆΠ΅Ρ‚ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, Ρ‚Π΅ ΠΌΠΎΠ³Π°Ρ‚ Π΄Π° Π±ΡŠΠ΄Π°Ρ‚ описани ΠΊΠ°ΠΊΡ‚ΠΎ Π² jsonnet, Ρ‚Π°ΠΊΠ° ΠΈ с ΠΎΠ±ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΈ yaml Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅
  • environments/ β€” Ρ‚ΡƒΠΊ Ρ‰Π΅ описвамС всички ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ (ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈ) Π·Π° Π½Π°ΡˆΠΈΡ‚Π΅ срСди.

По ΠΏΠΎΠ΄Ρ€Π°Π·Π±ΠΈΡ€Π°Π½Π΅ ΠΈΠΌΠ°ΠΌΠ΅ Π΄Π²Π° Ρ„Π°ΠΉΠ»Π°:

  • environments/base.libsonnet β€” Ρ‚ΠΎΠΉ Ρ‰Π΅ ΡΡŠΠ΄ΡŠΡ€ΠΆΠ° ΠΎΠ±Ρ‰ΠΈ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈ Π·Π° всички срСди
  • environments/default.libsonnet β€” ΡΡŠΠ΄ΡŠΡ€ΠΆΠ° ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈ, ΠΏΡ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈ Π·Π° срСдата ΠΏΠΎ ΠΏΠΎΠ΄Ρ€Π°Π·Π±ΠΈΡ€Π°Π½Π΅

НСка Π΄Π° ΠΎΡ‚Π²ΠΎΡ€ΠΈΠΌ environments/base.libsonnet ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Ρ‚Π°ΠΌ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈ Π·Π° нашия ΠΏΡŠΡ€Π²ΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚:

{
  components: {
    website: {
      name: 'example-docs',
      image: 'registry.gitlab.com/kvaps/docs.example.org/website:v0.0.1',
      replicas: 1,
      containerPort: 80,
      servicePort: 80,
      nodeSelector: {},
      tolerations: [],
      ingressClass: 'nginx',
      domain: 'docs.example.org',
    },
  },
}

БъздавамС ΡΡŠΡ‰ΠΎ ΠΈ нашия ΠΏΡŠΡ€Π²ΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ components/website.jsonnet:

local env = {
  name: std.extVar('qbec.io\/env'),
  namespace: std.extVar('qbec.io\/defaultNs'),
};
local p = import '..\/params.libsonnet';
local params = p.components.website;

[
  {
    apiVersion: 'apps\/v1',
    kind: 'Deployment',
    metadata: {
      labels: { app: params.name },
      name: params.name,
    },
    spec: {
      replicas: params.replicas,
      selector: {
        matchLabels: {
          app: params.name,
        },
      },
      template: {
        metadata: {
          labels: { app: params.name },
        },
        spec: {
          containers: [
            {
              name: 'darkhttpd',
              image: params.image,
              ports: [
                {
                  containerPort: params.containerPort,
                },
              ],
            },
          ],
          nodeSelector: params.nodeSelector,
          tolerations: params.tolerations,
          imagePullSecrets: [{ name: 'regsecret' }],
        },
      },
    },
  },
  {
    apiVersion: 'v1',
    kind: 'Service',
    metadata: {
      labels: { app: params.name },
      name: params.name,
    },
    spec: {
      selector: {
        app: params.name,
      },
      ports: [
        {
          port: params.servicePort,
          targetPort: params.containerPort,
        },
      ],
    },
  },
  {
    apiVersion: 'extensions\/v1beta1',
    kind: 'Ingress',
    metadata: {
      annotations: {
        'kubernetes.io\/ingress.class': params.ingressClass,
      },
      labels: { app: params.name },
      name: params.name,
    },
    spec: {
      rules: [
        {
          host: params.domain,
          http: {
            paths: [
              {
                backend: {
                  serviceName: params.name,
                  servicePort: params.servicePort,
                },
              },
            ],
          },
        },
      ],
    },
  },
]

Π’ Ρ‚ΠΎΠ·ΠΈ Ρ„Π°ΠΉΠ» описахмС Ρ‚Ρ€ΠΈ Kubernetes рСсурса: Deployment, Услуга ΠΈ IngressПо ΠΆΠ΅Π»Π°Π½ΠΈΠ΅, ΠΌΠΎΠΆΠ΅Ρ…ΠΌΠ΅ Π΄Π° Π³ΠΈ изнСсСм Π² Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΈ, Π½ΠΎ Π½Π° Ρ‚ΠΎΠ·ΠΈ Π΅Ρ‚Π°ΠΏ Π½ΠΈ стига ΠΈ Π΅Π΄ΠΈΠ½.

Бинтаксис jsonnet ΠΌΠ½ΠΎΠ³ΠΎ наподобява ΠΎΠ±ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ json, Π² ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ΅ обикновСният json Π²Π΅Ρ‡Π΅ Π΅ Π²Π°Π»ΠΈΠ΄Π΅Π½ jsonnet, Ρ‚Π°ΠΊΠ° Ρ‡Π΅ Π² Π½Π°Ρ‡Π°Π»ΠΎΡ‚ΠΎ вСроятно Ρ‰Π΅ бъдС ΠΏΠΎ-лСсно Π΄Π° ΠΏΠΎΠ»Π·Π²Π°Ρ‚Π΅ ΠΎΠ½Π»Π°ΠΉΠ½ услуги ΠΊΠ°Ρ‚ΠΎ yaml2json Π·Π° Π΄Π° ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€Π°Ρ‚Π΅ познатия Π²ΠΈ yaml Π² json, ΠΈΠ»ΠΈ, Π°ΠΊΠΎ Π²Π°ΡˆΠΈΡ‚Π΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΈ Π½Π΅ ΡΡŠΠ΄ΡŠΡ€ΠΆΠ°Ρ‚ Π½ΠΈΠΊΠ°ΠΊΠ²ΠΈ ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ, спокойно ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π³ΠΈ ΠΎΠΏΠΈΡˆΠ΅Ρ‚Π΅ Π² ΠΎΠ±ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ yaml.

ΠŸΡ€ΠΈ Ρ€Π°Π±ΠΎΡ‚Π° с jsonnet силам Π²ΠΈ Π΄Π° инсталиратС плъгин Π·Π° вашия Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΎΡ€.

НапримСр, Π·Π° vim ΠΈΠΌΠ° плъгин vim-jsonnet, ΠΊΠΎΠΉΡ‚ΠΎ Π²ΠΊΠ»ΡŽΡ‡Π²Π° подсвСтка Π½Π° синтаксиса ΠΈ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π½ΠΎ изпълнява jsonnet fmt ΠΏΡ€ΠΈ всяко Π·Π°ΠΏΠ°Π·Π²Π°Π½Π΅ (изисква инсталиран jsonnet).

Всичко Π΅ Π³ΠΎΡ‚ΠΎΠ²ΠΎ, сСга ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° Π·Π°ΠΏΠΎΡ‡Π½Π΅ΠΌ Π΄Π΅ΠΏΠ»ΠΎΠΉ:

Π—Π° Π΄Π° Π²ΠΈΠ΄ΠΈΠΌ ΠΊΠ°ΠΊΠ²ΠΎ смС ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΈ, изпълнявамС:

qbec show default

На ΠΈΠ·Ρ…ΠΎΠ΄Π° Ρ‰Π΅ Π²ΠΈΠ΄ΠΈΡ‚Π΅ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΡ€Π°Π½ΠΈ yaml манифСсти, ΠΊΠΎΠΈΡ‚ΠΎ Ρ‰Π΅ Π±ΡŠΠ΄Π°Ρ‚ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈ Π² кластСра default.

Π‘Ρ‚Ρ€Π°Ρ…ΠΎΡ‚Π½ΠΎ, сСга ΠΏΡ€ΠΈΠ»Π°Π³Π°ΠΌΠ΅:

qbec apply default

На ΠΈΠ·Ρ…ΠΎΠ΄Π° Π²ΠΈΠ½Π°Π³ΠΈ Ρ‰Π΅ Π²ΠΈΠ΄ΠΈΡ‚Π΅ ΠΊΠ°ΠΊΠ²ΠΎ Ρ‰Π΅ сС ΠΈΠ·Π²ΡŠΡ€ΡˆΠΈ във вашия кластСр, qbec Ρ‰Π΅ Π²ΠΈ ΠΏΠΎΠΌΠΎΠ»ΠΈ Π΄Π° сС ΡΡŠΠ³Π»Π°ΡΠΈΡ‚Π΅ с ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈΡ‚Π΅, ΠΊΠ°Ρ‚ΠΎ Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ y ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° ΠΏΠΎΡ‚Π²ΡŠΡ€Π΄ΠΈΡ‚Π΅ Π½Π°ΠΌΠ΅Ρ€Π΅Π½ΠΈΠ΅Ρ‚ΠΎ си.

Π“ΠΎΡ‚ΠΎΠ²ΠΎ! Π‘Π΅Π³Π° Π½Π°ΡˆΠ΅Ρ‚ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΅ Ρ€Π°Π·ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΎ!

Ако Π½Π°ΠΏΡ€Π°Π²ΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ, Π²ΠΈΠ½Π°Π³ΠΈ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° ΠΈΠ·ΠΏΡŠΠ»Π½ΠΈΡ‚Π΅:

qbec diff default

Π·Π° Π΄Π° Π²ΠΈΠ΄ΠΈΡ‚Π΅ ΠΊΠ°ΠΊ Ρ‚Π΅Π·ΠΈ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ Ρ‰Π΅ сС отразят Π½Π° Ρ‚Π΅ΠΊΡƒΡ‰ΠΎΡ‚ΠΎ Ρ€Π°Π·ΠΏΠΎΠ»Π°Π³Π°Π½Π΅

НС забравяйтС Π΄Π° ΠΊΠΎΠΌΠΈΡ‚Π½Π΅ΠΌ Π½Π°ΡˆΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ:

cd ..\/..\ngit add deploy\/website\ngit commit -m "Π”ΠΎΠ±Π°Π²ΠΈ Ρ€Π°Π·ΠΏΠΎΠ»Π°Π³Π°Π½Π΅ Π·Π° уСбсайта"

5. ΠŸΡ€ΠΎΠ±Π²Π°ΠΌΠ΅ Gitlab-runner с Kubernetes-executor

Π”ΠΎ Π½Π΅ΠΎΡ‚Π΄Π°Π²Π½Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ… само ΠΎΠ±ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ gitlab-runner Π½Π° ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»Π½ΠΎ ΠΏΠΎΠ΄Π³ΠΎΡ‚Π²Π΅Π½Π° машина (LXC-ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€) с shell- ΠΈΠ»ΠΈ docker-executor. ΠŸΡŠΡ€Π²ΠΎΠ½Π°Ρ‡Π°Π»Π½ΠΎ ΠΈΠΌΠ°Ρ…ΠΌΠ΅ няколко Ρ‚Π°ΠΊΠΈΠ²Π° Ρ€Π°Π½Π½Π΅Ρ€Π° Π³Π»ΠΎΠ±Π°Π»Π½ΠΎ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈ Π² нашия GitLab. Π’Π΅ ΡΡŠΠ±ΠΈΡ€Π°Ρ…Π° docker-ΠΎΠ±Ρ€Π°Π·ΠΈ Π·Π° всички ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΈ.

Но ΠΊΠ°ΠΊΡ‚ΠΎ ΠΏΠΎΠΊΠ°Π·Π° ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ°Ρ‚Π° β€” Ρ‚ΠΎΠ·ΠΈ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ Π½Π΅ Π΅ ΠΈΠ΄Π΅Π°Π»Π΅Π½, ΠΊΠ°ΠΊΡ‚ΠΎ Π² ΠΏΡ€Π°ΠΊΡ‚ΠΈΡ‡Π½ΠΎ, Ρ‚Π°ΠΊΠ° ΠΈ Π² бСзопасност. Много ΠΏΠΎ-Π΄ΠΎΠ±Ρ€Π΅ ΠΈ идСологичСски ΠΏΡ€Π°Π²ΠΈΠ»Π½ΠΎ Π΅ Π΄Π° ΠΈΠΌΠ°Ρ‚Π΅ ΠΎΡ‚Π΄Π΅Π»Π½ΠΈ Ρ€Π°Π½Π½Π΅Ρ€ΠΈ Ρ€Π°Π·ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈ Π·Π° всСки ΠΏΡ€ΠΎΠ΅ΠΊΡ‚, Π΄ΠΎΡ€ΠΈ ΠΈ Π·Π° всяка срСда.

Π—Π° щастиС, Ρ‚ΠΎΠ²Π° Π½Π΅ Π΅ никакъв ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ, Ρ‚ΡŠΠΉ ΠΊΠ°Ρ‚ΠΎ сСга Ρ‰Π΅ Ρ€Π°Π·ΠΏΠΎΠ»Π°Π³Π°ΠΌΠ΅ gitlab-runner Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ ΠΊΠ°Ρ‚ΠΎ част ΠΎΡ‚ нашия ΠΏΡ€ΠΎΠ΅ΠΊΡ‚, Π½Π°ΠΏΡ€Π°Π²ΠΎ Π² Kubernetes.

GitLab прСдоставя Π³ΠΎΡ‚ΠΎΠ² helm-Ρ‡Π°Ρ€Ρ‚ Π·Π° Ρ€Π°Π·ΠΏΠΎΠ»Π°Π³Π°Π½Π΅ Π½Π° gitlab-runner Π² Kubernetes. Π’Π°ΠΊΠ° Ρ‡Π΅ всичко, ΠΎΡ‚ ΠΊΠΎΠ΅Ρ‚ΠΎ ΠΈΠΌΠ°Ρ‚Π΅ Π½ΡƒΠΆΠ΄Π°, Π΅ Π΄Π° Ρ€Π°Π·Π±Π΅Ρ€Π΅Ρ‚Π΅ registration token Π·Π° нашия ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ Π² Settings β€”> CI \/ CD β€”> Runners ΠΈ Π΄Π° Π³ΠΎ ΠΏΡ€Π΅Π΄Π°Π΄Π΅Ρ‚Π΅ Π½Π° helm:

helm repo add gitlab https:\/\/charts.gitlab.io\n\nhelm install gitlab-runner \n  --set gitlabUrl=https:\/\/gitlab.com \n  --set runnerRegistrationToken=yga8y-jdCusVDn_t4Wxc \n  --set rbac.create=true \n  gitlab\/gitlab-runner

ΠšΡŠΠ΄Π΅Ρ‚ΠΎ:

  • https://gitlab.com β€” Π°Π΄Ρ€Π΅ΡΡŠΡ‚ Π½Π° вашия GitLab-ΡΡŠΡ€Π²ΡŠΡ€.
  • yga8y-jdCusVDn_t4Wxc β€” registration token Π·Π° вашия ΠΏΡ€ΠΎΠ΅ΠΊΡ‚.
  • rbac.create=true β€” прСдоставя Π½Π° Ρ€Π°Π½Π½Π΅Ρ€Π° Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΡ‚ΠΎ количСство ΠΏΡ€ΠΈΠ²ΠΈΠ»Π΅Π³ΠΈΠΈ, Π·Π° Π΄Π° ΠΌΠΎΠΆΠ΅ Π΄Π° създава ΠΏΠΎΠ΄ΠΎΠ²Π΅ Π·Π° изпълнСниС Π½Π° Π·Π°Π΄Π°Ρ‡ΠΈΡ‚Π΅ Π½ΠΈ с ΠΏΠΎΠΌΠΎΡ‰Ρ‚Π° Π½Π° kubernetes-executor.

Ако всичко Π΅ Π½Π°ΠΏΡ€Π°Π²Π΅Π½ΠΎ ΠΏΡ€Π°Π²ΠΈΠ»Π½ΠΎ, трябва Π΄Π° Π²ΠΈΠ΄ΠΈΡ‚Π΅ рСгистриран Ρ€Π°Π½Π½Π΅Ρ€ Π² сСкцията Runners, Π² настройкитС Π½Π° вашия ΠΏΡ€ΠΎΠ΅ΠΊΡ‚.

Π‘ΠΊΡ€ΠΈΠ½ΡˆΠΎΡ‚ Π½Π° добавСния Ρ€Π°Π½Π½Π΅Ρ€

ΠžΠΏΠΈΡ‚Π²Π°ΠΌΠ΅ Π½ΠΎΠ²ΠΈ инструмСнти Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ ΠΈ автоматизация Π½Π° дСплоя Π² Kubernetes.

Π’ΠΎΠ»ΠΊΠΎΠ²Π° Π»ΠΈ Π΅ лСсно? β€” Π΄Π°, Ρ‚Π°ΠΊΠ° Π΅! ΠŸΠΎΠ²Π΅Ρ‡Π΅ Π½ΠΈΠΊΠ°ΠΊΠ²ΠΈ притСснСния с Ρ€ΡŠΡ‡Π½Π°Ρ‚Π° рСгистрация Π½Π° Ρ€Π°Π½Π½Π΅Ρ€ΠΈΡ‚Π΅, ΠΎΡ‚ Ρ‚ΠΎΠ·ΠΈ ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π½Π°Ρ‚Π°Ρ‚ΡŠΠΊ, Ρ€Π°Π½Π½Π΅Ρ€ΠΈΡ‚Π΅ Ρ‰Π΅ Π±ΡŠΠ΄Π°Ρ‚ създавани ΠΈ ΡƒΠ½ΠΈΡ‰ΠΎΠΆΠ°Π²Π°Π½ΠΈ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π½ΠΎ.

6. Π Π°Π·ΠΏΠΎΠ»Π°Π³Π°Π½Π΅ Π½Π° Helm-Ρ‡Π°Ρ€Ρ‚ΠΈ с QBEC

Въй ΠΊΠ°Ρ‚ΠΎ Ρ€Π΅ΡˆΠΈΡ…ΠΌΠ΅ Π΄Π° считамС gitlab-runner част ΠΎΡ‚ нашия ΠΏΡ€ΠΎΠ΅ΠΊΡ‚, Π²Ρ€Π΅ΠΌΠ΅ Π΅ Π΄Π° Π³ΠΎ опишСм Π² Π½Π°ΡˆΠ΅Ρ‚ΠΎ Git-Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ.

ΠœΠΎΠΆΠ΅Ρ…ΠΌΠ΅ Π΄Π° Π³ΠΎ опишСм ΠΊΠ°Ρ‚ΠΎ ΠΎΡ‚Π΄Π΅Π»Π΅Π½ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ website, Π½ΠΎ Π² Π±ΡŠΠ΄Π΅Ρ‰Π΅ ΠΏΠ»Π°Π½ΠΈΡ€Π°ΠΌΠ΅ Π΄Π° Ρ€Π°Π·ΠΏΠΎΠ»Π°Π³Π°ΠΌΠ΅ Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ копия website ΠΌΠ½ΠΎΠ³ΠΎ чСсто, Π² ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ gitlab-runner, ΠΊΠΎΠΉΡ‚ΠΎ Ρ‰Π΅ бъдС Ρ€Π°Π·ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ само вСднъТ Π½Π° всСки Kubernetes-ΠΊΠ»ΡŠΡΡ‚Π΅Ρ€. Π’Π°ΠΊΠ° Ρ‡Π΅ Π΄Π° ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€Π°ΠΌΠ΅ ΠΎΡ‚Π΄Π΅Π»Π½ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π·Π° Π½Π΅Π³ΠΎ:

cd deploy\nqbec init gitlab-runner\ncd gitlab-runner

Π’ΠΎΠ·ΠΈ ΠΏΡŠΡ‚ няма Π΄Π° описвамС Kubernetes-ΡΡŠΡ‰Π΅ΡΡ‚Π²Π°Ρ‚Π° Π½Π° Ρ€ΡŠΠΊΠ°, Π° Ρ‰Π΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ Π³ΠΎΡ‚ΠΎΠ² Helm Ρ‡Π°Ρ€Ρ‚. Π•Π΄Π½ΠΎ ΠΎΡ‚ прСдимствата Π½Π° qbec Π΅ Π²ΡŠΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚Ρ‚Π° Π΄Π° Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΡ€Π°ΠΌΠ΅ Helm Ρ‡Π°Ρ€Ρ‚ΠΎΠ²Π΅ Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ ΠΎΡ‚ Git Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ.

НСка Π³ΠΎ ΡΠ²ΡŠΡ€ΠΆΠ΅ΠΌ, ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΉΠΊΠΈ git submodule:

git submodule add https://gitlab.com/gitlab-org/charts/gitlab-runner vendor/gitlab-runner

Π‘Π΅Π³Π° дирСкторията vendor/gitlab-runner ΡΡŠΠ΄ΡŠΡ€ΠΆΠ° рСпозитория с Ρ‡Π°Ρ€Ρ‚ Π·Π° gitlab-runner.

По ΠΏΠΎΠ΄ΠΎΠ±Π΅Π½ Π½Π°Ρ‡ΠΈΠ½ ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° ΡΠ²ΡŠΡ€Π·Π²Π°ΠΌΠ΅ ΠΈ Π΄Ρ€ΡƒΠ³ΠΈ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΈ цСлия Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ с ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»Π½ΠΈ Ρ‡Π°Ρ€ΠΏΠΎΠ²Π΅. https://github.com/helm/charts

НСка опишСм ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° components/gitlab-runner.jsonnet:

local env = {
  name: std.extVar('qbec.io/env'),
  namespace: std.extVar('qbec.io/defaultNs'),
};
local p = import '.. /params.libsonnet';
local params = p.components.gitlabRunner;

std.native('expandHelmTemplate')(
  '.. /vendor/gitlab-runner',
  params.values,
  {
    nameTemplate: params.name,
    namespace: env.namespace,
    thisFile: std.thisFile,
    verbose: true,
  }
)

ΠŸΡŠΡ€Π²ΠΈΡΡ‚ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ Π½Π° expandHelmTemplate ΠΏΡ€Π΅Π΄Π°Π²Π°ΠΌΠ΅ ΠΏΡŠΡ‚Ρ Π΄ΠΎ Ρ‡Π°Ρ€Ρ‚Π°, слСд Ρ‚ΠΎΠ²Π° params.values, ΠΊΠΎΠΉΡ‚ΠΎ Ρ‰Π΅ Π²Π·Π΅ΠΌΠ΅ΠΌ ΠΎΡ‚ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈΡ‚Π΅ Π½Π° ΠΎΠΊΠΎΠ»Π½Π°Ρ‚Π° срСда, слСдва ΠΎΠ±Π΅ΠΊΡ‚ с

  • nameTemplate β€” ΠΈΠΌΠ΅Ρ‚ΠΎ Π½Π° Ρ€Π΅Π»ΠΈΠ·Π°
  • namespace β€” Π½Π΅ΠΉΠΌΡΠΏΠ΅ΠΉΡΡŠΡ‚, ΠΏΡ€Π΅Π΄Π°Π²Π°Π½ Π½Π° Helm
  • thisFile β€” Π·Π°Π΄ΡŠΠ»ΠΆΠΈΡ‚Π΅Π»Π΅Π½ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚ΡŠΡ€, ΠΏΡ€Π΅Π΄Π°Π²Π°Ρ‰ ΠΏΡŠΡ‚Ρ Π΄ΠΎ тСкущия Ρ„Π°ΠΉΠ»
  • verbose β€” ΠΏΠΎΠΊΠ°Π·Π²Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°Ρ‚Π° helm template с всички Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΈ ΠΏΡ€ΠΈ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΡ€Π°Π½Π΅ Π½Π° Ρ‡Π°Ρ€Ρ‚Π°.

Π‘Π΅Π³Π° Π½Π΅ΠΊΠ° опишСм ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈΡ‚Π΅ Π·Π° нашия ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ Π² environments/base.libsonnet:

local secrets = import '.. /secrets/base.libsonnet';

{
  components: {
    gitlabRunner: {
      name: 'gitlab-runner',
      values: {
        gitlabUrl: 'https://gitlab.com/',
        rbac: {
          create: true,
        },
        runnerRegistrationToken: secrets.runnerRegistrationToken,
      },
    },
  },
}

ΠžΠ±ΡŠΡ€Π½Π΅Ρ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ runnerRegistrationToken Π²Π·ΠΈΠΌΠ°ΠΌΠ΅ ΠΎΡ‚ външния Ρ„Π°ΠΉΠ» secrets/base.libsonnet, Π½Π΅ΠΊΠ° Π³ΠΎ създадСм:

{
  runnerRegistrationToken: 'yga8y-jdCusVDn_t4Wxc',
}

НСка ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ Π΄Π°Π»ΠΈ всичко Ρ€Π°Π±ΠΎΡ‚ΠΈ:

qbec show default

Π°ΠΊΠΎ всичко Π΅ Π½Π°Ρ€Π΅Π΄, ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° ΠΈΠ·Ρ‚Ρ€ΠΈΠ΅ΠΌ нашия ΠΏΡ€Π΅Π΄ΠΈΡˆΠ΅Π½ Ρ€Π΅Π»ΠΈΠ·, Π΄Π΅ΠΏΠ»ΠΎΠΈΠ·ΠΈΡ€Π°Π½ Ρ‡Ρ€Π΅Π· Helm:

helm uninstall gitlab-runner

ΠΈ Π΄Π° Π³ΠΎ Π΄Π΅ΠΏΠ»ΠΎΠΈΠ·ΠΈΡ€Π°ΠΌΠ΅ ΠΎΡ‚Π½ΠΎΠ²ΠΎ, Π½ΠΎ Π²Π΅Ρ‡Π΅ Ρ‡Ρ€Π΅Π· qbec:

qbec apply default

7. Π—Π°ΠΏΠΎΠ·Π½Π°Π²Π°Π½Π΅ с git-crypt

Git-crypt Π΅ инструмСнт, ΠΊΠΎΠΉΡ‚ΠΎ позволява настройванСто Π½Π° ΠΏΡ€ΠΎΠ·Ρ€Π°Ρ‡Π½ΠΎ ΠΊΡ€ΠΈΠΏΡ‚ΠΈΡ€Π°Π½Π΅ Π·Π° вашия Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ.

Π’ ΠΌΠΎΠΌΠ΅Π½Ρ‚Π° структурата Π½Π° Π½Π°ΡˆΠ°Ρ‚Π° дирСктория Π·Π° gitlab-runner ΠΈΠ·Π³Π»Π΅ΠΆΠ΄Π° Ρ‚Π°ΠΊΠ°:

.
β”œβ”€β”€ components
β”‚   β”œβ”€β”€ gitlab-runner.jsonnet
β”œβ”€β”€ environments
β”‚   β”œβ”€β”€ base.libsonnet
β”‚   └── default.libsonnet
β”œβ”€β”€ params.libsonnet
β”œβ”€β”€ qbec.yaml
β”œβ”€β”€ secrets
β”‚   └── base.libsonnet
└── vendor
    └── gitlab-runner (submodule)

Но ΡΡŠΡ…Ρ€Π°Π½Π΅Π½ΠΈΠ΅Ρ‚ΠΎ Π½Π° Ρ‚Π°ΠΉΠ½ΠΈ Π² Git Π½Π΅ Π΅ бСзопасно, Π½Π°Π»ΠΈ? Π’Π°ΠΊΠ° Ρ‡Π΅ трябва Π΄Π° Π³ΠΈ ΠΊΡ€ΠΈΠΏΡ‚ΠΈΡ€Π°ΠΌΠ΅ ΠΏΡ€Π°Π²ΠΈΠ»Π½ΠΎ.

ОбикновСно Π·Π° Π΅Π΄Π½Π° СдинствСна ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²Π° Ρ‚ΠΎΠ²Π° Π½Π΅ Π²ΠΈΠ½Π°Π³ΠΈ ΠΈΠΌΠ° смисъл. ΠœΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° ΠΏΡ€Π΅Π΄Π°Π²Π°Ρ‚Π΅ Ρ‚Π°ΠΉΠ½ΠΈ Π² qbec ΠΈ Ρ‡Ρ€Π΅Π· ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° ΠΎΠΊΠΎΠ»Π½Π°Ρ‚Π° срСда Π½Π° Π²Π°ΡˆΠ°Ρ‚Π° CI систСма.
Но Π΅ Π²Π°ΠΆΠ½ΠΎ Π΄Π° сС ΠΎΡ‚Π±Π΅Π»Π΅ΠΆΠΈ, Ρ‡Π΅ ΠΈΠΌΠ° ΠΈ ΠΏΠΎ-слоТни ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΈ, ΠΊΠΎΠΈΡ‚ΠΎ ΠΌΠΎΠ³Π°Ρ‚ Π΄Π° ΡΡŠΠ΄ΡŠΡ€ΠΆΠ°Ρ‚ Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»Π½ΠΎ ΠΏΠΎΠ²Π΅Ρ‡Π΅ сСкрСти, ΠΈ ΠΏΡ€Π΅Π΄Π°Π²Π°Π½Π΅Ρ‚ΠΎ ΠΈΠΌ всичкитС Ρ‡Ρ€Π΅Π· ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° срСдата Π±ΠΈ Π±ΠΈΠ»ΠΎ ΠΊΡ€Π°ΠΉΠ½ΠΎ Π·Π°Ρ‚Ρ€ΡƒΠ΄Π½ΠΈΡ‚Π΅Π»Π½ΠΎ.

ОсвСн Ρ‚ΠΎΠ²Π°, Π² Ρ‚Π°ΠΊΡŠΠ² случай нямашС Π΄Π° ΠΌΠΎΠ³Π° Π΄Π° Π²ΠΈ Ρ€Π°Π·ΠΊΠ°ΠΆΠ° Π·Π° Ρ‚ΠΎΠ·ΠΈ чудСсСн инструмСнт, Π½Π°Ρ€Π΅Ρ‡Π΅Π½ git-crypt.

git-crypt ΠΊΠΎΠΉΡ‚ΠΎ Π΅ ΡƒΠ΄ΠΎΠ±Π΅Π½, Π·Π°Ρ‰ΠΎΡ‚ΠΎ позволява Π΄Π° ΡΡŠΡ…Ρ€Π°Π½ΠΈΡ‚Π΅ цялата история Π½Π° сСкрСтитС, ΠΊΠ°ΠΊΡ‚ΠΎ ΠΈ Π΄Π° сравняватС, обСдиняватС ΠΈ Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π²Π°Ρ‚Π΅ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ΠΈ, ΠΊΠ°ΠΊΡ‚ΠΎ смС свикнали Π΄Π° ΠΏΡ€Π°Π²ΠΈΠΌ с Git.

ΠŸΡŠΡ€Π²ΠΎΡ‚ΠΎ Π½Π΅Ρ‰ΠΎ слСд инсталиранСто git-crypt Π΅ Π΄Π° Π³Π΅Π½Π΅Ρ€ΠΈΡ€Π°ΠΌΠ΅ ΠΊΠ»ΡŽΡ‡ΠΎΠ²Π΅ Π·Π° Π½Π°ΡˆΠ΅Ρ‚ΠΎ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅:

git crypt init

Ако ΠΈΠΌΠ°Ρ‚Π΅ PGP ΠΊΠ»ΡŽΡ‡, ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π²Π΅Π΄Π½Π°Π³Π° Π΄Π° сС Π΄ΠΎΠ±Π°Π²ΠΈΡ‚Π΅ ΠΊΠ°Ρ‚ΠΎ ΡΡŠΡ‚Ρ€ΡƒΠ΄Π½ΠΈΠΊ Π½Π° Ρ‚ΠΎΠ·ΠΈ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚:

git-crypt add-gpg-user kvapss@gmail.com

По Ρ‚ΠΎΠ·ΠΈ Π½Π°Ρ‡ΠΈΠ½ Π²ΠΈΠ½Π°Π³ΠΈ Ρ‰Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π΄Π΅ΠΊΡ€ΠΈΠΏΡ‚ΠΈΡ€Π°Ρ‚Π΅ Ρ‚ΠΎΠ²Π° Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅, ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΉΠΊΠΈ своя частСн ΠΊΠ»ΡŽΡ‡.

Ако няматС PGP ΠΊΠ»ΡŽΡ‡ ΠΈ Π½Π΅ ΠΏΡ€Π΅Π΄Π²ΠΈΠΆΠ΄Π°Ρ‚Π΅ Ρ‚Π°ΠΊΡŠΠ², ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° ΠΏΠΎΠ΅ΠΌΠ΅Ρ‚Π΅ ΠΏΠΎ Π΄Ρ€ΡƒΠ³ ΠΏΡŠΡ‚ ΠΈ Π΄Π° СкспортиратС ΠΊΠ»ΡŽΡ‡Π° Π½Π° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°:

git crypt export-key /path/to/keyfile

Π’Π°ΠΊΠ° всСки, ΠΊΠΎΠΉΡ‚ΠΎ ΠΏΡ€ΠΈΡ‚Π΅ΠΆΠ°Π²Π° Скспортирания keyfile Ρ‰Π΅ ΠΌΠΎΠΆΠ΅ Π΄Π° Π΄Π΅ΠΊΡ€ΠΈΠΏΡ‚ΠΈΡ€Π° Π²Π°ΡˆΠ΅Ρ‚ΠΎ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅.

Π’Ρ€Π΅ΠΌΠ΅ Π΅ Π΄Π° настроим нашия ΠΏΡŠΡ€Π²ΠΈ сСкрСт.
Напомням, Ρ‡Π΅ всС ΠΎΡ‰Π΅ смС Π² дирСкторията deploy/gitlab-runner/, ΠΊΡŠΠ΄Π΅Ρ‚ΠΎ ΠΈΠΌΠ°ΠΌΠ΅ дирСктория secrets/, Π½Π΅ΠΊΠ° Π΄Π° ΠΊΡ€ΠΈΠΏΡ‚ΠΈΡ€Π°ΠΌΠ΅ всичкитС Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ Π² нСя, Π·Π° Ρ†Π΅Π»Ρ‚Π° Ρ‰Π΅ създадСм Ρ„Π°ΠΉΠ» secrets/.gitattributes с Ρ‚Π°ΠΊΠΎΠ²Π° ΡΡŠΠ΄ΡŠΡ€ΠΆΠ°Π½ΠΈΠ΅:

* filter=git-crypt diff=git-crypt
.gitattributes !filter !diff

ΠšΠ°ΠΊΡ‚ΠΎ Π΅ Π²ΠΈΠ΄Π½ΠΎ ΠΎΡ‚ ΡΡŠΠ΄ΡŠΡ€ΠΆΠ°Π½ΠΈΠ΅Ρ‚ΠΎ, всички Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ ΠΏΠΎ маска * Ρ‰Π΅ ΠΏΡ€Π΅ΠΌΠΈΠ½Π°Π²Π°Ρ‚ ΠΏΡ€Π΅Π· git-crypt, с ΠΈΠ·ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Π½Π° самия .gitattributes

МоТСм Π΄Π° ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ Ρ‚ΠΎΠ²Π°, ΠΊΠ°Ρ‚ΠΎ стартирамС:

git crypt status -e

На ΠΈΠ·Ρ…ΠΎΠ΄Π° Ρ‰Π΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ списък Π½Π° всички Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ Π² Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅Ρ‚ΠΎ, Π·Π° ΠΊΠΎΠΈΡ‚ΠΎ Π΅ Π°ΠΊΡ‚ΠΈΠ²ΠΈΡ€Π°Π½ΠΎ ΠΊΡ€ΠΈΠΏΡ‚ΠΈΡ€Π°Π½Π΅.

Π’ΠΎΡ‚ ΠΈ всичко, сСга ΠΌΠΎΠΆΠ΅ΠΌ смСло Π΄Π° ΠΊΠΎΠΌΠΈΡ‚Π½Π΅ΠΌ Π½Π°ΡˆΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ:

cd ../../
git add .
git commit -m "Add deploy for gitlab-runner"

Π—Π° Π΄Π° Π·Π°ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅Ρ‚ΠΎ, Π΅ Π΄ΠΎΡΡ‚Π°Ρ‚ΡŠΡ‡Π½ΠΎ Π΄Π° ΠΈΠ·ΠΏΡŠΠ»Π½ΠΈΡ‚Π΅:

git crypt lock

ΠΈ Π²Π΅Π΄Π½Π°Π³Π° всички ΠΊΡ€ΠΈΠΏΡ‚ΠΈΡ€Π°Π½ΠΈ Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅ Ρ‰Π΅ сС ΠΏΡ€Π΅Π²ΡŠΡ€Π½Π°Ρ‚ Π² Π±ΠΈΠ½Π°Ρ€Π½ΠΎ Π½Π΅Ρ‰ΠΎ, ΠΊΠΎΠ΅Ρ‚ΠΎ Ρ‰Π΅ бъдС нСвъзмоТно Π΄Π° сС ΠΏΡ€ΠΎΡ‡Π΅Ρ‚Π΅.
Π—Π° Π΄Π° Π΄Π΅ΠΊΡ€ΠΈΠΏΡ‚ΠΈΡ€Π°Ρ‚Π΅ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅Ρ‚ΠΎ, ΠΈΠ·ΠΏΡŠΠ»Π½Π΅Ρ‚Π΅:

git crypt unlock

8. БъздавамС toolbox-ΠΎΠ±Ρ€Π°Π·

Toolbox-ΠΎΠ±Ρ€Π°Π· Π΅ ΠΎΠ±Ρ€Π°Π· с всички инструмСнти, ΠΊΠΎΠΈΡ‚ΠΎ Ρ‰Π΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ Π·Π° Ρ€Π°Π·ΠΏΠΎΠ»Π°Π³Π°Π½Π΅ Π½Π° нашия ΠΏΡ€ΠΎΠ΅ΠΊΡ‚. Π’ΠΎΠΉ Ρ‰Π΅ бъдС ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½ ΠΎΡ‚ gitlab-Ρ€Π°Π½Π΅Ρ€Π° Π·Π° изпълнСниС Π½Π° Ρ‚ΠΈΠΏΠΈΡ‡Π½ΠΈ Π·Π°Π΄Π°Ρ‡ΠΈ Π·Π° Ρ€Π°Π·ΠΏΠΎΠ»Π°Π³Π°Π½Π΅.

Π’ΡƒΠΊ всичко Π΅ просто, създавамС Π½ΠΎΠ² dockerfiles/toolbox/Dockerfile с Ρ‚Π°ΠΊΠΎΠ²Π° ΡΡŠΠ΄ΡŠΡ€ΠΆΠ°Π½ΠΈΠ΅:

ОВ alpine:3.11

RUN apk add --no-cache git git-crypt

RUN QBEC_VER=0.10.3 
 && wget -O- https://github.com/splunk/qbec/releases/download/v${QBEC_VER}/qbec-linux-amd64.tar.gz 
     | tar -C /tmp -xzf - 
 && mv /tmp/qbec /tmp/jsonnet-qbec /usr/local/bin/

RUN KUBECTL_VER=1.17.0 
 && wget -O /usr/local/bin/kubectl 
      https://storage.googleapis.com/kubernetes-release/release/v${KUBECTL_VER}/bin/linux/amd64/kubectl 
 && chmod +x /usr/local/bin/kubectl

RUN HELM_VER=3.0.2 
 && wget -O- https://get.helm.sh/helm-v${HELM_VER}-linux-amd64.tar.gz 
     | tar -C /tmp -zxf - 
 && mv /tmp/linux-amd64/helm /usr/local/bin/helm

Как ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π·Π°ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ, Π² этом ΠΎΠ±Ρ€Π°Π·Π΅ ΠΌΡ‹ устанавливаСм всС ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ использовались для развСртывания нашСго прилоТСния. Нам Π½Π΅ Π½ΡƒΠΆΠ΅Π½ здСсь Ρ€Π°Π·Π²Π΅ Ρ‡Ρ‚ΠΎ kubectl, Π½ΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ Π²Ρ‹ Π·Π°Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΏΠΎΡΠΊΡΠΏΠ΅Ρ€ΠΈΠΌΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ с Π½ΠΈΠΌ Π½Π° этапС настройки ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½Π°.

Π’Π°ΠΊΠΆΠ΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠΌΠ΅Ρ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ с Kubernetes ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒ Ρ€Π°Π·Π²Π΅Ρ€Ρ‚Ρ‹Π²Π°Π½ΠΈΠ΅ Π² Π½Π΅Π³ΠΎ, Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ Ρ€ΠΎΠ»ΡŒ для ΠΏΠΎΠ΄ΠΎΠ², Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅ΠΌΡ‹Ρ… gitlab-runner’ом.

Для этого ΠΏΠ΅Ρ€Π΅ΠΉΠ΄Π΅ΠΌ Π² Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ с gitlab-runner’ом:

cd deploy/gitlab-runner

ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π½ΠΎΠ²Ρ‹ΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ components/rbac.jsonnet:

local env = {
  name: std.extVar('qbec.io/env'),
  namespace: std.extVar('qbec.io/defaultNs'),
};
local p = import '../params.libsonnet';
local params = p.components.rbac;

[
  {
    apiVersion: 'v1',
    kind: 'ServiceAccount',
    metadata: {
      labels: {
        app: params.name,
      },
      name: params.name,
    },
  },
  {
    apiVersion: 'rbac.authorization.k8s.io/v1',
    kind: 'Role',
    metadata: {
      labels: {
        app: params.name,
      },
      name: params.name,
    },
    rules: [
      {
        apiGroups: [
          '*',
        ],
        resources: [
          '*',
        ],
        verbs: [
          '*',
        ],
      },
    ],
  },
  {
    apiVersion: 'rbac.authorization.k8s.io/v1',
    kind: 'RoleBinding',
    metadata: {
      labels: {
        app: params.name,
      },
      name: params.name,
    },
    roleRef: {
      apiGroup: 'rbac.authorization.k8s.io',
      kind: 'Role',
      name: params.name,
    },
    subjects: [
      {
        kind: 'ServiceAccount',
        name: params.name,
        namespace: env.namespace,
      },
    ],
  },
]

Π’Π°ΠΊΠΆΠ΅ опишСм Π½ΠΎΠ²Ρ‹Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ Π² environments/base.libsonnet, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ выглядит Ρ‚Π°ΠΊ:

local secrets = import '../secrets/base.libsonnet';

{
  components: {
    gitlabRunner: {
      name: 'gitlab-runner',
      values: {
        gitlabUrl: 'https://gitlab.com/',
        rbac: {
          create: true,
        },
        runnerRegistrationToken: secrets.runnerRegistrationToken,
        runners: {
          serviceAccountName: $.components.rbac.name,
          image: 'registry.gitlab.com/kvaps/docs.example.org/toolbox:v0.0.1',
        },
      },
    },
    rbac: {
      name: 'gitlab-runner-deploy',
    },
  },
}

ΠžΠ±ΡŠΡ€Π½Π΅Ρ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ $.components.rbac.name ссылаСтся Π½Π° name для ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° rbac

Π”Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ, Ρ‡Ρ‚ΠΎ измСнилось:

qbec diff default

ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΠΌ наши измСнСния Π² Kubernetes:

qbec apply default

Π’Π°ΠΊΠΆΠ΅ Π½Π΅ Π·Π°Π±Ρ‹Π²Π°Π΅ΠΌ Π·Π°ΠΊΠΎΠΌΠΌΠΈΡ‚ΠΈΡ‚ΡŒ наши измСнСния Π² git:

cd ../..
git add dockerfiles/toolbox
git commit -m "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Dockerfile для toolbox"
git add deploy/gitlab-runner
git commit -m "ΠΠ°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ gitlab-runner для использования toolbox"

9. Наш ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ ΠΈ сборка ΠΎΠ±Ρ€Π°Π·ΠΎΠ² ΠΏΠΎ Ρ‚Π΅Π³Π°ΠΌ

Π’ ΠΊΠΎΡ€Π½Π΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° ΠΌΡ‹ создадим .gitlab-ci.yml с Ρ‚Π°ΠΊΠΎΠ²Π° ΡΡŠΠ΄ΡŠΡ€ΠΆΠ°Π½ΠΈΠ΅:

.build_docker_image:
  stage: build
  image:
    name: gcr.io/kaniko-project/executor:debug-v0.15.0
    entrypoint: [""]
  before_script:
    - echo "{"auths":{"$CI_REGISTRY":{"username":"$CI_REGISTRY_USER","password":"$CI_REGISTRY_PASSWORD"}}}" > /kaniko/.docker/config.json

build_toolbox:
  extends: .build_docker_image
  script:
    - /kaniko/executor --cache --context $CI_PROJECT_DIR/dockerfiles/toolbox --dockerfile $CI_PROJECT_DIR/dockerfiles/toolbox/Dockerfile --destination $CI_REGISTRY_IMAGE/toolbox:$CI_COMMIT_TAG
  only:
    refs:
      - tags

build_website:
  extends: .build_docker_image
  variables:
    GIT_SUBMODULE_STRATEGY: normal
  script:
    - /kaniko/executor --cache --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/website/Dockerfile --destination $CI_REGISTRY_IMAGE/website:$CI_COMMIT_TAG
  only:
    refs:
      - tags

ΠžΠ±ΡŠΡ€Π½Π΅Ρ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Π½ΠΈΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ GIT_SUBMODULE_STRATEGY: normal Π·Π° Ρ‚Π΅Π·ΠΈ Π΄ΠΆΠΎΠ±ΠΎΠ²Π΅, ΠΊΡŠΠ΄Π΅Ρ‚ΠΎ Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ явно ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€Π°Π½Π΅ Π½Π° сабмодулитС ΠΏΡ€Π΅Π΄ΠΈ ΠΈΠ·ΠΏΡŠΠ»Π½Π΅Π½ΠΈΠ΅Ρ‚ΠΎ.

НС забравяйтС Π΄Π° ΠΊΠΎΠΌΠΈΡ‚Π½Π΅ΠΌ Π½Π°ΡˆΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ:

git add .gitlab-ci.yml
git commit -m "АвтоматизиранС Π½Π° Docker строСТ"

Мисля, Ρ‡Π΅ ΠΌΠΎΠΆΠ΅ΠΌ смСло Π΄Π° Π½Π°Ρ€Π΅Ρ‡Π΅ΠΌ Ρ‚ΠΎΠ²Π° вСрсия v0.0.1 ΠΈ Π΄Π° поставим Ρ‚Π°Π³:

git tag v0.0.1

Π©Π΅ поставямС Ρ‚Π°Π³ΠΎΠ²Π΅ всСки ΠΏΡŠΡ‚, ΠΊΠΎΠ³Π°Ρ‚ΠΎ трябва Π΄Π° пуснСм Π½ΠΎΠ²Π° вСрсия. Π’Π°Π³ΠΎΠ²Π΅Ρ‚Π΅ Π² Docker изобраТСнията Ρ‰Π΅ Π±ΡŠΠ΄Π°Ρ‚ ΡΠ²ΡŠΡ€Π·Π°Π½ΠΈ с Git Ρ‚Π°Π³ΠΎΠ²Π΅Ρ‚Π΅. ВсСки push с Π½ΠΎΠ² Ρ‚Π°Π³ Ρ‰Π΅ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€Π° строСТ Π½Π° изобраТСния с Ρ‚ΠΎΠ·ΠΈ Ρ‚Π°Π³.

ИзпълнявамС git push β€”tags, ΠΈ Ρ‰Π΅ Π²ΠΈΠ΄ΠΈΠΌ нашия ΠΏΡŠΡ€Π²ΠΈ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½:

Π‘Π½ΠΈΠΌΠΊΠ° Π½Π° ΠΏΡŠΡ€Π²ΠΈΡ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½

ΠžΠΏΠΈΡ‚Π²Π°ΠΌΠ΅ Π½ΠΎΠ²ΠΈ инструмСнти Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ ΠΈ автоматизация Π½Π° дСплоя Π² Kubernetes.

Π’Π°ΠΆΠ½ΠΎ Π΅ Π΄Π° ΠΎΠ±ΡŠΡ€Π½Π΅Ρ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Ρ‡Π΅ ΡΡ‚Ρ€ΠΎΠ΅ΠΆΡŠΡ‚ ΠΏΠΎ Ρ‚Π°Π³ΠΎΠ²Π΅ Π΅ подходящ Π·Π° строСТ Π½Π° Docker изобраТСния, Π½ΠΎ Π½Π΅ Π΅ подходящ Π·Π° Π΄Π΅ΠΏΠ»ΠΎΠΉ Π½Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π² Kubernetes. ПонСТС Π½ΠΎΠ²ΠΈ Ρ‚Π°Π³ΠΎΠ²Π΅ ΠΌΠΎΠ³Π°Ρ‚ Π΄Π° Π±ΡŠΠ΄Π°Ρ‚ Π½Π°Π·Π½Π°Ρ‡Π°Π²Π°Π½ΠΈ ΠΈ Π·Π° стари ΠΊΠΎΠΌΠΈΡ‚ΠΈ, Π² Ρ‚ΠΎΠ·ΠΈ случай инициализацията Π½Π° ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½Π° Π·Π° тях Ρ‰Π΅ Π΄ΠΎΠ²Π΅Π΄Π΅ Π΄ΠΎ Π΄Π΅ΠΏΠ»ΠΎΠΉ Π½Π° стара вСрсия.

Π—Π° Π΄Π° Ρ€Π΅ΡˆΠΈΠΌ Ρ‚ΠΎΠ·ΠΈ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ, ΠΎΠ±ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΎ ΡΡ‚Ρ€ΠΎΠ΅ΠΆΡŠΡ‚ Π½Π° Docker изобраТСнията Π΅ ΡΠ²ΡŠΡ€Π·Π°Π½ с Ρ‚Π°Π³ΠΎΠ²Π΅Ρ‚Π΅, Π° Π΄Π΅ΠΏΠ»ΠΎΠΉ Π½Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ с ΠΊΠ»ΠΎΠ½ master, Π² ΠΊΠΎΠΉΡ‚ΠΎ са Π·Π°Π΄Π°Π΄Π΅Π½ΠΈ вСрсиитС Π½Π° ΡΡŠΠ±Ρ€Π°Π½ΠΈΡ‚Π΅ изобраТСния. Π‘Π°ΠΌΠΎ Π² Ρ‚ΠΎΠ·ΠΈ случай Ρ‰Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€Π°Ρ‚Π΅ rollback с прост revert master-ΠΊΠ»ΠΎΠ½Π°.

10. Автоматизация Π½Π° дСплоя

Π—Π° Π΄Π° ΠΌΠΎΠΆΠ΅ Gitlab-runner Π΄Π° Ρ€Π°Π·ΠΊΠΎΠ΄ΠΈΡ€Π° Π½Π°ΡˆΠΈΡ‚Π΅ Ρ‚Π°ΠΉΠ½ΠΈ, Ρ‰Π΅ трябва Π΄Π° СкспортирамС ΠΊΠ»ΡŽΡ‡Π° Π½Π° рСпозитория ΠΈ Π΄Π° Π³ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π² ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈΡ‚Π΅ Π½Π° срСдата Π½Π° Π½Π°ΡˆΠ°Ρ‚Π° CI:

git crypt export-key /tmp/docs-repo.key
base64 -w0 /tmp/docs-repo.key; echo

ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π°Ρ‚Π° строка Ρ‰Π΅ Π·Π°ΠΏΠ°Π·ΠΈΠΌ Π² Gitlab, Π·Π°Ρ‚ΠΎΠ²Π° Ρ‰Π΅ ΠΎΡ‚ΠΈΠ΄Π΅ΠΌ Π² настройкитС Π½Π° нашия ΠΏΡ€ΠΎΠ΅ΠΊΡ‚:
Настройки β†’ CI / CD β†’ ΠŸΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ

И Ρ‰Π΅ създадСм Π½ΠΎΠ²Π° ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²Π°:

Type
ΠšΠ»ΡŽΡ‡
Бтойност
Π—Π°Ρ‰ΠΈΡ‚Π΅Π½Π°
Π‘ΠΊΡ€ΠΈΠ²Π°Π½Π°
ΠžΠ±Ρ…Π²Π°Ρ‚

File
GITCRYPT_KEY
<your string>
истинно (ΠΏΠΎ Π²Ρ€Π΅ΠΌΠ΅ Π½Π° ΠΎΠ±ΡƒΡ‡Π΅Π½ΠΈΠ΅Ρ‚ΠΎ ΠΌΠΎΠΆΠ΅ ΠΈ Π½Π΅Π²Π΅Ρ€Π½ΠΎ)
истинно
Всички срСди

Π‘Π½ΠΈΠΌΠΊΠ° Π½Π° Π΄ΠΎΠ±Π°Π²Π΅Π½Π°Ρ‚Π° ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²Π°

ΠžΠΏΠΈΡ‚Π²Π°ΠΌΠ΅ Π½ΠΎΠ²ΠΈ инструмСнти Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ ΠΈ автоматизация Π½Π° дСплоя Π² Kubernetes.

Π‘Π΅Π³Π° Ρ‰Π΅ ΠΎΠ±Π½ΠΎΠ²ΠΈΠΌ нашия .gitlab-ci.yml добавяйки Π² Π½Π΅Π³ΠΎ:

.deploy_qbec_app:
  stage: deploy
  only:
    refs:
      - master

deploy_gitlab_runner:
  extends: .deploy_qbec_app
  variables:
    GIT_SUBMODULE_STRATEGY: normal
  before_script:
    - base64 -d "$GITCRYPT_KEY" | git-crypt unlock -
  script:
    - qbec apply default --root deploy/gitlab-runner --force:k8s-context __incluster__ --wait --yes

deploy_website:
  extends: .deploy_qbec_app
  script:
    - qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes

Π’ΡƒΠΊ смС ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π»ΠΈ няколко Π½ΠΎΠ²ΠΈ ΠΎΠΏΡ†ΠΈΠΈ Π·Π° qbec:

  • β€”root some/app β€” позволява Π΄Π° сС ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈ дирСкторията Π½Π° ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅
  • β€”force:k8s-context __incluster__ β€” Ρ‚ΠΎΠ²Π° Π΅ магичСска ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²Π°, която ΠΊΠ°Π·Π²Π°, Ρ‡Π΅ Π΄Π΅ΠΏΠ»ΠΎΠΉΠΌΠ΅Π½Ρ‚ΡŠΡ‚ Ρ‰Π΅ сС случи Π² ΡΡŠΡ‰ΠΈΡ ΠΊΠ»ΡŠΡΡ‚Π΅Ρ€, Π² ΠΊΠΎΠΉΡ‚ΠΎ Π΅ стартиран gitlab-runner. Π’ΠΎΠ²Π° Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ, Π·Π°Ρ‰ΠΎΡ‚ΠΎ Π² ΠΏΡ€ΠΎΡ‚ΠΈΠ²Π΅Π½ случай qbec Ρ‰Π΅ сС ΠΎΠΏΠΈΡ‚Π° Π΄Π° Π½Π°ΠΌΠ΅Ρ€ΠΈ подходящ Kubernetes ΡΡŠΡ€Π²ΡŠΡ€ Π² kubeconfig-Π° Π²ΠΈ.
  • β€”wait β€” ΠΏΡ€ΠΈΠ½ΡƒΠΆΠ΄Π°Π²Π° qbec Π΄Π° ΠΈΠ·Ρ‡Π°ΠΊΠ°, Π΄ΠΎΠΊΠ°Ρ‚ΠΎ ΡΡŠΠ·Π΄Π°Π΄Π΅Π½ΠΈΡ‚Π΅ рСсурси ΠΏΡ€Π΅ΠΌΠΈΠ½Π°Ρ‚ Π² ΡΡŠΡΡ‚ΠΎΡΠ½ΠΈΠ΅ Ready ΠΈ само слСд Ρ‚ΠΎΠ²Π° Π·Π°Π²ΡŠΡ€ΡˆΠ²Π° с ΡƒΡΠΏΠ΅ΡˆΠ΅Π½ exit-code.
  • β€”yes β€” просто Π΄Π΅Π°ΠΊΡ‚ΠΈΠ²ΠΈΡ€Π° интСрактивния шСл. Π‘ΠΈΠ³ΡƒΡ€Π½ΠΈ Π»ΠΈ стС? ΠΏΡ€ΠΈ Π΄Π΅ΠΏΠ»ΠΎΠΉΠΌΠ΅Π½Ρ‚Π°.

НС забравяйтС Π΄Π° ΠΊΠΎΠΌΠΈΡ‚Π½Π΅ΠΌ Π½Π°ΡˆΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ:

git add .gitlab-ci.yml
git commit -m "АвтоматизиранС Π½Π° Π΄Π΅ΠΏΠ»ΠΎΠΉ"

И слСд Ρ‚ΠΎΠ²Π° git push Ρ‰Π΅ Π²ΠΈΠ΄ΠΈΠΌ ΠΊΠ°ΠΊ прилоТСнията Π½ΠΈ са Π±ΠΈΠ»ΠΈ Π΄Π΅ΠΏΠ»ΠΎΠΈΠ½ΠΈΡ€Π°Π½ΠΈ:

Π‘ΠΊΡ€ΠΈΠ½ΡˆΠΎΡ‚ Π½Π° втория ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½

ΠžΠΏΠΈΡ‚Π²Π°ΠΌΠ΅ Π½ΠΎΠ²ΠΈ инструмСнти Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ ΠΈ автоматизация Π½Π° дСплоя Π² Kubernetes.

11. АртСфакти ΠΈ сборка ΠΏΡ€ΠΈ push Π² master

ОбикновСно горСспомСнатитС ΡΡ‚ΡŠΠΏΠΊΠΈ са напълно Π΄ΠΎΡΡ‚Π°Ρ‚ΡŠΡ‡Π½ΠΈ Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ ΠΈ доставка Π½Π° ΠΏΠΎΡ‡Ρ‚ΠΈ всяка микрослуТба, Π½ΠΎ Π½Π΅ искамС Π΄Π° слагамС Ρ‚Π°Π³ всСки ΠΏΡŠΡ‚, ΠΊΠΎΠ³Π°Ρ‚ΠΎ трябва Π΄Π° ΠΎΠ±Π½ΠΎΠ²ΠΈΠΌ сайта. Π—Π°Ρ‚ΠΎΠ²Π° Ρ‰Π΅ ΠΏΠΎΠ΅ΠΌΠ΅ΠΌ ΠΏΠΎ-Π΄ΠΈΠ½Π°ΠΌΠΈΡ‡Π΅Π½ ΠΌΠ°Ρ€ΡˆΡ€ΡƒΡ‚ ΠΈ Ρ‰Π΅ настроим Π΄Π΅ΠΏΠ»ΠΎΠΉ ΠΏΠΎ digest Π² master-Π²Π΅Ρ‚ΠΊΠ°Ρ‚Π°.

Π˜Π΄Π΅ΡΡ‚Π° Π΅ проста: ΠΎΠ±Ρ€Π°Π·ΡŠΡ‚ Π½Π° нашия website Ρ‰Π΅ бъдС ΠΏΠ΅Ρ€Π΅ΡΡŠΠ±ΠΈΡ€Π°Π½ всСки ΠΏΡŠΡ‚ ΠΏΡ€ΠΈ push Π² master, Π° слСд Ρ‚ΠΎΠ²Π° Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π½ΠΎ Ρ‰Π΅ сС Π΄Π΅ΠΏΠ»ΠΎΠΉΠ²Π° Π² Kubernetes.

НСка Π°ΠΊΡ‚ΡƒΠ°Π»ΠΈΠ·ΠΈΡ€Π°ΠΌΠ΅ Ρ‚Π΅Π·ΠΈ Π΄Π²Π΅ Π·Π°Π΄Π°Ρ‡ΠΈ Π² нашия .gitlab-ci.yml:

build_website:
  extends: .build_docker_image
  variables:
    GIT_SUBMODULE_STRATEGY: normal
  script:
    - mkdir -p $CI_PROJECT_DIR/artifacts
    - /kaniko/executor --cache --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/website/Dockerfile --destination $CI_REGISTRY_IMAGE/website:$CI_COMMIT_REF_NAME --digest-file $CI_PROJECT_DIR/artifacts/website.digest
  artifacts:
    paths:
      - artifacts/
  only:
    refs:
      - master
      - tags

deploy_website:
  extends: .deploy_qbec_app
  script:
    - DIGEST="$(cat artifacts/website.digest)"
    - qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST"

ΠžΠ±ΡŠΡ€Π½Π΅Ρ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Π΄ΠΎΠ±Π°Π²ΠΈΡ…ΠΌΠ΅ Π±Ρ€Π°Π½ΡˆΠ° master ΠΊ refs Π·Π° Π·Π°Π΄Π°Ρ‡Π°Ρ‚Π° build_website ΠΈ сСга ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ $CI_COMMIT_REF_NAME вмСсто $CI_COMMIT_TAG, Ρ‚Π°ΠΊΠ° Ρ‡Π΅ сС ΠΎΡ‚ΠΊΡŠΡΠ²Π°ΠΌΠ΅ ΠΎΡ‚ Ρ‚Π°Π³ΠΎΠ²Π΅Ρ‚Π΅ Π² Git ΠΈ сСга Ρ‰Π΅ пускамС ΠΎΠ±Ρ€Π°Π·Π° с ΠΈΠΌΠ΅Ρ‚ΠΎ Π½Π° Π±Ρ€Π°Π½ΡˆΠ° Π½Π° ΠΊΠΎΠΌΠΈΡ‚Π°, ΠΈΠ½ΠΈΡ†ΠΈΠΈΡ€Π°Π» ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½Π°. Π’Π°ΠΆΠ½ΠΎ Π΅ Π΄Π° сС ΠΎΡ‚Π±Π΅Π»Π΅ΠΆΠΈ, Ρ‡Π΅ Ρ‚ΠΎΠ²Π° ΡΡŠΡ‰ΠΎ Ρ‰Π΅ Ρ€Π°Π±ΠΎΡ‚ΠΈ ΠΈ с Ρ‚Π°Π³ΠΎΠ²Π΅, ΠΊΠΎΠ΅Ρ‚ΠΎ Ρ‰Π΅ Π½ΠΈ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈ Π΄Π° Π·Π°ΠΏΠ°Π·Π²Π°ΠΌΠ΅ снимки Π½Π° сайта с ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π° вСрсия Π² docker-registry.

ΠšΠΎΠ³Π°Ρ‚ΠΎ ΠΈΠΌΠ΅Ρ‚ΠΎ Π½Π° docker-Ρ‚Π°Π³Π° Π·Π° Π½ΠΎΠ²Π°Ρ‚Π° вСрсия Π½Π° сайта ΠΌΠΎΠΆΠ΅ Π΄Π° останС Π΅Π΄Π½ΠΎ ΠΈ ΡΡŠΡ‰ΠΎ, всС ΠΏΠ°ΠΊ трябва Π΄Π° описвамС ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈΡ‚Π΅ Π·Π° Kubernetes, Π² ΠΏΡ€ΠΎΡ‚ΠΈΠ²Π΅Π½ случай Ρ‚ΠΎΠΉ просто няма Π΄Π° ΠΈΠ·Π²ΡŠΡ€ΡˆΠΈ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎ Ρ€Π°Π·Π³Ρ€ΡŠΡ‰Π°Π½Π΅ Π½Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ ΠΎΡ‚ новия ΠΎΠ±Ρ€Π°Π·, Ρ‚ΡŠΠΉ ΠΊΠ°Ρ‚ΠΎ няма Π΄Π° Π·Π°Π±Π΅Π»Π΅ΠΆΠΈ Π½ΠΈΠΊΠ°ΠΊΠ²ΠΈ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ Π² манифСста Π½Π° Ρ€Π°Π·Π³Ρ€ΡŠΡ‰Π°Π½Π΅Ρ‚ΠΎ.

ΠžΠΏΡ†ΠΈΡ β€”vm:ext-str digest=" $DIGEST " Π·Π° qbec β€” позволява ΠΏΡ€Π΅Π΄Π°Π²Π°Π½Π΅ Π½Π° външна ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²Π° Π² jsonnet. ИскамС, ΠΏΡ€ΠΈ всяко ΠΈΠ·Π΄Π°Π½ΠΈΠ΅ Π½Π° Π½Π°ΡˆΠ΅Ρ‚ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, Ρ‚ΠΎ Π΄Π° сС Ρ€Π°Π·Π³Ρ€ΡŠΡ‰Π° Π² кластСра. Π”Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ ΠΈΠΌΠ΅ Π½Π° Ρ‚Π°Π³, ΠΊΠΎΠ΅Ρ‚ΠΎ ΠΌΠΎΠΆΠ΅ Π΄Π° останС Π΅Π΄Π½ΠΎ ΠΈ ΡΡŠΡ‰ΠΎ, Π²Π΅Ρ‡Π΅ Π½Π΅ ΠΌΠΎΠΆΠ΅ΠΌ, Ρ‚ΡŠΠΉ ΠΊΠ°Ρ‚ΠΎ трябва Π΄Π° сС ΡΠ²ΡŠΡ€ΠΆΠ΅ΠΌ с ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Π° вСрсия Π½Π° ΠΎΠ±Ρ€Π°Π·Π° ΠΈ Π΄Π° задСйствамС Ρ€Π°Π·Π³Ρ€ΡŠΡ‰Π°Π½Π΅Ρ‚ΠΎ ΠΏΡ€ΠΈ Π½Π΅ΠΉΠ½ΠΎΡ‚ΠΎ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅.

Π’ΡƒΠΊ Ρ‰Π΅ Π½ΠΈ ΠΏΠΎΠΌΠΎΠ³Π½Π΅ Π²ΡŠΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚Ρ‚Π° Π½Π° Kaniko Π΄Π° Π·Π°ΠΏΠ°Π·ΠΈ digest Π½Π° ΠΎΠ±Ρ€Π°Π·Π° Π² Ρ„Π°ΠΉΠ» (опция β€”digest-file)
Π‘Π»Π΅Π΄ Ρ‚ΠΎΠ²Π° Ρ‚ΠΎΠ·ΠΈ Ρ„Π°ΠΉΠ» Ρ‰Π΅ ΠΏΡ€Π΅Π΄Π°Π΄Π΅ΠΌ ΠΈ ΠΏΡ€ΠΎΡ‡Π΅Ρ‚Π΅ΠΌ Π² ΠΌΠΎΠΌΠ΅Π½Ρ‚Π° Π½Π° Ρ€Π°Π·Π³Ρ€ΡŠΡ‰Π°Π½Π΅Ρ‚ΠΎ.

АктуализирамС ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈΡ‚Π΅ Π·Π° нашия deploy/website/environments/base.libsonnet ΠΊΠΎΠΉΡ‚ΠΎ сСга Ρ‰Π΅ ΠΈΠ·Π³Π»Π΅ΠΆΠ΄Π° Ρ‚Π°ΠΊΠ°:

{
  components: {
    website: {
      name: 'example-docs',
      image: 'registry.gitlab.com/kvaps/docs.example.org/website@' + std.extVar('digest'),
      replicas: 1,
      containerPort: 80,
      servicePort: 80,
      nodeSelector: {},
      tolerations: [],
      ingressClass: 'nginx',
      domain: 'docs.example.org',
    },
  },
}

Π“ΠΎΡ‚ΠΎΠ²ΠΎ, сСга всСки ΠΊΠΎΠΌΠΈΡ‚ Π² master ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅Ρ‚ΠΎ Π½Π° docker-ΠΎΠ±Ρ€Π°Π·Π° Π·Π° website, Π° слСд Ρ‚ΠΎΠ²Π° Π½Π΅Π³ΠΎΠ²ΠΎΡ‚ΠΎ Ρ€Π°Π·Π³Ρ€ΡŠΡ‰Π°Π½Π΅ Π² Kubernetes.

НС забравяйтС Π΄Π° ΠΊΠΎΠΌΠΈΡ‚Π½Π΅ΠΌ Π½Π°ΡˆΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ:

git add .
git commit -m "Configure dynamic build"

ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡΠ²Π°ΠΌΠ΅, слСд git push трябва Π΄Π° Π²ΠΈΠ΄ΠΈΠΌ Π½Π΅Ρ‰ΠΎ ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΎ:

Π‘ΠΊΡ€ΠΈΠ½ΡˆΠΎΡ‚ Π½Π° ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½Π° Π·Π° master

ΠžΠΏΠΈΡ‚Π²Π°ΠΌΠ΅ Π½ΠΎΠ²ΠΈ инструмСнти Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ ΠΈ автоматизация Π½Π° дСплоя Π² Kubernetes.

Π’ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ΅ Π½Π΅ Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π΄Π° Ρ€Π°Π·Π³Ρ€ΡŠΡ‰Π°ΠΌΠ΅ gitlab-runner ΠΏΡ€ΠΈ всяко push, стига, Ρ€Π°Π·Π±ΠΈΡ€Π° сС, Π½ΠΈΡ‰ΠΎ Π΄Π° Π½Π΅ сС Π΅ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈΠ»ΠΎ Π² Π½Π΅Π³ΠΎΠ²Π°Ρ‚Π° конфигурация, Π½Π΅ΠΊΠ° Π΄Π° ΠΏΠΎΠΏΡ€Π°Π²ΠΈΠΌ Ρ‚ΠΎΠ²Π° Π² .gitlab-ci.yml:

deploy_gitlab_runner:
  extends: .deploy_qbec_app
  variables:
    GIT_SUBMODULE_STRATEGY: normal
  before_script:
    - base64 -d "$GITCRYPT_KEY" | git-crypt unlock -
  script:
    - qbec apply default --root deploy/gitlab-runner --force:k8s-context __incluster__ --wait --yes
  only:
    changes:
      - deploy/gitlab-runner/**/*

changes Ρ‰Π΅ слСди Π·Π° измСнСния Π² deploy/gitlab-runner/ ΠΈ Ρ‰Π΅ задСйства Π½Π°ΡˆΠ°Ρ‚Π° Ρ€Π°Π±ΠΎΡ‚Π° само ΠΏΡ€ΠΈ Π½Π°Π»ΠΈΡ‡ΠΈΠ΅ Π½Π° Ρ‚Π°ΠΊΠΈΠ²Π°

НС забравяйтС Π΄Π° ΠΊΠΎΠΌΠΈΡ‚Π½Π΅ΠΌ Π½Π°ΡˆΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ:

git add .gitlab-ci.yml
git commit -m "Reduce gitlab-runner deploy"

git push, Ρ‚Π°ΠΊΠ° Π΅ ΠΏΠΎ-Π΄ΠΎΠ±Ρ€Π΅:

Π‘ΠΊΡ€ΠΈΠ½ΡˆΠΎΡ‚ Π½Π° актуализирания ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½

ΠžΠΏΠΈΡ‚Π²Π°ΠΌΠ΅ Π½ΠΎΠ²ΠΈ инструмСнти Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ ΠΈ автоматизация Π½Π° дСплоя Π² Kubernetes.

12. Π”ΠΈΠ½Π°ΠΌΠΈΡ‡Π½ΠΈ срСди

Π’Ρ€Π΅ΠΌΠ΅ Π΅ Π΄Π° Ρ€Π°Π·Π½ΠΎΠΎΠ±Ρ€Π°Π·ΠΈΠΌ нашия ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ с Π΄ΠΈΠ½Π°ΠΌΠΈΡ‡Π½ΠΈ срСди.

ΠŸΡŠΡ€Π²ΠΎ Π°ΠΊΡ‚ΡƒΠ°Π»ΠΈΠ·ΠΈΡ€Π°ΠΌΠ΅ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚Π° build_website Π² нашия .gitlab-ci.yml, ΠΏΡ€Π΅ΠΌΠ°Ρ…Π²Π°ΠΉΠΊΠΈ Π±Π»ΠΎΠΊΠ° only, ΠΊΠΎΠ΅Ρ‚ΠΎ Ρ‰Π΅ Π½Π°ΠΊΠ°Ρ€Π° Gitlab Π΄Π° я задСйства ΠΏΡ€ΠΈ всСки ΠΊΠΎΠΌΠΈΡ‚ Π² всяка ΠΊΠ»ΠΎΠ½:

build_website:
  extends: .build_docker_image
  variables:
    GIT_SUBMODULE_STRATEGY: normal
  script:
    - mkdir -p $CI_PROJECT_DIR/artifacts
    - /kaniko/executor --cache --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/website/Dockerfile --destination $CI_REGISTRY_IMAGE/website:$CI_COMMIT_REF_NAME --digest-file $CI_PROJECT_DIR/artifacts/website.digest
  artifacts:
    paths:
      - artifacts/

Π‘Π»Π΅Π΄ Ρ‚ΠΎΠ²Π° Π°ΠΊΡ‚ΡƒΠ°Π»ΠΈΠ·ΠΈΡ€Π°ΠΌΠ΅ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚Π° deploy_website, Ρ‰Π΅ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Ρ‚Π°ΠΌ Π±Π»ΠΎΠΊ срСда:

deploy_website:
  extends: .deploy_qbec_app
  environment:
    name: prod
    url: https://docs.example.org
  script:
    - DIGEST="$(cat artifacts/website.digest)"
    - qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST"

Π’ΠΎΠ²Π° Ρ‰Π΅ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈ Π½Π° Gitlab Π΄Π° асоциира Ρ€Π°Π±ΠΎΡ‚Π½ΠΎΡ‚ΠΎ място с prod ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ ΠΈ Π΄Π° ΠΈΠ·Π²Π΅ΠΆΠ΄Π° ΠΏΡ€Π°Π²ΠΈΠ»Π½Π°Ρ‚Π° Π²Ρ€ΡŠΠ·ΠΊΠ° Π·Π° Π½Π΅Π³ΠΎ.

Π‘Π΅Π³Π° Π΄ΠΎΠ±Π°Π²ΠΈΠΌ ΠΎΡ‰Π΅ Π΄Π²Π΅ Ρ€Π°Π±ΠΎΡ‚Π½ΠΈ мСста:

deploy_website:
  extends: .deploy_qbec_app
  environment:
    name: prod
    url: https://docs.example.org
  script:
    - DIGEST="$(cat artifacts/website.digest)"
    - qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST"

deploy_review:
  extends: .deploy_qbec_app
  environment:
    name: review/$CI_COMMIT_REF_NAME
    url: http://$CI_ENVIRONMENT_SLUG.docs.example.org
    on_stop: stop_review
  script:
    - DIGEST="$(cat artifacts/website.digest)"
    - qbec apply review --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST" --vm:ext-str subdomain="$CI_ENVIRONMENT_SLUG" --app-tag "$CI_ENVIRONMENT_SLUG"
  only:
    refs:
    - branches
  except:
    refs:
      - master

stop_review:
  extends: .deploy_qbec_app
  environment:
    name: review/$CI_COMMIT_REF_NAME
    action: stop
  stage: deploy
  before_script:
    - git clone "$CI_REPOSITORY_URL" master
    - cd master
  script:
    - qbec delete review --root deploy/website --force:k8s-context __incluster__ --yes --vm:ext-str digest="$DIGEST" --vm:ext-str subdomain="$CI_ENVIRONMENT_SLUG" --app-tag "$CI_ENVIRONMENT_SLUG"
  variables:
    GIT_STRATEGY: none
  only:
    refs:
    - branches
  except:
    refs:
      - master
  when: manual

Π’Π΅ Ρ‰Π΅ Π±ΡŠΠ΄Π°Ρ‚ стартирани ΠΏΡ€ΠΈ push Π² ΠΊΠ°ΠΊΠ²ΠΈΡ‚ΠΎ ΠΈ Π΄Π° Π΅ ΠΊΠ»ΠΎΠ½ΠΎΠ²Π΅ освСн master ΠΈ Ρ‰Π΅ дСплоят ΠΏΡ€Π΅Π³Π»Π΅Π΄Π½Π° вСрсия Π½Π° сайта.

Π’ΠΈΠΆΠ΄Π°ΠΌΠ΅ Π½ΠΎΠ²Π° опция Π·Π° qbec: β€”app-tag β€” тя позволява Π΄Π° сС Π΅Ρ‚ΠΈΠΊΠ΅Ρ‚ΠΈΡ€Π°Ρ‚ Π΄Π΅ΠΏΠ»ΠΎΠΈΡ‚ΠΈΡ€Π°Π½ΠΈΡ‚Π΅ вСрсии Π½Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ ΠΈ Π΄Π° сС Ρ€Π°Π±ΠΎΡ‚ΠΈ само Π² Ρ€Π°ΠΌΠΊΠΈΡ‚Π΅ Π½Π° Ρ‚Π°Π·ΠΈ Ρ‚Π°Π³, ΠΊΠΎΠ³Π°Ρ‚ΠΎ сС ΡΡŠΠ·Π΄Π°Π²Π°Ρ‚ ΠΈ ΡƒΠ½ΠΈΡ‰ΠΎΠΆΠ°Π²Π°Ρ‚ рСсурси Π² Kubernetes qbec Ρ‰Π΅ ΠΎΠΏΠ΅Ρ€ΠΈΡ€Π° само с тях.
По Ρ‚ΠΎΠ·ΠΈ Π½Π°Ρ‡ΠΈΠ½ ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° Π½Π΅ създавамС ΠΎΡ‚Π΄Π΅Π»Π½ΠΎ ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠ΅ Π·Π° всяко Ρ€Π΅Π²ΡŽ, Π° просто Π΄Π° ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ ΡΡŠΡ‰ΠΎΡ‚ΠΎ.

Π’ΡƒΠΊ ΡΡŠΡ‰ΠΎ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ qbec apply review, вмСсто qbec apply default β€” Ρ‚ΠΎΠ²Π° Ρ‚ΠΎΡ‡Π½ΠΎ Π΅ ΠΌΠΎΠΌΠ΅Π½Ρ‚ΡŠΡ‚, ΠΊΠΎΠ³Π°Ρ‚ΠΎ Ρ‰Π΅ сС ΠΎΠΏΠΈΡ‚Π°ΠΌΠ΅ Π΄Π° опишСм Ρ€Π°Π·Π»ΠΈΠΊΠΈΡ‚Π΅ Π·Π° Π½Π°ΡˆΠΈΡ‚Π΅ срСди (review ΠΈ default):

Π”ΠΎΠ±Π°Π²ΠΈΠΌ review ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠ΅ Π² deploy/website/qbec.yaml

spec:
  environments:
    review:
      defaultNamespace: docs
      server: https://kubernetes.example.org:8443

Π‘Π»Π΅Π΄ Ρ‚ΠΎΠ²Π° Ρ‰Π΅ Π³ΠΎ обявим Π² deploy/website/params.libsonnet:

local env = std.extVar('qbec.io/env');
local paramsMap = {
  _: import './environments/base.libsonnet',
  default: import './environments/default.libsonnet',
  review: import './environments/review.libsonnet',
};

if std.objectHas(paramsMap, env) then paramsMap[env] else error 'environment ' + env + ' not defined in ' + std.thisFile

И Ρ‰Π΅ запишСм пСрсонализирани ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈ Π·Π° Π½Π΅Π³ΠΎ Π² deploy/website/environments/review.libsonnet:

// this file has the param overrides for the default environment
local base = import './base.libsonnet';
local slug = std.extVar('qbec.io/tag');
local subdomain = std.extVar('subdomain');

base {
  components+: {
    website+: {
      name: 'example-docs-' + slug,
      domain: subdomain + '.docs.example.org',
    },
  },
}

НСка ΡΡŠΡ‰ΠΎ Ρ‚Π°ΠΊΠ° Π΄Π° сС Π²Π³Π»Π΅Π΄Π°ΠΌΠ΅ ΠΏΠΎ-Π²Π½ΠΈΠΌΠ°Ρ‚Π΅Π»Π½ΠΎ Π² Ρ€Π°Π±ΠΎΡ‚Π½ΠΎΡ‚ΠΎ място stop_review, Ρ‚ΠΎ Ρ‰Π΅ сработва ΠΏΡ€ΠΈ ΠΈΠ·Ρ‚Ρ€ΠΈΠ²Π°Π½Π΅ Π½Π° ΠΊΠ»ΠΎΠ½ ΠΈ Π·Π° Π΄Π° Π½Π΅ сС ΠΎΠΏΠΈΡ‚Π²Π° gitlab Π΄Π° Π½Π°ΠΏΡ€Π°Π²ΠΈ checkout Π½Π° Π½Π΅Π³ΠΎ, сС ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° GIT_STRATEGY: none, слСд Ρ‚ΠΎΠ²Π° ΠΊΠ»ΠΎΠ½ΠΈΡ€Π°ΠΌΠ΅ master-ΠΊΠ»ΠΎΠ½Π° ΠΈ ΠΏΡ€Π΅ΠΌΠ°Ρ…Π²Π°ΠΌΠ΅ ΠΏΡ€Π΅Π³Π»Π΅Π΄Π° ΠΏΡ€Π΅Π· Π½Π΅Π³ΠΎ.
Малко слоТно, Π½ΠΎ Π½Π΅ съм Π½Π°ΠΌΠ΅Ρ€ΠΈΠ» ΠΏΠΎ-красив Π½Π°Ρ‡ΠΈΠ½ досСга.
АлтСрнативният Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ ΠΌΠΎΠΆΠ΅ Π΄Π° бъдС дСплоя Π½Π° всСки ΠΏΡ€Π΅Π³Π»Π΅Π΄ Π² ΠΎΡ‚Π΄Π΅Π»Π½ΠΎ пространство, ΠΊΠΎΠ΅Ρ‚ΠΎ Π²ΠΈΠ½Π°Π³ΠΈ ΠΌΠΎΠΆΠ΅ Π΄Π° бъдС ΠΏΡ€Π΅ΠΌΠ°Ρ…Π½Π°Ρ‚ΠΎ изцяло.

НС забравяйтС Π΄Π° ΠΊΠΎΠΌΠΈΡ‚Π½Π΅ΠΌ Π½Π°ΡˆΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ:

git add .
git commit -m "АктивиранС Π½Π° Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π΅Π½ ΠΏΡ€Π΅Π³Π»Π΅Π΄"

git push, git checkout -b тСст, git push origin тСст, провСрявамС:

Π‘ΠΊΡ€ΠΈΠ½ΡˆΠΎΡ‚ Π½Π° ΡΡŠΠ·Π΄Π°Π΄Π΅Π½ΠΈΡ‚Π΅ срСди Π² Gitlab

ΠžΠΏΠΈΡ‚Π²Π°ΠΌΠ΅ Π½ΠΎΠ²ΠΈ инструмСнти Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ ΠΈ автоматизация Π½Π° дСплоя Π² Kubernetes.

Всичко Ρ€Π°Π±ΠΎΡ‚ΠΈ? β€” ΠΎΡ‚Π»ΠΈΡ‡Π½ΠΎ, ΠΈΠ·Ρ‚Ρ€ΠΈΠ²Π°ΠΌΠ΅ нашия тСстови ΠΊΠ»ΠΎΠ½: git checkout master, git push origin :тСст, провСрявамС Π΄Π°Π»ΠΈ Π·Π°Π΄Π°Ρ‡ΠΈΡ‚Π΅ Π·Π° ΠΏΡ€Π΅ΠΌΠ°Ρ…Π²Π°Π½Π΅ Π½Π° срСдата са изпълнСни Π±Π΅Π· Π³Ρ€Π΅ΡˆΠΊΠΈ.

Π’ΡƒΠΊ Π²Π΅Π΄Π½Π°Π³Π° искам Π΄Π° уточня, Ρ‡Π΅ всякакви Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΡ†ΠΈ Π² ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° ΠΌΠΎΠ³Π°Ρ‚ Π΄Π° ΡΡŠΠ·Π΄Π°Π²Π°Ρ‚ ΠΊΠ»ΠΎΠ½ΠΈ, Ρ‚Π΅ ΡΡŠΡ‰ΠΎ ΠΌΠΎΠ³Π°Ρ‚ Π΄Π° промСнят .gitlab-ci.yml Ρ„Π°ΠΉΠ»Π° ΠΈ Π΄Π° ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ Π΄ΠΎΡΡ‚ΡŠΠΏ Π΄ΠΎ сСкрСтни ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ.
Π—Π°Ρ‚ΠΎΠ²Π° настоатСлно сС ΠΏΡ€Π΅ΠΏΠΎΡ€ΡŠΡ‡Π²Π° Π΄Π° Ρ€Π°Π·Ρ€Π΅ΡˆΠΈΡ‚Π΅ тяхното ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ само Π·Π° Π·Π°Ρ‰ΠΈΡ‚Π΅Π½ΠΈ ΠΊΠ»ΠΎΠ½ΠΈ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π² master, ΠΈΠ»ΠΈ Π΄Π° ΡΡŠΠ·Π΄Π°Π΄Π΅Ρ‚Π΅ ΠΎΡ‚Π΄Π΅Π»Π΅Π½ Π½Π°Π±ΠΎΡ€ ΠΎΡ‚ ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π·Π° всяка срСда.

13. ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ Π·Π° ΠΏΡ€Π΅Π³Π»Π΅Π΄

ΠŸΡ€Π΅Π³Π»Π΅Π΄Π½ΠΈ прилоТСния Ρ‚ΠΎΠ²Π° Π΅ Π²ΡŠΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚Ρ‚Π° Π½Π° GitLab, която позволява Π·Π° всСки Ρ„Π°ΠΉΠ» Π² рСпозиторият Π΄Π° Π΄ΠΎΠ±Π°Π²ΠΈΡ‚Π΅ Π±ΡƒΡ‚ΠΎΠ½ Π·Π° Π±ΡŠΡ€Π·ΠΎ ΠΏΡ€Π΅Π³Π»Π΅ΠΆΠ΄Π°Π½Π΅ Π² Ρ€Π°Π·ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½Π°Ρ‚Π° срСда.

Π—Π° Π΄Π° сС появят Ρ‚Π΅Π·ΠΈ Π±ΡƒΡ‚ΠΎΠ½ΠΈ, Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π΄Π° сС създадС Ρ„Π°ΠΉΠ» .gitlab/route-map.yml ΠΈ Π΄Π° сС ΠΎΠΏΠΈΡˆΠ°Ρ‚ Π² Π½Π΅Π³ΠΎ всички трансформации Π½Π° ΠΏΡŠΡ‚ΠΈΡ‰Π°Ρ‚Π°, Π² нашия случай Ρ‚ΠΎΠ²Π° Ρ‰Π΅ бъдС ΠΌΠ½ΠΎΠ³ΠΎ просто:

# Indices
- source: /content/(.+?)_index.(md|html)/ 
  public: '1'

# Pages
- source: /content/(.+?).(md|html)/ 
  public: '1/'

НС забравяйтС Π΄Π° ΠΊΠΎΠΌΠΈΡ‚Π½Π΅ΠΌ Π½Π°ΡˆΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ:

git add .gitlab/
git commit -m "АктивиранС Π½Π° прилоТСния Π·Π° ΠΏΡ€Π΅Π³Π»Π΅Π΄"

git push, ΠΈ провСрявамС:

Π‘ΠΊΡ€ΠΈΠ½ΡˆΠΎΡ‚ Π½Π° Π±ΡƒΡ‚ΠΎΠ½Π° ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π·Π° ΠΏΡ€Π΅Π³Π»Π΅Π΄

ΠžΠΏΠΈΡ‚Π²Π°ΠΌΠ΅ Π½ΠΎΠ²ΠΈ инструмСнти Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ ΠΈ автоматизация Π½Π° дСплоя Π² Kubernetes.

Π—Π°Π΄Π°Ρ‡Π°Ρ‚Π° Π΅ Π·Π°Π²ΡŠΡ€ΡˆΠ΅Π½Π°!

Π˜Π·Ρ…ΠΎΠ΄Π½ΠΈΡ ΠΊΠΎΠ΄ Π½Π° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°:

Благодаря Π·Π° Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅Ρ‚ΠΎ, надявам сС Π΄Π° Π²ΠΈ Π΅ харСсало ΠžΠΏΠΈΡ‚Π²Π°ΠΌΠ΅ Π½ΠΎΠ²ΠΈ инструмСнти Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ ΠΈ автоматизация Π½Π° дСплоя Π² Kubernetes.

Π˜Π·Ρ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com

ΠšΡƒΠΏΠ΅Ρ‚Π΅ Π½Π°Π΄Π΅ΠΆΠ΄Π΅Π½ хостинг Π·Π° сайтовС със Π·Π°Ρ‰ΠΈΡ‚Π° ΠΎΡ‚ DDoS, VPS ΠΈ VDS ΡΡŠΡ€Π²ΡŠΡ€ΠΈ πŸ”₯ ΠšΡƒΠΏΠ΅Ρ‚Π΅ Π½Π°Π΄Π΅ΠΆΠ΄Π΅Π½ хостинг Π·Π° сайтовС със Π·Π°Ρ‰ΠΈΡ‚Π° ΠΎΡ‚ DDoS, VPS ΠΈ VDS ΡΡŠΡ€Π²ΡŠΡ€ΠΈ | ProHoster