Azure DevOps pipeline to deploy Elasticsearch

This guide provides a comprehensive walkthrough for deploying an Elasticsearch application on an Azure Virtual Machine using an automated Azure DevOps pipeline. The process is broken down into four main parts: Azure VM Setup, Azure DevOps Pipeline Setup, Troubleshooting and Optimisation, and Security Recommendations.
- Setup Azure resource group
- Azure DevOps Pipeline Setup Guide
- Troubleshooting
- Security Recommendations
- Delete resource group
Setup Azure resource group
Azure VM
Install Azure CLI if not already installed
# macOS:
brew install azure-cli
# Login to Azure
az login
Let’s create the resources group
az group create \
--name "rg-elasticsearch-dev" \
--location "East US"
💥 It is essential to note that if you don’t delete the resource group, it will continue to incur charges. Please check the end of this post.
Create a virtuale machine:
az vm create \
--resource-group "rg-elasticsearch-dev" \
--name "vm-elasticsearch-dev" \
--image "Ubuntu2204" \
--size "Standard_B2s" \
--admin-username "azureuser" \
--generate-ssh-keys \
--public-ip-sku Standard \
--location "East US"
Configure Public DNS (Recommended)
# Create a unique DNS prefix
DNS_PREFIX="elasticsearch-$(date +%s)"
az network public-ip update \
--resource-group "rg-elasticsearch-dev" \
--name "vm-elasticsearch-devPublicIP" \
--dns-name "$DNS_PREFIX"
Open Required Ports
# HTTPS port for Kibana
az network nsg rule create \
--resource-group "rg-elasticsearch-dev" \
--nsg-name "vm-elasticsearch-devNSG" \
--name "Allow-Kibana-HTTPS" \
--priority 1001 \
--access Allow \
--protocol Tcp \
--destination-port-ranges 8443
# HTTP port for Kibana (redirects to HTTPS)
az network nsg rule create \
--resource-group "rg-elasticsearch-dev" \
--nsg-name "vm-elasticsearch-devNSG" \
--name "Allow-Kibana-HTTP" \
--priority 1002 \
--access Allow \
--protocol Tcp \
--destination-port-ranges 8080
If you need new rule, check what priorites are enabled
az network nsg rule list \
--resource-group "rg-elasticsearch-dev" \
--nsg-name "vm-elasticsearch-devNSG" \
--query "[].{Name:name, Priority:priority, Port:destinationPortRange}" \
--output table
Output:
Name Priority Port
------------------ ---------- ------
default-allow-ssh 1000 22
Allow-Kibana-HTTPS 1001 8443
Allow-Kibana-HTTP 1002 8080
If you want to enable standard ports 443:
az network nsg rule create \
--resource-group "rg-elasticsearch-dev" \
--nsg-name "vm-elasticsearch-devNSG" \
--name "Allow-HTTPS-Standard" \
--priority 1003 \
--access Allow \
--protocol Tcp \
--destination-port-ranges 443
📊 Azure NSG Priority System
Azure NSG rules need unique priorities between 100-4096:
Priority | Typical Use |
---|---|
100-299 | High priority (critical services) |
300-999 | Standard services |
1000-1999 | Common services (SSH typically uses 1000) |
2000-4096 | Low priority rules |
Get VM Details
az vm show -d \
--resource-group "rg-elasticsearch-dev" \
--name "vm-elasticsearch-dev" \
--query "{Name:name, PublicIP:publicIps, FQDN:fqdns, PrivateIP:privateIps}" \
--output table
Test SSH Connection
# Replace with your VM's public IP or FQDN
ssh azureuser@YOUR_VM_IP_OR_FQDN
If you want to stop, deallocate
az vm stop --resource-group "rg-elasticsearch-dev" --name "vm-elasticsearch-dev" && \
az vm deallocate --resource-group "rg-elasticsearch-dev" --name "vm-elasticsearch-dev"
and start again
az vm start --resource-group "rg-elasticsearch-dev" --name "vm-elasticsearch-dev"
Azure DevOps Pipeline Setup Guide
Prerequisites
- Azure VM created (above)
- SSH access to the VM is working
- Azure DevOps organization:
https://dev.azure.com/<your orginaisation>
Step 1: Create SSH Service Connection
1.1 Get SSH Private Key
On your local machine (where you created the VM):
# Display your private key
cat ~/.ssh/id_rsa
# Copy the entire content including headers:
# -----BEGIN OPENSSH PRIVATE KEY-----
# ...key content...
# -----END OPENSSH PRIVATE KEY-----
1.2 Create Service Connection in Azure DevOps
- Go to https://dev.azure.com/…
- Select your project
- Navigate to Project Settings (bottom left)
- Click Service connections
- Click Create service connection
- Choose SSH and click Next
1.3 Configure SSH Connection
Fill in these details:
Connection name: elasticsearch-vm-connection
Host name: [YOUR_VM_PUBLIC_IP_OR_FQDN]
Port number: 22
User name: azureuser
Private key: [PASTE YOUR SSH PRIVATE KEY HERE]
1.4 Verify Connection
Click Verify to test the connection, then Save.
Step 2: Create Environment
2.1 Create Production Environment
- Go to Pipelines → Environments
- Click Create environment
- Configure:
Name: elasticsearch-production Description: Production environment for Elasticsearch deployment
- Click Create
2.2 Add VM Resource (Optional)
- In the environment, click Add resource
- Choose Virtual machines
- Select Linux
- Use the SSH connection details to add your VM
Step 3: Set Up the Pipeline
3.1 Update Pipeline Variables
Your azure-pipelines.yml
already has good configuration. Verify these variables match your VM:
variables:
vmResourceGroup: 'rg-elasticsearch-dev'
vmName: 'vm-elasticsearch-dev'
vmAdminUser: 'azureuser'
serverDomain: '[YOUR_VM_FQDN]' # Update this!
3.2 Update Server Domain
Replace [YOUR_VM_FQDN]
with your actual VM domain. Get it by running:
az vm show -d \
--resource-group "rg-elasticsearch-dev" \
--name "vm-elasticsearch-dev" \
--query "fqdns" \
--output tsv
3.3 Create the Pipeline
- Go to Pipelines → Pipelines
- Click Create Pipeline
- Choose Azure Repos Git (or your repo location)
- Select your repository
- Choose an Existing Azure Pipelines YAML file
- Select
/azure-pipelines.yml
- Click Continue
3.4 Review and Save
- Review the pipeline configuration
- Click Save and run
Step 4: Update Environment File for Remote Deployment
Your pipeline automatically handles this. The file .env.template
will be copied and modified as required.
Step 5: Run the Pipeline
5.1 Manual Trigger
- Go to your pipeline
- Click Run pipeline
- Select the branch (usually
main
) - Click Run
5.2 Monitor Deployment
The pipeline will:
- Build Stage: Prepare deployment artifacts
- Deploy Stage: Deploy to your VM
- Post-Deployment: Verify the deployment
5.3 Check Deployment Logs
Monitor each stage for any issues:
- Prepare VM Environment: Install Docker, Docker Compose
- Copy Application Files: Transfer your code
- Deploy Application: Start the services
- Verify Deployment: Health checks
Step 6: Verify Deployment
6.1 Check Pipeline Success
Ensure all stages complete successfully.
6.2 Test Remote Access
Replace [YOUR_VM_FQDN]
with your actual domain:
# Test HTTP (should redirect to HTTPS)
curl -I http://[YOUR_VM_FQDN]:8080
# Test HTTPS (ignore SSL warnings for self-signed cert)
curl -k https://[YOUR_VM_FQDN]:8443/api/status
6.3 Access Kibana
Open in browser:
https://[YOUR_VM_FQDN]:8443
Default credentials:
- Username:
elastic
- Password:
changeme
Troubleshooting
Common Issues
It is essential to know that
- Use
runOptions: 'inline'
instead ofrunOptions: 'commands'
for complex conditionals. - The
inline
option treats your code as a proper bash script. - The
commands
option has parsing limitations with multi-line if statements.
Method 1: Chained Commands (Simple cases)
# OLD (Broken)
commands: |
cd $(deploymentPath)
docker-compose up -d
# NEW (Fixed)
commands: |
cd $(deploymentPath) && docker-compose up -d
Method 2: Single Script Session (Complex cases)
# For tasks with multiple directory-dependent commands
runOptions: 'inline' # This runs as a single script!
inline: |
#!/bin/bash
set -e
cd $(deploymentPath)
# All commands run in same session now
docker-compose up -d
./manage.sh health
Upgrade to 16GB RAM (Recommended):
bash
az vm stop --resource-group "rg-elasticsearch-dev" --name "vm-elasticsearch-dev" && \
az vm deallocate --resource-group "rg-elasticsearch-dev" --name "vm-elasticsearch-dev" && \
az vm resize --resource-group "rg-elasticsearch-dev" --name "vm-elasticsearch-dev" --size "Standard_B4ms" && \
az vm start --resource-group "rg-elasticsearch-dev" --name "vm-elasticsearch-dev" && \
echo "✅ VM upgraded to 16GB RAM (Standard_B4ms)"
Upgrade to 8GB RAM (Budget Option):
bash
az vm stop --resource-group "rg-elasticsearch-dev" --name "vm-elasticsearch-dev" && \
az vm deallocate --resource-group "rg-elasticsearch-dev" --name "vm-elasticsearch-dev" && \
az vm resize --resource-group "rg-elasticsearch-dev" --name "vm-elasticsearch-dev" --size "Standard_D2s_v3" && \
az vm start --resource-group "rg-elasticsearch-dev" --name "vm-elasticsearch-dev" && \
echo "✅ VM upgraded to 8GB RAM (Standard_D2s_v3)"
Upgrade to 32GB RAM (High Performance):
bash
az vm stop --resource-group "rg-elasticsearch-dev" --name "vm-elasticsearch-dev" && \
az vm deallocate --resource-group "rg-elasticsearch-dev" --name "vm-elasticsearch-dev" && \
az vm resize --resource-group "rg-elasticsearch-dev" --name "vm-elasticsearch-dev" --size "Standard_D8s_v3" && \
az vm start --resource-group "rg-elasticsearch-dev" --name "vm-elasticsearch-dev" && \
echo "✅ VM upgraded to 32GB RAM (Standard_D8s_v3)"
🔧 After Resize - Update Elasticsearch
Get VM Connection Info:
bash
az vm show -d --resource-group "rg-elasticsearch-dev" --name "vm-elasticsearch-dev" --query "{IP:publicIps, FQDN:fqdns}" --output table
1. SSH Connection Fails
# Test manual SSH
ssh azureuser@[YOUR_VM_IP]
# Check if port 22 is open
az network nsg rule list \
--resource-group "rg-elasticsearch-dev" \
--nsg-name "vm-elasticsearch-devNSG" \
--query "[?name=='default-allow-ssh']"
2. Docker Installation Fails
The pipeline installs Docker automatically, but if it fails:
# SSH into VM and install manually
ssh azureuser@[YOUR_VM_IP]
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
3. Services Don’t Start
# SSH into VM and check
ssh azureuser@[YOUR_VM_IP]
cd /opt/elasticsearch
sudo docker-compose logs -f
4. Firewall Issues
# Check Ubuntu firewall
sudo ufw status
# Allow ports if needed
sudo ufw allow 8443
sudo ufw allow 8080
Pipeline Failure Recovery
If the pipeline fails:
- Check the logs in Azure DevOps
- Fix the issue in your code
- Commit and push the changes
- Re-run the pipeline
Manual Deployment (Fallback)
If the pipeline doesn’t work, you can deploy manually:
# SSH into VM
ssh azureuser@[YOUR_VM_IP]
# Install dependencies
sudo apt update
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
# Clone your repo or copy files
git clone [YOUR_REPO_URL]
cd [YOUR_PROJECT_FOLDER]
# Start services
./manage.sh start
Security Recommendations
Change Default Passwords
Before production use:
- Update
.env
file with strong passwords - Redeploy the application
- Update any documentation with new credentials
SSL Certificates
For production, consider:
- Let’s Encrypt for free SSL certificates
- Azure Key Vault for certificate management
- Custom domain for better branding
Delete resource group
As a first step, list the subscriptions:
az account list --query "[?state=='Enabled'].{Name:name, SubscriptionId:id}" --output table
If you have one more active subscription, you have to set.
az account set --subscription "<your-subscription-id>"
To delete the resource group:
az group delete --name rg-elasticsearch-dev --yes --no-wait