Розбіжності

Тут показані розбіжності між вибраною ревізією та поточною версією сторінки.

Посилання на цей список змін

Порівняння попередніх версій Попередня ревізія
Наступна ревізія
Попередня ревізія
devops:jenkins [14/11/2025 22:56] osvexdevops:jenkins [14/11/2025 23:00] (поточний) osvex
Рядок 1: Рядок 1:
-Гаразд, це чудова ідея. Зберегти фінальну, робочу конфігурацію як "шпаргалку" — це найкращий спосіб закріпити знання.+====== Автоматизація деплою стеку моніторингу за допомогою Jenkins + Ansible + Git ======
  
-Оскільки ви будете використовувати DokuWiki, я підготую статтю, використовуючи її синтаксис (він дуже схожий на Markdown, але з деякими відмінностями, особливо у заголовках та кодових блоках).+Ця стаття — шпаргалка з налаштування безпечного CI/CD пайплайну "Push-to-Deploy".
  
-Ось готова стаття-шпаргалка, яка описує **тільки** наш фінальний, професійний сетап.+**Мета:** Автоматично оновлювати та перезапускати Docker Compose стек моніторингу на сервері щоразу, коли відбувається git push у main гілку.
  
-----+-----
  
-## (Скопіюйте цей текст і вставте його на вашу сторінку DokuWiki)+===== Архітектура рішення =====
  
-`====== Автоматизація деплою стеку моніторингу за допомогою Jenkins + Ansible + Git ======`+Ми використовуємо модель із **поділом обов'язків** для максимальної безпеки та гнучкості:
  
-Ця стаття — шпаргалка з налаштування безпечного CI/CD пайплайну "Push-to-Deploy".+* **Git (GitHub):** Єдине "джерело правди" для всіх конфігурацій.
  
-**Мета:** Автоматично оновлювати та перезапускати Docker Compose стек моніторингу на сервері щоразу, коли відбувається `git push` у `main` гілку.+* **Ansible (на хост-сервері):** "Виконавець" (CD). Він встановлений на самому сервері sim-serv і єдиний, хто має доступ до Docker та файлів проєкту. Він виконує інструкції (плейбуки).
  
-----+* **Jenkins (в Docker):** "Оркестратор" (CI). Він ізольований у своєму контейнері **без** доступу до docker.sock і **без** root прав. Його єдина задача — "слухати" GitHub і, у разі змін, "дзвонити" по SSH на хост-сервер, наказуючи Ansible виконати плейбук.
  
-`===== Архітектура рішення =====`+-----
  
-Ми використовуємо модель із **поділом обов'язків** для максимальної безпеки та гнучкості:+===== Крок 1: Налаштування Ansible (Виконавецьна хост-сервері =====
  
-   * **Git (GitHub):**  Єдине "джерело правди" для всіх конфігурацій. +Все це виконується на сервері sim-serv (наприклад, з-під користувача osvex).
-  * **Ansible (на хост-сервері):**  "Виконавець" (CD). Він встановлений на самому сервері `sim-serv` і єдиний, хто має доступ до Docker та файлів проєкту. Він виконує інструкції (плейбуки). +
-  * **Jenkins (в Docker):**  "Оркестратор" (CI). Він ізольований у своєму контейнері **без**  доступу до `docker.sock` і **без**  `root` прав. Його єдина задача — "слухати" GitHub і, у разі змін, "дзвонити" по SSH на хост-сервер, наказуючи Ansible виконати плейбук. +
-----+
  
-`===== Крок 1: Налаштування Ansible (Виконавець) на хостервері =====`+==== Встановлення Ansible та Docker-бібліотек ====
  
-Все це виконується на сервері `sim-serv` (наприклад, з-під користувача `osvex`).+\<code bash\>
  
-`==== Встановлення Ansible та Docker-бібліотек ====`+Встановлення PPA та самого Ansible
  
-\'' ''+sudo apt update
  
-''# Встановлення PPA та самого Ansible ''+sudo apt install -y software-properties-common
  
-''sudo apt update sudo apt install -y software-properties-common sudo add-apt-repository –yes –update ppa:ansible/ansible sudo apt install -y ansible ''+sudo add-apt-repository --yes --update ppa:ansible/ansible
  
-''# Встановлення Python-бібліотеки для Docker (потрібно для модуля Ansible) ''+sudo apt install -y ansible
  
-''sudo apt install python3-docker \ ''+# Встановлення Python-бібліотеки для Docker (потрібно для модуля Ansible)
  
-''`==== Створення робочої папки та файлів Ansible ====` ''+sudo apt install python3-docker
  
-''Ми зберігаємо всі конфігурації Ansible у `/home/osvex/ansible/`. ''+\</code\>
  
-''**1. Файл `inventory` (де виконувати):**  ''+==== Створення робочої папки та файлів Ansible ====
  
-''Це наш список серверів. Оскільки Ansible керує сам собою, ми використовуємо `localhost`''+Ми зберігаємо всі конфігурації Ansible у /home/osvex/ansible/.
  
-''\'' ''''+**1. Файл inventory (де виконувати):**
  
-''''# /home/osvex/ansible/inventory ''''+Це наш список серверів. Оскільки Ansible керує сам собою, ми використовуємо localhost.
  
-''''[monitoring] localhost ansible\_connection=local ''''+\<code ini\>
  
-''''**2. Файл `deploy_monitoring.yml` (що робити):**  ''''+# /home/osvex/ansible/inventory
  
-''''Це "плейбук", або інструкція для Ansible. Він оновлює Git-репозиторій та перезапускає Docker Compose. ''''+[monitoring]
  
-''''\'' ''''''+localhost ansible\_connection=local
  
-''''''# /home/osvex/ansible/deploy\_monitoring.yml ''''''+\</code\>
  
-----+**2. Файл deploy_monitoring.yml (що робити):**
  
-  - ''''''hosts: monitoring'''''' +Це "плейбук", або інструкція для Ansible. Він оновлює Git-репозиторій та перезапускає Docker Compose.
-''''''become: no \# Не отримувати sudo, працювати від імені osvex ''''''+
  
-<code> +\<code yaml\>
-''''''  tasks:+
  
-''''''+# /home/osvex/ansible/deploy\_monitoring.yml
  
-</code>+-----
  
-'''''' ''''''+- hosts: monitoring
  
-  - ''''''name1. Оновити код моніторингу з Git'''''' +becomeno \# Не отримувати sudo, працювати від імені osvex
-<code> +
-''''''      # Використовуємо вбудований git модуль+
  
-''''''+tasks:
  
-</code>+- name: 1. Оновити код моніторингу з Git
  
-'''''' ''''''+# Використовуємо вбудований git модуль
  
-<code> +git:
-''''''      git: +
-      repo: '[email protected]:osvex/monitoring.git' +
-      dest: '/home/osvex/docker/monitoring' \# Шлях до проєкту на хості +
-      version: 'main' +
-      accept\_hostkey: yes +
-      force: yes+
  
-''''''+repo: '[email protected]:osvex/monitoring.git'
  
-</code>+dest: '/home/osvex/docker/monitoring' \# Шлях до проєкту на хості
  
-'''''' ''''''+version: 'main'
  
-  - ''''''name2. Перезапустити стек моніторингу (Docker Compose v2)'''''' +accept\_hostkeyyes
-<code> +
-''''''      # Використовуємо звичайну команду, оскільки модуль v1 не підтримує v2+
  
-''''''+force: yes
  
-</code>+- name: 2. Перезапустити стек моніторингу (Docker Compose v2)
  
-'''''' ''''''+# Використовуємо звичайну команду, оскільки модуль v1 не підтримує v2
  
-<code> +ansible.builtin.command:
-''''''      ansible.builtin.command: +
-      cmd: docker compose up -d --build --remove-orphans +
-      chdir: '/home/osvex/docker/monitoring' \# Папка, з якої запускати+
  
-''''''+cmd: docker compose up -d --build --remove-orphans
  
-</code>+chdir: '/home/osvex/docker/monitoring' \# Папка, з якої запускати
  
-'''''' ''''''+\</code\>
  
-'''''' ''''''+-----
  
-----+===== Крок 2: Налаштування Jenkins (Оркестратор) в Docker =====
  
-''''''`===== Крок 2: Налаштування Jenkins (Оркестратор) в Docker =====` ''''''+Jenkins запускається у власному ізольованому Docker-контейнері.
  
-''''''Jenkins запускається у власному ізольованому Docker-контейнері''''''+==== docker-compose.yml для Jenkins ====
  
-''''''` ==== `docker-compose.yml` для Jenkins ==== ` ''''''+Це **безпечна** конфігурація. Ми **НЕ** використовуємо user: root і **НЕ** прокидаємо docker.sock. Єдиний зв'язок зі світом — це "домашня" папка Jenkins.
  
-''''''Це **безпечна**  конфігурація. Ми **НЕ**  використовуємо `user: root` і **НЕ**  прокидаємо `docker.sock`. Єдиний зв'язок зі світом — це "домашня" папка Jenkins. ''''''+\<code yaml\>
  
-''''''\'' ''''''''+# /home/osvex/docker/jenkins/docker-compose.yml
  
-''''''''# /home/osvex/docker/jenkins/docker-compose.yml ''''''''+version: '3.8'
  
-''''''''version'3.8' ''''''''+services:
  
-''''''''services: jenkins: image: jenkins/jenkins:lts-jdk17 container\_name: jenkins restartunless-stopped ''''''''+jenkins:
  
-''''''''``` # Секція 'userroot' видалена для безпеки ''''''''+imagejenkins/jenkins:lts-jdk17
  
-''''''''# Порти прокидаються через реверс-проксі (Traefik) # ports# - "8090:8080" ''''''''+container\_namejenkins
  
-''''''''labels''''''''+restartunless-stopped
  
-  - ''''''''"traefik.enable=true"'''''''' +\\ 
-  ''''''''"traefik.http.routers.jenkins.rule=Host(`jenkins.osvex.com`)"'''''''' +# Секція 'user: rootвидалена для безпеки 
-  ''''''''"traefik.http.routers.jenkins.entrypoints=websecure"'''''''' + 
-  ''''''''"traefik.http.routers.jenkins.tls.certresolver=lets-encrypt"'''''''' +# Порти прокидаються через реверс-проксі (Traefik) 
-  ''''''''"traefik.http.services.jenkins.loadbalancer.server.port=8080" # Внутрішній порт Jenkins'''''''' + 
-  ''''''''"traefik.http.services.jenkins.loadbalancer.server.scheme=http"'''''''' +# ports: 
-  ''''''''"traefik.docker.network=shared_traefik"'''''''' + 
-''''''''volumes: ''''''''+# - "8090:8080" 
 + 
 +labels: 
 + 
 +"traefik.enable=true" 
 + 
 +- "traefik.http.routers.jenkins.rule=Host(jenkins.osvex.com)" 
 + 
 +- "traefik.http.routers.jenkins.entrypoints=websecure" 
 + 
 +- "traefik.http.routers.jenkins.tls.certresolver=lets-encrypt" 
 + 
 +- "traefik.http.services.jenkins.loadbalancer.server.port=8080" # Внутрішній порт Jenkins 
 + 
 +- "traefik.http.services.jenkins.loadbalancer.server.scheme=http" 
 + 
 +- "traefik.docker.network=shared_traefik" 
 + 
 +volumes: 
 + 
 +# Залишаємо ТІЛЬКИ цей один 'bind mountдля даних Jenkins
  
-<code> 
-''''''''# Залишаємо ТІЛЬКИ цей один 'bind mount' для даних Jenkins 
 - /srv/docker/jenkins:/var/jenkins_home - /srv/docker/jenkins:/var/jenkins_home
  
 # Всі інші volumes (docker.sock, /usr/bin/docker і т.д.) видалені # Всі інші volumes (docker.sock, /usr/bin/docker і т.д.) видалені
  
-''''''''+networks: 
 + 
 +- shared_traefik 
 + 
 +\\ 
 +networks: 
 + 
 +shared\_traefik: 
 + 
 +external: true 
 + 
 +\</code\> 
 + 
 +==== Встановлення прав на папку Jenkins ==== 
 + 
 +Оскільки Jenkins тепер працює від імені користувача jenkins (UID 1000), ми повинні надати йому права на "домашню" папку: 
 + 
 +\<code bash\> 
 + 
 +sudo chown -R 1000:1000 /srv/docker/jenkins/ 
 + 
 +\</code\> 
 + 
 +==== Необхідні плагіни Jenkins ==== 
 + 
 +У Jenkins (через **Manage Jenkins -\> Plugins**) мають бути встановлені: 
 + 
 +* **GitHub Integration** (для тригерів та вебхуків) 
 + 
 +* **SSH Agent** (для використання SSH-ключів у пайплайнах) 
 + 
 +----- 
 + 
 +===== Крок 3: Налаштування "Мосту" (SSH-ключі та Webhook) ===== 
 + 
 +Ми створюємо два окремих SSH-ключа для двох різних завдань. Вони зберігаються у /srv/docker/jenkins/.ssh/ (що відповідає /var/jenkins_home/.ssh/ всередині контейнера). 
 + 
 +==== Ключ 1: Для підключення до GitHub (id\_rsa) ==== 
 + 
 +1. **Налаштування Jenkins:** Перейдіть у **Manage Jenkins -\> Credentials -\> Global** та додайте SSH Username with private key: 
 + 
 +* **ID:** github-ssh-key 
 + 
 +* **Username:** git 
 + 
 +* **Private Key:** (Вміст id_rsa) 
 + 
 +2. **Налаштування GitHub:** Перейдіть у **Репозиторій -\> Settings -\> Deploy keys** та додайте публічний ключ (вміст id_rsa.pub). 
 + 
 +==== Ключ 2: Для підключення до хоста (Ansible) (id\_rsa\_ansible) ==== 
 + 
 +1. **Налаштування Jenkins:** Перейдіть у **Manage Jenkins -\> Credentials -\> Global** та додайте SSH Username with private key: 
 + 
 +* **ID:** ansible-ssh-key 
 + 
 +* **Username:** osvex (ваш логін на хост-сервері) 
 + 
 +* **Private Key:** (Вміст id_rsa_ansible) 
 + 
 +2. **Налаштування хост-сервера:** Додайте публічний ключ (вміст id_rsa_ansible.pub) до списку довірених для користувача osvex: 
 + 
 +\<code bash\> 
 + 
 +cat /srv/docker/jenkins/.ssh/id\_rsa\_ansible.pub \>\> /home/osvex/.ssh/authorized\_keys 
 + 
 +chmod 600 /home/osvex/.ssh/authorized\_keys 
 + 
 +\</code\> 
 + 
 +==== Налаштування known\_hosts (у Jenkins) ==== 
 + 
 +Jenkins повинен "довіряти" серверам, до яких він підключається. 
 + 
 +\<code bash\> 
 + 
 +# На хост-сервері виконайте: 
 + 
 +ssh-keyscan -t rsa github.com \>\> /srv/docker/jenkins/.ssh/known\_hosts 
 + 
 +ssh-keyscan -t ed25519 github.com \>\> /srv/docker/jenkins/.ssh/known\_hosts 
 + 
 +ssh-keyscan -t rsa 172.17.0.1 \>\> /srv/docker/jenkins/.ssh/known\_hosts \# IP хоста зсередини Docker 
 + 
 +\</code\> 
 + 
 +==== Налаштування GitHub Webhook ==== 
 + 
 +У **Репозиторій -\> Settings -\> Webhooks** додайте новий Webhook: 
 + 
 +* **Payload URL:** https://jenkins.osvex.com/github-webhook/ 
 + 
 +* **Content type:** application/json 
 + 
 +----- 
 + 
 +===== Крок 4: Фінальний Jenkinsfile (Мозок) ===== 
 + 
 +Цей файл лежить у корені вашого Git-репозиторію моніторингу. Він описує всю логіку пайплайну. 
 + 
 +\<code groovy\> 
 + 
 +# /home/osvex/docker/monitoring/Jenkinsfile 
 + 
 +pipeline { 
 + 
 +agent any // Запускати на будь-якому агенті 
 + 
 +\\ 
 +stages { 
 + 
 +// Етап 1: Отримання коду з Git (Jenkins робить це автоматично) 
 + 
 +stage('Checkout') { 
 + 
 +steps { 
 + 
 +echo 'Отримання коду з репозиторію...' 
 + 
 +checkout scm 
 + 
 +
 + 
 +
 + 
 +// Етап 2: Запуск розгортання через Ansible 
 + 
 +stage('Deploy via Ansible') { 
 + 
 +steps { 
 + 
 +echo 'Запуск плейбука Ansible на хост-сервері...'
  
-</code>+// "Обгортаємо" команду в sshagent,
  
-'''''''' ''''''''+// щоб надати їй ключ 'ansible-ssh-key(де вказано логін 'osvex')
  
-''''''''networks: ''''''''+sshagent(credentials['ansible-ssh-key']) {
  
-  ''''''''shared_traefik'''''''' +// Виконуємо SSH-команду
-''''''''``` ''''''''+
  
-''''''''networks: shared\_traefik: external: true \ ''''''''+// Ми підключаємось до 172.17.0.1 (IP хост-сервера зсередини Docker)
  
-''''''''`==== Встановлення прав на папку Jenkins ====` ''''''''+// і запускаємо наш плейбук
  
-''''''''Оскільки Jenkins тепер працює від імені користувача `jenkins` (UID 1000), ми повинні надати йому права на "домашню" папку: ''''''''+sh '''
  
-''''''''\'' sudo chown -R 1000:1000 /srv/docker/jenkins/ ''''''''''+ssh -o StrictHostKeyChecking=no [email protected] \
  
-''''''''''`==== Необхідні плагіни Jenkins ====` ''''''''''+"cd /home/osvex/ansible && ansible-playbook -i inventory deploy_monitoring.yml"
  
-''''''''''У Jenkins (через **Manage Jenkins -\> Plugins**) мають бути встановлені: ''''''''''+'''
  
-  * ''''''''''**GitHub Integration**  (для тригерів та вебхуків)'''''''''' +}
-  * ''''''''''**SSH Agent**  (для використання SSH-ключів у пайплайнах)'''''''''' +
-----+
  
-''''''''''`===== Крок 3: Налаштування "Мосту" (SSH-ключі та Webhook) =====` ''''''''''+}
  
-''''''''''Ми створюємо два окремих SSH-ключа для двох різних завдань. Вони зберігаються у `/srv/docker/jenkins/.ssh/` (що відповідає `/var/jenkins_home/.ssh/` всередині контейнера). ''''''''''+}
  
-''''''''''`==== Ключ 1: Для підключення до GitHub (`id\_rsa`) ====` ''''''''''+}
  
-''''''''''1. **Налаштування Jenkins:**  Перейдіть у **Manage Jenkins -\> Credentials -\> Global**  та додайте `SSH Username with private key`: ''''''''''+// Блок post-дій
  
-  * ''''''''''**ID:**  `github-ssh-key`'''''''''' +post {
-  * ''''''''''**Username:**  `git`'''''''''' +
-  * ''''''''''**Private Key:**  (Вміст `id_rsa`)'''''''''' +
-''''''''''2. **Налаштування GitHub:**  Перейдіть у **Репозиторій -\> Settings -\> Deploy keys**  та додайте публічний ключ (вміст `id_rsa.pub`). ''''''''''+
  
-''''''''''`==== Ключ 2: Для підключення до хоста (Ansible) (`id\_rsa\_ansible`) ====` ''''''''''+success {
  
-''''''''''1. **Налаштування Jenkins:**  Перейдіть у **Manage Jenkins -\> Credentials -\> Global**  та додайте `SSH Username with private key`: ''''''''''+echo 'ЧУДОВО: Пайплайн Ansible успішно виконано.'
  
-  * ''''''''''**ID:**  `ansible-ssh-key`'''''''''' +}
-  * ''''''''''**Username:**  `osvex` (ваш логін на хост-сервері)'''''''''' +
-  * ''''''''''**Private Key:**  (Вміст `id_rsa_ansible`)'''''''''' +
-''''''''''2. **Налаштування хост-сервера:**  Додайте публічний ключ (вміст `id_rsa_ansible.pub`) до списку довірених для користувача `osvex`: ''''''''''+
  
-<code> +failure {
-''''''''''  \'' +
-  cat /srv/docker/jenkins/.ssh/id\_rsa\_ansible.pub \>\> /home/osvex/.ssh/authorized\_keys +
-  chmod 600 /home/osvex/.ssh/authorized\_keys +
-  \+
  
-''''''''''''+echo 'ПОМИЛКА: Пайплайн впав. Перевірте логи.'
  
-</code>+}
  
-'''''''''''' ''''''''''''+}
  
-''''''''''''` ==== Налаштування `known\_hosts` (у Jenkins) ==== ` ''''''''''''+\
 +}
  
-''''''''''''Jenkins повинен "довіряти" серверам, до яких він підключається. ''''''''''''+\</code\>
  
-''''''''''''\'' ''''''''''''''+-----
  
-''''''''''''''# На хост-сервері виконайте: ''''''''''''''+===== Фінальний потік роботи (Workflow) =====
  
-''''''''''''''ssh-keyscan -t rsa github.com \>\> /srv/docker/jenkins/.ssh/known\_hosts ssh-keyscan -t ed25519 github.com \>\> /srv/docker/jenkins/.ssh/known\_hosts ssh-keyscan -t rsa 172.17.0.\>\> /srv/docker/jenkins/.ssh/known\_hosts \# IP хоста зсередини Docker \ ''''''''''''''+1. Ви робите git push зі змінами у docker-compose.yml або prometheus.yml.
  
-''''''''''''''`==== Налаштування GitHub Webhook ====` ''''''''''''''+2. GitHub "ловить" цей push і надсилає Webhook на https://jenkins.osvex.com.
  
-''''''''''''''У **Репозиторій -\> Settings -\> Webhooks**  додайте новий Webhook: ''''''''''''''+3. Jenkins "прокидається", запускає пайплайн, завантажує Jenkinsfile.
  
-  * ''''''''''''''**Payload URL:**  `[[https://jenkins.osvex.com/github-webhook/|https://jenkins.osvex.com/github-webhook/]]`'''''''''''''' +4Етап "Deploy" підключається по SSH до osvex@172.17.0.1 (до вашого хост-сервера).
-  * ''''''''''''''**Content type:**  `application/json`'''''''''''''' +
-----+
  
-''''''''''''''` ===== Крок 4: Фінальний `Jenkinsfile` (Мозок) ===== ` ''''''''''''''+5. Jenkins виконує команду: ansible-playbook ...
  
-''''''''''''''Цей файл лежить у корені вашого Git-репозиторію моніторингу. Він описує всю логіку пайплайну. ''''''''''''''+6. Ansible (на хостівиконує плейбук:
  
-''''''''''''''\'' ''''''''''''''''+* Заходить у /home/osvex/docker/monitoring і робить git pull.
  
-''''''''''''''''# /home/osvex/docker/monitoring/Jenkinsfile ''''''''''''''''+* Запускає docker compose up -d ...
  
-''''''''''''''''pipeline { agent any // Запускати на будь-якому агенті ``` stages { // Етап 1: Отримання коду з Git (Jenkins робить це автоматично) stage('Checkout') { steps { echo 'Отримання коду з репозиторію...' checkout scm } } // Етап 2: Запуск розгортання через Ansible stage('Deploy via Ansible') { steps { echo 'Запуск плейбука Ansible на хост-сервері...' // "Обгортаємо" команду в sshagent, // щоб надати їй ключ 'ansible-ssh-key' (де вказано логін 'osvex') sshagent(credentials: ['ansible-ssh-key']) { // Виконуємо SSH-команду // Ми підключаємось до 172.17.0.1 (IP хост-сервера зсередини Docker) // і запускаємо наш плейбук sh ''' ssh -o StrictHostKeyChecking=no [email protected] \ "cd /home/osvex/ansible && ansible-playbook -i inventory deploy_monitoring.yml" ''' } } } } // Блок post-дій post { success { echo 'ЧУДОВО: Пайплайн Ansible успішно виконано.' } failure { echo 'ПОМИЛКА: Пайплайн впав. Перевірте логи.' } } ``` } \ —– `===== Фінальний потік роботи (Workflow) =====` 1. Ви робите `git push` зі змінами у `docker-compose.yml` або `prometheus.yml`. 2. GitHub "ловить" цей push і надсилає Webhook на `[[https://jenkins.osvex.com|https://jenkins.osvex.com]]`. 3. Jenkins "прокидається", запускає пайплайн, завантажує `Jenkinsfile`. 4. Етап "Deploy" підключається по SSH до `[email protected]` (до вашого хост-сервера). 5. Jenkins виконує команду: `ansible-playbook …` 6. Ansible (на хості) виконує плейбук: * Заходить у `/home/osvex/docker/monitoring` і робить `git pull`. * Запускає `docker compose up -d …` 7. Jenkins отримує "успішний" статус від Ansible і завершує пайплайн з зеленим кольором. //''''''''''''''''+7. Jenkins отримує "успішний" статус від Ansible і завершує пайплайн з зеленим кольором.
  
  • devops/jenkins.1763161008.txt.gz
  • Востаннє змінено: 14/11/2025 22:56
  • повз osvex