惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LINUX DO - 最新话题
C
Cyber Attacks, Cyber Crime and Cyber Security
G
GRAHAM CLULEY
T
Tenable Blog
T
Threatpost
C
CXSECURITY Database RSS Feed - CXSecurity.com
I
Intezer
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
D
Darknet – Hacking Tools, Hacker News & Cyber Security
K
Kaspersky official blog
Security Latest
Security Latest
P
Privacy & Cybersecurity Law Blog
Google Online Security Blog
Google Online Security Blog
SecWiki News
SecWiki News
P
Palo Alto Networks Blog
TaoSecurity Blog
TaoSecurity Blog
Webroot Blog
Webroot Blog
Spread Privacy
Spread Privacy
O
OpenAI News
The Last Watchdog
The Last Watchdog
P
Proofpoint News Feed
C
Check Point Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
人人都是产品经理
人人都是产品经理
S
Security @ Cisco Blogs
Scott Helme
Scott Helme
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
月光博客
月光博客
S
Securelist
酷 壳 – CoolShell
酷 壳 – CoolShell
V
V2EX
T
Troy Hunt's Blog
W
WeLiveSecurity
GbyAI
GbyAI
N
News | PayPal Newsroom
Y
Y Combinator Blog
C
Cisco Blogs
H
Help Net Security
The GitHub Blog
The GitHub Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园 - 【当耐特】
Jina AI
Jina AI
MongoDB | Blog
MongoDB | Blog
P
Proofpoint News Feed
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
云风的 BLOG
云风的 BLOG
小众软件
小众软件
N
News and Events Feed by Topic

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Настройка GitLab CI/CD: понимаем принципы работы и запускаем первый pipeline
gtosss · 2026-05-05 · via Все публикации подряд на Хабре

Уровень сложностиПростой

Время на прочтение13 мин

Охват и читатели254

Туториал

Настройка GitLab CI/CD: понимаем принципы работы и запускаем первый pipeline

Все найденные мной русскоязычные гайды не дают базового понимания того, как это работает, по большому счету это просто инструкции по настройке, причем под какой-то конкретный продукт и кейс: .net, Java, Node JS, etc.

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

  • Максимально много функционала, которыми обладает Gitlab (общие абстракции актуальны и для его аналогов).

  • Инструменты которые нужны: Bash, Docker, Kubernetes и другие.

  • Общую теорию и практику с конкретными сценариями.


Материал разбит на 3 части.

  1. [Вы здесь → ] Простейший пример ci-cd

  2. [in progress 80%] Более зрелый CI/CD (выход в продакшн, self-hosted runner и работа с registry)

  3. [todo] Горизонтальное масштабирование CI/CD (высоко-нагруженный продакшн)

Оглавление

  • В чем идея CI/CD?

  • Терминология

  • Простейший CI/CD (разработка, MVP)

    • Простой пример .gitlab-ci.yml

    • Схема работы простейшего CI/CD

    • Практика с простейшим шаблоном CI/CD


В чем идея CI/CD

Даже начинающему разработку интуитивно понятно что такое CI/CD и для чего оно нужно. Отправили коммиты с изменениями в репозиторий — нужно исходный код превратить в собранное приложение и развернуть его на dev/test/prod стенде. Можно зайти на VPS и все сделать вручную: git clone, запустить автотесты, сделать сборку и запустить собранное приложение, при этом старое запущенное приложение, нужно заменить новым билдом. Автоматизацию этого процесса и назвали CI/CD. В эту аббревиатуру навалили сразу несколько значений которые всегда делаются рядом друг с другом и часто эти действия трудно однозначно классифицировать.

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

Терминология

CI (continues integration, непрерывная интеграция) — действия необходимые для интеграции новых изменений в имеющуюся кодовую базу.

Continues integration включает в себя следующее:

  • объедение всех изменений в одну точку

  • установку зависимостей

  • статистические проверки кода (типизация, линтеры)

  • запуск тестов (Unit, интеграционные, e2e)

  • проверка работоспособности сборки (убедиться что сборка возможна)

  • сборка кодовой базы. Это может быть как сборка библиотеки в соответствующий формат (например, npm-модуль, PyPI-пакет, Go-модуль), так и сборка в конечный исполняемый формат (.jar, .whl, bundle, Docker-контейнер, .exe-файл и т. д.) Результат сборки принято называть артефактом.

  • загрузка артефакта в специализированное хранилище для дальнейшего использования и версионирования. Такие хранилища часто называют registry (npm registry, Docker Registry, PyPI) или hub (Docker Hub), а также repository manager (Nexus, Artifactory, GitHub Packages).

CD (continues delivery, непрерывная доставка) — действия необходимые для доставки артефакта в место назначения (сервер где он будет выполняться). На этом этапе определяется куда будет доставлен артефакт, на dev, test, pre-prod(stage), prod.

Continues delivery включает в себя следующее:

  • Получение артефакта на целевом сервере

CD (continues deployment, непрерывное развертывание) — Действия необходимые для запуска уже доставленного артефакта.

Continues deployment включает в себя следующее:

  • Запуск артефакта

  • Миграция БД (если наш артефакт ее использует)

  • Запуск e2e тестов. Именно тех чья функция заключается в том, что бы проверить целостность работы системы. Некоторые e2e могли быть запущены еще на этапе CI.

  • Тут может быть так же механизм отката к предыдущей версии.

Delivery и Deployment на практике часто смешивается в одно целое “доставили и сразу запустили”. А если приблизиться к реальности еще больше и отдалиться от академических определений — часто на практике все 3 части смешиваются в один большой конвеер который и называется единым словом CI/CD или CICD. Таким образом, на практике все может быть свалено в одну большую кучу и например запуск тестов или миграций можно встретить совсем не в той последовательности, которая встречается в учебниках и теоритических статьях.

Pipeline (пайплайн) — это цепочка всех шагов необходимых для реализации CI/CD, каждый шаг это stage (стадия, этап), внутри каждого stage запускаются jobs (джобы, задачи). Если один этап падает, дальнейшие шаги отменяются. Дословно с английского переводиться как “трубопровод”, соответственно для носителя языка это ассоциируется с каким-то промышленным трубопроводом, который построен с целью доставки чего-то из точки A в точку B.

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

job (джоба) — конкретное действие или скрипт.

Runner (раннер) GitLab — runner выполняет джобы в пайплайне. Runner умеет выполнять джобы параллельно друг другу, использовать разные экзекьютеры (executors). Раннер можно установить отдельно на вашу машину и тогда gitlab будет просить его выполнять все инструкции.

Executor (экзекьютер) — способ выполнения скриптов описанных в джобах, например может работать в docker или сразу на целевой машине в bash.

Все варианты экзекьютеров

Всего есть такие варианты:

  • Docker — Самый популярный, все джобы изолировано в одноразовых контейнерах.

  • Docker Machine (deprecated в пользу Autoscaler) — будет удален в 2027-ом.

  • Docker Autoscaler — Замена Docker Machine, автоматически управляет виртуальными машинами с Docker.

  • Custom — Для нестандартных случаев, когда какой-то самописный или малоизвестный механизм оркестрации. Полная кастомизация и контроль, но и все сопустсвующие подводные камни.

  • Instance — Каждая джоба, отдельная преднастроенная виртуалка.

  • Kubernetes — Джобы запускаются как поды в кластере. Можно использовать если уже настроен кластер k8s.

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

  • SSH — Тоже как Shell, но через SSH подключение.

  • Parallels — Адаптация под Parallels Desktop for Mac, это коммерческий гипервизор позволяющий запускать Windows/Linux на маке. Короче решение для тех у кого слишком много лишних денег (возможно полезен тем кто специализируется на iOS/macOS разработке).

  • VirtualBox — Полная виртуализация для каждой джобы в виртуалках VirtualBox.

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

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

Простейший CI/CD (разработка, MVP)

В этом разделе рассмотрим конфигурацию и схему простой реализации CI/CD которая подойдет на этапе разработки или MVP.

Простой пример .gitlab-ci.yml

Все начинается с репозитория, а точнее с описанного в нем файла .gitlab-ci.yml (документация GitLab по gitlab-ci.yml). Этот файл содержит все инструкции, которые нужно выполнить для целей CI/CD.

Рассмотрим простейший пример, который GitLab предлагает в качестве стартового шаблона .gitlab-ci.yml:

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

stages:          # Список stages (стадий) для jobs и порядок их выполнения
  - build
  - test
  - deploy

build-job:       # Джоба build, выполняемая в первую очередь
  stage: build
  script:
    - echo "Compiling the code..."
    - echo "Compile complete."

unit-test-job:   # Запуск тестов
  stage: test    # Запустится только если build прошел успешно
  script:
    - echo "Имитация запуска unit-тестов... с задержкой 60 секунд"
    - sleep 60
    - echo "Покрытие кода в районе 90%"

lint-test-job:   # Еще одна джоба, которая относится к стадии "test"
  stage: test    # Так как она тоже относится к стадии "test", будет запущена параллельно
  script:
    - echo "Проверка кода линтером... Задержка 10 секунд."
    - sleep 10
    - echo "Нет ошибок линтера."

deploy-job:      # Само развертывание (deploy)
  stage: deploy  # Запустится только если все джобы из стадии "test" завершились успешно
  environment: production
  script:
    - echo "Развертывание приложения..."
    - echo "Приложение развернуто."

Когда GitLab отслеживает изменение в репозитории, он передает инструкции из .gitlab-ci.yml раннеру. Раннер, в свою очередь, использует указанный executor для выполнения команд. Подробнее о поддерживаемых executors — в документации GitLab.

Runner (раннер) GitLab — это программа, которая выполняет инструкции в указанном окружении. Executor определяет, в каком именно окружении будут выполнены команды. Так как в примере используются только базовые утилиты echo и sleep, подойдет практически любой executor:

  • Docker — каждая джоба запускается в изолированном Docker-контейнере на основе указанного образа.

  • Shell — команды выполняются напрямую в оболочке хост-системы, где установлен раннер.

  • Kubernetes — джобы выполняются в подах кластера Kubernetes.

  • SSH — команды выполняются на удаленной машине через SSH-соединение.

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

Если вы используете не Self Hosted Gitlab (который поднят в вашей инфраструктуре), а GitLab.com (SaaS-инстанс) по умолчанию будет использован shared runners, который в стандартной конфигурации использует Docker executor — каждая джоба запускается в изолированном контейнере.

Схема работы простейшего CI/CD

Схема на примере когда:

  • Используется gitlab.com (не self hosted)

  • Runner установлен на вашем сервере

  • Используется docker executor

  • Используется вышеописанный шаблон .gitlab-ci.yml (4 джобы)

Если build-job создает какой-то артефакт, его можно расположить в каком-то хранилище. Если довольствоваться самой простой и быстрой реализацией, можно исключить работу с registry (хранилищем артефактов). Часто на начальных этапах разработки так и поступают, вместо дополнительных действий с registry происходит следующее: раннер поднимает контейнер в котором происходит подключение по SSH к целевому серверу, на целевом сервере уже установлен docker и git, по этому в рамках подключения SSH достаточно сделать git pull, docker run, а старый контейнер просто гасят. Это работает когда в репозитории разработчика есть Dockerfile который делает все необходимое для запуска приложения: установка зависимостей, сборка и запуск.

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

  • Downtime — нужно положить старый контейнер, поднять новый, приложение недоступно пока происходит сборка нового контейнера.

  • Сборка нагружает production сервер

  • Нет истории артефактов, нет возможности откатиться к прошлому артефакту, если с новым что-то пошло не так.

  • Не подходит для горизонтального масштабирования.

  • Уязвимая инфраструктура — доступ к серверу прода попадает в gitlab (ssh ключи), а на сервере прода есть доступ к репозиторию.

  • Исходный код присутствует на сервере прода.

  • Docker хранит свои слои и кэш на сервере прода.

При этом у многих такой подход живет в проде и ничего страшного не случается (до поры до времени).

Практика с простейшим шаблоном CI/CD

Закоммитим и запушим данный .gitlab-ci.yml файл gitlab и посмотрим что произойдет.

Переходим к списку пайплайнов

Переходим к списку пайплайнов

Обзор списка пайплайнов

Обзор списка пайплайнов

Просмотр конкретного пайплайна

Просмотр конкретного пайплайна

При просмотре пайплайна, gitlab визуализирует наши stages и jobs. Всего у нас 4 джобы. 2 параллельных lint-test-job и unit-test-job они находятся в стадии test. Перейдем в unit-test-job и посмотрим что gitlab нам отобразит:

Логи джобы unit-test-job

Логи джобы unit-test-job

В .gitlab-ci.yml это описано так:

unit-test-job:   # Запуск тестов
  stage: test    # Запустится только если build прошел успешно
  script:
    - echo "Имитация запуска unit-тестов... с задержкой 60 секунд"
    - sleep 60
    - echo "Покрытие кода в районе 90%"

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

Running with gitlab-runner 18.10.0~pre.705.ge11dde90 (e11dde90)
  on green-4.saas-linux-small-amd64.runners-manager.gitlab.com/default ntHFEtyXQ, system ID: s_8990de21c550
  feature flags: FF_USE_GIT_PROACTIVE_AUTH:true
Подробно
Running with gitlab-runner 18.10.0~pre.705.ge11dde90 (e11dde90)

Используется gitlab-runner версии 18.10.0 (pre-release сборка).
e11dde90 — Судя по всему хэш-коммита.

on green-4.saas-linux-small-amd64.runners-manager.gitlab.com/default ntHFEtyXQ

Имя хоста runner’а: green-4.saas-linux-small-amd64.runners-manager.gitlab.com:
green-4 — конкретная нода
saas-linux-small-amd64 — тип машины: SaaS (облако GitLab), Linux, small (малый размер ресурсов), архитектура amd64
ntHFEtyXQ — видимо просто ID раннера (но почему-то в UI мы увидим этот ID без последнего символа).
Исходя из всего этого складывается впечатление, что это shared runner от GitLab (не self-hosted). system ID: s_8990de21c550 — Уникальный системный идентификатор машины, на которой работает runner. Узнал из документации gitab API.
feature flags: FF_USE_GIT_PROACTIVE_AUTH:true — Определяет стратегию авторизации которую использует Gitaly. Gitaly — это программный модуль разработанный gitlab для удаленного управления репозиториями GIT.
Документация по Gitaly.
Документация гитлаб о feature flags.
Документация proactiveAuth GIT.

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

Раннер выполнишвий нашу джобу

Раннер выполнишвий нашу джобу

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

Двигаемся по логам дальше и видим:

Preparing the "docker+machine" executor
Using default image
Using Docker executor with image ruby:3.1 ...
Using default image
Using effective pull policy of [always] for container ruby:3.1
Pulling docker image ruby:3.1 ...
Using docker image sha256:9981... for ruby:3.1 with digest ruby@sha256:9162...
Подробно
Preparing the "docker+machine" executor

Тип executor’а docker+machine — Он кстати deprecated уже года 4 и gitlab выбрал другое направление развития — Autoscaler. Странно почему до сих пор используется в shared runners. Подробнее docker+machine. В двух словах этот экзекьютор умеет поднимать полноценные виртуальные машины, а внутри уже запускать docker. Зачем гитлабу виртуализация, если есть контейнеризация? Коротко — безопасность, фикс проблемы известной под именем container escape.

Using default image
Using Docker executor with image ruby:3.1 ...

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

Using effective pull policy of [always] for container ruby:3.1

Политика скачивания образа always — то есть всегда скачивать, даже если есть локально.

Pulling docker image ruby:3.1
Using docker image sha256:9981... for ruby:3.1 with digest ruby@sha256:9162...

Информация об успешном скачивании docker образа ruby:3.1 из docker hub.

Нам говориться о подготовке экзекьютора и загрузке docker образа. Читаем дальше:

Preparing environment
Using effective pull policy of [always] for container sha256:c11...
Running on runner-nthfetyxq-project-79632759-concurrent-0 via runner-nthfetyxq-s-l-s-amd64-1775396763-e03183f3...
Getting source from Git repository
Gitaly correlation ID: 73b6c9732c8240b7b5a1937a1eaac112
Fetching changes with git depth set to 20...
Initialized empty Git repository in /builds/webstap/self-server-config/.git/
Created fresh repository.
Checking out 3575359a as detached HEAD (ref is main)...
Skipping Git submodules setup
$ git remote set-url origin "${CI_REPOSITORY_URL}" || echo 'Not a git repository; skipping'
Подробно
Preparing environment
Using effective pull policy of [always] for container sha256:c11...

Runner поднимает вспомогательный контейнер (это уже другой, не тот который ruby:3.1). Контейнер ruby:3.1 имеет другой хэш 9981, он предназначен для наших jobs. Контейнер о котором сейчас идет речь имеет другой хэш c11, он нужен раннеру для клонирования git репозитория, работой с кэшем/артефактами и всем тем что происходит до и после нашего пользовательского скрипта.

Running on runner-nthfetyxq-project-79632759-concurrent-0 via runner-nthfetyxq-s-l-s-amd64-1775396763-e03183f3...

Тут указывается 2 имени:
Первое имя — контейнер который будет запускаться.
Второе имя — виртуальная машина на которой будет запускаться контейнер, в ней есть Docker daemon за счет которого и запуститься контейнер.

Имя контейнера состоит из:

runner-nthfetyxq-project-79632759-concurrent-0
       │                 │                   │
       │                 │                   └─ Слот конкурентности (первый из N)
       │                 └─ ID проекта в GitLab
       └─ Токен/ID раннера (короткий хеш)

Имя виртуальной машины состоит из:

via runner-nthfetyxq-s-l-s-amd64-1775396763-e03183f3
           │         │ │ │  │        │      │
           │         │ │ │  │        │      └─ ID инстанса (VM)
           │         │ │ │  │        └─ Похоже на Timestamp или порядковый номер
           │         │ │ │  └─ Архитектура: amd64
           │         s-l-s = shared/linux/small (тип машины)
           └─  Токен/ID раннера (короткий хеш)
Gitaly correlation ID: 73b6c9732c8240b7b5a1937a1eaac112

Ранее мы уже говорили о Gitaly. Тут просто указан ID для трассировки. Простыми словами это конкретный ID операции, который позволит отыскать ее в логах.

Fetching changes with git depth set to 20...

Информация о том, что runner выполнит что-то вроде:

git init
git remote add <наш репозиторий>
git fetch origin --depth 20 

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

Initialized empty Git repository in /builds/webstap/self-server-config/.git/
Created fresh repository.

Инициализирован пустой git репозиторий в файловой системе внутри контейнера.

Checking out 3575359a as detached HEAD (ref is main)...

Было выполнено git checkout 3575359a — переключение на конкретный коммит (не на ветку). Переключение именно на коммит важно в условиях CI — пока запускался пайплайн, в ветку могли прилететь сверху еще коммиты, но пайплайн предназначен строго для конкретного коммита, по этому раннер ориентируется строго по коммитам, а не по веткам.

Skipping Git submodules setup

Подмодули не настроены (нет GIT_SUBMODULE_STRATEGY в .gitlab-ci.yml). Подробнее.

git remote set-url origin "${CI_REPOSITORY_URL}" || echo 'Not a git repository; skipping'

CI_REPOSITORY_URL — predefined переменная. Содержит полный путь к репозиторию. Ее значение:

https://gitlab-ci-token:$CI_JOB_TOKEN@gitlab.example.com/my-group/my-project.git

Это команда перезаписывает URL remote origin, чтобы последующие git операции были авторизованы.

|| echo 'Not a git repository; skipping

Если не удалось выполнить git remote будет просто написано “Not a git repository; skipping”, это нужно что бы джоба не упала, на случай если работа не с git репозиторием.

GitLab Runner на виртуальной машине скачал два Docker-образа — ruby:3.1 для выполнения пользовательского кода и gitlab-runner-helper для служебных операций, затем helper-контейнер склонировал Git-репозиторий webstap/self-server-config (shallow clone, глубина 20 коммитов) в директорию /builds/webstap/self-server-config, переключился на конкретный коммит 3575359a из ветки main и подготовил рабочую среду для выполнения скриптов из .gitlab-ci.yml.

Осталось разобрать последнюю часть:

Executing "step_script" stage of the job script
Using default image
Using effective pull policy of [always] for container ruby:3.1
Using docker image sha256:9981... for ruby:3.1 with digest ruby@sha256:916... ...
$ echo "Имитация запуска unit-тестов... с задержкой 60 секунд"
Имитация запуска unit-тестов... с задержкой 60 секунд
$ sleep 60
$ echo "Покрытие кода в районе 90%"
Покрытие кода в районе 90%
Cleaning up project directory and file based variables
Job succeeded
Подробно
Using default image
Using effective pull policy of [always] for container ruby:3.1
Using docker image sha256:9981... for ruby:3.1 with digest ruby@sha256:916... ...

Подготовка контейнера для скрипта. Раннер поднимает новый контейнер из образа ruby:3.1, в котором будет выполняться наш скрипт из .gitlab-ci.yml.

$ echo "Имитация запуска unit-тестов... с задержкой 60 секунд"

Далее мы видим строку которая начинается с $ — гитлаб показывает саму команду, которую он запустит в контейнере. А затем stdout это команды (результат ее выполнения):

Имитация запуска unit-тестов... с задержкой 60 секунд

Аналогично далее:

$ sleep 60
$ echo "Покрытие кода в районе 90%"
Покрытие кода в районе 90%

Завершение:

Cleaning up project directory and file based variables
Job succeeded

“Cleaning up project directory” — Удаляются файлы проекта из рабочей директории /builds/webstap/self-server-config/.

“file based variables” — Удаляются временные файлы, созданные из CI/CD переменных типа File (для безопасности — чтобы секреты не остались на диске).

Job succeeded

Все команды вернули exit code 0 — то есть выполнены без ошибок.

Выполнен блок script из .gitlab-ci.yml джобы unit-test-job:

unit-test-job:   # Запуск тестов
  stage: test    # Запустится только если build прошел успешно
  script:
    - echo "Имитация запуска unit-тестов... с задержкой 60 секунд"
    - sleep 60
    - echo "Покрытие кода в районе 90%"

Ранее мы говорили об артефактах, в результате выполнения пайплайнов мы не создавали артефакты в скриптах наших джобов, но все же некоторые файлы были созданы и размещены в хранилище артефактов gitlab. Речь идет о файлах с логами. Просмотреть их можно если перейти в Build → Artifacts.

Просмотр артефактов

Просмотр артефактов

Мы рассмотрели как себя ведет шаблон CI-CD предложенный gitlab. Данную реализацию можно доработать таким образом, что одна из наших джобов подключалась через SSH к нашему VPS, заходила в определенную директорию, обновляла git репозиторий и поднимала контейнер. Но как я уже писал: у этого есть ряд недостатков.


С вами был Тимофей. Кто я?

Разрабатываю с 2015 года. Стартовал как front-end разработчик на React, после 6-лет переключился на full-stack, последние годы — чаще DevOps. Мой публичный WakaTime.


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