Deploying load-balanced IIS web servers

This tutorial is the third part of a series that helps you deploy a highly available Windows architecture with Microsoft Active Directory, SQL Server, and Internet Information Services (IIS). In this tutorial, you set up two IIS web servers that run in different zones within the same region. You then connect the web servers to your SQL Server availability group and domain controllers. By setting up the web servers behind a load balancer, you reduce the load to the individual servers. You are also able to keep the app running if one of the servers goes offline.

The series consists of these tutorials:

You set up a domain controller and SQL Server instance on a Google Cloud project. Each component in this deployment is also designed to integrate securely with Windows authentication that's provided by the domain controllers.

The architecture described in this tutorial is designed to run on Google Cloud. However, some components, like Active Directory and SQL Server, could be run on-premises. This tutorial addresses only the scenario of running all components on Google Cloud.

Objectives

  • Create two network subnets that span two zones.
  • Deploy a Microsoft SQL Server virtual machine (VM) in each zone.
  • Configure each SQL Server instance to join your Active Directory domain.
  • Create a Windows Server failover cluster.
  • Create and configure a SQL Server bookshelf sample database.
  • Set up the SQL Server Always On availability group.

Costs

In this tutorial, you continue using Google Cloud resources that you configured in earlier tutorials. You use the following billable components:

The Pricing Calculator estimates the cost of this environment at around $4 per day.

Before you begin

The configuration that you use in this tutorial requires you to have access to a Windows domain controller and a working Active Directory domain. If you don't already have this environment, complete the steps in the following tutorials:

For parts of this tutorial, you perform tasks on a Windows workstation. This can be your local computer; it doesn't have to be inside the VPC network that you use for the IIS web servers. Make sure that the workstation has the following installed on it:

Initializing common variables

In the first part of this series, you defined variables that control where elements of the infrastructure are deployed in Google Cloud. Verify that the variables are still set correctly and that they match the values that you set earlier.

  1. Open Cloud Shell.

    Open Cloud Shell

  2. In Cloud Shell, create the following environment variables to set values that you need later in the tutorial.

    The commands set the region to us-east1. If you used a different region in the previous tutorials, change the region in this script to match what you used before.

    region=us-east1
    zone_1=${region}-b
    zone_2=${region}-c
    vpc_name=webappnet
    project_id=your-project-id
    

    Replace your-project-id with the ID of the Cloud project that you're using.

Creating the network infrastructure

In this section, you add subnetworks to the existing virtual private cloud (VPC) network. (You created the VPC network in an earlier tutorial.) These subnets offer unique IP address ranges that are allocated for the web server instances, and that can later offer optional firewall policies based on the subnets.

  1. In Cloud Shell, add a subnet to the existing VPC network:

    gcloud compute networks subnets create public-webapp-zone \
        --network $vpc_name \
        --region $region \
        --range 10.5.0.0/24 \
        --project $project_id
    
  2. Create an internal firewall rule to allow traffic between internal IP addresses:

    gcloud compute firewall-rules create  allow-internal-ports-public-webapp \
        --network $vpc_name \
        --allow tcp:1-65535,udp:1-65535,icmp \
        --source-ranges 10.5.0.0/24 \
        --project $project_id
    

Launching the web servers

You use an image from Google Cloud Marketplace to provision your web servers. After you provision the web servers, you can use them as targets to deploy web apps.

Create the first server

  1. Go to Google Cloud Marketplace.

    Go to Google Cloud Marketplace

  2. In the Google Cloud Console, select the Cloud project where you want the web server to run. Because this tutorial builds off of the previous set, use the same project for this tutorial that you used in the previous tutorials.

  3. Set the following values in the page:

    • Deployment Name: webserver1
    • Zone: zone_1
    • Windows Server OS Version: 2016
    • Boot type: SSD persistent disk
    • Disk size: 200 GB
    • Network name: vpc_name
    • Subnetwork name: public-webapp-zone
    • Firewall: Allow WebDeploy traffic, Allow HTTP traffic

    Replace zone_1 and vpc_name with values that you used when you initialized variables earlier.

  4. Click Deploy and wait for the Cloud Console to indicate that the deployment is complete.

Connect to the server instance

  1. In Cloud Shell, create a password for the webserver1 instance:

    gcloud compute reset-windows-password webserver1 \
        --zone $zone_1 \
        --project $project_id \
        --quiet
    
  2. Connect to the new Windows instance using Remote Desktop Protocol (RDP). Use the credentials that you created in the previous step.

Configure the server instance

  1. On the webserver1 instance, open the PowerShell terminal as Administrator.

  2. Set variables for the DNS IP addresses and for the domain name:

    $DNS1 = "10.1.0.100"
    $DNS2 = "10.2.0.100"
    $DomainName = "example-gcp.com"
    
  3. Create a local service account called webapp.service, which you will use later to publish the web app:

    net user webapp.service * /add
    

    When you're prompted, enter a password. Use a strong password and store it in a safe location for future use.

  4. Enable the account and add it to the Administrators local group:

    net user webapp.service /active:yes
    net localgroup administrators webapp.service /add
    
  5. Configure the DNS servers:

    netsh interface ip set dns Ethernet static $DNS1
    netsh interface ip add dns Ethernet $DNS2 index=2
    
  6. Join the web server to the example-gcp.com domain:

    Add-Computer -DomainName $DomainName -Credential (Get-Credential "example\Administrator")
    

    When you're prompted, enter a password for the Administrator account. This is the domain account that you used when you created an Active Directory forest in the first tutorial in this series. Use a strong password and store it in a safe location for future use.

    You can ignore the following error message:

    WARNING: The changes will take effect after you restart the computer webserver1.
    
  7. Reboot the VM:

    Restart-Computer
    

    This closes the RDP session that you have open.

Create the second server instance and configure it

You now repeat the previous procedures in order to create a second server instance.

  1. Repeat the procedure for creating the server, using the following values:

    • Deployment name: webserver2
    • Zone: zone_2
    • Machine type: 2 vCPU
    • Windows Server OS Version: 2016
    • Boot type: SSD persistent disk
    • Disk size: 200 GB
    • Network name: vpc_name
    • Subnetwork name: public-webapp-zone
    • Firewall: Allow WebDeploy traffic, Allow HTTP traffic

    Replace zone_2 and vpc_name with values that you used when you initialized variables earlier.

  2. Create a password for the webserver2 Windows instance:

    gcloud compute reset-windows-password webserver2 \
        --zone $zone_2\
        --project $project_id \
        --quiet
    

    This step sets the password for your user account for connecting with RDP. The username is your Google account name (that is, the username that's returned by the gcloud config get-value core/account command). Make a note of the username and password for use later in this tutorial.

  3. Connect to the instance using RDP. Use the credentials that you created in the previous step.

  4. Connect to the webserver2 instance. Follow the steps that you used for the first instance, but use the password that you created for the second server instance.

  5. Configure the webserver2 instance. Follow the steps that you used for configuring the first instance. Create the same service account using the same password.

Cloning the web app

The next task is to configure each IIS server and deploy a sample ASP.NET app to it. The web app has credentials to automatically connect to the SQL Server instance that you configured in the previous tutorial.

  1. Make sure you're signed in to the Windows workstation where Visual Studio and Git are installed.

  2. In a command window on the Windows workstation, clone the sample source code repository to the workstation:

    cd c:\
    git clone https://github.com/GoogleCloudPlatform/getting-started-dotnet.git
    cd getting-started-dotnet
    git checkout ad49d787eec88fb30a4b45b4146f5cb63c0519e
    
  3. Go to the following folder:

    C:\getting-started-dotnet\aspnet\2-structured-data
    
  4. To open the sample app solution in Visual Studio, double-click the 2-structured-data.sln file.

  5. In the Solution Explorer pane, double-click the Web.config file to open it.

  6. Set the GoogleCloudSamples:ProjectId key to the project ID.

    For the project ID webapp-sql-ad, the line is similar to the following:

    <add key="GoogleCloudSamples:ProjectId" value="webapp-sql-ad" />
    
  7. Set the GoogleCloudSamples:BookStore value to sqlserver:

    <add key="GoogleCloudSamples:BookStore" value="sqlserver" />
    
  8. Near the end of the file, under <connectionStrings>, find the connectionStrings XML subelement that has the attribute name="LocalSqlServer". Then do the following:

    • Update the connectionString value with the name of the SQL Server availability group listener, which is sql-listener. (You set up this listener in Deploying a multi-subnet SQL Server in this tutorial series.)
    • Change Initial Catalog to bookshelf.
    • Set Integrated Security to True.
    • Use the username and sign-in password that you created for the database service account when you set up the database.
  9. Save and close the Web.config file.

  10. To build the solution, in the Visual Studio menu, click Build > Build Solution.

Deploying the ASP.NET app

In this section, you deploy the web app to both web servers.

  1. On the workstation, if you closed the 2-structured-data.sln file, reopen it. Find the file in the following folder and then double-click it:

    C:\getting-started-dotnet\aspnet\2-structured-data
    
  2. In Visual Studio, click Tools > Google Cloud Tools > Google Cloud Explorer.

  3. Select the project you're working on, and then expand Google Compute Engine.

  4. Right-click the webserver1 instance.

  5. Select Manage Windows credentials.

  6. Click Add credentials.

  7. Enter the username webapp.service.

  8. Select I have password for this user, and then enter the password that you created earlier when you launched the web servers.

  9. Verify that Create a password for me is not selected, and then click Save.

  10. To close the Windows Credentials window, click Close.

  11. Close Google Cloud Explorer.

  12. In Visual Studio, click Tools > Google Cloud Tools > Publish 2-structured-data to Google Cloud.

  13. In the Publish dialog box, select Compute Engine.

  14. Select the webserver1 VM, and then set Credentials to webapp.service.

  15. To build and deploy the sample app, click Publish.

    After the sample app is published, Visual Studio opens the app in your default web browser.

  16. Repeat this procedure for webserver2.

Setting up load balancing

You can now set up network load balancing for the web servers. As part of this procedure, you add health checking to the load balancer. The global load balancer spreads requests between the IIS servers automatically. In addition, if one of the IIS servers fails health checks and is offline, the load balancer automatically directs traffic to the other server.

  1. In Cloud Shell, create a static external IP address for the load balancer:

    gcloud compute addresses create webapp-lb-ip \
        --region $region \
        --project $project_id
    

    The VM instances receive packets that are destined for this IP address.

  2. Add an HTTP health check object:

    gcloud compute http-health-checks create bookshelf-check \
        --project $project_id \
        --request-path /Books
    

    This example uses the default settings for the health check mechanism. You can customize these settings. You specify the /Books request path because that's the path that the sample web app uses.

  3. Add a target pool that's in the same region as your VM instances. Target pools require a health check service to function; use the health check object that you created in step 2 for this target pool.

    gcloud compute target-pools create books-lb \
        --region $region \
        --http-health-check bookshelf-check \
        --project $project_id
    
  4. Add the IIS server instances to the target pool:

    gcloud compute target-pools add-instances books-lb \
        --instances webserver1 \
        --instances-zone $zone_1 \
        --project $project_id
    
    gcloud compute target-pools add-instances books-lb \
        --instances webserver2 \
        --instances-zone $zone_2 \
        --project $project_id
    

    Instances within a target pool must be in the same region. However, the instances can be in different zones in the same region.

  5. Add a forwarding rule on behalf of an external IP address and port range that points to your target pool:

    gcloud compute forwarding-rules create www-rule \
        --region $region \
        --ports 80 \
        --address webapp-lb-ip \
        --target-pool books-lb \
        --project $project_id
    

Sending traffic to the instances

After the load balancing service is configured, you can start sending traffic to the load balancer.

  1. Wait at least one minute after you've set up load balancing to allow the configuration to be fully loaded.
  2. In Cloud Shell, check the health of the instances within the load balancer:

    gcloud compute target-pools get-health books-lb \
        --region $region \
        --project $project_id
    

    The output is similar to the following:

    ---
    healthStatus:
    - healthState: HEALTHY
    instance: https://www.googleapis.com/compute/v1/projects/sales-enablement-support/zones/us-east1-c/instances/webserver1
    ipAddress: 35.190.170.76
    kind: compute#targetPoolInstanceHealth
    ---
    healthStatus:
    - healthState: HEALTHY
    instance: https://www.googleapis.com/compute/v1/projects/sales-enablement-support/zones/us-east1-b/instances/webserver2
    ipAddress: 35.190.170.76
    
  3. Copy the ipAddress value, which is the IP address of the load balancer.

  4. In a browser window, enter the load balancer IP address.

    If everything is working, you see the default page for the ASP.NET web app that you deployed:

    Default web page for the Bookshelf app.

Testing load balancing and redundancy

You can now verify how the cluster behaves when components are taken offline. You can test load balancing and redundancy at multiple levels by selectively shutting down an instance of Active Directory, SQL Server, and the IIS servers.

  1. In the Cloud Console, go the VM instances page:

    Go to the VM instances page

  2. Select an instance for Active Directory, for SQL Server, or for IIS. You can choose any of these instances in order to simulate a component going offline.

    List of images that have been created for this architecture.

  3. Click Stop.

  4. In a browser window, enter the load balancer IP address again.

    You see the default Bookshelf app page. This indicates that the app is still running even though components of the infrastructure are no longer available.

  5. Optionally, repeat steps 2 and 3 for other components. For example, if you shut down SQL Server instance earlier, shut down an IIS instance this time.

    As long as one instance of each component is running, the app continues to work.

Cleaning up

After you've finished the tutorial, you can clean up the Google Cloud resources that you created to ensure you aren't billed for them in the future. You can delete the whole project, or you can delete the resources. The following sections describe how to delete these resources.

Deleting the project

  • In the Cloud Console, go to the Manage resources page.

    Go to the Manage resources page

  • In the project list, select the project that you want to delete and then click Delete .
  • In the dialog, type the project ID and then click Shut down to delete the project.
  • Deleting the resources within the project

    At the beginning of the tutorial, you defined variables that control where elements of the infrastructure are deployed. You use those variables in this section for cleanup. Make sure the following variables are set:

    region=us-east1
    zone_1=${region}-b
    zone_2=${region}-c
    vpc_name=webappnet
    project_id=your-project-id
    

    Replace your-project-id with the ID of the Cloud project you're using.

    1. Delete the VMs that you created in this tutorial:

      gcloud compute instances delete ad-dc1 \
          --zone $zone_1 \
          --project $project_id \
          --quiet
      
      gcloud compute instances delete ad-dc2 \
          --zone $zone_2 \
          --project $project_id \
          --quiet
      
      gcloud compute instances delete cluster-sql1 \
          --zone $zone_1 \
          --project $project_id \
          --quiet
      
      gcloud compute instances delete cluster-sql2 \
          --zone $zone_2 \
          --project $project_id \
          --quiet
      
      gcloud compute instances delete webserver1 \
          --zone $zone_1 \
          --project $project_id \
          --quiet
      
      gcloud compute instances delete webserver2 \
          --zone $zone_2 \
          --project $project_id \
          --quiet
      
    2. Delete the firewall rules and routes that you created in this tutorial:

      gcloud compute firewall-rules delete \
          allow-internal-ports-private-ad \
          allow-internal-ports-private-sql \
          allow-internal-ports-public-webapp \
          allow-rdp \
        --project $project_id \
        --quiet
      
      gcloud compute firewall-rules delete \
          webserver1-tcp-80 \
          webserver1-tcp-8172 \
          webserver2-tcp-80 \
          webserver2-tcp-8172 \
        --project $project_id \
        --quiet
      
      gcloud compute routes delete \
          cluster-sql1-route \
          cluster-sql1-route-listener \
          cluster-sql2-route \
          cluster-sql2-route-listener \
        --project $project_id \
        --quiet
      
    3. Delete the subnets in the VPC network:

      gcloud compute networks subnets delete \
          --region $region \
          private-ad-zone-a \
          private-ad-zone-b \
          private-sql-zone-a \
          private-sql-zone-b \
          public-webapp-zone \
        --project $project_id \
        --quiet
      
    4. Delete the VPC network:

      gcloud compute networks delete $vpc_name \
          --project $project_id \
          --quiet
      
    5. Delete the load balancer static IP address that you created:

      gcloud compute addresses delete webapp-lb-ip \
          --region $region \
          --project $project_id \
          --quiet
      
    6. Delete the load balancer infrastructure:

      gcloud compute forwarding-rules delete www-rule \
          --region $region \
          --project $project_id \
          --quiet
      gcloud compute target-pools delete books-lb \
          --region $region \
          --project $project_id \
          --quiet
      gcloud compute http-health-checks delete bookshelf-check \
          --project $project_id \
          --quiet
      

    What's next