APACHE-2.0 License
This will deploy a Windows environment on to Google Cloud Platform (GCP). This will include Windows Servers with SQL Server installed with AlwaysOn AG.
The creation of the infrastructure is just the start, which takes about 4 minutes.
It then takes about 15 minutes for the domain controller to get configured. The SQL Server VMs will wait for this to happen. After the domain controller has completed the SQL Server VMs will take an approximately 10 more minutes.
Before you start running Terraform, you need to create a service account in your project for Terraform to run as. Under IAM and Admin --> Service accounts, create a serice account and then download the key. Give the service account the permissions it needs to create infrastructure in your project.
Upload the key to wherever you are running the terraform and set GOOGLE_APPLICATION_CREDENTIALS to use this key ( or follow adding credntials in https://www.terraform.io/docs/providers/google/getting_started.html##)
On a machine with terraform
(at least 0.13) and git
(the Google Cloud Shell can be leveraged as well):
gcloud source repos clone terraform-sqlserver-alwayson --project=cloud-ce-shared-code
Or:
git clone https://github.com/GoogleCloudPlatform/terraform-sqlserver-alwayson.git
Let's get into that directory:
cd terraform-sqlserver-alwayson/demo-staging/
Here we'll update the deployment variables in prepareProject.sh
. Edit everything within the single quotes in prepareProject.sh
(Note: projectNumber
doesn't need single quotes, just the number itself):
region='{your-region-here}'
zone='{your-zone-here}'
project='{your-project-id}'
projectNumber={your-project-number}
#differentiate this deployment from others. Use lowercase alphanumerics between 6 and 30 characters.
prefix='{desired-domain-name-and-unique-seed-for-bucket-name}'
#user you will be running as
user='{user-you-will-run-as}'
‼️ For deployment troubleshooting, try entering in another unique prefix
.
Now we'll update the terraform project in the environment folder containing main.tf
and backend.tf
, by running:
./prepareProject.sh
Here's what's happening:
gcloud services enable cloudkms.googleapis.com
gcloud services enable runtimeconfig.googleapis.com
gcloud services enable cloudresourcemanager.googleapis.com
gcloud services enable compute.googleapis.com
gcloud services enable iam.googleapis.com
#create the bucket
gsutil mb -p $project gs://$bucketName
gsutil -m cp -r ../powershell/bootstrap gs://$bucketName/powershell/bootstrap/
gcloud kms keyrings create acme-deployment-ring --location=us-central1
gcloud kms keys create acme-deployment-key --location=us-central1 --keyring=myring --purpose=encryption
Next we'll run:
terraform init
Followed by
terraform apply
You might encounter some warnings about interpolation-only expressions, due to changes between TF versions but they can safely be ignored. as of 0.13.2
NetBIOS is a legacy network application used by windows for active directory. It limits the names of machines to 15 characters. For this reason we must observe this limit on our computer names for our deployment to succeed.
We are limited as described above. ${var.deployment-name} - a unique 8 character deployment name ${var.function} - 3 characters decribing the purpose of the instance ${var.instancenumber} - two digits computername = "${var.deployment-name}-${var.function}-${var.instancenumber}"
domain admin: usr: {full domain name}\Administrator pw: * Domain Controller Password: * SQL 1 Password: * SQL 2 Password: * SQL 3 Password:
There are folders for environment-specific content such as sandbox, clickToDeploy and acme-staging. Modules, used by the deployment scripts, can be found in the ./modules directory. The contents of the docs directory is for documentary purposes, even if it is code. The 2 shell scripts in the environment folders are:
Runtime-config has limited support in terraform. In deployment manager one can create the config and variables. In terraform, you can only create the runtime config, variable and waiters must be created in powershell scipts or using command line or rest API.
The following deletes a waiter, which you might need to do if you redeploy
gcloud beta runtime-config configs waiters delete clicktodeploy-dev-sql-p-01_waiter --config-name=acme-runtime-config
The network module has a defult firewall resource that allows access for 3389 and 8080 to machines tagged we, pdc pr sql. If you are testing in a google project, your rules will be deleted by gce enforcer every 15 minutes and you will need to recreate your rule.
terraform apply --target=module.create-network.google_compute_firewall.default
$script:gce_install_dir = 'C:\Program Files\Google\Compute Engine\sysprep'
$Script:c2d_scripts_bucket = 'c2d-windows/scripts'
$Script:install_path="C:\C2D" # Folder for downloads
$script:show_msgs = $false
$script:write_to_serial = $false
# Instance specific variables
$script_name = 'sql_install.ps1'
$script_subpath = 'sqlserver'
$task_name = "SQLInstall"
# Download the scripts
# Base Script
$base_script_path = "$Script:c2d_scripts_bucket/c2d_base.psm1"
$base_script = "$Script:install_path\c2d_base.psm1"
# Run Script
$run_script = "$Script:install_path\$script_name"
$run_script_path = "$Script:c2d_scripts_bucket/$script_subpath/$script_name"
So... ClickToDeploy depends upon (preinstalled on all windows instances):
We are downloading:
These are provided for reference purposes in powershell/c2d
sql_install.ps1 gets called without any arguments from a scheduled task. It does the following:
On all sql instances:
Install-WindowsFeature RSAT-AD-PowerShell
Install-WindowsFeature Failover-Clustering -IncludeManagementTools
$Script:static_ip=@("10.10.0.3","10.10.0.4","10.10.0.5")
$Script:cluster_name="cluster-dbclus"
$Script:all_nodes_fqdn=@('c2d-sql-01.corp.acme.com','c2d-sql-02.corp.acme.com','c2d-sql-03.corp.acme.com')
New-Cluster -Name $Script:cluster_name -Node $Script:all_nodes_fqdn -NoStorage -StaticAddress $Script:static_ip
#The following is how you add a cluster in powershell. This must be run as domain admin
$Script:cluster_name='cluster-dbclust'
#$Script:all_nodes_fqdn ="c2d-sql-01.acme.com,c2d-sql-02.acme.com,c2d-sql-03.acme.com"
$Script:all_nodes_fqdn =@("c2d-sql-01.acme.com","c2d-sql-02.acme.com","c2d-sql-03.acme.com")
$Script:static_ip= @("10.1.0.4","10.2.0.4","10.3.0.4")
Write-Host "Setting up cluster $Script:cluster_name for nodes $Script:all_nodes_fqdn and ips $Script:static_ip"
# Create the cluster
try {
$result = New-Cluster -Name $Script:cluster_name -Node $Script:all_nodes_fqdn `
-NoStorage -StaticAddress $Script:static_ip
Write-Host "Result for setup cluster: $result"
return $true
}
catch {
Write-Host "** Failed to setup cluster: $Script:cluster_name ** "
Write-Host $_.Exception.GetType().FullName
Write-Host "$_.Exception.Message"
return $false
}
#New-Cluster -Name "cluster-dbclus" -Node "c2d-sql-01.acme.com,c2d-sql-02.acme.com,c2d-sql-03.acme.com" -NoStorage -StaticAddress "10.1.0.4,10.2.0.4,10.3.0.4"
New-Cluster -Name "cluster-dbclus" -Node @("c2d-sql-01","c2d-sql-02","c2d-sql-03") -NoStorage -StaticAddress @("10.1.0.4","10.2.0.4","10.3.0.4")