Как вы управляете версиями изображений с помощью Packer и Terraform?

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

  1. Создайте образ с помощью Packer, используя наши существующие скрипты Ansible
  2. Разверните созданный образ в облаке с помощью Terraform
  3. Разверните наши ресурсы Kubernetes с помощью наших текущих инструментов

Все отлично. Теперь у нас есть неизменная инфраструктура с использованием самых современных инструментов.

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

Я могу представить, как это можно сделать вручную, отредактировав шаблон перед его запуском, а затем отредактировав конфигурацию terraform, чтобы выбрать новую версию, но это не сработает для конвейера CI / CD. Другая проблема в том, что мы можем перемещаться между разными регионами и поставщиками. Таким образом, версия изображения может присутствовать в одной области, но не в другой, и в идеале конвейер должен создавать изображение, если оно не существует, и использовать существующее, если оно уже существует. Это может привести к тому, что образы в разных регионах или облаках будут разными, особенно потому, что они могут быть созданы в разные дни и иметь разные обновления безопасности.

Все это встроено в рабочий процесс Docker, но с Packer далеко не очевидно, что делать. Я не нашел никакой документации или руководств по этой теме. Есть ли в Packer и Terraform какие-либо встроенные функции управления версиями? Может ли Terraform вызвать Packer, если изображение отсутствует? Есть ли какая-нибудь передовая практика?

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


person Erik B    schedule 02.06.2020    source источник
comment
Я только что нашел это: davidbegin.com/packer-and-terraform, так что кажется как будто это может быть нерешенная проблема, для которой люди придумывают свои собственные решения. Если вы используете Terraform и Packer в производстве, дайте мне знать, как вы с этим справляетесь.   -  person Erik B    schedule 02.06.2020
comment
Управление версиями на самом деле не встроено в Packer, потому что он объединяет несколько поставщиков, провайдеров и т. Д. У каждого из них есть свое собственное управление версиями. Например, вы упоминаете, что у Docker есть это, потому что это один конкретный провайдер, который Packer может интегрировать среди многих других. Virtualbox, AWS, GCP, AZR, VMWare и т. Д. - это другие провайдеры со своими собственными версиями. В этом вопросе есть еще много интересного, но это объясняет, почему вы не можете найти эту функциональность в Packer.   -  person Matt Schuchard    schedule 02.06.2020
comment
@MattSchuchard Я не понимаю, почему Packer не может унифицировать управление версиями или почему Terraform не может обрабатывать изображения так же, как любой другой облачный ресурс, и считает Packer поставщиком этих изображений. Затем мы заставляем наши виртуальные машины зависеть от этих образов, так что они должны быть созданы / представлены до запуска виртуальных машин. Мне это кажется очевидным рабочим процессом, и это то, чего я ожидал. Для меня не имеет смысла использовать еще один инструмент для построения этого графа зависимостей.   -  person Erik B    schedule 03.06.2020


Ответы (3)


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

И Terraform, и Packer могут выбрать самый последний AMI, соответствующий фильтру.

Конструктор AWS AMI от Packer использует source_ami_filter, который можно использовать для выбора самое последнее изображение, на основе которого будет создано ваше изображение. Пример приведен в amazon-ebs документации по построителю:

{
  "source_ami_filter": {
    "filters": {
      "virtualization-type": "hvm",
      "name": "ubuntu/images/\*ubuntu-xenial-16.04-amd64-server-\*",
      "root-device-type": "ebs"
    },
    "owners": ["099720109477"],
    "most_recent": true
  }
}

Типичный случай здесь - всегда использовать для сборки последний официальный образ Ubuntu. Если вы создаете несколько AMI для разных вариантов использования (например, рабочие узлы Kubernetes и узлы etcd), вы можете затем создать золотой базовый образ с известной схемой именования (например, ubuntu/20.04/base/{{isotime | clean_resource_name}}), в котором есть все, что вы хотите, в каждом Создаваемый вами AMI, а затем другие AMI также могут использовать source_ami_filter для выбора самого последнего опубликованного вами базового AMI.

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

Пример приведен в aws_instance ресурсной документации:

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"] # Canonical
}

resource "aws_instance" "web" {
  ami           = "${data.aws_ami.ubuntu.id}"
  instance_type = "t2.micro"

  tags = {
    Name = "HelloWorld"
  }
}

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


Управление жизненным циклом образов выходит за рамки самого Packer, и его следует использовать как часть более крупной системы. Если вы хотите откатить изображение, вам доступны два варианта:

  • Если ваша сборка воспроизводима, и проблема в этой воспроизводимой вещи, вы можете создать и зарегистрировать новое изображение со старым кодом, чтобы ваше новейшее изображение теперь было таким же, как и изображение, которое было 2 изображения назад.
  • Отмените регистрацию самого нового изображения, чтобы вы снова начали собирать старое изображение при поиске последнего. Это зависит от облачного провайдера, но с AWS это можно сделать программно, например, с помощью _ 9_ командная строка

Хотя Packer может автоматически копировать изображения в разные регионы (см. ami_regions для AWS) и разные учетные записи (используйте ami_users, чтобы поделиться создал AMI с другой учетной записью или постпроцессором для создания отдельных копий в разных учетных записях) он не может легко делать что-то условно, если у вас нет разных файлов конфигурации Packer для каждой комбинации способов, которыми вы хотите делиться вещами, и не может отделить развертывание, поэтому вы выпускаете для непроизводственной учетной записи, прежде чем выпускать для производственный счет и т. д.

Если вы хотите развернуть AMI в некоторых учетных записях и регионах, но не во всех, вам нужно будет разместить эту логику в месте более высокого порядка, например, в механизме оркестрации, таком как ваша система CI / CD.

person ydaetskcoR    schedule 03.06.2020
comment
Спасибо, этот ответ определенно полезен. Одна вещь, которую мне все еще не хватает, - это то, как Packer узнает, нужно ли создавать образ. Docker имеет кэшированные слои и перестраивает только при наличии изменений, но кажется, что Packer будет создавать новые образы с нуля каждый раз, независимо от того, изменилось ли что-нибудь. Другое дело, как продвигать имидж от постановки до постановки. Если у вас есть кластер K8s с автоматическим масштабированием, вы не хотите, чтобы он разворачивал узлы с изображениями, которые еще не были протестированы вашим конвейером. Придется ли вам справляться с этим, переименовывая изображения вне Terraform / Packer? - person Erik B; 03.06.2020
comment
Он не знает, произошли ли какие-либо изменения, поэтому вам придется справиться с этим помимо использования Packer, если вам это небезразлично. И, как я уже упоминал в ответе, вам также нужно обрабатывать продвижение изображений отдельно. Packer очень ориентирован на построение изображений. Вам решать, когда создавать образ и где его следует опубликовать. - person ydaetskcoR; 03.06.2020
comment
Я лично публикую AMI для всех наших учетных записей одновременно, и наша система CI / CD затем вызывает Terraform для применения изменений сначала к нашим непроизводственным системам, а затем, в конечном итоге, развертывается в производственной среде на более позднем этапе (в настоящее время это утверждение выполняется вручную. но может быть автоматическим, если вы уверены в процессе тестирования). - person ydaetskcoR; 03.06.2020
comment
Я стараюсь, чтобы мои конвейеры CI / CD были свободны от логики. В идеале каждый этап просто вызывает одну команду. В случае проекта Java я бы, вероятно, поместил такую ​​логику (одна команда в зависимости от вывода другой команды, которая может или не может потребоваться) в Gradle. Представлять Gradle здесь кажется странным, но инструмент сборки, который позволяет вам построить граф зависимостей (как это делает Gradle) для моделирования зависимости между Packer и Terraform, кажется, нам нужен. Есть ли вообще какой-нибудь инструмент, обычно используемый для этого? - person Erik B; 04.06.2020
comment
Нет, это полностью зависит от вас. Многие люди (в том числе и я) оборачивают Terraform в сценарии оболочки для обработки таких вещей, как настройка состояния и извлечение модулей, так что это более распространенный шаблон, чем использование Gradle. Я также видел, как используется Make. - person ydaetskcoR; 04.06.2020
comment
Если читать больше о Terraform, похоже, что у него есть все возможности для поддержки такого графа зависимостей. Я не понимаю, почему образ не считается просто ресурсом, предоставляемым Packer, от которого зависят ресурсы вашей виртуальной машины. Это то, чего я ожидал, и я не вижу никаких технических причин не разрабатывать его таким образом, но похоже, что мне пришлось бы реализовать собственный поставщик, чтобы он работал. - person Erik B; 04.06.2020
comment
Именно так это и работает. Вы также можете использовать ресурс aws_ami для создания этого AMI непосредственно в Terraform, но это не так хорошо, как создание изображений в Packer и их разъединение. Исходя из ваших упомянутых требований, вам понадобится что-то для обработки логики оркестровки для постепенного развертывания этого изображения в разных учетных записях и регионах в любом случае, чтобы его нужно было закодировать где-то за пределами Terraform, и на этом этапе вы все равно можете справиться с связыванием Packer и Terraform. - person ydaetskcoR; 04.06.2020
comment
Хорошо, похоже, что некоторые облачные провайдеры рассматривают ресурсы изображений, но другие делают их доступными только как источники данных. Даже зная это, я не могу понять, как предоставить им Packer. Из приведенных примеров кажется, что вы должны создать образ с диска виртуальной машины, а не с помощью Packer. Это верно? Похоже, что использование Ansible для вызова Packer (при необходимости), а затем вызова Terraform - обычная практика. По крайней мере, этот доклад, кажется, предполагает, что: hashicorp.com/resources/ansible- terraform-лучше-вместе - person Erik B; 05.06.2020
comment
@ErikB Пожалуйста, не переходите по пути конфигурации после инициализации. Упаковщик может запускать инструменты конфигурации в процессе сборки - примером может быть поставщик типа salt. Более или менее, как большинство людей создают AMI, так это то, что они берут базовый AMI (управляемый командами DevOps) и строят с упаковщиком поверх этого AMI. Например, вы берете Centos7 AMI с предустановленными общими пакетами, и ваша зависимая команда использует его как source_ami для своей конфигурации web_applications. Также подумайте о том, чтобы управление изображениями не выполнялось в ситуации, когда у вас есть 25 000 неиспользуемых AMI. - person Daniel Hajduk; 17.11.2020

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

Я не делал этого для многих приложений и обнаружил, что обычно лучше сделать что-то вроде ниже

vendor-app-appversion-epoch

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

data "aws_ami" "amazon_linux2" {
  most_recent = true
  filter {
    name = "name"
    values = ["amzn2-ami-*-x86_64-gp2"]
  }

  filter {
    name = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["amazon"]
}

Это приведет к получению последнего образа для linux2, когда вы примените terraform.

person hikerspath    schedule 03.06.2020
comment
Извините, но я не понимаю, как это отвечает на мой вопрос. Похоже, вы предлагаете соглашение об именах, а не стратегию управления версиями. Вы также ничего не упоминаете о взаимодействии Terraform и Packer. Если вы предлагаете мне вручную скопировать имя изображения из вывода Packer в переменную в Terraform, то этот ответ мне совсем не помогает, потому что это то, чего я пытаюсь избежать. - person Erik B; 03.06.2020
comment
Ну, это не позволит мне разместить здесь форматированный текст, поэтому я уточнил. Да, это структура именования, но она позволяет всегда получать самые свежие. - person hikerspath; 04.06.2020

Я написал сообщение в блоге по этой теме, Сохранение версий изображений Packer и Terraform , синхронизировано и СУХОЕ.

В итоге:

Наши цели

  • Образы, созданные Packer, должны иметь версии.
  • Управление версиями образа должно быть СУХИМ (храниться в одном месте) и совместно использоваться Packer и Terraform, чтобы избежать рассинхронизации по ошибке.
  • Файлы конфигурации для Packer, Terraform и информация об управлении версиями изображений должны храниться в git, так что проверка конкретной фиксации и выполнение terraform apply должно быть достаточно для выполнения отката.
  • Terraform должен автоматически определять, основываясь только на локальной информации, наличие более новой версии одного или нескольких изображений ИЛИ необходимость создания более новой версии.
  • Должна быть возможность иметь N независимых сред разработки / подготовки, в которых управление версиями образов не зависит от производства.
  • Подход должен быть независимым от IaaS (должен работать с любым облачным провайдером).

Краткое изложение подхода

Используйте соглашение об именах, например

<IMAGE-NAME> ::= <ROLE>__<BRANCH>-<REVISION>

Задайте значение переменной в отдельном файле packer/versions.pkvars.hcl:

service-a-img-name = "service-a__main-3"

Создайте образ с помощью:

$ packer build -var-file=versions.pkrvars.hcl minimal.pkr.hcl

На стороне Terraform, поскольку файл packer/versions.pkvars.hcl находится в HCL, мы можем прочитать его из Terraform:

$ terraform apply -var-file=../../packer/versions.pkrvars.hcl

Все подробности в упомянутом выше сообщении блога.

person marco.m    schedule 02.09.2020