In this document, we are going to use the Azure CLI to manage Azure resources.
First, after installing and configuring the Azure CLI, you need to log in to your account:
az loginThis command opens a browser window for you to sign in to your Azure account. After you'''ve signed in, it retrieves the tenants and subscriptions associated with your account.
The next command displays details about the currently active Azure subscription that your CLI is using:
az account showEvery resource in Azure needs to be in a resource group. A resource group is a container that holds related resources for an Azure solution.
We can create one using the following command:
az group create --name DevOps --location northeurope--name: You must provide a unique name for your resource group within your subscription.--location: This is the Azure region where your resource group will be created. You can get a list of available locations usingaz account list-locations -o table. Examples of locations includenortheurope,westeurope,eastus,westus, etc.
Next, we'''ll create a virtual machine (VM) inside our new resource group.
az vm create --resource-group DevOps --name myVM --image Ubuntu2204 --admin-username azureuser --generate-ssh-keys--resource-group DevOps: This specifies that the VM will be created in theDevOpsresource group we created earlier.--name myVM: This sets the name of the virtual machine tomyVM.--image Ubuntu2204: This specifies the operating system image for the VM. In this case, it'''s Ubuntu 22.04 LTS. You can find other images usingaz vm image list --output table.--admin-username azureuser: This creates a user account on the VM with the usernameazureuser.--generate-ssh-keys: This automatically generates SSH public and private key files and saves them in~/.ssh. The public key will be configured on the VM for authentication. If SSH keys already exist in the default location (~/.ssh/id_rsaand~/.ssh/id_rsa.pub), those keys will be used.
After the VM is created, you can connect to it using SSH. The output of the az vm create command includes the public IP address of your VM.
The --generate-ssh-keys flag used your existing SSH public key (~/.ssh/id_rsa.pub) to configure access to the new VM. The corresponding private key to connect to the VM is located at ~/.ssh/id_rsa.
To connect to your VM, you can use the following command:
ssh azureuser@Public IPIf that doesn't work, you may need to explicitly specify the path to your private key:
ssh -i ~/.ssh/id_rsa azureuser@Public IPIn this section, we'''ll learn how to list and modify network rules for our VM using the Azure CLI. Network Security Groups (NSGs) are used to filter network traffic to and from Azure resources in an Azure virtual network. An NSG contains a list of security rules that allow or deny network traffic based on factors like source and destination IP addresses, ports, and protocols.
When you create a VM, Azure automatically creates an NSG for it, typically named myVMNSG if your VM is named myVM.
To see the current rules applied to your VM'''s NSG, you first need to find the name of the NSG associated with your VM. You can list the network interfaces of your VM to find the attached NSG.
First, find your Network Interface Card (NIC) name:
az network nic list --resource-group DevOps --query "[?contains(virtualMachine.id, 'myVM')].name" -o tsvThe previous command gives you the name of your NIC. Your output shows the name is myVMVMNic. You must use this exact name in the next command. The name myVMNic in the documentation was an example placeholder.
Now, use the NIC name you found to get the ID of the associated Network Security Group:
az network nic show --resource-group DevOps --name myVMVMNic --query "networkSecurityGroup.id" -o tsvThis command will give you the full ID of the NSG. The name of the NSG is the last part of the ID. Let's assume the NSG name is myVMNSG.
Now you can list the rules for that NSG:
az network nsg rule list --resource-group DevOps --nsg-name myVMNSG -o tableBy default, only SSH traffic is allowed. To allow incoming HTTP traffic to our VM (for example, if we want to run a web server), we need to create a new rule in the NSG.
Here is the command to add a rule that allows HTTP traffic on port 80:
az network nsg rule create \
--resource-group DevOps \
--nsg-name myVMNSG \
--name Allow-HTTP \
--protocol Tcp \
--priority 1010 \
--destination-port-range 80 \
--access Allow \
--direction InboundExplanation of the parameters:
--resource-group DevOps: The resource group containing the NSG.--nsg-name myVMNSG: The name of the Network Security Group.--name Allow-HTTP: The name of the new rule.--protocol Tcp: The protocol for the rule (TCP for HTTP).--priority 1010: A number between 100 and 4096. Rules are processed in priority order. Lower numbers are processed first. It'''s a good practice to leave gaps between priority numbers to allow for adding more rules later.--destination-port-range 80: The port the traffic is destined for.--access Allow: This rule allows traffic.--direction Inbound: The rule applies to inbound traffic.
You can use the following commands to get more details about your VM'''s network configuration:
-
Show Public IP details: This command shows information about the public IP address of your VM, including the IP address, allocation method, and domain name label. You can find your public IP name with
az network public-ip list --resource-group DevOps -o table.az network public-ip show --resource-group DevOps --name myVMPublicIP -o table
-
List Network Interfaces: This command lists the network interface cards (NICs) in the resource group.
az network nic list --resource-group DevOps -o table
Now that we have a VM and have opened port 80, let's deploy a simple Node.js web application. We will use scp to copy the web app files to the VM and then use az vm run-command to install Node.js, install dependencies, and run the application.
First, create a simple Node.js application. I have already created the following files for you in the week8/simple-web-app directory:
index.html: The main page of your web app.app.js: A simple Node.js server to serve theindex.htmlfile.package.json: Defines the project metadata and dependencies.
Now, we will use the scp command to securely copy the simple-web-app directory to your VM's home directory.
Note: The command below assumes you are in the week8 directory. If you are in another directory, you will need to adjust the path to the simple-web-app directory accordingly.
scp -r -i ~/.ssh/id_rsa simple-web-app azureuser@52.138.205.52:~Next, we will use the az vm run-command to execute a script on the VM. This script will:
- Update the package lists.
- Install Nginx and Node.js.
- Set up a reverse proxy to forward traffic from port 80 to your Node.js app running on port 3000.
- Navigate into the
simple-web-appdirectory. - Install the application dependencies using
npm install. - Start the Node.js application using
npm start.
az vm run-command invoke \
--resource-group DevOps \
--name myVM \
--command-id RunShellScript \
--scripts "sudo apt-get update && sudo apt-get install -y nginx nodejs npm && sudo systemctl start nginx && sudo systemctl enable nginx && echo 'server { listen 80; server_name _; location / { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection '\\''upgrade'\\''; proxy_set_header Host \$host; proxy_cache_bypass \$http_upgrade; } }' | sudo tee /etc/nginx/sites-available/default && sudo nginx -s reload && cd /home/azureuser/simple-web-app && npm install && nohup npm start &"Once the command has finished, you should be able to access your web app by navigating to your VM's public IP address in your web browser:
In this section, we'll create an Azure Storage Account, create a container within it, and upload a file.
First, I've created a test.txt file in the week8 directory for you to upload.
Now, let's create a new storage account in our DevOps resource group. Storage account names must be globally unique, so we'll use a random number to help with that.
az storage account create \
--name devopsstorage10938 \
--resource-group DevOps \
--sku Standard_LRSNext, we'll create a container named mycontainer inside our new storage account.
az storage container create \
--name mycontainer \
--account-name devopsstorage10938The error "You do not have the required permissions" occurs because your user account doesn't have the necessary role assignment on the storage account to upload data when using --auth-mode login. We need to assign the "Storage Blob Data Contributor" role to your user.
It can take a minute or two for role assignments to propagate in Azure.
First, get your user's principal ID and store it in a variable. This command gets the object ID of the currently signed-in user.
PRINCIPAL_ID=$(az ad signed-in-user show --query id -o tsv)Next, get the full resource ID of the storage account and store it in a variable. This will be used as the scope for the role assignment.
SCOPE=$(az storage account show --name devopsstorage10938 --resource-group DevOps --query id -o tsv)Now, create the role assignment. This command grants your user the "Storage Blob Data Contributor" role on the devopsstorage10938 storage account.
az role assignment create \
--role "Storage Blob Data Contributor" \
--assignee $PRINCIPAL_ID \
--scope $SCOPEAfter running these commands, wait for a minute or two for the permissions to apply before proceeding.
Now that you have the correct permissions, you can upload the test.txt file.
az storage blob upload \
--account-name devopsstorage10938 \
--container-name mycontainer \
--name test.txt \
--file week8/test.txt \
--auth-mode loginFinally, you can list the blobs in the container to verify that the file was uploaded successfully.
az storage blob list \
--account-name devopsstorage10938 \
--container-name mycontainer \
--auth-mode login \
--output tableTo automate the entire process of creating the infrastructure, deploying the web application, and cleaning up the resources, we have created a bash script named deploy.sh.
This script provides two main functions:
deploy: Creates the resource group, virtual machine, configures the network security group, copies the web application files, and runs the application on the VM.cleanup: Deletes the entire resource group, which removes all the resources created during the deployment.
Here is the full content of the deploy.sh script. It is located in the week8 directory.
#!/bin/bash
# This script automates the deployment of a Node.js web application on an Azure VM.
# It also includes a function to clean up all created resources.
# Exit on any error
set -e
# --- Configuration ---
# You can change these variables to match your desired settings.
RESOURCE_GROUP="DevOps"
LOCATION="northeurope"
VM_NAME="myVM"
VM_IMAGE="Ubuntu2204"
ADMIN_USERNAME="azureuser"
NSG_NAME="${VM_NAME}NSG" # Azure's default naming convention for the NSG
SSH_KEY_PATH="$HOME/.ssh/id_rsa" # Path to your SSH private key
WEB_APP_PATH="week8/simple-web-app" # Path to the web app source code
# --- Deployment Function ---
deploy() {
echo "Starting Azure infrastructure deployment..."
# 1. Create Resource Group
echo "Creating resource group: $RESOURCE_GROUP in $LOCATION..."
az group create --name "$RESOURCE_GROUP" --location "$LOCATION" --output none
# 2. Create Virtual Machine
echo "Creating VM: $VM_NAME..."
# This command also generates SSH keys if they don't exist
az vm create \
--resource-group "$RESOURCE_GROUP" \
--name "$VM_NAME" \
--image "$VM_IMAGE" \
--admin-username "$ADMIN_USERNAME" \
--generate-ssh-keys \
--output none
echo "VM created successfully."
# 3. Get Public IP Address
echo "Fetching Public IP address..."
PUBLIC_IP=$(az vm show -d --resource-group "$RESOURCE_GROUP" --name "$VM_NAME" --query "publicIps" -o tsv)
if [ -z "$PUBLIC_IP" ]; then
echo "Error: Could not retrieve Public IP address."
exit 1
fi
echo "Public IP address is: $PUBLIC_IP"
# 4. Add NSG Rule for HTTP
echo "Opening port 80 for HTTP traffic on NSG: $NSG_NAME..."
az network nsg rule create \
--resource-group "$RESOURCE_GROUP" \
--nsg-name "$NSG_NAME" \
--name "Allow-HTTP" \
--protocol Tcp \
--priority 1010 \
--destination-port-range 80 \
--access Allow \
--direction Inbound \
--output none
echo "Port 80 is now open."
# 5. Copy Web Application to VM
echo "Waiting for VM to be ready for SSH connection..."
sleep 20 # A simple wait. For production, a more robust check is needed.
echo "Copying web application files from '$WEB_APP_PATH' to VM..."
scp -r -i "$SSH_KEY_PATH" -o StrictHostKeyChecking=no -o ConnectionAttempts=60 "$WEB_APP_PATH" "${ADMIN_USERNAME}@${PUBLIC_IP}:~"
echo "Web app files copied."
# 6. Deploy Application on VM
echo "Installing dependencies and starting the web server on the VM..."
# This long command installs nginx, node, npm, configures a reverse proxy, and starts the app
DEPLOY_SCRIPT="sudo apt-get update && sudo apt-get install -y nginx nodejs npm && sudo systemctl start nginx && sudo systemctl enable nginx && echo 'server { listen 80; server_name _; location / { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection '\\''upgrade'\\''; proxy_set_header Host \$host; proxy_cache_bypass \$http_upgrade; } }' | sudo tee /etc/nginx/sites-available/default && sudo nginx -s reload && cd /home/azureuser/simple-web-app && npm install && nohup npm start &"
az vm run-command invoke \
--resource-group "$RESOURCE_GROUP" \
--name "$VM_NAME" \
--command-id RunShellScript \
--scripts "$DEPLOY_SCRIPT" \
--output none
echo "Application deployed and running."
echo "-----------------------------------------------------"
echo "Deployment successful!"
echo "You can now access your web app at: http://$PUBLIC_IP"
echo "-----------------------------------------------------"
}
# --- Cleanup Function ---
cleanup() {
echo "Starting cleanup..."
echo "This will delete the entire '$RESOURCE_GROUP' resource group."
read -p "Are you sure you want to continue? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Deleting resource group: $RESOURCE_GROUP..."
az group delete --name "$RESOURCE_GROUP" --yes --no-wait
echo "Cleanup initiated. The resource group is being deleted in the background."
else
echo "Cleanup cancelled."
fi
}
# --- Main Script Logic ---
# Checks for the command-line argument
if [ "$1" == "deploy" ]; then
deploy
elif [ "$1" == "cleanup" ]; then
cleanup
else
echo "Usage: $0 {deploy|cleanup}"
echo " deploy : Deploys the Azure resources and the web application."
echo " cleanup : Deletes the Azure resource group and all its resources."
exit 1
fi
To run the script, navigate to the root directory of the repository and use the following commands.
To deploy the infrastructure and application:
bash week8/deploy.sh deployTo clean up all resources:
bash week8/deploy.sh cleanupThis will prompt you for confirmation before deleting the resource group.