В этой статье показано, как развернуть кластер Docker Swarm в Azure с помощью Infrastructure-As-Code с Azure Bicep, доменным языком (DSL) для декларативного развертывания ресурсов Azure.
Docker Swarm — это инструмент оркестрации контейнеров, позволяющий управлять несколькими контейнерами, развернутыми на нескольких хост-компьютерах.
Следующий шаблон Bicep основан на следующей архитектуре:
Вы можете обратиться к следующему репозиторию GitHub для получения более подробной информации. Мы сосредоточимся на том, как вы можете выполнить развертывание, используя Bicep.
Одна из целей использования Bicep Language — повысить гибкость при создании инфраструктуры как кода для Azure.
Если вы прочтете приведенный выше репозиторий GitHub и шаблоны ARM, вы заметите, что это немного сложный шаблон ARM.
Используя Bicep, вы упростите объявление ресурсов, которые хотите развернуть в Azure.
Предпосылки
Для развертывания решения вам потребуется следующее:
- Активная учетная запись Azure: вы можете создать учетную запись бесплатно.
- Azure Bicep установлен на вашей локальной машине.
- Азур PowerShell. См.: Установка Azure PowerShell.
- Группа ресурсов в вашей подписке Azure.
Давайте начнем!
Обзор решения
Мы создадим шаблон Bicep, который создаст 3 менеджера Swarm и указанное количество узлов Swarm в расположении группы ресурсов.
Решение будет включать следующие файлы:
- main.bicep: это шаблон бицепса.
- azuredeploy.parameters.json: эти файлы параметров содержат значения, используемые для развертывания шаблона Bicep.
1. Создайте пару ключей SSH
Первый шаг — создать пару ключей SSH; вы можете прочитать следующую статью о том, как создать пару ключей SSH для виртуальных машин Linux в Azure — https://docs.microsoft.com/en-us/azure/virtual-machines/linux/mac-create-ssh-keys »
В этом случае мы создадим пару ключей SSH с помощью консоли Azure Bash. На портале Azure запросите новую консоль, как показано на изображении ниже.
Облачная оболочка — портал Azure
Затем мы сгенерируем SSH-ключ, используя следующую команду:
ssh-keygen \ -m PEM \ -t rsa \ -b 4096 \ -C "docker-swarm" \ -f ~/.ssh/docker-swarm-priv-key \ -N yourpasshphrase
Это сгенерирует ключ в каталоге SSH в вашем файловом ресурсе:
Если вы не знакомы с форматом открытого ключа SSH, вы можете отобразить свой открытый ключ с помощью следующей команды cat, заменив «~/.ssh/id_rsa.pub» на путь и имя файла. вашего собственного файла открытого ключа, если необходимо:
cat ~/.ssh/docker-swarm-priv-key.pub
Приведенная выше команда покажет открытый ключ SSH в консоли. Он понадобится нам во время развертывания, так что держите его под рукой.
Прохладный! Теперь у нас есть пара ключей SSH. Мы передадим значение этого ключа SSH в файле параметров.
2. Шаблон Azure Bicep — параметры
Создайте новый файл в своем рабочем каталоге и назовите его «main.bicep». Определим следующие параметры:
@description('SSH public key for the Virtual Machines.') @secure() param sshPublicKey string @description('Number of Swarm worker nodes in the cluster.') param nodeCount int = 3 @description('Location for all resources.') param location string = resourceGroup().location @description('Admin Username.') param adminUsername string = 'azureuser' @description('Default Master VM Size') param vmSizeMaster string = 'Standard_A0' @description('Default Node VM Size') param vmSizeNode string = 'Standard_A2'
3. Шаблон Azure Bicep — переменные
Мы определим следующие переменные:
var masterCount = 3 var vmNameMaster_var = 'swarm-master-' var vmNameNode_var = 'swarm-node-' var availabilitySetMasters_var = 'swarm-masters-set' var availabilitySetNodes_var = 'swarm-nodes-set' var osImagePublisher = 'Canonical' var osImageOffer = 'UbuntuServer' var osImageSKU = '16.04-LTS' var managementPublicIPAddrName_var = 'swarm-lb-masters-ip' var nodesPublicIPAddrName_var = 'swarm-lb-nodes-ip' var virtualNetworkName_var = 'swarm-vnet' var subnetNameMasters = 'subnet-masters' var subnetNameNodes = 'subnet-nodes' var addressPrefixMasters = '10.0.0.0/16' var addressPrefixNodes = '192.168.0.0/16' var subnetPrefixMasters = '10.0.0.0/24' var subnetPrefixNodes = '192.168.0.0/24' var mastersNsgName_var = 'swarm-masters-firewall' var nodesNsgName_var = 'swarm-nodes-firewall' var newStorageAccountName_var = uniqueString(resourceGroup().id, deployment().name) var clusterFqdn = 'swarm-${uniqueString(resourceGroup().id, deployment().name)}' var storageAccountType = 'Standard_LRS' var mastersLbName_var = 'swarm-lb-masters' var mastersLbIPConfigName = 'MastersLBFrontEnd' var mastersLbBackendPoolName = 'swarm-masters-pool' var nodesLbName_var = 'swarm-lb-nodes' var nodesLbBackendPoolName = 'swarm-nodes-pool' var sshKeyPath = '/home/${adminUsername}/.ssh/authorized_keys' var consulServerArgs = [ '-advertise 10.0.0.4 -bootstrap-expect 3 -retry-join 10.0.0.5 -retry-join 10.0.0.6' '-advertise 10.0.0.5 -retry-join 10.0.0.4 -retry-join 10.0.0.6' '-advertise 10.0.0.6 -retry-join 10.0.0.4 -retry-join 10.0.0.5' ]
4. Шаблон Azure Bicep — ресурсы
Мы определим следующие ресурсы:
resource newStorageAccountName 'Microsoft.Storage/storageAccounts@2021-01-01' = { name: newStorageAccountName_var location: location sku: { name: storageAccountType } kind: 'StorageV2' } resource availabilitySetMasters 'Microsoft.Compute/availabilitySets@2017-12-01' = { name: availabilitySetMasters_var location: location sku: { name: 'Aligned' } properties: { platformFaultDomainCount: 2 platformUpdateDomainCount: 5 } } resource availabilitySetNodes 'Microsoft.Compute/availabilitySets@2017-12-01' = { name: availabilitySetNodes_var location: location sku: { name: 'Aligned' } properties: { platformFaultDomainCount: 2 platformUpdateDomainCount: 5 } } resource managementPublicIPAddrName 'Microsoft.Network/publicIPAddresses@2015-06-15' = { name: managementPublicIPAddrName_var location: location properties: { publicIPAllocationMethod: 'Dynamic' dnsSettings: { domainNameLabel: '${clusterFqdn}-manage' } } } resource nodesPublicIPAddrName 'Microsoft.Network/publicIPAddresses@2015-06-15' = { name: nodesPublicIPAddrName_var location: location properties: { publicIPAllocationMethod: 'Dynamic' dnsSettings: { domainNameLabel: clusterFqdn } } } resource virtualNetworkName 'Microsoft.Network/virtualNetworks@2015-06-15' = { name: virtualNetworkName_var location: location properties: { addressSpace: { addressPrefixes: [ addressPrefixMasters addressPrefixNodes ] } subnets: [ { name: subnetNameMasters properties: { addressPrefix: subnetPrefixMasters networkSecurityGroup: { id: mastersNsgName.id } } } { name: subnetNameNodes properties: { addressPrefix: subnetPrefixNodes networkSecurityGroup: { id: nodesNsgName.id } } } ] } } resource mastersNsgName 'Microsoft.Network/networkSecurityGroups@2015-06-15' = { name: mastersNsgName_var location: location properties: { securityRules: [ { name: 'ssh' properties: { protocol: 'Tcp' sourcePortRange: '*' destinationPortRange: '22' sourceAddressPrefix: '*' destinationAddressPrefix: '*' access: 'Allow' priority: 1000 direction: 'Inbound' } } ] } } resource nodesNsgName 'Microsoft.Network/networkSecurityGroups@2015-06-15' = { name: nodesNsgName_var location: location properties: { securityRules: [ { name: 'AllowAny' properties: { description: 'Swarm node ports need to be configured on the load balancer to be reachable' protocol: '*' sourcePortRange: '*' destinationPortRange: '*' sourceAddressPrefix: '*' destinationAddressPrefix: '*' access: 'Allow' priority: 1000 direction: 'Inbound' } } ] } } resource vmNameMaster_nic 'Microsoft.Network/networkInterfaces@2015-06-15' = [for i in range(0, masterCount): { name: '${vmNameMaster_var}${i}-nic' location: location properties: { ipConfigurations: [ { name: 'ipConfigMaster' properties: { privateIPAllocationMethod: 'Static' privateIPAddress: '10.0.0.${(i + 4)}' subnet: { id: resourceId('Microsoft.Network/virtualNetworks/subnets', virtualNetworkName_var, subnetNameMasters) } loadBalancerBackendAddressPools: [ { id: resourceId('Microsoft.Network/loadBalancers/backendAddressPools', mastersLbName_var, mastersLbBackendPoolName) } ] loadBalancerInboundNatRules: [ { id: resourceId('Microsoft.Network/loadBalancers/inboundNatRules', mastersLbName_var, 'SSH-${vmNameMaster_var}${i}') } ] } } ] } dependsOn: [ mastersLbName virtualNetworkName mastersLbName_SSH_vmNameMaster ] }] resource mastersLbName 'Microsoft.Network/loadBalancers@2015-06-15' = { name: mastersLbName_var location: location properties: { frontendIPConfigurations: [ { name: mastersLbIPConfigName properties: { publicIPAddress: { id: managementPublicIPAddrName.id } } } ] backendAddressPools: [ { name: mastersLbBackendPoolName } ] } } resource mastersLbName_SSH_vmNameMaster 'Microsoft.Network/loadBalancers/inboundNatRules@2021-03-01' = [for i in range(0, masterCount): { name: '${mastersLbName_var}/SSH-${vmNameMaster_var}${i}' properties: { frontendIPConfiguration: { id: resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', mastersLbName_var, mastersLbIPConfigName) } protocol: 'Tcp' frontendPort: (i + 2200) backendPort: 22 enableFloatingIP: false } dependsOn: [ mastersLbName ] }] resource nodesLbName 'Microsoft.Network/loadBalancers@2015-06-15' = { name: nodesLbName_var location: location properties: { frontendIPConfigurations: [ { name: 'LoadBalancerFrontEnd' properties: { publicIPAddress: { id: nodesPublicIPAddrName.id } } } ] backendAddressPools: [ { name: nodesLbBackendPoolName } ] } } resource vmNameNode_nic 'Microsoft.Network/networkInterfaces@2015-06-15' = [for i in range(0, nodeCount): { name: '${vmNameNode_var}${i}-nic' location: location properties: { ipConfigurations: [ { name: 'ipConfigNode' properties: { privateIPAllocationMethod: 'Dynamic' subnet: { id: resourceId('Microsoft.Network/virtualNetworks/subnets', virtualNetworkName_var, subnetNameNodes) } loadBalancerBackendAddressPools: [ { id: resourceId('Microsoft.Network/loadBalancers/backendAddressPools', nodesLbName_var, nodesLbBackendPoolName) } ] } } ] } dependsOn: [ nodesLbName virtualNetworkName ] }] resource vmNameMaster 'Microsoft.Compute/virtualMachines@2017-03-30' = [for i in range(0, masterCount): { name: '${vmNameMaster_var}${i}' location: location properties: { availabilitySet: { id: availabilitySetMasters.id } hardwareProfile: { vmSize: vmSizeMaster } osProfile: { computerName: '${vmNameMaster_var}${i}' adminUsername: adminUsername linuxConfiguration: { disablePasswordAuthentication: true ssh: { publicKeys: [ { path: sshKeyPath keyData: sshPublicKey } ] } } } storageProfile: { imageReference: { publisher: osImagePublisher offer: osImageOffer sku: osImageSKU version: 'latest' } osDisk: { name: '${vmNameMaster_var}${i}_OSDisk' caching: 'ReadWrite' createOption: 'FromImage' } } networkProfile: { networkInterfaces: [ { id: resourceId('Microsoft.Network/networkInterfaces', '${vmNameMaster_var}${i}-nic') } ] } } dependsOn: [ newStorageAccountName availabilitySetMasters ] }] resource vmNameNode 'Microsoft.Compute/virtualMachines@2017-03-30' = [for i in range(0, nodeCount): { name: '${vmNameNode_var}${i}' location: location properties: { availabilitySet: { id: availabilitySetNodes.id } hardwareProfile: { vmSize: vmSizeNode } osProfile: { computerName: '${vmNameNode_var}${i}' adminUsername: adminUsername linuxConfiguration: { disablePasswordAuthentication: true ssh: { publicKeys: [ { path: sshKeyPath keyData: sshPublicKey } ] } } } storageProfile: { imageReference: { publisher: osImagePublisher offer: osImageOffer sku: osImageSKU version: 'latest' } osDisk: { name: '${vmNameNode_var}${i}_OSDisk' caching: 'ReadWrite' createOption: 'FromImage' } } networkProfile: { networkInterfaces: [ { id: resourceId('Microsoft.Network/networkInterfaces', '${vmNameNode_var}${i}-nic') } ] } } dependsOn: [ newStorageAccountName ] }] resource vmNameMaster_DockerExtension 'Microsoft.Compute/virtualMachines/extensions@2015-06-15' = [for i in range(0, masterCount): { name: '${vmNameMaster_var}${i}/DockerExtension' location: location properties: { publisher: 'Microsoft.Azure.Extensions' type: 'DockerExtension' typeHandlerVersion: '1.0' autoUpgradeMinorVersion: true settings: { compose: { consul: { image: 'progrium/consul' command: '-server -node master${i} ${consulServerArgs[i]}' ports: [ '8500:8500' '8300:8300' '8301:8301' '8301:8301/udp' '8302:8302' '8302:8302/udp' '8400:8400' ] volumes: [ '/data/consul:/data' ] restart: 'always' } swarm: { image: 'swarm' command: 'manage --replication --advertise ${reference(resourceId('Microsoft.Network/networkInterfaces', '${vmNameMaster_var}${i}-nic')).ipConfigurations[0].properties.privateIPAddress}:2375 --discovery-opt kv.path=docker/nodes consul://10.0.0.4:8500' ports: [ '2375:2375' ] links: [ 'consul' ] volumes: [ '/etc/docker:/etc/docker' ] restart: 'always' } } } } dependsOn: [ vmNameMaster ] }] resource vmNameNode_DockerExtension 'Microsoft.Compute/virtualMachines/extensions@2015-06-15' = [for i in range(0, nodeCount): { name: '${vmNameNode_var}${i}/DockerExtension' location: location properties: { publisher: 'Microsoft.Azure.Extensions' type: 'DockerExtension' typeHandlerVersion: '1.0' autoUpgradeMinorVersion: true settings: { docker: { port: '2375' options: [ '--cluster-store=consul://10.0.0.4:8500' '--cluster-advertise=eth0:2375' ] } } } dependsOn: [ vmNameNode ] }]
5. Выходы
Мы включим следующие выходы:
output sshTunnelCmd string = 'ssh -L 2375:swarm-master-0:2375 -N ${adminUsername}@${managementPublicIPAddrName.properties.dnsSettings.fqdn} -p 2200' output dockerCmd string = 'docker -H tcp://localhost:2375 info' output swarmNodesLoadBalancerAddress string = nodesPublicIPAddrName.properties.dnsSettings.fqdn output sshMaster0 string = 'ssh ${adminUsername}@${managementPublicIPAddrName.properties.dnsSettings.fqdn} -A -p 2200' output sshMaster1 string = 'ssh ${adminUsername}@${managementPublicIPAddrName.properties.dnsSettings.fqdn} -A -p 2201' output sshMaster2 string = 'ssh ${adminUsername}@${managementPublicIPAddrName.properties.dnsSettings.fqdn} -A -p 2202'
6. Файл параметров
Создайте новый файл с именем «azuredeploy.parameters.json». Код ниже показывает определение файла параметров:
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "sshPublicKey": { "value": "GEN-SSH-PUB-KEY" }, "nodeCount": { "value": 3 } } }
6. Шаблон Azure Bicep — развертывание
Мы будем использовать приведенную ниже команду для развертывания нашего шаблона Bicep:
$date = Get-Date -Format "MM-dd-yyyy" $deploymentName = "AzInsiderDeployment"+"$date" New-AzResourceGroupDeployment -Name $deploymentName -ResourceGroupName azinsider_demo -TemplateFile .\main.bicep -TemplateParameterFile .\azuredeploy.parameters.json -c
На изображении ниже показан предварительный просмотр развертывания:
Затем мы выполним развертывание. На изображении ниже показан результат развертывания:
Вы можете проверить развертывание на портале Azure.
Теперь вы можете подключиться к управляемым узлам Swarm по SSH, используя доменное имя или общедоступный IP-адрес swarm-lb-masters. Вы можете получить полное DNS-имя из выходных данных развертывания.
Чтобы получить доступ к рабочим узлам, вы можете получить к ним доступ с главных узлов. Дополнительные сведения см. в следующем репозитории GitHub — https://github.com/Azure/azure-quickstart-templates/tree/master/application-workloads/swarm/docker-swarm-cluster.
Полный шаблон Bicep и файл параметров можно найти по следующему URL-адресу:
👉 Присоединяйтесь к списку рассылки AzInsider здесь.
-Дэйв Р.