Skip to content

Instantly share code, notes, and snippets.

@mike-seger
Last active June 14, 2024 21:22
Show Gist options
  • Save mike-seger/62dc656257e7c21ff07a48e1585b979c to your computer and use it in GitHub Desktop.
Save mike-seger/62dc656257e7c21ff07a48e1585b979c to your computer and use it in GitHub Desktop.
3 - azure app + gw full playbook

Explanation

  • Resource Group, Service Plans, and Web Apps:

    • Using az group create, az appservice plan create, and az webapp create to create the resource group, service plans, and web apps respectively.
  • Deploy JAR Files:

    • Using az webapp deploy to deploy JAR files to the web apps.
  • Setting App Settings:

    • Using az webapp config appsettings set to set spring.profiles.active and app.env properties for each web app.
  • Virtual Network and Subnets:

    • Using az network vnet create and az network vnet subnet create to create the virtual network and subnets.
  • VNet Integration:

    • Using az webapp vnet-integration add to integrate the web apps with the virtual network.
  • Private Endpoints and DNS Records:

    • Using az network private-endpoint create, az network private-dns zone create, az network private-dns link vnet create, and az network private-dns record-set a add-record to create private endpoints and configure DNS.
  • Clean-Up:

    • Using az webapp delete, az network private-endpoint delete, and az network private-dns record-set a remove-record to remove web apps, private endpoints, and DNS records that are not in app_instances.

Running the Playbook

  1. Install Azure CLI:

    Ensure that Azure CLI is installed and configured on your system.

  2. Set Up Azure Credentials:
    Configure your Azure credentials using az login or by setting up a service principal.

  3. Run the Playbook with the app_env_param parameter: Save the playbook to a file, e.g., deploy_webapps.yml, and run it using the ansible-playbook command. You can pass the app_env_param parameter as follows:

    ansible-playbook deploy_webapps.yml --extra-vars "app_env_param=production"
az role assignment create --assignee <principal-id-or-email> --role Contributor --resource-group <resource-group-name>
az role assignment list --assignee <principal-id-or-email> --resource-group <resource-group-name> --output table
---
- name: Deploy Spring Boot Applications and Configure Azure Resources
hosts: localhost
vars:
resource_group: resourcegroup1
location: eastus
app_plan_name: app-plan
gw_plan_name: gw-plan
app_instances:
- testapp1
- testapp2
gw_instances:
- gateway
jar_directory: "/path/to/jars"
num_app_instances: 4 # Global variable for the number of instances per app
num_gw_instances: 1 # Number of gateway instances
app_prefix: "app"
gw_prefix: "gw"
address_prefixes: "10.0.0.0/16"
subnet_prefix: "10.0.1.0/24"
app_gateway_subnet_prefix: "10.0.2.0/24"
app_gateway_name: appGateway
vnet_name: appVNet
subnet_name: appSubnet
app_gateway_subnet_name: appGatewaySubnet
app_env: "{{ app_env_param }}" # Parameter for app.env, default value if not passed
tasks:
- name: Create resource group
command: >
az group create --name {{ resource_group }} --location {{ location }}
ignore_errors: yes
- name: Determine spring_boot_apps for app_instances
set_fact:
spring_boot_apps: "{{ spring_boot_apps | default([]) + [{'name': item, 'jar_path': jar_directory + '/' + item + '.jar', 'plan': app_plan_name}] }}"
with_items: "{{ app_instances }}"
- name: Determine spring_boot_apps for gw_instances
set_fact:
spring_boot_apps: "{{ spring_boot_apps + [{'name': item, 'jar_path': jar_directory + '/' + item + '.jar', 'plan': gw_plan_name}] }}"
with_items: "{{ gw_instances }}"
- name: Create service plans
command: >
az appservice plan create --name {{ item.plan }} --resource-group {{ resource_group }} --location {{ location }} --sku F1 --is-linux
loop:
- "{{ app_plan_name }}"
- "{{ gw_plan_name }}"
- name: Create web apps
command: >
az webapp create --name {{ item.name }} --resource-group {{ resource_group }} --plan {{ item.plan }} --runtime "JAVA|11-java11"
with_items: "{{ spring_boot_apps }}"
- name: Deploy JAR files to Azure Web Apps
command: >
az webapp deploy --resource-group {{ resource_group }} --name {{ item.name }} --src-path {{ item.jar_path }} --type jar > /dev/null 2>&1
with_items: "{{ spring_boot_apps }}"
- name: Set spring.profiles.active and app.env properties
command: >
az webapp config appsettings set --resource-group {{ resource_group }} --name {{ item.name }} --settings spring.profiles.active=azure app.env={{ app_env }}
with_items: "{{ spring_boot_apps }}"
- name: Get App Plan ID
command: az appservice plan show --name {{ app_plan_name }} --resource-group {{ resource_group }} --query id --output tsv
register: app_plan_id
changed_when: false
- name: Get GW Plan ID
command: az appservice plan show --name {{ gw_plan_name }} --resource-group {{ resource_group }} --query id --output tsv
register: gw_plan_id
changed_when: false
- name: Create Virtual Network
command: >
az network vnet create --name {{ vnet_name }}
--resource-group {{ resource_group }}
--address-prefixes {{ address_prefixes }}
--subnet-name {{ subnet_name }}
--subnet-prefix {{ subnet_prefix }}
register: vnet
changed_when: false
- name: Create App Gateway Subnet
command: >
az network vnet subnet create --vnet-name {{ vnet_name }}
--name {{ app_gateway_subnet_name }}
--resource-group {{ resource_group }}
--address-prefix {{ app_gateway_subnet_prefix }}
register: app_gateway_subnet
changed_when: false
- name: Create and Move App Instances
command: >
az webapp create --name {{ item.app_name }}-{{ item.instance }}
--resource-group {{ resource_group }}
--plan {{ app_plan_id.stdout }}
--runtime "JAVA|11-java11"
with_subelements:
- "{{ app_instances | map('product', with_sequence('start=1 end=' + num_app_instances|string)) | list }}"
- list
- name: Create and Move GW Instances
command: >
az webapp create --name {{ gw_prefix }}-{{ item }}
--resource-group {{ resource_group }}
--plan {{ gw_plan_id.stdout }}
--runtime "JAVA|11-java11"
with_sequence: start=1 end={{ num_gw_instances }}
- name: Integrate App Instances with VNet
command: >
az webapp vnet-integration add --name {{ item.app_name }}-{{ item.instance }}
--resource-group {{ resource_group }}
--vnet {{ vnet_name }}
--subnet {{ subnet_name }}
with_subelements:
- "{{ app_instances | map('product', with_sequence('start=1 end=' + num_app_instances|string)) | list }}"
- list
- name: Integrate GW Instances with VNet
command: >
az webapp vnet-integration add --name {{ gw_prefix }}-{{ item }}
--resource-group {{ resource_group }}
--vnet {{ vnet_name }}
--subnet {{ subnet_name }}
with_sequence: start=1 end={{ num_gw_instances }}
- name: Create Private Endpoints for App Instances
command: >
az network private-endpoint create --name {{ item.app_name }}-{{ item.instance }}PrivateEndpoint
--resource-group {{ resource_group }}
--vnet-name {{ vnet_name }}
--subnet {{ subnet_name }}
--private-connection-resource-id $(az webapp show --name {{ item.app_name }}-{{ item.instance }} --resource-group {{ resource_group }} --query id --output tsv)
--group-ids sites
--connection-name {{ item.app_name }}-{{ item.instance }}Connection
with_subelements:
- "{{ app_instances | map('product', with_sequence('start=1 end=' + num_app_instances|string)) | list }}"
- list
- name: Determine Private IP Addresses
command: >
az network private-endpoint show --name {{ item.app_name }}-{{ item.instance }}PrivateEndpoint
--resource-group {{ resource_group }}
--query 'customDnsConfigurations[0].ipAddresses[0]'
--output tsv
register: private_ips
with_subelements:
- "{{ app_instances | map('product', with_sequence('start=1 end=' + num_app_instances|string)) | list }}"
- list
changed_when: false
- name: Configure Private DNS Zones
command: az network private-dns zone create --resource-group {{ resource_group }} --name privatelink.azurewebsites.net
- name: Link VNet to Private DNS Zone
command: >
az network private-dns link vnet create --resource-group {{ resource_group }}
--zone-name privatelink.azurewebsites.net
--name appVNetLink
--virtual-network {{ vnet_name }}
--registration-enabled false
- name: Add DNS Records for App Instances
command: >
az network private-dns record-set a add-record --resource-group {{ resource_group }}
--zone-name privatelink.azurewebsites.net
--record-set-name {{ item.0.app_name }}-{{ item.1.instance }}
--ipv4-address {{ item.1.stdout }}
with_subelements:
- "{{ private_ips.results }}"
- stdout_lines
- name: Restrict Public Access to App Instances
command: >
az webapp config access-restriction add --name {{ item.app_name }}-{{ item.instance }}
--resource-group {{ resource_group }}
--rule-name DenyPublicAccess
--priority 100
--action Deny
--ip-address 0.0.0.0/0
with_subelements:
- "{{ app_instances | map('product', with_sequence('start=1 end=' + num_app_instances|string)) | list }}"
- list
- name: List all webapps in resource group
command: az webapp list --resource-group {{ resource_group }} --query [].name --output tsv
register: all_webapps
changed_when: false
- name: Remove Web Apps not in app_instances
command: az webapp delete --resource-group {{ resource_group }} --name {{ item }}
when: "'{{ item }}' not in (app_instances + gw_instances)"
loop: "{{ all_webapps.stdout_lines }}"
- name: List all private endpoints in resource group
command: az network private-endpoint list --resource-group {{ resource_group }} --query [].name --output tsv
register: all_private_endpoints
changed_when: false
- name: Remove Private Endpoints not in app_instances
command: az network private-endpoint delete --resource-group {{ resource_group }} --name {{ item }}
when: "'{{ item }}PrivateEndpoint' not in (app_instances | map('join', 'PrivateEndpoint'))"
loop: "{{ all_private_endpoints.stdout_lines }}"
- name: List all DNS records in private DNS zone
command: az network private-dns record-set list --resource-group {{ resource_group }} --zone-name privatelink.azurewebsites.net --query [].name --output tsv
register: all_dns_records
changed_when: false
- name: Remove DNS Records not in app_instances
command: >
az network private-dns record-set a remove-record --resource-group {{ resource_group }}
--zone-name privatelink.azurewebsites.net
--record-set-name {{ item }}
--ipv4-address $(az network private-endpoint show --name {{ item }}PrivateEndpoint --resource-group {{ resource_group }} --query 'customDnsConfigurations[0].ipAddresses[0]' --output tsv)
when: "'{{ item }}.privatelink.azurewebsites.net' not in (app_instances | map('join', '.privatelink.azurewebsites.net'))"
loop: "{{ all_dns_records.stdout_lines }}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment