Azure: подключение volume – ARM, Ansible и данные Prometheus

By | 10/12/2017
 

Задача – добавить подключение data-диска к виртуальной машине во время развёртывания Azure Resource Group с виртуальной машиной, смонтировать диск к файловой системе и запустить Prometheus с использованием этого диска для хранения данных.

Azure data disk

Диск уже есть.

Используем Azure CLI v2 из Docker образа:

docker run -v ~/Work/BER.JM/azure-infrastructure/:/root/azure-infrastructure/ -it  azuresdk/azure-cli-python

Логинимся:

bash-4.3# az login

Проверяем диски:

bash-4.3# az disk list -g europe-jm --query '[*].{Name:name,Gb:diskSizeGb,Tier:accountType}' --output table
Name                           Gb
---------------------------  ----
jenkinsworkspaces             100
jm-monitoring-data-disk-dev    10

(Azure в новой CLI тупо копирует всё от AWS CLI – даже --query…)

Azure template

Шаблон уже есть – см. пост Azure: provisioning с Resource Manager, Jenkins и Groovy.

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

Сейчас ресурс выглядит так:

...
    {
      "apiVersion": "2016-04-30-preview",
      "type": "Microsoft.Compute/virtualMachines",
      "name": "[variables('vmName')]",
      "location": "[variables('location')]",
      "dependsOn": [
        "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
      ],
      "properties": {
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "osProfile": {
          "computerName": "[variables('vmName')]",
          "adminUsername": "[parameters('adminUserName')]",
          "linuxConfiguration": {
            "disablePasswordAuthentication": "true",
            "ssh": {
              "publicKeys": [
                {
                  "path": "[variables('sshKeyPath')]",
                  "keyData": "[parameters('sshKeyData')]"
                }
              ]
            }
          }
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "[variables('imagePublisher')]",
            "offer": "[variables('imageOffer')]",
            "sku": "[variables('ubuntuOSVersion')]",
            "version": "latest"
          },
          "osDisk": {
            "createOption": "FromImage"
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]"
            }
          ]
        }
      }
    }
...

В parameters шаблона добавляем параметр с указанием диска:

...
    "vmdatadiskname": {
      "type": "string",
      "metadata": {
        "description": "Existing data disk resource ID to be attached to VM."
      }
    }
...

В файле параметров указываем значение:

...
    "vmdatadiskname": {
      "value": "/subscriptions/0a4f2b9c-***-***-***-40b17ef8c3ab/resourceGroups/europe-jm/providers/Microsoft.Compute/disks/jm-monitoring-data-disk-dev"
    }
...

К ресурсу виртуальной машины добавляем подключение диска:

...
          "dataDisks": [
              {
                  "lun": 0,
                  "createOption": "Attach",
                  "caching": "None",
                  "diskSizeGB": 10,
                  "managedDisk": {
                      "id": "[parameters('vmdatadiskname')]"
                  }
              }
          ]
...

В результате – ресурс виртуальной машины полностью теперь будет выглядеть так:

...
    {
      "apiVersion": "2016-04-30-preview",
      "type": "Microsoft.Compute/virtualMachines",
      "name": "[variables('vmName')]",
      "location": "[variables('location')]",
      "dependsOn": [
        "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
      ],
      "properties": {
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "osProfile": {
          "computerName": "[variables('vmName')]",
          "adminUsername": "[parameters('adminUserName')]",
          "linuxConfiguration": {
            "disablePasswordAuthentication": "true",
            "ssh": {
              "publicKeys": [
                {
                  "path": "[variables('sshKeyPath')]",
                  "keyData": "[parameters('sshKeyData')]"
                }
              ]
            }
          }
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "[variables('imagePublisher')]",
            "offer": "[variables('imageOffer')]",
            "sku": "[variables('ubuntuOSVersion')]",
            "version": "latest"
          },
          "osDisk": {
            "createOption": "FromImage"
          },
          "dataDisks": [
              {
                  "lun": 0,
                  "createOption": "Attach",
                  "caching": "None",
                  "diskSizeGB": 10,
                  "managedDisk": {
                      "id": "[parameters('vmdatadiskname')]"
                  }
              }
          ]

        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]"
            }
          ]
        }
      }
    }
...

Сохраняем в репозиторий, запускаем provision в Jenkins на уже развёрнутую группу ресурсов – ARM должен обновить вирутальную машину и подключить к ней диск:

git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified:   jm-monitoring/jm-monitoring.json
...
git add jm-monitoring/jm-monitoring.json && git commit -m "data disk attach" && git push

Билд в Jenkins:

...
info:    Resource 'jm-monitoring-dev-vm' of type 'Microsoft.Compute/virtualMachines' provisioning status is Running
info:    Resource 'jm-monitoring-dev-nic' of type 'Microsoft.Network/networkInterfaces' provisioning status is Succeeded
info:    Resource 'jm-monitoring-dev-ip' of type 'Microsoft.Network/publicIPAddresses' provisioning status is Succeeded
info:    Resource 'jm-monitoring-dev-vnet' of type 'Microsoft.Network/virtualNetworks' provisioning status is Succeeded
info:    Resource 'jm-monitoring-dev-nsg' of type 'Microsoft.Network/networkSecurityGroups' provisioning status is Succeeded
...
info:    Resource 'jm-monitoring-dev-vm' of type 'Microsoft.Compute/virtualMachines' provisioning status is Succeeded
info:    Resource 'jm-monitoring-dev-nic' of type 'Microsoft.Network/networkInterfaces' provisioning status is Succeeded
info:    Resource 'jm-monitoring-dev-ip' of type 'Microsoft.Network/publicIPAddresses' provisioning status is Succeeded
info:    Resource 'jm-monitoring-dev-vnet' of type 'Microsoft.Network/virtualNetworks' provisioning status is Succeeded
info:    Resource 'jm-monitoring-dev-nsg' of type 'Microsoft.Network/networkSecurityGroups' provisioning status is Succeeded
data:    DeploymentName     : jenkins-jm-monitoring-azure-ENV-DEV-provisioning-14
data:    ResourceGroupName  : jm-monitoring-dev
data:    ProvisioningState  : Succeeded
data:    Timestamp          : Thu Oct 12 2017 09:38:01 GMT+0000 (UTC)
data:    Mode               : Incremental
...
info:    group deployment create command OK
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
$ docker stop --time=1 31c06c78359ca60182e19af5cd7df161e07c4da4cfe95b3500a504a1f2b4a614
$ docker rm -f 31c06c78359ca60182e19af5cd7df161e07c4da4cfe95b3500a504a1f2b4a614
[Pipeline] // withDockerContainer
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

Проверяем data-диск сервера:

bash-4.3# az vm show --resource-group jm-monitoring-dev --name jm-monitoring-dev-vm --query '{storageProfile:storageProfile.dataDisks}'
{
"storageProfile": [
{
"caching": "None",
"createOption": "Attach",
"diskSizeGb": 10,
"image": null,
"lun": 0,
"managedDisk": {
"id": "/subscriptions/0a4f2b9c-***-***-***-40b17ef8c3ab/resourceGroups/europe-jm/providers/Microsoft.Compute/disks/jm-monitoring-data-disk-dev",
"resourceGroup": "europe-jm",
"storageAccountType": "Standard_LRS"
},
"name": "jm-monitoring-data-disk-dev",
"vhd": null
}
]
}

diskSizeGB – надо бы тоже вынести в параметры для production.

Логинимся на сервер, проверяем там:

admin@jm-monitoring-dev-vm:~$ lsblk /dev/sdc
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sdc      8:32   0   10G  0 disk
└─sdc1   8:33   0   10G  0 part

ОК – диск есть, всё хорошо.

Ansible

Монтирование диска

Установка Prometheus и роли описаны в посте Ansible: роли для Docker Compose, Prometheus и node_exporter.

Аналогичную задачу – монтирование диска из Ansible – описывал в посте Ansible: RTFM Jenkins provision.

Имя раздела и каталог монтирования вынесем в переменные роли prometheus.

В файл jm-monitoring/ansible/jm-monitoring/roles/prometheus/vars/main.yml добавляем две переменные:

prometheus_data_volume: "/dev/sdc1"  
prometheus_data_mount_path: "/prometheus-data"

Далее, в файле jm-monitoring/ansible/jm-monitoring/roles/prometheus/tasks/main.yml добавляем создание каталога и монтирование диска:

...
- name: Create  "{{ prometheus_data_mount_path }}" directory
  file:
    path: "{{ prometheus_data_mount_path }}"
    owner: root
    group: root
    mode: 0755
    state: directory

- name: Mount volume "{{ prometheus_data_volume }}"
  mount:
    path: "{{ prometheus_data_mount_path }}"
    src: "{{ prometheus_data_volume }}"
    state: mounted
    fstype: ext4
...

Сохраняем изменения в репозиторий:

git status
...
modified:   jm-monitoring/ansible/jm-monitoring/roles/prometheus/tasks/main.yml
modified:   jm-monitoring/ansible/jm-monitoring/roles/prometheus/vars/main.yml

Запускаем Jenkins билд:

...
TASK [prometheus : Create  "/prometheus-data" directory] ***********************
sudo
-H -S -n
ok: [dev.monitoring.domain.ms]
TASK [prometheus : Mount EBS "/dev/sdc1"] **************************************
sudo
-H -S -n
changed: [dev.monitoring.domain.ms]
TASK [prometheus : Start Prometheus service] ***********************************

sudo
-H -S -n
ok: [dev.monitoring.domain.ms]

Обновление Prometheus docker-compose.yml

Последний шаг – подключить каталог /prometheus-data/ с данными к Docker-контейнеру, в котором запускается Prometheus.

По умолчанию – он хранит данные в каталоге /prometheus/:

root@jm-monitoring-dev-vm:~# docker exec -ti prometheus_prometheus_1 ls -l /prometheus
total 4576
drwx------    2 root     root          4096 Oct  2 11:42 00
drwx------    2 root     root          4096 Oct  3 19:47 01
drwx------    2 root     root          4096 Oct  2 15:17 02
drwx------    2 root     root          4096 Oct  2 11:45 03
...

Запуск описан в файле jm-monitoring/ansible/jm-monitoring/roles/prometheus/files/docker-compose.yml.

Что бы использовать в нём переменные ({{ prometheus_data_mount_path }}) – перемещаем его в templates:

mkdir jm-monitoring/ansible/jm-monitoring/roles/prometheus/templates
mv jm-monitoring/ansible/jm-monitoring/roles/prometheus/files/docker-compose.yml jm-monitoring/ansible/jm-monitoring/roles/prometheus/templates/docker-compose.yml.j2

Обновляем jm-monitoring/ansible/jm-monitoring/roles/prometheus/templates/docker-compose.yml.j2 – добавляем монтирование volume /prometheus-data/ с хоста в каталог /prometheus/ контейнера:

version: '2'
  
services:

  prometheus:

    network_mode: "host"

    image: prom/prometheus
    expose:
      - 9090
    ports:
      - 9090:9090
    volumes:
      - /etc/prometheus/:/etc/prometheus/
      - {{ prometheus_data_mount_path }}:/prometheus

Обновляем jm-monitoring/ansible/jm-monitoring/roles/prometheus/tasks/main.yml – в задаче Copy compose file меняем Ansible модуль copy на template:

...
- name: Copy compose file
  template:
    src: templates/docker-compose.yml.j2
    dest: "{{ prometheus_home }}/docker-compose.yml"
    owner: "{{ prometheus_user }}"
    group:  "{{ prometheus_group }}"
    mode: 0644
...

Повторяем билд Jenkins и проверяем данные в каталоге на хосте мониторинга:

root@jm-monitoring-dev-vm:~# ls -l /prometheus-data/
total 36
drwxr-xr-x 2 root root  4096 Oct 12 10:54 archived_fingerprint_to_metric
drwxr-xr-x 2 root root  4096 Oct 12 10:54 archived_fingerprint_to_timerange
-rw-r--r-- 1 root root     0 Oct 12 10:54 DIRTY
drwxr-xr-x 2 root root  4096 Oct 12 10:54 labelname_to_labelvalues
drwxr-xr-x 2 root root  4096 Oct 12 10:54 labelpair_to_fingerprints
drwx------ 2 root root 16384 Oct 12 10:27 lost+found
-rw-r--r-- 1 root root     2 Oct 12 10:54 VERSION

Проверяем сам контейнер:

docker inspect prometheus_prometheus_1
...
"Mounts": [
{
"Type": "bind",
"Source": "/prometheus-data",
"Destination": "/prometheus",
"Mode": "rw",
"RW": true,
"Propagation": "rprivate"
},
{
"Type": "bind",
"Source": "/etc/prometheus",
"Destination": "/etc/prometheus",
"Mode": "rw",
"RW": true,
"Propagation": "rprivate"
}
],
...

Данные node_exporter в самом Prometheus:

Готово.

Ссылки  по теме

Azure: Azure Resource Manager provisioning и Jenkins в Docker

Azure: подключение дополнительного диска к VM и миграция Jenkins

Azure: provisioning с Resource Manager, Jenkins и Groovy