Skip to content

Latest commit

 

History

History
774 lines (679 loc) · 36 KB

DOCS.ru.md

File metadata and controls

774 lines (679 loc) · 36 KB

Деплойер: документация по версии 1.3.X

Описание принципов работы

Деплойер, по своей сути, - локальный CI/CD. Иными словами, менеджер bash-команд.

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

Описание основных сущностей

1. Действие - Action

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

В составе Пайплайнов или в Реестре Действий Деплойера действие выглядит как конструкция:

{
  "title": "UPX Compress",
  "desc": "Compress the binary file with UPX.",
  "info": "[email protected]",
  "tags": [
    "upx"
  ],
  "action": {
    "PostBuild": {
      "supported_langs": [
        "Rust",
        "Go",
        "C",
        "Cpp",
        "Python",
        {
          "Other": "any"
        }
      ],
      "commands": [
        {
          "bash_c": "upx <artifact>",
          "placeholders": [
            "<artifact>"
          ],
          "ignore_fails": false,
          "show_success_output": false,
          "show_bash_c": false,
          "only_when_fresh": false
        }
      ]
    }
  },
  "requirements": [
    {
      "ExistsAny": [
        "/usr/bin/upx",
        "~/.local/bin/upx"
      ]
    }
  ]
}

В составе Реестров каждое Действие и каждый Пайплайн являются значениями в словаре с ключом info (например, "[email protected]": { ... }). Таким образом их можно быстро редактировать, выводить на экран содержимое, добавлять в Пайплайны и проекты.

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

[
  {
    // если один из этих путей будет найден, требование будет считаться удовлетворённым
    "ExistsAny": [
      "path-1",
      "path-2"
    ]
  },
  {
    // если данный путь существует, требование считается удовлетворённым
    "Exists": "path"
  },
  {
    // если данная проверка будет пройдена, требование будет считаться удовлетворённым (подробности см. ниже - Действие `Check`)
    "CheckSuccess": {
      "command": {
        "bash_c": "/usr/bin/python -V",
        "ignore_fails": true,
        "show_success_output": false,
        "show_bash_c": false,
        "only_when_fresh": false
      },
      "success_when_found": "Python 3.",
      "success_when_not_found": null
    }
  },
  {
    // если данный удалённый хост существует в Реестре, доступен, и его версия Деплойера идентична версии запущенного Деплойера,
    // требование будет считаться удовлетворённым
    "RemoteAccessibleAndReady": "short-name"
  }
]

Существует 3 категории основных Действий и 9 дополнительных видов Действий:

  1. Действия сборки (PreBuild, Build, PostBuild и Test)
  2. Действия установки (Pack, Deliver, Install)
  3. Действия развёртывания (ConfigureDeploy, Deploy, PostDeploy)
  4. Действие наблюдения Observe
  5. Действие прерывания Interrupt
  6. Действие с кастомной командой Custom
  7. Действие проверки вывода кастомной команды Check
  8. Действия добавления контента в хранилище Деплойера AddToStorage и использования этого контента UseFromStorage
  9. Действие применения патча Patch
  10. Действия синхронизации папок сборки - с текущего хоста на удалённый SyncToRemote и наоборот SyncFromRemote

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

1.1. Кастомная команда

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

{
  "bash_c": "upx <artifact>",
  "placeholders": [
    "<artifact>"
  ],
  "ignore_fails": false,
  "show_success_output": false,
  "show_bash_c": false,
  "only_when_fresh": false,
  "remote_exec": []
}
  • bash_c содержит текст команды, которая будет выполняться в терминале
  • placeholders содержит список плейсхолдеров, которые можно будет заменять на переменные и артефакты проекта, чтобы выполнять с ними необходимые действия
  • ignore_fails говорит Деплойеру, нужно ли квалифицировать статус выхода процесса, не равный нулю, как нормальное поведение команды, или нет; если нет, то Деплойер прервёт выполнение Пайплайна и выйдет со статусом 1
  • show_success_output говорит Деплойеру, нужно ли печатать вывод команды всегда (в т.ч. когда статус выхода процесса - 0), или же нужно печатать только при ошибке
  • show_bash_c говорит Деплойеру, нужно ли печатать на экране полный текст команды; это может быть полезным, когда команда содержит уязвимые переменные
  • only_when_fresh говорит Деплойеру, что это действие нужно выполнять только при свежей сборке (либо при первой сборке, либо при явном указании пересобрать с нуля при помощи опции -f)
  • remote_exec содержит список коротких имён хостов, на которых необходимо будет выполнить эту команду

Когда команда специализируется для конкретного проекта, она обрастает дополнительным свойством - replacements:

{
  "bash_c": "upx <artifact>",
  "placeholders": [
    "<artifact>"
  ],
  "replacements": [
    [
      [
        "<artifact>",
        {
          "title": "target/release/deployer",
          "is_secret": false,
          "value": {
            "Plain": "target/release/deployer"
          }
        }
      ]
    ]
  ],
  "ignore_fails": false,
  "show_success_output": false,
  "show_bash_c": false,
  "only_when_fresh": false
}

replacements содержит список замен плейсхолдеров в команде на указанные артефакты или переменные (см. п.3). Следует заметить, что одна и та же команда может выполняться несколько раз для разных наборов переменных, даже если указана в Действии один раз:

{
  "bash_c": "upx <artifact>",
  "placeholders": [
    "<artifact>"
  ],
  "replacements": [
    [
      [
        "<artifact>",
        {
          "title": "target/release/deployer",
          "is_secret": false,
          "value": {
            "Plain": "target/release/deployer"
          }
        }
      ]
    ],
    [
      [
        "<artifact>",
        {
          "title": "target/release/another",
          "is_secret": false,
          "value": {
            "Plain": "target/release/another"
          }
        }
      ]
    ]
  ],
  "ignore_fails": false,
  "show_success_output": false,
  "show_bash_c": false,
  "only_when_fresh": false
}

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

Соответственно, если вы хотите просто выполнять команды, которые нельзя отнести к одному из трёх основных видов Действий, следует использовать Действие типа Custom:

{
  "title": "List all files and folders",
  "desc": "",
  "info": "[email protected]",
  "tags": [],
  "action": {
    "Custom": {
      "bash_c": "ls",
      "ignore_fails": false,
      "show_success_output": true,
      "show_bash_c": true,
      "only_when_fresh": false
    }
  }
}

1.2. Действия сборки - PreBuild, Build, PostBuild и Test

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

Note

Специализации работают только при назначении Действий или Пайплайнов из TUI. Если вручную отредактировать конфигурацию, добавив несовместимый Пайплайн, никаких предупреждений Деплойер не выдаст. Это отражает нестрогий и рекомендательный характер таких предупреждений, в отличие от требований requirements.

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

{
  "PostBuild": {
    "supported_langs": [
      "Rust",
      "Go",
      "C",
      "Cpp",
      "Python",
      {
        "Other": "any"
      }
    ],
    "commands": [
      {
        "bash_c": "upx <artifact>",
        "placeholders": [
          "<artifact>"
        ],
        "ignore_fails": false,
        "show_success_output": false,
        "show_bash_c": false,
        "only_when_fresh": false
      }
    ]
  }
}

1.3. Действия установки - Pack, Deliver и Install

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

С удовольствием заметим, что UPX скорее относится к Действию упаковки, нежели к Действию после сборки:

{
  "title": "UPX Pack",
  "desc": "Pack the binary by UPX.",
  "info": "[email protected]",
  "tags": [
    "upx"
  ],
  "action": {
    "Pack": {
      "target": {
        "arch": "x86_64",
        "os": "Linux",
        "derivative": "any",
        "version": "No"
      },
      "commands": [
        {
          "bash_c": "upx <af>",
          "placeholders": [
            "<af>"
          ],
          "ignore_fails": false,
          "show_success_output": false,
          "show_bash_c": false,
          "only_when_fresh": false
        }
      ]
    }
  }
}
  • arch - это строковое обозначение архитектуры аппаратного обеспечения таргета
  • os - это один из вариантов (android|ios|linux|unix-{unix-name}|windows|macos) или любое другое строковое обозначение операционнной системы
  • derivative - это дополнительное описание операционной системы или программной платформы
  • version - это версия операционной системы или программной платформы

Если derivative отсутствует, рекомендуется писать any.

1.4. Действия развёртывания - ConfigureDeploy, Deploy, PostDeploy

Для этой группы Действий ключевым фактором специализации является тулкит для развёртывания - Docker, Docker Compose, Podman, k8s или иной инструментарий контейнеризации или виртуализации. Если в проекте будет указан не тот тулкит, Деплойер выдаст предупреждение.

Приведём пример с Docker Compose:

{
  "title": "Build Docker Compose Image",
  "desc": "Build Docker image with Docker Compose",
  "info": "[email protected]",
  "tags": [
    "docker",
    "compose"
  ],
  "action": {
    "ConfigureDeploy": {
      "deploy_toolkit": "docker-compose",
      "tags": [
        "docker",
        "compose"
      ],
      "commands": [
        {
          "bash_c": "docker compose build",
          "ignore_fails": false,
          "show_success_output": false,
          "show_bash_c": true,
          "only_when_fresh": false
        }
      ]
    }
  }
}

1.5. Действия добавления контента AddToStorage, использования контента UseFromStorage и применения патча Patch

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

deployer new content

Тогда для проектов, которые должны использовать эти файлы, можно добавить в Пайплайн сборки новое Действие - UseFromStorage:

{
  "title": "Sync content",
  "desc": "",
  "info": "[email protected]",
  "tags": [],
  "action": {
    "UseFromStorage": "[email protected]"
  }
}

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

Раз за разом вы начнёте замечать, что некоторые проекты переиспользуются в других проектах как зависимости, и их необходимо где-то публиковать. Для этого как нельзя лучше подходят репозитории пакетов, но если вы не хотите публиковать свой проект, то можете добавлять его в хранилище Деплойера в качестве контента. Более того, добавлять его можно автоматически - при помощи Действия AddToStorage:

{
  "title": "Add content",
  "desc": "",
  "info": "[email protected]",
  "tags": [],
  "action": {
    "AddToStorage": {
      "short_name": "my-project",
      "auto_version_rule": {
        "plain_file": "file-with-current-version.txt"
      }
    }
  }
}
  • short_name - строковое обозначение контента, которое будет использовано для размещения в хранилище и каждый раз при использовании
  • auto_version_rule - способ автоматического определения версии контента (либо plain_file - файл, в котором будет указана только версия и больше ничего, либо cmd_stdout - команда, которая выведет на экран только версию и больше ничего)

Однако иногда файл нужно каким-то образом редактировать - и не столько даже добавляемый контент из хранилища Деплойера, сколько, например, различные файлы в зависимостях сборки, например, вручную делать форки библиотек Python для добавления нужной функциональности и т.д. и т.п. Причём, как правило, хочется делать это без создания форков и синхронизации изменений с main-репозиторием! Одними патчами git'а не обойтись.

Для этого Деплойер использует для патчей библиотеку smart-patcher. Такие патчи позволяют изменять исходные тексты, сложные документы и даже бинарные файлы, позволяя искать необходимые включения в содержимом на базе отсеивающих правил и даже используя скрипты на таких языках, как Python, Lua и Rhai. Например, в репозитории smart-patcher есть пример с патчем для документа Microsoft Word - и много других примеров.

Для использования умных патчей вам необходимо сперва написать файл патча. Пример:

{
  "patches": [
    {
      "files": [
        {
          "just": "test_v5.docx"
        }
      ],
      "decoder": {
        "python": "../tests/test_v5.py"
      },
      "encoder": {
        "python": "../tests/test_v5.py"
      },
      "path_find_graph": [],
      "replace": {
        "from_to": [
          "game",
          "rock"
        ]
      }
    }
  ]
}

Действие патча же выглядит так:

{
  "title": "Apply patch",
  "desc": "",
  "info": "[email protected]",
  "tags": [],
  "action": {
    "Patch": {
      "patch": "my_path.json"
    }
  }
}

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

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

1.6. Действия синхронизации папок сборки - с текущего хоста на удалённый SyncToRemote и наоборот SyncFromRemote

Иногда нужно синхронизировать файлы сборки между удалёнными хостами и текущим хостом. Например, когда часть действий нужно обязательно выполнить на одном хосте, а часть - на другом. Для этого можно использовать встроенные Действия SyncToRemote и SyncFromRemote:

{
  "title": "Send build folder to remote",
  "desc": "",
  "info": "[email protected]",
  "tags": [],
  "action": {
    "SyncToRemote": "remote-pc"
  }
}

1.7. Другие действия - Interrupt, Observe и Check

NOTE: Нет нужного примера конфигурации? Создайте действие самостоятельно при помощи команды deployer new action и выведите его на экран при помощи deployer cat action [email protected].

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

Observe - Действие, которое практически идентично Custom. Оно используется, например, чтобы запустить Prometheus, Jaeger или что угодно ещё. Отличительной особенностью является то, что оно запускается без перенаправления ввода-вывода, т.е. в нём можно взаимодействовать с программами.

А вот Check - особенное действие, позволяющее проверять, что вывела команда в stdout/stderr:

{
  "Check": {
    "command": {
      "bash_c": "<af>",
      "placeholders": [
        "<af>"
      ],
      "ignore_fails": true,
      "show_success_output": false,
      "show_bash_c": false,
      "only_when_fresh": false
    },
    "success_when_found": "some rust regex",
    "success_when_not_found": null
  }
}
  • success_when_found сообщает Деплойеру, что если он найдёт указанное регулярное выражение, то выполнение команды будет считаться успешным
  • success_when_not_found сообщает Деплойеру, что если он не найдёт указанное регулярное выражение, то выполнение команды будет считаться успешным

Причём, если оба поля указаны, то успешным запуск будет считаться в случае, если оба варианта были успешны (первое регулярное выражение должен найти, второе - должен не найти).

На этом описание Действий заканчивается, и мы переходим к Пайплайнам.

2. Пайплайн - Pipeline

Пайплайн - это упорядоченный набор Действий, который необходим для достижения определённой цели. Например, когда нужно проверить качество кода, проверить код с помощью статического анализатора, затем собрать, сжать, упаковать в пакет для определённого дистрибутива и загрузить на хостинг. Или когда нужно собрать Android-приложение, подписать и установить на устройство, подключённое по ADB. Композиция Пайплайна может быть любой, главный же пример приведён в файле deploy-config.json этого репозитория:

{
  "title": "Deployer Pipeline",
  "desc": "Default Deployer Pipeline for itself.",
  "info": "[email protected]",
  "tags": [
    "cargo",
    "clippy",
    "build",
    "upx"
  ],
  "actions": [
    {
      "title": "Lint",
      "desc": "Got from `Cargo Clippy`.",
      "info": "[email protected]",
      "tags": [
        "cargo",
        "clippy"
      ],
      "action": {
        "PreBuild": {
          "supported_langs": [
            "Rust"
          ],
          "commands": [
            {
              "bash_c": "cargo clippy",
              "ignore_fails": false,
              "show_success_output": true,
              "show_bash_c": true,
              "only_when_fresh": null
            }
          ]
        }
      }
    },
    {
      "title": "Build",
      "desc": "Got from `Cargo Build (Release)`. Build the Rust project with Cargo default settings in release mode",
      "info": "[email protected]",
      "tags": [
        "rust",
        "cargo"
      ],
      "action": {
        "Build": {
          "supported_langs": [
            "Rust"
          ],
          "commands": [
            {
              "bash_c": "cargo build --release",
              "ignore_fails": false,
              "show_success_output": false,
              "show_bash_c": true,
              "only_when_fresh": null
            }
          ]
        }
      }
    },
    {
      "title": "Compress",
      "desc": "Got from `UPX Compress`.",
      "info": "[email protected]",
      "tags": [
        "upx"
      ],
      "action": {
        "PostBuild": {
          "supported_langs": [
            "Rust",
            "Go",
            "C",
            "Cpp",
            "Python",
            {
              "Other": "any"
            }
          ],
          "commands": [
            {
              "bash_c": "upx <artifact>",
              "placeholders": [
                "<artifact>"
              ],
              "replacements": [
                [
                  [
                    "<artifact>",
                    {
                      "title": "target/release/deployer",
                      "is_secret": false,
                      "value": {
                        "Plain": "target/release/deployer"
                      }
                    }
                  ]
                ]
              ],
              "ignore_fails": false,
              "show_success_output": false,
              "show_bash_c": false,
              "only_when_fresh": null
            }
          ]
        }
      }
    },
    {
      "title": "Install to ~/.cargo/bin",
      "desc": "",
      "info": "[email protected]",
      "tags": [
        "cargo"
      ],
      "action": {
        "Install": {
          "target": {
            "arch": "x86_64",
            "os": "Linux",
            "derivative": "any",
            "version": "No"
          },
          "commands": [
            {
              "bash_c": "cp -f <artifact> ~/.cargo/bin",
              "placeholders": [
                "<artifact>"
              ],
              "replacements": [
                [
                  [
                    "<artifact>",
                    {
                      "title": "target/release/deployer",
                      "is_secret": false,
                      "value": {
                        "Plain": "target/release/deployer"
                      }
                    }
                  ]
                ]
              ],
              "ignore_fails": false,
              "show_success_output": false,
              "show_bash_c": false,
              "only_when_fresh": null
            }
          ]
        }
      }
    }
  ],
  "default": true
}

В общем, Пайплайн содержит список Действий в поле actions.

Помимо этого, если ваши Пайплайны должны управлять конфликтующими версиями кэша (например, при сборке проекта под разные целевые архитектуры), то вы можете указать эксклюзивную метку сборки в поле exclusive_exec_tag. Например, укажите x86_64 при добавлении Пайплайна сборки для одной архитектуры, а aarch64 - для другой. Тогда Пайплайны будут собираться в разных папках, и информация о кэше будет сохранена в обоих случаях.

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

{
  "title": "deployer artifact location",
  "is_secret": false,
  "value": {
    "Plain": "target/release/deployer"
  }
}
  • title - название переменной (то, как она будет отображаться в TUI)
  • is_secret - является ли переменная секретом (если является, то команда, которая её содержит, не будет показана на экране)
  • value - само значение переменной или же информация о том, откуда и как это значение брать

Есть три поддерживаемых сейчас типа переменных:

  1. Plain - содержимое строки и есть переменная
  2. FromEnvVar - переменная будет взята из окружения оболочки Деплойера
  3. FromEnvFile - переменная будет взята из указанного env-файла с указанным ключом
  4. FromHCVaultKv2 - переменная будет взята из HashiCorp Vault KV2-хранилища с указанными mount_path и secret_path

Примеры:

{
  "title": "Grafana token",
  "is_secret": true,
  "value": {
    "FromEnvFile": {
      "env_file_path": ".env",
      "key": "GRAFANA_TOKEN"
    }
  }
}
{
  "title": "Simple env var",
  "is_secret": false,
  "value": {
    "FromEnvVar": "variable-key"
  }
}
{
  "title": "Secret!",
  "is_secret": true,
  "value": {
    "FromHCVaultKv2": {
      "mount_path": "The mount path where your KV2 secrets engine is mounted",
      "secret_path": "Path to your secret"
    }
  }
}

Заметьте, что вы должны перед использованием FromHCVaultKv2-переменных указать две переменные окружения: DEPLOYER_VAULT_ADDR (URL-адрес Vault) и DEPLOYER_VAULT_TOKEN (токен Vault).

Ещё одной важной сущностью является удалённый хост. Деплойер хранит все хосты в Реестре (глобальный файл конфигурации - список remote_hosts). Структура хоста выглядит так:

{
  "short_name": "localhost",
  "ip": "127.0.0.1",
  "port": 22,
  "username": "username",
  "ssh_private_key_file": "/path/to/id_rsa"
}

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

Описание утилиты CLI

Деплойер, в первую очередь, - CLI-утилита. По любой команде Деплойера можно посмотреть справку, указав опцию -h. Приведём примеры самых распространённых команд:

deployer new action                            # создать Действие и поместить в Реестр
deployer new pipeline                          # создать Пайплайн и поместить в Реестр
deployer new remote                            # добавить в Реестр новый удалённый хост
deployer init                                  # инициализировать проект, указать все свойства
deployer with                                  # проверить совместимость и назначить Пайплайн для проекта,
                                               # а также указать необходимые переменные и артефакты вместо плейсхолдеров
deployer build                                 # запустить Пайплайн, назначенный по умолчанию
deployer build my-pipe                         # запустить Пайплайн по короткому имени
deployer build configure,build -o build-folder # запустить Пайплайны `configure` и `build` в папке `build-folder`
deployer build -R my-remote my-pipe            # запустить Пайплайн `my-pipe` на удалённом хосте `my-remote`

Интерфейс консоли (TUI)

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

Логи

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