# webservice\_scaleset

## Description

This example creates a load balanced https web farm using a scaleset to dynamically resize the number of virtual machines running nginx. The front end of the balancer listens to ports 80 and 443, and creates the necessary structures to store and use a certificate (it can be self-signed).

Due to the fundamental differences in networking between AWS (which uses subnets that are in availability zones) and Azure (which uses subnets that are region-wide), a portable blueprint creates one subnet per availability zone for the virtual machine traffic. On AWS all of the subnets may be used, however on Azure only one of the subnets will be used.

To make the example portable, use a 2048-bit length private key. If you use a larger length private key on AWS you will receive a "certificate not found" error, which is due to an AWS configuration limitation of ELBv2 load balancers against ACM.

## Concepts

The following concepts are present in this example:

* Certificates
* HTTPS
* Linux
* Load Balancing
* Nginx
* Scalesets
* Secrets
* Userdata
* Variables
* Virtual Machines

## Venues

This example is regularly tested against:

![azure](https://4172935707-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MAzdR4AyersVibQD8Ei%2Fsync%2Fd2a51335bb50c250c191db68d5c884bf9b32ca84.png?generation=1596016310017287\&alt=media)

## Release Notes

### 1.0

* Initial release.

### 2.0

* Added variables for controlling vm, zone counts.
* Added https support for existing certificates.

### 3.0

* Removed the prerequisite for certificates (and on Azure, a managed identity) to be created manually before applying this example.
* Added support for importing certificates into the venue.
* Removed azure-specific variables.

### 4.0

* Converted to using a scaleset.

## Blueprint

```yaml
---
variables:
  admin_username:
    description: >-
      The administrative username for SSH access to the linux virtual machines.
      Note that the web servers are not publicly accessible however they still
      require an administrative user configuration.
    type: string
    default: adminuser
  admin_public_key:
    description: >-
      The administrative public key for SSH access to the linux virtual machines.
      Note that the web servers are not publicly accessible however they still
      require an administrative user configuration.
    type: string
  balancer_cert_body:
    description: >-
      The balancer certificate in PEM format.
    type: string
  balancer_cert_private_key:
    description: >-
      The balancer certificate's private key in PEM format.
    type: secret

location:
  region:
    my-region:
      country: USA
      area: northwest
  folder:
    tuono-webservice-vmss:
      region: my-region

security:
  certificate:
    webservice-cert:
      body: (( balancer_cert_body ))
      private_key: (( balancer_cert_private_key ))

networking:
  network:
    webservice:
      range: 10.0.0.0/16
      scope: public

  balancer:
    webservice-balancer:
      network: webservice
      scope: public
      purpose: testing
      routes:
        # redirect port 80 to port 443
        - from: external-http
          to: external-https
        # service port 443
        - from: external-https
          to: internal-http-dev

  service:
    external-http:
      # traffic coming in from the internet
      port: 80
      protocol: http
    external-https:
      # secure traffic coming in from the internet
      port: 443
      protocol: https
      certificate: webservice-cert
      security_policy:
        aws: ELBSecurityPolicy-TLS-1-2-Ext-2018-06
        azure: AppGwSslPolicy20170401S
    internal-http-dev:
      # traffic for the web service internally
      port: 8080
      protocol: http

compute:
  image:
    bitnami:
      publisher: bitnami
      product: nginxstack
      sku: 1-9
      venue:
        aws:
          image_id: ami-0e789678bc78bb87e

  scaleset:
    webpool:
      monitor:
        - metric: cpu
          grow:
            threshold: 75
            duration: 2 minutes
            cooldown: 10 minutes
          shrink:
            threshold: 25
            duration: 5 minutes
            cooldown: 15 minutes
      network: webservice
      provides: internal-http-dev
      scope: private-no-internet
      size:
        default: 3
        maximum: 4
        minimum: 2
      cores: 1
      memory: 1 GB
      image: bitnami
      tags:
        wicked: awesome
      configure:
        admin:
          # required to initiate a deploy on Azure, but ignored on AWS
          # when userdata is present
          username: (( admin_username ))
          public_key: (( admin_public_key ))
        userdata:
          # why not use cloud-init?
          # answer: the azure bitnami nginx marketplace image has disabled cloud-init
          #         so we have to use a shell script to make a portable example
          type: shell
          content: |
            #!/bin/sh

            ### debugging mode so we can see what is happening in the logs
            set -x

            ### set up administrative user (idempotent)
            userid=$(id -u (( admin_username )))
            if [ -z "$userid" ]; then
                set -e
                adduser --gecos "" --disabled-password (( admin_username ))
                cd ~(( admin_username ))
                mkdir .ssh
                chmod 700 .ssh
                echo "(( admin_public_key ))" > .ssh/authorized_keys
                chmod 600 .ssh/authorized_keys
                chown -R (( admin_username )).(( admin_username )) .ssh
                usermod -aG sudo (( admin_username ))
                echo "(( admin_username ))   ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
                set +e
            fi

            ### set up nginx by replacing the home page
            echo "webserver-$(uuidgen)" > /opt/bitnami/nginx/html/index.html

            ### make it run on port 8080
            sed -i 's/listen  80;/listen  8080;/' /opt/bitnami/nginx/conf/nginx.conf

            ### restart nginx due to the port change
            /opt/bitnami/ctlscript.sh restart nginx
```
