ΠŸΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Π½ΠΎΠ²Ρ‹Π΅ инструмСнты для сборки ΠΈ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ дСплоя Π² Kubernetes

ΠŸΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Π½ΠΎΠ²Ρ‹Π΅ инструмСнты для сборки ΠΈ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ дСплоя Π² Kubernetes

ΠŸΡ€ΠΈΠ²Π΅Ρ‚! Π—Π° послСднСС врСмя Π²Ρ‹ΡˆΠ»ΠΎ ΠΌΠ½ΠΎΠ³ΠΎ классных инструмСнтов Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΊΠ°ΠΊ для сборки Docker-ΠΎΠ±Ρ€Π°Π·ΠΎΠ² Ρ‚Π°ΠΊ ΠΈ для дСплоя Π² Kubernetes. Π’ связи с этим Ρ€Π΅ΡˆΠΈΠ» ΠΏΠΎΠΈΠ³Ρ€Π°Ρ‚ΡŒΡΡ с Π³ΠΈΡ‚Π»Π°Π±ΠΎΠΌ, ΠΊΠ°ΠΊ слСдуСт ΠΈΠ·ΡƒΡ‡ΠΈΡ‚ΡŒ Π΅Π³ΠΎ возмоТности ΠΈ, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ ΠΆΠ΅, Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½.

Π’Π΄ΠΎΡ…Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ΠΌ для этой Ρ€Π°Π±ΠΎΡ‚Ρ‹ стал сайт kubernetes.io, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ гСнСрируСтся ΠΈΠ· исходных ΠΊΠΎΠ΄ΠΎΠ² автоматичСски, Π° Π½Π° ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ присланный ΠΏΡƒΠ» рСквСст Ρ€ΠΎΠ±ΠΎΡ‚ автоматичСски Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ preview-Π²Π΅Ρ€ΡΠΈΡŽ сайта с вашими ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ΠΌΠΈ ΠΈ прСдоставляСт ссылку для просмотра.

Π― постарался Π²Ρ‹ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΏΠΎΠ΄ΠΎΠ±Π½Ρ‹ΠΉ процСсс с нуля, Π½ΠΎ Ρ†Π΅Π»ΠΈΠΊΠΎΠΌ построСнный Π½Π° Gitlab CI ΠΈ свободных инструмСнтах, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ я ΠΏΡ€ΠΈΠ²Ρ‹ΠΊ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ для дСплоя ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π² Kubernetes. БСгодня я, Π½Π°ΠΊΠΎΠ½Π΅Ρ†, расскаТу Π²Π°ΠΌ ΠΎ Π½ΠΈΡ… ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Π΅Π΅.

Π’ ΡΡ‚Π°Ρ‚ΡŒΠ΅ Π±ΡƒΠ΄ΡƒΡ‚ рассмотрСны Ρ‚Π°ΠΊΠΈΠ΅ инструмСнты ΠΊΠ°ΠΊ:
Hugo, qbec, kaniko, git-crypt ΠΈ GitLab CI с созданиСм динамичСских ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠΉ.

CΠΎΠ΄Π΅Ρ€ΠΆΠ°Π½ΠΈΠ΅

  1. Знакомство с Hugo
  2. ΠŸΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠ° Dockerfile
  3. Знакомство с kaniko
  4. Знакомство с qbec
  5. ΠŸΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Gitlab-runner с Kubernetes-executor
  6. Π”Π΅ΠΏΠ»ΠΎΠΉ Helm-Ρ‡Π°Ρ€Ρ‚ΠΎΠ² с qbec
  7. Знакомство с git-crypt
  8. Π‘ΠΎΠ·Π΄Π°Ρ‘ΠΌ toolbox-ΠΎΠ±Ρ€Π°Π·
  9. Наш ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ ΠΈ сборка ΠΎΠ±Ρ€Π°Π·ΠΎΠ² ΠΏΠΎ тэгам
  10. Автоматизация дСплоя
  11. АртСфакты ΠΈ сборка ΠΏΡ€ΠΈ push Π² master
  12. Dynamic environments
  13. Review Apps

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-Π΄Π΅ΠΌΠΎΠ½Π°, Π° саму сборку ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€ΠΎΠ²ΠΎΠ΄ΠΈΡ‚ΡŒ Π½Π° любой машинС ΠΈ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ кэш прямо Π² registry, избавлясь, Ρ‚Π΅ΠΌ самым, ΠΎΡ‚ нСобходимости ΠΈΠΌΠ΅Ρ‚ΡŒ ΠΏΠΎΠ»Π½ΠΎΡ†Π΅Π½Π½ΠΎΠ΅ persistent-Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅.

Для сборки ΠΎΠ±Ρ€Π°Π·Π° достаточно Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ с 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, для ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° ΠΎΠ½ΠΈ Π±ΡƒΠ΄ΡƒΡ‚ ΡΠΎΡ…Ρ€Π°Π½ΡΡŽΡ‚ΡŒΡΡ Π² 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 ΡƒΠΆΠ΅ создал Π·Π° нас default ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠ΅ ΠΈ взял адрСс сСрвСра, Π° Ρ‚Π°ΠΊΠΆΠ΅ namespace ΠΈΠ· нашСго Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ kubeconfig.
Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΏΡ€ΠΈ Π΄Π΅ΠΏΠ»ΠΎΠ΅ Π² default ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠ΅, qbec всСгда Π±ΡƒΠ΄Π΅Ρ‚ Π΄Π΅ΠΏΠ»ΠΎΠΈΡ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΉ Kubernetes-кластСр ΠΈ Π² ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΉ нСймспСйс, Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ Π²Π°ΠΌ большС Π½Π΅ придётся ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒΡΡ ΠΌΠ΅ΠΆΠ΄Ρƒ контСкстами ΠΈ нСймспСйсами для Ρ‚ΠΎΠ³ΠΎ Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ Π΄Π΅ΠΏΠ»ΠΎΠΉ.
Π’ случаС нСобоходимости Π²Ρ‹ всСгда ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ настройки Π² этом Ρ„Π°ΠΉΠ»Π΅.

ВсС ваши окруТСния ΠΎΠΏΠΈΡΡ‹Π²Π°ΡŽΡ‚ΡΡ Π² qbec.yaml, ΠΈ Π² Ρ„Π°ΠΉΠ»Π΅ params.libsonnet, Π³Π΄Π΅ сказано ΠΎΡ‚ΠΊΡƒΠ΄Π° Π½ΡƒΠΆΠ½ΠΎ Π±Ρ€Π°Ρ‚ΡŒ для Π½ΠΈΡ… ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹.

Π”Π°Π»ΡŒΡˆΠ΅ ΠΌΡ‹ Π²ΠΈΠ΄ΠΈΠΌ Π΄Π²Π΅ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ:

  • components/ β€” здСсь Π±ΡƒΠ΄ΡƒΡ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒΡΡ всС манифСсты для нашСго прилоТСния, ΠΎΠ½ΠΈ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ описанны ΠΊΠ°ΠΊ Π² jsonnet Ρ‚Π°ΠΊ ΠΈ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΌΠΈ yaml-Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ
  • environments/ β€” здСсь ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΎΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ всС ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ (ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹) для Π½Π°ΡˆΠΈΡ… ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠΉ.

По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ ΠΌΡ‹ ΠΈΠΌΠ΅Π΅ΠΌ Π΄Π²Π° Ρ„Π°ΠΉΠ»Π°:

  • environments/base.libsonnet β€” ΠΎΠ½ Π±ΡƒΠ΄Π΅Ρ‚ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ ΠΎΠ±Ρ‰ΠΈΠ΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ для всСх ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠΉ
  • environments/default.libsonnet β€” содСрТит ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹Π΅ для окруТСния default

Π”Π°Π²Π°ΠΉΡ‚Π΅ ΠΎΡ‚ΠΊΡ€ΠΎΠ΅ΠΌ 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-cущности, это: Deployment, Service ΠΈ 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 ../..
git add deploy/website
git commit -m "Add deploy for website"

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

Π”ΠΎ Π½Π΅Π΄Π°Π²Π½ΠΎΠ³ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ я использовал Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ gitlab-runner Π½Π° Π·Π°Ρ€Π°Π½Π΅Π΅ ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²Π»Π΅Π½Π½ΠΎΠΉ машинС (LXC-ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π΅) с shell- ΠΈΠ»ΠΈ docker-executor. Π˜Π·Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎ ΠΌΡ‹ ΠΈΠΌΠ΅Π»ΠΈ нСсколько Ρ‚Π°ΠΊΠΈΡ… Ρ€Π°Π½Π½Π΅Ρ€ΠΎΠ² глобально ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹Ρ… Π² нашСм Π³ΠΈΡ‚Π»Π°Π±Π΅. Они собирали docker-ΠΎΠ±Ρ€Π°Π·Ρ‹ для всСх ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΎΠ².

Но ΠΊΠ°ΠΊ ΠΏΠΎΠΊΠ°Π·Π°Π»Π° ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ° β€” этот Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ Π½Π΅ самый ΠΈΠ΄Π΅Π°Π»ΡŒΠ½Ρ‹ΠΉ, ΠΊΠ°ΠΊ Π² ΠΏΠ»Π°Π½Π΅ практичности, Ρ‚Π°ΠΊ ΠΈ Π² ΠΏΠ»Π°Π½Π΅ бСзопасности. Π“ΠΎΡ€Π°Π·Π΄ΠΎ Π»ΡƒΡ‡ΡˆΠ΅ ΠΈ идСологичСски ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Π΅ΠΉ ΠΈΠΌΠ΅Ρ‚ΡŒ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ Ρ€Π°Π½Π½Π΅Ρ€Ρ‹ Π·Π°Π΄Π΅ΠΏΠ»ΠΎΠ΅Π½Π½Ρ‹Π΅ для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°, Π° Ρ‚ΠΎ ΠΈ для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ окруТСния.

К ΡΡ‡Π°ΡΡ‚ΡŒΡŽ это вовсС Π½Π΅ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ°, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Π΄Π΅ΠΏΠ»ΠΎΠΈΡ‚ΡŒ gitlab-runner нСпосрСдствСнно ΠΊΠ°ΠΊ Ρ‡Π°ΡΡ‚ΡŒ нашСго ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° прямо Π² Kubernetes.

Gitlab прСдоставляСт Π³ΠΎΡ‚ΠΎΠ²Ρ‹ΠΉ helm-Ρ‡Π°Ρ€Ρ‚ для дСплоя gitlab-runner Π² Kubernetes. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ всё Ρ‡Ρ‚ΠΎ Π²Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ, это ΡƒΠ·Π½Π°Ρ‚ΡŒ registration token для нашСго ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π² Settings —> CI / CD —> Runners ΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ Π΅Π³ΠΎ helm:

helm repo add gitlab https://charts.gitlab.io

helm install gitlab-runner 
  --set gitlabUrl=https://gitlab.com 
  --set runnerRegistrationToken=yga8y-jdCusVDn_t4Wxc 
  --set rbac.create=true 
  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
qbec init gitlab-runner
cd 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 β€” нСймспСйс ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Π΅ΠΌΡ‹ΠΉ Ρ…Π΅Π»ΡŒΠΌΡƒ
  • 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-ΠΊΠ»ΡŽΡ‡, Ρ‚ΠΎ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ сразу Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ сСбя ΠΊΠ°ΠΊ collaborator’Π° для этого ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°:

git-crypt add-gpg-user [email protected]

Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ Π²Ρ‹ всСгда смоТСтС Ρ€Π°ΡΡˆΠΈΡ„Ρ€ΠΎΠ²Π°Ρ‚ΡŒ этот Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ свой ΠΏΡ€ΠΈΠ²Π°Ρ‚Π½Ρ‹ΠΉ ΠΊΠ»ΡŽΡ‡.

Если ΠΆΠ΅ 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-ΠΎΠ±Ρ€Π°Π· β€” это Ρ‚Π°ΠΊΠΎΠΉ ΠΎΠ±Ρ€Π°Π· со всСми инструмСнтами ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ для дСплоя нашСго ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°. Он Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ Π³ΠΈΡ‚Π»Π°Π±-Ρ€Π°Π½Π½Π΅Ρ€ΠΎΠΌ для выполнСния Ρ‚ΠΈΠΏΠΎΠ²Ρ‹Ρ… Π·Π°Π΄Π°Ρ‡ дСплоя.

Π—Π΄Π΅ΡΡŒ всё просто, создаём Π½ΠΎΠ²Ρ‹ΠΉ dockerfiles/toolbox/Dockerfile с Ρ‚Π°ΠΊΠΈΠΌ содСрТаниСм:

FROM 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 "Add Dockerfile for toolbox"
git add deploy/gitlab-runner
git commit -m "Configure gitlab-runner to use 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 "Automate docker build"

Π”ΡƒΠΌΠ°ΡŽ ΠΌΠΎΠΆΠ½ΠΎ смСло Π½Π°Π·Π²Π°Ρ‚ΡŒ это вСрсиСй 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, для этого ΠΏΠ΅Ρ€Π΅ΠΉΠ΄Ρ‘ΠΌ Π² настройки нашСго ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°:
Settings —> CI / CD —> Variables

И создадим Π½ΠΎΠ²ΡƒΡŽ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ:

Type
Key
Value
Protected
Masked
Scope

File
GITCRYPT_KEY
<your string>
true (Π½Π° врСмя обучСния ΠΌΠΎΠΆΠ½ΠΎ ΠΈ false)
true
All environments

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

ΠŸΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Π½ΠΎΠ²Ρ‹Π΅ инструмСнты для сборки ΠΈ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ дСплоя Π² 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__ β€” это магичСская пСрСмСнная, которая Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ Ρ‡Ρ‚ΠΎ Π΄Π΅ΠΏΠ»ΠΎΠΉ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΠΈΡΡ…ΠΎΠ΄ΠΈΡ‚ΡŒ Π² Ρ‚ΠΎΡ‚ΠΆΠ΅ кластСр Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π·Π°ΠΏΡƒΡ‰Π΅Π½ gtilab-runner. Π‘Π΄Π΅Π»Π°Ρ‚ΡŒ это Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ Π² ΠΏΡ€ΠΎΡ‚ΠΈΠ²Π½ΠΎΠΌ случаС qbec Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ‹Ρ‚Π°Ρ‚ΡŒΡΡ Π½Π°ΠΉΡ‚ΠΈ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΡΡˆΠΈΠΉ Kubernetes-сСрвСр Π² вашСм kubeconfig
  • —wait β€” заставляСт qbec Π΄ΠΎΠΆΠ΄Π°Ρ‚ΡŒΡΡ, ΠΊΠΎΠ³Π΄Π° создаваСмыС ΠΈΠΌ рСсурсы ΠΏΠ΅Ρ€Π΅ΠΉΠ΄ΡƒΡ‚ Π² состояниС Ready ΠΈ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΠΎΡ‚ΠΎΠΌ Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ΡΡ с ΡƒΡΠΏΠ΅ΡˆΠ½Ρ‹ΠΌ exit-code.
  • —yes β€” просто ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹ΠΉ шСлл Are you sure? ΠΏΡ€ΠΈ Π΄Π΅ΠΏΠ»ΠΎΠ΅.

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

git add .gitlab-ci.yml
git commit -m "Automate deploy"

И послС 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. Dynamic environments

Настало врСмя Ρ€Π°Π·Π½ΠΎΠΎΠ±Ρ€Π°Π·ΠΈΡ‚ΡŒ наш ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ динамичСскими окруТСниями.

Для Π½Π°Ρ‡Π°Π»Π° ΠΎΠ±Π½ΠΎΠ²ΠΈΠΌ Π΄ΠΆΠΎΠ±Ρƒ 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, Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Ρ‚ΡƒΠ΄Π° Π±Π»ΠΎΠΊ environment:

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 ΠΈ Π±ΡƒΠ΄ΡƒΡ‚ Π΄Π΅ΠΏΠ»ΠΎΠΈΡ‚ΡŒ preview Π²Π΅Ρ€ΡΠΈΡŽ сайта.

ΠœΡ‹ Π²ΠΈΠ΄ΠΈΠΌ Π½ΠΎΠ²ΡƒΡŽ ΠΎΠΏΡ†ΠΈΡŽ для qbec: —app-tag β€” ΠΎΠ½Π° позволяСт Ρ‚ΡΠ³ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π·Π°Π΄Π΅ΠΏΠ»ΠΎΠ΅Π½Π½Ρ‹Π΅ вСрсии прилоТСния ΠΈ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² ΠΏΡ€Π΅Π΄Π΅Π»Π°Ρ… этого тэга, ΠΏΡ€ΠΈ создании ΠΈ ΡƒΠ½ΠΈΡ‡Ρ‚ΠΎΠΆΠ΅Π½ΠΈΠΈ рСсурсов Π² Kubernetes qbec Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠΏΠ΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΠΌΠΈ.
Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π½Π΅ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ энвайромСнт ΠΏΠΎΠ΄ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ review, Π° просто ΠΏΠ΅Ρ€Π΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠ΄ΠΈΠ½ ΠΈ Ρ‚ΠΎΡ‚ ΠΆΠ΅.

Π—Π΄Π΅ΡΡŒ ΠΌΡ‹ Ρ‚Π°ΠΊ ΠΆΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ 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-Π²Π΅Ρ‚ΠΊΡƒ ΠΈ удаляСм review Ρ‡Π΅Ρ€Π΅Π· Π½Π΅Ρ‘.
НСмного Π·Π°ΠΌΠΎΡ€ΠΎΡ‡Π½ΠΎ, Π½ΠΎ Π±ΠΎΠ»Π΅Π΅ красивого способа я ΠΏΠΎΠΊΠ° Π½Π΅ Π½Π°ΡˆΡ‘Π».
ΠΠ»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΌ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ΠΎΠΌ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π΄Π΅ΠΏΠ»ΠΎΠΉ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ review Π² ΠΎΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ нСймспСйс, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ всСгда ΠΌΠΎΠΆΠ½ΠΎ снСсти Ρ†Π΅Π»ΠΈΠΊΠΎΠΌ.

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

git add .
git commit -m "Enable automatic review"

git push, git checkout -b test, git push origin test, провСряСм:

Π‘ΠΊΡ€ΠΈΠ½ΡˆΠΎΡ‚ созданных environments Π² Gitlab

ΠŸΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Π½ΠΎΠ²Ρ‹Π΅ инструмСнты для сборки ΠΈ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ дСплоя Π² Kubernetes

Всё Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚? β€” ΠΎΡ‚Π»ΠΈΡ‡Π½ΠΎ, удаляСм Π½Π°ΡˆΡƒ Ρ‚Π΅ΡΡ‚ΠΎΠ²ΡƒΡŽ Π²Π΅Ρ‚ΠΊΡƒ: git checkout master, git push origin :test, провСряСм Ρ‡Ρ‚ΠΎ Π΄ΠΆΠΎΠ±Ρ‹ Π½Π° ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠ΅ environment ΠΎΡ‚Ρ€Π°Π±ΠΎΡ‚Π°Π»ΠΈ Π±Π΅Π· ошибок.

Π—Π΄Π΅ΡΡŒ сразу хочСтся ΡƒΡ‚ΠΎΡ‡Π½ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ Π²Π΅Ρ‚ΠΊΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ любой Π΄Π΅Π²Π΅Π»ΠΎΠΏΠ΅Ρ€ Π² ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅, ΠΎΠ½ Ρ‚Π°ΠΊΠΆΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ .gitlab-ci.yml Ρ„Π°ΠΉΠ» ΠΈ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ ΠΊ сСкрСтным ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΌ.
По этому Π½Π°ΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ рСкомСндуСтся Ρ€Π°Π·Ρ€Π΅ΡˆΠΈΡ‚ΡŒ ΠΈΡ… использованиС Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для protected-Π²Π΅Ρ‚ΠΎΠΊ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π² master, Π»ΠΈΠ±ΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ сСт ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… ΠΏΠΎΠ΄ ΠΊΠ°ΠΆΠ΄ΠΎΠ΅ ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠ΅.

13. Review Apps

Review Apps это такая Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π³ΠΈΡ‚Π»Π°Π±Π°, которая позволяСт для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ Ρ„Π°ΠΉΠ»Π° Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠ½ΠΎΠΏΠΊΡƒ для Π΅Π³ΠΎ быстрого просмотра Π² Π·Π°Π΄Π΅ΠΏΠ»ΠΎΠ΅Π½Π½ΠΎΠΌ ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠΈ.

Для Ρ‚ΠΎΠ³ΠΎ Ρ‡Ρ‚ΠΎΠ±Ρ‹ эти ΠΊΠ½ΠΎΠΏΠΊΠΈ появились, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ» .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 "Enable review apps"

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

Π‘ΠΊΡ€ΠΈΠ½ΡˆΠΎΡ‚ ΠΊΠ½ΠΎΠΏΠΊΠΈ Review App

ΠŸΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Π½ΠΎΠ²Ρ‹Π΅ инструмСнты для сборки ΠΈ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ дСплоя Π² Kubernetes

Job is done!

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

Бпасибо Π·Π° Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, надСюсь Π²Π°ΠΌ ΠΏΠΎΠ½Ρ€Π°Π²ΠΈΠ»ΠΎΡΡŒ ΠŸΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Π½ΠΎΠ²Ρ‹Π΅ инструмСнты для сборки ΠΈ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ дСплоя Π² Kubernetes

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

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ