• О WordPress
    • WordPress.org
    • Документация
    • Поддержка
    • Обратная связь
  • Войти
  • Зарегистрироваться
RUSinfoproduct
  • Главная
  • Наши услуги
  • О нас
  • Contact Us
  • Our Blog

Recent Posts

  • Лучшие практики Ansible: часть 1

  • Непрерывное развертывание инфраструктуры AWS без доверия стороннему CI

  • Лучшие практики Ansible: часть 2

  • Краткое руководство по GraalVM

@2019 - All Right Reserved. Designed and Developed by PenciDesign
Devops практики

Лучшие практики Ansible: часть 1

by moiseevrus 17.12.2022
written by moiseevrus

Существует множество инструментов DevOps. Выбрать человека для работы не всегда просто. Используя его эффективно с самого начала, тем более.

Возможно, вы исследуете Ansible в связи с переходом на новую платформу, и вам необходимо управлять всеми ресурсами. Или у вас есть куча самодельных скриптов для управления вашей инфраструктурой, но поддерживать их становится мучительно. Первые шаги с новым инструментом также могут быть ошеломляющими, и все возможности могут показаться ошеломляющими.

Этот пост и следующий стремятся ответить на вопросы: «Когда я должен выбрать Ansible?» и «Как эффективно использовать Ansible?». Возможно также: «Почему Норвегия фальшивая?».

Поиск в Google: «Инженер DevOps». Возможно, Вы имели в виду: "инженер файлов YAML"
Читайте дальше, чтобы получить помощь в выборе правильного инструмента для работы. Ознакомьтесь с некоторыми передовыми практиками Ansible, а также конкретными советами и рекомендациями.

Что такое Анзибл?

Ansible — это инструмент автоматизации, используемый для управления конфигурацией и оркестровки инфраструктуры, систем и приложений.

Он начал свою жизнь как проект одного человека. Затем была расширена до компании и теперь спонсируется RedHat. Поддерживаемый сообществом открытого исходного кода, он является зрелым и широко используется.

Ansible, как и его известные товарищи: Chef , Puppet и SaltStack , используется для описания желаемого состояния системы в виде кода, что в данном случае означает YAML с вкраплениями шаблонов Jinja2 сверху. Все перечисленные инструменты стремятся к идемпотентности, что вкратце означает, что они вносят изменения только тогда, когда это необходимо. Есть некоторая разница в том, достигается ли это декларативно или императивно, но результат один и тот же.

Он имеет безагентную архитектуру, поэтому начать работу с ним несложно. Никаких зависимостей, кроме Python, для обработки управляемых хостов. Напишите сценарий в YAML, и готово. Направление толкать , а не тянуть . По умолчанию он подключается к целевым хостам с помощью SSH или WinRM в случае ящиков Windows. Если вы привыкли писать это install.shили install.ps1, вы почувствуете себя как дома, изменив это на install.yamlи получив все преимущества платформы автоматизации Ansible.

Ansible также можно использовать для подключения к различным API-интерфейсам для подготовки облачных серверов или для настройки кластеров Kubernetes. Таким образом, его можно использовать в качестве дополнительного инструмента или замены Terraform , и ничто не мешает вам создавать манифесты Kubernetes YAML, наполненные шаблонами Jinja2, и развертывать их с помощью Ansible , а не Helm .

Но поскольку ландшафт инструментов с открытым исходным кодом огромен, возникает вопрос: должны ли вы?

В чем он хорош?

Как было сказано ранее, начать работу с ним несложно. Распространяемый как единый пакет Python, Ansible поставляется со всем, кроме кухонной раковины .

До версии 2.10 , которая в настоящее время находится в разработке, это особенно верно, поскольку в ядре Ansible есть такие модули, как package и win_service , которые управляют обещанными ресурсами с их именами. Но есть и более специфические модули . Идите вперед и запускайте планы Terraform с помощью Ansible. Все это с помощью сингла pip install ansible. После выхода версии 2.10 пользовательский интерфейс может не сильно измениться, но в будущем модули будут жить вне ядра в коллекциях и ими можно будет управлять отдельно.

Ansible также широко используется для управления сетевым оборудованием. От маршрутизаторов до коммутаторов, безагентная архитектура делает Ansible хорошим выбором для автоматизации довольно утомительных задач по назначению VLAN в оборудовании Cisco или интерфейсах Juniper Junos. В этих случаях подключение к устройствам отличается от SSH по умолчанию. Благодаря архитектуре плагинов такие протоколы, как NETCONF, можно использовать для управления всеми вещами.

Написанный на Python, Ansible легко расширяется. Так что если в списке выше нет нужного вам модуля, вы можете написать какой-нибудь свой или расширить включенные фильтры Jinja2 с помощью плагина . Чаще всего достаточно готовых модулей и желаемое состояние системы достигается комбинацией задач.

Ansible также удобен для глаз. Задачи для запуска написаны на YAML, который де-факто становится языком конфигурации многих других современных инструментов. Он приносит с собой некоторые подводные камни, но в основном это список задач…

- hosts: localhost
# Use sudo to become root.
become: true
tasks:
- name: Install Apache
package:
name: apache2
state: present
- name: Start and enable Apache
service:
name: apache2
state: started
enabled: true

…легко понимается и не системным администратором.

С Ansible легко делать простые вещи, а более сложные задачи не слишком сложны, поскольку Ansible допускает циклы и другие конструкции , которые делают YAML шагом к реальному языку программирования, где возможно все. Синтаксис Ansible находится где-то между императивным и декларативным, в основном ближе к последнему по оси парадигм программирования. Вы сосредотачиваетесь на том, чего хотите, а не на том, как . Пуристы также определят императивные аспекты. Если ничего не помогает, добавьте немного кода Python в блок шаблонов Jinja2, чтобы выполнить даже самую сложную задачу.

Помимо написания плейбуков для выполнения задач, в Ansible есть концепция, называемая специальной командой , которую можно использовать для внесения изменений в работающие системы без написания какого-либо YAML. Например, чтобы перезапустить все экземпляры Apache на всех хостах в webserversгруппе. Это похоже на подключение по SSH ко всем хостам и запуск systemctl restart apache2. Это и синтаксис делают Ansible очень подходящим для ситуаций, когда оператор очень привык к управлению системами, но ему нужны руки робота, чтобы помочь с управлением парком.

Если вы стремитесь создать неизменяемую инфраструктуру, подобную той, которая обычно связана с запуском контейнеров, Ansible можно пометить вместе с Packer . При совместном использовании Ansible управляет состоянием развертываемых образов. Также доступен Ansible-ориентированный способ создания контейнеров, так как чистый синтаксис Dockerfile может начать вас раздражать в какой-то момент.

Кстати, короткий фрагмент выше полностью функционален! Вы можете поместить его в файл с именем playbook.ymlи запустить команду ansible-playbook -i localhost playbook.ymlпосле установки самого Ansible. Без каких-либо изменений он установит и запустит Apache в системе Linux на основе Debian. Просто для начала, не так ли?

Каковы недостатки?

Теперь вы могли бы вести со мной продолжительную дискуссию, и я мог бы убедить вас, что их нет. Но ради реализма… чтобы мои коллеги были счастливы , есть некоторые вещи, которые могут вас раздражать в Ansible.

У Jinja2 есть свои особенности, одна из которых — обработка всего как строки по умолчанию, так как по своей сути он предназначен для рендеринга текстовых файлов. Будьте готовы немного потанцевать с целыми числами. Некоторый прогресс был достигнут из темных дней, но вам все еще нужно включить его .

YAML. Что ж, YAML хорош и все такое, но обманчиво прост. На самом деле это довольно сложно , и вы можете, например, определить многострочную строку миллионом способов. Достаточно, чтобы гарантировать наличие специального веб-сайта: yaml-multiline.info . Логические значения также могут быть выражены разными способами, поэтому в некоторых местах вы можете увидеть yesвместо . trueОба варианта синтаксически правильны , но для ясности следует придерживаться одного из них. Просто помните, что Norway тоже ложнаNO , так как интерпретируется как логическое значение. Не забывайте также правильно делать отступ в каждой строке. Неправильный размер отступа в большинстве случаев приводит к ошибке или неправильному толкованию в остальных.

Выполнение задачи линейное, для каждой задачи одновременно выполняется пакет хостов, но задачи следуют друг за другом в строгом порядке. Это можно изменить, выбрав другую стратегию , но опять же, это параметр конфигурации, который, скорее всего, оставлен по умолчанию, и вам нужно знать последствия его включения.

Ansible также не имеет состояния по своей конструкции, поэтому по сравнению с обработкой состояния Terraform ему необходимо идти и проверять каждый ресурс, каждый раз, когда он сталкивается с задачей, которую вы создали для управления состоянием указанного ресурса. Получить хорошую разницу изменений за один раз невозможно, например, в Terraform или Helm. В сочетании с линейной стратегией по умолчанию будьте готовы ждать, пока ваша 1000-я задача внесет свои изменения после того, как 999 впервые будут отмечены знаком ok. Есть несколько способов ограничить это время ожидания, но у Ansible нет способа узнать , что модификация есть только у последней задачи, а у остальных нет, пока она не дойдет до конца.

Также нет реальных зависимостей между ресурсами, как в Puppet и Terraform. В то время как вы можете получать выходные данные задач registerи использовать их в качестве входных данных в другом месте, а также можете notifyиспользовать другие ресурсы handlersво время изменений. Вы не можете получить график всех ресурсов в ваших книгах и ролях.

Ansible отлично работает, когда у вас есть ограниченное количество администраторов, выполняющих команды. Все они имеют контроль доступа на стороне «корневого доступа» спектра разрешений. У него нет механизма блокировки, если только вы его не создадите, поэтому ничто не мешает вам запускать конфликтующие изменения из нескольких мест одновременно. Контроль версий настоятельно рекомендуется с плейбуками, но из-за этого обработка ветвей может потребовать некоторой работы со стороны пользователя. Вы можете начать мечтать о сервере, как в Chef или Puppet, когда достигнете определенного уровня. Для контроля доступа, централизованного управления или при наличии пользователей с разной степенью разрешений.

Можно также сказать, что безагентная push-архитектура имеет свои ограничения, но давайте согласимся, что у другого направления тоже есть проблемы, и они подходят для разных типов вариантов использования. Среди всех плюсов и минусов возникает еще один вопрос: когда следует выбирать Ansible в качестве предпочтительного инструмента?

Когда я должен выбрать Ansible вместо альтернатив?

Ansible отлично справляется с управлением серверами и инфраструктурой Unix-y. Написание ролей и управление установкой, настройкой и запуском таких сервисов, как Apache, Elasticsearch или MariaDB. Он также имеет множество модулей, связанных с сетью, поэтому Ansible чувствует себя как дома в центре обработки данных. Места, где среда немного более статична по сравнению с эфемерной природой контейнеров.

Специальные команды и простой синтаксис делают его хорошим инструментом для операторов. Чтобы быстро начать работу, старые скрипты и штуковины можно преобразовать в YAML с меньшими усилиями, чем научиться писать Ruby для Chef, терраформировать все или перейти на новый способ работы с контейнерами и Kubernetes.

У Ansible нет ни пользовательского интерфейса, ни сервера, если не считать Ansible Tower от RedHat. Таким образом, он обслуживает пользователей, разбирающихся в командной строке, лучше, чем люди, привыкшие нажимать кнопки. Говоря о Tower, он позволяет визуализировать и централизовать использование Ansible. Он также предоставляет вам API и контроль доступа. Это также идет с ценником. В качестве альтернативы AWX — это исходная версия Tower с открытым исходным кодом.

Хотя можно использовать Ansible для взаимодействия с API-интерфейсами облачной платформы для создания серверов, а затем с помощью модуля динамической инвентаризации для подключения к ним в качестве хостов, Ansible не в лучшем виде. В более широком масштабе вы можете начать ценить обработку состояния Terraform и сопоставление конфигурации с реальными ресурсами.

При работе с общедоступными облаками, такими как AWS, Azure или GCP, консенсус, похоже, заключается в том, чтобы использовать Terraform для подготовки. Вполне возможно, из-за указанной выше причины обработки состояния. Но Terraform не преуспевает в управлении содержимым серверов, поэтому, возможно, продолжайте управлять конфигурацией с помощью Ansible. Однако это плохо работает с автоматическим масштабированием и другими действиями по оркестровке. Поэтому лучшим вариантом было бы создать изображения с помощью Ansible, а затем отправить их в облако с помощью Terraform. После этого выполните любое автомасштабирование и восстановление после сбоя с неизменяемыми образами. Что касается операций, Ansible будет удобен благодаря специальным командам и быстрому написанию плейбуков.

Облачные провайдеры также имеют свои собственные способы ведения дел. Я слышал хорошие отзывы о CDK от Amazon, но никогда им не пользовался. Поскольку это фактически код-код , а не вид-кода Ansible , он зависит от вашего опыта и личных предпочтений, а также от возможностей программного обеспечения. И даже с CDK вы получаете промежуточный декларативный CloudFormation . У Azure есть свой Resource Manager , а Google назвал их Deployment Manager . Но облачные технологии — это именно облачные технологии . При выборе инструментов я вижу большую ценность в том, чтобы придерживаться более широкого круга задач.

Например, в OpenStack я лично предпочел бы Ansible писать шаблоны Heat при предоставлении основных ресурсов. Инструмент более общий, и я думаю, что лучше быть экспертом Ansible, чем экспертом OpenStack Heat. Шаблоны Heat, как правило, со временем становятся все более запутанными и чрезмерно сложными. Но существуют некоторые ограничения на то, что поддерживают текущие модули OpenStack, поэтому необходимость управления новейшими компонентами OpenStack может ограничить ваш выбор инструментов. Однако после перехода к collections разработка модуля, похоже, набирает обороты. Говоря об OpenStack, OpenStack-Ansible — хороший проект для развертывания самого OpenStack.

Поддерживается управление серверами Windows, но модули Windows хранятся отдельно от вариантов Linux. Их также гораздо меньше по количеству. Переход с Ubuntu на RedHat менее болезненный и требует меньше изменений в YAML, чем переход с Ubuntu на Windows. Контроллер Ansible также должен быть основан на Unix, и, хотя теоретически возможно использовать для этого WSL, он не поддерживается и не рекомендуется для использования в производстве.

Но дело в том, что вы не ограничены только одним инструментом! Ansible отлично работает в сочетании с Terraform. Вы можете использовать его для создания некоторых кластеров Kubernetes локально или в облаке , а затем использовать Helm для управления самими развертываниями. Вы также можете более глубоко подключить Ansible к Kubernetes с помощью Operator SDK . Вы можете использовать его для создания образов контейнеров, а также образов виртуальных машин для достижения неизменности в производственных средах. И, помимо различных альтернатив, он действительно превосходен в управлении сетевым оборудованием, поэтому вы можете подключить его к NetBox .

Я надеюсь, что это послужит хорошим введением в Ansible и пробудит ваш интерес. Если вы уже знакомы с этим или находитесь в процессе выбора инструментов, взгляните на следующую часть этой серии блогов, чтобы узнать об основных концепциях, некоторых фактах использования и передовых методах.

Статья является переводом medium.com

17.12.2022 0 comment
0 FacebookTwitterPinterestEmail
Бизнес в итернете

Непрерывное развертывание инфраструктуры AWS без доверия стороннему CI

by moiseevrus 17.12.2022
written by moiseevrus

Я работал со многими клиентами, которые размещают свою производственную инфраструктуру на AWS, но их конвейеры CI размещаются у стороннего поставщика, такого как Travis, Wercker и CircleCI. Довольно легко понять, почему: сторонние ЭК очень просты в настройке и использовании! У них также есть неплохая документация, и они широко используются в проектах с открытым исходным кодом. CI обычно используется для запуска тестов, создания артефактов выпуска, а иногда даже для развертывания приложений.

Однако многие команды чувствуют себя неловко, когда дело доходит до использования CI для развертывания изменений инфраструктуры. Обычно это происходит не потому, что они не доверяют автоматизированному процессу, а потому, что они не хотят предоставлять широкий доступ к учетным записям AWS, которые обычно требуются при управлении инфраструктурой как кодом.

Однако я обнаружил, что автоматизация изменений инфраструктуры может быть полезной. Я думаю, что это значительно снижает когнитивную нагрузку, когда речь идет о синхронизации вашей инфраструктуры. Итак, есть ли способ, которым мы могли бы по-прежнему обеспечивать непрерывное развертывание для изменений инфраструктуры, не доверяя стороннему CI? В этой статье я представлю одно решение этой проблемы. В основном я работаю с AWS, поэтому я создал решение специально для него.

Ограничения

Мы хотим автоматизировать изменения инфраструктуры, но есть ограничения. Давайте разберем проблему.

Ограничение № 1. Мы не хотим предоставлять стороннему CI доступ к инфраструктуре AWS, который позволит ему нанести какой-либо ущерб, если доступ по какой-либо причине попадет в чужие руки. Например, если произойдет утечка учетных данных AWS, назначенных CI, злоумышленник, использующий эти учетные данные, не сможет удалить наши базы данных и запустить крипто-майнеры.

Ограничение № 2: мы хотим, чтобы изменения инфраструктуры запускались без участия человека. Как только изменение кода инфраструктуры будет зафиксировано в основной ветке в репозитории Git, оно в конечном итоге будет развернуто в рабочей среде при условии, что остальные этапы автоматизации перед его выполнением будут успешно выполнены.

Ограничение № 3. Мы хотим, чтобы изменения инфраструктуры инициировались после конвейера CI, подключенного к тому же репозиторию кода. Некоторые репозитории Git могут содержать как код приложения, так и код инфраструктуры. Например, репозиторий Git может содержать исходный код веб-приложения и код инфраструктуры для развертывания приложения и окружающих служб (например, корзины S3, экземпляры RDS). В этих случаях важно убедиться, что изменения инфраструктуры не выполняются, если тесты не пройдены в конвейере CI.

Ограничение № 4. Мы хотим, чтобы это решение работало с несколькими репозиториями Git. Как упоминалось в приведенном выше ограничении, у нас может быть код инфраструктуры, совмещенный с кодом приложения, а это означает, что нам необходимо поддерживать изменения инфраструктуры, поступающие из нескольких репозиториев.

Грубый архитектурный эскиз

Имея в виду эти ограничения, давайте представим, как примерно будет выглядеть архитектура.

Если мы хотим развернуть изменения инфраструктуры AWS, но в то же время сделать это безопасно, обычно рекомендуется запускать их в самом AWS. Таким образом, вам нужно доверять только AWS, а не дополнительным третьим сторонам. В конце концов, вы уже доверяете AWS свою инфраструктуру. Кроме того, если вы развертываете изменения из AWS, вы можете использовать роли IAM, которыми гораздо сложнее злоупотреблять, чем пользователями IAM .

Предполагая, что у нас есть этот волшебный деплойер, размещенный в AWS, нам нужен способ его запуска. Если мы запустим его напрямую от нашего поставщика Git (например, веб-перехватчики Github), мы не можем гарантировать, что он будет работать после завершения конвейера CI (ограничение № 3). По этой причине мы предоставим возможность запускать деплойер для репозитория по запросу из CI (ограничение № 2), но не более того. Разработчик по-прежнему будет нести ответственность за получение исходного кода и любых других деталей, связанных с запуском развертывания, вместо того, чтобы доверять CI передавать правильную информацию (ограничение № 1).

Нам также нужен регистр, чтобы содержать информацию о том, какие именно репозитории можно использовать с развертывателем. Когда развертыватель запускается, он проверяет данные репозитория из реестра. Таким образом, мы можем поддерживать несколько исходных репозиториев с одним и тем же деплойером (ограничение № 4), но также убедиться, что мы не запускаем код из произвольных источников. Мы также можем включить в реестр такую ​​информацию, как данные аутентификации Git и команды развертывания.

Поиск решений

Давайте заглянем в нашу кучу LEGO, которая является каталогом продуктов AWS , и посмотрим, какие компоненты мы можем найти для решения нашей проблемы.

Фото Рика Мейсона на Unsplash

КодБилд

Что мы действительно хотим сделать, так это непрерывное развертывание на AWS, и AWS рекомендует использовать для этого CodePipeline и CodeBuild. Подводя итог, можно сказать, что CodePipeline — это решение для связывания различных шагов для формирования конвейера доставки вашего кода, а CodeBuild предназначен для работы в качестве шага в конвейере, который запускает произвольные команды, такие как тесты и упаковка программного обеспечения.

Поскольку все, что мы хотим сделать, это запустить один шаг, развернуть код инфраструктуры, CodeBuild должно быть достаточно для наших целей. CodeBuild может запускать контейнеры Docker, поэтому мы можем создать собственный образ Docker, включающий весь код и инструменты, необходимые для получения исходного репозитория и внесения изменений в инфраструктуру. Затем мы можем выполнить его независимо, используя вызов API StartBuild .

Проксирование вызовов CodeBuild

Итак, мы просто создадим проект CodeBuild и предоставим возможность вызывать API StartBuild из стороннего CI, верно? К сожалению, это раскрывает слишком многое. API StartBuild позволяет вам переопределить множество деталей, указанных в проекте CodeBuild, в том числе какие команды запускать. В случае утечки доступа к API злоумышленник, имеющий доступ, может выполнять произвольные команды в нашей инфраструктуре AWS.

Если бы только у нас был какой-то прокси для соединения и фильтрации вызовов от стороннего CI к CodeBuild.

Я сомневаюсь, что у AWS есть продукт, специально предназначенный для решения этой проблемы, но мы всегда можем положиться на Lambda — часть AWS LEGO 2×4 — чтобы склеить эти части вместе. Мы можем создать тему SNS, где CI может отправить сообщение, чтобы инициировать развертывание в AWS. Затем тема SNS запускает функцию Lambda, которая запускает задание CodeBuild. Мы также можем использовать функцию Lambda для проверки репозитория и запускать задание CodeBuild только в том случае, если репозиторий находится в белом списке.

параметры ССМ

Нам по-прежнему нужно место для хранения сведений о том, какие репозитории можно использовать с развертывателем. Я обнаружил, что параметры SSM являются полезным решением для записи произвольных пар ключ-значение небольшого объема. Он также поддерживает IAM для управления доступом и KMS для шифрования значений, поэтому мы можем ограничить, кто может изменять список репозиториев, внесенных в белый список для развертывателя, и безопасно хранить учетные данные Git.

Диаграмма архитектуры

Теперь, когда мы заполнили недостающие части, вот как выглядит наша архитектура.

Покажи мне код!

Это не было бы большой демонстрацией, если бы я просто показал вам кучу архитектурных диаграмм. Давайте посмотрим на некоторые примеры кода.

У меня есть полный пример, размещенный в репозитории GitHub: I Wanna Own My Pipeline in AWS . Я создал его с помощью AWS CDK с TypeScript в качестве языка программирования, но здесь подойдет практически любой инструмент «инфраструктура как код» с поддержкой AWS.

Информация о проекте в параметрах SSM

Во-первых, давайте посмотрим, как мы храним информацию о проекте в параметрах SSM.

Я решил разместить всю информацию о проекте по одному корневому пути ( /iwomp-in-aws), при этом каждый проект имеет один параметр, содержащий все необходимые сведения в формате JSON. JSON включает следующие ключи:

  • gitUrl: URL-адрес репозитория Git, из которого нужно извлечь код.
  • authToken: Токен для аутентификации на основе токенов. (по желанию)
  • basicUsername: Имя пользователя для базовой аутентификации. (по желанию)
  • basicPassword: Пароль для базовой аутентификации. (по желанию)
  • deployDir: Каталог, в котором находится весь код инфраструктуры. По умолчанию: корневой каталог Git. (по желанию)
  • command: команда для развертывания изменений инфраструктуры. Обратите внимание, что одна и та же команда выполняется всегда для каждого запуска, поэтому, если вам нужно выполнить какую-либо фильтрацию веток Git, это необходимо учитывать в сценарии.

Например, /iwomp-in-aws/demoможет содержать следующий документ JSON:

{ 
"gitUrl": "https://github.com/jkpl/cdk-demo ", 
"command": "./deploy.sh" 
}

Проект использует «demo» в качестве идентификатора проекта, код извлекается из репозитория cdk-demo, и ./deploy.shкоманда выполняется каждый раз, когда запускается деплойер.

Информация о проекте может управляться вручную или автоматически. Любой способ работает лучше всего для вас. Репозиторий Git содержит пример того, как управлять проектами с помощью CDK .

Проект CodeBuild

Поскольку мы собираемся запускать собственный контейнер Docker в CodeBuild, мы сначала настроим репозиторий ECR для размещения образов Docker . Я расскажу о содержимом образа Docker в следующем разделе.

import * as ecr from '@aws-cdk/aws-ecr';
const containerImageRepo = new ecr.Repository(this, 'repo', {
repositoryName: 'iwomp-in-aws',
});

Теперь мы можем создать проект CodeBuild для нашего деплойнера . Мы настроим его на чтение образа Docker из репозитория ECR выше и запустим команду развертывания iwomp-in-aws, доступную в образе. Я дополнительно установлю CONFIGPATHпеременную среды, которая сообщает контейнеру, где мы можем найти всю информацию о проекте в параметрах SSM.

import * as codebuild from '@aws-cdk/aws-codebuild';
const configPath = iwompProps.configPath || 'iwomp-in-aws';
const worker = new codebuild.Project(this, 'worker', {
buildSpec: codebuild.BuildSpec.fromObject({
version: '0.2',
phases: {
build: {
commands: ['iwomp-in-aws'],
},
},
}),
description: 'iwomp-in-aws worker',
environment: {
buildImage: codebuild.LinuxBuildImage.fromEcrRepository(containerImageRepo),
computeType: codebuild.ComputeType.SMALL,
environmentVariables: {
'CONFIGPATH': {value: configPath},
}
},
});

Нам потребуется предоставить IAM-разрешения проекту CodeBuild, чтобы он работал. CDK автоматически создаст роль IAM для проекта CodeBuild, которому мы можем предоставить разрешение. Во- первых, нам нужно предоставить ему доступ для чтения параметров SSM .

import * as iam from '@aws-cdk/aws-iam';
const configPath = iwompProps.configPath || 'iwomp-in-aws';
const configPathArn = this.formatArn({
service: 'ssm',
resource: `parameter/${configPath}/*`
});
worker.addToRolePolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
resources: [configPathArn],
actions: ['ssm:GetParameter'],
}));

Мы также хотим предоставить доступ к управлению другими сервисами AWS, которыми мы хотим управлять автоматически. В репозитории Git есть один пример того, как это сделать .

Инструмент развертывания

Проекту CodeBuild требуется специальный инструмент для клонирования исходного репозитория Git и выполнения команды развертывания в соответствии с информацией, хранящейся в параметрах SSM. Это iwomp-in-awsкоманда, упомянутая в последнем разделе.

Я решил закодировать инструмент, используя Go в качестве языка программирования, потому что я знаком с ним, и поскольку он создает статические двоичные файлы, я могу просто вставить любой образ Docker.

Параметры запуска инструмента считываются из переменных среды с помощью envconfig . Эти параметры предоставляются при запуске задания CodeBuild.

package mainimport (
	"fmt"
	"log"
	"github.com/kelseyhightower/envconfig"
)type appConfig struct {
	ConfigPath  string `default:"iwomp-in-aws"`
	ProjectName string `required:"true"`
	GitBranch   string `required:"true"`
}

func (c *appConfig) projectPath() string {
	return fmt.Sprintf("/%s/%s", c.ConfigPath, c.ProjectName)
}

func (c *appConfig) load() error {
	return envconfig.Process("", c)
}func main() {
	if err := mainWithErr(); err != nil {
		log.Fatalf("iwomp-in-aws: %s", err)
	}
}

func mainWithErr() error {
	// Load app config
	var appConf appConfig
	if err := appConf.load(); err != nil {
		return err
	}
	// continued in the next code block ...
}

Вот для чего нужны конфигурации:

  • ConfigPath: базовый путь для параметров SSM.
  • ProjectName: Имя проекта для развертывания. Имя должно совпадать с идентификатором проекта в параметрах SSM. Например, если установлено значение demo и ConfigPathиспользуется значение по умолчанию, сведения о проекте извлекаются из параметра SSM /iwomp-in-aws/demo.
  • GitBranch: имя ветки Git для клонирования проекта.

Далее мы загрузим конфигурацию проекта из параметров SSM.

import (
	"encoding/json"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ssm"
)type projectConfig struct {
	GitURL        string `json:"gitUrl"`
	AuthToken     string `json:"authToken"`
	BasicUsername string `json:"basicUsername"`
	BasicPassword string `json:"basicPassword"`
	DeployDir     string `json:"deployDir"`
	Command       string `json:"command"`
}func (c *projectConfig) load(ac *appConfig, sess *session.Session) error {
	ssmSVC := ssm.New(sess)

	projectPath := ac.projectPath()
	projectOut, err := ssmSVC.GetParameter(&ssm.GetParameterInput{
		Name:           aws.String(projectPath),
		WithDecryption: aws.Bool(true),
	})
	if err != nil {
		return fmt.Errorf("failed to fetch from SSM path %s: %s", projectPath, err)
	}
	if err := c.loadFromParameter(projectOut.Parameter); err != nil {
		return fmt.Errorf("failed to load from SSM path %s: %s", projectPath, err)
	}

	// Fill in the gaps
	if c.DeployDir == "" {
		c.DeployDir = "."
	}

	// Validate
	if c.GitURL == "" {
		return fmt.Errorf("no Git URL specified for project %s", ac.ProjectName)
	}
	if c.Command == "" {
		return fmt.Errorf("no command specified for project %s", ac.ProjectName)
	}

	return nil
}

func (c *projectConfig) loadFromParameter(parameter *ssm.Parameter) error {
	return json.Unmarshal([]byte(*parameter.Value), c)
}func mainWithErr() error {
	// continued from the previous code block ...

	// Start AWS session
	sess, err := session.NewSession(&aws.Config{})
	if err != nil {
		return err
	}

	// Load config for the project
	var projectConf projectConfig
	if err := projectConf.load(&appConf, sess); err != nil {
		return err
	}

	// continued in the next code block ...
}

Конфигурация проекта включает в себя все параметры, перечисленные в разделе «Информация о проекте в параметрах SSM». Как упоминалось ранее, мы загрузим один параметр SSM и проанализируем его содержимое как JSON. Некоторые параметры имеют разумные значения по умолчанию, поэтому мы просто восполним пробелы, если они есть. Мы также проверим, что по крайней мере URL-адрес Git и команда развертывания были указаны, и быстро завершится сбой, если они не указаны.

Получив всю информацию о проекте, мы можем продолжить и клонировать репозиторий Git, используя эту удобную библиотеку Go .

import (
	git "github.com/go-git/go-git/v5"
	gitPlumbing "github.com/go-git/go-git/v5/plumbing"
	gitTransport "github.com/go-git/go-git/v5/plumbing/transport"
	gitHTTP "github.com/go-git/go-git/v5/plumbing/transport/http"
)func (c *projectConfig) gitAuth() gitTransport.AuthMethod {
	if c.AuthToken != "" {
		return &gitHTTP.TokenAuth{
			Token: c.AuthToken,
		}
	}
	if c.BasicPassword != "" {
		return &gitHTTP.BasicAuth{
			Username: c.BasicUsername,
			Password: c.BasicPassword,
		}
	}

	return nil
}func cloneRepository(appConf *appConfig, projectConf *projectConfig) error {
	log.Printf("cloning repo %s branch %s", projectConf.GitURL, appConf.GitBranch)

	_, err := git.PlainClone(".", false, &git.CloneOptions{
		URL:           projectConf.GitURL,
		Auth:          projectConf.gitAuth(),
		ReferenceName: gitPlumbing.NewBranchReferenceName(appConf.GitBranch),
		SingleBranch:  true,
		Progress:      os.Stdout,
		Depth:         1,
	})
	return err
}func mainWithErr() error {
	// continued from the previous code block ...	// Clone repo for the project based on app config
	if err := cloneRepository(&appConf, &projectConf); err != nil {
		return err
	}

	// continued in the next code block ...
}

Нам понадобится только последняя фиксация, поэтому мы можем настроить операцию клонирования так, чтобы она извлекала только последнюю фиксацию из ветки, указанной в переменных среды.

Наконец, мы можем выполнить команду развертывания, указанную для проекта.

import (
	"os"
	"os/exec"
)func (c *projectConfig) run(appConf *appConfig) error {
	cmd := exec.Command(c.Command, appConf.GitBranch)
	cmd.Dir = c.DeployDir
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}func mainWithErr() error {
	// continued from the previous code block ...

	// Run the project command
	return projectConf.run(&appConf)
}

Вы можете найти полный исходный код этого инструмента в репозитории Git .

Развертывание Docker-образа

Нам нужен образ Docker для обработки процесса развертывания. Он должен включать следующее:

  1. Инструмент развертывания из предыдущего раздела.
  2. Фоновые зависимости, необходимые для выполнения фактического развертывания. Например, CDK, Terraform, Pulumi или любой другой инструмент, который вы хотите использовать для управления инфраструктурой AWS.

Начнем с создания инструмента развертывания на этапе сборки в Docker:

FROM golang:1.14 as builder

WORKDIR /project

# Download dependencies
COPY go.mod go.sum ./
RUN go mod download

# Build the app
COPY main.go ./
RUN CGO_ENABLED=0 go build -o iwomp-in-aws

Создав инструмент, мы можем подготовить образ Docker для нашего проекта CodeBuild.

FROM node:14-slim

# Install system packages
RUN apt-get update && \
    apt-get install -y ca-certificates && \
    rm -rf /var/lib/apt/lists/*

# Install CDK
RUN npm install -g aws-cdk

# Non-root user
RUN groupadd -g 10101 cdk && \
    useradd -m -d /project -g cdk -u 10101 cdk
USER cdk:cdk
WORKDIR /project

# Runner script
COPY --from=builder /project/iwomp-in-aws /usr/bin/iwomp-in-aws
ENTRYPOINT [ "iwomp-in-aws" ]

Последнее, что нам осталось сделать, — это создать образ Docker и отправить его в репозиторий ECR , который мы создали ранее.

Лямбда-функция

Далее давайте посмотрим на функцию Lambda, которая используется для запуска развертывателя.

Мы создадим обработчик JavaScript для приема событий SNS. Во-первых, мы проверим входящее событие, чтобы оно содержало достаточно информации. Он должен содержать идентификатор проекта и ветку Git, содержащую код инфраструктуры.

exports.handler = async function(event) {
    if (!event.Records[0]) {
        throw new Error('No SNS event found');
    }
    const message = parseMessage(event.Records[0].Sns.Message);
    // continued in the next code block ...
}function parseMessage(message) {
    const json = JSON.parse(message);
    if (!json.project) {
        throw new Error('No project name provided');
    }
    if (!json.branch) {
        throw new Error('No branch provided');
    }
    return json;
}

Далее мы проверим наличие проекта в белом списке, проверив, что он записан в параметрах SSM. Базовый путь для параметров SSM предоставляется через CONFIGPATHпеременную среды.

const aws = require('aws-sdk');
const ssm = new aws.SSM();exports.handler = async function(event) {
    // continued from the previous code block ...
    try {
        await validateProject(message.project);
    } catch (e) {
        throw new Error(`Invalid project ${message.project}: ${e.message}`);
    }
    // continued in the next code block ...
};async function validateProject(project) {
    const ssmPath = `/${process.env.CONFIGPATH}/${project}`
    const params = {
        Name: ssmPath,
        WithDecryption: true
    };
    const parameter = await ssm.getParameter(params).promise();
    const json = JSON.parse(parameter.Parameter.Value);
    if (!json.gitUrl) {
        throw new Error('No Git URL set');
    }
}

Наконец, мы запустим задание CodeBuild, используя сведения о событии. Lambda прочитает имя задания CodeBuild из WORKER_PROJECT_NAME переменной среды. Мы передадим в задание имя проекта и ветку Git в качестве переменных среды. Инструмент, который мы создали с помощью Go, будет читать их с помощью envconfig, как показано ранее.

const codebuild = new aws.CodeBuild();exports.handler = async function(event) {
    // continued from the previous code block ...
    await launchWorkerJob(message);
    return 'ok';
};async function launchWorkerJob(message) {
    console.log(`Triggering job for project ${message.project} on branch ${message.branch}`);
    const params = {
        projectName: process.env.WORKER_PROJECT_NAME,
        environmentVariablesOverride: [
            {
                name: 'PROJECTNAME',
                value: message.project,
            },
            {
                name: 'GITBRANCH',
                value: message.branch,
            },
        ],
    };
    const data = await codebuild.startBuild(params).promise();
    console.log(`Job started: ${data.build.id}`);
    return data;
}

Развертывание лямбда-функции

Мы можем использовать CDK для развертывания функции Lambda . Код загружается из каталога с таким именем lambda, расположенного в том же репозитории. Здесь мы передадим путь конфигурации и имя проекта CodeBuild в лямбда-код в качестве переменных среды.

import * as lambda from '@aws-cdk/aws-lambda';
const launcher = new lambda.Function(this, 'launcher', {
runtime: lambda.Runtime.NODEJS_12_X,
handler: 'index.handler',
code: lambda.Code.fromAsset(path.join(__dirname, '..', 'lambda')),
description: "iwomp-in-aws launcher",
environment: {
'CONFIGPATH': configPath,
'WORKER_PROJECT_NAME': worker.projectName,
},
});

Lambda также нуждается в доступе для запуска заданий CodeBuild и чтения параметров SSM .

const configPathArn = this.formatArn({
service: 'ssm',
resource: `parameter/${configPath}/*`
});
launcher.addToRolePolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
resources: [worker.projectArn],
actions: ['codebuild:StartBuild']
}))
launcher.addToRolePolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
resources: [configPathArn],
actions: ['ssm:GetParameter'],
}));

Нам также понадобится тема SNS для входящих событий , и она должна быть подключена к Lambda , которую мы создали ранее.

import * as sns from '@aws-cdk/aws-sns';
import * as lambdaES from '@aws-cdk/aws-lambda-event-sources';
const jobTopic = new sns.Topic(this, 'topic', {});
launcher.addEventSource(new lambdaES.SnsEventSource(jobTopic));

Запуск развертывания из стороннего CI

Теперь у нас должен быть настроен конвейер развертывания в AWS. Теперь нам просто нужно запустить его из стороннего CI. Мы можем сделать это с помощью команды публикации SNS в интерфейсе командной строки AWS.

aws sns publish \ 
  --topic-arn "$TOPIC_ARN" \ 
  --message "{\"project\": \"$PROJECT\", \"branch\": \"$BRANCH\"}"

Это опубликует событие SNS в формате JSON, содержащее два поля projectи branch. Нам нужно указать три параметра:

  • TOPIC_ARN: ARN для темы SNS, которую мы создали ранее.
  • PROJECT: идентификатор проекта. Напримерdemo
  • BRANCH: ветка Git, из которой запускается этот конвейер.

В качестве альтернативы мы можем использовать скрипт, который самостоятельно определяет тему ARN и ветку .

Выводы

В этой статье я рассмотрел решение для автоматического запуска изменений кода инфраструктуры AWS, не доверяя сторонним поставщикам CI. Я разбил проблему на четыре ограничения и разработал решение, исходя из них. Наконец, я рассмотрел код, используемый для управления решением.

Этот пост оказался немного длиннее, чем я изначально ожидал. Однако пусть это не обескураживает вас! Там довольно много кода, чтобы настроить все это, но на самом деле нет никаких компонентов, которые работают непрерывно. Вместо этого все компоненты основаны на сервисах AWS, счета за которые выставляются в зависимости от использования, что должно снизить затраты, когда конвейер не используется активно. Именно так, как мне нравится.

Конечно, в представленном мной решении есть много возможностей для расширений. Я не рассказывал о каких-либо механизмах публикации отзывов от развертывателя. Например, средство развертывания может быть расширено для отправки результатов развертывания обратно в сторонний CI, запросы на вытягивание GitHub или в Slack. Я также опустил некоторые детали, такие как аутентификация SSH для Git.

Статья является переводом medium.com

17.12.2022 0 comment
0 FacebookTwitterPinterestEmail
Бизнес в итернете

Лучшие практики Ansible: часть 2

by moiseevrus 17.12.2022
written by moiseevrus

Ansible делает простые вещи простыми, но более сложные вещи могут заставить вас почесать голову, когда вы начинаете свое путешествие с Ansible. Вот несколько советов, которые могут помочь вам избежать некоторых из этих вещей.

Ансибль

Для выбора Ansible в первую очередь в первой части этой серии блогов есть несколько рекомендаций. С этого момента я предполагаю, что вы уже используете Ansible для чего-то. Вам не обязательно знать Ansible глубоко, прежде чем переходить к тексту ниже, но полезно знать немного YAML и основы.

К счастью , в документации Ansible есть необходимая информация . Документы также содержат раздел с рекомендациями .

У нас есть довольно много земли, чтобы покрыть, так что поехали!

Начиная

Как упоминалось в первой части этого блога, вы можете установить Ansible, что означает, что вы также можете довольно хорошо контролировать версию. Однако среды Python могут получить, поэтому, если это вообще возможно, используйте и virtualenv или управляйте версиями своих инструментов другими способами.

Недавно я применил подход, при котором я пишу оболочку и файл Dockerfile, чтобы обеспечить согласованность инструментов на ноутбуках людей и CI/CD. Это работает очень хорошо. Расширение Visual Studio Code Remote Containers также удобно.

Можно также использовать менеджеры пакетов, такие как apt и yum, но тогда вы застрянете с любой версией в репозиториях дистрибутива. Попробуйте получить хотя бы версию 2.8. Версия 2.7 устарела , так как выпущена версия 2.10, и вам не хватает критических исправлений ошибок и множества новых вещей. Версии до 2.7 безнадежно устарели. Огромное количество новых вещей было представлено после того, как RedHat приобрела проект в 2015 году.

Обработка зависимостей

Храните свои плейбуки, роли, модули и плагины Ansible в системе контроля версий. Сюда входят любые сторонние роли зависимостей, которые вы подключаете с помощью ansible-galaxy . В противном случае Ansible будет использовать любые версии, найденные в roles_path . Который может быть или не быть тем, который вы указали в файле requirements.yml !

Однако это может привести к дублированию, если вы запускаете несколько проектов Ansible на одном компьютере, и они зависят от одних и тех же ролей. Действуйте осторожно, так как в этом случае ад зависимости также является реальной проблемой. Моя главная мысль здесь заключается в том, что вы должны думать о том, как вы справляетесь с зависимостями. В конце концов, это инфраструктура как код, поэтому многие вещи, о которых вам нужно думать с помощью реального кода, теперь применимы и к вашей инфраструктуре. Но вы также получаете те же преимущества!

Зависимости ролей также можно указать в файле meta/main.yml роли, но это приводит к путанице в порядке выполнения и приоритете переменных. Эти роли автоматически импортируются во время запуска playbook. Лучше сделать импорт явно с помощью import_role .

Ансибл Галактика

Инструмент зависимостей Ansible Galaxy работает аналогично pip, поэтому, если у вас есть опыт работы с ним, вы знаете некоторые болевые точки. Он извлекает указанные роли напрямую из системы контроля версий, чаще всего с GitHub. Вы действительно хотите установить эти конкретные версии для использования, так как основная ветвь может включать изменения, которые нарушают вашу инфраструктуру.

Если сопровождающий решит полностью удалить свой репозиторий, вам не повезло, если только у вас нет спрятанной где-то копии. Как упоминалось выше, в этом помогает хранение зависимостей в том же репозитории, что и код вашей инфраструктуры.

Теперь, когда коллекции Ansible набирают обороты, важность управления зависимостями и их версиями становится еще более важной, поскольку вы будете обрабатывать модули и плагины одинаковым образом.

Организация проекта

Структура каталогов проекта Ansible довольно гибкая. В основном это определяется тем, что плагин выполняет чтение переменных и инвентаризаций. Если вы только начинаете, вы, скорее всего, будете использовать значение по умолчанию, поэтому ознакомьтесь с документацией .

Обычно вы видите каталог для ролей, несколько плейбуков, инвентарь и каталоги для переменных:

├── ansible.cfg
├── group_vars
│ ├── all
│ │ └── our-vault-secrets.yml
│ └── webservers
│ └── apache-configs.yml
├── inventory.ini
├── master-playbook.yml
├── playbook.yml
├── requirements.yml
├── roles
│ ├── apache
│ │ ├── handlers
│ │ │ └── main.yml
│ │ └── tasks
│ │ ├── configure.yml
│ │ ├── install.yml
│ │ ├── main.yml
│ │ └── service.yml
│ ├── example
│ │ └── tasks
│ │ └── main.yml
│ └── yet-another
│ └── tasks
│ └── main.yml
└── webservers.yml

Поскольку в мире столько же потребностей в контенте и организации проектов, сколько организаций, использующих Ansible, я не могу дать вам набор правил, который применим ко всему. Просто постарайтесь, чтобы это было просто. В будущем вам по-прежнему нужно будет находить что-то в своей стопке плейбуков Ansible, ролей, инвентаризаций и переменных файлов, поэтому чем проще, тем лучше.

Управление запасами

В зависимости от вашей среды может быть полезно переместить инвентаризацию в отдельный каталог вместе с соответствующими файлами group_vars. Вы также можете работать с несколькими запасами , если это необходимо.

Используйте динамические запасы там, где это целесообразно. Либо среда является динамической, либо у вас уже есть система, которая управляет инвентаризацией серверов и оборудования. Однако статические инвентаризации в формате INI или YAML вполне подходят. INI немного проще для чтения, но не так хорошо работает с переменными , как YAML . Но вы в любом случае должны держать свои переменные вне статического инвентаря. Мы обсудим организацию переменных более подробно позже.

Погружение в реализацию

Начать с написания сборников игр для достижения цели — это быстрый способ начать. Но не забудьте быстро перейти к ролям. Роли обеспечивают такие преимущества, как модульность и возможность повторного использования. Роли можно тестировать изолированно. Роли также легче перемещаются между средами. Однако это немного изменилось с появлением коллекций Ansible. Роли похожи на модули Terraform, или вы можете думать о них как о классе или библиотеке.

Преимущества ролей

Они действуют как своего рода уровень абстракции и помогают вам поддерживать порядок. Если плейбук — это команда apt-get install apache2, то роль — это сам пакет .deb.

Продолжая этот аналог управления веб-сервером, представьте себе роль с именем apache, она управляет всем, что с ней связано:

  • настройка репозитория
  • установка
  • создание конфигурационного файла
  • запуск службы
  • перезапуск во время изменений

Фактическое использование осуществляется через playbook под названием webservers.yml, который импортирует apacheроль для обработки вышеперечисленных вещей.

Нам нужен HTTPS, поэтому давайте сделаем это, используя роль, вызываемую letsencryptдля получения сертификата для использования Apache. Правилами брандмауэра можно управлять с помощью роли iptables, которая позволяет пропускать трафик HTTP и HTTPS на веб-сервер.

Теперь у нас есть три роли, которые объединены в один плейбук для управления нашими веб-серверами. Роли напрямую не зависят друг от друга, поэтому iptablesвполне могут использоваться для открытия портов для SQL-серверов, а letsencryptтакже для получения сертификатов для HAProxy.

Многоразовое использование для победы!

При использовании ролей из плейбуков используйте import_roleили include_roleзадачу, а не более старое rolesключевое слово. Последнее затруднит обработку порядка выполнения ролей с другими задачами, set_factкоторые у вас, вероятно, будут, несмотря на то, что вы уже реализовали все в ролях. Вы также захотите, чтобы роли были слабо связаны и ограничивали зависимости от одной роли к другой. Плейбуки можно использовать, чтобы совмещать множество ролей для достижения целого.

Роль должна быть как можно более простой и концентрироваться на чем-то одном. Для универсальной роли, подобной приведенной выше apache, следует следовать соглашению, а не настройке . Вы не хотите раскрывать каждую ручку конфигурации Apache пользователям вашей роли.

Особенно при разработке собственного решения для управления парком серверов у вас, вероятно, уже есть соглашения. Просто используйте Ansible, чтобы обеспечить их соблюдение, а не создавать трудноуправляемый блок запутанных переменных. Автоматизация должна сделать вашу жизнь проще, а не сложнее. Установите разумные значения по умолчанию для роли, так как ее можно использовать без установки каких-либо переменных.

Выбор сторонних ролей

В начале у вас может возникнуть соблазн использовать множество сторонних ролей с помощью ansible-galaxy, особенно если вы управляете частью программного обеспечения, которое вы на самом деле не знаете наизусть. Но качество доступных ролей немного непостоянно. Рейтинги и количество загрузок в Ansible Galaxy дают некоторое представление, но важно копнуть немного глубже, прежде чем отказываться от роли в requirements.yml. Некоторые из опубликованных ролей могут хорошо работать для их создателей, но следовать соглашениям, которые не работают для вас.

Например, хорошо написанную роль, которая имеет только один файл задач, main.ymlтрудно изменить, если вы хотите изменить порядок задач. Для дополнительной помощи Джефф Герлинг написал пост об оценке ролей в сообществе.

Playbooks: включает, импортирует и теги

Плейбуки могут быть организованы по-разному. Они могут быть связаны с группой, например, как указано webservers.ymlвыше, или связаны с жизненным циклом, restart-apache.ymlили для конкретных ситуаций, таких как fix-heartbleed.yml.

Последний из них выполняет несколько разовых задач, которые помогут вам убедиться, что определенная версия OpenSSL развернута на всех серверах. Кто-то может возразить, что теги можно использовать для достижения того же эффекта, но я думаю, что иметь сборник сценариев для определенного случая гораздо понятнее.

Тегами становится трудно управлять, особенно если они используются в большом количестве внутри ролей. Теги в ролевых задачах в сочетании с динамическими включениями или статическим импортом приводят к затруднениям с потоками, и при использовании сторонних ролей вам нужно начать использовать включение с применением , и это просто закончится плачевно.

Создавайте явные плейбуки и роли с явными и отдельными файлами задач и сохраняйте здравомыслие на долгие годы. Группировка наборов задач внутри роли в отдельные файлы задач также повышает возможность повторного использования. Вы можете выполнять набор задач несколько раз с разными переменными.

В качестве примера, вот файл задачи из iptablesроли, используемой несколькими способами:

# roles/example-iptables/tasks/rules.yml
- name: Create iptables rules
  become: true
  iptables:
    comment: "{{ item.comment | default(omit) }}"
    action: "{{ item.action | default(omit) }}"
    rule_num: "{{ item.rule_num | default(omit) }}"
    table: "{{ item.table | default(omit) }}"
    chain: "{{ item.chain | default(omit) }}"
    source: "{{ item.source | default(omit) }}"
...
    protocol: "{{ item.protocol | default(omit) }}"
    match: "{{ item.match | default(omit) }}"
    jump: "{{ item.jump | default(omit) }}"
    policy: "{{ item.policy | default(omit) }}"
  loop: "{{ iptables_rules }}"
  notify: iptables save

По умолчанию в роли main.ymlможно было установить необходимые пакеты, очистить некоторые цепочки и установить правила, которые вы не хотите перезаписывать через файл задачи.

- hosts: all
tasks:
- name: Install iptables and configure defaults
import_role:
name: example-iptables
vars:
iptables_rules: "{{ example_default_iptables_rules }}"
---
- hosts: webservers
tasks:
- name: Create iptables rules for HTTP
include_role:
name: example-iptables
tasks_from: rules
vars:
iptables_rules:
- chain: INPUT
protocol: tcp
destination_port: 80
jump: ACCEPT
comment: Accept HTTP
- chain: INPUT
protocol: tcp
destination_port: 443
jump: ACCEPT
comment: Accept HTTPS

Все дело в переменных

Переменные по существу являются глобальными в Ansible. Есть некоторые области видимости, но в основном вы можете относиться к ним как к таковым. Переменные также являются одной из самых сложных вещей для правильного понимания. Сначала они кажутся достаточно простыми, но, глядя на довольно длинную документацию по этому вопросу , вы заметите, что в какой-то момент они могут усложниться.

Исходя из некоторого опыта, переменные проще, чем атрибуты Chef и его двухпроходная модель выполнения, так что по большей части все в порядке. 🙂

Я предлагаю использовать пространство имен для ваших переменных. Короче говоря, использование одной и той же versionпеременной как в версии пакета в apacheроли, так и в версии OpenSSL в fix-heartbleed.ymlнаборе group_varsне будет работать.

Если вы смешиваете и сопоставляете сторонние роли с вашими собственными, добавление названия компании или какого-либо другого известного префикса также поможет отличить их. example_apache_package_versionхотя и длиннее, с первого взгляда понятнее, чем apache_version. По крайней мере, используйте эту последнюю версию. Не каламбур.

Для зашифрованных переменных Ansible Vault полезно добавить префикс или суффикс, чтобы определить, откуда берется фактическое значение. Итак, если у роли есть входная переменная с именем « mysql_root_password", вы захотите зашифровать и сохранить ее как « vault_mysql_root_password".

Затем передайте это среди других связанных переменных:

mysql_package_version: "5.7.31-0ubuntu0.18.04.1" 
mysql_config_file: /etc/mysql/our-special-config.cnf 
mysql_root_password: "{{ vault_mysql_root_password }}"

Куда ставить переменные?

Существуют различные места, где вы можете указать переменную, и список приоритетов переменных довольно длинный. Старайтесь не усложнять и избегайте чрезмерного использования мест, находящихся высоко в списке приоритетов.

Другими словами, не распространяйте переменные повсюду. Их конечные значения трудно отлаживать как есть. Придерживайтесь избранных и отклоняйтесь от этих мест только в случае необходимости.

Я обычно стараюсь придерживаться этих (в порядке возрастания приоритета):

  1. по умолчанию / в роли
  • Читать без особых задач автоматически
  • Хорошее место для документирования входных переменных роли с разумными значениями по умолчанию.

2. group_vars/

  • Обычный подозреваемый при выяснении значения переменной в любой заданной среде и группе серверов.
  • Использование host_vars/ только в случае крайней необходимости

3. vars:поставить задачу

  • В основном для динамических включений, при многократном вызове одной и той же include_task/include_role с разными входными данными.
  • Также полезно для ясности в templateмодуле, чтобы передать некоторые измененные переменные в файл шаблона, сохраняя при этом большую часть логики за пределами шаблона.

4.set_fact:

  • Для более динамичных вещей/определений переменных, собранных во время выполнения
  • Например, для json_queryнекоторой переменной среды, которая находится в «неправильном» формате.

Написание задач

Задачи не должны оставаться без названия. В основном это связано с тем, как работает вывод Ansible по умолчанию. Во время бега ansible-playbookвы будете читать многие из этих строк, так что хорошо, что они рассказывают, что делают. Есть некоторые исключения: include_role, include_tasksи их эквиваленты импорта обычно достаточно ясны как в реализации, так и в выводе.

Рассмотрим эту пьесу:

- hosts: webservers
tasks:
- package:
name: apache2

Читая реализацию задачи, вы можете сделать естественный вывод, о чем она, даже без названия задачи, но ее вывод совершенно не ясен:

TASK [package] *****************************************************************
changed: [example]

Глядя на это, вы бы не поняли, каким пакетом управляли, не включив чрезмерное количество отладки.

Сравните это с этим:

- hosts: webservers
tasks:
- name: Install Apache
package:
name: apache2

И вывод:

TASK [Install Apache] **********************************************************
changed: [example]

Сделаем еще один шаг и разделим вышеуказанные задачи на роль с некоторыми изменяемыми переменными:

roles/apache/
├── defaults
│ └── main.yml
└── tasks
├── install.yml
└── main.yml

Файл задачи:

# roles/apache/tasks/install.yml
- name: install | Ensure package state
package:
name: "{{ example_apache_package_name }}"
state: "{{ example_apache_package_state }}"

И вывод:

TASK [include_role : apache] ***************************************************TASK [apache : install | Ensure package state] *********************************
changed: [example]

Теперь в приведенном выше вы видите роль, реализующую задачу. Добавляя короткий префикс, вы видите имя файла задачи installи саму задачу, которая действительно обрабатывает состояние пакета.

Чего не хватает в приведенных выше примерах, так это использования become. Become — это ваш sudo-эквивалент, но работает кроссплатформенно. Он используется для указания задач, которые необходимо запускать с правами администратора. Довольно распространенная вещь, учитывая, что вы обычно устанавливаете, настраиваете и запускаете службы с помощью Ansible.

Я обычно becomeчетко устанавливаю каждую задачу, которая требует этого. Это понятнее, документирует задачи, требующие root-доступа, не заставляет пользователя использовать --becomeкомандную строку или более глобальные "become"сценарии в плейбуках.

Я признаю, что это немного утомительно, но оно того стоит, когда команда безопасности начинает спрашивать, почему все работает как root.

Вернуться к переменным

Кроме того, благодаря использованию переменных в задаче у вас внезапно появляется распределяемая роль для Apache, которая может установить правильный пакет как в системах на основе Debian, так и в системах на основе RedHat, поскольку имена их пакетов различаются. Он также может удалить пакет, указав absentсостояние пакета.

Итак, очень быстро мы перешли от одноразового сценария к роли, которая обратно совместима и может использоваться повторно!

Не забудьте указать разумные значения по умолчанию для переменных вашей роли. example_apache_package_stateбыло бы естественно, presentи вещи, специфичные для операционной системы, могли бы обрабатываться через vars/подкаталог и включать файл на основе собранного факта:

# roles/apache/tasks/variables.yml
- name: variables | Read distribution-specific vars
include_vars: "{{ ansible_distribution }}.yml"

Обратите внимание, что include_varsпользователь вашей роли не может переопределить переменную, указав ее «обычным способом», т.е. в group_vars, как include_varsприоритет. Это может привести к некоторой путанице и дополнительной сложности при обработке переменных. Для имени пакета в конкретных переменных дистрибутива, include_varsвероятно, было бы хорошо, но состояние — это то, что вы хотите, чтобы конечный пользователь роли легко контролировал.

Сами переменные обычно должны быть одномерными. Ansible поддерживает списки и словари, но могут возникнуть проблемы с глубоко вложенными переменными. Если ваша конфигурация представляет собой файл dict, и вы хотите изменить одно значение, вы должны заменить все это. Параметр конфигурации hash_behaviour также влияет на то, как dictsони обрабатываются. По умолчанию Ansible переопределяет предыдущие значения любыми предыдущими, которые он находит.

Пример в списках, когда вы group_vars/all/monitoring.ymlуказываете вещи для мониторинга:

example_monitoring_metricbeat_modules:
- module: apache
metricsets:
- status
period: 1s
hosts:
- http://127.0.0.1/
- module: mysql
metricsets:
- status
period: 2s
hosts:
- root@tcp(127.0.0.1:3306)/

Если для одного хоста или группы вам нужно заменить номер порта для MySQL, вам нужно определить весь example_monitoring_metricbeat_moduleзаново. Кроме того, часть, связанная с Apache!

Способ сделать это – использовать переменные внутри переменных. Вот так:

- module: mysql
metricsets:
- status
period: 2s
hosts:
- "root@tcp((127.0.0.1:{{ example_monitoring_mysql_port }})/”

Который будет работать до тех пор, пока вам не понадобится добавить целый модуль в список модулей для мониторинга с помощью Metricbeat.

Но выгода от one dictв этом случае будет заключаться в том, что собственная конфигурация Metricbeat — это YAML , поэтому вы можете просто поместить эту переменную в фильтр {{ example_monitoring_metricbeat_modules | to_nice_yaml }}и быть довольным.

Поэтому важно найти баланс между простотой настройки и простотой управления переменными.

Фильтры

Если вы решите использовать многомерную переменную вместо более простой, попробуйте использовать списки вместо диктов. Большинство фильтров и циклов лучше работают со списками.

Говоря о фильтрах, обязательно изучите json_query . Это очень полезно для изменения структур данных, чтобы они соответствовали входным данным различных модулей.

В качестве примера соберем всех наших SQL-клиентов из групп для iptablesроли:

- name: Set iptables rules for SQL clients
  set_fact:
    sql_client_rules: >
      {{ groups.backend | map('extract', hostvars)
         | list | json_query(get_sql_clients) }}
  vars:
    get_sql_clients: >
      [?backend_is_sql_client].{
        comment: join(' ', ['Allow SQL traffic from', inventory_hostname]),
        protocol: 'tcp'
        source: ansible_host,
        destination_port: '3306',
        jump: 'ACCEPT',
        chain: 'INPUT'
      }- include_role:
    name: example-iptables
    tasks_from: rules
  vars:
    iptables_rules: "{{ sql_client_rules }}"
```

Пример немного запутан, но в основном он просто извлекает hostvarsвсе внутренние серверы, выбирает те, которые используют SQL, и получает необходимые переменные: inventory_hostname и ansible_host, а затем создает красивую строку комментария с помощью функции jmespath join () . Вы могли бы добиться того же с некоторыми другими задачами, но мне нравится его мощь в манипулировании данными.json_query

Если хост является членом многих групп, становится все труднее управлять переменными. Группы будут обрабатываться в алфавитном порядке, поэтому, если вы не хотите начинать добавлять к именам групп числа для управления порядком, вы можете использовать ansible_group_priority .

Но обычно правильным решением в таких случаях является рефакторинг переменных, чтобы вам не приходилось беспокоиться о слиянии заказов. Майкл ДеХаан, первоначальный разработчик Ansible, несколько лет назад задал соответствующий вопрос и предложил переместить список пакетов в роль и использовать игру для привязки группы к роли.

Будь проще!

Обработчики

Как указывалось ранее, в разделе ролевых игр и ролей написание явных и отдельных файлов задач упрощает повторное использование роли. Включение частей роли — мощный инструмент, и вы также можете использовать его в обработчиках. Обработчики — это то, что срабатывает, когда что-то изменилось, на основе уведомления .

Допустим, у вас есть перезапуск службы, и вы также хотите дождаться, пока эта служба появится после перезапуска.

Создайте файл задачи restart.yml, включите его в обработчик! Теперь этот файл задачи также можно использовать в плейбуке «restart-services.yml».

Вот пример:

# roles/apache/tasks/restart.yml
- name: Restart webserver
  service:
    name: httpd
    state: restarted- name: Wait for webserver to start
  wait_for:
    port: 80
    delay: 10

Входит в состав обработчика:

# roles/apache/handlers/main.yml
- name: restart apache
include_tasks: restart.yml

Модули

Всегда выбирайте модули Ansible, т.е. используйте доступные задачи, а не commandили shell. В основном это потому, что модули идемпотентны из коробки. Иногда вы не можете избежать действий, не запуская команду в отдельной оболочке, но в большинстве случаев у Ansible есть модуль для вас.

Кстати, начиная с версии 2.10 в документации ссылки на встроенные модули указаны с полным именем коллекции (FQCN) , поэтому вышеприведенный сервис в документации будет называться ansible.builtin.service.

Вы также можете довольно легко написать свои собственные модули и распространять их через коллекцию.

Кроме того, если вы привыкли проверять детали реализации в основном репозитории Ansible , проверьте организацию коллекций на GitHub.

Синтаксис и YAML

Как упоминалось в первой части этой серии блогов, YAML сложнее, чем кажется на первый взгляд. Я не собираюсь здесь концентрироваться на всех мелочах, других доступных источников более чем достаточно.

Например, в YAML есть приемы вроде якорей, чтобы не повторяться, но не делайте этого. У Ansible есть достаточно методов, чтобы помочь с этим.

По сути, пишите Ansible, а не YAML.

Ansible позволяет указывать большинство вещей в виде встроенных строк вместо передачи ключей и значений задаче. Не делай и этого! 🙂 Подсветка синтаксиса вашего редактора не будет работать, его трудно читать, а отличия от системы контроля версий становятся труднее понять.

Сконцентрируйтесь на удобочитаемости, так как плейбуки и роли станут документацией вашей инфраструктуры. Пустая строка и комментарий здесь или там очень помогают.

Помните, что строки могут иметь несколько разных обозначений в YAML. Тот, что без кавычек, так же функционален, как и тот, что с кавычками. Часто последний требуется в Ansible из-за того, что он содержит шаблоны Jinja2, обозначенные фигурными скобками. Как было сказано в первой части серии, целые числа иногда вызывают путаницу.

Вы могли заметить, что логические значения также могут быть выражены разными способами yes. а не trueв некоторых местах. Оба варианта синтаксически правильны, но для ясности следует придерживаться одного из них. И когда я говорю придерживаться одного, я имею в виду использование trueвместо yes.

Стоит отточить свои навыки создания отступов, поскольку это важно для того, чтобы Ansible понял, что вы имеете в виду. Обратите внимание на разницу между словарем, который содержит пары ключ-значение, и списком, который содержит один или несколько объектов различных типов.

Тестирование вашей инфраструктуры

Ваша инфраструктура тоже заслуживает испытаний. Мы стараемся относиться к этому как к коду. Как и в случае с любым другим кодом, вы захотите проверить его, так как удобочитаемость имеет важное значение. Такие инструменты, как ansible-lint , можно очень легко подключить к конвейеру CI.

Линтеры также улавливают такие вещи, как повторяющиеся ключи в вашем YAML. Это проблема, которую не так просто обнаружить иначе. Если вы случайно укажете параметр задачи дважды, используется только последний.

Использование ролей вместо голых плейбуков действительно помогает при тестировании функциональности. Называть эти модульные тесты немного натянуто, но Molecule был разработан для сведения роли с определенным набором входных данных, и вы можете проверить результат.

Раньше он использовал Testinfra в качестве верификатора по умолчанию, но начиная с 3.0 для этого используется Ansible. Он также использует Ansible для подготовки контейнеров для тестирования.

На первый взгляд может показаться немного излишним сначала сказать «установить пакет foo», а затем убедиться, что пакет «foo» действительно установлен. Но это позволяет легко выявлять регрессии во время разработки роли.

А в случае роли, которая поддерживает несколько операционных систем, запустить конвергенцию для нескольких систем несложно. Такое тестирование жизненно важно, если вы планируете опубликовать свою роль в Galaxy, поскольку в противном случае у вас возникнут проблемы с воспроизведением всех пользовательских сред.

Molecule очень ориентирован на тестирование ролей в изоляции, что также подталкивает вас к написанию подобных вещей. Это полезный подход, как я уже говорил много раз, но иногда вы хотите протестировать всю пьесу. Test Kitchen , созданный в мире, также можно использовать с Ansible через Provisioner . Оба позволяют создавать контейнеры и виртуальные машины для тестирования. Они имеют архитектуру плагинов, поэтому драйверы сообщества доступны, если значения по умолчанию не соответствуют вашим потребностям.

Для тестирования во время выполнения Ansible имеет встроенную задачу подтверждения . Это особенно помогает, когда входные переменные поступают из внешней системы, которой вы не обязательно доверяете. Вы также можете использовать assert в роли, чтобы убедиться, что пользователь правильно все настроил. Assert хорош, но может быстро стать слишком ограниченным. Интересным подходом было бы использование схемы JSON для реализации пользовательского модуля, который проверяет входные данные на соответствие указанной схеме.

Заключение

Фу, вот оно!

Надеюсь, вам что-то помогло. Либо при запуске, либо если вы уже столкнулись с ситуацией, когда вашим пакетом автоматизации инфраструктуры становится немного сложно управлять.

TL;DR:

  1. Используйте описательные имена и сосредоточьтесь на удобочитаемости ваших игр и ролей.
  2. Разделите свою реализацию на роли и заставьте их работать независимо с разумными значениями по умолчанию.
  3. Стремитесь к повторному использованию с помощью ролей и отдельных файлов задач.
  4. Не злоупотребляйте тегами
  5. Предпочитайте явное неявному, в импорте и использованииbecome
  6. Подумайте о том, как вы справляетесь с зависимостями
  7. Обеспечьте качество сторонней роли, прежде чем использовать ее в качестве зависимости.
  8. Разумно организуйте свои сборники игр
  9. Постарайтесь ограничить уровни приоритета в ваших переменных и сделать их простыми.
  10. Проверьте свои сценарии и роли

Статья является переводом medium.com

17.12.2022 0 comment
0 FacebookTwitterPinterestEmail
Бизнес в итернете

Краткое руководство по GraalVM

by moiseevrus 17.12.2022
written by moiseevrus

Существует три основных способа, которыми GraalVM может помочь с Java-приложениями: сделать их быстрее с помощью современного JIT-компилятора, скомпилировать их в автономные нативные исполняемые файлы с мгновенным запуском и низким потреблением памяти и улучшить их с помощью библиотек или кода. на других поддерживаемых языках.

Этот краткий справочник представляет собой краткий обзор возможностей GraalVM на одной странице, а также основные параметры и команды, иллюстрирующие его возможности.

Вы можете скачать и распечатать его. Он аккуратно помещается на бумаге формата А4, так что вы можете повесить его в офисе и использовать как напоминание о том, что может делать GraalVM и какие параметры его включают. Не забудьте взять PDF-версию для печати, чтобы она выглядела аккуратно и четко. Обратите внимание, что если ваш принтер более удобен для форматов бумаги Letter в США, обязательно установите эту версию , она будет выглядеть лучше.

В этом посте мы рассмотрим информацию в кратком справочнике и опишем ее более подробно.

Первая часть посвящена запуску Java-приложений. Прежде всего, следует помнить, что дистрибутивы GraalVM содержат JDK со всеми обычными инструментами JDK, что означает, что вы можете использовать GraalVM в качестве своего JDK. Например, компиляция исходного кода Java с помощью javacутилиты:

javac MyApp.java

Естественно, вы также можете использовать GraalVM для запуска приложений Java или любых других языков JVM. В дополнение к возможности запускать Java, GraalVM обладает мощным JIT-компилятором и обеспечивает высочайшую производительность, которая часто позволяет запускать их быстрее, чем другие JDK.

java -jar MyApp.jar

При своевременном запуске Java-приложений с помощью GraalVM базовой JVM является обычная виртуальная машина Java Hotspot ™, что означает, что большинство параметров конфигурации эквивалентны, например, указание пути к классам для вашего приложения работает следующим образом:

java -cp target/myapp.jar com.example.Main

Компилятор GraalVM обычно запускается в режиме прекомпиляции в собственную разделяемую библиотеку . Но его код написан на Java, и его можно использовать как файл JAR, что приводит к несколько иному профилю производительности: использование кучи памяти для компиляции за счет более длительного прогрева (например, Java-код компилятора должен компилировать). Следующая опция настраивает режим, в котором вы хотите работать (включен +по умолчанию):

-XX:+-UseJVMCINativeLibrary

Помимо запуска компилятора в виде JAR или собственной библиотеки, вы можете указать конфигурацию для оптимизации , выбрав economyдля более быстрого прогрева и enterpriseдля наилучшей пиковой производительности (конечно, требуется GraalVM Enterprise).

-Dgraal.CompilerConfiguration=enterprise|community|economy

Воздействие JIT-компилятора может быть значительным, ускоряя приложения довольно сильно, но иногда неясно, работает ли компилятор, действительно ли код достигает верхнего уровня и какие методы попадают в компилятор.

-Dgraal.PrintCompilation=true

В дополнение к просмотру журналов вы можете включить больше вывода отладки, например, распечатать графики компилятора, чтобы проанализировать их для поиска дополнительных возможностей оптимизации:

-Dgraal.Dump=:2

И, конечно же, другие функции JVM также работают с GraalVM. Например, вы можете подключить агент Java, который будет обрабатывать код, генерировать классы во время выполнения и выполнять другие «агентские» функции Java. Работают как агенты на основе Java, так и собственные агенты. Одним из ярких примеров может быть агент вспомогательной настройки для упрощения сборки собственного образа.

-javaagent:path/to/jar.jar

-agentlib:path/to/native/agent

Вторым важным преимуществом использования GraalVM являются его возможности Native Image : заблаговременная компиляция вашего приложения в собственный двоичный файл.

Обновление: мы опубликовали отдельный краткий справочник по native-image, пожалуйста, ознакомьтесь с ним: Краткий справочник по исходному изображению .

Для того, чтобы использовать это, вам нужно установить native-imageкомпонент. Один из способов сделать это — загрузить JAR-файл компонента для вашего дистрибутива GraalVM и выполнить следующее:

gu install -L native-image.jar

Затем вы можете использовать установленную native-imageутилиту для подготовки собственного двоичного файла вашего приложения:

native-image [options] MyClass

Кроме того, вы можете использовать синтаксис файла JAR, аналогичный javaкоманде.

native-image -jar MyApp.jar

Запустите полученный двоичный файл как любой исполняемый файл:

./myApp

Если вместо исполняемого файла вы хотите создать разделяемую библиотеку , вы можете сделать это, передав --sharedопцию. Вам необходимо пометить методы, которые будут представлены, с помощью @CEntryPointаннотации, но более подробное изучение этой темы выходит за рамки этой статьи.

--shared

Еще одна очень полезная возможность — создавать статически связанные двоичные файлы , в которых библиотеки ОС, например libc, связаны с исполняемым файлом. Можно даже выбрать, какую libcреализацию использовать. glibcиспользуется по умолчанию, muslcявляется опцией, для которой вам нужно немного подготовить среду сборки.

--static --libc=muslc

Можно включить инфраструктуру для запуска языков на основе Truffle: JavaScript, Ruby, Python, R и так далее. Это будет включать интерпретатор языка, инфраструктуру Truffle и JIT-компилятор, поэтому код можно будет скомпилировать во время выполнения для более быстрого выполнения.

Например, каждый из них будет включать поддержку соответствующего языка:

--language:js 
--language:python 
--language:llvm 
--language:ruby

--language:js

Еще одна захватывающая возможность — оптимизация на основе профиля для исполняемых файлов собственных изображений. Вы можете сгенерировать инструментированный двоичный файл, применить к нему соответствующие рабочие нагрузки, записать профиль исполняемого кода аналогично тому, что делает JIT, и использовать эти профили для создания производственного двоичного файла.

native-image — pgo-instrument MyApp
./myApp
native-image — pgo profile.iprof MyApp

И, если вы хотите иметь больше информации о том, что происходит во время процесса сборки собственного образа, например, пытаясь понять цепочку классов, через которую класс был инициализирован, вы можете использовать набор полезных параметров.

Отслеживание пути инициализации к определенному классу включается следующим:

-H:+TraceClassInitialization=package.class.Name

Сборка собственного образа — это процесс Java, поэтому вы можете поместить точку останова в код и подключить к нему отладчик, чтобы иметь полное представление о том, что происходит.

--debug-attach=[port]

В дополнение к этому существует множество других полезных параметров для настройки сборки собственного образа и поведения во время выполнения, которые мы рассмотрим в будущем, но вы можете получить общее представление о том, что доступно, используя опцию справки эксперта:

--expert-options-all

Третье важное преимущество, которое дает вам GraalVM, — это многоязычная среда выполнения , способная работать на нескольких языках и включающая платформу Node.js, работающую на движке GraalVM для JavaScript. Итак, если у вас есть приложение узла, вы можете запустить его, вызвав nodeкоманду.

node myApp.js

Кроме того, существует ряд средств запуска языков, которые вы можете использовать для запуска программ на поддерживаемых языках:

js myApp.js 
graalpython myApp.py 
ruby ​​myApp.rb 
R myApp.r 
lli myApp

Средства запуска, в том числе node, по умолчанию запускаются в собственном режиме, где интерпретатор скомпилирован как собственный двоичный образ. Итак, чтобы включить взаимодействие с JVM для использования классов Java, используйте --jvmопцию и для других языков --polyglot:

--polyglot --jvm

Языковые движки имеют ряд функций для ограничения количества ресурсов , таких как, например, количество времени в миллисекундах, в течение которого контекст языка может выполняться:

--sandbox.MaxCPUTime=Nms

И последнее, но не менее важное: языки GraalVM имеют встроенную поддержку общих инструментов разработчика. Это одна из самых интересных частей всей экосистемы GraalVM — внедрите языковой интерпретатор, фиксирующий семантику языка, и получите мощную виртуальную машину, набор алгоритмов GC, отладчик, профилировщик, анализатор памяти и другие инструменты. бесплатно.

Укажите следующие параметры, чтобы включить соответственно отладчик на основе отладчика Chrome DevTools, профилировщик выборки, профилировщик трассировки и анализатор памяти:

--inspect 
--cpusampler 
--cputracer 
--memsampler

Заключение

GraalVM — универсальный проект, предлагающий множество интересных возможностей, которые вы можете использовать для своих приложений, будь то Java, языки JVM, JavaScript, Ruby, Python, R и другие.

От использования лучшего своевременного компилятора до создания собственных исполняемых файлов ваших приложений и запуска компонентов на разных языках — вы можете использовать GraalVM уже сегодня.

В этом кратком справочнике мы попытались описать наиболее часто используемые параметры, описывающие различные возможности GraalVM.

Скачайте , распечатайте и прикрепите на стену. Надеюсь, он будет напоминать вам о том, насколько интересен проект GraalVM, даже если в настоящее время вы используете только часть того, что он может предложить.

А пока вы этим занимаетесь, получите дистрибутив GraalVM и попробуйте несколько вещей из краткого справочника, например, быстрее запускайте свои Java-приложения, сделайте микросервисы более дружественными к облаку с помощью нативных образов или улучшите свои приложения с помощью библиотек на других языках!

Статья является переводом medium.com

17.12.2022 0 comment
0 FacebookTwitterPinterestEmail
Бизнес в итернете

Как развернуть Kubernetes с помощью Kubespray

by moiseevrus 17.12.2022
written by moiseevrus

Kubernetes — это система оркестрации с открытым исходным кодом, которая автоматизирует процесс развертывания и обслуживания контейнерных приложений. Он дает вам механизм планирования и запуска контейнеров в кластерах из нескольких физических и/или виртуальных машин. Для получения дополнительной информации ознакомьтесь с официальной документацией Kubernetes .

Kubespray — это набор игр Ansible, инвентаризация, инструменты подготовки и знания предметной области для общих задач управления конфигурацией кластеров OS/Kubernetes. Он обеспечивает высокодоступный кластер, компонуемые атрибуты и поддержку самых популярных дистрибутивов Linux. Он стал де-факто готовым к работе установщиком Kubernetes, которому доверяют в облачном сообществе (10 тысяч звезд на GitHub).

В этом руководстве мы покажем шаги, необходимые для развертывания кластера Kubernetes в UpCloud с помощью Kubespray. В руководстве предполагается, что у вас есть базовые знания о Kubernetes и различных терминах, связанных с ним, но шаги достаточно просты для новичков.

 

Настройка предварительных условий

 

В принципе, шаги в этом руководстве можно разделить на следующие две основные процедуры, необходимые для настройки нового кластера Kubernetes.

  1. Создайте инфраструктуру
  2. Развертывание Kubernetes

Прежде чем углубляться в конкретные шаги, клонируйте Kubespray на свой компьютер, например, с помощью инструмента командной строки git. Если у вас еще не установлен git, вы можете использовать приведенную ниже команду, чтобы установить git в Ubuntu или других операционных системах на основе Debian, или проверить другие параметры ОС в руководстве по установке git .

sudo apt install git-all

Затем загрузите пакет Kubespray и перейдите в новый каталог.

git клон
git clone

https://github.com/kubernetes-sigs/kubespray.git

cd kubespray

Вам также потребуется установить Ansible и другие зависимости. К счастью, Kubespray предоставляет удобный список требований, которые можно использовать для установки всех необходимых компонентов с помощью одной команды. Однако, чтобы это работало, вам сначала понадобится установщик пакетов Python, pip.

sudo apt install python3-pip
sudo pip3 install -r requirements.txt

Если вы столкнулись с какой-либо проблемой при установке необходимых компонентов, проверьте официальный репозиторий Kubespray , чтобы узнать, как устранить неполадки.

 

Установка Терраформ

 

Terraform — это инструмент подготовки инфраструктуры. Он используется для безопасного и эффективного создания, изменения и управления версиями инфраструктуры. Установив Terraform CLI на свой компьютер, вы получите все инструменты, необходимые для управления вашей облачной инфраструктурой.

Чтобы установить Terraform, найдите подходящий для вашей системы пакет , скачайте и установите его.

Например, чтобы установить Terraform в большинстве систем Linux, сначала загрузите последнюю версию.

wget https://releases.hashicorp.com/terraform/0.14.7/terraform_0.14.7_linux_amd64.zip

Затем извлеките двоичные файлы в подходящее место, например /usr/local/bin , и убедитесь, что они включены в переменную среды PATH. Например, с помощью приведенной ниже команды.

sudo unzip terraform_0.14.7_linux_amd64.zip -d /usr/local/bin

Вы можете убедиться, что установка работает, перечислив доступные подкоманды Terraform в терминале.

terraform -help
Usage: terraform [-version] [-help]  [args]
The available commands for execution are listed below.
The primary workflow commands are given first, followed by
less common or more advanced commands.
...

 

Настройка доступа к API

 

Чтобы Terraform могла развертывать облачные ресурсы в вашей учетной записи UpCloud, вам сначала необходимо предоставить ей доступ. Для этого выполните следующие действия.

Создайте отдельную учетную запись API в панели управления UpCloud.

Рекомендуется создать отдельного пользователя API для Terraform для взаимодействия с UpCloud API во время развертывания инфраструктуры вместо использования вашей основной учетной записи. Вы можете сделать это в панели управления UpCloud, используя учетные записи участников рабочей области. Имя и пароль вашей учетной записи API очень похожи на традиционный идентификатор API и пару ключей с дополнительным преимуществом, заключающимся в возможности свободно устанавливать их самостоятельно.

Чтобы создать новую учетную запись, выберите « Люди » в левой части панели управления UpCloud и следуйте инструкциям. Для получения дополнительной информации см. этот учебник о том, как начать работу с UpCloud API .

Разрешить API-доступ к вашей учетной записи UpCloud

После того, как вы создали свою учетную запись API, вам нужно будет разрешить ей доступ к API UpCloud, чтобы Terraform мог создать вашу инфраструктуру в UpCloud. Для этого убедитесь, что вы выбрали Разрешить подключения API в новой учетной записи и установите для него значение Все адреса , чтобы легко убедиться, что последующие шаги в этом руководстве будут работать.

Настройка разрешений на подключение API

Вы можете и по соображениям безопасности, возможно, должны ограничить это позже своим собственным IP-адресом.

Настройте учетные данные пользователя UpCloud

Наконец, вам нужно будет передать Terraform учетные данные новой учетной записи API. Используйте приведенные ниже команды, чтобы экспортировать новое имя пользователя и пароль API в качестве переменных среды в текущем сеансе оболочки. Затем имя пользователя и пароль будут доступны для Terraform CLI при создании кластера.

export TF_VAR_UPCLOUD_USERNAME=
export TF_VAR_UPCLOUD_PASSWORD=

Примечание. Приведенные выше учетные данные представлены в виде открытого текста. Желательно хранить имя пользователя и пароль в кодировке Base64 для более постоянного использования.

 

Обзор инфраструктуры

 

Кластер в Kubernetes состоит из нескольких плоскостей управления и рабочих узлов. Узлы плоскости управления — это узлы, которые контролируют и управляют набором рабочих узлов (среда выполнения рабочих нагрузок), а рабочие узлы — это узлы, на которых выполняются контейнерные приложения.

Пример настройки кластера Kubernetes может выглядеть следующим образом.

Кластер Kubernetes

Вам необходимо определить количество как плоскости управления, так и рабочих узлов для вашего кластера. В этом посте мы будем использовать один узел плоскости управления и три рабочих узла.

Чтобы создать кластер Kubernetes, вам необходимо убедиться, что в вашей системе установлен CLI Terraform, а также правильная конфигурация для вашего кластера. Terraform помогает нам определить инфраструктуру как код. Определение инфраструктуры как кода дает много преимуществ, таких как простое редактирование, просмотр и управление версиями, а также легкое совместное использование членами команды.

 

Настройка кластера

 

Далее мы настроим конфигурацию для нашего кластера. Чтобы не изменять файлы шаблона, давайте скопируем необходимые файлы в новый каталог и внесем изменения там.

Создайте каталог с именем my-upcloud-cluster следующим образом. Переменная CLUSTER здесь является сокращением имени нашего каталога. Если вы хотите назвать свой каталог по-другому, просто измените следующую строку, и остальная часть конфигурации будет работать так же.

CLUSTER=my-upcloud-cluster
mkdir inventory/$CLUSTER

Скопируйте образец инвентаризации и конфигурацию кластера по умолчанию в новый каталог.

cp -r inventory/sample inventory/$CLUSTER
cp -r contrib/terraform/upcloud/* inventory/$CLUSTER/

Измените рабочий каталог на новый каталог конфигурации и отредактируйте файл cluster-settings.tfvars в соответствии с вашими требованиями.

cd inventory/$CLUSTER
vim cluster-settings.tfvars

Ниже приведены основные переменные Terraform, которые вы можете изменить в файле cluster-settings.tfvars   .

  • hostname : допустимое доменное имя, например, example.com. Максимальная длина составляет 128 символов.
  • template_name : имя или UUID базового образа.
  • имя пользователя : пользователь для доступа к узлам, например, через SSH. Обратите внимание , что имя пользователя  kube зарезервировано kubernetes.
  • ssh_public_keys : требуется один или несколько открытых SSH-ключей, чтобы иметь возможность доступа и подготовки компьютеров после развертывания.
  • zone : Зона, в которой будет создан кластер. Проверитьдоступные зоны для справки.
  • машины : облачные серверы, которые будут подготовлены. Содержит список машин, составляющих кластер. Ключ этого объекта будет использоваться как имя машины.
    • node_type : роль этого узла ( master|worker , в Kubespray и, следовательно, в этом руководстве называется «master» из-за устаревшего именования плоскости управления — вероятно, изменится в будущем).
    • cpu : количество ядер процессора.
    • mem : Размер памяти в МБ.
    • disk_size : размер хранилища в ГБ.

Например, чтобы создать кластер с двумя узлами плоскости управления, тремя рабочими узлами и каждым узлом с 2 ядрами, 4 ГБ памяти и размером диска 250 ГБ, замените раздел компьютеров в переменных следующим фрагментом кода.

machines = {
  "master-0" : {
    "node_type" : "master",
    #number of cpu cores
    "cpu" : "2",
    #memory size in MB
    "mem" : "4096"
    # The size of the storage in GB
    "disk_size" : 250
  },
  "worker-0" : {
    "node_type" : "worker",
    #number of cpu cores
    "cpu" : "2",
    #memory size in MB
    "mem" : "4096"
    # The size of the storage in GB
    "disk_size" : 250
  },
  "worker-1" : {
    "node_type" : "worker",
    #number of cpu cores
    "cpu" : "2",
    #memory size in MB
    "mem" : "4096"
    # The size of the storage in GB
    "disk_size" : 250
  },
  "worker-2" : {
    "node_type" : "worker",
    #number of cpu cores
    "cpu" : "2",
    #memory size in MB
    "mem" : "4096"
    # The size of the storage in GB
    "disk_size" : 250
  }
}

Не забудьте заменить значение переменной ssh_public_keys вашим общедоступным SSH-ключом, так как он будет использоваться для подключения по ssh к каждой машине при установке Kubernetes с помощью Kubespray.

 

Развертывание кластера

 

Теперь, когда настройки выполнены, вы можете приступить к развертыванию своего кластера.

Инициализируйте каталог конфигурации

Команда terraform init используется для инициализации рабочего каталога, содержащего файлы конфигурации Terraform. Он загрузит и установит плагин провайдера UpCloud Terraform.

Выполните следующую команду, чтобы инициализировать Terraform.

terraform init

Проверьте свою инфраструктуру

Команда terraform plan проверяет синтаксическую правильность вашей конфигурации и создает план выполнения. Terraform выполняет обновление, если оно явно не отключено, а затем определяет, какие действия необходимы для достижения желаемого состояния, указанного в файлах конфигурации.

Выполните следующую команду, чтобы увидеть свой план выполнения:

terraform plan --var-file cluster-settings.tfvars 
-state=tfstate-$CLUSTER.tfstate

Развернуть инфраструктуру

Команда terraform apply используется для применения изменений, необходимых для достижения желаемого состояния конфигурации или предопределенного набора действий, сгенерированного планом выполнения Terraform. Он создает новую или вносит изменения в существующую инфраструктуру в соответствии с вашей конфигурацией.

Выполните следующую команду, чтобы создать свой кластер, и ответьте « да » на запрос подтверждения:

terraform apply --var-file cluster-settings.tfvars 
-state=tfstate-$CLUSTER.tfstate

Как только Terraform завершит развертывание, вы можете проверить ресурсы своего кластера в панели управления UpCloud . На следующем рисунке показаны четыре сервера (одна плоскость управления и три рабочих узла), созданные Terraform.

Кластер Kubernetes в панели управления UpCloud

Вы также должны получить файл инвентаря с именем inventory.ini , который вы можете использовать с Kubespray. Мы будем использовать файл инвентаризации для настройки кластера Kubernetes позже.

ls
cluster-settings.tfvars  inventory.ini  sample
terraform.tfstate tfstate-my-upcloud-cluster.tfstate

 

Настройка Kubernetes с помощью Kubespray

 

Ansible — это инструмент с открытым исходным кодом для предоставления программного обеспечения, управления конфигурацией и развертывания приложений, позволяющий использовать инфраструктуру как код.

Настроить Ansible

Установите переменные среды ANSIBLE_CONFIG в файл конфигурации Kubespray ansible следующим образом:

export ANSIBLE_CONFIG=../../ansible.cfg

Убедитесь, что у вас есть базовое SSH-подключение к узлам. Вы можете сделать это, выполнив следующую команду ansible.

ansible -i inventory.ini -m ping all

Вы должны увидеть что-то похожее на следующем рисунке, если все узлы доступны.

master-0.example.com | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
worker-0.example.com | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
worker-1.example.com | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
worker-2.example.com | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}

Развертывание Kubernetes

Теперь вы можете развернуть Kubernetes с помощью Kubespray, используя файл инвентаризации, созданный на этапе применения Terraform, следующим образом.

Примечание: если вы используете другого пользователя для доступа к узлам, отличному от ubuntu по умолчанию , замените ubuntu новым пользователем в файле inventory.ini .

ansible-playbook -i inventory.ini ../../cluster.yml -b -v

Затем расслабьтесь и расслабьтесь, пока Ansible и Kubespray сделают всю тяжелую работу!

После этого вы увидите обзор развертывания, как показано на снимке экрана ниже.

Развертывание Ansible завершено

 

Доступ к вашему новому кластеру Kubernetes

 

По умолчанию Kubespray настраивает хосты kube-master с доступом к kube-apiserver через порт 6443 как http://127.0.0.1:6443. Вы можете подключиться к этому с одного из мастер-узлов.

Получите IP-адрес одного из мастер-узлов и подключитесь к нему по SSH.

Например, следующий сценарий извлекает IP-адрес узла master-0 из файла инвентаризации и открывает к нему SSH-соединение, используя имя пользователя по умолчанию.

# get the  IP address of  master-0
ip=$(grep -m 1  "master-0" inventory.ini | grep -o '[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}' | head -n 1)
# ssh to master-0 node
ssh ubuntu@$ip

Как только вы войдете в один из главных узлов, вы сможете запустить любую из команд kubectl . Например, с помощью приведенной ниже команды отображается список узлов в кластере.

sudo kubectl get nodes
NAME                   STATUS   ROLES                  AGE    VERSION
master-0.example.com   Ready    control-plane,master   10m   v1.20.5
worker-0.example.com   Ready                           10m   v1.20.5
worker-1.example.com   Ready                           10m   v1.20.5
worker-2.example.com   Ready                           10m   v1.20.5

Доступ к кластеру Kubernetes с рабочей станции

Хотя в приведенном выше примере мы вошли в один из узлов кластера, также можно управлять Kubernetes прямо с вашей собственной рабочей станции. Чтобы это работало, просто скопируйте файл /etc/kubernetes/admin.conf с главного узла на свою рабочую станцию ​​и используйте его с kubectl .

Следующий скрипт делает свое дело.

# get the  IP address of  master-0
ip=$(grep -m 1  "master-0" inventory.ini | grep -o '[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}' | head -n 1)
# copy /etc/kubernetes/admin.conf file on the local system
ssh ubuntu@$ip 'sudo cat /etc/kubernetes/admin.conf' > admin.conf

Убедитесь, что вы установили инструмент kubectl на свой локальный компьютер.

Если вы еще этого не сделали, следуйте инструкциям здесь . После установки инструмента вы можете взаимодействовать со своим кластером.

Чтобы получить удаленный доступ к вашему кластеру Kubernetes, вам нужно сообщить kubectl, где находится ваш файл конфигурации. Один из способов сделать это — указать переменную среды KUBECONFIG на файл kubeconfig вашего кластера, как показано ниже:

export KUBECONFIG=admin.conf

Последнее, что вам нужно сделать перед запуском любой из команд kubectl, — это заменить IP-адрес Kubernetes API в admin.conf на один из IP-адресов узла плоскости управления.

Откройте файл admin.conf в своем любимом текстовом редакторе и замените 127.0.0.1 IP-адресом, который вы получили выше.

vim admin.conf

В качестве альтернативы, если у вас уже есть IP-адрес первого главного узла, сохраните его в переменной $ip . Вы можете поменять IP-адрес 127.0.0.1 на IP-адрес, сохраненный в переменной, с помощью следующей команды.

sed -i "s/127.0.0.1/$ip/g" admin.conf

С IP-адресом главного узла, установленным в файле администратора, вы готовы начать играть со своим кластером с вашего локального компьютера!

Например, используйте следующую команду, чтобы отобразить список пространств имен в вашем кластере.

kubectl get namespace
NAME             STATUS  AGE
default          Active  12m
kube-node-lease  Active  12m
kube-public      Active  12m
kube-system      Active  12m

Поздравляем, теперь у вас есть полнофункциональный готовый к работе кластер Kubernetes!

 

Срывать

 

Когда вы закончите тестирование кластера и он вам больше не понадобится, вы можете использовать Terraform для демонтажа развернутой инфраструктуры.

Команда terraform destroy используется для уничтожения управляемой Terraform инфраструктуры. Он прерывает ресурсы, определенные в вашей конфигурации Terraform, и выполняет действия, противоположные тому, что делает terraform apply .

Вы можете снести свою инфраструктуру, используя следующую команду Terraform:

terraform destroy --var-file cluster-settings.tfvars
-state=tfstate-$CLUSTER.tfstate ../../contrib/terraform/upcloud/

После удаления вы всегда можете использовать одни и те же файлы конфигурации, чтобы настроить и изменить свой кластер и развернуть его снова с мгновенным уведомлением!

Статья является переводом upcloud.com

17.12.2022 0 comment
0 FacebookTwitterPinterestEmail
Бизнес в итернете

Памятка по безопасности Kubernetes¶

by moiseevrus 11.12.2022
written by moiseevrus

Кубернетес

Kubernetes — это механизм оркестрации контейнеров с открытым исходным кодом для автоматизации развертывания, масштабирования и управления контейнерными приложениями. Проект с открытым исходным кодом поддерживается Cloud Native Computing Foundation (CNCF).

Когда вы развертываете Kubernetes, вы получаете кластер. Кластер Kubernetes состоит из набора рабочих машин, называемых узлами, на которых выполняются контейнерные приложения. Плоскость управления управляет рабочими узлами и модулями в кластере.

Компоненты плоскости управления

Компоненты плоскости управления принимают глобальные решения о кластере, а также обнаруживают события кластера и реагируют на них. Он состоит из таких компонентов, как kube-apiserver, etcd, kube-scheduler, kube-controller-manager и cloud-controller-manager.

Составная часть Описание
kube-apiserver kube-apiserver предоставляет API Kubernetes. Сервер API — это внешний интерфейс для плоскости управления Kubernetes.
и т. д. etcd — это согласованное и высокодоступное хранилище ключей и значений, используемое Kubernetes в качестве резервного хранилища для всех данных кластера.
kube-планировщик kube-scheduler отслеживает вновь созданные поды без назначенного узла и выбирает узел для их запуска.
kube-контроллер-менеджер kube-controller-manager запускает процессы контроллера. Логически каждый контроллер — это отдельный процесс, но для упрощения все они компилируются в один бинарник и запускаются в одном процессе.
облачный контроллер-менеджер Диспетчер облачных контроллеров позволяет связать ваш кластер с API вашего облачного провайдера и отделить компоненты, которые взаимодействуют с этой облачной платформой, от компонентов, которые просто взаимодействуют с вашим кластером.

Компоненты узла

Компоненты узла запускаются на каждом узле, поддерживая работающие модули и обеспечивая среду выполнения Kubernetes. Он состоит из таких компонентов, как kubelet, kube-proxy и среды выполнения контейнера.

Составная часть Описание
кубелет kubelet — это агент, работающий на каждом узле кластера. Это гарантирует, что контейнеры работают в поде
kube-прокси kube-proxy — это сетевой прокси, который работает на каждом узле в вашем кластере и реализует часть концепции службы Kubernetes.
Время выполнения контейнера Среда выполнения контейнера — это программное обеспечение, отвечающее за запуск контейнеров.

Архитектура Кубернета

Эта памятка представляет собой отправную точку для защиты кластера Kubernetes. Он делится на следующие категории:

  • Защита хостов Kubernetes
  • Защита компонентов Kubernetes
  • Рекомендации по безопасности Kubernetes: этап сборки
  • Рекомендации по безопасности Kubernetes: этап развертывания
  • Рекомендации по безопасности Kubernetes: фаза выполнения

Защита хостов Kubernetes

Существует несколько вариантов развертывания Kubernetes: на «голом железе», локально и в общедоступном облаке (собственная сборка Kubernetes на виртуальных машинах ИЛИ использование управляемой службы). Kubernetes был разработан, чтобы быть легко переносимым, и клиенты могут легко переключаться между этими установками, перенося свои рабочие нагрузки.

Вся эта потенциальная кастомизация Kubernetes означает, что его можно разработать для самых разных сценариев; однако это также его самая большая слабость, когда речь идет о безопасности. Kubernetes разработан так, чтобы его можно было настраивать, и пользователи должны включать определенные функции для защиты своего кластера. Это означает, что инженеры, ответственные за развертывание платформы Kubernetes, должны знать обо всех потенциальных векторах атак и уязвимостях, к которым может привести неправильная конфигурация.

Рекомендуется усилить защиту базовых хостов, установив последнюю версию операционной системы, укрепив операционную систему, внедрив необходимую систему управления исправлениями и конфигурацией, внедрив основные правила брандмауэра и предприняв определенные меры безопасности в зависимости от среды центра обработки данных.

Версия Kubernetes

Отследить все потенциальные векторы атак стало невозможно. Этот факт прискорбен, поскольку нет ничего более важного, чем быть в курсе потенциальных угроз. Лучшая защита — убедиться, что вы используете последнюю доступную версию Kubernetes.

Проект Kubernetes поддерживает выпускные ветки для последних трех второстепенных выпусков и выполняет резервное копирование применимых исправлений, включая исправления безопасности, для этих трех выпускных веток, в зависимости от серьезности и осуществимости. Выпуски исправлений регулярно вырезаются из этих веток, а при необходимости добавляются дополнительные срочные выпуски. Поэтому всегда рекомендуется обновлять кластер Kubernetes до последней доступной стабильной версии. Для получения дополнительной информации рекомендуется обратиться к политике перекоса версий https://kubernetes.io/docs/setup/release/version-skew-policy/ .

Существует несколько методов, таких как последовательные обновления и миграция пула узлов, которые позволяют выполнить обновление с минимальными перерывами и простоями.

Защита компонентов Kubernetes

Контролируйте сетевой доступ к конфиденциальным портам

Кластеры Kubernetes обычно прослушивают ряд четко определенных и отличительных портов, что упрощает идентификацию кластеров и их атаку. Следовательно, настоятельно рекомендуется настроить аутентификацию и авторизацию в кластере и узлах кластера.

Вот обзор портов по умолчанию, используемых в Kubernetes. Убедитесь, что ваша сеть блокирует доступ к портам, и рассмотрите возможность ограничения доступа к серверу API Kubernetes, кроме как из доверенных сетей.

Главный узел (узлы):

Протокол Диапазон портов Цель
TCP 6443- Сервер API Kubernetes
TCP 2379-2380 клиентский API сервера etcd
TCP 10250 Кубелет API
TCP 10251 kube-планировщик
TCP 10252 kube-контроллер-менеджер
TCP 10255 Kubelet API только для чтения

Рабочие узлы:

Протокол Диапазон портов Цель
TCP 10250 Кубелет API
TCP 10255 Kubelet API только для чтения
TCP 30000-32767 Услуги NodePort

Ограничьте прямой доступ к узлам Kubernetes

Вам следует ограничить доступ SSH к узлам Kubernetes, чтобы снизить риск несанкционированного доступа к ресурсу хоста. Вместо этого вы должны попросить пользователей использовать «kubectl exec», который обеспечит прямой доступ к среде контейнера без возможности доступа к хосту.

Вы можете использовать плагины авторизации Kubernetes для дальнейшего контроля доступа пользователей к ресурсам. Это позволяет определять детальные правила управления доступом для конкретных пространств имен, контейнеров и операций.

Управление доступом к Kubernetes API

Платформа Kubernetes управляется с помощью запросов API и поэтому является первой линией защиты от злоумышленников. Контроль за тем, кто имеет доступ и какие действия им разрешено выполнять, является главной задачей. Для получения дополнительной информации обратитесь к документации по адресу https://kubernetes.io/docs/reference/access-authn-authz/controlling-access/ .

Используйте безопасность транспортного уровня

Связь в кластере между службами должна осуществляться с использованием TLS, по умолчанию шифрующего весь трафик. Это, однако, часто упускают из виду, считая, что кластер безопасен и нет необходимости обеспечивать шифрование при передаче внутри кластера.

Достижения в области сетевых технологий, таких как сервисная сетка, привели к созданию таких продуктов, как LinkerD и Istio, которые могут включать TLS по умолчанию, предоставляя при этом дополнительную телеметрическую информацию о транзакциях между службами.

Kubernetes ожидает, что все соединения API в кластере по умолчанию зашифрованы с помощью TLS, и большинство методов установки позволят создавать необходимые сертификаты и распространять их среди компонентов кластера. Обратите внимание, что некоторые компоненты и методы установки могут активировать локальные порты через HTTP, и администраторам следует ознакомиться с настройками каждого компонента для выявления потенциально незащищенного трафика.

Чтобы узнать больше об использовании TLS в кластере Kubernetes, обратитесь к документации по адресу https://kubernetes.io/blog/2018/07/18/11-ways-not-to-get-hacked/#1-tls-everywhere . .

API-аутентификация

Kubernetes предоставляет ряд встроенных механизмов для аутентификации сервера API, однако они, скорее всего, подходят только для непроизводственных или небольших кластеров.

  • Аутентификация со статическим файлом токена использует маркеры открытого текста, хранящиеся в CSV-файле на узлах сервера API. Изменение учетных данных в этом файле требует перезапуска сервера API.
  • Клиентские сертификаты X509 также доступны, однако они не подходят для производственного использования, поскольку Kubernetes не поддерживает отзыв сертификатов , что означает, что учетные данные пользователя не могут быть изменены или отозваны без смены ключа корневого центра сертификации и повторной выдачи всех сертификатов кластера.
  • Токены учетных записей служб также доступны для аутентификации. Их основное предназначение — разрешить рабочим нагрузкам, работающим в кластере, проходить аутентификацию на сервере API, однако их также можно использовать для аутентификации пользователей.

Рекомендуемый подход для больших или производственных кластеров заключается в использовании внешнего метода аутентификации:

  • OpenID Connect Connect (OIDC) позволяет внедрить аутентификацию, использовать недолговечные токены и использовать централизованные группы для авторизации.
  • Управляемые дистрибутивы Kubernetes, такие как GKE, EKS и AKS, поддерживают аутентификацию с использованием учетных данных от соответствующих поставщиков IAM.
  • Kubernetes Impersonation можно использовать как с управляемыми облачными кластерами, так и с локальными кластерами для внешней аутентификации без необходимости доступа к параметрам конфигурации сервера API.

Помимо выбора подходящей системы аутентификации, доступ к API следует считать привилегированным и использовать многофакторную аутентификацию (MFA) для всех пользователей.

Для получения дополнительной информации обратитесь к справочному документу по аутентификации Kubernetes по адресу https://kubernetes.io/docs/reference/access-authn-authz/authentication .

Авторизация API — реализация управления доступом на основе ролей¶

В Kubernetes вы должны пройти аутентификацию (войти в систему), прежде чем ваш запрос будет авторизован (предоставлено разрешение на доступ). Kubernetes ожидает атрибуты, общие для запросов REST API. Это означает, что авторизация Kubernetes работает с существующими системами управления доступом на уровне организации или облачного провайдера, которые могут обрабатывать другие API, помимо API Kubernetes.

Kubernetes авторизует запросы API с помощью сервера API. Он оценивает все атрибуты запроса по всем политикам и разрешает или отклоняет запрос. Для продолжения все части запроса API должны быть разрешены какой-либо политикой. Это означает, что разрешения запрещены по умолчанию.

Управление доступом на основе ролей (RBAC) — это метод регулирования доступа к компьютерным или сетевым ресурсам на основе ролей отдельных пользователей в вашей организации.

Kubernetes поставляет интегрированный компонент управления доступом на основе ролей (RBAC), который сопоставляет входящего пользователя или группу с набором разрешений, связанных с ролями. Эти разрешения объединяют глаголы (получить, создать, удалить) с ресурсами (модулями, службами, узлами) и могут быть ограничены пространством имен или кластером. Предоставляется набор готовых ролей, которые предлагают разумное разделение ответственности по умолчанию в зависимости от того, какие действия клиент может захотеть выполнить. Рекомендуется использовать авторизаторы Node и RBAC вместе в сочетании с подключаемым модулем допуска NodeRestriction.

Авторизация RBAC использует группу API rbac.authorization.k8s.io для принятия решений об авторизации, что позволяет динамически настраивать политики через API Kubernetes. Чтобы включить RBAC, запустите сервер API с флагом –authorization-mode, установленным в список, разделенный запятыми, который включает RBAC; Например:

kube-apiserver --authorization-mode=Example,RBAC --other-options --more-options

Подробные примеры использования RBAC см. в документации Kubernetes по адресу https://kubernetes.io/docs/reference/access-authn-authz/rbac .

Ограничить доступ к etcd

etcd — критически важный компонент Kubernetes, хранящий информацию о состоянии и секретах, и его следует защищать иначе, чем остальную часть вашего кластера. Доступ на запись к etcd сервера API эквивалентен получению root прав на весь кластер, и даже доступ на чтение можно использовать для довольно легкого повышения привилегий.

Планировщик Kubernetes будет искать в etcd определения pod, у которых нет узла. Затем он отправляет найденные модули в доступный kubelet для планирования. Проверка отправленных модулей выполняется сервером API до того, как он запишет их в etcd, поэтому злоумышленники, записывающие напрямую в etcd, могут обойти многие механизмы безопасности, например PodSecurityPolicies.

Администраторы всегда должны использовать надежные учетные данные от серверов API к своему серверу etcd, такие как взаимная аутентификация через клиентские сертификаты TLS, и часто рекомендуется изолировать серверы etcd за брандмауэром, к которому могут получить доступ только серверы API.

Осторожность

Предоставление другим компонентам в кластере доступа к главному экземпляру etcd с доступом для чтения или записи к полному пространству ключей эквивалентно предоставлению доступа администратора кластера. Настоятельно рекомендуется использовать отдельные экземпляры etcd для компонентов, не являющихся главными, или использовать списки управления доступом etcd для ограничения доступа на чтение и запись к подмножеству пространства ключей.

Управление доступом к Kubelet

Kubelets предоставляет конечные точки HTTPS, которые предоставляют мощный контроль над узлом и контейнерами. По умолчанию Kubelets разрешают неавторизованный доступ к этому API. Рабочие кластеры должны поддерживать аутентификацию и авторизацию Kubelet.

Для получения дополнительной информации см. документацию по аутентификации/авторизации Kubelet по адресу https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-authentication-authorization .

Защита панели управления Kubernetes

Панель инструментов Kubernetes — это веб-приложение для управления вашим кластером. Он не является частью самого кластера Kubernetes, его должны установить владельцы кластера. Таким образом, существует множество руководств о том, как это сделать. К сожалению, большинство из них создают учетную запись службы с очень высокими привилегиями. Это привело к тому, что Tesla и некоторые другие компании были взломаны с помощью такой плохо настроенной приборной панели K8s. (Ссылка: облачные ресурсы Tesla взломаны для запуска вредоносных программ для майнинга криптовалюты — https://arstechnica.com/information-technology/2018/02/tesla-cloud-resources-are-hacked-to-run-cryptocurrency-mining-malware / )

Чтобы предотвратить атаки через личный кабинет, следует придерживаться нескольких советов:

  • Не раскрывайте панель инструментов без дополнительной аутентификации для общественности. Нет необходимости получать доступ к такому мощному инструменту из-за пределов вашей локальной сети.
  • Включите RBAC, чтобы вы могли ограничить учетную запись службы, которую использует панель мониторинга.
  • Не предоставляйте сервисной учетной записи панели мониторинга высокие привилегии
  • Предоставьте разрешения каждому пользователю, чтобы каждый пользователь мог видеть только то, что он должен видеть.
  • Если вы используете сетевые политики, вы можете блокировать запросы к дашборду даже от внутренних подов (это не повлияет на туннель прокси через kubectl proxy)
  • До версии 1.8 на приборной панели была учетная запись службы с полными привилегиями, поэтому проверьте, не осталось ли привязки роли для cluster-admin.
  • Разверните панель управления с помощью обратного прокси-сервера с проверкой подлинности и включенной многофакторной проверкой подлинности. Это можно сделать либо с помощью встроенного OIDC id_tokens, либо с помощью олицетворения Kubernetes. Это позволяет вам использовать панель мониторинга с учетными данными пользователя вместо использования привилегированного файла ServiceAccount. Этот метод можно использовать как в локальных, так и в управляемых облачных кластерах.

Рекомендации по безопасности Kubernetes: этап сборки

Защита контейнеров и Kubernetes начинается на этапе сборки с защиты образов контейнеров. Две основные вещи, которые нужно сделать здесь, — это создать безопасные образы и просканировать эти образы на наличие любых известных уязвимостей.

Образ контейнера — это неизменяемый, легкий, автономный исполняемый пакет программного обеспечения, который включает в себя все необходимое для запуска приложения: код, среду выполнения, системные инструменты, системные библиотеки и настройки [ https://www.docker.com/resources/what- контейнер ]. Образ использует ядро ​​операционной системы, присутствующее на хост-компьютере.

Образы контейнеров должны создаваться с использованием утвержденного и безопасного базового образа, который регулярно сканируется и контролируется, чтобы гарантировать, что в кластере можно использовать только безопасные и аутентичные образы. Рекомендуется настроить строгие политики управления в отношении того, как образы создаются и хранятся в доверенных реестрах образов.

Убедитесь, что в вашей среде используются только авторизованные образы

Без процесса, который гарантирует, что разрешен запуск только образов, соответствующих политике организации, организация подвержена риску запуска уязвимых или даже вредоносных контейнеров. Загрузка и запуск изображений из неизвестных источников опасны. Это эквивалентно запуску программного обеспечения от неизвестного поставщика на производственном сервере. Не делай этого.

Реестр контейнеров и использование сканера изображений для выявления известных уязвимостей

Реестр контейнеров — это центральный репозиторий образов контейнеров. В зависимости от потребностей мы можем использовать общедоступные репозитории или частный репозиторий в качестве реестра контейнеров. Используйте частные реестры для хранения утвержденных изображений — убедитесь, что вы отправляете только утвержденные изображения в эти реестры. Уже одно это уменьшает количество потенциальных изображений, попадающих в ваш конвейер, до доли сотен тысяч общедоступных изображений.

Создайте конвейер непрерывной интеграции, который интегрирует оценку безопасности (например, сканирование уязвимостей), сделав его частью процесса сборки. Конвейер непрерывной интеграции должен гарантировать, что для создания образов используется только проверенный код (утвержденный для производства). После создания образа его следует проверить на наличие уязвимостей в системе безопасности, и только в случае отсутствия проблем образ будет помещен в частный реестр, из которого выполняется развертывание в рабочей среде. Сбой в оценке безопасности должен привести к сбою в конвейере, предотвращая отправку образов с плохим качеством безопасности в реестр образов.

Многие репозитории исходного кода предоставляют возможности сканирования (например, Github , GitLab ), а многие инструменты CI предлагают интеграцию со сканерами уязвимостей с открытым исходным кодом, такими как Trivy или Grype .

В Kubernetes ведется работа над плагинами авторизации изображений, которые позволят предотвратить отправку неавторизованных изображений. Для получения дополнительной информации обратитесь к PR https://github.com/kubernetes/kubernetes/pull/27129 .

Используйте минимальное количество базовых образов и избегайте добавления ненужных компонентов.

Избегайте использования образов с менеджерами пакетов ОС или оболочками, поскольку они могут содержать неизвестные уязвимости. Если вам необходимо включить пакеты ОС, удалите диспетчер пакетов на более позднем этапе. В качестве примера рассмотрите возможность использования минимальных образов, таких как образы без дистрибутива.

Ограничение того, что находится в вашем контейнере среды выполнения, только тем, что необходимо для вашего приложения, является передовой практикой, используемой Google и другими технологическими гигантами, которые используют контейнеры в производстве в течение многих лет. Это улучшает отношение сигнала к шуму сканеров (например, CVE) и снижает нагрузку по установлению происхождения до того, что вам нужно.

Образы без дистрибутива

Образы Distroless содержат меньше пакетов по сравнению с другими образами и не включают оболочку, что уменьшает поверхность атаки.

Дополнительные сведения об образах ditroless см. на странице https://github.com/GoogleContainerTools/distroless .

Скретч-изображение

Пустой образ, идеально подходящий для статически скомпилированных языков, таких как Go. Поскольку изображение пусто – поверхность атаки действительно минимальна – только ваш код!

Для получения дополнительной информации см. https://hub.docker.com/_/scratch.

Используйте последние изображения/убедитесь, что изображения обновлены

Убедитесь, что ваши образы (и любые сторонние инструменты, которые вы включаете) обновлены и используют последние версии их компонентов.

Рекомендации по безопасности Kubernetes: этап развертывания

Инфраструктура Kubernetes должна быть надежно настроена до развертывания рабочих нагрузок. С точки зрения безопасности вам в первую очередь необходимо иметь представление о том, что вы развертываете и как. Затем вы можете выявлять нарушения политики безопасности и реагировать на них. Как минимум, вам нужно знать:

  • Что развертывается — включая информацию об используемом образе, например о компонентах или уязвимостях, а также о модулях, которые будут развернуты.
  • Где он будет развернут — какие кластеры, пространства имен и узлы
  • Как он развернут — работает ли он привилегированно, с какими другими развертываниями он может взаимодействовать, применяемый контекст безопасности модуля, если таковой имеется.
  • К чему он может получить доступ, включая секреты, тома и другие компоненты инфраструктуры, такие как API хоста или оркестратора.
  • Является ли он совместимым — соответствует ли он вашим политикам и требованиям безопасности

Используйте пространства имен Kubernetes для правильной изоляции ресурсов Kubernetes.

Пространства имен дают вам возможность создавать логические разделы и обеспечивать разделение ваших ресурсов, а также ограничивать область разрешений пользователей.

Установка пространства имен для запроса

Чтобы установить пространство имен для текущего запроса, используйте флаг –namespace. Обратитесь к следующим примерам:

kubectl run nginx --image=nginx --namespace=<insert-namespace-name-here>
kubectl get pods --namespace=<insert-namespace-name-here>

Настройка предпочтения пространства имен

Вы можете навсегда сохранить пространство имен для всех последующих команд kubectl в этом контексте.

kubectl config set-context --current --namespace=<insert-namespace-name-here>

Подтвердите его с помощью следующей команды.

kubectl config view --minify | grep namespace:

Узнайте больше о пространствах имен на странице https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces .

Создание политик для управления происхождением изображений с помощью ImagePolicyWebhook.

Предотвращение использования неутвержденных изображений с контроллером доступа ImagePolicyWebhook для отклонения модулей, которые используют неутвержденные изображения, в том числе:

  • Изображения, которые не сканировались в последнее время
  • Изображения, использующие базовое изображение, которое явно не разрешено
  • Образы из незащищенных реестров Узнайте больше о веб-перехватчике по адресу https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#imagepolicywebhook .

Внедрение непрерывного сканирования уязвимостей безопасности¶

Новые уязвимости публикуются каждый день, и контейнеры могут включать устаревшие пакеты с недавно обнаруженными уязвимостями (CVE). Надежная система безопасности будет включать регулярное производственное сканирование, охватывающее собственные контейнеры (приложения, которые вы создали и ранее сканировали) и сторонние контейнеры (полученные из доверенных репозиториев и поставщиков).

Проекты с открытым исходным кодом, такие как ThreatMapper, могут помочь в выявлении и приоритизации уязвимостей.

Регулярно применяйте обновления безопасности к вашей среде

В случае обнаружения уязвимостей в запущенных контейнерах рекомендуется всегда обновлять исходный образ и повторно развертывать контейнеры.

ПРИМЕЧАНИЕ

Старайтесь избегать прямых обновлений запущенных контейнеров, так как это может нарушить связь между образом и контейнером.

Example: apt-update  

Обновление контейнеров чрезвычайно просто благодаря функции непрерывного обновления Kubernetes — это позволяет постепенно обновлять работающее приложение, обновляя его образы до последней версии.

Оценить привилегии, используемые контейнерами

Набор возможностей, привязок ролей и привилегий, предоставляемых контейнерам, может значительно повлиять на вашу угрозу безопасности. Цель здесь — придерживаться принципа наименьших привилегий и предоставлять минимальные привилегии и возможности, которые позволили бы контейнеру выполнять предназначенную ему функцию.

Политики безопасности подов — это один из способов управления атрибутами подов, связанными с безопасностью, включая уровни привилегий контейнеров. Они могут позволить оператору указать следующее:

  • Не запускайте процессы приложений от имени root.
  • Не разрешать повышение привилегий.
  • Используйте корневую файловую систему только для чтения.
  • Использовать монтирование файловой системы по умолчанию (замаскированное) /proc
  • Не используйте сеть хоста или пространство процесса — использование «hostNetwork: true» приведет к игнорированию NetworkPolicies, поскольку Pod будет использовать свою сеть хоста.
  • Отбросьте неиспользуемые и ненужные возможности Linux.
  • Используйте параметры SELinux для более точного управления процессом.
  • Дайте каждому приложению собственную учетную запись службы Kubernetes.
  • Не подключайте учетные данные служебной учетной записи в контейнер, если ему не требуется доступ к API Kubernetes.

Дополнительные сведения о политиках безопасности Pod см. в документации по адресу https://kubernetes.io/docs/concepts/policy/pod-security-policy/ .

Примените контекст безопасности к своим модулям и контейнерам

Контекст безопасности — это свойство, определенное в yaml развертывания. Он управляет параметрами безопасности, которые будут назначены поду/контейнеру/тому. Эти элементы управления могут устранить целые классы атак, которые зависят от привилегированного доступа. Например, корневые файловые системы, доступные только для чтения, могут предотвратить любую атаку, которая зависит от установки программного обеспечения или записи в файловую систему.

При разработке своих контейнеров и модулей убедитесь, что вы настроили контекст безопасности для ваших модулей, контейнеров и томов, чтобы предоставить только те привилегии, которые необходимы для функционирования ресурса. Вот некоторые из важных параметров:

Настройка контекста безопасности Описание
SecurityContext->runAsNonRoot Указывает, что контейнеры должны запускаться от имени пользователя без полномочий root.
SecurityContext->Возможности Управляет возможностями Linux, назначенными контейнеру.
SecurityContext->readOnlyRootFilesystem Определяет, сможет ли контейнер записывать в корневую файловую систему.
PodSecurityContext-> runAsNonRoot Предотвращает запуск контейнера с пользователем root в составе модуля.

Вот пример определения пода с параметрами контекста безопасности:

apiVersion: v1  
kind: Pod  
metadata:  
  name: hello-world  
spec:  
  containers:  
  # specification of the pod’s containers  
  # ...
  # ...
  # Security Context
  securityContext:  
    readOnlyRootFilesystem: true  
    runAsNonRoot: true

Для получения дополнительной информации о контексте безопасности для модулей см. документацию по адресу https://kubernetes.io/docs/tasks/configure-pod-container/security-context .

Внедрение сервисной сетки

Сервисная сетка — это уровень инфраструктуры для приложений микросервисов, который может помочь упростить управление микросервисами и развертываниями за счет быстрой, безопасной и надежной связи инфраструктурных сервисов. Сервисные сетки отлично подходят для решения операционных задач и проблем при запуске контейнеров и микросервисов, поскольку они обеспечивают единый способ защиты, подключения и мониторинга микросервисов. Сервисная сетка дает следующие преимущества:

Наблюдаемость

Service Mesh предоставляет метрики трассировки и телеметрии, которые упрощают понимание вашей системы и быстро определяют причины любых проблем.

Безопасность

Сервисная сетка предоставляет функции безопасности, направленные на защиту служб внутри вашей сети и быстрое выявление любого компрометирующего трафика, входящего в ваш кластер. Сервисная сетка упрощает управление безопасностью с помощью mTLS, управления входом и выходом и т. д.

  • mTLS и почему это важно Обеспечить безопасность микросервисов сложно. Существует множество инструментов для обеспечения безопасности микросервисов, но сервисная сетка является наиболее элегантным решением для шифрования сетевого трафика в сети. Сервисная сетка обеспечивает защиту с помощью взаимного TLS (mTLS) шифрования трафика между вашими сервисами. Сетка может автоматически шифровать и расшифровывать запросы и ответы, снимая эту нагрузку с разработчика приложения. Это также может повысить производительность за счет приоритизации повторного использования существующих постоянных подключений, уменьшая потребность в дорогостоящем создании новых. С помощью Service Mesh вы можете защитить сетевой трафик, а также обеспечить надежную аутентификацию и авторизацию на основе удостоверений для каждой микрослужбы. Мы видим в этом большую ценность для корпоративных компаний.
  • Сетка Ingress & Egress Control Service добавляет уровень безопасности, который позволяет отслеживать и устранять компрометирующий трафик, когда он входит в сетку. Istio интегрируется с Kubernetes в качестве входного контроллера и обеспечивает балансировку нагрузки для входящего трафика. Это позволяет добавить уровень безопасности по периметру с помощью правил входа. Управление выходом позволяет вам видеть и управлять внешними службами, а также контролировать, как ваши службы взаимодействуют с ними.

Оперативный контроль

Сервисная сетка позволяет специалистам по безопасности и платформе устанавливать правильные макроэлементы управления для обеспечения контроля доступа, а также позволяет разработчикам выполнять настройки, необходимые им для быстрого перемещения в рамках этих ограждений.

RBAC

Надежная система управления доступом на основе ролей (RBAC), возможно, является одним из наиболее важных требований в крупных инженерных организациях, поскольку даже самую безопасную систему могут легко обойти чрезмерно привилегированные пользователи или сотрудники. Ограничение привилегированных пользователей минимальными привилегиями, необходимыми для выполнения должностных обязанностей, обеспечение того, чтобы доступ к системам был установлен на «запретить всем» по умолчанию, и обеспечение наличия надлежащей документации с подробным описанием ролей и обязанностей — одна из наиболее важных проблем безопасности на предприятии.

Недостатки

Наряду со многими преимуществами, Service mesh также имеет ряд проблем, некоторые из которых перечислены ниже:

  • Добавленная сложность: внедрение прокси-серверов, дополнительных компонентов и других компонентов в и без того сложную среду резко увеличивает сложность разработки и эксплуатации.
  • Требуемый опыт: добавление сервисной сетки, такой как Istio, поверх оркестратора, такого как Kubernetes, часто требует от операторов быть экспертами в обеих технологиях.
  • Медлительность: сервисные сетки — это инвазивная и сложная технология, которая может значительно замедлить архитектуру.
  • Принятие платформы: инвазивность сервисных сеток вынуждает как разработчиков, так и операторов приспосабливаться к платформе с строгим самоуправлением и соответствовать ее правилам.

Внедрение Open Policy Agent (OPA) для централизованного управления политиками

OPA — это проект, запущенный в 2016 году и направленный на унификацию применения политик в различных технологиях и системах. Его можно использовать для применения политик на их платформах (например, в кластерах Kubernetes). Когда дело доходит до политик безопасности Kubernetes, RBAC и Pod, они обеспечивают детальный контроль над кластером. Но опять же, это будет применяться только к кластеру, но не за его пределами. Вот где в игру вступает Open Policy Agent (OPA). OPA был введен для создания унифицированного метода применения политики безопасности в стеке.

OPA — это универсальный инструмент для применения политик, не зависящий от домена. Его можно интегрировать с API, демоном SSH Linux, хранилищем объектов, таким как CEPH, и т. д. Разработчики OPA намеренно избегали основывать его на каком-либо другом проекте. Соответственно, запрос политики и решение не соответствуют определенному формату. То есть вы можете использовать любые действительные данные JSON в качестве атрибутов запроса, если они предоставляют необходимые данные. Точно так же решение о политике, поступающее от OPA, также может быть любым допустимым JSON-данным. Вы выбираете, что будет на входе, а что на выходе. Например, вы можете выбрать, чтобы OPA возвращал объект JSON True или False, число, строку или даже сложный объект данных. В настоящее время OPA является частью CNCF в качестве инкубационного проекта.

Наиболее распространенные варианты использования OPA:

  • Авторизация приложений

OPA позволяет сократить время выхода на рынок, предоставляя предварительно подготовленную технологию авторизации, поэтому вам не нужно разрабатывать ее с нуля. Он использует декларативный язык политики, предназначенный для написания и применения правил, таких как «Алиса может писать в этот репозиторий» или «Боб может обновлять эту учетную запись». Он поставляется с богатым набором инструментов, которые помогают разработчикам интегрировать эти политики в свои приложения и даже позволяют конечным пользователям приложения также вносить изменения в политику для своих арендаторов.

Если у вас есть собственные решения для авторизации приложений, вы можете не захотеть вырывать их для замены в OPA. По крайней мере, пока. Но если вы собираетесь декомпозировать эти монолитные приложения и перейти к микросервисам для масштабирования и повышения эффективности разработчиков, вам понадобится распределенная система авторизации, и OPA — это ответ.

  • Контроль доступа Kubernetes

Kubernetes предоставил разработчикам огромный контроль над традиционными хранилищами вычислений, сетей и хранилищ. Сегодня разработчики могут настроить сеть так, как они хотят, и настроить хранилище так, как они хотят. Администраторы и группы безопасности, отвечающие за благополучие данного контейнерного кластера, должны следить за тем, чтобы разработчики не стреляли себе (или своим соседям) в ногу.

OPA можно использовать для создания политик, которые требуют, например, чтобы все образы контейнеров были из надежных источников, которые не позволяют разработчикам запускать программное обеспечение с правами root, которые гарантируют, что хранилище всегда помечено битом шифрования, что хранилище не удаляется просто так. потому что модуль перезапускается, что ограничивает доступ в Интернет и т. д.

OPA интегрируется непосредственно в API-сервер Kubernetes, поэтому он имеет полное право отклонять любой ресурс — будь то вычислительные ресурсы, сеть, хранилище и т. д. — которые, согласно политике, не относятся к кластеру. Более того, вы можете опубликовать эти политики на более ранних этапах жизненного цикла разработки (например, в конвейере CICD или даже на ноутбуках разработчиков), чтобы разработчики могли получать обратную связь как можно раньше. Вы даже можете запускать политики вне диапазона, чтобы отслеживать результаты, чтобы администраторы могли убедиться, что изменения политики непреднамеренно не нанесут больше вреда, чем пользы.

  • Авторизация сервисной сетки

И, наконец, многие организации используют OPA для регулирования использования архитектур сервисной сетки. Таким образом, даже если вы не встраиваете OPA для реализации логики авторизации приложений (распространенный вариант использования, описанный выше), вам, вероятно, все равно нужен контроль над микросервисами API. Вы можете выполнить и добиться этого, поместив политики авторизации в сервисную сетку. Или вас может мотивировать безопасность, и вы можете внедрить политики в сервисной сетке, чтобы ограничить горизонтальное движение в архитектуре микросервисов. Другой распространенной практикой является встраивание политик в сервисную сетку, чтобы обеспечить соблюдение ваших правил соответствия, даже если требуется изменение исходного кода.

Ограничение использования ресурсов в кластере

Квота ресурсов ограничивает количество или емкость ресурсов, предоставляемых пространству имен. Это чаще всего используется для ограничения объема ЦП, памяти или постоянного диска, которые может выделять пространство имен, но также может контролировать количество модулей, служб или томов, существующих в каждом пространстве имен.

Предельные диапазоны ограничивают максимальный или минимальный размер некоторых из вышеперечисленных ресурсов, чтобы пользователи не запрашивали необоснованно высокие или низкие значения для обычно зарезервированных ресурсов, таких как память, или для предоставления ограничений по умолчанию, когда они не указаны.

Вариант запуска контейнеров без привязки к ресурсам подвергает вашу систему риску DoS или сценариям «шумного соседа». Чтобы предотвратить и свести к минимуму эти риски, вы должны определить квоты ресурсов. По умолчанию все ресурсы в кластере Kubernetes создаются с неограниченными запросами/ограничениями ЦП и памяти. Вы можете создавать политики квот ресурсов, прикрепленные к пространству имен Kubernetes, чтобы ограничить ЦП и память, которые разрешено потреблять поду.

Ниже приведен пример определения квоты ресурсов пространства имен, которая ограничивает количество модулей в пространстве имен до 4, ограничивая их запросы ЦП от 1 до 2 и запросы памяти от 1 ГБ до 2 ГБ.

вычислительные ресурсы.yaml:

apiVersion: v1  
kind: ResourceQuota  
metadata:  
  name: compute-resources  
spec:  
  hard:  
    pods: "4"  
    requests.cpu: "1"  
    requests.memory: 1Gi  
    limits.cpu: "2"  
    limits.memory: 2Gi

Назначьте квоту ресурсов пространству имен:

kubectl create -f ./compute-resources.yaml --namespace=myspace

Дополнительные сведения о настройке квот ресурсов см. в документации Kubernetes по адресу https://kubernetes.io/docs/concepts/policy/resource-quotas/ .

Используйте сетевые политики Kubernetes для управления трафиком между модулями и кластерами.

Запуск разных приложений в одном и том же кластере Kubernetes создает риск того, что одно скомпрометированное приложение атакует соседнее приложение. Сегментация сети важна для того, чтобы контейнеры могли взаимодействовать только с теми, с кем они должны работать.

По умолчанию Kubernetes позволяет каждому модулю связываться с любым другим модулем. Трафик к модулю от конечной точки внешней сети за пределами кластера разрешен, если вход от этой конечной точки разрешен к модулю. Трафик от модуля к конечной точке внешней сети за пределами кластера разрешен, если разрешен выход из модуля к этой конечной точке.

Политики сегментации сети — это ключевой элемент управления безопасностью, который может предотвратить горизонтальное перемещение между контейнерами в случае взлома злоумышленника. Одной из проблем при развертывании Kubernetes является создание сегментации сети между модулями, службами и контейнерами. Это проблема из-за «динамического» характера сетевых идентификаторов (IP) контейнеров, а также того факта, что контейнеры могут взаимодействовать как внутри одного узла, так и между узлами.

Пользователи Google Cloud Platform могут воспользоваться автоматическими правилами брандмауэра, предотвращающими взаимодействие между кластерами. Аналогичную реализацию можно развернуть локально с помощью сетевых брандмауэров или решений SDN. В этой области группа Kubernetes Network SIG ведет работу, которая значительно улучшит политики связи между модулями. Новый API сетевой политики должен учитывать необходимость создания правил брандмауэра для модулей, ограничивая доступ к сети, который может иметь контейнер.

Ниже приведен пример сетевой политики, которая контролирует сеть для «внутренних» модулей, разрешая входящий доступ к сети только из «интерфейсных» модулей:

POST /apis/net.alpha.kubernetes.io/v1alpha1/namespaces/tenant-a/networkpolicys  
{  
  "kind": "NetworkPolicy",
  "metadata": {
    "name": "pol1"
  },
  "spec": {
    "allowIncoming": {
      "from": [{
        "pods": { "segment": "frontend" }
      }],
      "toPorts": [{
        "port": 80,
        "protocol": "TCP"
      }]
    },
    "podSelector": {
      "segment": "backend"
    }
  }
}

Дополнительные сведения о настройке сетевых политик см. в документации Kubernetes по адресу https://kubernetes.io/docs/concepts/services-networking/network-policies .

Защита данных

Храни секреты как секреты

В Kubernetes секрет — это небольшой объект, который содержит конфиденциальные данные, такие как пароль или токен. Важно понимать, как хранятся и доступны конфиденциальные данные, такие как учетные данные и ключи. Даже если модуль не может получить доступ к секретам другого модуля, крайне важно хранить секрет отдельно от образа или модуля. В противном случае любой, у кого есть доступ к изображению, также будет иметь доступ к секрету. Сложные приложения, которые обрабатывают несколько процессов и имеют общий доступ, особенно уязвимы в этом отношении. Секреты лучше монтировать в тома только для чтения в ваших контейнерах, а не выставлять их как переменные среды.

Шифровать секреты в состоянии покоя

База данных etcd в целом содержит любую информацию, доступную через Kubernetes API, и может предоставить злоумышленнику значительную информацию о состоянии вашего кластера.

Всегда шифруйте свои резервные копии, используя хорошо проверенное решение для резервного копирования и шифрования, и рассмотрите возможность использования полного шифрования диска, где это возможно.

Kubernetes поддерживает шифрование в состоянии покоя — функция, представленная в версии 1.7, и бета-версия версии 1, начиная с версии 1.13. Это зашифрует секретные ресурсы в etcd, не позволяя сторонам, получившим доступ к вашим резервным копиям etcd, просматривать содержимое этих секретов. Хотя эта функция в настоящее время находится в стадии бета-тестирования, она предлагает дополнительный уровень защиты, когда резервные копии не зашифрованы или злоумышленник получает доступ для чтения к etcd.

Альтернативы секретным ресурсам Kubernetes

Вы можете рассмотреть возможность использования внешнего диспетчера секретов для хранения секретов и управления ими, а не хранить их в секретах Kubernetes. Это дает ряд преимуществ по сравнению с использованием секретов Kubernetes, в том числе возможность управлять секретами в нескольких кластерах (или облаках), а также возможность централизованного управления и ротации секретов.

Для получения дополнительной информации о секретах и ​​их альтернативах обратитесь к документации по адресу https://kubernetes.io/docs/concepts/configuration/secret/ .

Нахождение раскрытых секретов

Инструменты с открытым исходным кодом, такие как SecretScanner и ThreatMapper, могут сканировать файловые системы контейнеров на наличие конфиденциальных ресурсов, таких как токены API, пароли и ключи. Такие ресурсы будут доступны любому пользователю, имеющему доступ к незашифрованной файловой системе контейнера, будь то во время сборки, в состоянии покоя в реестре или в резервной копии или во время работы.

Проверьте секретный материал, присутствующий на контейнере, на соответствие принципу «наименьших привилегий» и оцените риск, связанный с компрометацией.

Рекомендации по безопасности Kubernetes: фаза выполнения

Фаза выполнения подвергает контейнерные приложения множеству новых проблем с безопасностью. Ваша цель здесь состоит в том, чтобы получить представление о вашей рабочей среде, а также обнаруживать угрозы и реагировать на них по мере их возникновения.

Упреждающая защита ваших контейнеров и развертываний Kubernetes на этапах сборки и развертывания может значительно снизить вероятность инцидентов безопасности во время выполнения и последующих усилий, необходимых для реагирования на них.

Во-первых, вы должны отслеживать наиболее важные для безопасности действия контейнера, в том числе:

  • Процессная активность
  • Сетевые коммуникации между контейнерными сервисами
  • Сетевые коммуникации между контейнерными службами и внешними клиентами и серверами

Наблюдение за поведением контейнера для обнаружения аномалий обычно проще в контейнерах, чем в виртуальных машинах, из-за декларативного характера контейнеров и Kubernetes. Эти атрибуты упрощают самоанализ того, что вы развернули, и ожидаемой активности.

Используйте политики безопасности Pod, чтобы предотвратить использование рискованных контейнеров/Pod.

PodSecurityPolicy — это ресурсы на уровне кластера, доступные в Kubernetes (через kubectl), которые настоятельно рекомендуется использовать. Для его использования необходимо включить контроллер допуска PodSecurityPolicy. Учитывая характер контроллеров доступа, вы должны авторизовать хотя бы одну политику, иначе в кластере не будет разрешено создание модулей.

Политики безопасности Pod охватывают несколько критических случаев использования безопасности, в том числе:

  • Предотвращение запуска контейнеров с привилегированным флагом — этот тип контейнера будет иметь большинство возможностей, доступных базовому хосту. Этот флаг также перезаписывает любые правила, которые вы установили с помощью CAP DROP или CAP ADD.
  • Предотвращение совместного использования пространства имен хоста PID/IPC, сети и портов — этот шаг обеспечивает надлежащую изоляцию между контейнерами Docker и базовым хостом.
  • Ограничение использования типов томов — например, тома каталога hostPath с возможностью записи позволяют контейнерам записывать в файловую систему таким образом, который позволяет им перемещаться по файловой системе хоста за пределами pathPrefix, поэтому необходимо использовать readOnly: true
  • Наложение ограничений на использование файловой системы хоста
  • Обеспечение только чтения для корневой файловой системы через ReadOnlyRootFilesystem
  • Предотвращение повышения привилегий до привилегий root
  • Отклонение контейнеров с привилегиями root
  • Ограничение возможностей Linux до минимума в соответствии с принципами наименьших привилегий.

Дополнительные сведения о политиках безопасности Pod см. в документации по адресу https://kubernetes.io/docs/concepts/policy/pod-security-policy/ .

Безопасность контейнера во время выполнения

Защита контейнеров во время выполнения дает группам безопасности возможность обнаруживать угрозы и аномалии и реагировать на них, пока контейнеры или рабочие нагрузки находятся в рабочем состоянии. Обычно это осуществляется путем перехвата низкоуровневых системных вызовов и поиска событий, которые могут указывать на компрометацию. Некоторые примеры событий, которые должны вызывать оповещение, включают:

  • Оболочка запускается внутри контейнера
  • Контейнер монтирует конфиденциальный путь от хоста, например /proc
  • В работающем контейнере, таком как /etc/shadow, неожиданно читается конфиденциальный файл.
  • Установлено исходящее сетевое соединение
  • Доступны инструменты с открытым исходным кодом, такие как Falco от Sysdig, чтобы помочь операторам начать работу с защитой среды выполнения контейнера, предоставляя большое количество готовых обнаружений, а также гибкость для создания настраиваемых правил.

Контейнерная песочница

Средам выполнения контейнеров обычно разрешается делать прямые вызовы к ядру хоста, после чего ядро ​​взаимодействует с оборудованием и устройствами, чтобы ответить на запрос. Cgroups и namespaces существуют, чтобы дать контейнерам определенную степень изоляции, но неподвижное ядро ​​​​представляет собой большую поверхность атаки. Часто в мультитенантных и ненадежных кластерах требуется дополнительный уровень песочницы, чтобы гарантировать отсутствие взлома контейнера и эксплойтов ядра. Ниже мы рассмотрим несколько технологий OSS, которые помогают еще больше изолировать запущенные контейнеры от ядра хоста:

  • Kata Containers: Kata Containers — это проект OSS, в котором используются урезанные виртуальные машины, чтобы свести к минимуму использование ресурсов и максимизировать производительность, чтобы в конечном итоге еще больше изолировать контейнеры.
  • gVisor: gVisor легче, чем виртуальная машина (даже урезанная). gVisor — это собственное независимое ядро, написанное на Go, которое находится между контейнером и ядром хоста. Сильная песочница. gVisor поддерживает ~70% системных вызовов Linux из контейнера, но использует ТОЛЬКО около 20 системных вызовов к ядру хоста.
  • Firecracker: сверхлегкая виртуальная машина Firecracker, работающая в пользовательском пространстве. Заблокировано политиками seccomp, cgroup и namespace, поэтому системные вызовы очень ограничены. Firecracker создан с учетом требований безопасности, но может не поддерживать все развертывания Kubernetes или среды выполнения контейнеров.

Предотвращение загрузки контейнерами нежелательных модулей ядра

Ядро Linux автоматически загружает модули ядра с диска, если это необходимо в определенных обстоятельствах, например, когда подключается часть оборудования или монтируется файловая система. Что особенно важно для Kubernetes, даже непривилегированные процессы могут вызвать загрузку определенных модулей ядра, связанных с сетевым протоколом, просто создав сокет соответствующего типа. Это может позволить злоумышленнику воспользоваться уязвимостью в модуле ядра, который, по мнению администратора, не используется.

Чтобы предотвратить автоматическую загрузку определенных модулей, вы можете удалить их с узла или добавить правила для их блокировки. В большинстве дистрибутивов Linux это можно сделать, создав такой файл, как /etc/modprobe.d/kubernetes-blacklist.conf, с таким содержимым:

# DCCP is unlikely to be needed, has had multiple serious
# vulnerabilities, and is not well-maintained.
blacklist dccp

# SCTP is not used in most Kubernetes clusters, and has also had
# vulnerabilities in the past.
blacklist sctp

Чтобы заблокировать загрузку модулей в более широком смысле, вы можете использовать модуль безопасности Linux (например, SELinux), чтобы полностью запретить разрешение module_request для контейнеров, не позволяя ядру загружать модули для контейнеров ни при каких обстоятельствах. (Поды по-прежнему смогут использовать модули, загруженные вручную, или модули, загруженные ядром от имени какого-либо более привилегированного процесса.

Сравнивайте и анализируйте различные действия во время выполнения в модулях одних и тех же развертываний.

Контейнерные приложения реплицируются для обеспечения высокой доступности, отказоустойчивости или масштабируемости. Реплики должны вести себя почти одинаково; реплики со значительными отклонениями от других требуют дальнейшего изучения. Интегрируйте свой инструмент безопасности Kubernetes с другими внешними системами (электронная почта, PagerDuty, Slack, Google Cloud Security Command Center, SIEM [информация о безопасности и управление событиями] и т. д.) и используйте метки развертывания или аннотации, чтобы предупредить команду, ответственную за данное приложение, когда обнаружена потенциальная угроза. Поставщики коммерческих средств безопасности Kubernetes должны поддерживать широкий спектр интеграций с внешними инструментами.

Мониторинг сетевого трафика для ограничения ненужного или небезопасного обмена данными

Наблюдайте за своим активным сетевым трафиком и сравнивайте этот трафик с тем, что разрешено в соответствии с вашими сетевыми политиками Kubernetes. Контейнерные приложения обычно широко используют кластерную сеть, и наблюдение за активным сетевым трафиком — хороший способ понять, как приложения взаимодействуют друг с другом, и выявить неожиданные связи.

В то же время сравнение активного трафика с разрешенным дает ценную информацию о том, что не происходит, но разрешено. С помощью этой информации вы можете еще больше ужесточить разрешенные сетевые политики, чтобы удалить лишние подключения и уменьшить поверхность атаки.

С этим могут помочь проекты с открытым исходным кодом, такие как https://github.com/kinvolk/inspektor-gadget или https://github.com/deepfence/PacketStreamer , а коммерческие решения для обеспечения безопасности обеспечивают разную степень анализа сетевого трафика контейнеров.

В случае нарушения масштабируйте подозрительные модули до нуля

Используйте встроенные элементы управления Kubernetes, чтобы сдержать успешную утечку, автоматически предписывая Kubernetes масштабировать подозрительные модули до нуля или уничтожать, а затем перезапускать экземпляры взломанных приложений.

Часто меняйте учетные данные инфраструктуры

Чем короче срок действия секрета или учетных данных, тем сложнее злоумышленнику использовать эти учетные данные. Установите короткие сроки действия сертификатов и автоматизируйте их ротацию. Используйте поставщика аутентификации, который может контролировать, как долго будут доступны выданные токены, и по возможности используйте короткие сроки действия. Если вы используете токены сервисного аккаунта во внешних интеграциях, запланируйте частую ротацию этих токенов. Например, после завершения фазы начальной загрузки маркер начальной загрузки, используемый для настройки узлов, должен быть отозван или его авторизация удалена.

Получение предупреждений об обновлениях безопасности и сообщения об уязвимостях

Присоединяйтесь к группе kubernetes-announce (< https://kubernetes.io/docs/reference/issues-security/security/ ), чтобы получать электронные письма об объявлениях о безопасности. См. страницу отчетов о безопасности ( https://kubernetes.io/docs/reference/issues-security/security ) для получения дополнительной информации о том, как сообщать об уязвимостях.

логирование

Kubernetes обеспечивает ведение журнала на основе кластера, что позволяет регистрировать активность контейнера в центральном концентраторе журналов. При создании кластера стандартные выходные данные и стандартные выходные данные ошибок каждого контейнера могут быть загружены с помощью агента Fluentd, работающего на каждом узле, либо в Google Stackdriver Logging, либо в Elasticsearch и просмотрены с помощью Kibana.

Включить ведение журнала аудита

Регистратор аудита — это бета-функция, которая записывает действия, предпринятые API, для последующего анализа в случае компрометации. Рекомендуется включить ведение журнала аудита и архивировать файл аудита на защищенном сервере.

Убедитесь, что журналы отслеживают аномальные или нежелательные вызовы API, особенно любые ошибки авторизации (эти записи журнала будут иметь статус «Запрещено»). Сбои авторизации могут означать, что злоумышленник пытается злоупотребить украденными учетными данными.

Управляемые провайдеры Kubernetes, включая GKE, предоставляют доступ к этим данным в своей облачной консоли и могут позволить вам настроить оповещения об ошибках авторизации.

ЖУРНАЛЫ АУДИТА

Журналы аудита могут быть полезны для соблюдения требований, поскольку они должны помочь вам ответить на вопросы о том, что произошло, кто что сделал и когда. Kubernetes обеспечивает гибкий аудит запросов kube-apiserver на основе политик. Это поможет вам отслеживать все действия в хронологическом порядке.

Вот пример журнала аудита:

{
  "kind":"Event",
  "apiVersion":"audit.k8s.io/v1beta1",
  "metadata":{ "creationTimestamp":"2019-08-22T12:00:00Z" },
  "level":"Metadata",
  "timestamp":"2019-08-22T12:00:00Z",
  "auditID":"23bc44ds-2452-242g-fsf2-4242fe3ggfes",
  "stage":"RequestReceived",
  "requestURI":"/api/v1/namespaces/default/persistentvolumeclaims",
  "verb":"list",
  "user": {
    "username":"user@example.org",
    "groups":[ "system:authenticated" ]
  },
  "sourceIPs":[ "172.12.56.1" ],
  "objectRef": {
    "resource":"persistentvolumeclaims",
    "namespace":"default",
    "apiVersion":"v1"
  },
  "requestReceivedTimestamp":"2019-08-22T12:00:00Z",
  "stageTimestamp":"2019-08-22T12:00:00Z"
}

Определение политик аудита

Политика аудита определяет правила о том, какие события следует регистрировать и какие данные они должны включать. Структура объекта политики аудита определяется в группе API audit.k8s.io. Когда событие обрабатывается, оно сравнивается со списком правил по порядку. Первое правило сопоставления устанавливает «уровень аудита» события.

Известны следующие уровни аудита:

  • Нет — не регистрировать события, соответствующие этому правилу.
  • Метаданные — метаданные запроса журнала (запрашивающий пользователь, отметка времени, ресурс, команда и т. д.), но не тело запроса или ответа.
  • Запрос — регистрирует метаданные события и тело запроса, но не тело ответа. Это не относится к запросам, не связанным с ресурсами.
  • RequestResponse — регистрирует метаданные событий, тела запросов и ответов. Это не относится к запросам, не связанным с ресурсами.

Вы можете передать файл с политикой в ​​kube-apiserver с помощью флага –audit-policy-file. Если флаг опущен, никакие события не регистрируются. Обратите внимание, что поле правил должно быть предоставлено в файле политики аудита. Политика без (0) правил считается незаконной.

Понимание ведения журнала

Одна из основных проблем с ведением журналов в Kubernetes — понять, какие журналы создаются и как их использовать. Давайте начнем с изучения архитектуры ведения журналов Kubernetes с высоты птичьего полета.

ВЕДЕНИЕ ЖУРНАЛА КОНТЕЙНЕРА

Первый уровень журналов, которые можно собрать из кластера Kubernetes, — это журналы, созданные вашими контейнерными приложениями.

  • Самый простой способ протоколирования контейнеров — запись в стандартный поток вывода (stdout) и стандартный поток ошибок (stderr).

Манифест выглядит следующим образом.

apiVersion: v1
kind: Pod
metadata:
name: example
spec:
containers:
  - name: example
image: busybox
args: [/bin/sh, -c, 'while true; do echo $(date); sleep 1; done']

Чтобы применить манифест, запустите:

kubectl apply -f example.yaml

Чтобы просмотреть журналы для этого контейнера, запустите:

kubectl log <container-name> command.
  • Для сохраняемых журналов контейнера общий подход заключается в записи журналов в файл журнала, а затем в использовании дополнительного контейнера. Как показано ниже в приведенной выше конфигурации модуля, контейнер sidecar будет работать в одном модуле вместе с контейнером приложения, монтируя тот же том и обрабатывая журналы отдельно.

Манифест пода выглядит следующим образом:

apiVersion: v1
kind: Pod
metadata:
  name: example
spec:
  containers:
  - name: example
    image: busybox
    args:
    - /bin/sh
    - -c
    - >
      while true;
      do
        echo "$(date)\n" >> /var/log/example.log;
        sleep 1;
      done
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  - name: sidecar
    image: busybox
    args: [/bin/sh, -c, 'tail -f /var/log/example.log']
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  volumes:
  - name: varlog
    emptyDir: {}
ВЕДЕНИЕ ЖУРНАЛА УЗЛА

Когда контейнер, работающий в Kubernetes, записывает свои журналы в потоки stdout или stderr, механизм контейнера передает их драйверу ведения журналов, настроенному в Kubernetes.

В большинстве случаев эти журналы будут находиться в каталоге /var/log/containers на вашем хосте. Docker поддерживает несколько драйверов ведения журналов, но, к сожалению, конфигурация драйверов не поддерживается через API Kubernetes.

После завершения или перезапуска контейнера kubelet сохраняет журналы на узле. Чтобы эти файлы не занимали все хранилище хоста, узел Kubernetes реализует механизм ротации журналов. При удалении контейнера с узла удаляются все контейнеры с соответствующими файлами журналов.

В зависимости от того, какую операционную систему и дополнительные службы вы используете на своем хост-компьютере, вам может потребоваться просмотреть дополнительные журналы. Например, журналы systemd можно получить с помощью следующей команды:

journalctl -u
ВЕДЕНИЕ ЖУРНАЛА КЛАСТЕРА

На уровне самого кластера Kubernetes существует длинный список компонентов кластера, которые можно регистрировать, а также дополнительные типы данных, которые можно использовать (события, журналы аудита). Вместе эти разные типы данных могут дать вам представление о том, как Kubernetes работает как система.

Некоторые из этих компонентов работают в контейнере, а некоторые — на уровне операционной системы (в большинстве случаев это служба systemd). Службы systemd записывают в журнал, а компоненты, работающие в контейнерах, записывают журналы в каталог /var/log, если механизм контейнера не настроен для потоковой передачи журналов по-другому.

События

События Kubernetes могут указывать на любые изменения состояния ресурсов и ошибки Kubernetes, такие как превышение квоты ресурсов или ожидающие выполнения модули, а также любые информационные сообщения. События Kubernetes могут указывать на любые изменения состояния ресурсов и ошибки Kubernetes, такие как превышение квоты ресурсов или ожидающие выполнения модули, а также любые информационные сообщения.

Следующая команда возвращает все события в определенном пространстве имен:

kubectl get events -n <namespace>

NAMESPACE LAST SEEN TYPE   REASON OBJECT MESSAGE
kube-system  8m22s  Normal   Scheduled            pod/metrics-server-66dbbb67db-lh865                                       Successfully assigned kube-system/metrics-server-66dbbb67db-lh865 to aks-agentpool-42213468-1
kube-system     8m14s               Normal    Pulling                   pod/metrics-server-66dbbb67db-lh865                                       Pulling image "aksrepos.azurecr.io/mirror/metrics-server-amd64:v0.2.1"
kube-system     7m58s               Normal    Pulled                    pod/metrics-server-66dbbb67db-lh865                                       Successfully pulled image "aksrepos.azurecr.io/mirror/metrics-server-amd64:v0.2.1"
kube-system     7m57s               Normal     Created                   pod/metrics-server-66dbbb67db-lh865                                       Created container metrics-server
kube-system     7m57s               Normal    Started                   pod/metrics-server-66dbbb67db-lh865                                       Started container metrics-server
kube-system     8m23s               Normal    SuccessfulCreate          replicaset/metrics-server-66dbbb67db             Created pod: metrics-server-66dbbb67db-lh865

Следующая команда покажет последние события для этого конкретного ресурса Kubernetes:

kubectl describe pod <pod-name>

Events:
  Type    Reason     Age   From                               Message
  ----    ------     ----  ----                               -------
  Normal  Scheduled  14m   default-scheduler                  Successfully assigned kube-system/coredns-7b54b5b97c-dpll7 to aks-agentpool-42213468-1
  Normal  Pulled     13m   kubelet, aks-agentpool-42213468-1  Container image "aksrepos.azurecr.io/mirror/coredns:1.3.1" already present on machine
  Normal  Created    13m   kubelet, aks-agentpool-42213468-1  Created container coredns
  Normal  Started    13m   kubelet, aks-agentpool-42213468-1  Started container coredns

Последние мысли

Внедряйте средства безопасности на ранних этапах жизненного цикла контейнера

Вы должны заранее интегрировать безопасность в жизненный цикл контейнера и обеспечить согласованность и общие цели между командами безопасности и DevOps. Безопасность может (и должна) быть фактором, позволяющим вашим разработчикам и командам DevOps уверенно создавать и развертывать приложения, готовые к масштабированию, стабильности и безопасности.

Используйте встроенные в Kubernetes элементы управления безопасностью, чтобы снизить операционный риск.

Используйте собственные элементы управления, встроенные в Kubernetes, когда они доступны, чтобы применять политики безопасности, чтобы ваши элементы управления безопасностью не конфликтовали с оркестратором. Например, вместо использования стороннего прокси-сервера или оболочки для обеспечения сегментации сети используйте сетевые политики Kubernetes для обеспечения безопасного сетевого взаимодействия.

Используйте контекст, который предоставляет Kubernetes, для определения приоритетов усилий по исправлению

В разросшихся средах Kubernetes ручная сортировка инцидентов безопасности и нарушений политик занимает много времени.

Например, развертывание, содержащее уязвимость с оценкой серьезности 7 или выше, должно быть перемещено в приоритет исправления, если это развертывание содержит привилегированные контейнеры и открыто для Интернета, но перемещено вниз, если оно находится в тестовой среде и поддерживает некритическое приложение. .

Статья является переводом cheatsheetseries.owasp.org

11.12.2022 0 comment
0 FacebookTwitterPinterestEmail
Бизнес в итернете

Как управлять инфраструктурой AWS с помощью Terraform

by moiseevrus 11.12.2022
written by moiseevrus

Что такое Терраформ?

Хашикорп Терраформ

Hashicorp Terraform — чрезвычайно полезный и гибкий инструмент для безопасного и эффективного построения, изменения и управления версиями инфраструктуры. Он основан на концепции «инфраструктура как код» — управлении всей инфраструктурой с использованием машиночитаемых файлов конфигурации, а не интерактивных команд и инструментов настройки.

Terraform — одно из предложений Hashicorp, предназначенных для автоматизации. Версия Terraform для командной строки с открытым исходным кодом доступна для всех через GitHub .

Terraform хорошо работает с широким спектром поставщиков частных облаков, таких как VMWare vSphere, а также с поставщиками общедоступных облаков, такими как Google Cloud Platform (GCP), Microsoft Azure и Amazon AWS. Полный список поддерживаемых провайдеров можно посмотреть здесь .

В этом подробном руководстве я расскажу вам, как начать управлять инфраструктурой AWS с помощью Terraform с нуля. Вот как будет выглядеть наша архитектура AWS:

Архитектура АВС

Предпосылки

Прежде чем мы сможем начать использовать Terraform для управления инфраструктурой AWS, нам необходимо настроить следующее:

IAM-пользователь

В соответствии с рекомендациями AWS создайте пользователя IAM с программным доступом и присоедините к нему следующие политики с помощью управления идентификацией и доступом (IAM) в консоли AWS:

– Администратор сети
– AmazonEC2FullAccess
– AmazonS3FullAccess

Если вы еще не создали пользователя IAM, вот полезное руководство, которым вы можете воспользоваться. В конце процесса создания пользователя IAM вам должна быть представлена ​​следующая страница с идентификатором ключа доступа и секретным ключом доступа . Пожалуйста, скопируйте эти значения и сохраните их где-нибудь (приватно), потому что мы будем использовать их позже.

Для этого урока я создал пользователя с именем terraform-user :

Пользователь IAM для Terraform

Помните: всегда держите эти учетные данные в тайне ! Не беспокойтесь обо мне, эти учетные данные больше не будут работать, как только я опубликую этот урок!

Ведро S3

Создайте корзину S3, в которой будет храниться наш файл terraform.tfstate . Файлы состояния Terraform объясняются на следующем шаге в этом руководстве.

Если вы еще не создавали корзину S3, вот полезное руководство, которое вы можете использовать. Для этого урока я создал корзину S3 под названием terraform-s3-bucket-testing :

Ведро S3 для файла состояния Terraform

Помните: пожалуйста, заблокируйте ВЕСЬ публичный доступ к корзине и ко всем объектам в корзине.

Монтаж

Теперь мы готовы установить Terraform!

Сначала откройте окно терминала и создайте рабочий каталог для нашего проекта Terraform. Обратите внимание, что в этом руководстве я использую macOS, поэтому вам могут понадобиться другие команды, соответствующие вашей рабочей станции.

mkdir ~/terraform-aws
cd ~/terraform-aws

На момент написания последняя версия командной строки Terraform — 0.12.29. Поддерживается установка Terraform на следующих платформах:

  • macOS (64-разрядная версия)
  • FreeBSD (32-разрядная, 64-разрядная и ARM)
  • Linux (32-разрядная, 64-разрядная и ARM)
  • OpenBSD (32-битная и 64-битная)
  • Солярис (64-разрядная версия)
  • Windows (32-разрядная и 64-разрядная версии)

Для этого урока я использую macOS, поэтому мне нужно загрузить соответствующий Zip-файл:

wget https://releases.hashicorp.com/terraform/0.12.29/terraform_0.12.29_darwin_amd64.zip

Кроме того, вы можете посетить страницу загрузки , где вы можете найти последние исполняемые файлы для вашей соответствующей платформы.

Затем разархивируйте исполняемый файл и покажите двоичный файл terraform .

which terraform

Переместите двоичный файл в место в вашем $PATH. Я бы предложил перенести terraform в /usr/local/bin:

mv terraform /usr/local/bin

Убедитесь, что двоичный файл terraform доступен в текущем $PATH:

which terraform

Если в выводе отображается /usr/local/bin/terraform , значит все готово! Запустите эту последнюю команду, чтобы проверить версию Terraform:

santino:terraform-aws santino$ terraform - version
Terraform v0.12.29
santino:terraform-aws santino$

Состояние терраформирования

Terraform сохраняет сопоставление реальных ресурсов поставщика (в нашем случае Amazon AWS) с нашей локальной конфигурацией. Это достигается за счет поддержки файла terraform.tfstate , который по умолчанию хранится в локальном рабочем каталоге.

Это хорошо работает, если вы один поддерживаете нашу инфраструктуру AWS с помощью Terraform. Однако при работе с группами каждый, кому необходимо выполнить terraform, также должен иметь копию файла terraform.tfstate в своем локальном рабочем каталоге.

Подход к решению этой проблемы состоит в том, чтобы зафиксировать файл terraform.tfstate в репозитории Git, чтобы каждый мог работать с одним и тем же файлом. Однако такой подход небезопасен, учитывая, что файл состояния содержит много ценной информации о вашей инфраструктуре AWS. Фактически, файлы .gitignore в официальном git-репозитории Terraform не позволяют Git управлять этим файлом:

terraform.tfstate 
terraform.tfstate.backup 
.terraform/*

Наилучший подход к этой проблеме — использовать удаленный репозиторий состояния terraform. Этого можно добиться несколькими способами, но в этом руководстве мы будем использовать корзину S3 для хранения нашего файла terraform.tfstate .

Определите поставщика и удаленное местоположение

Создайте наш первый файл .tf с помощью вашего любимого редактора, который будет содержать информацию о провайдере (AWS) и корзине S3, в которой будет храниться наше удаленное состояние.

провайдер.tf

# Define AWS as our provider
provider "aws" {
     region        = "eu-central-1"
}# Terraform remote state
terraform {
     backend "s3" {
         bucket    = "terraform-s3-bucket-testing"
         key       = "terraform-s3-bucket-testing/terraform.tfstate"
         region    = "eu-central-1"
     }
}

Следующим шагом является определение двух переменных среды, которые будут содержать идентификатор ключа доступа и секретный ключ доступа из предыдущего раздела.

export AWS_ACCESS_KEY_ID="AKIAUN57B3YGREQNABE4"
export AWS_SECRET_ACCESS_KEY="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"

После определения нашего провайдера, местоположения нашей корзины S3 и учетных данных для входа в нашу учетную запись AWS мы теперь можем инициализировать наш проект Terraform с помощью команды terraform init .

Вот пример вывода:

santino:terraform-aws santino$ terraform initInitializing the backend...Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "aws" (hashicorp/aws) 2.70.0...The following providers do not have any version constraints in configuration,
so the latest version was installed.To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.* provider.aws: version = "~> 2.70"Terraform has been successfully initialized!You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
santino:terraform-aws santino$

Управление сетью

После успешной инициализации нашего проекта Terraform теперь мы можем приступить к созданию ресурсов в нашей учетной записи AWS.

Начнем с сети. Нам нужно создать несколько сетевых объектов:

  • ВКК
  • Подсети
  • Интернет-шлюз
  • Таблица маршрутов

vpc.tf

## Demo VPC
resource "aws_vpc" "terraform-demo-vpc" {
cidr_block = "10.0.0.0/16"
instance_tenancy = "default"
enable_dns_support = "true"
enable_dns_hostnames = "true"
enable_classiclink = "false"
tags = {
Name = "terraform-demo-vpc"
}
}

подсети.tf

## Demo subnets# Web tier subnet
resource "aws_subnet" "terraform-demo-snet-web" {
     vpc_id                  = aws_vpc.terraform-demo-vpc.id
     cidr_block              = "10.0.0.0/21"
     map_public_ip_on_launch = "true"
     availability_zone       = "eu-central-1a"
     tags = {
          Name = "terraform-demo-snet-web"
     }
}# Application tier subnet
resource "aws_subnet" "terraform-demo-snet-app" {
     vpc_id                  = aws_vpc.terraform-demo-vpc.id
     cidr_block              = "10.0.8.0/21"
     map_public_ip_on_launch = "false"
     availability_zone       = "eu-central-1a"
     tags = {
          Name = "terraform-demo-snet-app"
     }
}# Database tier subnet
resource "aws_subnet" "terraform-demo-snet-db" {
     vpc_id                  = aws_vpc.terraform-demo-vpc.id
     cidr_block              = "10.0.16.0/21"
     map_public_ip_on_launch = "false"
     availability_zone       = "eu-central-1a"
     tags = {
          Name = "terraform-demo-snet-db"
     }
}

igw.tf

## Internet Gateway
resource "aws_internet_gateway" "terraform-demo-igw" {
     vpc_id = aws_vpc.terraform-demo-vpc.id
     tags = {
          Name  = "terraform-demo-igw"
     }
}

route-table.tf

## Route table
resource "aws_route_table" "terraform-demo-rtable" {
     vpc_id = aws_vpc.terraform-demo-vpc.id
     route {
          cidr_block = "0.0.0.0/0"
          gateway_id = aws_internet_gateway.terraform-demo-igw.id
     }
     tags = {
          Name = "terraform-demo-rtable"
     }
}# Route table associations
resource "aws_route_table_association" "terraform-demo-rtassoc1" {
     subnet_id      = aws_subnet.terraform-demo-snet-web.id
     route_table_id = aws_route_table.terraform-demo-rtable.id
}
resource "aws_route_table_association" "terraform-demo-rtassoc2" {
     subnet_id      = aws_subnet.terraform-demo-snet-app.id
     route_table_id = aws_route_table.terraform-demo-rtable.id
}
resource "aws_route_table_association" "terraform-demo-rtassoc3" {
     subnet_id      = aws_subnet.terraform-demo-snet-db.id
     route_table_id = aws_route_table.terraform-demo-rtable.id
}

Быстрое объяснение!

Обратите внимание, что синтаксис для определения ресурса выглядит следующим образом:

 resource "<resource type>" "<resource name>"

Затем мы можем ссылаться на этот ресурс при создании других ресурсов, используя синтаксис <тип ресурса>.<имя ресурса>.<свойство> .

Например, мы определили наш VPC как:

## Demo VPC
resource “aws_vpc” “terraform-demo-vpc” {
…

При создании подсети нам нужно связать ее с VPC, в котором она должна находиться. Таким образом, мы определяем эту связь с параметром vpc_id и идентификатором VPC:

resource “aws_subnet” “terraform-demo-snet-web” {
vpc_id = aws_vpc.terraform-demo-vpc.id
…

Применение наших изменений

Используйте команду terraform plan , чтобы просмотреть изменения, которые Terraform будет выполнять в нашей инфраструктуре AWS, прежде чем применять их.

Пример вывода:

santino:terraform-aws santino$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.------------------------------------------------------------------------An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + createTerraform will perform the following actions:# aws_internet_gateway.terraform-demo-igw will be created
  + resource "aws_internet_gateway" "terraform-demo-igw" {
      + arn      = (known after apply)
      + id       = (known after apply)
      + owner_id = (known after apply)
      + tags     = {
          + "Name" = "terraform-demo-igw"
        }
      + vpc_id   = (known after apply)
    }<CUT># aws_vpc.terraform-demo-vpc will be created
  + resource "aws_vpc" "terraform-demo-vpc" {
      + arn                              = (known after apply)
      + assign_generated_ipv6_cidr_block = false
      + cidr_block                       = "10.0.0.0/16"
      + default_network_acl_id           = (known after apply)
      + default_route_table_id           = (known after apply)
      + default_security_group_id        = (known after apply)
      + dhcp_options_id                  = (known after apply)
      + enable_classiclink               = false
      + enable_classiclink_dns_support   = (known after apply)
      + enable_dns_hostnames             = true
      + enable_dns_support               = true
      + id                               = (known after apply)
      + instance_tenancy                 = "default"
      + ipv6_association_id              = (known after apply)
      + ipv6_cidr_block                  = (known after apply)
      + main_route_table_id              = (known after apply)
      + owner_id                         = (known after apply)
      + tags                             = {
          + "Name" = "terraform-demo-vpc"
        }
    }Plan: 9 to add, 0 to change, 0 to destroy.------------------------------------------------------------------------Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.santino:terraform-aws santino$

Чтобы окончательно создать объекты в AWS, запустите команду terraform apply . Вам будет предоставлен последний шанс просмотреть изменения, и вам будет предложено, хотите ли вы продолжить. После ответа yes Terraform модифицирует AWS, чтобы отразить желаемое состояние.

Пример вывода:

santino:terraform-aws santino$ terraform applyAn execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + createTerraform will perform the following actions:# aws_internet_gateway.terraform-demo-igw will be created
  + resource "aws_internet_gateway" "terraform-demo-igw" {
      + arn      = (known after apply)
      + id       = (known after apply)
      + owner_id = (known after apply)
      + tags     = {
          + "Name" = "terraform-demo-igw"
        }
      + vpc_id   = (known after apply)
    }<CUT># aws_vpc.terraform-demo-vpc will be created
  + resource "aws_vpc" "terraform-demo-vpc" {
      + arn                              = (known after apply)
      + assign_generated_ipv6_cidr_block = false
      + cidr_block                       = "10.0.0.0/16"
      + default_network_acl_id           = (known after apply)
      + default_route_table_id           = (known after apply)
      + default_security_group_id        = (known after apply)
      + dhcp_options_id                  = (known after apply)
      + enable_classiclink               = false
      + enable_classiclink_dns_support   = (known after apply)
      + enable_dns_hostnames             = true
      + enable_dns_support               = true
      + id                               = (known after apply)
      + instance_tenancy                 = "default"
      + ipv6_association_id              = (known after apply)
      + ipv6_cidr_block                  = (known after apply)
      + main_route_table_id              = (known after apply)
      + owner_id                         = (known after apply)
      + tags                             = {
          + "Name" = "terraform-demo-vpc"
        }
    }Plan: 9 to add, 0 to change, 0 to destroy.Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.Enter a value: yesaws_vpc.terraform-demo-vpc: Creating...
aws_vpc.terraform-demo-vpc: Creation complete after 2s [id=vpc-03ae143c2a8e3284c]
aws_internet_gateway.terraform-demo-igw: Creating...
aws_subnet.terraform-demo-snet-app: Creating...
aws_subnet.terraform-demo-snet-db: Creating...
aws_subnet.terraform-demo-snet-web: Creating...
aws_subnet.terraform-demo-snet-app: Creation complete after 1s [id=subnet-0b6474b59034abcb0]
aws_subnet.terraform-demo-snet-db: Creation complete after 1s [id=subnet-0c5f28652ff57e71b]
aws_internet_gateway.terraform-demo-igw: Creation complete after 1s [id=igw-05519819650e3f727]
aws_route_table.terraform-demo-rtable: Creating...
aws_subnet.terraform-demo-snet-web: Creation complete after 2s [id=subnet-06bd93be3e1b13772]
aws_route_table.terraform-demo-rtable: Creation complete after 1s [id=rtb-08a56a903445b0c7c]
aws_route_table_association.terraform-demo-rtassoc3: Creating...
aws_route_table_association.terraform-demo-rtassoc2: Creating...
aws_route_table_association.terraform-demo-rtassoc1: Creating...
aws_route_table_association.terraform-demo-rtassoc1: Creation complete after 1s [id=rtbassoc-0d9d2fe02770cf4fd]
aws_route_table_association.terraform-demo-rtassoc2: Creation complete after 1s [id=rtbassoc-04e0a5bdcddd03f22]
aws_route_table_association.terraform-demo-rtassoc3: Creation complete after 1s [id=rtbassoc-0daec5cb8a9545d2a]Apply complete! Resources: 9 added, 0 changed, 0 destroyed.
santino:terraform-aws santino$

Теперь вы можете войти в консоль AWS, чтобы проверить созданные объекты. Вот как теперь выглядит моя панель инструментов:

Информационная панель VPC

Файл terraform.tfstate также будет создан в корзине S3, которую мы определили ранее:

Сегмент S3, содержащий файл удаленного состояния

Развертывание серверов

Теперь, когда наш VPC готов, мы можем развернуть серверы.

Группы безопасности

Во-первых, давайте определим 3 группы безопасности:

  1. Группа безопасности, которая разрешит входящий доступ к нашим веб-серверам в подсети terraform-demo-snet-web из Интернета.
  2. Группа безопасности, которая разрешит доступ к нашим серверам приложений в подсети terraform-demo-snet-app из подсети terraform-demo-snet-web .
  3. Группа безопасности, которая разрешит доступ к нашим серверам баз данных в подсети terraform-demo-snet-db из подсети terraform-demo-snet-app .

secgroups.tf

## Security groups# Web tier security group
resource "aws_security_group" "terraform-demo-secgrp-webpub" {
        vpc_id              = aws_vpc.terraform-demo-vpc.id
        name                = "terraform-demo-secgrp-webpub"
        description         = "Allow web traffic from the internet"
        ingress {
                from_port       = 80
                to_port         = 80
                protocol        = "tcp"
                cidr_blocks     = ["0.0.0.0/0"]
                description     = "Plain HTTP"
        }
        ingress{
                from_port       = 443
                to_port         = 443
                protocol        = "tcp"
                cidr_blocks     = ["0.0.0.0/0"]
                description     = "Secure HTTP"
        }
        egress {
                from_port       = 0
                to_port         = 0
                protocol        = "-1"
                cidr_blocks     = ["0.0.0.0/0"]
        }
        tags = {
                Name = "terraform-demo-secgrp-webpub"
        }
}# Application tier security group
resource "aws_security_group" "terraform-demo-secgrp-app" {
        vpc_id              = aws_vpc.terraform-demo-vpc.id
        name                = "terraform-demo-secgrp-app"
        description         = "Allow traffic from the web tier"
        ingress{
                from_port       = 8080
                to_port         = 8080
                protocol        = "tcp"
                cidr_blocks     = ["10.0.0.0/21"]
                description     = "Plain HTTP"
        }
        ingress{
                from_port       = 8443
                to_port         = 8443
                protocol        = "tcp"
                cidr_blocks     = ["10.0.0.0/21"]
                description     = "Secure HTTP"
        }
        egress {
                from_port       = 0
                to_port         = 0
                protocol        = "-1"
                cidr_blocks     = ["0.0.0.0/0"]
        }
        tags = {
                Name = "terraform-demo-secgrp-app"
        }
}# Database tier security group
resource "aws_security_group" "terraform-demo-secgrp-db" {
        vpc_id              = aws_vpc.terraform-demo-vpc.id
        name                = "terraform-demo-secgrp-db"
        description         = "Allow traffic from the app tier"
        ingress{
                from_port       = 5432
                to_port         = 5432
                protocol        = "tcp"
                cidr_blocks     = ["10.0.8.0/21"]
                description     = "PostgreSQL"
        }
        ingress{
                from_port       = 3306
                to_port         = 3306
                protocol        = "tcp"
                cidr_blocks     = ["10.0.8.0/21"]
                description     = "MySQL"
        }
        ingress{
                from_port       = 27017
                to_port         = 27017
                protocol        = "tcp"
                cidr_blocks     = ["10.0.8.0/21"]
                description     = "mongodb"
        }
        egress {
                from_port       = 0
                to_port         = 0
                protocol        = "-1"
                cidr_blocks     = ["0.0.0.0/0"]
        }
        tags = {
                Name = "terraform-demo-secgrp-db"
        }
}

Снова запустите ту же команду плана terraform ранее и просмотрите предложенные изменения, затем запустите terraform apply и ответьте « да» на приглашение.

Пример вывода:

santino:terraform-aws santino$ terraform apply
aws_vpc.terraform-demo-vpc: Refreshing state... [id=vpc-03ae143c2a8e3284c]
<CUT>
aws_route_table_association.terraform-demo-rtassoc3: Refreshing state... [id=rtbassoc-0daec5cb8a9545d2a]An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + createTerraform will perform the following actions:<CUT># aws_security_group.terraform-demo-secgrp-webpub will be created
  + resource "aws_security_group" "terraform-demo-secgrp-webpub" {
      + arn                    = (known after apply)
      + description            = "Allow web traffic from the internet"
      + egress                 = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = ""
              + from_port        = 0
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "-1"
              + security_groups  = []
              + self             = false
              + to_port          = 0
            },
        ]
      + id                     = (known after apply)
      + ingress                = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = "Plain HTTP"
              + from_port        = 80
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 80
            },
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = "Secure HTTP"
              + from_port        = 443
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 443
            },
        ]
      + name                   = "terraform-demo-secgrp-webpub"
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = false
      + tags                   = {
          + "Name" = "terraform-demo-secgrp-webpub"
        }
      + vpc_id                 = "vpc-03ae143c2a8e3284c"
    }Plan: 3 to add, 0 to change, 0 to destroy.Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.Enter a value: yesaws_security_group.terraform-demo-secgrp-db: Creating...
aws_security_group.terraform-demo-secgrp-app: Creating...
aws_security_group.terraform-demo-secgrp-webpub: Creating...
aws_security_group.terraform-demo-secgrp-app: Creation complete after 2s [id=sg-0d920e06fa8dd370f]
aws_security_group.terraform-demo-secgrp-webpub: Creation complete after 2s [id=sg-029d4f9c83b6fed54]
aws_security_group.terraform-demo-secgrp-db: Creation complete after 2s [id=sg-049704a710b385483]Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
santino:terraform-aws santino$

Определения сервера

Наконец-то мы можем развернуть наши серверы!

Во-первых, мы запросим идентификатор последней официальной версии Centos 7 AMI. Далее мы создадим ресурс ключа SSH на основе нашего открытого ключа в ~/.ssh/id_rsa.pub . Наконец, мы создадим наш веб-сервер, наш сервер приложений и 2 сервера баз данных, все в соответствующих подсетях. Мы также связали бы каждый сервер с соответствующей группой безопасности, созданной ранее.

серверы.tf :

## Query the  latest AMI for Centos 7
data "aws_ami" "centos7" {
    owners      = ["679593333241"]
    most_recent = true
    filter {
        name   = "name"
        values = ["CentOS Linux 7 x86_64 HVM EBS *"]
    }
    filter {
        name   = "architecture"
        values = ["x86_64"]
    }
    filter {
        name   = "root-device-type"
        values = ["ebs"]
    }
}## SSH Key pair
resource "aws_key_pair" "terraform-demo-sshkey-santino" {
    key_name   = "terraform-demo-sshkey-santino"
    public_key = file("~/.ssh/id_rsa.pub")
        tags = {
             Name = "terraform-demo-sshkey-santino"
        }
}### Server definitions
# Web server
resource "aws_instance" "terraform-demo-web" {
  ami                    = data.aws_ami.centos7.id
  instance_type          = "t2.micro"
  key_name               = aws_key_pair.terraform-demo-sshkey-santino.key_name
  subnet_id              = aws_subnet.terraform-demo-snet-web.id
  vpc_security_group_ids = [aws_security_group.terraform-demo-secgrp-webpub.id]
        tags = {
             Name = "terraform-demo-web"
        }
}
# Application server
resource "aws_instance" "terraform-demo-app" {
  ami                    = data.aws_ami.centos7.id
  instance_type          = "t2.micro"
  key_name               = aws_key_pair.terraform-demo-sshkey-santino.key_name
  subnet_id              = aws_subnet.terraform-demo-snet-app.id
  vpc_security_group_ids = [aws_security_group.terraform-demo-secgrp-app.id]
        tags = {
             Name = "terraform-demo-app"
        }
}
# Database server - Postgresql
resource "aws_instance" "terraform-demo-postgres" {
  ami                    = data.aws_ami.centos7.id
  instance_type          = "t3a.medium"
  key_name               = aws_key_pair.terraform-demo-sshkey-santino.key_name
  subnet_id              = aws_subnet.terraform-demo-snet-db.id
  vpc_security_group_ids = [aws_security_group.terraform-demo-secgrp-db.id]
        tags = {
             Name = "terraform-demo-postgres"
        }
}
# Database server - MySQL
resource "aws_instance" "terraform-demo-mysql" {
  ami                    = data.aws_ami.centos7.id
  instance_type          = "t3a.medium"
  key_name               = aws_key_pair.terraform-demo-sshkey-santino.key_name
  subnet_id              = aws_subnet.terraform-demo-snet-db.id
  vpc_security_group_ids = [aws_security_group.terraform-demo-secgrp-db.id]
        tags = {
             Name = "terraform-demo-mysql"
        }
}

Снова запустите ту же команду плана terraform ранее и просмотрите предложенные изменения, затем запустите terraform apply и ответьте « да» на приглашение.

santino:terraform-aws santino$ terraform apply
data.aws_ami.centos7: Refreshing state...
aws_vpc.terraform-demo-vpc: Refreshing state... [id=vpc-03ae143c2a8e3284c]
aws_subnet.terraform-demo-snet-app: Refreshing state... [id=subnet-0b6474b59034abcb0]
aws_internet_gateway.terraform-demo-igw: Refreshing state... [id=igw-05519819650e3f727]
aws_subnet.terraform-demo-snet-web: Refreshing state... [id=subnet-06bd93be3e1b13772]
aws_subnet.terraform-demo-snet-db: Refreshing state... [id=subnet-0c5f28652ff57e71b]
aws_security_group.terraform-demo-secgrp-db: Refreshing state... [id=sg-049704a710b385483]
aws_security_group.terraform-demo-secgrp-app: Refreshing state... [id=sg-0d920e06fa8dd370f]
aws_security_group.terraform-demo-secgrp-webpub: Refreshing state... [id=sg-029d4f9c83b6fed54]
aws_route_table.terraform-demo-rtable: Refreshing state... [id=rtb-08a56a903445b0c7c]
aws_route_table_association.terraform-demo-rtassoc3: Refreshing state... [id=rtbassoc-0daec5cb8a9545d2a]
aws_route_table_association.terraform-demo-rtassoc1: Refreshing state... [id=rtbassoc-0d9d2fe02770cf4fd]
aws_route_table_association.terraform-demo-rtassoc2: Refreshing state... [id=rtbassoc-04e0a5bdcddd03f22]An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create
-/+ destroy and then create replacementTerraform will perform the following actions:# aws_instance.terraform-demo-app will be created
  + resource "aws_instance" "terraform-demo-app" {
      + ami                          = "ami-0e8286b71b81c3cc1"
      + arn                          = (known after apply)
      + associate_public_ip_address  = (known after apply)
      + availability_zone            = (known after apply)
      + cpu_core_count               = (known after apply)
      + cpu_threads_per_core         = (known after apply)
      + get_password_data            = false
      + host_id                      = (known after apply)
      + id                           = (known after apply)
      + instance_state               = (known after apply)
      + instance_type                = "t2.micro"
      + ipv6_address_count           = (known after apply)
      + ipv6_addresses               = (known after apply)
      + key_name                     = "terraform-demo-sshkey-santino"
      + network_interface_id         = (known after apply)
      + outpost_arn                  = (known after apply)
      + password_data                = (known after apply)
      + placement_group              = (known after apply)
      + primary_network_interface_id = (known after apply)
      + private_dns                  = (known after apply)
      + private_ip                   = (known after apply)
      + public_dns                   = (known after apply)
      + public_ip                    = (known after apply)
      + security_groups              = (known after apply)
      + source_dest_check            = true
      + subnet_id                    = "subnet-0b6474b59034abcb0"
      + tags                         = {
          + "Name" = "terraform-demo-app"
        }
      + tenancy                      = (known after apply)
      + volume_tags                  = (known after apply)
      + vpc_security_group_ids       = (known after apply)+ ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }+ ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        }+ metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
        }+ network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_interface_id  = (known after apply)
        }+ root_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }<CUT>Plan: 7 to add, 0 to change, 0 to destroy.Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.Enter a value: yes<CUT>
aws_instance.terraform-demo-mysql: Creation complete after 13s [id=i-029c67de608e848b5]
aws_instance.terraform-demo-web: Still creating... [20s elapsed]
aws_instance.terraform-demo-app: Still creating... [20s elapsed]
aws_instance.terraform-demo-app: Creation complete after 22s [id=i-01363d0b335a46378]
aws_instance.terraform-demo-web: Still creating... [30s elapsed]
aws_instance.terraform-demo-web: Creation complete after 32s [id=i-059f9773402b1eb34]Apply complete! Resources: 7 added, 0 changed, 0destroyed.
santino:terraform-aws santino$

Войдите в панель управления EC2 и перейдите к экземплярам, ​​чтобы проверить созданные серверы:

Информационная панель EC2

Поздравляем! Вы только что внедрили свою инфраструктуру AWS с помощью Terraform!

Статья является переводом medium.com

11.12.2022 0 comment
0 FacebookTwitterPinterestEmail
Newer Posts
Older Posts

RSS Крипто новости

  • Лучшие практики Ansible: часть 1
  • Непрерывное развертывание инфраструктуры AWS без доверия стороннему CI
  • Лучшие практики Ansible: часть 2
  • Краткое руководство по GraalVM

Подпишитесь на новости

Рубрики сайта

Свежие записи

  • Лучшие практики Ansible: часть 1 17.12.2022
  • Непрерывное развертывание инфраструктуры AWS без доверия стороннему CI 17.12.2022
  • Лучшие практики Ansible: часть 2 17.12.2022
  • Краткое руководство по GraalVM 17.12.2022
  • Как развернуть Kubernetes с помощью Kubespray 17.12.2022

Страницы

  • Checkout
  • Contact Us
  • Login/Register
  • My account
  • Our Blog
  • Наши услуги
  • О нас
  • Регистрация

Счетчик просмотров

Курс криптовалют

1 BTC = $28418.36 USD  (via Coinbase)
1 ETH = $1818.72 USD  (via Coinbase)
1 LTC = $93.90 USD  (via Coinbase)
Quotes delayed up to 2 minutes.
Рассылка 'Все о инвестициях в криптовалюту'

Keep in touch

Facebook Twitter Instagram Linkedin Youtube Email

Recent Posts

  • Лучшие практики Ansible: часть 1

  • Непрерывное развертывание инфраструктуры AWS без доверия стороннему CI

  • Лучшие практики Ansible: часть 2

  • Краткое руководство по GraalVM

  • Как развернуть Kubernetes с помощью Kubespray

Newsletter

Subscribe my Newsletter for new blog posts, tips & new photos. Let's stay updated!

Рубрики

  • Devops практики (7)
  • ICO новости (2)
  • IT services (4)
  • Java программирование (1)
  • linux администрирование (2)
  • News (4)
  • Security (1)
  • Swift программирование (8)
  • Update (4)
  • Альткоины (9)
  • Бизнес в итернете (154)
  • Биржи криптовалют (1)
  • Биткоин краны (1)
  • Майнинг (1)
  • Новости биткоин (9)
  • Новости блокчейн технологий (4)
  • Новости криптовалют (88)
  • обучение Ruby (3)
  • Смартконтракты (1)
  • Facebook
  • Twitter
  • Linkedin
  • Youtube
  • Email

@2019 - All Right Reserved. Designed and Developed by PenciDesign