āĻŽā§āĻ°āĻ—āĻŋ āĻŦāĻž āĻĄāĻŋāĻŽ: āĻ†āĻ‡āĻāĻ¸āĻŋ āĻŦāĻŋāĻ­āĻ•ā§āĻ¤ āĻ•āĻ°āĻž

āĻŽā§āĻ°āĻ—āĻŋ āĻŦāĻž āĻĄāĻŋāĻŽ: āĻ†āĻ‡āĻāĻ¸āĻŋ āĻŦāĻŋāĻ­āĻ•ā§āĻ¤ āĻ•āĻ°āĻž
āĻĄāĻŋāĻŽ āĻ†āĻ—ā§‡ āĻ¨āĻž āĻŽā§āĻ°āĻ—ā§€ ​​āĻ†āĻ—ā§‡? āĻ‡āĻ¨āĻĢā§āĻ°āĻžāĻ¸ā§āĻŸā§āĻ°āĻžāĻ•āĻšāĻžāĻ°-āĻ-āĻ•ā§‹āĻĄ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻŦā§‡āĻļ āĻ…āĻĻā§āĻ­ā§āĻ¤ āĻļā§āĻ°ā§, āĻ¤āĻžāĻ‡ āĻ¨āĻž?

āĻāĻ•āĻŸāĻŋ āĻĄāĻŋāĻŽ āĻ•āĻŋ?

āĻĒā§āĻ°āĻžāĻ¯āĻŧāĻļāĻ‡, āĻ‡āĻ¨āĻĢā§āĻ°āĻžāĻ¸ā§āĻŸā§āĻ°āĻžāĻ•āĻšāĻžāĻ°-āĻ-āĻ•ā§‹āĻĄ (āĻ†āĻ‡āĻāĻ¸āĻŋ) āĻšāĻ˛ āĻ…āĻŦāĻ•āĻžāĻ āĻžāĻŽā§‹āĻ° āĻĒā§āĻ°āĻ¤āĻŋāĻ¨āĻŋāĻ§āĻŋāĻ¤ā§āĻŦ āĻ•āĻ°āĻžāĻ° āĻāĻ•āĻŸāĻŋ āĻ˜ā§‹āĻˇāĻŖāĻžāĻŽā§‚āĻ˛āĻ• āĻ‰āĻĒāĻžāĻ¯āĻŧāĨ¤ āĻāĻŸāĻŋāĻ¤ā§‡ āĻ†āĻŽāĻ°āĻž āĻšāĻžāĻ°ā§āĻĄāĻ“āĻ¯āĻŧā§āĻ¯āĻžāĻ° āĻ…āĻ‚āĻļ āĻĨā§‡āĻ•ā§‡ āĻļā§āĻ°ā§ āĻ•āĻ°ā§‡ āĻāĻŦāĻ‚ āĻ¸āĻĢā§āĻŸāĻ“āĻ¯āĻŧā§āĻ¯āĻžāĻ° āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ°ā§‡āĻļāĻ¨ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻļā§‡āĻˇ āĻ•āĻ°ā§‡ āĻ¯ā§‡ āĻ…āĻŦāĻ¸ā§āĻĨāĻžāĻŸāĻŋ āĻ…āĻ°ā§āĻœāĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ‡ āĻ¤āĻž āĻŦāĻ°ā§āĻŖāĻ¨āĻž āĻ•āĻ°āĻŋāĨ¤ āĻ¤āĻžāĻ‡ IaC āĻāĻ° āĻœāĻ¨ā§āĻ¯ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ:

  1. āĻ¸āĻŽā§āĻĒāĻĻ āĻŦāĻŋāĻ§āĻžāĻ¨āĨ¤ āĻāĻ—ā§āĻ˛ā§‹ āĻšāĻ˛ VM, S3, VPC āĻ‡āĻ¤ā§āĻ¯āĻžāĻĻāĻŋāĨ¤ āĻ•āĻžāĻœā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻŽā§ŒāĻ˛āĻŋāĻ• āĻ¸āĻ°āĻžā§āĻœāĻžāĻŽ: Terraform и āĻ•ā§āĻ˛āĻžāĻ‰āĻĄāĻĢāĻ°ā§āĻŽā§‡āĻļāĻ¨.
  2. āĻ¸āĻĢā§āĻŸāĻ“āĻ¯āĻŧā§āĻ¯āĻžāĻ° āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ°ā§‡āĻļāĻ¨. āĻŽā§ŒāĻ˛āĻŋāĻ• āĻ¸āĻ°āĻžā§āĻœāĻžāĻŽ: Ansible, āĻļā§‡āĻĢ, āĻ‡āĻ¤ā§āĻ¯āĻžāĻĻāĻŋ

āĻ¯ā§‡āĻ•ā§‹āĻ¨ā§‹ āĻ•ā§‹āĻĄ āĻ—āĻŋāĻŸ āĻ°āĻŋāĻĒā§‹āĻœāĻŋāĻŸāĻ°āĻŋāĻ¤ā§‡ āĻĨāĻžāĻ•ā§‡āĨ¤ āĻāĻŦāĻ‚ āĻļā§€āĻ˜ā§āĻ°āĻ‡ āĻŦāĻž āĻĒāĻ°ā§‡ āĻĻāĻ˛ā§‡āĻ° āĻ¨ā§‡āĻ¤āĻž āĻ¸āĻŋāĻĻā§āĻ§āĻžāĻ¨ā§āĻ¤ āĻ¨ā§‡āĻŦā§‡āĻ¨ āĻ¯ā§‡ āĻ¤āĻžāĻĻā§‡āĻ° āĻļā§ƒāĻ™ā§āĻ–āĻ˛āĻžāĻŦāĻĻā§āĻ§ āĻ•āĻ°āĻž āĻĻāĻ°āĻ•āĻžāĻ°āĨ¤ āĻāĻŦāĻ‚ āĻ¤āĻŋāĻ¨āĻŋ āĻ°āĻŋāĻĢā§āĻ¯āĻžāĻ•ā§āĻŸāĻ° āĻ•āĻ°āĻŦā§‡āĻ¨āĨ¤ āĻāĻŦāĻ‚ āĻāĻŸāĻŋ āĻ•āĻŋāĻ›ā§ āĻ•āĻžāĻ āĻžāĻŽā§‹ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻŦā§‡āĨ¤ āĻāĻŦāĻ‚ āĻ¤āĻŋāĻ¨āĻŋ āĻĻā§‡āĻ–āĻ¤ā§‡ āĻĒāĻžāĻŦā§‡āĻ¨ āĻ¯ā§‡ āĻāĻŸāĻŋ āĻ­āĻžāĻ˛āĨ¤

āĻāĻŸāĻžāĻ“ āĻ­āĻžāĻ˛ā§‹ āĻ¯ā§‡ āĻāĻŸāĻž āĻ†āĻ—ā§‡ āĻĨā§‡āĻ•ā§‡āĻ‡ āĻ†āĻ›ā§‡ GitLab и GitHub-āĻŸā§‡āĻ°āĻžāĻĢāĻ°ā§āĻŽā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻĒā§āĻ°āĻĻāĻžāĻ¨āĻ•āĻžāĻ°ā§€ (āĻāĻŦāĻ‚ āĻāĻŸāĻŋ āĻ¸āĻĢā§āĻŸāĻ“āĻ¯āĻŧā§āĻ¯āĻžāĻ° āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ°ā§‡āĻļāĻ¨)āĨ¤ āĻ¤āĻžāĻĻā§‡āĻ° āĻ¸āĻžāĻšāĻžāĻ¯ā§āĻ¯ā§‡, āĻ†āĻĒāĻ¨āĻŋ āĻĒā§āĻ°ā§‹ āĻĒā§āĻ°āĻ•āĻ˛ā§āĻĒāĻŸāĻŋ āĻĒāĻ°āĻŋāĻšāĻžāĻ˛āĻ¨āĻž āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨: āĻĻāĻ˛ā§‡āĻ° āĻ¸āĻĻāĻ¸ā§āĻ¯, CI/CD, āĻ—āĻŋāĻŸ-āĻĢā§āĻ˛ā§‹, āĻ‡āĻ¤ā§āĻ¯āĻžāĻĻāĻŋāĨ¤

āĻĄāĻŋāĻŽ āĻ•ā§‹āĻĨāĻž āĻĨā§‡āĻ•ā§‡ āĻāĻ˛ā§‹?

āĻ¤āĻžāĻ‡ āĻ†āĻŽāĻ°āĻž āĻ§ā§€āĻ°ā§‡ āĻ§ā§€āĻ°ā§‡ āĻŽā§‚āĻ˛ āĻĒā§āĻ°āĻļā§āĻ¨ā§‡āĻ° āĻ•āĻžāĻ›ā§‡ āĻ¯āĻžāĻšā§āĻ›āĻŋāĨ¤

āĻĒā§āĻ°āĻĨāĻŽāĻ¤, āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻāĻ•āĻŸāĻŋ āĻ¸āĻ‚āĻ—ā§āĻ°āĻšāĻ¸ā§āĻĨāĻ˛ āĻĻāĻŋāĻ¯āĻŧā§‡ āĻļā§āĻ°ā§ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡ āĻ¯āĻž āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¨āĻŋāĻœā§‡āĻ° āĻ¸āĻš āĻ…āĻ¨ā§āĻ¯āĻžāĻ¨ā§āĻ¯ āĻ¸āĻ‚āĻ—ā§āĻ°āĻšāĻ¸ā§āĻĨāĻ˛ā§‡āĻ° āĻ—āĻ āĻ¨ āĻŦāĻ°ā§āĻŖāĻ¨āĻž āĻ•āĻ°ā§‡āĨ¤ āĻāĻŦāĻ‚ āĻ…āĻŦāĻļā§āĻ¯āĻ‡, GitOps āĻāĻ° āĻ…āĻ‚āĻļ āĻšāĻŋāĻ¸āĻžāĻŦā§‡, āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ CI āĻ¯ā§‹āĻ— āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡ āĻ¯āĻžāĻ¤ā§‡ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨āĻ—ā§āĻ˛āĻŋ āĻ¸ā§āĻŦāĻ¯āĻŧāĻ‚āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻ­āĻžāĻŦā§‡ āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ° āĻšāĻ¯āĻŧāĨ¤

āĻ¯āĻĻāĻŋ āĻ—āĻŋāĻŸ āĻāĻ–āĻ¨ā§‹ āĻ¤ā§ˆāĻ°āĻŋ āĻ¨āĻž āĻšāĻ¯āĻŧ?

  1. āĻ•āĻŋāĻ­āĻžāĻŦā§‡ āĻāĻŸāĻŋ Git āĻ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°āĻŦā§‡āĻ¨?
  2. āĻ•āĻŋāĻ­āĻžāĻŦā§‡ CI āĻ‡āĻ¨āĻ¸ā§āĻŸāĻ˛ āĻ•āĻ°āĻŦā§‡āĻ¨?
  3. āĻ†āĻŽāĻ°āĻž āĻ¯āĻĻāĻŋ āĻ†āĻ‡āĻāĻ¸āĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻ—āĻŋāĻŸāĻ˛ā§āĻ¯āĻžāĻŦ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻ•āĻ°āĻŋ, āĻāĻŽāĻ¨āĻ•āĻŋ āĻ•ā§āĻŦāĻžāĻ°āĻ¨ā§‡āĻŸāĻ¸ā§‡āĻ“?
  4. āĻ†āĻ° āĻ—āĻŋāĻŸāĻ˛ā§āĻ¯āĻžāĻŦ āĻ°āĻžāĻ¨āĻžāĻ°āĻ“ āĻ•ā§āĻŦāĻžāĻ°āĻ¨ā§‡āĻŸāĻ¸ā§‡?
  5. āĻ•ā§āĻ˛āĻžāĻ‰āĻĄ āĻĒā§āĻ°āĻĻāĻžāĻ¨āĻ•āĻžāĻ°ā§€āĻ° āĻ•ā§āĻŦāĻžāĻ°āĻ¨ā§‡āĻŸāĻ¸ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ āĻ•ā§€?

āĻĒā§āĻ°āĻĨāĻŽā§‡ āĻ•ā§€ āĻāĻ¸ā§‡āĻ›āĻŋāĻ˛: āĻ—āĻŋāĻŸāĻ˛ā§āĻ¯āĻžāĻŦ āĻ¯ā§‡āĻ–āĻžāĻ¨ā§‡ āĻ†āĻŽāĻŋ āĻ†āĻŽāĻžāĻ° āĻ•ā§‹āĻĄ āĻ†āĻĒāĻ˛ā§‹āĻĄ āĻ•āĻ°āĻŦ, āĻŦāĻž āĻ•ā§‹āĻĄ āĻ¯āĻž āĻŦāĻ°ā§āĻŖāĻ¨āĻž āĻ•āĻ°ā§‡ āĻ¯ā§‡ āĻ†āĻŽāĻžāĻ° āĻ•ā§€ āĻ§āĻ°āĻ¨ā§‡āĻ° āĻ—āĻŋāĻŸāĻ˛ā§āĻ¯āĻžāĻŦ āĻĻāĻ°āĻ•āĻžāĻ°?

āĻĄāĻŋāĻŽ āĻĻāĻŋāĻ¯āĻŧā§‡ āĻŽā§āĻ°āĻ—āĻŋ

ÂĢāĻ“āĻ¯āĻŧāĻžāĻ•ā§‹āĻĄāĻ¨āĻāĻ•āĻŸāĻŋ āĻĄāĻžāĻ‡āĻ¨ā§‹āĻ¸āĻ°ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ 3" [src]

āĻ†āĻ¸ā§āĻ¨ āĻāĻ•āĻŸāĻŋ āĻ•ā§āĻ˛āĻžāĻ‰āĻĄ āĻ¸āĻ°āĻŦāĻ°āĻžāĻšāĻ•āĻžāĻ°ā§€ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻāĻ•āĻŸāĻŋ āĻĨāĻžāĻ˛āĻž āĻ°āĻžāĻ¨ā§āĻ¨āĻž āĻ•āĻ°āĻžāĻ° āĻšā§‡āĻˇā§āĻŸāĻž āĻ•āĻ°āĻŋ āĻĒāĻ°āĻŋāĻšāĻžāĻ˛āĻŋāĻ¤ Kubernetes Selectel.

TL; āĻĄāĻŋāĻ†āĻ°

āĻāĻ•āĻŦāĻžāĻ°ā§‡ āĻāĻ•āĻŸāĻŋ āĻĻāĻ˛ā§‡ āĻ¯ā§‹āĻ— āĻĻā§‡āĻ“āĻ¯āĻŧāĻž āĻ•āĻŋ āĻ¸āĻŽā§āĻ­āĻŦ?

$ export MY_SELECTEL_TOKEN=<token>
$ curl https://gitlab.com/chicken-or-egg/mks/make/-/snippets/2002106/raw | bash

āĻ‰āĻĒāĻžāĻĻāĻžāĻ¨āĻ—ā§āĻ˛ā§‹:

  • my.selectel.ru āĻĨā§‡āĻ•ā§‡ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ;
  • āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻŸā§‹āĻ•ā§‡āĻ¨;
  • Kubernetes āĻĻāĻ•ā§āĻˇāĻ¤āĻž;
  • āĻšā§‡āĻ˛āĻŽ āĻĻāĻ•ā§āĻˇāĻ¤āĻž;
  • āĻŸā§‡āĻ°āĻžāĻĢāĻ°ā§āĻŽ āĻĻāĻ•ā§āĻˇāĻ¤āĻž;
  • āĻšā§‡āĻ˛āĻŽ āĻšāĻžāĻ°ā§āĻŸ āĻ—āĻŋāĻŸāĻ˛ā§āĻ¯āĻžāĻŦ;
  • āĻšā§‡āĻ˛āĻŽ āĻšāĻžāĻ°ā§āĻŸ āĻ—āĻŋāĻŸāĻ˛ā§āĻ¯āĻžāĻŦ āĻ°āĻžāĻ¨āĻžāĻ°āĨ¤

āĻ°ā§‡āĻ¸āĻŋāĻĒāĻŋ:

  1. āĻĒā§āĻ¯āĻžāĻ¨ā§‡āĻ˛ āĻĨā§‡āĻ•ā§‡ MY_SELECTEL_TOKEN āĻĒāĻžāĻ¨ my.selectel.ru.
  2. āĻāĻŸāĻŋāĻ¤ā§‡ āĻāĻ•āĻŸāĻŋ āĻ…ā§āĻ¯āĻžāĻ•āĻžāĻ‰āĻ¨ā§āĻŸ āĻŸā§‹āĻ•ā§‡āĻ¨ āĻ¸ā§āĻĨāĻžāĻ¨āĻžāĻ¨ā§āĻ¤āĻ° āĻ•āĻ°ā§‡ āĻāĻ•āĻŸāĻŋ Kubernetes āĻ•ā§āĻ˛āĻžāĻ¸ā§āĻŸāĻžāĻ° āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§āĻ¨āĨ¤
  3. āĻ¤ā§ˆāĻ°āĻŋ āĻ•ā§āĻ˛āĻžāĻ¸ā§āĻŸāĻžāĻ° āĻĨā§‡āĻ•ā§‡ KUBECONFIG āĻĒāĻžāĻ¨āĨ¤
  4. Kubernetes āĻ GitLab āĻ‡āĻ¨āĻ¸ā§āĻŸāĻ˛ āĻ•āĻ°ā§āĻ¨āĨ¤
  5. āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻœāĻ¨ā§āĻ¯ āĻ¤ā§ˆāĻ°āĻŋ āĻ—āĻŋāĻŸāĻ˛ā§āĻ¯āĻžāĻŦ āĻĨā§‡āĻ•ā§‡ āĻ—āĻŋāĻŸāĻ˛ā§āĻ¯āĻžāĻŦ-āĻŸā§‹āĻ•ā§‡āĻ¨ āĻĒāĻžāĻ¨ āĻļāĻŋāĻ•āĻĄāĻŧ.
  6. GitLab-āĻŸā§‹āĻ•ā§‡āĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻ—āĻŋāĻŸāĻ˛ā§āĻ¯āĻžāĻŦā§‡ āĻāĻ•āĻŸāĻŋ āĻĒā§āĻ°āĻ•āĻ˛ā§āĻĒ āĻ•āĻžāĻ āĻžāĻŽā§‹ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§āĻ¨āĨ¤
  7. āĻŦāĻŋāĻĻā§āĻ¯āĻŽāĻžāĻ¨ āĻ•ā§‹āĻĄāĻŸāĻŋ āĻ—āĻŋāĻŸāĻ˛ā§āĻ¯āĻžāĻŦā§‡ āĻĒā§āĻļ āĻ•āĻ°ā§āĻ¨āĨ¤
  8. ???
  9. āĻ˛āĻžāĻ­!

āĻĒāĻ‡āĻ āĻž 1. āĻŸā§‹āĻ•ā§‡āĻ¨ āĻŦāĻŋāĻ­āĻžāĻ—ā§‡ āĻĒāĻžāĻ“āĻ¯āĻŧāĻž āĻ¯āĻžāĻŦā§‡ API āĻ•ā§€.

āĻŽā§āĻ°āĻ—āĻŋ āĻŦāĻž āĻĄāĻŋāĻŽ: āĻ†āĻ‡āĻāĻ¸āĻŋ āĻŦāĻŋāĻ­āĻ•ā§āĻ¤ āĻ•āĻ°āĻžāĻĒāĻ‡āĻ āĻž 2. āĻ†āĻŽāĻ°āĻž 2 āĻ¨ā§‹āĻĄā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻ•ā§āĻ˛āĻžāĻ¸ā§āĻŸāĻžāĻ° "āĻŦā§‡āĻ•āĻŋāĻ‚" āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻŸā§‡āĻ°āĻžāĻĢāĻ°ā§āĻŽ āĻĒā§āĻ°āĻ¸ā§āĻ¤ā§āĻ¤ āĻ•āĻ°āĻŋāĨ¤ āĻ†āĻĒāĻ¨āĻŋ āĻ¯āĻĻāĻŋ āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤ āĻšāĻ¨ āĻ¯ā§‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ•āĻžāĻ›ā§‡ āĻ¸āĻŦāĻ•āĻŋāĻ›ā§āĻ° āĻœāĻ¨ā§āĻ¯ āĻĒāĻ°ā§āĻ¯āĻžāĻĒā§āĻ¤ āĻ¸āĻ‚āĻ¸ā§āĻĨāĻžāĻ¨ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡, āĻ¤āĻžāĻšāĻ˛ā§‡ āĻ†āĻĒāĻ¨āĻŋ āĻ¸ā§āĻŦāĻ¯āĻŧāĻ‚āĻ•ā§āĻ°āĻŋāĻ¯āĻŧ āĻ•ā§‹āĻŸāĻž āĻ¸āĻ•ā§āĻˇāĻŽ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨:

provider "selectel" {
 token = var.my_selectel_token
}

variable "my_selectel_token" {}
variable "username" {}
variable "region" {}


resource "selectel_vpc_project_v2" "my-k8s" {
 name = "my-k8s-cluster"
 theme = {
   color = "269926"
 }
 quotas {
   resource_name = "compute_cores"
   resource_quotas {
     region = var.region
     zone = "${var.region}a"
     value = 16
   }
 }
 quotas {
   resource_name = "network_floatingips"
   resource_quotas {
     region = var.region
     value = 1
   }
 }
 quotas {
   resource_name = "load_balancers"
   resource_quotas {
     region = var.region
     value = 1
   }
 }
 quotas {
   resource_name = "compute_ram"
   resource_quotas {
     region = var.region
     zone = "${var.region}a"
     value = 32768
   }
 }
 quotas {
   resource_name = "volume_gigabytes_fast"
   resource_quotas {
     region = var.region
     zone = "${var.region}a"
     # (20 * 2) + 50 + (8 * 3 + 10)
     value = 130
   }
 }
}

resource "selectel_mks_cluster_v1" "k8s-cluster" {
 name         = "k8s-cluster"
 project_id   = selectel_vpc_project_v2.my-k8s.id
 region       = var.region
 kube_version = "1.17.9"
}

resource "selectel_mks_nodegroup_v1" "nodegroup_1" {
 cluster_id        = selectel_mks_cluster_v1.k8s-cluster.id
 project_id        = selectel_mks_cluster_v1.k8s-cluster.project_id
 region            = selectel_mks_cluster_v1.k8s-cluster.region
 availability_zone = "${var.region}a"
 nodes_count       = 2
 cpus              = 8
 ram_mb            = 16384
 volume_gb         = 15
 volume_type       = "fast.${var.region}a"
 labels            = {
   "project": "my",
 }
}

āĻĒā§āĻ°āĻ•āĻ˛ā§āĻĒā§‡ āĻāĻ•āĻœāĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€ āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨:

resource "random_password" "my-k8s-user-pass" {
 length = 16
 special = true
 override_special = "_%@"
}

resource "selectel_vpc_user_v2" "my-k8s-user" {
 password = random_password.my-k8s-user-pass.result
 name = var.username
 enabled  = true
}

resource "selectel_vpc_keypair_v2" "my-k8s-user-ssh" {
 public_key = file("~/.ssh/id_rsa.pub")
 user_id    = selectel_vpc_user_v2.my-k8s-user.id
 name = var.username
}

resource "selectel_vpc_role_v2" "my-k8s-role" {
 project_id = selectel_vpc_project_v2.my-k8s.id
 user_id    = selectel_vpc_user_v2.my-k8s-user.id
}

āĻ†āĻ‰āĻŸāĻĒā§āĻŸ:

output "project_id" {
 value = selectel_vpc_project_v2.my-k8s.id
}

output "k8s_id" {
 value = selectel_mks_cluster_v1.k8s-cluster.id
}

output "user_name" {
 value = selectel_vpc_user_v2.my-k8s-user.name
}

output "user_pass" {
 value = selectel_vpc_user_v2.my-k8s-user.password
}

āĻ†āĻŽāĻ°āĻž āĻšāĻžāĻ˛ā§ āĻ•āĻ°āĻŋ:

$ env 
TF_VAR_region=ru-3 
TF_VAR_username=diamon 
TF_VAR_my_selectel_token=<token> 
terraform plan -out planfile

$ terraform apply -input=false -auto-approve planfile

āĻŽā§āĻ°āĻ—āĻŋ āĻŦāĻž āĻĄāĻŋāĻŽ: āĻ†āĻ‡āĻāĻ¸āĻŋ āĻŦāĻŋāĻ­āĻ•ā§āĻ¤ āĻ•āĻ°āĻž
āĻĒāĻ‡āĻ āĻž 3. āĻ†āĻŽāĻ°āĻž cubconfig āĻĒā§‡āĻ¤ā§‡.

āĻĒā§āĻ°ā§‹āĻ—ā§āĻ°āĻžāĻŽā§āĻ¯āĻžāĻŸāĻŋāĻ•āĻ­āĻžāĻŦā§‡ KUBECONFIG āĻĄāĻžāĻ‰āĻ¨āĻ˛ā§‹āĻĄ āĻ•āĻ°āĻ¤ā§‡, āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ OpenStack āĻĨā§‡āĻ•ā§‡ āĻāĻ•āĻŸāĻŋ āĻŸā§‹āĻ•ā§‡āĻ¨ āĻĒā§‡āĻ¤ā§‡ āĻšāĻŦā§‡:

openstack token issue -c id -f value > token

āĻāĻŦāĻ‚ āĻāĻ‡ āĻŸā§‹āĻ•ā§‡āĻ¨ āĻĻāĻŋāĻ¯āĻŧā§‡ āĻĒāĻ°āĻŋāĻšāĻžāĻ˛āĻŋāĻ¤ Kubernetes Selectel API-āĻāĻ° āĻ•āĻžāĻ›ā§‡ āĻāĻ•āĻŸāĻŋ āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻ•āĻ°ā§āĻ¨āĨ¤ k8s_id āĻ–ā§āĻāĻœā§‡ āĻĻā§‡āĻ¯āĻŧ terraform:

curl -XGET -H "x-auth-token: $(cat token)" "https://ru-3.mks.selcloud.ru/v1/clusters/$(cat k8s_id)/kubeconfig" -o kubeConfig.yaml

Cupconfig āĻĒā§āĻ¯āĻžāĻ¨ā§‡āĻ˛ā§‡āĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡āĻ“ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻ•āĻ°āĻž āĻ¯ā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤

āĻŽā§āĻ°āĻ—āĻŋ āĻŦāĻž āĻĄāĻŋāĻŽ: āĻ†āĻ‡āĻāĻ¸āĻŋ āĻŦāĻŋāĻ­āĻ•ā§āĻ¤ āĻ•āĻ°āĻž
āĻĒāĻ‡āĻ āĻž 4. āĻ•ā§āĻ˛āĻžāĻ¸ā§āĻŸāĻžāĻ° āĻŦā§‡āĻ• āĻ•āĻ°āĻžāĻ° āĻĒāĻ°ā§‡ āĻāĻŦāĻ‚ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻāĻŸāĻŋ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻ•āĻ°āĻžāĻ° āĻĒāĻ°ā§‡, āĻ†āĻŽāĻ°āĻž āĻ¸ā§āĻŦāĻžāĻĻā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ‰āĻĒāĻ°ā§‡ āĻ‡āĻ¯āĻŧāĻžāĻŽāĻ˛ āĻ¯ā§‹āĻ— āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°āĻŋāĨ¤

āĻ†āĻŽāĻŋ āĻ¯ā§‹āĻ— āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻ›āĻ¨ā§āĻĻ āĻ•āĻ°āĻŋ:

  • āĻ¨āĻžāĻŽāĻ¸ā§āĻĨāĻžāĻ¨,
  • āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœ āĻ•ā§āĻ˛āĻžāĻ¸
  • āĻĒāĻĄ āĻ¨āĻŋāĻ°āĻžāĻĒāĻ¤ā§āĻ¤āĻž āĻ¨ā§€āĻ¤āĻŋ āĻāĻŦāĻ‚ āĻ¤āĻžāĻ‡āĨ¤

āĻ¸āĻ‚āĻ—ā§āĻ°āĻšāĻ¸ā§āĻĨāĻ˛ āĻ•ā§āĻ˛āĻžāĻ¸ āĻ¸āĻŋāĻ˛ā§‡āĻ•ā§āĻŸā§‡āĻ˛ āĻĨā§‡āĻ•ā§‡ āĻ¨ā§‡āĻ“āĻ¯āĻŧāĻž āĻ¯ā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡ āĻ…āĻĢāĻŋāĻ¸āĻŋāĻ¯āĻŧāĻžāĻ˛ āĻ­āĻžāĻ¨ā§āĻĄāĻžāĻ°.

āĻ¯ā§‡āĻšā§‡āĻ¤ā§ āĻĒā§āĻ°āĻžāĻĨāĻŽāĻŋāĻ•āĻ­āĻžāĻŦā§‡ āĻ†āĻŽāĻŋ āĻœā§‹āĻ¨ā§‡ āĻāĻ•āĻŸāĻŋ āĻ•ā§āĻ˛āĻžāĻ¸ā§āĻŸāĻžāĻ° āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ āĻ•āĻ°ā§‡āĻ›āĻŋ ru-3a, āĻ¤āĻžāĻšāĻ˛ā§‡ āĻ†āĻŽāĻžāĻ° āĻāĻ‡ āĻœā§‹āĻ¨ āĻĨā§‡āĻ•ā§‡ āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœ āĻ•ā§āĻ˛āĻžāĻ¸ āĻĻāĻ°āĻ•āĻžāĻ°āĨ¤

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
 name: fast.ru-3a
 annotations:
   storageclass.kubernetes.io/is-default-class: "true"
provisioner: cinder.csi.openstack.org
parameters:
 type: fast.ru-3a
 availability: ru-3a
allowVolumeExpansion: true

āĻĒāĻ‡āĻ āĻž 5. āĻāĻ•āĻŸāĻŋ āĻ˛ā§‹āĻĄ āĻŦā§āĻ¯āĻžāĻ˛ā§‡āĻ¨ā§āĻ¸āĻžāĻ° āĻ‡āĻ¨āĻ¸ā§āĻŸāĻ˛ āĻ•āĻ°ā§āĻ¨āĨ¤

āĻ†āĻŽāĻ°āĻž āĻ…āĻ¨ā§‡āĻ•ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ¸ā§āĻŸā§āĻ¯āĻžāĻ¨ā§āĻĄāĻžāĻ°ā§āĻĄ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŦ nginx-āĻ…āĻ¨ā§āĻĒā§āĻ°āĻŦā§‡āĻļ. āĻāĻŸāĻŋ āĻ‡āĻ¨āĻ¸ā§āĻŸāĻ˛ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ‡āĻ¤āĻŋāĻŽāĻ§ā§āĻ¯ā§‡āĻ‡ āĻĒā§āĻ°āĻšā§āĻ° āĻ¨āĻŋāĻ°ā§āĻĻā§‡āĻļāĻžāĻŦāĻ˛ā§€ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡, āĻ¤āĻžāĻ‡ āĻ†āĻŽāĻ°āĻž āĻāĻŸāĻŋāĻ¤ā§‡ āĻĨāĻžāĻ•āĻŦ āĻ¨āĻžāĨ¤

$ helm repo add nginx-stable https://helm.nginx.com/stable
$ helm upgrade nginx-ingress nginx-stable/nginx-ingress -n ingress --install -f ../internal/K8S-cluster/ingress/values.yml

āĻ†āĻŽāĻ°āĻž āĻĒā§āĻ°āĻžāĻ¯āĻŧ 3-4 āĻŽāĻŋāĻ¨āĻŋāĻŸā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻŸāĻŋ āĻāĻ•āĻŸāĻŋ āĻŦāĻžāĻšā§āĻ¯āĻŋāĻ• āĻ†āĻ‡āĻĒāĻŋ āĻĒāĻžāĻ“āĻ¯āĻŧāĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ…āĻĒā§‡āĻ•ā§āĻˇāĻž āĻ•āĻ°āĻŋ:

āĻŽā§āĻ°āĻ—āĻŋ āĻŦāĻž āĻĄāĻŋāĻŽ: āĻ†āĻ‡āĻāĻ¸āĻŋ āĻŦāĻŋāĻ­āĻ•ā§āĻ¤ āĻ•āĻ°āĻž
āĻĒā§āĻ°āĻžāĻĒā§āĻ¤ āĻŦāĻšāĻŋāĻ°āĻžāĻ—āĻ¤ āĻ†āĻ‡āĻĒāĻŋ:

āĻŽā§āĻ°āĻ—āĻŋ āĻŦāĻž āĻĄāĻŋāĻŽ: āĻ†āĻ‡āĻāĻ¸āĻŋ āĻŦāĻŋāĻ­āĻ•ā§āĻ¤ āĻ•āĻ°āĻž
āĻĒāĻ‡āĻ āĻž 6. GitLab āĻ‡āĻ¨āĻ¸ā§āĻŸāĻ˛ āĻ•āĻ°ā§āĻ¨āĨ¤

$ helm repo add gitlab https://charts.gitlab.io
$ helm upgrade gitlab gitlab/gitlab -n gitlab  --install -f gitlab/values.yml --set "global.hosts.domain=gitlab.$EXTERNAL_IP.nip.io"

āĻ†āĻŦāĻžāĻ° āĻ†āĻŽāĻ°āĻž āĻ¸āĻŦ āĻļā§āĻāĻŸāĻŋ āĻ“āĻ āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ…āĻĒā§‡āĻ•ā§āĻˇāĻž āĻ•āĻ°āĻŋāĨ¤

kubectl get po -n gitlab
NAME                                      	READY   STATUS  	RESTARTS   AGE
gitlab-gitaly-0                           	0/1 	Pending 	0      	0s
gitlab-gitlab-exporter-88f6cc8c4-fl52d    	0/1 	Pending 	0      	0s
gitlab-gitlab-runner-6b6867c5cf-hd9dp     	0/1 	Pending 	0      	0s
gitlab-gitlab-shell-55cb6ccdb-h5g8x       	0/1 	Init:0/2	0      	0s
gitlab-migrations.1-2cg6n                 	0/1 	Pending 	0      	0s
gitlab-minio-6dd7d96ddb-zd9j6             	0/1 	Pending 	0      	0s
gitlab-minio-create-buckets.1-bncdp       	0/1 	Pending 	0      	0s
gitlab-postgresql-0                       	0/2 	Pending 	0      	0s
gitlab-prometheus-server-6cfb57f575-v8k6j 	0/2 	Pending 	0      	0s
gitlab-redis-master-0                     	0/2 	Pending 	0      	0s
gitlab-registry-6bd77b4b8c-pb9v9          	0/1 	Pending 	0      	0s
gitlab-registry-6bd77b4b8c-zgb6r          	0/1 	Init:0/2	0      	0s
gitlab-shared-secrets.1-pc7-5jgq4         	0/1 	Completed   0      	20s
gitlab-sidekiq-all-in-1-v1-54dbcf7f5f-qbq67   0/1 	Pending 	0      	0s
gitlab-task-runner-6fd6857db7-9x567       	0/1 	Pending 	0      	0s
gitlab-webservice-d9d4fcff8-hp8wl         	0/2 	Pending 	0      	0s
Waiting gitlab
./wait_gitlab.sh ../internal/gitlab/gitlab/.pods
waiting for pod...
waiting for pod...
waiting for pod...

āĻļā§āĻāĻŸāĻŋ āĻ‰āĻ āĻ˛:

āĻŽā§āĻ°āĻ—āĻŋ āĻŦāĻž āĻĄāĻŋāĻŽ: āĻ†āĻ‡āĻāĻ¸āĻŋ āĻŦāĻŋāĻ­āĻ•ā§āĻ¤ āĻ•āĻ°āĻž
āĻĒāĻ‡āĻ āĻž 7. āĻ†āĻŽāĻ°āĻž āĻ—āĻŋāĻŸāĻ˛ā§āĻ¯āĻžāĻŦ-āĻŸā§‹āĻ•ā§‡āĻ¨ āĻĒāĻžāĻ‡āĨ¤

āĻĒā§āĻ°āĻĨāĻŽā§‡, āĻ˛āĻ—āĻ‡āĻ¨ āĻĒāĻžāĻ¸āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻ–ā§āĻāĻœā§‡ āĻŦā§‡āĻ° āĻ•āĻ°ā§āĻ¨:

kubectl get secret -n gitlab gitlab-gitlab-initial-root-password -o jsonpath='{.data.password}' | base64 --decode

āĻāĻ–āĻ¨ āĻ˛āĻ— āĻ‡āĻ¨ āĻ•āĻ°ā§āĻ¨ āĻāĻŦāĻ‚ āĻāĻ•āĻŸāĻŋ āĻŸā§‹āĻ•ā§‡āĻ¨ āĻĒāĻžāĻ¨:

python3 get_gitlab_token.py root $GITLAB_PASSWORD http://gitlab.gitlab.$EXTERNAL_IP.nip.io

āĻĒāĻ‡āĻ āĻž 8. āĻ—āĻŋāĻŸāĻ˛ā§āĻ¯āĻžāĻŦ āĻĒā§āĻ°ā§‹āĻ­āĻžāĻ‡āĻĄāĻžāĻ° āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻ—āĻŋāĻŸ āĻ°āĻŋāĻĒā§‹āĻœāĻŋāĻŸāĻ°āĻŋāĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻ¸āĻ āĻŋāĻ• āĻ…āĻ¨ā§āĻ•ā§āĻ°āĻŽā§‡ āĻ†āĻ¨āĻžāĨ¤

cd ../internal/gitlab/hierarchy && terraform apply -input=false -auto-approve planfile

āĻĻā§āĻ°ā§āĻ­āĻžāĻ—ā§āĻ¯āĻŦāĻļāĻ¤, āĻŸā§‡āĻ°āĻžāĻĢāĻ°ā§āĻŽ āĻ—āĻŋāĻŸāĻ˛ā§āĻ¯āĻžāĻŦ āĻĒā§āĻ°āĻĻāĻžāĻ¨āĻ•āĻžāĻ°ā§€āĻ° āĻāĻ•āĻŸāĻŋ āĻ­āĻžāĻ¸āĻŽāĻžāĻ¨ āĻ†āĻ›ā§‡ āĻŦāĻžāĻ—. āĻ¤āĻžāĻ°āĻĒāĻ° tf.state āĻ āĻŋāĻ• āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻŦāĻŋāĻ°ā§‹āĻ§āĻĒā§‚āĻ°ā§āĻŖ āĻĒā§āĻ°āĻ•āĻ˛ā§āĻĒāĻ—ā§āĻ˛āĻŋ āĻŽā§āĻ¯āĻžāĻ¨ā§āĻ¯āĻŧāĻžāĻ˛āĻŋ āĻŽā§āĻ›ā§‡ āĻĢā§‡āĻ˛āĻ¤ā§‡ āĻšāĻŦā§‡āĨ¤ āĻ¤āĻžāĻ°āĻĒāĻ° `$make all` āĻ•āĻŽāĻžāĻ¨ā§āĻĄāĻŸāĻŋ āĻĒā§āĻ¨āĻ°āĻžāĻ¯āĻŧ āĻšāĻžāĻ˛āĻžāĻ¨

āĻĒāĻ‡āĻ āĻž 9. āĻ†āĻŽāĻ°āĻž āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°ā§‡ āĻ¸ā§āĻĨāĻžāĻ¨ā§€āĻ¯āĻŧ āĻ¸āĻ‚āĻ—ā§āĻ°āĻšāĻ¸ā§āĻĨāĻ˛ āĻ¸ā§āĻĨāĻžāĻ¨āĻžāĻ¨ā§āĻ¤āĻ° āĻ•āĻ°āĻŋāĨ¤

$ make push

[master (root-commit) b61d977]  Initial commit
 3 files changed, 46 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 values.yml
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 770 bytes | 770.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0)

āĻļā§‡āĻˇ:

āĻŽā§āĻ°āĻ—āĻŋ āĻŦāĻž āĻĄāĻŋāĻŽ: āĻ†āĻ‡āĻāĻ¸āĻŋ āĻŦāĻŋāĻ­āĻ•ā§āĻ¤ āĻ•āĻ°āĻž
āĻŽā§āĻ°āĻ—āĻŋ āĻŦāĻž āĻĄāĻŋāĻŽ: āĻ†āĻ‡āĻāĻ¸āĻŋ āĻŦāĻŋāĻ­āĻ•ā§āĻ¤ āĻ•āĻ°āĻž
āĻŽā§āĻ°āĻ—āĻŋ āĻŦāĻž āĻĄāĻŋāĻŽ: āĻ†āĻ‡āĻāĻ¸āĻŋ āĻŦāĻŋāĻ­āĻ•ā§āĻ¤ āĻ•āĻ°āĻž

āĻ‰āĻĒāĻ¸āĻ‚āĻšāĻžāĻ°

āĻ†āĻŽāĻ°āĻž āĻ…āĻ°ā§āĻœāĻ¨ āĻ•āĻ°ā§‡āĻ›āĻŋ āĻ¯ā§‡ āĻ†āĻŽāĻ°āĻž āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ¸ā§āĻĨāĻžāĻ¨ā§€āĻ¯āĻŧ āĻŽā§‡āĻļāĻŋāĻ¨ āĻĨā§‡āĻ•ā§‡ āĻ˜ā§‹āĻˇāĻŖāĻžāĻŽā§‚āĻ˛āĻ•āĻ­āĻžāĻŦā§‡ āĻ¸āĻŦāĻ•āĻŋāĻ›ā§ āĻĒāĻ°āĻŋāĻšāĻžāĻ˛āĻ¨āĻž āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°āĻŋāĨ¤ āĻāĻ–āĻ¨ āĻ†āĻŽāĻŋ āĻāĻ‡ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻ•āĻžāĻœāĻ—ā§āĻ˛āĻŋ CI āĻ āĻ¸ā§āĻĨāĻžāĻ¨āĻžāĻ¨ā§āĻ¤āĻ° āĻ•āĻ°āĻ¤ā§‡ āĻšāĻžāĻ‡ āĻāĻŦāĻ‚ āĻ•ā§‡āĻŦāĻ˛ āĻŦā§‹āĻ¤āĻžāĻŽ āĻŸāĻŋāĻĒā§āĻ¨āĨ¤ āĻāĻŸāĻŋ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯, āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ¸ā§āĻĨāĻžāĻ¨ā§€āĻ¯āĻŧ āĻ°āĻžāĻœā§āĻ¯āĻ—ā§āĻ˛āĻŋ (āĻŸā§‡āĻ°āĻžāĻĢāĻ°ā§āĻŽ āĻ°āĻžāĻœā§āĻ¯) CI-āĻ¤ā§‡ āĻ¸ā§āĻĨāĻžāĻ¨āĻžāĻ¨ā§āĻ¤āĻ° āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡āĨ¤ āĻāĻŸāĻŋ āĻ•ā§€āĻ­āĻžāĻŦā§‡ āĻ•āĻ°āĻŦā§‡āĻ¨ āĻ¤āĻž āĻĒāĻ°āĻŦāĻ°ā§āĻ¤ā§€ āĻ…āĻ‚āĻļā§‡ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤

āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ¸āĻĻāĻ¸ā§āĻ¯āĻ¤āĻž āĻŦā§āĻ˛āĻ—āĻ¯āĻžāĻ¤ā§‡ āĻ¨āĻ¤ā§āĻ¨ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§ āĻĒā§āĻ°āĻ•āĻžāĻļ āĻŽāĻŋāĻ¸ āĻ¨āĻž!

āĻ‰āĻ¤ā§āĻ¸: www.habr.com

āĻāĻ•āĻŸāĻŋ āĻŽāĻ¨ā§āĻ¤āĻŦā§āĻ¯ āĻœā§āĻĄāĻŧā§āĻ¨