This document describes how to manually install Pivotal Cloud Foundry 2.3 for Azure, and how to avoid pitfalls during deployment.
Install Azure CLI:
$ brew update && brew install azure-cli
Set Azure environment:
$ az cloud set --name=AzureCloud
Login to Azure:
$ az login
Note, we have launched a browser for you to login. For old experience with device code, use "az login --use-device-code"
You have logged in. Now let us find all the subscriptions to which you have access...
[
{
"cloudName": "AzureCloud",
"id": "19972672-3fb3-4746-9499-xxxxxxxxxxxx",
"isDefault": true,
"name": "PA-xxx",
"state": "Enabled",
"tenantId": "29248f74-371f-4db2-9a50-xxxxxxxxxxxx",
"user": {
"name": "xxx@pivotal.io",
"type": "user"
}
}
]
List Azure subscriptions:
$ az account list
[
{
"cloudName": "AzureCloud",
"id": "19972672-3fb3-4746-9499-xxxxxxxxxxxx",
"isDefault": true,
"name": "PA-xxx",
"state": "Enabled",
"tenantId": "29248f74-371f-4db2-9a50-xxxxxxxxxxxx",
"user": {
"name": "xxx@pivotal.io",
"type": "user"
}
}
]
Record the value of your subscription id
(SUBSCRIPTION_ID
), and the value
of tenantId
(TENAND_ID
) as well:
$ export SUBSCRIPTION_ID=`az account list | jq -r ".[].id"`
$ export TENANT_ID=`az account list | jq -r ".[].tenantId"`
Generate a password for your client secret (denoted as CLIENT_SECRET
in
this document). Use this value to create an Azure Active Director (AAD):
$ export CLIENT_SECRET=mysecret
$ az ad app create --display-name "Service Principal for BOSH" --password "$CLIENT_SECRET" --homepage "http://BOSHAzureCPI" --identifier-uris "http://BOSHAzureCPI"
{
"acceptMappedClaims": null,
"addIns": [],
"appId": "1c9445f6-d3a5-4c5c-b5ad-xxxxxxxxxxxx",
"appPermissions": null,
"appRoles": [],
"availableToOtherTenants": false,
"deletionTimestamp": null,
"displayName": "Service Principal for BOSH",
"errorUrl": null,
"groupMembershipClaims": null,
"homepage": "http://BOSHAzureCPI",
"identifierUris": [
"http://BOSHAzureCPI"
],
"informationalUrls": {
"marketing": null,
"privacy": null,
"support": null,
"termsOfService": null
},
"isDeviceOnlyAuthSupported": null,
"keyCredentials": [],
"knownClientApplications": [],
"logo@odata.mediaContentType": "application/json;odata=minimalmetadata; charset=utf-8",
"logoUrl": null,
"logoutUrl": null,
"oauth2AllowIdTokenImplicitFlow": true,
"oauth2AllowImplicitFlow": false,
"oauth2AllowUrlPathMatching": false,
"oauth2Permissions": [
{
"adminConsentDescription": "Allow the application to access Service Principal for BOSH on behalf of the signed-in user.",
"adminConsentDisplayName": "Access Service Principal for BOSH",
"id": "0f1b8ad3-0245-46f9-8017-xxxxxxxxxxxx",
"isEnabled": true,
"type": "User",
"userConsentDescription": "Allow the application to access Service Principal for BOSH on your behalf.",
"userConsentDisplayName": "Access Service Principal for BOSH",
"value": "user_impersonation"
}
],
"oauth2RequirePostResponse": false,
"objectId": "a715e3e2-29f0-40da-b836-xxxxxxxxxxxx",
"objectType": "Application",
"odata.metadata": "https://graph.windows.net/29248f74-371f-4db2-9a50-c62a6877a0c1/$metadata#directoryObjects/Microsoft.DirectoryServices.Application/@Element",
"odata.type": "Microsoft.DirectoryServices.Application",
"optionalClaims": null,
"orgRestrictions": [],
"parentalControlSettings": {
"countriesBlockedForMinors": [],
"legalAgeGroupRule": "Allow"
},
"passwordCredentials": [
{
"customKeyIdentifier": null,
"endDate": "2019-10-25T09:46:05.19817Z",
"keyId": "a6a8bd99-f7a2-4cb9-a4ff-xxxxxxxxxxxx",
"startDate": "2018-10-25T09:46:05.19817Z",
"value": null
}
],
"publicClient": null,
"publisherDomain": null,
"recordConsentConditions": null,
"replyUrls": [],
"requiredResourceAccess": [],
"samlMetadataUrl": null,
"signInAudience": "AzureADMyOrg",
"tokenEncryptionKeyId": null
}
Record the value of appId
(APPLICATION_ID
):
$ export APPLICATION_ID=`az ad app list --identifier-uri "http://BOSHAzureCPI" | jq -r '.[].appId'`
Create a service principal:
$ az ad sp create --id $APPLICATION_ID
{
"accountEnabled": true,
"addIns": [],
"alternativeNames": [],
"appDisplayName": "Service Principal for BOSH",
"appId": "1c9445f6-d3a5-4c5c-b5ad-xxxxxxxxxxxx",
"appOwnerTenantId": "29248f74-371f-4db2-9a50-xxxxxxxxxxxx",
"appRoleAssignmentRequired": false,
"appRoles": [],
"deletionTimestamp": null,
"displayName": "Service Principal for BOSH",
"errorUrl": null,
"homepage": "http://BOSHAzureCPI",
"keyCredentials": [],
"logoutUrl": null,
"oauth2Permissions": [
{
"adminConsentDescription": "Allow the application to access Service Principal for BOSH on behalf of the signed-in user.",
"adminConsentDisplayName": "Access Service Principal for BOSH",
"id": "0f1b8ad3-0245-46f9-8017-xxxxxxxxxxxx",
"isEnabled": true,
"type": "User",
"userConsentDescription": "Allow the application to access Service Principal for BOSH on your behalf.",
"userConsentDisplayName": "Access Service Principal for BOSH",
"value": "user_impersonation"
}
],
"objectId": "f226a7f4-dc06-4be2-b52c-xxxxxxxxxxxx",
"objectType": "ServicePrincipal",
"odata.metadata": "https://graph.windows.net/29248f74-371f-4db2-9a50-c62a6877a0c1/$metadata#directoryObjects/Microsoft.DirectoryServices.ServicePrincipal/@Element",
"odata.type": "Microsoft.DirectoryServices.ServicePrincipal",
"passwordCredentials": [],
"preferredTokenSigningKeyThumbprint": null,
"publisherName": "Pivotal Corporation",
"replyUrls": [],
"samlMetadataUrl": null,
"servicePrincipalNames": [
"1c9445f6-d3a5-4c5c-b5ad-xxxxxxxxxxxx",
"http://BOSHAzureCPI"
],
"servicePrincipalType": "Application",
"signInAudience": "AzureADMyOrg",
"tags": [],
"tokenEncryptionKeyId": null
}
Record the value of your service principal name (such as the same as APPLICATION_ID
):
$ export SERVICE_PRINCIPAL_NAME=`az ad sp list | jq -r --arg APPLICATION_ID $APPLICATION_ID '.[] | select(.appId==$APPLICATION_ID) | .servicePrincipalNames[1]'`
Assign the role Contributor
on your service principal:
$ az role assignment create --assignee "$SERVICE_PRINCIPAL_NAME" --role "Contributor" --scope /subscriptions/$SUBSCRIPTION_ID
{
"canDelegate": null,
"id": "/subscriptions/19972672-3fb3-4746-9499-xxxxxxxxxxxx/providers/Microsoft.Authorization/roleAssignments/4fe0a5d9-4ae2-4da8-b8ac-xxxxxxxxxxxx",
"name": "4fe0a5d9-4ae2-4da8-b8ac-xxxxxxxxxxxx",
"principalId": "f226a7f4-dc06-4be2-b52c-xxxxxxxxxxxx",
"roleDefinitionId": "/subscriptions/19972672-3fb3-4746-9499-xxxxxxxxxxxx/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-xxxxxxxxxxxx",
"scope": "/subscriptions/19972672-3fb3-4746-9499-xxxxxxxxxxxx",
"type": "Microsoft.Authorization/roleAssignments"
}
Make sure the assignment is set:
$ az role assignment list --assignee "$SERVICE_PRINCIPAL_NAME"
[
{
"canDelegate": null,
"id": "/subscriptions/19972672-3fb3-4746-9499-xxxxxxxxxxxx/providers/Microsoft.Authorization/roleAssignments/4fe0a5d9-4ae2-4da8-b8ac-xxxxxxxxxxxx",
"name": "4fe0a5d9-4ae2-4da8-b8ac-xxxxxxxxxxxx",
"principalId": "f226a7f4-dc06-4be2-b52c-xxxxxxxxxxxx",
"principalName": "http://BOSHAzureCPI",
"roleDefinitionId": "/subscriptions/19972672-3fb3-4746-9499-xxxxxxxxxxxx/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-xxxxxxxxxxxx",
"roleDefinitionName": "Contributor",
"scope": "/subscriptions/19972672-3fb3-4746-9499-xxxxxxxxxxxx",
"type": "Microsoft.Authorization/roleAssignments"
}
]
Verify your service principal:
$ az login --username $APPLICATION_ID --password $CLIENT_SECRET --service-principal --tenant $TENANT_ID
[
{
"cloudName": "AzureCloud",
"id": "19972672-3fb3-4746-9499-xxxxxxxxxxxx",
"isDefault": true,
"name": "PA-xxx",
"state": "Enabled",
"tenantId": "29248f74-371f-4db2-9a50-xxxxxxxxxxxx",
"user": {
"name": "1c9445f6-d3a5-4c5c-b5ad-xxxxxxxxxxxx",
"type": "servicePrincipal"
}
}
]
The login should be successful: if not, create a new service principal again.
Register your subscription with Microsoft.Storage
:
$ az provider register --namespace Microsoft.Storage
Registering is still on-going. You can monitor using 'az provider show -n Microsoft.Storage'
Register your subscription with Microsoft.Network
:
$ az provider register --namespace Microsoft.Network
Registering is still on-going. You can monitor using 'az provider show -n Microsoft.Network'
Register your subscription with Microsoft.Compute
:
$ az provider register --namespace Microsoft.Compute
Registering is still on-going. You can monitor using 'az provider show -n Microsoft.Compute'
Create a resource group using Azure Portal:
Record the resource group name (RESOURCE_GROUP
):
$ export RESOURCE_GROUP=xxx
Choose a location name corresponding to the location you used for the resource
group (for instance: France Central
):
$ az account list-locations
[
{
"displayName": "France Central",
"id": "/subscriptions/19972672-3fb3-4746-9499-0ffdc10b8f47/locations/francecentral",
"latitude": "46.3772",
"longitude": "2.3730",
"name": "francecentral",
"subscriptionId": null
},
{
"displayName": "France South",
"id": "/subscriptions/19972672-3fb3-4746-9499-0ffdc10b8f47/locations/francesouth",
"latitude": "43.8345",
"longitude": "2.1972",
"name": "francesouth",
"subscriptionId": null
}
]
Record the location you used for this resource group (LOCATION
):
$ export LOCATION=`az account list-locations | jq -r --arg LOCATION_NAME "France Central" '.[] | select(.displayName==$LOCATION_NAME) | .name'`
Create a network security group named pcf-nsg
:
$ az network nsg create --name pcf-nsg --resource-group $RESOURCE_GROUP --location $LOCATION
{
"NewNSG": {
"defaultSecurityRules": [
{
"access": "Allow",
"description": "Allow inbound traffic from all VMs in VNET",
"destinationAddressPrefix": "VirtualNetwork",
"destinationAddressPrefixes": [],
"destinationApplicationSecurityGroups": null,
"destinationPortRange": "*",
"destinationPortRanges": [],
"direction": "Inbound",
"etag": "W/\"9c2fbc1f-826e-4aae-b3cf-xxxxxxxxxxxx\"",
"id": "/subscriptions/19972672-3fb3-4746-9499-xxxxxxxxxxxx/resourceGroups/pas-res-group/providers/Microsoft.Network/networkSecurityGroups/pcf-nsg/defaultSecurityRules/AllowVnetInBound",
"name": "AllowVnetInBound",
"priority": 65000,
"protocol": "*",
"provisioningState": "Succeeded",
"resourceGroup": "pas-res-group",
"sourceAddressPrefix": "VirtualNetwork",
"sourceAddressPrefixes": [],
"sourceApplicationSecurityGroups": null,
"sourcePortRange": "*",
"sourcePortRanges": [],
"type": "Microsoft.Network/networkSecurityGroups/defaultSecurityRules"
},
{
"access": "Allow",
"description": "Allow inbound traffic from azure load balancer",
"destinationAddressPrefix": "*",
"destinationAddressPrefixes": [],
"destinationApplicationSecurityGroups": null,
"destinationPortRange": "*",
"destinationPortRanges": [],
"direction": "Inbound",
"etag": "W/\"9c2fbc1f-826e-4aae-b3cf-xxxxxxxxxxxx\"",
"id": "/subscriptions/19972672-3fb3-4746-9499-xxxxxxxxxxxx/resourceGroups/pas-res-group/providers/Microsoft.Network/networkSecurityGroups/pcf-nsg/defaultSecurityRules/AllowAzureLoadBalancerInBound",
"name": "AllowAzureLoadBalancerInBound",
"priority": 65001,
"protocol": "*",
"provisioningState": "Succeeded",
"resourceGroup": "pas-res-group",
"sourceAddressPrefix": "AzureLoadBalancer",
"sourceAddressPrefixes": [],
"sourceApplicationSecurityGroups": null,
"sourcePortRange": "*",
"sourcePortRanges": [],
"type": "Microsoft.Network/networkSecurityGroups/defaultSecurityRules"
},
{
"access": "Deny",
"description": "Deny all inbound traffic",
"destinationAddressPrefix": "*",
"destinationAddressPrefixes": [],
"destinationApplicationSecurityGroups": null,
"destinationPortRange": "*",
"destinationPortRanges": [],
"direction": "Inbound",
"etag": "W/\"9c2fbc1f-826e-4aae-b3cf-xxxxxxxxxxxx\"",
"id": "/subscriptions/19972672-3fb3-4746-9499-xxxxxxxxxxxx/resourceGroups/pas-res-group/providers/Microsoft.Network/networkSecurityGroups/pcf-nsg/defaultSecurityRules/DenyAllInBound",
"name": "DenyAllInBound",
"priority": 65500,
"protocol": "*",
"provisioningState": "Succeeded",
"resourceGroup": "pas-res-group",
"sourceAddressPrefix": "*",
"sourceAddressPrefixes": [],
"sourceApplicationSecurityGroups": null,
"sourcePortRange": "*",
"sourcePortRanges": [],
"type": "Microsoft.Network/networkSecurityGroups/defaultSecurityRules"
},
{
"access": "Allow",
"description": "Allow outbound traffic from all VMs to all VMs in VNET",
"destinationAddressPrefix": "VirtualNetwork",
"destinationAddressPrefixes": [],
"destinationApplicationSecurityGroups": null,
"destinationPortRange": "*",
"destinationPortRanges": [],
"direction": "Outbound",
"etag": "W/\"9c2fbc1f-826e-4aae-b3cf-xxxxxxxxxxxx\"",
"id": "/subscriptions/19972672-3fb3-4746-9499-xxxxxxxxxxxx/resourceGroups/pas-res-group/providers/Microsoft.Network/networkSecurityGroups/pcf-nsg/defaultSecurityRules/AllowVnetOutBound",
"name": "AllowVnetOutBound",
"priority": 65000,
"protocol": "*",
"provisioningState": "Succeeded",
"resourceGroup": "pas-res-group",
"sourceAddressPrefix": "VirtualNetwork",
"sourceAddressPrefixes": [],
"sourceApplicationSecurityGroups": null,
"sourcePortRange": "*",
"sourcePortRanges": [],
"type": "Microsoft.Network/networkSecurityGroups/defaultSecurityRules"
},
{
"access": "Allow",
"description": "Allow outbound traffic from all VMs to Internet",
"destinationAddressPrefix": "Internet",
"destinationAddressPrefixes": [],
"destinationApplicationSecurityGroups": null,
"destinationPortRange": "*",
"destinationPortRanges": [],
"direction": "Outbound",
"etag": "W/\"9c2fbc1f-826e-4aae-b3cf-xxxxxxxxxxxx\"",
"id": "/subscriptions/19972672-3fb3-4746-9499-xxxxxxxxxxxx/resourceGroups/pas-res-group/providers/Microsoft.Network/networkSecurityGroups/pcf-nsg/defaultSecurityRules/AllowInternetOutBound",
"name": "AllowInternetOutBound",
"priority": 65001,
"protocol": "*",
"provisioningState": "Succeeded",
"resourceGroup": "pas-res-group",
"sourceAddressPrefix": "*",
"sourceAddressPrefixes": [],
"sourceApplicationSecurityGroups": null,
"sourcePortRange": "*",
"sourcePortRanges": [],
"type": "Microsoft.Network/networkSecurityGroups/defaultSecurityRules"
},
{
"access": "Deny",
"description": "Deny all outbound traffic",
"destinationAddressPrefix": "*",
"destinationAddressPrefixes": [],
"destinationApplicationSecurityGroups": null,
"destinationPortRange": "*",
"destinationPortRanges": [],
"direction": "Outbound",
"etag": "W/\"9c2fbc1f-826e-4aae-b3cf-xxxxxxxxxxxx\"",
"id": "/subscriptions/19972672-3fb3-4746-9499-xxxxxxxxxxxx/resourceGroups/pas-res-group/providers/Microsoft.Network/networkSecurityGroups/pcf-nsg/defaultSecurityRules/DenyAllOutBound",
"name": "DenyAllOutBound",
"priority": 65500,
"protocol": "*",
"provisioningState": "Succeeded",
"resourceGroup": "pas-res-group",
"sourceAddressPrefix": "*",
"sourceAddressPrefixes": [],
"sourceApplicationSecurityGroups": null,
"sourcePortRange": "*",
"sourcePortRanges": [],
"type": "Microsoft.Network/networkSecurityGroups/defaultSecurityRules"
}
],
"etag": "W/\"9c2fbc1f-826e-4aae-b3cf-xxxxxxxxxxxx\"",
"id": "/subscriptions/19972672-3fb3-4746-9499-xxxxxxxxxxxx/resourceGroups/pas-res-group/providers/Microsoft.Network/networkSecurityGroups/pcf-nsg",
"location": "francecentral",
"name": "pcf-nsg",
"networkInterfaces": null,
"provisioningState": "Succeeded",
"resourceGroup": "pas-res-group",
"resourceGuid": "db3c47c1-76fc-4440-b41c-xxxxxxxxxxxx",
"securityRules": [],
"subnets": null,
"tags": null,
"type": "Microsoft.Network/networkSecurityGroups"
}
}
Add rules to this network security group:
$ az network nsg rule create --name ssh --nsg-name pcf-nsg --resource-group $RESOURCE_GROUP --protocol Tcp --priority 100 --destination-port-range '22'
$ az network nsg rule create --name http --nsg-name pcf-nsg --resource-group $RESOURCE_GROUP --protocol Tcp --priority 200 --destination-port-range '80'
$ az network nsg rule create --name https --nsg-name pcf-nsg --resource-group $RESOURCE_GROUP --protocol Tcp --priority 300 --destination-port-range '443'
$ az network nsg rule create --name diego-ssh --nsg-name pcf-nsg --resource-group $RESOURCE_GROUP --protocol Tcp --priority 400 --destination-port-range '2222'
Create a network security group named opsmgr-ns
:
$ az network nsg create --name opsmgr-nsg --resource-group $RESOURCE_GROUP --location $LOCATION
Add a network security group rule to the opsmgr-nsg
group to allow HTTP traffic to the Ops Manager VM:
$ az network nsg rule create --name http --nsg-name opsmgr-nsg --resource-group $RESOURCE_GROUP --protocol Tcp --priority 100 --destination-port-range 80
Add a network security group rule to the opsmgr-nsg
group to allow HTTPS traffic to the Ops Manager VM:
$ az network nsg rule create --name https --nsg-name opsmgr-nsg --resource-group $RESOURCE_GROUP --protocol Tcp --priority 200 --destination-port-range 443
Add a network security group rule to the opsmgr-nsg
group to allow SSH traffic to the Ops Manager VM:
$ az network nsg rule create --name ssh --nsg-name opsmgr-nsg --resource-group $RESOURCE_GROUP --protocol Tcp --priority 300 --destination-port-range 22
Create a virtual network named PCF
:
$ az network vnet create --name PCF --resource-group $RESOURCE_GROUP --location $LOCATION --address-prefixes 10.0.0.0/16
Add subnets to the network for Ops Manager, BOSH director and PCF VMs and attach the Network Security Group:
$ az network vnet subnet create --name Management \
--vnet-name PCF \
--resource-group $RESOURCE_GROUP \
--address-prefix 10.0.4.0/22 \
--network-security-group pcf-nsg
$ az network vnet subnet create --name Deployment \
--vnet-name PCF \
--resource-group $RESOURCE_GROUP \
--address-prefix 10.0.12.0/22 \
--network-security-group pcf-nsg
$ az network vnet subnet create --name Services \
--vnet-name PCF \
--resource-group $RESOURCE_GROUP \
--address-prefix 10.0.8.0/22 \
--network-security-group pcf-nsg
Generate a name for your BOSH storage account:
$ export STORAGE_NAME=`openssl rand -hex 12`
Create a Standard storage account for BOSH:
$ az storage account create --name $STORAGE_NAME --resource-group $RESOURCE_GROUP --sku Standard_LRS --location $LOCATION
Record the connection string for this storage account (CONNECTION_STRING
):
$ export CONNECTION_STRING=`az storage account show-connection-string --name $STORAGE_NAME --resource-group $RESOURCE_GROUP | jq -r '.connectionString'`
Create three blob containers in the BOSH storage account, named opsmanager
, bosh
, and stemcell
:
$ az storage container create --name opsmanager --connection-string $CONNECTION_STRING
$ az storage container create --name bosh --connection-string $CONNECTION_STRING
$ az storage container create --name stemcell --public-access blob --connection-string $CONNECTION_STRING
Create a table named stemcells
:
$ az storage table create --name stemcells --connection-string $CONNECTION_STRING
Create 5 deployment storage accounts for BOSH:
$ export STORAGE_TYPE="Premium_LRS"
$ for i in $(seq 1 5); do \
az storage account create --name boshdeployment$i --resource-group $RESOURCE_GROUP --sku $STORAGE_TYPE --kind Storage --location $LOCATION && \
export CONNECTION_STRING=`az storage account show-connection-string --name boshdeployment$i --resource-group $RESOURCE_GROUP | jq -r '.connectionString'` && \
az storage container create --name bosh --connection-string $CONNECTION_STRING && \
az storage container create --name stemcell --connection-string $CONNECTION_STRING ;\
done
Create a load balancer named pcf-lb
:
$ az network lb create --name pcf-lb --resource-group $RESOURCE_GROUP --location $LOCATION --backend-pool-name pcf-lb-be-pool --frontend-ip-name pcf-lb-fe-ip --public-ip-address pcf-lb-ip --public-ip-address-allocation Static --sku Standard
$ az network lb probe create --lb-name pcf-lb --name tcp80 --resource-group $RESOURCE_GROUP --protocol Tcp --port 80
$ az network lb rule create --lb-name pcf-lb --name http --resource-group $RESOURCE_GROUP --protocol Tcp --frontend-port 80 --backend-port 80 --frontend-ip-name pcf-lb-fe-ip --backend-pool-name pcf-lb-be-pool --probe-name tcp80
$ az network lb rule create --lb-name pcf-lb --name https --resource-group $RESOURCE_GROUP --protocol Tcp --frontend-port 443 --backend-port 443 --frontend-ip-name pcf-lb-fe-ip --backend-pool-name pcf-lb-be-pool --probe-name tcp80
Get the allocated IP address for the load balancer:
$ az network public-ip show --name pcf-lb-ip --resource-group $RESOURCE_GROUP | jq -r '.ipAddress'
40.66.59.98
Create a wildcard DNS entry pointing this IP address. The DNS entry should look like this:
*.mydomain.com IN A 40.66.59.98
Create a load balancer named pcf-ssh-lb
:
$ az network lb create --name pcf-ssh-lb --resource-group $RESOURCE_GROUP --location $LOCATION --backend-pool-name pcf-ssh-lb-be-pool --frontend-ip-name pcf-ssh-lb-fe-ip --public-ip-address pcf-ssh-lb-ip --public-ip-address-allocation Static --sku Standard
$ az network lb probe create --lb-name pcf-ssh-lb --name tcp2222 --resource-group $RESOURCE_GROUP --protocol Tcp --port 2222
$ az network lb rule create --lb-name pcf-ssh-lb --name diego-ssh --resource-group $RESOURCE_GROUP --protocol Tcp --frontend-port 2222 --backend-port 2222 --frontend-ip-name pcf-ssh-lb-fe-ip --backend-pool-name pcf-ssh-lb-be-pool --probe-name tcp2222
Get the allocated IP address for the load balancer:
$ az network public-ip show --name pcf-ssh-lb-ip --resource-group $RESOURCE_GROUP | jq -r '.ipAddress'
40.66.59.100
Create a wildcard DNS entry pointing this IP address. The DNS entry should look like this:
*.ssh.sys.mydomain.com IN A 40.66.59.100
Navigate to Pivotal Network and get the URL to the Ops Manager VM image. Record this URL:
$ export OPS_MAN_IMAGE_URL="https://opsmanagerwesteurope.blob.core.windows.net/images/ops-manager-2.3-build.188.vhd"
Import the Ops Manager image to Azure:
$ export CONNECTION_STRING=`az storage account show-connection-string --name $STORAGE_NAME --resource-group $RESOURCE_GROUP | jq -r '.connectionString'`
$ az storage blob copy start --source-uri $OPS_MAN_IMAGE_URL --connection-string $CONNECTION_STRING --destination-container opsmanager --destination-blob opsman-image-2.3.x.vhd
{
"completionTime": null,
"id": "0e421db0-8696-4315-ba35-b4547dd7fc4b",
"progress": null,
"source": null,
"status": "pending",
"statusDescription": null
}
Importing the Ops Manager image takes a long time. Monitor this operation using this command:
$ az storage blob show --name opsman-image-2.3.x.vhd --container-name opsmanager --connection-string $CONNECTION_STRING | jq '.properties.copy'
{
"completionTime": null,
"id": "0e421db0-8696-4315-ba35-b4547dd7fc4b",
"progress": "2682601472/10737418752",
"source": "https://opsmanagerwesteurope.blob.core.windows.net/images/ops-manager-2.3-build.188.vhd",
"status": "pending",
"statusDescription": null
}
Create a public IP address named ops-manager-ip
:
$ az network public-ip create --name ops-manager-ip --resource-group $RESOURCE_GROUP --location $LOCATION --allocation-method Static
Record the public IP address for Ops Manager:
$ export OPS_MANAGER_IP=`az network public-ip list | jq -r '.[] | select(.name=="ops-manager-ip") | .ipAddress'`
Create a network interface for Ops Manager:
$ az network nic create --vnet-name PCF --subnet Management --network-security-group opsmgr-nsg --private-ip-address 10.0.4.4 --public-ip-address ops-manager-ip --resource-group $RESOURCE_GROUP --name opsman-nic --location $LOCATION
Create a key pair with the username ubuntu
:
$ ssh-keygen -t rsa -f opsman -C ubuntu
Create a managed image from the Ops Manager image:
$ az image create --resource-group $RESOURCE_GROUP --name opsman-image-2.3.x --source https://$STORAGE_NAME.blob.core.windows.net/opsmanager/opsman-image-2.3.x.vhd --location $LOCATION --os-type Linux
{
"id": "/subscriptions/19972672-3fb3-4746-9499-xxxxxxxxxxxx/resourceGroups/pas-res-group/providers/Microsoft.Compute/images/opsman-image-2.3.x",
"location": "francecentral",
"name": "opsman-image-2.3.x",
"provisioningState": "Succeeded",
"resourceGroup": "pas-res-group",
"sourceVirtualMachine": null,
"storageProfile": {
"dataDisks": [],
"osDisk": {
"blobUri": "https://a307f431e61a19e10e05b521.blob.core.windows.net/opsmanager/opsman-image-2.3.x.vhd",
"caching": "None",
"diskSizeGb": 10,
"managedDisk": null,
"osState": "Generalized",
"osType": "Linux",
"snapshot": null,
"storageAccountType": "Standard_LRS"
},
"zoneResilient": null
},
"tags": {},
"type": "Microsoft.Compute/images"
}
Create the Ops Manager VM:
$ az vm create --name opsman-2.3.x --resource-group $RESOURCE_GROUP --location $LOCATION --nics opsman-nic --image opsman-image-2.3.x --os-disk-size-gb 128 --os-disk-name opsman-2.3.x-osdisk --admin-username ubuntu --size Standard_DS2_v2 --storage-sku Standard_LRS --ssh-key-value opsman.pub
{
"fqdns": "",
"id": "/subscriptions/19972672-3fb3-4746-9499-xxxxxxxxxxxx/resourceGroups/pas-res-group/providers/Microsoft.Compute/virtualMachines/opsman-2.3.x",
"location": "francecentral",
"macAddress": "00-0D-3A-95-31-E3",
"powerState": "VM running",
"privateIpAddress": "10.0.4.4",
"publicIpAddress": "40.89.165.11",
"resourceGroup": "pas-res-group",
"zones": ""
}
Create a DNS entry pointing to the Ops Manager VM. Always access Ops Manager using this FQDN.
Navigate to the Ops Manager FQDN: https://opsman.mydomain.com
.
Select Internal Authentication, and fill in the form:
- Username:
admin
- Password:
MYSECRET
- Decryption passphrase:
MYSECRET
Validate, and wait for the Ops Manager to start. On the login page, use your credentials to access the Ops Manager Dashboard.
Click the BOSH Director Tile. Enter configuration values by following instructions from this page.
Once you are ready, click on Review pending changes
from the
Installation Dashboard
, then click on Apply changes
.
☕ Grab a coffee!
Since the installation is done, BOSH Director is now installed on your environment. It's time to handle PAS.
Download PAS for Azure from Pivotal Network.
Select Small Footprint PAS
to install a lightweight installation (less VM,
less resources). This installation is not production ready!
Once you have downloaded this file, you need to import it into Ops Manager.
Click on Import a Product
from Installation Dashboard
.
When the upload is done, follow installation steps from this page.