В этой статье описывается возможность/идея/концепт изменения глобальных настроек на локальных серверах команд в большой инфраструктуре используя Gitlab CI и Ansible.


Допустим у вас имеются 20 команд разработчиков и 1 команда админов/DevOps. Как менять на всех серверах пароли админов? Как добавить корневой сертификат Предприятия на все сервера? И т.д.


Какую задачу решает?


Типичная ситуация:
Есть глобальные администраторы/DevOps.
Есть глобальные настройки (NTP, DNS, Proxy и т.д.)
Ecть локальные команды разработки: TeamA, TeamB, TeamC, TeamD и т.д.
Есть разработчики, которые могут ходить только на сервера своей команды.
Как добавлять/обновлять глобальных администраторов, глобальные настройки?



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


Если у вас во всей компании немного серверов, то можно запустить Ansible в простом режиме — запустить обновление глобальных администраторов, глобальных настроек на всех серверах сразу.


Для больших инсталляций компании обычно используют Puppet, Chef.


Концепция


Для изменения глобальных настроек на локальных серверах команд в большой инфраструктуре я предлагаю механизм git субмодулей.


В репозиторий с локальными настройками применяются git субмодули с глобальными настройками.


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



Вы можете использовать концепцию обновления глобальных настроек используя git submodule в инфраструктуре с Puppet, Chef, Salt, но в статье приводиться пример с Ansible.


Для примера установим tomcat, mysql, nginx и применим к ним глобальные настройки в команде под названием team.


В gitlab есть группа common, которая содержит общие настройки.


В группе common есть проект base-bootstrap, который содержит администраторов, настройки sysctl и т.д.


Обычно в компании есть несколько отделов разработки — чаще их называют командами (team).


В gitlab создаем группу team (у вас будет свое название команды).


В группе team создаем проекты: application, database, loadbalancer.


Скриншот с base-bootstrap, application, database, loadbalancer:



Репозиторий base-bootstrap включен как git submodule в репозитории application, database, loadbalancer.


При каждом коммите в репозитории application, database, loadbalancer запускает обновление субмодуля base-bootstrap.


После этого на сервера application, database, loadbalancer применяются ansible-playbook из base-bootstrap и ansible-playbook из base-bootstrap.



То есть, если добавить нового администратора в base-bootstrap или изменить системные настройки в base-bootstrap, то при коммите application, database, loadbalancer — новые настройки из base-bootstrap применятся в application, database, loadbalancer.


Подготовка


Необходимо прочитать статьи про Ansible для начинающих:


# Ansible с чего начать


# Пособие по Ansible


У вас должен быть развернут gitlab и gitlab-runner c установленным docker.


Docker executor здесь используется как пример — вы можете использовать Shell executor.


Как разворачивать gitlab и gitlab-runner:


# Статья о Gitlab-CI от Southbridge


# Непрерывная интеграция и развертывание Docker в GitLab CI


У вас должны быть 3 сервера (например, на ubuntu): application, database, loadbalancer.


Application, database, loadbalancer — это общие названия.


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


Как реализовать


Репозитори и весь код для теста можно взять отсюда: https://github.com/patsevanton/ansible-gitlab-habr


Если вы ходите на сервера по логину/паролю, то в нужной группе (в данном случае это team) создаем переменную userpassword (когда будете менять нужно также поменять переменную и в коде) и укажем там пароль (в коде используется пароль password)


Не забудьте на конечных серверах создать нужного вам пользователя с правами sudo (в коде используется юзер — user).


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


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


В каждом репозитории (application, database, loadbalancer) создаем git submodule:


git submodule add git@gitlab.example.com:common/base-bootstrap.git
git submodule add git@gitlab.example.com:team/team-users.git

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


В нашем случае это репозиторий с общими настройками base-bootstrap и репозиторий пользователей команды team-users.


Где gitlab.example.com — ваш gitlab сервер.


Затем в .gitmodules меняем путь до репозитория на относительный


Пример:


[submodule "team-users"]
  path = team-users
  url = ../team-users.git
[submodule "base-bootstrap"]
  path = base-bootstrap
  url = ../../common/base-bootstrap.git

В каждом репозитории в hosts меняем IP на свои, в ansible.cfg меняем remote_user на своего пользователя.


Если у вас репозитории в последнее несколько часов/дней не было коммитов, а на сервера нужно выкатить новые общие изменения (например, нужно добавить нового админа) — для таких ситуаций есть ansible-pull.


Настроим чтобы ansible-pull скачивал репозиторий common/base-bootstrap.


Для этого нужно добавить репозиторий deploy token.


Переходим в репозиторий common/base-bootstrap затем идем в settings/repository/Deploy Tokens.


Создаем token. Полученные username и пароль записываем в base-bootstrap/vars/cron.yml.


После того как проверите что все корректно работает — думаю стоит изменить время запуска ansible-pull с "каждые 2 минуты" на подходящее вам.


Если ansible-pull упал — значит и упадет CI этого сервиса, которая запускается при каждом коммите в этот репозиторий сервиса (допустим сервис называется application)


Проверка


Создание нового администратора.


Попробуйте добавить нового администратора в https://github.com/patsevanton/ansible-gitlab-habr/blob/master/commons/base-bootstrap/vars/users.yml


Изменение sysctl


Попробуйте добавить/изменить настройки sysctl в https://github.com/patsevanton/ansible-gitlab-habr/blob/master/commons/base-bootstrap/vars/sysctl.yml


Добавление записей в cron


Попробуйте добавить записи cron в https://github.com/patsevanton/ansible-gitlab-habr/blob/master/commons/base-bootstrap/vars/cron.yml


Расширение или установка ваших приложений


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


Зайдите на https://galaxy.ansible.com/ и найти роль для установки вашего приложения.


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


Например, попробуем рядом с tomcat установить java. Сначала установим роль geerlingguy.java


ansible-galaxy install geerlingguy.java

Создадим стандартный ansible.cfg такое же как репозиториях.


Создадим инвентарь:


[java]
java ansible_host=IP-сервера

Создадим playbook java.yml


- hosts: java
  become: yes
  vars_files:
    - vars/main.yml
  roles:
    - { role: geerlingguy.java }

Запускаем ansible-playbook java.yml


Если все прошло успешно добавляем в нужный проект (в данном случае application)


Роль geerlingguy.java добавляем в после роли robertdebock.tomcat https://github.com/patsevanton/ansible-gitlab-habr/blob/master/team/application/tomcat-app.yml#L11


Тоже самое и со всеми остальными приложениями, которые вам нужно установить на сервера.


Тестирование playbook и безопасность


Для упрощения статьи вопрос хранения паролей и тестирования не затрагиваем.


Есть статьи по тестированию playbook:
# Ansible: тестируем плейбуки (часть 1)


# Тестирование и непрерывная интеграция для Ansible-ролей при помощи Molecule и Jenkins


Ответы на вопросы


1) Mentat: А почему все-таки не как это в доке ansible написано, с окружениями? С первого прочтения выглядит как попытка переизобрести это все заново. Там достаточно удобно применять это все типа ansible-playbook -i env/teamA personalAPlaybook.yml
Ответ: Эта схема дает возможность менять глобальные настройки. То что описывается в вопросе — это изменение локальных настроек команд.


P.S. Возможно такая же функциональность реализована в Ansible Tower. Но я ничего по этому поводу сказать не могу — не работал с Ansible Tower.

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


  1. gecube
    06.12.2018 12:24

    Не рассмотрены вопросы:


    • push/pull
    • master-client / agentless
    • централизованный репозиторий с обвязками, которые позволяют его модифицировать согласно прав каждой из команд.
    • отдельная история — как не светить "секретные" данные всем пользователям (понятно, что если есть доступ к токену на чтение коммон-репозитория, то оттуда можно все вычитать).
    • еще момент: а если конкретной команде нужно переопределить значение из базового общего репозитория (ну, например, sysctl значение особенное поставить). Каким образом будут мержиться значения?

    Solt

    опечатка. Верно — "Salt"


  1. chemtech Автор
    06.12.2018 12:37

    • push/pull рассматривается в статьях про Ansible.
    • master-client / agentless здесь рассматривать не нужно, т.к. используется Ansible.
    • централизованный репозиторий с обвязками, которые позволяют его
      модифицировать согласно прав каждой из команд.
      — прошу уточнить вопрос
    • отдельная история — как не светить "секретные" данные всем пользователям (понятно, что если есть доступ к токену на чтение коммон-репозитория, то оттуда можно все вычитать). — В статье написано: "Для упрощения статьи вопрос хранения паролей и тестирования не затрагиваем."
    • еще момент: а если конкретной команде нужно переопределить значение из базового общего репозитория (ну, например, sysctl значение особенное поставить). Каким образом будут мержиться значения? — это делается по базовым правилам Ansible, т.к. применение базового общего репозитория — это всего лишь import_playbook


    1. gecube
      06.12.2018 13:34

      это делается по базовым правилам Ansible, т.к. применение базового общего репозитория — это всего лишь import_playbook

      это, к сожалению, не ответ. Короче, пример. Есть базовый шаблон sysctl. Нужно переопределить часть параметров, которые описаны в базовом шаблоне. Как будете делать? Какие подводные камни при этом выползут? Какие ограничения на плейбуки будут?
      В статье написано: «Для упрощения статьи вопрос хранения паролей и тестирования не затрагиваем.»

      без этого — это решение не полноценное.
      прошу уточнить вопрос

      по-моему, я вполне ясно выразился.
      push/pull рассматривается в статьях про Ansible.

      Ответ нерелевантен. Т.е. ответа на вопрос «почему ansible» именно в описываемом режиме — не будет и полагаю, что он будет таков, что «так было проще»?


      1. chemtech Автор
        06.12.2018 13:50

        это, к сожалению, не ответ. Короче, пример. Есть базовый шаблон sysctl. Нужно переопределить часть параметров, которые описаны в базовом шаблоне. Как будете делать? Какие подводные камни при этом выползут? Какие ограничения на плейбуки будут?

        В целях упрощения стать это не рассматривалось.
        без этого — это решение не полноценное.

        Тут еще очень что можно было бы добавить. Но написание статьи бы затянулось — я думаю что можно это поискать в интернете.
        Ответ нерелевантен. Т.е. ответа на вопрос «почему ansible» именно в описываемом режиме — не будет и полагаю, что он будет таков, что «так было проще»?

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


  1. AlexGluck
    06.12.2018 23:02

    А ниче, что сабмодуль при добавлении ставится на определенный хеш коммита? Каждый раз при пуле, надо апдейтить версию сабмодуля или при апдейте глобального РЕПО надо во всех дочерних апдейтить этот сабмодуль. Я пробовал такое реализовать, но отказался в пользу переменных, которые мерджатся и плейбуки под каждый проект. А роли через Галакси забираются.


    1. chemtech Автор
      07.12.2018 06:37

      Каждый раз при пуле субмодуль автоматически обновляется.
      При апдейте глобального РЕПО надо во всех дочерних апдейтить этот сабмодуль. — Да, при коммите в локальный репо обновляется субмодуль. А если локальный репо не обновляется — то можно использовать ansible-pull.
      Я пробовал такое реализовать, но отказался в пользу переменных, которые мерджатся и плейбуки под каждый проект. А роли через Галакси забираются. — я думаю всем интересно было бы почитать более подробно о вашем workflow.


      1. AlexGluck
        07.12.2018 13:11

        У меня пачка уже недописанным статей. Надеюсь в новогодние праздники допишу, может и по этой теме напишу.