В мире существует множество различных систем для хранения кода. Различаются они как протоколом работы: Git, Mercurial, Bazaar, — так и форматом работы (cloud, self-hosted). Но есть и другой важный параметр при их выборе: степень интеграции с сопутствующим инструментарием: issue tracker, CI/CD, wiki и т.д. Так сложилось, что мы в компании предпочитаем GitLab (вариант on-premise) и по умолчанию, если клиент не против, предлагаем ему это решение. В статье я расскажу про миграцию из Gitea c Jenkins в GitLab и о том, с какими сложностями пришлось столкнуться, а заодно поделюсь Python-скриптами, которые пригодились для успеха этого мероприятия.

Важно! В статье рассматривается Gitea 1.13.4 и GitLab 13.8. В новых версиях могут быть какие-то улучшения, которые облегчат перенос, но на момент миграции эти версии были актуальными.

Немного про Gitea и задачу

Gitea — легковесная Open Source-система для управления Git-репозиториями. Это форк другой легковесной системы — Gogs. Она интересна возможностью сочетать в одном инстансе несколько организаций с довольно широким спектром настроек прав доступа и GitHub-подобным API.

Проект популярен и имеет более 25 тысяч звёзд на GitHub. Среди спонсоров — DigitalOcean и Equinix, а также поддержать Gitea можно на Open Collective (и проследить, куда пойдут ваши средства)

Как вылядит веб-интерфейс Gitea
Как вылядит веб-интерфейс Gitea

Из плюсов хочется отметить, что Gitea очень проста как в установке и настройке, так и в бэкапе. Систему можно запустить на любом относительно современном компьютере, и она предложит некоторые встроенные сервисы: wiki-страницы, задачи и проекты, т.е. todo-листы.

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

Что было на старте

Исходное состояние — Gitea 1.13.4 со 165 репозиториями и 94 пользователями. Всё это было разложено по 18 организациями, а некоторые репозитории были личными.

Кроме того, клиент не хотел терять историю pull requests, а их было достаточно много: в некоторых репозиториях — более 5 тысяч.

Статистика по инсталляции Gitea до переноса
Статистика по инсталляции Gitea до переноса

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

Да и вообще, мы же инженеры! Поэтому пошли путем автоматизации и ниже расскажем о проблемах, которые пришлось преодолеть. Попутно мы научимся работе с REST API обоих решений: и Gitea, и GitLab. Посему этот опыт может оказаться полезным не только для непосредственной миграции, но и повседневных задач.

Реализация: импорт, экспорт, перенос

Итак, перейдем к самой миграции. Оба проекта имеют развитый API. Выберем клиенты для работы с API обеих систем:

  • Для Gitea я выбрал Python-вариант giteapy. К сожалению, он не так хорош, как аналогичный для GitLab. (В процессе повествования ещё встретятся соответствующие ремарки.)

  • Для GitLab — python-gitlab.

Часть 1. Пользователи

Для подключения к GitLab используется единый класс:

import gitlab

gl = gitlab.Gitlab('https://gitlab.example.com', private_token='secret')

gl_users = gl.users.list(page=1, per_page=1000)

В giteapy для каждого раздела API есть свой подкласс. Их общее количество — 6, но нам потребуются только 4: AdminApi, OrganizationApi, RepositoryApi, UserApi. Вот как будет выглядеть код (полные итоговые листинги — см. в репозитории flant/examples):

import giteapy
configuration = giteapy.Configuration()
configuration.api_key['access_token'] = 'secret'
configuration.host = 'https://git.example.com/api/v1'

admin_api = giteapy.AdminApi(giteapy.ApiClient(configuration))
user_api_instance = giteapy.UserApi(giteapy.ApiClient(configuration))
org_api_instance = giteapy.OrganizationApi(giteapy.ApiClient(configuration))
repo_api_instance = giteapy.RepositoryApi(giteapy.ApiClient(configuration))

gt_users = admin_api_instance.admin_get_all_users()

И уже тут ожидал первый сюрприз:

{'avatar_url': 'https://gitea.example.com/user/avatar/user1/-1',
 'created': datetime.datetime(2018, 10, 11, 19, 0, 0, tzinfo=tzutc()),
 'email': 'user1@example.com',
 'full_name': 'User Name',
 'id': 2,
 'is_admin': False,
 'language': 'ru-RU',
 'last_login': datetime.datetime(2020, 10, 19, 8, 0, 0, tzinfo=tzutc()),
 'login': 'user1'}

Вы спросите: что же не так? Очень просто: в выводе API не видно, заблокирован пользователь или нет. Изучение всех возможных методов привело к необходимости запрашивать эту информацию из базы Gitea. Благо, это не такая уж и проблема — она решается простым запросом:

SELECT is_active FROM “user” WHERE id = <user_id>

Заблокированных пользователей было немного (около 10), и мы перенесли их вручную.

SSH-ключи

Логично предположить, что если стоит задача миграции, нам требуется перенести еще и SSH-ключи пользователей. В библиотеке клиента API Gitea описан метод user_current_get_key. Однако он работает странным образом:

  • если у пользователя много ключей, он возвращает всего один ключ;

  • если ключей нет — он возвращает ошибку 404.

При первичном переносе мы это обстоятельство не учли и использовали вызов API как есть. В результате были получены неверные ключи — их не хватало. Поэтому настоятельно советую использовать метод user_list_keys. Однако и с ним нас ждал подвох: в базе отсутствует уникальный индекс по fingerprint.

Indexes:
    "public_key_pkey" PRIMARY KEY, btree (id)
    "IDX_public_key_fingerprint" btree (fingerprint)
    "IDX_public_key_owner_id" btree (owner_id)

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

# clean blocked users keys
for block_gl_user in gl.users.list(blocked=True, page=1, per_page=10000):
    print("Blocker user", block_gl_user.username)
    for block_gl_user_key in block_gl_user.keys.list():
        print("Found key", block_gl_user_key.title)
        block_gl_user_key.delete()

Права

Следующий шаг — выдача верных прав. Организации Gitea преобразуются в группы GitLab, а команды преобразуются в права доступов.

Получив все команды из API, мы согласовали с клиентом матрицу сопоставления прав:

# map access rules
map_access = {'Owners': gitlab.OWNER_ACCESS,
              'Developers': gitlab.DEVELOPER_ACCESS,
              'QA': gitlab.DEVELOPER_ACCESS,
              'Manager':gitlab.REPORTER_ACCESS,
              'Managers': gitlab.REPORTER_ACCESS,
              'Dev': gitlab.DEVELOPER_ACCESS,
              'Services': gitlab.REPORTER_ACCESS,
              'services': gitlab.REPORTER_ACCESS}

# inspect Gitea orgs and create Gitlab groups
# get all orgs
gt_all_orgs = admin_api_instance.admin_get_all_orgs()
for gt_org in gt_all_orgs:
    # does the group exist?
    res = None
    try:
        res = gl.groups.get(gt_org.username)
    except:
        pass

    if res:
        # append existing groups to dictionary 
        dict_gl_groups[gt_org.username] = res
    else:
        # create the missing group
        gl_group = gl.groups.create({'name': gt_org.username, 'path': gt_org.username})
        if len(gt_org.description) > 0:
            gl_group.description = gt_org.description
        if len(gt_org.full_name) > 0:
            gl_group.full_name = gt_org.full_name
        gl_group.save()
        dict_gl_groups[org.username] = gl_group
    # list teams for the Gitea org
    gt_org_teams = org_api_instance.org_list_teams(gt_org.username)
    for team in teams:
        # get all team members
        members = org_api_instance.org_list_team_members(team.id)
        for user in members:
            # add members to groups with their access level
            # dict_gl_users was created on user creation step
            member = dict_gl_groups[gt_org.username].members.create({'user_id': dict_gl_users[user.login].id, 'access_level': map_access.get(team.name, gitlab.REPORTER_ACCESS)})

Почтовые уведомления

Что произойдет после этих манипуляций? Перенос пользователей «породит» массу почтовых сообщений: о создании пользователя, о предоставлении доступа и т.п. Поэтому стоит заранее решить, оставлять эту корреспонденцию или же перенаправить в чёрную дыру.

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

gl_user = gl.users.create({'email': gt_user.email,
                                   'password': password,
                                   'username': gt_user.login,
                                   'name': gt_user.full_name if len(gt_user.full_name) > 0 else gt_user.login,
                                   'admin': gt_user.is_admin,
                                   'skip_confirmation': True})

Кроме того, понадобится почтовый сервер, который будет все письма отправлять в /dev/null. Для этого подойдёт следующий конфиг Postfix:

relayhost = 
relay_transport = relay
relay_domains = static:ALL
smtpd_end_of_data_restrictions = check_client_access static:discard

В нашем случае клиент сначала попросил сделать вариант с отправкой почты в «черную дыру», а затем подтвердить все почтовые адреса. Если не прописать при создании пользователя skip_confirmation, то в дальнейшем, если потребуется подтвердить пользователей, это надо делать вручную. К сожалению, это известный баг GitLab: для подтверждения придется лезть в консоль Rails.

Промежуточные итоги

Проблемы, выявленные в Gitea за время этих операций:

  1. отсутствие важной информации о свойствах пользователя в API;

  2. неочевидные методы API для работы с ключами;

  3. дублирующиеся ключи.

С другой стороны, в GitLab есть проблема с подтверждением email. Итоговый скрипт миграции пользователей можно найти в нашем репозитории с примерами.

Часть 2. Репозитории

Теперь, когда готово дерево пользователей, можно произвести миграцию репозиториев. GitLab умеет импортировать проекты Gitea уже с версии 8.15. Однако всё не так просто, как хотелось бы.

Начнём с того, что надо добавить нашего пользователя, которого мы завели в Gitea для миграции, во все репозитории. В этом поможет такой скрипт.

all_orgs = admin_api_instance.admin_get_all_orgs()
for org in all_orgs:
    for repo in org_api_instance.org_list_repos(org.username):
        body = giteapy.AddCollaboratorOption()
        repo_api_instance.repo_add_collaborator(repo.owner.login, repo.name, 'import_user', body=body)

    teams = org_api_instance.org_list_teams(org.username)
    for team in teams:
        members = org_api_instance.org_list_team_members(team.id)
        for user in members:
            for repo in user_api_instance.user_list_repos(user.login):
                repo_api_instance.repo_add_collaborator(repo.owner.login, repo.name, 'import_user', body=body)

Здесь опущено подключение к API, так как пример был уже выше. Можно заметить еще одну проблему клиента к Gitea: в разных местах попеременно используется либо User ID, либо User Login. Местами это неудобно, т.к. требует постоянно сверяться с документацией.

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

nginx как решение двух недостатков в API

Для начала стоит отметить, что GitLab знает, что API Gitea устроен аналогично API GitHub, и использует Octokit Gem. Однако имплементация API у нас не является полной. Поэтому импорт периодически спотыкается. Есть 2 основных момента:

  1. Отсутствие rate_limit в API;

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

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

Первым делом разберемся с rate limit. Это встроенный метод, через который Octokit спрашивает, как часто он может отправлять запросы в API. При запросе к корневым методам Gitea отдаёт 404, что клиентом воспринимается как Unimplemented:

[13/Apr/2021:01:08:15 +0000] "GET /api/v1/rate_limit HTTP/1.1" 404 152 "-" "Octokit Ruby Gem 4.15.0"

Однако запрос к RepoApi возвращает 401, из-за чего импорт останавливается:

[13/Apr/2021:01:26:25 +0000] "GET /org1/project1.git/api/v1/rate_limit HTTP/1.1" 401 152 "-" "Octokit Ruby Gem 4.15.0"

Чтобы обойти это, сделаем такой location в nginx:

location ~* "\/api\/v1\/rate_limit$" {
  return 404;
}

Все запросы вернут 404 — миграция пойдёт без проблем.

Вторая проблемы была интереснее: Octokit делал запросы с мусорным префиксом. Допустим, у нас есть org1 с project1 и есть пользователь i.ivanov с project2 в личном пространстве имён. В логе nginx появятся странные запросы:

/org1/project1/api/v1/repos/org1/project1/labels?page=1&per_page=100
/org1/project1/api/v1/repos/org1/project1/milestones?page=1&per_page=100&state=all
/org1/project1/api/v1/users/i.ivanov
/i./api/v1/repos/i.ivanov/project2/labels?page=1&per_page=100
/i.ivanov/project2/api/v1/rate_limit

Легко заметить, что в случае с организацией Octokit добавил префикс /org1/project1, а в случае с пользовательским репозиторием были добавлены 2 префикса:

  • /i.

  • /i.ivanov/project2

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

rewrite '^\/([^\/]+)\/([^\/]+\.git)\/api\/v1\/repos\/([^\/]+)\/([^\/]+)\/([^\/]+)$' /api/v1/repos/$3/$4/$5;
rewrite '^\/([^\/]+)\/([^\/]+\.git)\/api\/v1\/users\/(.+)$' /api/v1/users/$3;

После этого проблемные запросы были переписаны и, наконец-то, импорт прошел успешно!

Полный импорт

Останется последняя проблема: у нас 160 проектов, которые надо импортировать в верные namespaces. К сожалению, импорт через API не позволяет сделать полный импорт и поддерживает только импорт архива, который не даёт загрузить merge requests, issues и другие вспомогательные вещи. Пришлось сделать скрипт, который бы работал с GitLab WebUI и отправлял запросы на импорт.

Я предпочел сделать скрипт для Selenium:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import os
import time

GITLAB_URL="https://gitlab.example.com/"
GITLAB_USER="user"
GITLAB_PASSWORD="pa$$word"
GITED_URL="https://gitea.example.com/"
GITED_TOKEN="superSecret"


driver = webdriver.Firefox(os.getcwd()+os.path.sep)
driver.get(GITLAB_URL)

# Gitlab login
user = driver.find_element_by_id("user_login")
user.send_keys(GITLAB_USER)
pas = driver.find_element_by_id("user_password")
pas.send_keys(GITLAB_PASSWORD)
login = driver.find_element_by_name("commit").click()

Затем, используя полученную сессию, запросим страницу импорта:

# Starting import process
driver.get(GITLAB_URL+"/import/gitea/new")
gitea_host = driver.find_element_by_name("gitea_host_url")
gitea_host.send_keys(GITED_URL)
gitea_token = driver.find_element_by_name("personal_access_token")
gitea_token.send_keys(GITED_TOKEN)
process = driver.find_element_by_name("commit").click()

А теперь начнём импорт всех репозиториев. Для этого инициализируем подключение к Gitea и начнём импортировать репозитории:

# iterate over table and import repos step by step
wait = WebDriverWait(driver, 10)
table =  wait.until(EC.presence_of_element_located((By.XPATH, '//table')))
for row in table.find_elements_by_xpath(".//tr"):
  group=row.get_attribute("data-qa-source-project").split("/")[0]
  # clicking select button to show dropdown menu and activate buttons
  row.find_element_by_class_name("gl-dropdown-toggle").click()
  time.sleep(1)
  # Finding project group
  for btn in row.find_elements_by_class_name("dropdown-item"):
    if btn.get_attribute("data-qa-group-name") == group:
      btn.click()
  time.sleep(1)
  # starting import
  import_button = row.find_element(By.XPATH, "//button[@data-qa-selector='import_button']")
  import_button.click()
  while True:
    time.sleep(10)
    # Wait until 
    status = row.find_elements_by_class_name("gl-p-4")[-1].text
    if status == "Complete":
      break

Казалось бы, вот и всё! Но это, к сожалению, не так.

Финальный штрих

После миграции мы временно подключили GitLab к Jenkins и получили ошибку:

fatal: couldn't find remote ref refs/merge-requests/184/head

Оказалось, что при переносе были потеряны Git references. Чтобы это исправить, мы решили во все ветки, которые имеют открытые merge requests, сделать пустые коммиты. Это действие пересоздаст references.

Вот реализация такого workaround:

shutil.rmtree('code',ignore_errors=True)

all_orgs = gl.groups.list()
skip_orgs = ['org1','org2']
for org in all_orgs:
    if org.name in skip_orgs:
        print("Skip group", org.name)
        continue
    projects = org.projects.list(all=True)
    for project in projects:
        id=project.id
        mrs=gl.projects.get(id=id).mergerequests.list(state='opened', sort='desc',page=1, per_page=10000)
        os.mkdir('code')
        print(subprocess.run(["git", "clone", project.ssh_url_to_repo, "code"], capture_output=True))
        for mr in mrs:
            print(project.name, id, mr.title, mr.source_branch, '=>', mr.target_branch)
            print(subprocess.run(["git", "checkout", mr.source_branch], cwd='code', capture_output=True))
            print(subprocess.run(["git", "pull"], cwd='code', capture_output=True))
            print(subprocess.run(["git", "commit", "--allow-empty", "-m", "Nothing here"], cwd='code', capture_output=True))
            print(subprocess.run(["git", "push"], cwd='code', capture_output=True))
        shutil.rmtree('code',ignore_errors=True)

После выполнения скрипта всё заработало корректно.

Полные листинги Python-скриптов, приведённых в статье, доступны в репозитории flant/examples.

Получившаяся инсталляция GitLab. В неё были добавлены новые пользователи, а некоторые старые проекты удалены
Получившаяся инсталляция GitLab. В неё были добавлены новые пользователи, а некоторые старые проекты удалены

Выводы

Миграция из Gitea в GitLab, несмотря на кажущуюся простоту, оказалась непростой задачей. Чтобы добиться результата, пришлось написать ряд скриптов и пройти через множество неожиданных нюансов из-за неполноты в реализации и совместимости разных API. Тем не менее, это удалось, и надеюсь, что полученный опыт поможет кому-нибудь в миграции и облегчит жизнь.

P.S.

Читайте также в нашем блоге:

Комментарии (29)


  1. oxdef
    24.09.2021 13:07
    +9

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

    Интересно узнать подробности о том, почему связка Gitea + внешний CI/CD (тут Jenkins) оказалась настолько неудобной, что решились на замену всего стека.


    1. Borz
      24.09.2021 14:03
      +1

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


      1. shurup
        24.09.2021 16:38
        +1

        Не только, но преимущественно — да. Потому что так накапливается опыт/инструменты, с которыми создается добавленная стоимость, чтобы оказывать услуги эффективно и качественно (а не просто перепродавать чьи-то часы работы).


        1. Borz
          24.09.2021 23:12
          +1

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


          1. shurup
            25.09.2021 03:39
            +6

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

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

            У нас K8s-дистрибутив, который одинаково работает на разных провайдерах (в т.ч. на on-prem bare metal или OpenStack), сертифицированный в CNCF по соответствию базовым API оригинального K8s. Такой подход позволяет пользователю не быть ограниченным одним провайдером, а это огромная изначальная ценность Kubernetes, которую "съели" managed-сервисы крупных провайдеров.

            Если же такой подход кажется неподходящим... что ж, это рынок, он рассудит :-)


            1. Borz
              25.09.2021 17:48
              +2

              ну, у вас на сайте в качестве примеров есть "кластер Kubernetes в AWS", но вы всё же настаивали на переезде именно на вашу инфраструктуру с хостинга AWS.
              Хотя, может я тогда вас и не дослушал/недопонял и вы предлагали поднять свой "K8s-дистрибутив" на базе AWS, вместо использования их EKS...


              1. shurup
                26.09.2021 05:29
                +2

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

                Потому что написанное на сайте - правда. У наших клиентов работают кластеры и в разных публичных провайдерах (AWS, GCP, Azure, Яндекс.Облако...), и в частных (OpenStack, vSphere), и на обычном bare metal.


                1. Borz
                  26.09.2021 12:24

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


    1. n_bogdanov Автор
      24.09.2021 14:04
      +1

      Ну тут-то как раз загадки нет. Дешевле поддерживать один универсальный сервис, который объединял бы в себе сразу 3 других: Git storage, CI/CD и Registry. Кроме того Флант имеет богатый опыт поддержки Gitlab, который не ограничивается только CI/CD, но и покрывает другие аспекты: бэкап, обновление и мониторинг.


      1. oxdef
        24.09.2021 14:57
        +5

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


        1. shurup
          24.09.2021 16:36
          +2

          Максимально пристрастная точка зрения, но, если сразу смотреть с этим пониманием, то все-таки неплохо для старта (потому что довольно подробно) — здесь.

          Взгляд с другой стороны — здесь.

          Истина где-то посередине и в зависимости потребностей.


  1. bohdan-shulha
    24.09.2021 14:07
    +5

    Мне кажется, не указали самого главного - сколько это стоило заказчику (денег и времени) и какой экономический эффект от переезда (денег и ускорения процессов).


    1. Flux
      24.09.2021 15:16
      +4

      Заказчику сделали вендор лок за его же деньги.


      1. shurup
        24.09.2021 16:27
        +2

        Vendor lock — это про стоимость ухода с текущего решения на другие. GitLab выглядит куда меньшим vendor lock'ом (чем Gitea) в силу своей куда большей распространенности.


        1. Areso
          24.09.2021 16:39
          +2

          Экосистема Windows Server+dotnet+ASP+MSSQL server была самой популярной в свое время. Была ли она от этого меньшим вендор локом? Нет

          Или AWS сегодня. Самое популярное облако в мире. Тут, надеюсь, никто не станет спорить, что этот пример - пример прямо абсолютного вендорлока


          1. shurup
            24.09.2021 16:44
            +2

            Была ли она от этого меньшим вендор локом? Нет

            Зависит от того, что и с чем сравнивать. Тут мы сравниваем два Open Source-проекта. Один из которых значительно (ну, уж на порядок — точно) популярнее другого.

            P.S. Не думаю, что указанный выше стек был самым популярным. Для меня таковым являлся Linux + Apache. Но не суть…


            1. shurup
              24.09.2021 17:01
              +2

              И ещё важно в данном случае (если уж сравнивать с другими примерами): а) оба этих продукта - self-hosted и б) работают поверх одной и той же Git (а не на разных систем версионирования, что потребовало бы дополнительных манипуляций на уровне самого хранилища).


            1. Areso
              24.09.2021 17:52

              Хорошо. Давайте сравним.

              Gitlab CE, по факту, владеет некая компания, которая целиком и полностью направлеяет развитие проекта. Что она захочет - то и будет, остальным остается только лобзиком сбоку приделывать свои доработки и потом их мигрировать с версии на версию (что, между прочим, существенная работа).

              Gitea - community-driven решение. В случае большого конфликта, с примерно равными позициями, можно форкнуть еще раз проект.


              1. shurup
                24.09.2021 18:33
                +2

                Думаете, в этом больше рисков, чем в том, что менее популярное решение не будет достаточно хорошо развиваться (потому что к нему меньше интереса и у пользователей, и у разработчиков, и нет стабильной финансовой поддержки)? Мне так не кажется.

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


            1. dravor
              24.09.2021 18:18
              +4

              Зависит от того, что и с чем сравнивать. Тут мы сравниваем два Open Source-проекта. Один из которых значительно (ну, уж на порядок — точно) популярнее другого.

              Не надо ничего ни с чем сравнивать. Gitea ставится на любой слабый комп с современной ОС, пул настроек минимальный, просто работает и позволяет получить свой собственный маленький github, с пулреквестами, Milestone, WiKi, а также смузи и штаны с подворотами.
              GITLab потребует в 5-10 раз больше ресурсов, админа и много чего еще. Вендорлок здесь в том, что теперь для сопровождения нужно больше специалистов и ресурсов. Прощай возможность сделать apt-get и через 10 минут работать, наблюдая как выделение памяти остановилось на 1Гб.
              Оправдывают такие расходы будущие доходы — в статье демонстративно этот вопрос обошли стороной. Так что да, сейчас выглядит как «заказчика заставили заплатить за переезд в систему, в которой удобней работать исполнителю».


              1. shurup
                24.09.2021 18:37
                +2

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

                Вычислительные ресурсы в данной конкретной истории совсем не те, чтобы это было значительной разницей.


                1. Areso
                  24.09.2021 18:39
                  +1

                  А до вашего прихода оно же как-то работало? Оно бы и дальше продолжило работать, но тут пришли люди с синдромом not-invented-here, ой, not-supported-here, и как-то умудрились продать весь этот процесс ЛПР.


                  1. shurup
                    25.09.2021 11:51
                    +3

                    В "Как-то работало" и "как-то умудрились продать" чувствуется одновременно и противоречие, и разгадка для конкретного случая :-) За услугами не приходят просто так, когда все, что уже есть сейчас, бизнес устраивает... Проблемы были - и в том числе из-за того, что в схеме участвовала не только маленькая и делающая свое дело Gitea, но ее связка с Jenkins. И эта реализация не была достаточно гибкой и прозрачной, приносила и больше непонятного поведения, и сложности в процессе отладки. Но мы писали не об этом, а о пути, который посчитали оптимальным, учитывая многие факторы и в конечном счёте эффективность для бизнеса.

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

                    У статьи вообще не было умысла продвигать идею миграции с Gitea на GitLab как таковую. Материал для тех, кто такое решение уже принял или имеет свои причины его рассматривать. Для "убеждения" в такой миграции, как я уже писал, надо делать отдельную и совершенно другую статью, потому что раскрывать в ней надо бизнесовые темы (метрики, риски...) и весьма осторожно, т.к. случаи индивидуальны, а критериев - много. Сейчас же складывается впечатление, как будто мы призвали всех делать такую миграцию. Но этого не было и нет.

                    Если же переходит к теме бизнеса, то он ориентируется на свои показатели (метрики вроде скорости доставки новых версий бизнес-критичного софта) - ему они важны, а не то, какая Open Source-утилита будет под капотом для достижения адекватных значений. Нужен практический результат. Да, конечно, важен ещё фактор упомянутого vendor lock-in, потому что это финансовые риски, но конкретно эту тему уже в комментариях раскрыли достаточно, по-моему; аргументы приведены были, а выводы каждый волен делать сам.


              1. creker
                24.09.2021 22:59

                Справедливости ради, админить в гитлабе особо нечего. А вот ресурсы да. Жрет гитлаб непомерно, при этом все равно тормозит.


                1. shurup
                  25.09.2021 12:01
                  +2

                  Сравнивая все подобные показатели, надо ещё помнить, что GitLab пришел на замену не только Gitea, но её связке с Jenkins.


              1. shurup
                25.09.2021 12:12
                +3

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

                Не увидел этого примечания вчера. Как уже написал в комментарии выше, заказчик платит за то, чтобы получать результат для бизнеса, а инструменты для него вторичны. Если заказчик принципиально требует использования какой-то конкретной системы (а ее использование все же сопряжено с проблемами), на то должны быть весомые причины*, надо их отдельно обсуждать и приходить к компромиссу. А если нет компромисса, то искать другого исполнителя, и всем будет хорошо.

                * В данном случае их не было. Здесь в комментариях они тоже по сути свелись к "работает - не трогай" без знания всей ситуации. А в плане более простой поддержки того, что было, дополни свои ответы напоминанием, что речь шла не про одну Gitea, а про Gitea+Jenkins.


    1. shurup
      24.09.2021 16:32
      +1

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


      1. Borz
        24.09.2021 23:20
        +2

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

        Вы потратили вагон с тележкой времени и ресурсов на миграцию не просто "по фану" же? И не ради одного аргумента "нам так проще обслуживать, так как для нас это шаблонная работа будет"


        1. shurup
          25.09.2021 11:56
          +2

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