Создание домашних рецептов с помощью GoReleaser

Создание домашних рецептов с помощью GoReleaser

18 ноября 2022 г.

Мы решили использовать GoReleaser в ObservIQ для нашего дистрибутива OpenTelemetry Collector, чтобы упростить создание и поддержку многих операционных систем и архитектур. GoReleaser позволяет нам построить целевую матрицу целей GOOS и GOARCH, а также автоматизировать создание широкого спектра результатов. Мы использовали сборку архивов, пакетов nfpm, образов докеров и формулы Homebrew.

В этой статье основное внимание уделяется возможностям Homebrew Taps в GoReleaser и нашему пути их использования. Нашей целью было упростить пользователям установку нашего программного обеспечения на macOS, чтобы они могли легко его опробовать. Мы выбрали Homebrew, так как он знаком многим пользователям macOS и позволяет пользователям опробовать наше программное обеспечение и так же легко удалить его, когда они закончат работу.

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

Мы прошли через несколько итераций нашей формулы Homebrew, узнавая все больше и больше о том, как правильно делать вещи.

Во-первых, мы создали общедоступный репозиторий, который должен был стать нашей формулой Homebrew. Мы бы указали, куда GoReleaser будет отправлять обновления формулы. Мы создали [https://github.com/observIQ/homebrew-observiq-otel-collector].

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

Блок предупреждений

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

  1. Предоставьте информацию о том, как запустить/остановить/перезапустить установленную доморощенную службу
  2. Как правильно удалить всю формулу
  3. И предоставить информацию о том, где находятся определенные файлы конфигурации.

Установить блок

Внутри блока install вы можете использовать те же ярлыки brew для установки, что и в самом файле формулы. Это в конечном итоге скопирует те же самые строки в блок установки файла формулы ruby. Например, мы используем:

* prefix.install для копирования файлов и каталогов в каталог с версионной формулой homebrew. * prefix.install_symlink для создания символических ссылок в версионном каталоге формул homebrew. * etc.install для копирования файлов и каталогов в общий каталог etc доморощенного * bin.install для копирования двоичных исполняемых файлов в каталог «bin» версии формулы homebrew. * lib.install для копирования файлов библиотеки в каталог «lib» формулы homebrew с версией версии

Сервисные блоки

В блоке plist мы определили файл plist, позволяющий запускать наше программное обеспечение в качестве службы запуска. Когда мы только начинали, блок service не поддерживался в GoReleaser, а как только он появился, мы перешли на его использование, так как его было проще определить для нас, и это позволило использовать более оригинальный способ управления нашим сервисом.< /p>

Наш исходный блок plist выглядел так, как показано ниже:

plist: |
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>Label</key>
        <string>com.observiq.collector</string>
        <key>ProgramArguments</key>
        <array>
        <string>#{bin}/observiq-otel-collector</string>
        <string>--config</string>
        <string>#{prefix}/config.yaml</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
        <key>StandardErrorPath</key>
        <string>/tmp/observiq-otel-collector.log</string>
        <key>StandardOutPath</key>
        <string>/tmp/observiq-otel-collector.log</string>
    </dict>
    </plist>

Как только мы увидели, что GoReleaser поддерживает блок service, мы смогли упростить его до следующего:

service: |
    run [opt_bin/"observiq-otel-collector", "--config", opt_prefix/"config.yaml"]
    environment_variables OIQ_OTEL_COLLECTOR_HOME: opt_prefix
    keep_alive true

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

Вот некоторые из наиболее распространенных, которые мы использовали:

| Переменная пути | Путь | |:---|:---| | опт_префикс | $HOMEBREW_PREFIX/opt/имя_формулы | | opt_bin | opt_prefix/bin | | опция_include | opt_prefix/include | | opt_lib | opt_prefix/библиотека |

Первоначальная конфигурация

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

brews:
  - name: observiq-otel-collector
    tap:
      owner: observIQ
      name: homebrew-observiq-otel-collector
      branch: main
    download_strategy: CurlDownloadStrategy
    folder: Formula
    url_template: https://github.com/observIQ/observiq-otel-collector/releases/download/{{ .Tag }}/{{ .ArtifactName }}
    commit_author:
      name: observiq
      email: support@observiq.com
    homepage: "https://github.com/observIQ/observiq-otel-collector"
    license: "Apache 2.0"
    caveats: |
      ****************************************************************
      The configuration file that is run by the service is located at #{prefix}/config.yaml.
      If you are configuring a logreceiver the plugin directory is located at #{prefix}/plugins.
      ****************************************************************
      ****************************************************************
      Below are services commands to run to manage the collector service.
      If you wish to run the collector at boot prefix these commands with sudo
      otherwise the service will run at login.
      To start the collector service run:
        brew services start observiq/observiq-otel-collector/observiq-otel-collector
      To stop the collector service run:
        brew services stop observiq/observiq-otel-collector/observiq-otel-collector
      To restart the collector service run:
        brew services restart observiq/observiq-otel-collector/observiq-otel-collector
      ****************************************************************
      ****************************************************************
      To uninstall the collector and its dependencies run the following commands:
          brew services stop observiq/observiq-otel-collector/observiq-otel-collector
          brew uninstall observiq/observiq-otel-collector/observiq-otel-collector
          launchctl remove com.observiq.collector
          # If you moved the opentelemetry-java-contrib-jmx-metrics.jar
          sudo rm /opt/opentelemetry-java-contrib-jmx-metrics.jar
      ****************************************************************
    install: |
      bin.install "observiq-otel-collector"
      prefix.install "LICENSE", "config.yaml"
      prefix.install Dir["plugins"]
      lib.install "opentelemetry-java-contrib-jmx-metrics.jar"
    service: |
      run [opt_bin/"observiq-otel-collector", "--config", opt_prefix/"config.yaml"]
      environment_variables OIQ_OTEL_COLLECTOR_HOME: opt_prefix
      keep_alive true

Версии рецептов приготовления кофе

Одна из проблем, с которой мы в конце концов столкнулись, заключалась в управлении версиями наших выпусков программного обеспечения с помощью Homebrew. Мы обнаружили, что после каждого выпуска GoReleaser обновлял репозиторий формул, перезаписывая предыдущую формулу. Пользователь может обновить формулу и запустить brew upgrade, чтобы легко получить последнюю версию. Проблема, с которой мы столкнулись, заключалась в том, что если вам нужна конкретная версия коллекционера с определенной формулой варки? Вам нужно будет знать, какая фиксация в формуле соответствует желаемому выпуску. Это не очень удобно.

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

Было непросто выяснить, как создавать версии Homebrew Formulas. В итоге мы просмотрели репозиторий homebrew-core, где можно найти примеры того, как это делают другие формулы.

Для версии формулы необходимо выполнить несколько специальных действий. Имя формулы должно иметь формат имя-формулы@major.minor.patch.rb. Добавленный @major.minor.patch позволяет Homebrew узнать, какую формулу получить, если она указана в команде brew. Внутри формулы имя класса также должно иметь особое форматирование. Он должен иметь формат FormulaNameAT{Major}{Minor}{Patch}. Таким образом, пример имени файла и соответствующего имени класса для нашего коллектора: observiq-otel-collector@0.6.0.rb и ObserviqOtelCollectorAT060 соответственно.

Этот файл формулы будет находиться в каталоге Formula вашего репозитория рядом с текущей основной формулой, формулой, которую вы получите, если просто запустите brew install X. Вы также можете добавить версию к основной формуле, чтобы пользователи могли получить ее по версии или с помощью базовой команды заваривания. Для этого вы создаете каталог Aliases на том же уровне, что и ваш каталог Formula. Внутри этого каталога создайте символическую ссылку на основную формулу с именем версии.

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

cd Aliases && ln -s ../Formula/observiq-otel-collector.rb observiq-otel-collector@0.6.0

Теперь, когда мы знаем, как создать версионную формулу, нам нужно обновить нашу конфигурацию GoReleaser, чтобы она генерировала для нас версионные формулы. Это должно быть просто, поскольку имена формул и классов берутся из поля name в блоке brews. Мы изменили наше название на observiq-otel-collector@{{ .Major }}.{{ .Minor }}.{{ .Patch }}. Когда мы запустили тестовый релиз с GoReleaser, мы увидели, что класс для формулы не совсем правильный. GoReleaser генерировал имя класса как ObserviqOtelCollectorAT0_6_0. Один быстрый запрос на включение в GoReleaser, и мы это исправили.

Вот как теперь выглядит наш блок brews в конфигурации GoReleaser для поддержки версий.

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

brews:
  - name: observiq-otel-collector@{{ .Major }}.{{ .Minor }}.{{ .Patch }}
    description: "observIQ's distribution of the OpenTelemetry Collector"
    tap:
      owner: observIQ
      name: homebrew-observiq-otel-collector
      branch: main
    download_strategy: CurlDownloadStrategy
    folder: Formula
    url_template: https://github.com/observIQ/observiq-otel-collector/releases/download/{{ .Tag }}/{{ .ArtifactName }}
    commit_author:
      name: observiq
      email: support@observiq.com
    homepage: "https://github.com/observIQ/observiq-otel-collector"
    license: "Apache 2.0"
    caveats: |
      ****************************************************************
      The configuration file that is run by the service is located at #{prefix}/config.yaml.
      If you are configuring a logreceiver the plugin directory is located at #{prefix}/plugins.
      ****************************************************************
      ****************************************************************
      Below are services commands to run to manage the collector service.
      If you wish to run the collector at boot prefix these commands with sudo
      otherwise the service will run at login.
      To start the collector service run:
        brew services start observiq/observiq-otel-collector/observiq-otel-collector@{{ .Major }}.{{ .Minor }}.{{ .Patch }}
      To stop the collector service run:
        brew services stop observiq/observiq-otel-collector/observiq-otel-collector@{{ .Major }}.{{ .Minor }}.{{ .Patch }}
      To restart the collector service run:
        brew services restart observiq/observiq-otel-collector/observiq-otel-collector@{{ .Major }}.{{ .Minor }}.{{ .Patch }}
      ****************************************************************
      ****************************************************************
      To uninstall the collector and its dependencies run the following commands:
          brew services stop observiq/observiq-otel-collector/observiq-otel-collector@{{ .Major }}.{{ .Minor }}.{{ .Patch }}
          brew uninstall observiq/observiq-otel-collector/observiq-otel-collector@{{ .Major }}.{{ .Minor }}.{{ .Patch }}
          # If you moved the opentelemetry-java-contrib-jmx-metrics.jar
          sudo rm /opt/opentelemetry-java-contrib-jmx-metrics.jar
      ****************************************************************
    install: |
      bin.install "observiq-otel-collector"
      prefix.install "LICENSE", "config.yaml", "VERSION.txt", "logging.yaml"
      prefix.install Dir["plugins"]
      lib.install "opentelemetry-java-contrib-jmx-metrics.jar"
    service: |
      run [opt_bin/"observiq-otel-collector", "--config", opt_prefix/"config.yaml", "--logging", opt_prefix/"logging.yaml", "--manager", opt_prefix/"manager.yaml"]
      environment_variables OIQ_OTEL_COLLECTOR_HOME: opt_prefix
      keep_alive true

Сохранение файлов конфигурации

Изначально в нашем блоке install конфигурации GoReleaser мы использовали prefix.install, чтобы поместить наш файл конфигурации в основной каталог установки нашей формулы.

install: |
    
    prefix.install "LICENSE", "VERSION.txt", "config.yaml"
    

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

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

install: |
    
    prefix.install "LICENSE", "VERSION.txt"
    etc.install "config.yaml" => "observiq_config.yaml"
    

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

install: |
    
    prefix.install "LICENSE", "VERSION.txt"
    etc.install "config.yaml" => "observiq_config.yaml"
    prefix.install_symlink etc/"observiq_config.yaml" => "config.yaml"

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

Здесь следует отметить еще одну вещь. Когда поверх нашей формулы появляется новая установка, homebrew автоматически добавляет новую версию нашего файла конфигурации в свой каталог etc. В нашем случае файл называется примерно так: observiq_config.yaml.default. Это будет содержать чистую конфигурацию с настройками по умолчанию. Это встроенное поведение для Homebrew, и мы не нашли способа его изменить.

Заключение

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


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE