AZURE CLI: Azure Cloud Infrastructure Setup
Azure Cloud Infrastructure Setup Guide
This step-by-step guide will help you create a complete Azure infrastructure with VM, storage, and web application.
Prerequisites
Azure account (free tier available)
Azure CLI installed
Basic knowledge of Linux commands
Step 1: Install and Login to Azure CLI
Install Azure CLI (if not already installed)
# Download and install Azure CLI from: # https://docs.microsoft.com/en-us/cli/azure/install-azure-cli # Verify installation az --version
Login to Azure
# Login to your Azure account az login # This will open a browser window for authentication # After login, you'll see your subscription information # List available subscriptions az account list --output table # Set your subscription (if you have multiple) az account set --subscription "Your-Subscription-Name"
Step 2: Set Environment Variables
# Set variables for consistent resource naming RESOURCE_GROUP="myPythonAppRG" LOCATION="eastus" # You can change to your preferred region VM_NAME="pythonvm" VM_IMAGE="Ubuntu2204" ADMIN_USERNAME="azureuser" STORAGE_ACCOUNT="mypythonstorage$(date +%s)" # Unique name with timestamp BLOB_CONTAINER="fileuploads" SQL_SERVER="python-sql-server" SQL_DATABASE="FileUploadDB" SQL_ADMIN_USER="sqladmin" SQL_ADMIN_PASSWORD="MyStrongPassword123!" # Verify the variables are set echo "Resource Group: $RESOURCE_GROUP" echo "Location: $LOCATION" echo "VM Name: $VM_NAME" echo "Storage Account: $STORAGE_ACCOUNT"
Step 3: Create Resource Group
# Create a resource group to contain all our resources az group create \ --name $RESOURCE_GROUP \ --location $LOCATION # Verify resource group creation az group show --name $RESOURCE_GROUP
Step 4: Create Linux VM
# Create a Linux VM with Ubuntu az vm create \ --resource-group $RESOURCE_GROUP \ --name $VM_NAME \ --image $VM_IMAGE \ --admin-username $ADMIN_USERNAME \ --generate-ssh-keys \ --public-ip-sku Standard \ --size Standard_B1s # Basic tier for cost savings # Check if VM is running az vm show \ --resource-group $RESOURCE_GROUP \ --name $VM_NAME \ --show-details \ --query "powerState" # Get the public IP address of the VM VM_IP=$(az vm show \ --resource-group $RESOURCE_GROUP \ --name $VM_NAME \ --show-details \ --query "publicIps" -o tsv) echo "VM Public IP: $VM_IP"
Step 5: Configure Firewall Rules
# Open port 80 for HTTP and 5000 for Flask app az vm open-port \ --resource-group $RESOURCE_GROUP \ --name $VM_NAME \ --port 80 \ --priority 1001 az vm open-port \ --resource-group $RESOURCE_GROUP \ --name $VM_NAME \ --port 5000 \ --priority 1002 # Open port 22 for SSH (should already be open by default) az vm open-port \ --resource-group $RESOURCE_GROUP \ --name $VM_NAME \ --port 22 \ --priority 1003
Step 6: Create Blob Storage Account
# Create storage account az storage account create \ --resource-group $RESOURCE_GROUP \ --name $STORAGE_ACCOUNT \ --location $LOCATION \ --sku Standard_LRS \ --kind StorageV2 # Get storage account key STORAGE_KEY=$(az storage account keys list \ --resource-group $RESOURCE_GROUP \ --account-name $STORAGE_ACCOUNT \ --query "[0].value" -o tsv) echo "Storage Key: $STORAGE_KEY" # Create blob container az storage container create \ --name $BLOB_CONTAINER \ --account-name $STORAGE_ACCOUNT \ --account-key $STORAGE_KEY \ --public-access off # Get connection string for Python code CONNECTION_STRING=$(az storage account show-connection-string \ --resource-group $RESOURCE_GROUP \ --name $STORAGE_ACCOUNT \ --query "connectionString" -o tsv) echo "Connection String: $CONNECTION_STRING"
Step 7: Create Azure SQL Database
# Create SQL Server az sql server create \ --resource-group $RESOURCE_GROUP \ --name $SQL_SERVER \ --location $LOCATION \ --admin-user $SQL_ADMIN_USER \ --admin-password $SQL_ADMIN_PASSWORD # Configure firewall to allow Azure services and our VM IP az sql server firewall-rule create \ --resource-group $RESOURCE_GROUP \ --server $SQL_SERVER \ --name "AllowAzureServices" \ --start-ip-address 0.0.0.0 \ --end-ip-address 0.0.0.0 az sql server firewall-rule create \ --resource-group $RESOURCE_GROUP \ --server $SQL_SERVER \ --name "AllowVMIP" \ --start-ip-address $VM_IP \ --end-ip-address $VM_IP # Create SQL Database az sql db create \ --resource-group $RESOURCE_GROUP \ --server $SQL_SERVER \ --name $SQL_DATABASE \ --service-objective Basic \ --edition Basic # Get SQL connection string SQL_CONNECTION_STRING=$(az sql db show-connection-string \ --server $SQL_SERVER \ --name $SQL_DATABASE \ --client ado.net --output tsv) SQL_CONNECTION_STRING=${SQL_CONNECTION_STRING//<username>/$SQL_ADMIN_USER} SQL_CONNECTION_STRING=${SQL_CONNECTION_STRING//<password>/$SQL_ADMIN_PASSWORD} echo "SQL Connection String: $SQL_CONNECTION_STRING"
Step 8: SSH into VM and Setup Environment
# SSH into the VM using the generated keys ssh -o StrictHostKeyChecking=no $ADMIN_USERNAME@$VM_IP
Now you're inside the VM. Run these commands:
# Update package list and upgrade existing packages sudo apt update && sudo apt upgrade -y # Install Python and pip sudo apt install python3 python3-pip -y # Install Azure SDK and other dependencies pip3 install azure-storage-blob azure-identity flask sqlalchemy pymysql # Install additional system packages sudo apt install git -y
Step 9: Create Database Table
Create a SQL script file on the VM:
# Create a SQL script to setup the database table cat > setup_database.sql << 'EOF' CREATE TABLE file_uploads ( id INT PRIMARY KEY IDENTITY(1,1), filename NVARCHAR(255) NOT NULL, file_size BIGINT, upload_date DATETIME2 DEFAULT GETDATE(), blob_url NVARCHAR(500), is_deleted BIT DEFAULT 0 ); EOF # Install SQL command line tools curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - curl https://packages.microsoft.com/config/ubuntu/22.04/prod.list | sudo tee /etc/apt/sources.list.d/mssql-release.list sudo apt update sudo ACCEPT_EULA=Y apt install -y msodbcsql18 mssql-tools18 echo 'export PATH="$PATH:/opt/mssql-tools18/bin"' >> ~/.bashrc source ~/.bashrc # Run the SQL script (replace with your actual SQL server details) sqlcmd -S $SQL_SERVER.database.windows.net -U $SQL_ADMIN_USER -P $SQL_ADMIN_PASSWORD -d $SQL_DATABASE -i setup_database.sql
Step 10: Create Python Flask Web Application
Create the main application file:
cat > app.py << 'EOF' from flask import Flask, render_template, request, redirect, url_for, flash, send_file from azure.storage.blob import BlobServiceClient import pyodbc import os import uuid from io import BytesIO app = Flask(__name__) app.secret_key = 'your-secret-key-here' # Azure Storage Configuration connection_string = "YOUR_CONNECTION_STRING_HERE" container_name = "fileuploads" blob_service_client = BlobServiceClient.from_connection_string(connection_string) # SQL Database Configuration server = 'python-sql-server.database.windows.net' database = 'FileUploadDB' username = 'sqladmin' password = 'MyStrongPassword123!' driver = '{ODBC Driver 18 for SQL Server}' def get_db_connection(): return pyodbc.connect( f'DRIVER={driver};SERVER={server};DATABASE={database};UID={username};PWD={password}' ) @app.route('/') def index(): return render_template('index.html') @app.route('/upload', methods=['POST']) def upload_file(): if 'file' not in request.files: flash('No file selected') return redirect(request.url) file = request.files['file'] if file.filename == '': flash('No file selected') return redirect(request.url) if file: # Generate unique filename unique_filename = str(uuid.uuid4()) + '_' + file.filename # Upload to Azure Blob Storage blob_client = blob_service_client.get_blob_client( container=container_name, blob=unique_filename ) blob_client.upload_blob(file) # Store metadata in SQL Database conn = get_db_connection() cursor = conn.cursor() cursor.execute( "INSERT INTO file_uploads (filename, file_size, blob_url) VALUES (?, ?, ?)", file.filename, len(file.read()), blob_client.url ) conn.commit() conn.close() flash('File uploaded successfully!') return redirect(url_for('list_files')) @app.route('/files') def list_files(): conn = get_db_connection() cursor = conn.cursor() cursor.execute("SELECT id, filename, file_size, upload_date FROM file_uploads WHERE is_deleted = 0") files = cursor.fetchall() conn.close() return render_template('files.html', files=files) @app.route('/download/<int:file_id>') def download_file(file_id): conn = get_db_connection() cursor = conn.cursor() cursor.execute("SELECT filename FROM file_uploads WHERE id = ?", file_id) result = cursor.fetchone() conn.close() if result: original_filename = result[0] # In a real scenario, you'd get the blob name from database # This is simplified for demo blob_client = blob_service_client.get_blob_client( container=container_name, blob=original_filename ) download_stream = blob_client.download_blob() file_content = download_stream.readall() return send_file( BytesIO(file_content), as_attachment=True, download_name=original_filename ) flash('File not found') return redirect(url_for('list_files')) @app.route('/delete/<int:file_id>') def delete_file(file_id): conn = get_db_connection() cursor = conn.cursor() # Get filename before deleting record cursor.execute("SELECT filename FROM file_uploads WHERE id = ?", file_id) result = cursor.fetchone() if result: # Soft delete from database cursor.execute("UPDATE file_uploads SET is_deleted = 1 WHERE id = ?", file_id) conn.commit() # Delete from blob storage blob_client = blob_service_client.get_blob_client( container=container_name, blob=result[0] ) blob_client.delete_blob() conn.close() flash('File deleted successfully!') return redirect(url_for('list_files')) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=True) EOF
Step 11: Create HTML Templates
Create templates directory and HTML files:
mkdir templates cat > templates/index.html << 'EOF' <!DOCTYPE html> <html> <head> <title>Azure File Upload Service</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container mt-5"> <h1>Azure File Upload Service</h1> {% with messages = get_flashed_messages() %} {% if messages %} {% for message in messages %} <div class="alert alert-info">{{ message }}</div> {% endfor %} {% endif %} {% endwith %} <div class="card mt-4"> <div class="card-header"> <h5>Upload File to Azure Blob Storage</h5> </div> <div class="card-body"> <form action="/upload" method="post" enctype="multipart/form-data"> <div class="mb-3"> <input type="file" class="form-control" name="file" required> </div> <button type="submit" class="btn btn-primary">Upload File</button> </form> </div> </div> <div class="mt-3"> <a href="/files" class="btn btn-secondary">View All Files</a> </div> </div> </body> </html> EOF cat > templates/files.html << 'EOF' <!DOCTYPE html> <html> <head> <title>Uploaded Files</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container mt-5"> <h1>Uploaded Files</h1> {% with messages = get_flashed_messages() %} {% if messages %} {% for message in messages %} <div class="alert alert-info">{{ message }}</div> {% endfor %} {% endif %} {% endwith %} <a href="/" class="btn btn-secondary mb-3">Back to Upload</a> <table class="table table-striped"> <thead> <tr> <th>Filename</th> <th>Size</th> <th>Upload Date</th> <th>Actions</th> </tr> </thead> <tbody> {% for file in files %} <tr> <td>{{ file[1] }}</td> <td>{{ file[2] }} bytes</td> <td>{{ file[3] }}</td> <td> <a href="/download/{{ file[0] }}" class="btn btn-sm btn-success">Download</a> <a href="/delete/{{ file[0] }}" class="btn btn-sm btn-danger" onclick="return confirm('Are you sure you want to delete this file?')">Delete</a> </td> </tr> {% endfor %} </tbody> </table> {% if not files %} <div class="alert alert-warning">No files uploaded yet.</div> {% endif %} </div> </body> </html> EOF
Step 12: Update Configuration and Run Application
Back on the VM, update the connection string in app.py:
# Replace the connection string in app.py with your actual connection string sed -i "s|YOUR_CONNECTION_STRING_HERE|$CONNECTION_STRING|g" app.py # Make the app accessible on port 80 by running with sudo sudo pip3 install flask # Run the application (for testing) python3 app.py
The app will be accessible at: http://YOUR_VM_IP:5000
Step 13: Create Systemd Service for Auto-start
# Create a systemd service file sudo cat > /etc/systemd/system/python-app.service << EOF [Unit] Description=Python Flask File Upload App After=network.target [Service] Type=simple User=azureuser WorkingDirectory=/home/azureuser ExecStart=/usr/bin/python3 /home/azureuser/app.py Restart=always [Install] WantedBy=multi-user.target EOF # Reload systemd and enable the service sudo systemctl daemon-reload sudo systemctl enable python-app.service sudo systemctl start python-app.service # Check service status sudo systemctl status python-app.service
Step 14: Test Your Application
Access your application: Open browser and go to
http://YOUR_VM_IP:5000Upload a file: Use the upload form to test file upload
View files: Click "View All Files" to see uploaded files
Download files: Test download functionality
Delete files: Test delete functionality
Step 15: Cleanup (When Done)
# Delete the entire resource group (this will delete all resources) az group delete --name $RESOURCE_GROUP --yes --no-wait # Or delete individual resources az vm delete --resource-group $RESOURCE_GROUP --name $VM_NAME --yes az storage account delete --resource-group $RESOURCE_GROUP --name $STORAGE_ACCOUNT --yes az sql server delete --resource-group $RESOURCE_GROUP --name $SQL_SERVER --yes
Important Security Notes
Never hardcode credentials in production - use Azure Key Vault
Use environment variables for sensitive information
Implement proper authentication for production apps
Configure SSL/TLS for secure communication
Regularly update and patch your VM
Cost Optimization
Use Basic/Standard tiers for development
Shut down VMs when not in use
Use Azure Spot Instances for testing
Set up billing alerts
This complete setup demonstrates a real-world Azure cloud application using multiple Azure services working together!
Comments
Post a Comment