Описание сетапа развёртывания группы ресурсов Azure с одной виртуальной машиной для будущего мониторинга проекта.
В этой части — создание Azure Resource Manager шаблона, настройка Jenkins и примеры Groovy скриптов.
Далее — провижен NGINX и Prometheus с Ansbile. Ещё позже — Grafana.
Все файлы и скрипты хранятся в Github.
Содержание
Подготовка
Используем готовый шаблон от Azure отсюда>>>.
Переименовываем файлы:
[simterm]
$ mv azuredeploy.json jm-monitoring.json $ mv azuredeploy.parameters.json jm-monitoring.parameters.json
[/simterm]
Добавляем RSA ключ:
[simterm]
$ mkdir .ssh $ cp ~/.ssh/setevoy_main_pub_openssh .ssh/jm-monitoring.pub $ cp ~/.ssh/setevoy_main_priv_openssh .ssh/jm-monitoring
[/simterm]
Логинимся:
[simterm]
$ azure login
[/simterm]
Создаём группу ресурсов:
[simterm]
$ azure group create -n jm-monitoring-dev -l westeurope ... info: group create command OK
[/simterm]
Обновление ARM шаблона
Сначала обновляем параметры.
vmSize из variables переносим в parameters, что бы иметь возможность менять тип интанса для Dev и Prod (хотя можно было бы использовать какой-то mapping, по аналогии с AWS CloudFormation — но тратить на это время желания и необходимости нет):
...
"vmSize": {
"type": "string",
"defaultValue": "Standard_DS1",
"metadata": {
"description": "SSH rsa public key file as a string."
}
}
...
Обновляем переменные. Мне не нравятся имена, генерируемые Azure — имя ресурса, включающее имя группы выглядит приятнее и понятнее.
Т.е. используем функцию concat() и подставляем имя группы ресурсов и тип ресурса: "[concat(resourceGroup().name,'-RESOURCETYPE')]".
Тут же меняем ОС с Ubuntu 14 на Ubuntu 16:
...
"variables": {
"vmName": "[concat(resourceGroup().name,'-vm')]",
"ubuntuOSVersion": "16.04.0-LTS",
"uniqueDnsLabelPrefix": "[concat(resourceGroup().name,'-ip')]",
...
"addressPrefix": "10.0.0.0/16",
"subnet1Name": "[concat(resourceGroup().name,'-subnet')]",
...
"nicName": "[concat(resourceGroup().name,'-nic')]",
"publicIPAddressName": "[concat(resourceGroup().name,'-ip')]",
...
"virtualNetworkName": "[concat(resourceGroup().name,'-vnet')]",
"networkSecurityGroupName": "[concat(resourceGroup().name,'-nsg')]",
...
},
...
Обновляем ресурс «Microsoft.Compute/virtualMachines» — vmSize был в переменных, теперь в параметрах — "[parameters('vmSize')]":
...
{
"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')]"
},
...
Запускаем тестовый деплой группы:
[simterm]
$ azure group deployment create --resource-group jm-monitoring-dev \ > --name init \ > --template-file jm-monitoring.json \ > --parameters-file jm-monitoring.parameters.json info: Executing command group deployment create + Initializing template configurations and parameters + Creating a deployment info: Created template deployment "init" + Waiting for deployment to complete ... info: group deployment create command OK
[/simterm]
Хорошо, всё готово:
Логинимся, проверяем:
[simterm]
$ ssh -i .ssh/jm-monitoring jmadmin@13.***.***.62 ... Are you sure you want to continue connecting (yes/no)? yes ... jmadmin@jm-monitoring-dev-vm:~$
[/simterm]
Отлично.
Network security group
Обновим NSG, разрешим доступ по SSH только с одного IP и добавим доступ по 80 и 443, тоже с одного IP.
Возвращаемся к шаблону, обновляем ресурс «Microsoft.Network/networkSecurityGroups»:
...
{
"apiVersion": "[variables('apiVersion')]",
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[variables('networkSecurityGroupName')]",
"location": "[variables('location')]",
"properties": {
"securityRules": [
{
"name": "SSH_Work_Allow",
"properties": {
"description": "Locks inbound down to ssh default port 22.",
"protocol": "Tcp",
"sourcePortRange": "*",
"destinationPortRange": "22",
"sourceAddressPrefix": "194.***.***.45",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 120,
"direction": "Inbound"
}
},
{
"name": "HTTP_Work_Allow",
"properties": {
"description": "Locks inbound down to HTTP default port 80.",
"protocol": "Tcp",
"sourcePortRange": "*",
"destinationPortRange": "80",
"sourceAddressPrefix": "194.***.***.45",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 130,
"direction": "Inbound"
}
},
{
"name": "HTTPS_Work_Allow",
"properties": {
"description": "Locks inbound down to HTTPS default port 443.",
"protocol": "Tcp",
"sourcePortRange": "*",
"destinationPortRange": "443",
"sourceAddressPrefix": "194.***.***.45",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 140,
"direction": "Inbound"
}
}
]
}
},
...
Сохраняем, повторяем деплой (не уверен, что ARM разрешит обновить так правила в NSG):
[simterm]
$ azure group deployment create --resource-group jm-monitoring-dev --name NSG_Update --template-file jm-monitoring.json --parameters-file jm-monitoring.parameters.json
[/simterm]
Гуд — всё обновилось.
Jenkins
Для Jenkins используем Jenkins Pipeline плагин и Groovy скрипты.
Основной скрипт jm-monitoring-dev-provision.groovy содержит фукнции:
#!/usr/bin/env groovy
def templateValidate(infraUrl='1', env='2', resGroup='3', templateFile='4', paramFile='5') {
docker.image('microsoft/azure-cli').inside('-v /var/run/docker.sock:/var/run/docker.sock') {
git branch: "${BRANCH}", credentialsId: 'jm-github', url: "${infraUrl}"
stage('Temlate validate') {
sh "azure login -v -u ${AZURUSER} -p ${AZUREPASS}"
sh "azure account set -v ${SUBSCRIPTION}"
sh "azure group template validate -g ${resGroup} -f jm-monitoring/${templateFile} -e jm-monitoring/${paramFile}"
}
}
}
def environmentUpdate(infraUrl='1', env='2', resGroup='3', templateFile='4', paramFile='5', tag='6') {
docker.image('microsoft/azure-cli').inside('-v /var/run/docker.sock:/var/run/docker.sock') {
git branch: "${BRANCH}", credentialsId: 'jm-github', url: "${infraUrl}"
stage('Environment update') {
sh "azure login -v -u ${AZURUSER} -p ${AZUREPASS}"
sh "azure account set -v ${SUBSCRIPTION}"
sh "azure group deployment create -n ${tag} -g ${resGroup} -f jm-monitoring/${templateFile} -e jm-monitoring/${paramFile}"
}
}
}
def verify(msg='1') {
stage 'Verify'
input id: 'Deploy', message: "${msg}", ok: 'Deploy!'
}
return this
(не забываем return this)
И скрипт провижена самого окружения:
#!/usr/bin/env groovy
node {
TAG = "${env.BUILD_TAG}"
INFRAURL = 'https://github.com/jm/azure-infrastructure.git'
RESGROUP = "${RESGROUP}"
TMPL = "${TMPL}"
PARAMS = "${PARAMS}"
dir('buildscripts') {
git branch: 'master', credentialsId: 'jm-github', url: 'https://github.com/jm/jm-jenkins.git'
}
git branch: "${BRANCH}", credentialsId: 'jm-github', url: "${INFRAURL}"
def provision = load 'buildscripts/jm-monitoring-provision.groovy'
provision.templateValidate("${INFRAURL}", "${ENV}", "${RESGROUP}", "${TMPL}", "${PARAMS}")
provision.verify('Is Verify OK? Proceed with an environment deployment?')
provision.environmentUpdate("${INFRAURL}", "${ENV}", "${RESGROUP}", "${TMPL}", "${PARAMS}", "${TAG}")
}
Параметры в пайплайне Jenkins-а выглядят так:
Собственно — по Jenkins-у тут всё.
Запускаем, повторяем деплой, убеждаемся что всё работает:






