Сообщество / DevOps

Обсуждение — GitLab Runner на VPS: свой CI/CD-агент

Источник:
GitLab Runner на VPS: собственный CI/CD-агент за 15 минут

Свой GitLab Runner на VPS снимает лимиты бесплатных минут и даёт полный контроль над окружением сборки. Поставим агент с Docker-executor, зарегистрируем его и напишем пайплайн с деплоем. GitLab.com даёт ограниченный пул CI-минут, а на self-managed инсталляциях раннеров нет вовсе. Собственный агент на VPS решает обе проблемы: сборки идут без лимитов, а окружение вы контролируете полностью.

Подробнее →
kate_ekb
Junior
Сообщения: 37
Репутация: 12
Дата регистрации:
12.08.2026
АВТОР ТЕМЫ01 сент. 2026 г., 14:32 (GMT+3)
Гайд про свой раннер нормальный до места, где docker-executor и деплой встречаются в одном пайплайне.

Подняла агент, зарегистрировала, .gitlab-ci.yml как в примере — джоба зелёная. Дальше compose с nginx и wordpress. После второго прогона uploads пустые. Не баг раннера: в примере тома не зафиксированы, контейнер отработал и унёс wp_data с собой.

И сокет. Executor docker в тексте есть, а /var/run/docker.sock в volumes сервиса раннера — нет. Без проброса джоба либо не стартует, либо лезет не в тот демон. Это не тонкость CI, это ты порт не пробросил, только версия для пайплайна)

У меня раннер отдельным контейнером, сокет :ro, wordpress на своём томе, пайплайн трогает только nginx.conf и образ. Кто гоняет WP этим гайдом как есть — гляньте, что осталось от медиа после второй джобы. Или у вас тома сразу стояли?
0
tema_py
Junior
Сообщения: 25
Репутация: 11
Дата регистрации:
18.08.2026
02 сент. 2026 г., 19:00 (GMT+3)
kate_ekb ну ок, volumes, я в этом гайде тоже бы влетел)) uploads уехали со вторым прогоном, классика.
0
kate_ekb
Junior
Сообщения: 37
Репутация: 12
Дата регистрации:
12.08.2026
03 сент. 2026 г., 08:12 (GMT+3)

tema_py писал:
uploads уехали со вторым прогоном, классика.


не уехали — контейнер унёс анонимный том. Именованный wp_data, не bind в /tmp раннера. Сокет :ro ещё пробрось, пока «классика» не продолжилась)
0
lexa92
Junior
Сообщения: 59
Репутация: 20
Дата регистрации:
09.08.2026
03 сент. 2026 г., 09:27 (GMT+3)
Смотрел утром тот пример с сокетом. В volumes :ro, будто раннер в песочнице. Залез с хоста в docker ps из джобы — вижу все контейнеры, не «только пайплайн».

kate_ekb wp_data ты права, а :ro на /var/run/docker.sock файл не даёт подменить, api демона как был открытым, так и остался. Это не тонкость CI.
0
daniyar_ala
Junior
Сообщения: 21
Репутация: 4
Дата регистрации:
24.08.2026
03 сент. 2026 г., 10:04 (GMT+3)
lexa92, я как раз собирался wp через этот раннер гонять. Теперь думаю, джоба мне ещё и postgres остановит — я же «защитился» двоеточием ro. Так и есть?)
0
kate_ekb
Junior
Сообщения: 37
Репутация: 12
Дата регистрации:
12.08.2026
03 сент. 2026 г., 10:17 (GMT+3)

lexa92 писал:
Залез с хоста в docker ps из джобы — вижу все контейнеры


В обед села с ноута, прогнала test-job. В списке wordpress, nginx и redis, который зимой поднимала на пять минут и забыла. Джоба смотрит в тот же демон, что крутит прод.

Поэтому пайплайн у меня только nginx.conf кладёт и образ собирает. Никакого compose down в ci. :ro я ставила, чтобы раннер сокет файлом не затёр, не чтобы джоба ничего не увидела.

tema_py, ты уже влетел в тома — не пихай в ту же джобу docker stop, postgres ляжет следом)

daniyar_ala, да, так и есть. Двоеточие ro базу не закроет. Если в джобе есть docker, она остановит что угодно на хосте. У тебя в ci docker CLI вообще вызывается?
2
kate_ekb
Junior
Сообщения: 37
Репутация: 12
Дата регистрации:
12.08.2026
03 сент. 2026 г., 11:21 (GMT+3)

lexa92 писал:
вижу все контейнеры, не «только пайплайн»


tema_py, я из этой джобы exec в wordpress открыла. контейнер живой, шелл внутри)
0
andryukha
Junior
Сообщения: 40
Репутация: 15
Дата регистрации:
17.08.2026
03 сент. 2026 г., 12:37 (GMT+3)

kate_ekb писал:
Пайплайн у меня только nginx.conf кладёт и образ собирает.


kate_ekb, я не про сокет. открыл гитлаб в обед — 400 минут, потом платно. у тебя вордпресс, nginx, редис с зимы и ещё раннер рядом. окей, а сколько это в месяц по живому счёту, не «зато свой агент»? калькулятор у меня уже рефлекс))
2
kate_ekb
Junior
Сообщения: 37
Репутация: 12
Дата регистрации:
12.08.2026
03 сент. 2026 г., 13:08 (GMT+3)
andryukha redis с зимы так и крутится, забыла выключить. tema_py хоть в тома влетел, ты сразу калькулятор достал)
0
tema_py
Junior
Сообщения: 25
Репутация: 11
Дата регистрации:
18.08.2026
03 сент. 2026 г., 23:23 (GMT+3)
kate_ekb я как раз вечером в vscode сидел, когда ты про docker stop написала. второй монитор, .gitlab-ci.yml, стейдж deploy, курсор уже на новой строке. после тех томов первая мысль была тупая: ну хоть контейнер бота пересоберу по-человечески. и я уже набирал docker stop bot && docker rm bot. sqlite с бэкапом крутится рядом в другом контейнере, его бы эта же джоба увидела — так же, как ты из пайплайна wordpress увидела.

ты написала, что из джобы exec открыла, контейнер живой, шелл внутри. я это дочитал и строку стёр, даже в git add не пустил. вот что чуть уехало в репу. полчаса сочинял, «работает, я гений», и ты как обычно объяснила что нет))


deploy:
stage: deploy
tags:
- vps
script:
- docker stop bot || true
- docker rm bot || true
- docker build -t bot:latest .
- docker run -d --name bot --env-file /opt/bot/.env --restart unless-stopped bot:latest


на общем демоне это не «перезапустил своего бота». это «джоба видит вообще все контейнеры и может любой стопнуть». я после твоего exec запустил тестовую джобу с docker ps — в списке бот, сам раннер и nginx, который я под вебхук поднимал ещё в июле и забыл. :ro на сокете файл не даст подменить, api как был открытым, так и остался. lexa92 это уже написал, я просто своими глазами увидел.

пробовал сначала вообще сокет не пробрасывать. тесты на python 3.12 проходят, образ собирается, а контейнер на хосте как стоял, так и стоит со старым кодом. бот после пуша молчит, вебхук смотрит в старый процесс. без docker в ci мне этот деплой не закрыть, у тебя пайплайн только nginx.conf кладёт и образ собирает — мне надо ещё контейнер на этом же хосте обновить.

сейчас так, без stop и без rm. только up одного сервиса.


deploy:
stage: deploy
tags:
- vps
only:
- main
script:
- cd /opt/bot
- docker compose up -d --build --no-deps bot


--no-deps, чтобы соседний nginx с сертом не пересобрался по дороге. тома уже именованные, не bind в /tmp раннера, это я после прошлого раза руками переписал. healthcheck в compose так и не прописал, знаю, не бей сразу.

prune из джобы тоже выкинул. один раз почти добавил docker image prune -af, чтобы место не жрало — это бы снесло старые образы бота и заодно всё забытое. руки теперь не тянутся.

andryukha писал:
а сколько это в месяц по живому счёту, не «зато свой агент»?


я не вордпресс с редисом с зимы считаю. у меня бот и раннер на одном vps. на gitlab.com 400 минут сгорели за две недели: pytest плюс docker build, кэш не настроил, pip каждый раз качал колёса заново. один пайплайн 12–15 минут, пуш в main после работы — и к среде третьей недели баннер buy more minutes. это тоже счёт, просто его гитлаб присылает, а не хостер.

свой агент поставил на тот же uk, где бот живёт. раннер отдельным контейнером, тег vps, concurrent=1, чтобы два деплоя compose не схватили одновременно. начинал с Ba Lite, когда тесты и бот влезли впритык — перешёл на Uab и не жалею. в кабинете сумма как на сайте, гитлабовские минуты больше не покупаю. калькулятор у тебя рефлекс, ок, только считай не «вордпресс плюс редис плюс раннер», а «раннер вместо тех 400 минут, которые и так кончились».

песочницы из этого нет, я не спорю. джоба с docker cli теоретически напишет docker stop что угодно, даже если в yaml сейчас --no-deps. privileged в config.toml не включал, хотя в гайде как будто само собой. executor docker, каталог cache раннера не в /tmp — это уже проверил не по гайду с телефона, а зайдя на хост.

у кого пайплайн только тесты гоняет, без деплоя на тот же хост — вам проще, сокет можно не пробрасывать вообще. мне надо бота обновить с этого демона, вот и живу с открытым api. а у кого так же деплой в тот же docker — stop из джобы уже выкинули или ещё нет?
1
masha_spb
Junior
Сообщения: 34
Репутация: 16
Дата регистрации:
11.08.2026
04 сент. 2026 г., 00:07 (GMT+3)
tema_py, час ночи, в соседней вкладке open webui, а я читаю твой yml и прямо вижу этот курсор на новой строке. У меня тот же рефлекс был, когда захотела, чтобы пайплайн сам пересобирал контейнер с моделями.

tema_py писал:
я это дочитал и строку стёр, даже в git add не пустил


Стереть stop из yaml — полдела. Пока сокет торчит, следующая рука снова допишет эти четыре строки, «ну это же только бот». У меня на этом месте лежал том с эмбеддингами: контейнер встаёт за минуту, индексы заново считаются полдня.

Я в итоге сокет у раннера сняла совсем. Пайплайн только собирает образ и пушит в registry на этом же сервере. Перезапуск делает unit в systemd: смотрит тег, pull, restart. Джоба docker ps не вызывает, список ей не нужен.

Если совсем просто: ci не должен уметь stop. Иначе опечатка в имени, и ляжет не бот.

А у кого-то раннер без сокета уже живёт, не только правило «не класть docker stop»?
1
kate_ekb
Junior
Сообщения: 37
Репутация: 12
Дата регистрации:
12.08.2026
04 сент. 2026 г., 06:09 (GMT+3)
andryukha, утро. ноут, кофе, ты про живой счёт — ну я кабинет открыла.

andryukha писал:
сколько это в месяц по живому счёту, не «зато свой агент»



сначала uab. раннер рядом с wp на сборке всё поджал, уехала на heka и не жалею. в кабинете сумма как на сайте.

минуты гитлаба я не докупаю, за август пайплайны даже половины пакета не съели. ты их как пакет связи считаешь) а живой счёт — когда в ci лежит stop, и опечатка кладёт соседний контейнер. дешевле шареный воркер только пока туда не запихнули деплой. как запихнули — вопрос уже не в минутах, а кто будет поднимать то, что джоба уронила.

сокет пока не снимала, до systemd как masha_spb не дошла. чужой демон в прод всё равно не пускаю, даже бесплатный.

а у тебя в этих четырёхстах что — тесты, или деплой уже туда же?
1
daniyar_ala
Junior
Сообщения: 21
Репутация: 4
Дата регистрации:
24.08.2026
04 сент. 2026 г., 06:13 (GMT+3)

kate_ekb писал:
У тебя в ci docker CLI вообще вызывается?


kate_ekb, нет, ещё не вызывается. Утром сел за ноут, открыл пайплайн — как раз хотел compose для wp туда дописать. Теперь после твоего exec смотрю на этот файл и не уверен) Пайплайн без docker на общем демоне ещё кому-то нужен, или сокет лучше сразу не давать?
0
kate_ekb
Junior
Сообщения: 37
Репутация: 12
Дата регистрации:
12.08.2026
04 сент. 2026 г., 07:08 (GMT+3)

daniyar_ala писал:
хотел compose для wp туда дописать


не пиши, это уже деплой на общем демоне. без docker в ci сокет можно не снимать.
0
daniyar_ala
Junior
Сообщения: 21
Репутация: 4
Дата регистрации:
24.08.2026
04 сент. 2026 г., 07:13 (GMT+3)

kate_ekb писал:
без docker в ci сокет можно не снимать.


kate_ekb, yaml закрыл без compose, кофе ещё тёплый. Сокет у меня пока открыт — на прошлом хостинге я про него даже не думал. Если пайплайн только тесты гоняет, зачем раннеру демон вообще виден?
0
andryukha
Junior
Сообщения: 40
Репутация: 15
Дата регистрации:
17.08.2026
04 сент. 2026 г., 08:14 (GMT+3)

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


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

ты yaml закрыл без compose. kate_ekb рядом уехала с uab на heka, потому что раннер с wp на сборке поджал. это две разные сметы, и их почему-то смешивают в одну кучу «свой агент».

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

вот тут я обычно всех достаю.

посчитал чужие минуты против тарифа, чуть не сел)) gitlab.com: 400 бесплатно, потом платно. худой пайплайн раз в день — влезаешь. wordpress плюс образ плюс redis, который с зимы забыли — минуты кончаются быстро. тогда свой агент имеет смысл. но смысл появляется не от слова «сокет», а от того, что шареный воркер уже не влезает или туда запихнули деплой.

kate_ekb, ты heka назвала и «сумма как на сайте». этого мало для сметы. сколько списалось за август целиком, с тем что раннер жрёт рядом с wp? 23 это тариф с витрины. мне нужен живой счёт.

и без «зато панель красивая», пожалуйста.

я за год посидел на хечнере, потом на аезе, кусок селектела, сейчас здесь. не чтобы хвалить стулья — чтобы цифра не врала. хечнер дешевле за ядро: раннер, который ночью гоняет тесты, на бумаге там выгоднее. оплата из рф — лотерея. карта часто не проходит, юрлицу из подольска закрывающие письмами. пока на витрине минус два доллара, у меня три дня вопрос, дошли ли деньги. это тоже стоимость ci, просто её не рисуют в тарифе. с аезы картой было проще, поддержка русская, но ловил «сейчас переедем» — для пайплайна, который уже смотрит в конкретный ip, переезд посреди месяца мне дороже любой панели. селектел по бумагам ровно, по счёту это уже не восемь долларов за vps. если агент только тесты гоняет, переплата видна сразу, как открываешь акт.

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

daniyar_ala, с казахстана карта через юкассу не пройдёт, так устроено, не проблема. крипта и токен maat — нормальный путь, я бы на твоём месте так и делал. вопрос в другом: сколько по факту съедает сеть, пока деньги доходят? в теории usdt, в экселе — 23 плюс комиссия плюс ещё раз комиссия. кинь живую цифру за месяц, не «удобно».

я остаюсь, потому что по итогу сметы закрыт вопрос оплаты. если тесты в четыреста влезают — свой агент мне не нужен, и сокет тем более. если нет, или в ci уже деплой — тогда heka за 23 рядом с сайтом это не про красоту. это про то, что джоба не должна уметь стопнуть соседний контейнер, пока ты допиваешь кофе.

tema_py, те четыре строки со stop я прочитал. простой от опечатки в имени — вот это я хочу в таблицу. masha_spb, ты про том с эмбеддингами: контейнер встаёт за минуту, индексы полдня. сколько это в деньгах, если джоба один раз промахнётся? не «правило не класть stop», а строка убытка.

у кого за август живой счёт, не картинка с сайта — киньте. иначе к обеду опять будем спорить удобством, а цифра так и не приедет.
0
kate_ekb
Junior
Сообщения: 37
Репутация: 12
Дата регистрации:
12.08.2026
04 сент. 2026 г., 08:19 (GMT+3)
andryukha, эксель с утра, рука сама — слышала)

andryukha писал:
зачем платить 23, если тесты влезают в бесплатные минуты?



двадцать три у меня за сайт, не за раннер. он рядом сидит, потому что машина уже была. тебе с одними тестами агент правда не нужен. только сайт и минуты в одну колонку не клади.
1
lexa92
Junior
Сообщения: 59
Репутация: 20
Дата регистрации:
09.08.2026
04 сент. 2026 г., 09:02 (GMT+3)
kate_ekb, про минуты я не спорю, это не моя смета. спорю вот с этим.

kate_ekb писал:
без docker в ci сокет можно не снимать


нельзя. сокет «на всякий» живёт дольше yaml. yaml ты сегодня закрыла, завтра кто-то снова допишет stop, потому что демон отдаёт всё, что просят.

утром сел за свой раннер, глянул volumes. /var/run/docker.sock там нет уже давно. пайплайн собирает образ без демона, stop набрать физически нечем.

скинь вывод, что в binds?

docker inspect gitlab-runner --format '{{json .HostConfig.Binds}}'

если сокет в списке — вычеркни и рестартани. до systemd как у masha_spb можно не доходить, unit не нужен, чтобы просто не торчал docker.sock.
0
kate_ekb
Junior
Сообщения: 37
Репутация: 12
Дата регистрации:
12.08.2026
04 сент. 2026 г., 09:34 (GMT+3)
lexa92, inspect глянула — сокет в binds. сняла. yaml я закрыла, демон stop всё равно отдаст.
0
kate_ekb
Junior
Сообщения: 37
Репутация: 12
Дата регистрации:
12.08.2026
04 сент. 2026 г., 10:34 (GMT+3)
andryukha, пока ты минуты в экселе складываешь, я сокет с раннера сняла. тесты у тебя, машина у меня под сайт)
1