Создание тестовых ВМ через GitLab CI

С помощью Яндекс.Облака вы можете автоматизировать рутинные действия, например, запускать определенный скрипт после каждого коммита в ветку master git-репозитория. В примере ниже после каждого коммита создается и тестируется виртуальная машина.

Чтобы настроить CI для снимков дисков виртуальных машин:

  1. Создайте виртуальную машину для тестового приложения — создайте новую виртуальную машину, снимок диска которой будет использоваться для создания новых виртуальных машин с помощью CI.
  2. Подготовьте виртуальную машину с тестовым приложением — установите на виртуальную машину веб-сервер и набор компонентов для работы тестового приложения. Напишите тестовое приложение, которое будет переворачивать слова в переданном на сервер тексте.
  3. Проверьте работу приложения — проверьте настройки сервера и работу приложения с помощью пробного запроса.
  4. Создайте снимок диска виртуальной машины — создайте снимок диска виртуальной машины из которого CI будет создавать новые виртуальные машины.
  5. Создайте виртуальную машину с GitLab — создайте виртуальную машину с GitLab, где в репозитории будут храниться настройки CI и скрипт функционального тестирования.
  6. Настройте GitLab — создайте репозиторий для файлов и получите необходимые для конфигурации параметры.
  7. Настройте Runner — настройте Runner — инструмент для выполнения задач.
  8. Настройте CI — задайте конфигурацию CI, указав необходимые параметры для команд и тестирования.
  9. Проверьте работу приложения на виртуальной машине, созданной с помощью CI — убедитесь, что создающиеся с помощью CI и снимка машины создаются, а тестовое приложение работает.

Если созданные ВМ больше не нужны, удалите их.

Подготовьте облако к работе

Чтобы выполнить шаги сценария, нужно зарегистрироваться в Облаке и создать платежный аккаунт:

  1. Перейдите в консоль управления, затем войдите в Облако или зарегистрируйтесь, если вы еще не зарегистрированы.
  2. На странице биллинга убедитесь, что у вас подключен платежный аккаунт, и он находится в статусе ACTIVE или TRIAL_ACTIVE. Если платежного аккаунта нет, создайте его.

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

Подробнее об облаках и каталогах.

Перед тем, как создавать виртуальные машины:

  1. Перейдите в консоль управления Яндекс.Облака и выберите каталог, в котором будете выполнять операции.
  2. Убедитесь, что в выбранном каталоге есть сеть с подсетью, к которой можно подключить виртуальную машину. Для этого на странице каталога выберите сервис Virtual Private Cloud. Если в списке есть сеть — нажмите на нее, чтобы увидеть список подсетей. Если ни одной подсети или сети нет, создайте их.

В стоимость поддержки инфраструктуры входят:

Создайте виртуальную машину для тестового приложения

Создайте виртуальную машину, на которой будут установлены тестовое приложение, набор необходимых для его работы компонентов и веб-сервер:

  1. На странице каталога в консоли управления нажмите кнопку Создать ресурс и выберите Виртуальная машина.

  2. В поле Имя введите имя виртуальной машины: ci-tutorial-test-app.

  3. Выберите зону доступности, в которой будет находиться виртуальная машина.

  4. Выберите публичный образ Ubuntu 18.04.

  5. В блоке Вычислительные ресурсы выберите следующую конфигурацию:

    • Платформа — Intel Cascade Lake.
    • Гарантированная доля vCPU — 5%.
    • vCPU — 2.
    • RAM — 1 ГБ.
  6. В блоке Сетевые настройки выберите, к какой подсети необходимо подключить виртуальную машину при создании.

  7. Укажите данные для доступа на виртуальную машину:

    • В поле Логин введите имя пользователя.
    • В поле SSH ключ скопируйте содержимое файла открытого ключа. Пару ключей для подключения по SSH необходимо создать самостоятельно. Для создания ключей используйте сторонние инструменты, например утилиты ssh-keygen в Linux и macOS или PuTTYgen в Windows.
  8. Нажмите кнопку Создать ВМ.

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

При создании виртуальной машине назначаются IP-адрес и имя хоста (FQDN). Эти данные можно использовать для доступа по SSH.

Подготовьте виртуальную машину с тестовым приложением

На созданную виртуальную машину нужно установить набор необходимых для работы тестового приложения компонентов и веб-сервер для обработки запросов. Само приложение будет написано на языке Python 2.

  1. В блоке Сеть на странице виртуальной машины в консоли управления найдите публичный IP-адрес виртуальной машины.

  2. Подключитесь к виртуальной машине по протоколу SSH. Для этого можно использовать утилиту ssh в Linux и macOS и программу PuTTY для Windows.

    $ ssh <Логин>@<Публичный_IP-адрес_виртуальной_машины>
    
  3. Выполните команду apt update, чтобы обновить списки доступных для установки пакетов.

  4. Установите необходимые пакеты: JSON-процессор jq, git-клиент, менеджер пакетов PIP, систему управления виртуальными средами virtualenv, набор заголовочных файлов для Python C API и веб-сервер nginx:

    $ sudo apt-get --yes install jq git python-pip virtualenv python-dev nginx-full
    
  5. Создайте директорию, в которой будет находиться приложение и сделайте пользователя, от имени которого вы подключились к виртуальной машине, владельцем директории:

    $ sudo mkdir /srv/test-app
    $ sudo chown -R $USER /srv/test-app
    
  6. Перейдите в директорию и создайте в ней виртуальное окружение virtualenv:

    $ cd /srv/test-app
    $ virtualenv test-venv
    
  7. Запустите виртуальное окружение:

    $ . test-venv/bin/activate
    
  8. Установите в виртуальное окружение фреймворк Flask и веб-сервер uWSGI:

    $ pip install flask uwsgi
    
  9. Деактивируйте виртуальное окружение:

    $ deactivate
    
  10. Создайте в директории /srv/test-app файл api.py:

    $ touch api.py
    
  11. Откройте файл api.py любым текстовым редактором и скопируйте в него код на языке Python, который:

    • Принимает на вход текстовую строку в параметре text.
    • Записывает каждое слово из переданной строки наоборот.
    • Возвращает ответ:
      • В формате JSON, если клиентское приложение может принимать JSON.
      • Обычный текст, если клиентское приложение не может принять JSON.
    # api.py
    import json
    from flask import Flask, request, make_response as response
    
    app = Flask(__name__)
    
    
    @app.route("/")
    def index():
        text = request.args.get('text')
        json_type = 'application/json'
        json_accepted = json_type in request.headers.get('Accept', '')
        if text:
            words = text.split()
            reversed_words = [word[::-1] for word in words]
            if json_accepted:
                res = response(json.dumps({'text': reversed_words}), 200)
            else:
                res = response(' '.join(reversed_words), 200)
        else:
            res = response('text not found', 501)
        res.headers['Content-Type'] = json_type if json_accepted else 'text/plain'
        return res
    
  12. Создайте в директории /srv/test-app файл wsgi.py:

    $ touch wsgi.py
    
  13. Откройте файл wsgi.py любым текстовым редактором и скопируйте в него код, запускающий тестовое приложение:

    # wsgi.py
    from api import app
    
    if __name__ == "__main__":
        app.run()
    
  14. Создайте в директории /srv/test-app файл test-app.ini:

    $ touch test-app.ini
    
  15. Откройте файл test-app.ini любым текстовым редактором и скопируйте в него конфигурацию сервера uWSGI:

    #test-app.ini
    [uwsgi]
    module = wsgi:app
    
    master = true
    processes = 1
    
    socket = test-app.sock
    chmod-socket = 660
    vacuum = true
    
    die-on-term = true
    
  16. Назначьте пользователя www-data владельцем директории /srv/test-app и файлов в ней:

    $ sudo chown -R www-data:www-data /srv/test-app
    
  17. Подготовьте сервис для запуска вашего uWSGI-сервера. Для этого приведите файл /etc/systemd/system/test-app.service к следующему виду:

    #/etc/systemd/system/test-app.service
    [Unit]
    Description=uWSGI instance to serve test API
    After=network.target
    
    [Service]
    User=www-data
    Group=www-data
    WorkingDirectory=/srv/test-app
    Environment="PATH=/srv/test-app/test-venv/bin"
    ExecStart=/srv/test-app/test-venv/bin/uwsgi --ini test-app.ini
    
    [Install]
    WantedBy=multi-user.target
    
  18. Укажите настройки нового виртуального сервера в конфигурации nginx, приведя файл /etc/nginx/sites-available/test-app.conf к следующему виду:

    #/etc/nginx/sites-available/test-app.conf
    server {
        #server_name test-app.yandex  www.test-app.yandex;
    
        listen 80;
    
        location /test/ {
            include uwsgi_params;
            uwsgi_param SCRIPT_NAME /test;
            uwsgi_modifier1 30;
            uwsgi_pass unix:/srv/test-app/test-app.sock;
        }
    }
    
  19. Создайте символическую ссылку, указывающую на конфигурационный файл nginx test-app.conf:

    $ sudo ln -s /etc/nginx/sites-available/test-app.conf /etc/nginx/sites-enabled/
    
  20. Удалите символическую ссылку, указывающую на конфигурацию nginx по умолчанию:

    $ sudo unlink /etc/nginx/sites-enabled/default
    
  21. Добавьте сервис в список автозапуска системы:

    $ sudo systemctl enable test-app.service
    

Проверьте работу тестового приложения

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

  1. В строке браузера введите URL для проверки работы веб-сервера и приложения:

    http://<публичный_IP_адрес_ВМ>/test/?text=hello_world
    
  2. Если все выполнено верно, на экране отобразится текст с перевернутыми словами из параметра text.

Подготовьте снимок диска виртуальной машины

Чтоб легко переносить созданное приложение и конфигурацию веб-сервера на создаваемые с помощью CI машины, нужно сделать снимок диска тестовой виртуальной машины.

  1. В консоли управления Яндекс.Облака выберите каталог, в котором создана виртуальная машина.
  2. Выберите сервис Compute Cloud.
  3. Найдите виртуальную машину ci-tutorial-test-app и выберите ее.
  4. Нажмите кнопку Остановить.
  5. В открывшемся окне нажмите кнопку Остановить.
  6. После остановки ВМ выберите вкладку Диски.
  7. В строке диска нажмите кнопку vertical-ellipsis и выберите пункт Создать снимок.
  8. В открывшемся окне введите имя снимка: test-app-snap.
  9. Нажмите кнопку Создать снимок.

Создайте виртуальную машину с GitLab

Один из способов настроить CI в Яндекс.Облаке — воспользоваться публичным образом с предустановленной системой GitLab. В GitLab входит набор инструментов для управления репозиториями git и средства для настройки CI.

  1. На странице каталога в консоли управления нажмите кнопку Создать ресурс и выберите Виртуальная машина.

  2. В поле Имя введите имя виртуальной машины: ci-tutorial-gitlab.

  3. Выберите зону доступности, в которой будет находиться виртуальная машина.

  4. В разделе Образы нажмите кнопку Выбрать.

  5. В открывшемся окне откройте вкладку DevTools.

  6. Выберите образ GitLab.

  7. В блоке Вычислительные ресурсы выберите следующую конфигурацию:

    • Гарантированная доля vCPU — 100%.
    • vCPU — 2.
    • RAM — 2 ГБ.
  8. В блоке Сетевые настройки выберите, к какой подсети необходимо подключить виртуальную машину при создании.

  9. Укажите данные для доступа на виртуальную машину:

    • В поле Логин введите имя пользователя.
    • В поле SSH ключ скопируйте содержимое файла открытого ключа. Пару ключей для подключения по SSH необходимо создать самостоятельно. Для создания ключей используйте сторонние инструменты, например утилиты ssh-keygen в Linux и macOS или PuTTYgen в Windows.
  10. Нажмите кнопку Создать ВМ.

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

При создании виртуальной машине назначаются IP-адрес и имя хоста (FQDN). Эти данные можно использовать для доступа по SSH.

Настройте GitLab

Чтобы настроить GitLab и подготовить CI, необходимо создать новый репозиторий и ввести необходимые параметры для авторизации в CI.

  1. Откройте в браузере административную панель GitLab на созданной ВМ. Для этого откройте в браузере ссылку вида http://<публичный-IP-адрес-ВМ>.

  2. Задайте пароль администратора.

  3. Авторизуйтесь с логином root и заданным паролем администратора.

  4. Выберите сервис Create a project.

  5. Задайте имя проекта: gitlab-test.

  6. Нажмите кнопку Create project.

  7. Получите OAuth-токен в сервисе Яндекс.OAuth. Для этого перейдите по ссылке и нажмите Разрешить.

  8. Откройте в браузере ссылку вида http://<публичный-IP-адрес-ВМ>/root.

  9. Выберите проект gitlab-test.

  10. На открывшемся экране выберите слева вкладку Settings, а во всплывающем меню — CI/CD.

  11. В разделе Variables нажмите кнопку Expand.

  12. Создайте новую переменную:

    • В качестве имени переменной укажите YC_OAUTH.
    • В качестве значения переменной укажите полученный OAuth-токен.
    • Нажмите кнопку Save variables.
  13. В разделе Runners нажмите кнопку Expand.

  14. В разделе Set up a specific Runner automatically указан адрес сервера для подключения и токен для регистрации сервера в проекте. Используйте эти значения при регистрации Runner.

Настройте Runner

Runner — это инструмент для выполнения задач, которые создает пользователь. Runner необходимо установить на виртуальную машину и зарегистрировать его в GitLab. Чтобы Runner мог выполнять задачи, подготовьте дополнительные компоненты — установите CLI Яндекс.Облака и создайте тест для проверки созданной виртуальной машины.

  1. Подключитесь к виртуальной машине c GitLab по SSH:

    $ ssh <Логин>@<публичный_IP-адрес_виртуальной_машины_с_GitLab>
    
  2. Добавьте новый репозиторий в менеджер пакетов:

    $ curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
    
  3. Установите Runner, который будет выполнять скрипты вашего CI:

    $ sudo apt-get -y install gitlab-runner
    
  4. Зарегистрируйте Runner:

    • На шаге Please enter the gitlab-ci coordinator URL укажите адрес сервера GitLab.
    • На шаге Please enter the gitlab-ci token for this runner укажите токен Runner.
    • На шаге Please enter the gitlab-ci description for this runner введите описание gitlab test runner.
    • На шаге Please enter the gitlab-ci tags for this runner не вводите ничего, нажмите Enter.
    • На шаге Please enter the executor укажите shell.
    $ sudo gitlab-runner register
    Runtime platform                                    arch=amd64 os=linux pid=8197 revision=3afdaba6 version=11.5.0
    Running in system-mode.
    
    Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
    http://<IP-адрес-ci-gitlab>/
    Please enter the gitlab-ci token for this runner:
    <токен-Runner>
    Please enter the gitlab-ci description for this runner:
    [ci-tutorial-gitlab]: gitlab test runner
    Please enter the gitlab-ci tags for this runner (comma separated):
    
    Registering runner... succeeded                     runner=wZqzyy9s
    Please enter the executor: virtualbox, docker+machine, docker-ssh+machine, kubernetes, docker, docker-ssh, shell, ssh, parallels:
    shell
    Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
    
  5. Чтобы скрипт CI мог создавать виртуальные машины, установите CLI Яндекс.Облака:

    $ curl https://storage.yandexcloud.net/yandexcloud-yc/install.sh --output install.sh
    $ sudo bash install.sh -n -i /opt/yandex-cloud
    
  6. Для проведения функционального тестирования установите пакет pytest:

    $ sudo apt-get install python-pytest
    
  7. Создайте файл test.py со скриптом для функционального тестирования:

    1. Откройте главную страницу репозитория gitlab-test.

    2. Нажмите кнопку + и выберите пункт New file.

    3. В открывшемся окне дайте файлу имя test.py.

    4. В тело файла скопируйте следующий код:

      # test.py
      import pytest
      import json
      import socket as s
      
      
      @pytest.fixture
      def hostname(request):
          with open("instance-creation.out", "r") as fd:
              fqdn = json.loads(fd.read()).get("fqdn")
      
          return fqdn
      
      
      @pytest.fixture
      def socket(request):
          _socket = s.socket(s.AF_INET, s.SOCK_STREAM)
          def socket_teardown():
              _socket.close()
          request.addfinalizer(socket_teardown)
          return _socket
      
      
      def test_server_connect(socket, hostname):
          socket.connect((hostname, 80))
          assert socket
      
    5. Напишите любое сообщение коммита и нажмите кнопку Commit changes.

Настройте CI

Для CI необходимо задать конфигурацию.

  1. Откройте главную страницу репозитория gitlab-test:

    http://<публичный_IP_адрес_ВМ_c_GitLab>/root/gitlab-test
    
  2. Нажмите кнопку Set up CI/CD. Откроется экран добавления нового файла.

  3. GitLab автоматически даст файлу имя .gitlab-ci.yml — не изменяйте его. Скопируйте в файл следующую конфигурацию:

    #.gitlab-ci.yml
    stages:
      - build
      - test
    
    build:
      stage: build
      variables:
        snapshot_name: test-app-snap
        folder_id: <идентификатор-каталога>
        subnet_name: <имя-подсети>
      script:
        - export instance_name="ci-tutorial-test-app-$(date +%s)"
        - export PATH="/opt/yandex-cloud/bin:${PATH}"
        - yc config set token $YC_OAUTH
        - yc compute instance create
          --format json
          --name $instance_name
          --folder-id $folder_id
          --zone ru-central1-c
          --network-interface subnet-name=$subnet_name,nat-ip-version=ipv4
          --create-boot-disk name=$instance_name-boot,type=network-ssd,size=15,snapshot-name=$snapshot_name,auto-delete=true
          --memory 1
          --cores 1
          --hostname $instance_name > instance-creation.out
        - sleep 30
      artifacts:
        when: on_success
        paths:
        - instance-creation.out
        expire_in: 10 mins
    
    test_external:
      stage: test
      script:
        - py.test test.py > pytest-external.out
      artifacts:
        paths:
        - pytest-external.out
        expire_in: 1 hour
    
  4. В поле snapshot_name укажите имя снимка первой виртуальной машины. В поле folder_id укажите идентификатор каталога, в котором создаются виртуальные машины. В поле subnet_name укажите имя подсети, к которой будут подключаться виртуальные машины — имя можно получить в консоли управления, открыв нужный каталог и перейдя на страницу сервиса Virtual Private Cloud.

  5. Нажмите кнопку Commit changes.

Проверьте работу приложения на виртуальной машине, созданной с помощью CI

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

Чтобы проверить созданную виртуальную машину:

  1. Откройте консоль управления Яндекс.Облака.

  2. В каталоге, где создавались виртуальные машины, откройте сервис Compute Cloud.

  3. Если все было настроено верно, в списке виртуальных машин должна появиться новая виртуальная машина с именем вида ci-tutorial-test-app-1543910277.

  4. Выберите созданную виртуальную машину и скопируйте публичный адрес созданной виртуальной машины.

  5. В браузере откройте ссылку вида:

    http://<публичный_IP_адрес_созданной_ВМ>/test/?text=hello_world
    
  6. Созданное на предыдущих шагах приложение должно работать и на созданной виртуальной машине: возвращать перевернутые слова из параметра text.

Удалите созданные ресурсы

Если вам больше не нужны ВМ и образы: