From 38db586d5ac0912e6e15374a5b4b1601469f6de0 Mon Sep 17 00:00:00 2001 From: Miguel Veloso Date: Thu, 21 Nov 2019 10:45:28 +0000 Subject: [PATCH] Remove obsolete files/folders --- .../azurefunctions/azurefunctionsdeploy.json | 209 ---- .../azurefunctionsdeploy.parameters.json | 9 - deploy/azure/az/azurefunctions/readme.md | 39 - .../LinuxContainers/gen-keyvaultcert.ps1 | 53 - .../servicefabric/LinuxContainers/readme.md | 134 --- .../LinuxContainers/servicefabricdeploy.json | 751 -------------- .../servicefabricdeploy.parameters.json | 93 -- .../servicefabricdeploysecured.json | 821 ---------------- ...servicefabricdeploysecured.parameters.json | 102 -- .../WindowsContainers/gen-keyvaultcert.ps1 | 53 - .../servicefabric/WindowsContainers/readme.md | 138 --- .../servicefabricdeploy.json | 859 ---------------- .../servicefabricdeploy.parameters.json | 100 -- .../servicefabricdeploysecured.json | 924 ------------------ ...servicefabricdeploysecured.parameters.json | 106 -- deploy/azure/az/vms/docker-machine.md | 48 - deploy/azure/az/vms/linux-vm/linuxvm.json | 199 ---- .../az/vms/linux-vm/linuxvm.parameters.json | 7 - deploy/azure/az/vms/plain-vm.md | 77 -- deploy/azure/az/vms/readme.md | 10 - deploy/azure/az/vms/win-vm/windowsvm.json | 290 ------ .../az/vms/win-vm/windowsvm.parameters.json | 7 - deploy/k8s/README.CICD.k8s.md | 66 -- deploy/k8s/README.k8s.md | 98 -- deploy/k8s/build-push-images.ps1 | 72 -- deploy/k8s/conf-files.md | 17 - deploy/k8s/conf_cloud.yaml | 34 - deploy/k8s/conf_local.yaml | 27 - deploy/k8s/deploy-ingress-azure.ps1 | 1 - deploy/k8s/deploy-ingress-dockerlocal.ps1 | 2 - deploy/k8s/deploy-ingress.ps1 | 5 - deploy/k8s/deploy-nodeports.ps1 | 2 - deploy/k8s/deploy.ps1 | 212 ---- deploy/k8s/deploy.sh | 212 ---- deploy/k8s/img/blob_creation.png | Bin 26340 -> 0 bytes deploy/k8s/img/deploy_script_task.png | Bin 51001 -> 0 bytes deploy/k8s/img/get_kubectlbin_task.png | Bin 32167 -> 0 bytes deploy/k8s/img/get_kubectlconfig_task.png | Bin 31190 -> 0 bytes deploy/k8s/internalurls.yaml | 33 - deploy/k8s/nginx-ingress/mandatory-istio.yaml | 238 ----- deploy/k8s/nodeports/rabbitmq-admin.yaml | 12 - deploy/k8s/nodeports/sql-service.yaml | 12 - deploy/k8s/readme.md | 12 - obsolete/cli-linux/build-bits-linux.sh | 51 - .../cli-linux/docker-compose.local.build.yml | 10 - obsolete/cli-linux/prepare-spa-app.sh | 4 - obsolete/cli-linux/run.sh | 6 - obsolete/cli-mac/build-bits.sh | 47 - obsolete/cli-windows/build-bits-simple.ps1 | 17 - obsolete/cli-windows/build-bits.ps1 | 59 -- obsolete/cli-windows/build-images.ps1 | 11 - obsolete/cli-windows/delete-images.ps1 | 27 - .../delete-vs-and-eshop-images.ps1 | 46 - obsolete/cli-windows/start-external.ps1 | 11 - .../cli-windows/start-windows-containers.ps1 | 33 - .../vsts/build-bits-no-parallel.ps1 | 56 -- 56 files changed, 6462 deletions(-) delete mode 100644 deploy/azure/az/azurefunctions/azurefunctionsdeploy.json delete mode 100644 deploy/azure/az/azurefunctions/azurefunctionsdeploy.parameters.json delete mode 100644 deploy/azure/az/azurefunctions/readme.md delete mode 100644 deploy/azure/az/servicefabric/LinuxContainers/gen-keyvaultcert.ps1 delete mode 100644 deploy/azure/az/servicefabric/LinuxContainers/readme.md delete mode 100644 deploy/azure/az/servicefabric/LinuxContainers/servicefabricdeploy.json delete mode 100644 deploy/azure/az/servicefabric/LinuxContainers/servicefabricdeploy.parameters.json delete mode 100644 deploy/azure/az/servicefabric/LinuxContainers/servicefabricdeploysecured.json delete mode 100644 deploy/azure/az/servicefabric/LinuxContainers/servicefabricdeploysecured.parameters.json delete mode 100644 deploy/azure/az/servicefabric/WindowsContainers/gen-keyvaultcert.ps1 delete mode 100644 deploy/azure/az/servicefabric/WindowsContainers/readme.md delete mode 100644 deploy/azure/az/servicefabric/WindowsContainers/servicefabricdeploy.json delete mode 100644 deploy/azure/az/servicefabric/WindowsContainers/servicefabricdeploy.parameters.json delete mode 100644 deploy/azure/az/servicefabric/WindowsContainers/servicefabricdeploysecured.json delete mode 100644 deploy/azure/az/servicefabric/WindowsContainers/servicefabricdeploysecured.parameters.json delete mode 100644 deploy/azure/az/vms/docker-machine.md delete mode 100644 deploy/azure/az/vms/linux-vm/linuxvm.json delete mode 100644 deploy/azure/az/vms/linux-vm/linuxvm.parameters.json delete mode 100644 deploy/azure/az/vms/plain-vm.md delete mode 100644 deploy/azure/az/vms/readme.md delete mode 100644 deploy/azure/az/vms/win-vm/windowsvm.json delete mode 100644 deploy/azure/az/vms/win-vm/windowsvm.parameters.json delete mode 100644 deploy/k8s/README.CICD.k8s.md delete mode 100644 deploy/k8s/README.k8s.md delete mode 100644 deploy/k8s/build-push-images.ps1 delete mode 100644 deploy/k8s/conf-files.md delete mode 100644 deploy/k8s/conf_cloud.yaml delete mode 100644 deploy/k8s/conf_local.yaml delete mode 100644 deploy/k8s/deploy-ingress-azure.ps1 delete mode 100644 deploy/k8s/deploy-ingress-dockerlocal.ps1 delete mode 100644 deploy/k8s/deploy-ingress.ps1 delete mode 100644 deploy/k8s/deploy-nodeports.ps1 delete mode 100644 deploy/k8s/deploy.ps1 delete mode 100644 deploy/k8s/deploy.sh delete mode 100644 deploy/k8s/img/blob_creation.png delete mode 100644 deploy/k8s/img/deploy_script_task.png delete mode 100644 deploy/k8s/img/get_kubectlbin_task.png delete mode 100644 deploy/k8s/img/get_kubectlconfig_task.png delete mode 100644 deploy/k8s/internalurls.yaml delete mode 100644 deploy/k8s/nginx-ingress/mandatory-istio.yaml delete mode 100644 deploy/k8s/nodeports/rabbitmq-admin.yaml delete mode 100644 deploy/k8s/nodeports/sql-service.yaml delete mode 100644 deploy/k8s/readme.md delete mode 100644 obsolete/cli-linux/build-bits-linux.sh delete mode 100644 obsolete/cli-linux/docker-compose.local.build.yml delete mode 100644 obsolete/cli-linux/prepare-spa-app.sh delete mode 100644 obsolete/cli-linux/run.sh delete mode 100644 obsolete/cli-mac/build-bits.sh delete mode 100644 obsolete/cli-windows/build-bits-simple.ps1 delete mode 100644 obsolete/cli-windows/build-bits.ps1 delete mode 100644 obsolete/cli-windows/build-images.ps1 delete mode 100644 obsolete/cli-windows/delete-images.ps1 delete mode 100644 obsolete/cli-windows/delete-vs-and-eshop-images.ps1 delete mode 100644 obsolete/cli-windows/start-external.ps1 delete mode 100644 obsolete/cli-windows/start-windows-containers.ps1 delete mode 100644 obsolete/cli-windows/vsts/build-bits-no-parallel.ps1 diff --git a/deploy/azure/az/azurefunctions/azurefunctionsdeploy.json b/deploy/azure/az/azurefunctions/azurefunctionsdeploy.json deleted file mode 100644 index 29625302b..000000000 --- a/deploy/azure/az/azurefunctions/azurefunctionsdeploy.json +++ /dev/null @@ -1,209 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "SitesEshopfunctionsName": { - "type": "string", - "metadata": { - "description": "Name of the Azure Functions namespace" - }, - "defaultValue": "mktfunctionsdemo" - } - }, - "variables": { - "SitesEshopfunctionsName": "[parameters('SitesEshopfunctionsName')]", - "WebConfigName": "[concat(variables('SitesEshopfunctionsName'), '/web')]", - "Location": "[resourceGroup().location]", - "ServerFarmPlan": "[concat(trim(variables('location')), 'Plan')]", - "StorageAccounts": "[concat(variables('SitesEshopfunctionsName'), 'st')]" - }, - "resources": [ - { - "type": "Microsoft.Storage/storageAccounts", - "sku": { - "name": "Standard_LRS", - "tier": "Standard" - }, - "kind": "Storage", - "name": "[variables('StorageAccounts')]", - "apiVersion": "2016-01-01", - "location": "[variables('Location')]", - "tags": {}, - "scale": null, - "properties": {}, - "dependsOn": [] - }, - { - "type": "Microsoft.Web/serverfarms", - "sku": { - "name": "Y1", - "tier": "Dynamic", - "size": "Y1", - "family": "Y", - "capacity": 0 - }, - "kind": "functionapp", - "name": "[variables('ServerFarmPlan')]", - "apiVersion": "2015-08-01", - "location": "[variables('Location')]", - "scale": null, - "properties": { - "name": "[variables('ServerFarmPlan')]", - "numberOfWorkers": 0 - }, - "dependsOn": [] - }, - { - "type": "Microsoft.Web/sites", - "kind": "functionapp", - "name": "[variables('SitesEshopfunctionsName')]", - "apiVersion": "2015-08-01", - "location": "[variables('Location')]", - "scale": null, - "properties": { - "name": "[variables('SitesEshopfunctionsName')]", - "hostNames": [ - "[concat(variables('SitesEshopfunctionsName'),'.azurewebsites.net')]" - ], - "enabledHostNames": [ - "[concat(variables('SitesEshopfunctionsName'),'.azurewebsites.net')]", - "[concat(variables('SitesEshopfunctionsName'),'.scm.azurewebsites.net')]" - ], - "hostNameSslStates": [ - { - "name": "[concat(variables('SitesEshopfunctionsName'),'.azurewebsites.net')]", - "sslState": 0, - "thumbprint": null, - "ipBasedSslState": 0 - }, - { - "name": "[concat(variables('SitesEshopfunctionsName'),'.scm.azurewebsites.net')]", - "sslState": 0, - "thumbprint": null, - "ipBasedSslState": 0 - } - ], - "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('ServerFarmPlan'))]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Web/serverfarms', variables('ServerFarmPlan'))]" - ] - }, - { - "type": "Microsoft.Web/sites/config", - "name": "[variables('WebConfigName')]", - "apiVersion": "2015-08-01", - "location": "[variables('Location')]", - "scale": null, - "properties": { - "numberOfWorkers": 1, - "defaultDocuments": [ - "Default.htm", - "Default.html", - "Default.asp", - "index.htm", - "index.html", - "iisstart.htm", - "default.aspx", - "index.php", - "hostingstart.html" - ], - "netFrameworkVersion": "v4.0", - "phpVersion": "5.6", - "pythonVersion": "", - "nodeVersion": "", - "linuxFxVersion": "", - "requestTracingEnabled": false, - "remoteDebuggingEnabled": false, - "remoteDebuggingVersion": null, - "httpLoggingEnabled": false, - "logsDirectorySizeLimit": 35, - "detailedErrorLoggingEnabled": false, - "publishingUsername": "$eshopfunctions", - "publishingPassword": null, - "appSettings": null, - "metadata": null, - "connectionStrings": null, - "machineKey": null, - "handlerMappings": null, - "documentRoot": null, - "scmType": "None", - "use32BitWorkerProcess": true, - "webSocketsEnabled": false, - "alwaysOn": false, - "javaVersion": null, - "javaContainer": null, - "javaContainerVersion": null, - "appCommandLine": "", - "managedPipelineMode": 0, - "virtualApplications": [ - { - "virtualPath": "/", - "physicalPath": "site\\wwwroot", - "preloadEnabled": false, - "virtualDirectories": null - } - ], - "winAuthAdminState": 0, - "winAuthTenantState": 0, - "customAppPoolIdentityAdminState": false, - "customAppPoolIdentityTenantState": false, - "runtimeADUser": null, - "runtimeADUserPassword": null, - "loadBalancing": 1, - "routingRules": [], - "experiments": { - "rampUpRules": [] - }, - "limits": null, - "autoHealEnabled": false, - "autoHealRules": { - "triggers": null, - "actions": null - }, - "tracingOptions": null, - "vnetName": "", - "siteAuthEnabled": false, - "siteAuthSettings": { - "enabled": null, - "unauthenticatedClientAction": null, - "tokenStoreEnabled": null, - "allowedExternalRedirectUrls": null, - "defaultProvider": null, - "clientId": null, - "clientSecret": null, - "issuer": null, - "allowedAudiences": null, - "additionalLoginParams": null, - "isAadAutoProvisioned": false, - "googleClientId": null, - "googleClientSecret": null, - "googleOAuthScopes": null, - "facebookAppId": null, - "facebookAppSecret": null, - "facebookOAuthScopes": null, - "twitterConsumerKey": null, - "twitterConsumerSecret": null, - "microsoftAccountClientId": null, - "microsoftAccountClientSecret": null, - "microsoftAccountOAuthScopes": null - }, - "cors": { - "allowedOrigins": [ - "https://functions.azure.com", - "https://functions-staging.azure.com", - "https://functions-next.azure.com" - ] - }, - "push": null, - "apiDefinition": null, - "autoSwapSlotName": null, - "localMySqlEnabled": false, - "ipSecurityRestrictions": null - }, - "dependsOn": [ - "[resourceId('Microsoft.Web/sites', variables('SitesEshopfunctionsName'))]" - ] - } - ] -} \ No newline at end of file diff --git a/deploy/azure/az/azurefunctions/azurefunctionsdeploy.parameters.json b/deploy/azure/az/azurefunctions/azurefunctionsdeploy.parameters.json deleted file mode 100644 index 9ef07000d..000000000 --- a/deploy/azure/az/azurefunctions/azurefunctionsdeploy.parameters.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "SitesEshopfunctionsName": { - "value": "eshopfunctionsapp" - } - } -} \ No newline at end of file diff --git a/deploy/azure/az/azurefunctions/readme.md b/deploy/azure/az/azurefunctions/readme.md deleted file mode 100644 index 6ce3630b2..000000000 --- a/deploy/azure/az/azurefunctions/readme.md +++ /dev/null @@ -1,39 +0,0 @@ -# Deploying Azure Functions - -The ARM template `azurefunctionsdeploy.json` and its parameter file (`azurefunctionsdeploy.parameters.json`) are used to deploy Marketing azure functions. - -## Editing azurefunctionsdeploy.parameters.json file - -You can edit the `azurefunctionsdeploy.parameters.parameters.json` file to set your values, but is not needed. The only parameter that can be set is: - -1. `SitesEshopfunctionsName` is a string that is used to create the Azure function app name. - -## Deploy the template - -Once parameter file is edited you can deploy it using [create-resources script](../readme.md). - -i. e. if you are in Windows, to deploy the Azure Functions environment in a new resourcegroup located in westus, go to `deploy\az` folder and type: - -``` -create-resources.cmd azurefunctions\azurefunctionsdeploy newResourceGroup -c westus -``` -## Deploy Marketing azure function with Visual Studio. - -You need to deploy the Marketing azure function from Visual Studio 2017 15.3 from the the Marketing-functions project in the solution eShopOnContainers-AzureFunctions.sln (Visual Studio publish tool). - -## Setting Azure function configurations - -Once deployed, go to azure portal and set the connection string for the azure function under the name "SqlConnection". The value must be the connection string which points to MarketingDB. - -Example: - -"SqlConnection": "Server=tcp:eshopsql.database.windows.net,1433;Initial Catalog=marketingdb;" - -In appsettings section, add a new entry named "MarketingStorageUri". The value must be the uri of the blob storage where the campaign images are stored. - -Example: - -"MarketingStorageUri": "https://marketingcampaign.blob.core.windows.net/pics/" - - - diff --git a/deploy/azure/az/servicefabric/LinuxContainers/gen-keyvaultcert.ps1 b/deploy/azure/az/servicefabric/LinuxContainers/gen-keyvaultcert.ps1 deleted file mode 100644 index c6fc34013..000000000 --- a/deploy/azure/az/servicefabric/LinuxContainers/gen-keyvaultcert.ps1 +++ /dev/null @@ -1,53 +0,0 @@ -Param( - [parameter(Mandatory=$true)][string]$vaultName, - [parameter(Mandatory=$true)][string]$certName, - [parameter(Mandatory=$true)][string]$certPwd, - [parameter(Mandatory=$true)][string]$subjectName, - [parameter(Mandatory=$false)][string]$ValidityInMonths=12, - [parameter(Mandatory=$true)][string]$saveDir -) - - -#Log in Azure Account -Login-AzureRmAccount - - -# Create Cert in KeyVault -Write-Host "Creating certificate in Azure KeyVault..." -ForegroundColor Yellow -$policy = New-AzureKeyVaultCertificatePolicy -SubjectName $subjectName -IssuerName Self -ValidityInMonths $ValidityInMonths -Add-AzureKeyVaultCertificate -VaultName $vaultName -Name $certName -CertificatePolicy $policy - -# Downloading Certificate -Write-Host "Downloading Certificate from KeyVault..." -ForegroundColor Yellow - -$Stoploop = $false -$Retrycount = 0 - -do { - try { - - $kvSecret = Get-AzureKeyVaultSecret -VaultName $vaultName -Name $certName -ErrorAction SilentlyContinue - $kvSecretBytes = [System.Convert]::FromBase64String($kvSecret.SecretValueText) - $certCollection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection - $certCollection.Import($kvSecretBytes,$null,[System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable) - $protectedCertificateBytes = $certCollection.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12, $certPwd) - [System.IO.File]::WriteAllBytes($saveDir + "\" + $certName + ".pfx", $protectedCertificateBytes) - - $Stoploop = $true - Write-Host "Finished!" -ForegroundColor Yellow - } - catch { - if ($Retrycount -gt 5){ - $Stoploop = $true - Write-Host "Not possible to retrieve the certificate!" -ForegroundColor Yellow - } - else { - Start-Sleep -Seconds 20 - $Retrycount = $Retrycount + 1 - } - } -} -While ($Stoploop -eq $false) - -# Show Certificate Values -Get-AzureKeyVaultCertificate -VaultName $vaultName -Name $certName \ No newline at end of file diff --git a/deploy/azure/az/servicefabric/LinuxContainers/readme.md b/deploy/azure/az/servicefabric/LinuxContainers/readme.md deleted file mode 100644 index 98d097b10..000000000 --- a/deploy/azure/az/servicefabric/LinuxContainers/readme.md +++ /dev/null @@ -1,134 +0,0 @@ -# Deploying a Service Fabric cluster based on Linux nodes - -## A. Unsecured cluster (SF Linux cluster) -For a secured cluster, see option B. below. - -You can always deploy a SF cluster through the Azure portal, as explained in this article: https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-get-started-azure-cluster - -However, when creating a cluster, there are quite a few configurations to take into account, like enabling the internal DNS service or Reverse Proxy service, choosing between Linux/Windows, open/publish your application ports in the load-balancer and most of all (the most complex setup) how to create a secure cluster. - -Because of those reasons, we have created a set of ARM templates and scripts so you can create, re-create and configure the SF clusters much faster, as explained below: - -Within eShopOnContainers root folder, at the folder [..\deploy\az\servicefabric\LinuxContainers](https://github.com/dotnet-architecture/eShopOnContainers/tree/dev/deploy/az/servicefabric/LinuxContainers), you can find the ARM template `servicefabricdeploy.json` and its parameters file (`servicefabricdeploy.parameters.json`) to create a Service Fabric cluster environment for Linux Containers. - -## Edit the servicefabricdeploy.parameters.json file - -Edit the following params in `servicefabricdeploy.parameters.json` file to set your values: - -- clusterName: Name of your SF cluster -- clusterLocation: Datacenter location, like westus or westeurope -- computeLocation: Datacenter location, like westus or westeurope -- adminUserName: user-name for VMs administration -- adminPassword: user-password for VMs administration -- dnsName: Name assigned to your SF dns - -Optionally, you could modify which ports are opened in the LoadBalancer for the multiple eShopOnContainer apps and API services. -By default, they are setup as: -- webMvcHttpPort: 5100 -- webSpaHttpPort: 5104 -- webStatusHttpPort: 5107 -- IdSrvHttpRule: 5105 -- BasketApiHttpRule: 5103 -- CatalogApiHttpRule: 5101 -- OrderingApiHttpRule: 5102 -- MarketingApiHttpRule: 5110 -- LocationsApiHttpRule: 5109 - -## Deploy the Service Fabric cluster using the script and ARM templates - -Once parameter file is edited you can deploy it using [create-resources script](../readme.md). - -For example, to deploy the cluster to a new resourcegroup located in westus, go to `deploy\az` folder and type: - -``` -create-resources.cmd servicefabric\LinuxContainers\servicefabricdeploy qa-eshop-sflinux-resgrp -c westus -``` - -You should see a similar execution to the following: -![image](https://user-images.githubusercontent.com/1712635/31638180-15da9f84-b287-11e7-9d4e-604f33690198.png) - -Now, if you go to your subscription in Azure, you should be able to see the SF cluster already created and available, like in the following image: - -![image](https://user-images.githubusercontent.com/1712635/31638398-3fc08ad8-b288-11e7-879b-fc4df0daad2b.png) - -In this case, this is an unsecured SF cluster with a single Linux node, good for initial tests and getting started with SF. - -## B. Secured cluster (SF Linux cluster) - -Within eShopOnContainers root folder, at the folder [..\deploy\az\servicefabric\LinuxContainers](https://github.com/dotnet-architecture/eShopOnContainers/tree/dev/deploy/az/servicefabric/LinuxContainers), you can find the ARM template `servicefabricdeploysecured.json` and its parameter file (`servicefabricdeploysecured.parameters.json`) to create a secured Service Fabric cluster environment for Linux Containers (IN THIS CASE, IT IS A SECURED CLUSTER USING A CERTIFICATE). - -The ARM template `servicefabricdeploysecured.json` and its parameter file (`servicefabricdeploysecured.parameters.json`) are used to create a service fabric cluster environment for linux containers secured with a certificate. - -## Create Azure Keyvault service -Go to PortalAzure and create a Keyvault service. Make sure Enable access for deployment checkboxes are selected. - -![image](https://user-images.githubusercontent.com/1712635/31638848-9b266530-b28a-11e7-953b-1e3ec1a54f77.png) - -## Generate a certificate in Azure Keyvault -In a POWER-SHELL window, move to the folder [..\deploy\az\servicefabric\LinuxContainers](https://github.com/dotnet-architecture/eShopOnContainers/tree/dev/deploy/az/servicefabric/LinuxContainers). - -**Select your Azure subscription** You might have [several Azure subscriptions](https://docs.microsoft.com/en-us/cli/azure/account#set) as shown if you type the following. - - >``` - >az account list - >``` - If you have multiple subscription accounts, you first need to select the Azure subscription account you want to target. Type the following: - >``` - >az account set --subscription "Your Azure Subscription Name or ID" - >``` - -Execute the gen-keyvaultcert.ps1 script to generate and download a certificate from Keyvault. - -``` -.\gen-keyvaultcert.ps1 -vaultName -certName -certPwd -subjectName CN=.westeurope.cloudapp.azure.com -saveDir C:\Users\\Downloads - -``` - -You should see a similar execution to the following: -![image](https://user-images.githubusercontent.com/1712635/31640172-93efcca0-b291-11e7-970e-5b5e6bf07042.png) - -IMPORTANT: At this point, copy/cut the .PFX certificate file saved in the downloads forlder and save it in a secure place. - -## Install the certificate -Install the certificate (by double-clicking on the .PFX file) under 'Current User' store location (by default location) and check it as exportable. - - - -Also, install the same certificate as CA (Certificate Authority) under Current User, too. - -![image](https://user-images.githubusercontent.com/1712635/31642795-c6ffa434-b2a1-11e7-8ff8-2a63549a780e.png) - -## Editing servicefabricdeploysecured.parameters.json file - -Edit the parameters in `servicefabricdeploysecured.parameters.json` in a similar way you can do with the unsecured .json file shown above (clusterName, dnsName, etc.), plus edit the following values: - -- sourceVaultValue: Your Azure Keyvault's RESOURCE ID (check Azure keyvault properties, similar to: /subscriptions/e1234ac1-c09c-3jaf-6767-98b3c5f1f246/resourceGroups/eshop-global-resgrp/providers/Microsoft.KeyVault/vaults/eshopkeyvault") - -- certificateUrlValue: Your certificate Secret Identifier (check Azure Keyvault secret certificate properties, should be in the format of https://.vault.azure.net:443/secrets/, similar to: -https://eshopkeyvault.vault.azure.net/secrets/pro-eshop-sflinux-cluster-cert/fd47684442c04cdj83b3hfe4h8e08123) - -- certificateThumbprint: certificate thumbprint (check azure Keyvault certificate thumbprint, something like 69JK453486D55A6818577Z0699100365HDK70FCE) - -## Deploy the secured SF Linux cluster - -Once parameters file is edited you can deploy it using [create-resources script](../readme.md). -Use a command prompt window positioned into the deploy\az folder. - -``` -create-resources.cmd servicefabric\LinuxContainers\servicefabricdeploysecured pro-eshop-sflinux-resgrp -c westus -``` -The execution should be something like the following: -![image](https://user-images.githubusercontent.com/1712635/31642529-54479704-b2a0-11e7-90ee-2abf32c92205.png) - -Once the cluster is created you can explore it with Azure's portal, like in the following image: - -![image](https://user-images.githubusercontent.com/1712635/31642956-b7cfc8d0-b2a2-11e7-8ede-a141ec190eb4.png) - -## Deploy eShopOnServiceFabric with Visual Studio. - -Modify the cloud.xml file of each Service Fabric application in PublishProfile directory and set your certificate settings to be able to deploy eshopOnContainers in the secured cluster: - - - - - diff --git a/deploy/azure/az/servicefabric/LinuxContainers/servicefabricdeploy.json b/deploy/azure/az/servicefabric/LinuxContainers/servicefabricdeploy.json deleted file mode 100644 index fb28174db..000000000 --- a/deploy/azure/az/servicefabric/LinuxContainers/servicefabricdeploy.json +++ /dev/null @@ -1,751 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "clusterLocation": { - "type": "string", - "metadata": { - "description": "Location of the Cluster" - } - }, - "clusterName": { - "type": "string", - "defaultValue": "Cluster", - "metadata": { - "description": "Name of your cluster - Between 3 and 23 characters. Letters and numbers only" - } - }, - "nt0applicationStartPort": { - "type": "int", - "defaultValue": 20000 - }, - "nt0applicationEndPort": { - "type": "int", - "defaultValue": 30000 - }, - "nt0ephemeralStartPort": { - "type": "int", - "defaultValue": 49152 - }, - "nt0ephemeralEndPort": { - "type": "int", - "defaultValue": 65534 - }, - "nt0fabricTcpGatewayPort": { - "type": "int", - "defaultValue": 19000 - }, - "nt0fabricHttpGatewayPort": { - "type": "int", - "defaultValue": 19080 - }, - "webMvcHttpPort": { - "type": "int", - "defaultValue": 5100 - }, - "webSpaHttpPort": { - "type": "int", - "defaultValue": 5104 - }, - "webStatusHttpPort": { - "type": "int", - "defaultValue": 5107 - }, - "IdSrvHttpRule": { - "type": "int", - "defaultValue": 5105 - }, - "BasketApiHttpRule": { - "type": "int", - "defaultValue": 5103 - }, - "CatalogApiHttpRule": { - "type": "int", - "defaultValue": 5101 - }, - "OrderingApiHttpRule": { - "type": "int", - "defaultValue": 5102 - }, - "MarketingApiHttpRule": { - "type": "int", - "defaultValue": 5110 - }, - "LocationsApiHttpRule": { - "type": "int", - "defaultValue": 5109 - }, - "subnet0Name": { - "type": "string", - "defaultValue": "Subnet-0" - }, - "subnet0Prefix": { - "type": "string", - "defaultValue": "10.0.0.0/24" - }, - "computeLocation": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string", - "defaultValue": "PublicIP-VM" - }, - "publicIPAddressType": { - "type": "string", - "allowedValues": [ - "Dynamic" - ], - "defaultValue": "Dynamic" - }, - "vmStorageAccountContainerName": { - "type": "string", - "defaultValue": "vhds" - }, - "adminUserName": { - "type": "string", - "defaultValue": "testadm", - "metadata": { - "description": "Remote desktop user Id" - } - }, - "adminPassword": { - "type": "securestring", - "metadata": { - "description": "Remote desktop user password. Must be a strong password" - } - }, - "virtualNetworkName": { - "type": "string", - "defaultValue": "VNet" - }, - "addressPrefix": { - "type": "string", - "defaultValue": "10.0.0.0/16" - }, - "dnsName": { - "type": "string" - }, - "nicName": { - "type": "string", - "defaultValue": "NIC" - }, - "lbName": { - "type": "string", - "defaultValue": "LoadBalancer" - }, - "lbIPName": { - "type": "string", - "defaultValue": "PublicIP-LB-FE" - }, - "overProvision": { - "type": "string", - "defaultValue": "false" - }, - "vmImagePublisher": { - "type": "string", - "defaultValue": "Microsoft.Azure.ServiceFabric" - }, - "vmImageOffer": { - "type": "string", - "defaultValue": "UbuntuServer" - }, - "vmImageSku": { - "type": "string", - "defaultValue": "16.04" - }, - "vmImageVersion": { - "type": "string", - "defaultValue": "6.0.12" - }, - "storageAccountType": { - "type": "string", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS" - ], - "defaultValue": "Standard_LRS", - "metadata": { - "description": "Replication option for the VM image storage account" - } - }, - "supportLogStorageAccountType": { - "type": "string", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS" - ], - "defaultValue": "Standard_LRS", - "metadata": { - "description": "Replication option for the support log storage account" - } - }, - "supportLogStorageAccountName": { - "type": "string", - "defaultValue": "[toLower( concat('sflogs', uniqueString(resourceGroup().id),'2'))]", - "metadata": { - "description": "Name for the storage account that contains support logs from the cluster" - } - }, - "applicationDiagnosticsStorageAccountType": { - "type": "string", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS" - ], - "defaultValue": "Standard_LRS", - "metadata": { - "description": "Replication option for the application diagnostics storage account" - } - }, - "applicationDiagnosticsStorageAccountName": { - "type": "string", - "defaultValue": "[toLower(concat(uniqueString(resourceGroup().id), '3' ))]", - "metadata": { - "description": "Name for the storage account that contains application diagnostics data from the cluster" - } - }, - "nt0InstanceCount": { - "type": "int", - "defaultValue": 1, - "metadata": { - "description": "Instance count for node type" - } - }, - "vmNodeType0Name": { - "type": "string", - "defaultValue": "primary", - "maxLength": 9 - }, - "vmNodeType0Size": { - "type": "string", - "defaultValue": "Standard_D1_v2" - } - }, - "variables": { - "vmssApiVersion": "2017-03-30", - "lbApiVersion": "2015-06-15", - "vNetApiVersion": "2015-06-15", - "storageApiVersion": "2016-01-01", - "publicIPApiVersion": "2015-06-15", - "vnetID": "[resourceId('Microsoft.Network/virtualNetworks',parameters('virtualNetworkName'))]", - "subnet0Ref": "[concat(variables('vnetID'),'/subnets/',parameters('subnet0Name'))]", - "wadlogs": "", - "wadperfcounters1": "", - "wadperfcounters2": "", - "wadcfgxstart": "[concat(variables('wadlogs'),variables('wadperfcounters1'),variables('wadperfcounters2'),'')]", - "lbID0": "[resourceId('Microsoft.Network/loadBalancers', concat('LB','-', parameters('clusterName'),'-',parameters('vmNodeType0Name')))]", - "lbIPConfig0": "[concat(variables('lbID0'),'/frontendIPConfigurations/LoadBalancerIPConfig')]", - "lbPoolID0": "[concat(variables('lbID0'),'/backendAddressPools/LoadBalancerBEAddressPool')]", - "lbProbeID0": "[concat(variables('lbID0'),'/probes/FabricGatewayProbe')]", - "lbHttpProbeID0": "[concat(variables('lbID0'),'/probes/FabricHttpGatewayProbe')]", - "lbNatPoolID0": "[concat(variables('lbID0'),'/inboundNatPools/LoadBalancerBEAddressNatPool')]", - "vmStorageAccountName0": "[toLower(concat(uniqueString(resourceGroup().id), '1', '0' ))]", - "wadmetricsresourceid0": "[concat('/subscriptions/',subscription().subscriptionId,'/resourceGroups/',resourceGroup().name ,'/providers/','Microsoft.Compute/virtualMachineScaleSets/', parameters('vmNodeType0Name'))]" - }, - "resources": [ - { - "apiVersion": "[variables('storageApiVersion')]", - "type": "Microsoft.Storage/storageAccounts", - "name": "[parameters('supportLogStorageAccountName')]", - "location": "[parameters('computeLocation')]", - "dependsOn": [], - "properties": {}, - "kind": "Storage", - "sku": { - "name": "[parameters('supportLogStorageAccountType')]" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "[variables('storageApiVersion')]", - "type": "Microsoft.Storage/storageAccounts", - "name": "[parameters('applicationDiagnosticsStorageAccountName')]", - "location": "[parameters('computeLocation')]", - "dependsOn": [], - "properties": {}, - "kind": "Storage", - "sku": { - "name": "[parameters('applicationDiagnosticsStorageAccountType')]" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "[variables('vNetApiVersion')]", - "type": "Microsoft.Network/virtualNetworks", - "name": "[parameters('virtualNetworkName')]", - "location": "[parameters('computeLocation')]", - "dependsOn": [], - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[parameters('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[parameters('subnet0Name')]", - "properties": { - "addressPrefix": "[parameters('subnet0Prefix')]" - } - } - ] - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "[variables('publicIPApiVersion')]", - "type": "Microsoft.Network/publicIPAddresses", - "name": "[concat(parameters('lbIPName'),'-','0')]", - "location": "[parameters('computeLocation')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsName')]" - }, - "publicIPAllocationMethod": "Dynamic" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "[variables('lbApiVersion')]", - "type": "Microsoft.Network/loadBalancers", - "name": "[concat('LB','-', parameters('clusterName'),'-',parameters('vmNodeType0Name'))]", - "location": "[parameters('computeLocation')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/',concat(parameters('lbIPName'),'-','0'))]" - ], - "properties": { - "frontendIPConfigurations": [ - { - "name": "LoadBalancerIPConfig", - "properties": { - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses',concat(parameters('lbIPName'),'-','0'))]" - } - } - } - ], - "backendAddressPools": [ - { - "name": "LoadBalancerBEAddressPool", - "properties": {} - } - ], - "loadBalancingRules": [ - { - "name": "LBRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('nt0fabricTcpGatewayPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('nt0fabricTcpGatewayPort')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "LBHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('nt0fabricHttpGatewayPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('nt0fabricHttpGatewayPort')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbHttpProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "WebMVCHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('webMvcHttpPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('webMvcHttpPort')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "WebSPAHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('webSpaHttpPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('webSpaHttpPort')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "WebStatusHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('webStatusHttpPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('webStatusHttpPort')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "IdSrvHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('IdSrvHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('IdSrvHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "BasketApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('BasketApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('BasketApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "CatalogApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('CatalogApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('CatalogApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "OrderingApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('OrderingApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('OrderingApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "MarketingApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('MarketingApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('MarketingApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "LocationsApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('LocationsApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('LocationsApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - } - ], - "probes": [ - { - "name": "FabricGatewayProbe", - "properties": { - "intervalInSeconds": 5, - "numberOfProbes": 2, - "port": "[parameters('nt0fabricTcpGatewayPort')]", - "protocol": "tcp" - } - }, - { - "name": "FabricHttpGatewayProbe", - "properties": { - "intervalInSeconds": 5, - "numberOfProbes": 2, - "port": "[parameters('nt0fabricHttpGatewayPort')]", - "protocol": "tcp" - } - } - ], - "inboundNatPools": [ - { - "name": "LoadBalancerBEAddressNatPool", - "properties": { - "backendPort": "22", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPortRangeEnd": "4500", - "frontendPortRangeStart": "3389", - "protocol": "tcp" - } - } - ] - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "[variables('vmssApiVersion')]", - "type": "Microsoft.Compute/virtualMachineScaleSets", - "name": "[parameters('vmNodeType0Name')]", - "location": "[parameters('computeLocation')]", - "dependsOn": [ - "[concat('Microsoft.Network/virtualNetworks/', parameters('virtualNetworkName'))]", - "[concat('Microsoft.Network/loadBalancers/', concat('LB','-', parameters('clusterName'),'-',parameters('vmNodeType0Name')))]", - "[concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName'))]", - "[concat('Microsoft.Storage/storageAccounts/', parameters('applicationDiagnosticsStorageAccountName'))]" - ], - "properties": { - "overprovision": "[parameters('overProvision')]", - "upgradePolicy": { - "mode": "Automatic" - }, - "virtualMachineProfile": { - "extensionProfile": { - "extensions": [ - { - "name": "[concat(parameters('vmNodeType0Name'),'_ServiceFabricLinuxNode')]", - "properties": { - "type": "ServiceFabricLinuxNode", - "autoUpgradeMinorVersion": true, - "protectedSettings": { - "StorageAccountKey1": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('supportLogStorageAccountName')),'2015-05-01-preview').key1]", - "StorageAccountKey2": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('supportLogStorageAccountName')),'2015-05-01-preview').key2]" - }, - "publisher": "Microsoft.Azure.ServiceFabric", - "settings": { - "clusterEndpoint": "[reference(parameters('clusterName')).clusterEndpoint]", - "nodeTypeRef": "[parameters('vmNodeType0Name')]", - "durabilityLevel": "Bronze", - "enableParallelJobs": true, - "nicPrefixOverride": "[parameters('subnet0Prefix')]" - }, - "typeHandlerVersion": "1.0" - } - }, - { - "name": "[concat('VMDiagnosticsVmExt','_vmNodeType0Name')]", - "properties": { - "type": "LinuxDiagnostic", - "autoUpgradeMinorVersion": true, - "protectedSettings": { - "storageAccountName": "[parameters('applicationDiagnosticsStorageAccountName')]", - "storageAccountKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('applicationDiagnosticsStorageAccountName')),'2015-05-01-preview').key1]", - "storageAccountEndPoint": "https://core.windows.net/" - }, - "publisher": "Microsoft.OSTCExtensions", - "settings": { - "xmlCfg": "[base64(concat(variables('wadcfgxstart'),variables('wadmetricsresourceid0'),variables('wadcfgxend')))]", - "StorageAccount": "[parameters('applicationDiagnosticsStorageAccountName')]" - }, - "typeHandlerVersion": "2.3" - } - } - ] - }, - "networkProfile": { - "networkInterfaceConfigurations": [ - { - "name": "[concat(parameters('nicName'), '-0')]", - "properties": { - "ipConfigurations": [ - { - "name": "[concat(parameters('nicName'),'-',0)]", - "properties": { - "loadBalancerBackendAddressPools": [ - { - "id": "[variables('lbPoolID0')]" - } - ], - "loadBalancerInboundNatPools": [ - { - "id": "[variables('lbNatPoolID0')]" - } - ], - "subnet": { - "id": "[variables('subnet0Ref')]" - } - } - } - ], - "primary": true - } - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computernamePrefix": "[parameters('vmNodeType0Name')]" - }, - "storageProfile": { - "imageReference": { - "publisher": "[parameters('vmImagePublisher')]", - "offer": "[parameters('vmImageOffer')]", - "sku": "[parameters('vmImageSku')]", - "version": "[parameters('vmImageVersion')]" - }, - "osDisk": { - "caching": "ReadOnly", - "createOption": "FromImage", - "managedDisk": { - "storageAccountType": "[parameters('storageAccountType')]" - } - } - } - } - }, - "sku": { - "name": "[parameters('vmNodeType0Size')]", - "capacity": "[parameters('nt0InstanceCount')]", - "tier": "Standard" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "2017-07-01-preview", - "type": "Microsoft.ServiceFabric/clusters", - "name": "[parameters('clusterName')]", - "location": "[parameters('clusterLocation')]", - "dependsOn": [ - "[concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName'))]" - ], - "properties": { - "addonFeatures": [ - "DnsService" - ], - "clientCertificateCommonNames": [], - "clientCertificateThumbprints": [], - "clusterCodeVersion": "6.0.120.1", - "clusterState": "Default", - "diagnosticsStorageAccountConfig": { - "blobEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.blob]", - "protectedAccountKeyName": "StorageAccountKey1", - "queueEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.queue]", - "storageAccountName": "[parameters('supportLogStorageAccountName')]", - "tableEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.table]" - }, - "fabricSettings": [], - "managementEndpoint": "[concat('http://',reference(concat(parameters('lbIPName'),'-','0')).dnsSettings.fqdn,':',parameters('nt0fabricHttpGatewayPort'))]", - "nodeTypes": [ - { - "name": "[parameters('vmNodeType0Name')]", - "applicationPorts": { - "endPort": "[parameters('nt0applicationEndPort')]", - "startPort": "[parameters('nt0applicationStartPort')]" - }, - "clientConnectionEndpointPort": "[parameters('nt0fabricTcpGatewayPort')]", - "durabilityLevel": "Bronze", - "ephemeralPorts": { - "endPort": "[parameters('nt0ephemeralEndPort')]", - "startPort": "[parameters('nt0ephemeralStartPort')]" - }, - "httpGatewayEndpointPort": "[parameters('nt0fabricHttpGatewayPort')]", - "isPrimary": true, - "vmInstanceCount": "[parameters('nt0InstanceCount')]" - } - ], - "provisioningState": "Default", - "reliabilityLevel": "None", - "upgradeMode": "Manual", - "vmImage": "Linux" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - } - ], - "outputs": { - "clusterProperties": { - "value": "[reference(parameters('clusterName'))]", - "type": "object" - } - } -} \ No newline at end of file diff --git a/deploy/azure/az/servicefabric/LinuxContainers/servicefabricdeploy.parameters.json b/deploy/azure/az/servicefabric/LinuxContainers/servicefabricdeploy.parameters.json deleted file mode 100644 index 0e37d24ec..000000000 --- a/deploy/azure/az/servicefabric/LinuxContainers/servicefabricdeploy.parameters.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "clusterName": { - "value": "qa-eshop-sflinux-cluster" - }, - "clusterLocation": { - "value": "westus" - }, - "computeLocation": { - "value": "westus" - }, - "adminUserName": { - "value": "eshop" - }, - "adminPassword": { - "value": "Your_complex_Pass@word1" - }, - "nicName": { - "value": "NIC-eshoponsflin" - }, - "publicIPAddressName": { - "value": "eshoponsflin-PubIP" - }, - "dnsName": { - "value": "qa-eshop-sflinux-cluster" - }, - "virtualNetworkName": { - "value": "VNet-eshoponsflin" - }, - "lbName": { - "value": "LB-eshoponsflin" - }, - "lbIPName": { - "value": "LBIP-eshoponsflin" - }, - "vmImageSku": { - "value": "16.04-LTS" - }, - "vmImageVersion": { - "value": "latest" - }, - "vmImagePublisher": { - "value": "Canonical" - }, - "nt0ephemeralStartPort": { - "value": 49152 - }, - "nt0ephemeralEndPort": { - "value": 65534 - }, - "nt0applicationStartPort": { - "value": 20000 - }, - "nt0applicationEndPort": { - "value": 30000 - }, - "nt0fabricTcpGatewayPort": { - "value": 19000 - }, - "nt0fabricHttpGatewayPort": { - "value": 19080 - }, - "webMvcHttpPort": { - "value": 5100 - }, - "webSpaHttpPort": { - "value": 5104 - }, - "webStatusHttpPort": { - "value": 5107 - }, - "IdSrvHttpRule": { - "value": 5105 - }, - "BasketApiHttpRule": { - "value": 5103 - }, - "CatalogApiHttpRule": { - "value": 5101 - }, - "OrderingApiHttpRule": { - "value": 5102 - }, - "MarketingApiHttpRule": { - "value": 5110 - }, - "LocationsApiHttpRule": { - "value": 5109 - } - } -} \ No newline at end of file diff --git a/deploy/azure/az/servicefabric/LinuxContainers/servicefabricdeploysecured.json b/deploy/azure/az/servicefabric/LinuxContainers/servicefabricdeploysecured.json deleted file mode 100644 index 0d6620f32..000000000 --- a/deploy/azure/az/servicefabric/LinuxContainers/servicefabricdeploysecured.json +++ /dev/null @@ -1,821 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "clusterLocation": { - "type": "string", - "metadata": { - "description": "Location of the Cluster" - } - }, - "clusterName": { - "type": "string", - "defaultValue": "Cluster", - "metadata": { - "description": "Name of your cluster - Between 3 and 23 characters. Letters and numbers only" - } - }, - "nt0applicationStartPort": { - "type": "int", - "defaultValue": 20000 - }, - "nt0applicationEndPort": { - "type": "int", - "defaultValue": 30000 - }, - "nt0ephemeralStartPort": { - "type": "int", - "defaultValue": 49152 - }, - "nt0ephemeralEndPort": { - "type": "int", - "defaultValue": 65534 - }, - "nt0fabricTcpGatewayPort": { - "type": "int", - "defaultValue": 19000 - }, - "nt0fabricHttpGatewayPort": { - "type": "int", - "defaultValue": 19080 - }, - "webMvcHttpPort": { - "type": "int", - "defaultValue": 5100 - }, - "webSpaHttpPort": { - "type": "int", - "defaultValue": 5104 - }, - "webStatusHttpPort": { - "type": "int", - "defaultValue": 5107 - }, - "IdSrvHttpRule": { - "type": "int", - "defaultValue": 5105 - }, - "BasketApiHttpRule": { - "type": "int", - "defaultValue": 5103 - }, - "CatalogApiHttpRule": { - "type": "int", - "defaultValue": 5101 - }, - "OrderingApiHttpRule": { - "type": "int", - "defaultValue": 5102 - }, - "MarketingApiHttpRule": { - "type": "int", - "defaultValue": 5110 - }, - "LocationsApiHttpRule": { - "type": "int", - "defaultValue": 5109 - }, - "subnet0Name": { - "type": "string", - "defaultValue": "Subnet-0" - }, - "subnet0Prefix": { - "type": "string", - "defaultValue": "10.0.0.0/24" - }, - "computeLocation": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string", - "defaultValue": "PublicIP-VM" - }, - "publicIPAddressType": { - "type": "string", - "allowedValues": [ - "Dynamic" - ], - "defaultValue": "Dynamic" - }, - "vmStorageAccountContainerName": { - "type": "string", - "defaultValue": "vhds" - }, - "adminUserName": { - "type": "string", - "defaultValue": "testadm", - "metadata": { - "description": "Remote desktop user Id" - } - }, - "adminPassword": { - "type": "securestring", - "metadata": { - "description": "Remote desktop user password. Must be a strong password" - } - }, - "virtualNetworkName": { - "type": "string", - "defaultValue": "VNet" - }, - "addressPrefix": { - "type": "string", - "defaultValue": "10.0.0.0/16" - }, - "dnsName": { - "type": "string" - }, - "nicName": { - "type": "string", - "defaultValue": "NIC" - }, - "lbName": { - "type": "string", - "defaultValue": "LoadBalancer" - }, - "lbIPName": { - "type": "string", - "defaultValue": "PublicIP-LB-FE" - }, - "overProvision": { - "type": "string", - "defaultValue": "false" - }, - "vmImagePublisher": { - "type": "string", - "defaultValue": "Microsoft.Azure.ServiceFabric" - }, - "vmImageOffer": { - "type": "string", - "defaultValue": "UbuntuServer" - }, - "vmImageSku": { - "type": "string", - "defaultValue": "16.04" - }, - "vmImageVersion": { - "type": "string", - "defaultValue": "6.0.12" - }, - "clusterProtectionLevel": { - "type": "string", - "allowedValues": [ - "None", - "Sign", - "EncryptAndSign" - ], - "defaultValue": "EncryptAndSign", - "metadata": { - "description": "Protection level.Three values are allowed - EncryptAndSign, Sign, None. It is best to keep the default of EncryptAndSign, unless you have a need not to" - } - }, - "certificateStoreValue": { - "type": "string", - "allowedValues": [ - "My" - ], - "defaultValue": "My", - "metadata": { - "description": "The store name where the cert will be deployed in the virtual machine" - } - }, - "certificateThumbprint": { - "type": "string", - "metadata": { - "description": "Certificate Thumbprint" - } - }, - "sourceVaultValue": { - "type": "string", - "metadata": { - "description": "Resource Id of the key vault, is should be in the format of /subscriptions//resourceGroups//providers/Microsoft.KeyVault/vaults/" - } - }, - "certificateUrlValue": { - "type": "string", - "metadata": { - "description": "Refers to the location URL in your key vault where the certificate was uploaded, it is should be in the format of https://.vault.azure.net:443/secrets/" - } - }, - "storageAccountType": { - "type": "string", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS" - ], - "defaultValue": "Standard_LRS", - "metadata": { - "description": "Replication option for the VM image storage account" - } - }, - "supportLogStorageAccountType": { - "type": "string", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS" - ], - "defaultValue": "Standard_LRS", - "metadata": { - "description": "Replication option for the support log storage account" - } - }, - "supportLogStorageAccountName": { - "type": "string", - "defaultValue": "[toLower( concat('sflogs', uniqueString(resourceGroup().id),'2'))]", - "metadata": { - "description": "Name for the storage account that contains support logs from the cluster" - } - }, - "applicationDiagnosticsStorageAccountType": { - "type": "string", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS" - ], - "defaultValue": "Standard_LRS", - "metadata": { - "description": "Replication option for the application diagnostics storage account" - } - }, - "applicationDiagnosticsStorageAccountName": { - "type": "string", - "defaultValue": "[toLower(concat(uniqueString(resourceGroup().id), '3' ))]", - "metadata": { - "description": "Name for the storage account that contains application diagnostics data from the cluster" - } - }, - "nt0InstanceCount": { - "type": "int", - "defaultValue": 5, - "metadata": { - "description": "Instance count for node type" - } - }, - "vmNodeType0Name": { - "type": "string", - "defaultValue": "primary", - "maxLength": 9 - }, - "vmNodeType0Size": { - "type": "string", - "defaultValue": "Standard_D1_v2" - } - }, - "variables": { - "vmssApiVersion": "2017-03-30", - "lbApiVersion": "2015-06-15", - "vNetApiVersion": "2015-06-15", - "storageApiVersion": "2016-01-01", - "publicIPApiVersion": "2015-06-15", - "vnetID": "[resourceId('Microsoft.Network/virtualNetworks',parameters('virtualNetworkName'))]", - "subnet0Ref": "[concat(variables('vnetID'),'/subnets/',parameters('subnet0Name'))]", - "wadlogs": "", - "wadperfcounters1": "", - "wadperfcounters2": "", - "wadcfgxstart": "[concat(variables('wadlogs'),variables('wadperfcounters1'),variables('wadperfcounters2'),'')]", - "lbID0": "[resourceId('Microsoft.Network/loadBalancers', concat('LB','-', parameters('clusterName'),'-',parameters('vmNodeType0Name')))]", - "lbIPConfig0": "[concat(variables('lbID0'),'/frontendIPConfigurations/LoadBalancerIPConfig')]", - "lbPoolID0": "[concat(variables('lbID0'),'/backendAddressPools/LoadBalancerBEAddressPool')]", - "lbProbeID0": "[concat(variables('lbID0'),'/probes/FabricGatewayProbe')]", - "lbHttpProbeID0": "[concat(variables('lbID0'),'/probes/FabricHttpGatewayProbe')]", - "lbNatPoolID0": "[concat(variables('lbID0'),'/inboundNatPools/LoadBalancerBEAddressNatPool')]", - "vmStorageAccountName0": "[toLower(concat(uniqueString(resourceGroup().id), '1', '0' ))]", - "wadmetricsresourceid0": "[concat('/subscriptions/',subscription().subscriptionId,'/resourceGroups/',resourceGroup().name ,'/providers/','Microsoft.Compute/virtualMachineScaleSets/', parameters('vmNodeType0Name'))]" - }, - "resources": [ - { - "apiVersion": "[variables('storageApiVersion')]", - "type": "Microsoft.Storage/storageAccounts", - "name": "[parameters('supportLogStorageAccountName')]", - "location": "[parameters('computeLocation')]", - "dependsOn": [], - "properties": {}, - "kind": "Storage", - "sku": { - "name": "[parameters('supportLogStorageAccountType')]" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "[variables('storageApiVersion')]", - "type": "Microsoft.Storage/storageAccounts", - "name": "[parameters('applicationDiagnosticsStorageAccountName')]", - "location": "[parameters('computeLocation')]", - "dependsOn": [], - "properties": {}, - "kind": "Storage", - "sku": { - "name": "[parameters('applicationDiagnosticsStorageAccountType')]" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "[variables('vNetApiVersion')]", - "type": "Microsoft.Network/virtualNetworks", - "name": "[parameters('virtualNetworkName')]", - "location": "[parameters('computeLocation')]", - "dependsOn": [], - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[parameters('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[parameters('subnet0Name')]", - "properties": { - "addressPrefix": "[parameters('subnet0Prefix')]" - } - } - ] - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "[variables('publicIPApiVersion')]", - "type": "Microsoft.Network/publicIPAddresses", - "name": "[concat(parameters('lbIPName'),'-','0')]", - "location": "[parameters('computeLocation')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsName')]" - }, - "publicIPAllocationMethod": "Dynamic" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "[variables('lbApiVersion')]", - "type": "Microsoft.Network/loadBalancers", - "name": "[concat('LB','-', parameters('clusterName'),'-',parameters('vmNodeType0Name'))]", - "location": "[parameters('computeLocation')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/',concat(parameters('lbIPName'),'-','0'))]" - ], - "properties": { - "frontendIPConfigurations": [ - { - "name": "LoadBalancerIPConfig", - "properties": { - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses',concat(parameters('lbIPName'),'-','0'))]" - } - } - } - ], - "backendAddressPools": [ - { - "name": "LoadBalancerBEAddressPool", - "properties": {} - } - ], - "loadBalancingRules": [ - { - "name": "LBRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('nt0fabricTcpGatewayPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('nt0fabricTcpGatewayPort')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "LBHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('nt0fabricHttpGatewayPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('nt0fabricHttpGatewayPort')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbHttpProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "WebMVCHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('webMvcHttpPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('webMvcHttpPort')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "WebSPAHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('webSpaHttpPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('webSpaHttpPort')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "WebStatusHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('webStatusHttpPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('webStatusHttpPort')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "IdSrvHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('IdSrvHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('IdSrvHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "BasketApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('BasketApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('BasketApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "CatalogApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('CatalogApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('CatalogApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "OrderingApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('OrderingApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('OrderingApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "MarketingApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('MarketingApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('MarketingApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "LocationsApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('LocationsApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('LocationsApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - } - ], - "probes": [ - { - "name": "FabricGatewayProbe", - "properties": { - "intervalInSeconds": 5, - "numberOfProbes": 2, - "port": "[parameters('nt0fabricTcpGatewayPort')]", - "protocol": "tcp" - } - }, - { - "name": "FabricHttpGatewayProbe", - "properties": { - "intervalInSeconds": 5, - "numberOfProbes": 2, - "port": "[parameters('nt0fabricHttpGatewayPort')]", - "protocol": "tcp" - } - } - ], - "inboundNatPools": [ - { - "name": "LoadBalancerBEAddressNatPool", - "properties": { - "backendPort": "22", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPortRangeEnd": "4500", - "frontendPortRangeStart": "3389", - "protocol": "tcp" - } - } - ] - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "[variables('vmssApiVersion')]", - "type": "Microsoft.Compute/virtualMachineScaleSets", - "name": "[parameters('vmNodeType0Name')]", - "location": "[parameters('computeLocation')]", - "dependsOn": [ - "[concat('Microsoft.Network/virtualNetworks/', parameters('virtualNetworkName'))]", - "[concat('Microsoft.Network/loadBalancers/', concat('LB','-', parameters('clusterName'),'-',parameters('vmNodeType0Name')))]", - "[concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName'))]", - "[concat('Microsoft.Storage/storageAccounts/', parameters('applicationDiagnosticsStorageAccountName'))]" - ], - "properties": { - "overprovision": "[parameters('overProvision')]", - "upgradePolicy": { - "mode": "Automatic" - }, - "virtualMachineProfile": { - "extensionProfile": { - "extensions": [ - { - "name": "[concat(parameters('vmNodeType0Name'),'_ServiceFabricLinuxNode')]", - "properties": { - "type": "ServiceFabricLinuxNode", - "autoUpgradeMinorVersion": true, - "protectedSettings": { - "StorageAccountKey1": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('supportLogStorageAccountName')),'2015-05-01-preview').key1]", - "StorageAccountKey2": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('supportLogStorageAccountName')),'2015-05-01-preview').key2]" - }, - "publisher": "Microsoft.Azure.ServiceFabric", - "settings": { - "clusterEndpoint": "[reference(parameters('clusterName')).clusterEndpoint]", - "nodeTypeRef": "[parameters('vmNodeType0Name')]", - "durabilityLevel": "Bronze", - "enableParallelJobs": true, - "nicPrefixOverride": "[parameters('subnet0Prefix')]", - "certificate": { - "thumbprint": "[parameters('certificateThumbprint')]", - "x509StoreName": "[parameters('certificateStoreValue')]" - } - }, - "typeHandlerVersion": "1.0" - } - }, - { - "name": "[concat('VMDiagnosticsVmExt','_vmNodeType0Name')]", - "properties": { - "type": "LinuxDiagnostic", - "autoUpgradeMinorVersion": true, - "protectedSettings": { - "storageAccountName": "[parameters('applicationDiagnosticsStorageAccountName')]", - "storageAccountKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('applicationDiagnosticsStorageAccountName')),'2015-05-01-preview').key1]", - "storageAccountEndPoint": "https://core.windows.net/" - }, - "publisher": "Microsoft.OSTCExtensions", - "settings": { - "xmlCfg": "[base64(concat(variables('wadcfgxstart'),variables('wadmetricsresourceid0'),variables('wadcfgxend')))]", - "StorageAccount": "[parameters('applicationDiagnosticsStorageAccountName')]" - }, - "typeHandlerVersion": "2.3" - } - } - ] - }, - "networkProfile": { - "networkInterfaceConfigurations": [ - { - "name": "[concat(parameters('nicName'), '-0')]", - "properties": { - "ipConfigurations": [ - { - "name": "[concat(parameters('nicName'),'-',0)]", - "properties": { - "loadBalancerBackendAddressPools": [ - { - "id": "[variables('lbPoolID0')]" - } - ], - "loadBalancerInboundNatPools": [ - { - "id": "[variables('lbNatPoolID0')]" - } - ], - "subnet": { - "id": "[variables('subnet0Ref')]" - } - } - } - ], - "primary": true - } - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computernamePrefix": "[parameters('vmNodeType0Name')]", - "secrets": [ - { - "sourceVault": { - "id": "[parameters('sourceVaultValue')]" - }, - "vaultCertificates": [ - { - "certificateUrl": "[parameters('certificateUrlValue')]" - } - ] - } - ] - }, - "storageProfile": { - "imageReference": { - "publisher": "[parameters('vmImagePublisher')]", - "offer": "[parameters('vmImageOffer')]", - "sku": "[parameters('vmImageSku')]", - "version": "[parameters('vmImageVersion')]" - }, - "osDisk": { - "caching": "ReadOnly", - "createOption": "FromImage", - "managedDisk": { - "storageAccountType": "[parameters('storageAccountType')]" - } - } - } - } - }, - "sku": { - "name": "[parameters('vmNodeType0Size')]", - "capacity": "[parameters('nt0InstanceCount')]", - "tier": "Standard" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "2017-07-01-preview", - "type": "Microsoft.ServiceFabric/clusters", - "name": "[parameters('clusterName')]", - "location": "[parameters('clusterLocation')]", - "dependsOn": [ - "[concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName'))]" - ], - "properties": { - "addonFeatures": [ - "DnsService" - ], - "certificate": { - "thumbprint": "[parameters('certificateThumbprint')]", - "x509StoreName": "[parameters('certificateStoreValue')]" - }, - "clientCertificateCommonNames": [], - "clientCertificateThumbprints": [], - "clusterCodeVersion": "6.0.120.1", - "clusterState": "Default", - "diagnosticsStorageAccountConfig": { - "blobEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.blob]", - "protectedAccountKeyName": "StorageAccountKey1", - "queueEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.queue]", - "storageAccountName": "[parameters('supportLogStorageAccountName')]", - "tableEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.table]" - }, - "fabricSettings": [ - { - "parameters": [ - { - "name": "ClusterProtectionLevel", - "value": "[parameters('clusterProtectionLevel')]" - } - ], - "name": "Security" - } - ], - "managementEndpoint": "[concat('https://',reference(concat(parameters('lbIPName'),'-','0')).dnsSettings.fqdn,':',parameters('nt0fabricHttpGatewayPort'))]", - "nodeTypes": [ - { - "name": "[parameters('vmNodeType0Name')]", - "applicationPorts": { - "endPort": "[parameters('nt0applicationEndPort')]", - "startPort": "[parameters('nt0applicationStartPort')]" - }, - "clientConnectionEndpointPort": "[parameters('nt0fabricTcpGatewayPort')]", - "durabilityLevel": "Bronze", - "ephemeralPorts": { - "endPort": "[parameters('nt0ephemeralEndPort')]", - "startPort": "[parameters('nt0ephemeralStartPort')]" - }, - "httpGatewayEndpointPort": "[parameters('nt0fabricHttpGatewayPort')]", - "isPrimary": true, - "vmInstanceCount": "[parameters('nt0InstanceCount')]" - } - ], - "provisioningState": "Default", - "reliabilityLevel": "Silver", - "upgradeMode": "Manual", - "vmImage": "Linux" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - } - ], - "outputs": { - "clusterProperties": { - "value": "[reference(parameters('clusterName'))]", - "type": "object" - } - } -} \ No newline at end of file diff --git a/deploy/azure/az/servicefabric/LinuxContainers/servicefabricdeploysecured.parameters.json b/deploy/azure/az/servicefabric/LinuxContainers/servicefabricdeploysecured.parameters.json deleted file mode 100644 index 65875cb31..000000000 --- a/deploy/azure/az/servicefabric/LinuxContainers/servicefabricdeploysecured.parameters.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "clusterName": { - "value": "pro-eshop-sflinux-cluster" - }, - "clusterLocation": { - "value": "westus" - }, - "computeLocation": { - "value": "westus" - }, - "adminUserName": { - "value": "eshop" - }, - "adminPassword": { - "value": "Pass@word1" - }, - "nicName": { - "value": "NIC-eshopsflinsec" - }, - "publicIPAddressName": { - "value": "eshopsflinsec-PubIP" - }, - "dnsName": { - "value": "pro-eshop-sflinux-cluster" - }, - "virtualNetworkName": { - "value": "VNet-eshopsflin" - }, - "lbName": { - "value": "LB-eshopsflin" - }, - "lbIPName": { - "value": "LBIP-eshopsflin" - }, - "sourceVaultValue": { - "value": "your-value-check-keyvault-at-azure" - }, - "certificateUrlValue": { - "value": "your-value-check-keyvault-at-azure" - }, - "certificateThumbprint": { - "value": "your-value-check-keyvault-at-azure" - }, - "vmImageSku": { - "value": "16.04-LTS" - }, - "vmImageVersion": { - "value": "latest" - }, - "vmImagePublisher": { - "value": "Canonical" - }, - "nt0ephemeralStartPort": { - "value": 49152 - }, - "nt0ephemeralEndPort": { - "value": 65534 - }, - "nt0applicationStartPort": { - "value": 20000 - }, - "nt0applicationEndPort": { - "value": 30000 - }, - "nt0fabricTcpGatewayPort": { - "value": 19000 - }, - "nt0fabricHttpGatewayPort": { - "value": 19080 - }, - "webMvcHttpPort": { - "value": 5100 - }, - "webSpaHttpPort": { - "value": 5104 - }, - "webStatusHttpPort": { - "value": 5107 - }, - "IdSrvHttpRule": { - "value": 5105 - }, - "BasketApiHttpRule": { - "value": 5103 - }, - "CatalogApiHttpRule": { - "value": 5101 - }, - "OrderingApiHttpRule": { - "value": 5102 - }, - "MarketingApiHttpRule": { - "value": 5110 - }, - "LocationsApiHttpRule": { - "value": 5109 - } - } -} \ No newline at end of file diff --git a/deploy/azure/az/servicefabric/WindowsContainers/gen-keyvaultcert.ps1 b/deploy/azure/az/servicefabric/WindowsContainers/gen-keyvaultcert.ps1 deleted file mode 100644 index c6fc34013..000000000 --- a/deploy/azure/az/servicefabric/WindowsContainers/gen-keyvaultcert.ps1 +++ /dev/null @@ -1,53 +0,0 @@ -Param( - [parameter(Mandatory=$true)][string]$vaultName, - [parameter(Mandatory=$true)][string]$certName, - [parameter(Mandatory=$true)][string]$certPwd, - [parameter(Mandatory=$true)][string]$subjectName, - [parameter(Mandatory=$false)][string]$ValidityInMonths=12, - [parameter(Mandatory=$true)][string]$saveDir -) - - -#Log in Azure Account -Login-AzureRmAccount - - -# Create Cert in KeyVault -Write-Host "Creating certificate in Azure KeyVault..." -ForegroundColor Yellow -$policy = New-AzureKeyVaultCertificatePolicy -SubjectName $subjectName -IssuerName Self -ValidityInMonths $ValidityInMonths -Add-AzureKeyVaultCertificate -VaultName $vaultName -Name $certName -CertificatePolicy $policy - -# Downloading Certificate -Write-Host "Downloading Certificate from KeyVault..." -ForegroundColor Yellow - -$Stoploop = $false -$Retrycount = 0 - -do { - try { - - $kvSecret = Get-AzureKeyVaultSecret -VaultName $vaultName -Name $certName -ErrorAction SilentlyContinue - $kvSecretBytes = [System.Convert]::FromBase64String($kvSecret.SecretValueText) - $certCollection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection - $certCollection.Import($kvSecretBytes,$null,[System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable) - $protectedCertificateBytes = $certCollection.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12, $certPwd) - [System.IO.File]::WriteAllBytes($saveDir + "\" + $certName + ".pfx", $protectedCertificateBytes) - - $Stoploop = $true - Write-Host "Finished!" -ForegroundColor Yellow - } - catch { - if ($Retrycount -gt 5){ - $Stoploop = $true - Write-Host "Not possible to retrieve the certificate!" -ForegroundColor Yellow - } - else { - Start-Sleep -Seconds 20 - $Retrycount = $Retrycount + 1 - } - } -} -While ($Stoploop -eq $false) - -# Show Certificate Values -Get-AzureKeyVaultCertificate -VaultName $vaultName -Name $certName \ No newline at end of file diff --git a/deploy/azure/az/servicefabric/WindowsContainers/readme.md b/deploy/azure/az/servicefabric/WindowsContainers/readme.md deleted file mode 100644 index 18aa8ad78..000000000 --- a/deploy/azure/az/servicefabric/WindowsContainers/readme.md +++ /dev/null @@ -1,138 +0,0 @@ -# Deploying a Service Fabric cluster based on Windows nodes - -## A. Unsecured cluster (SF Windows cluster) -For a secured cluster, see option B. below. - -You can always deploy a SF cluster through the Azure portal, as explained in this article: https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-get-started-azure-cluster - -However, when creating a cluster, there are quite a few configurations to take into account, like enabling the internal DNS service or Reverse Proxy service, choosing between Linux/Windows, open/publish your application ports in the load-balancer and most of all (the most complex setup) how to create a secure cluster. - -Because of those reasons, we have created a set of ARM templates and scripts so you can create, re-create and configure the SF clusters much faster, as explained below: - -Within eShopOnContainers root folder, at the folder [..\deploy\az\servicefabric\WindowsContainers](https://github.com/dotnet-architecture/eShopOnContainers/tree/dev/deploy/az/servicefabric/WindowsContainers), you can find the ARM template `servicefabricdeploy.json` and its parameters file (`servicefabricdeploy.parameters.json`) to create a Service Fabric cluster environment for Windows Containers (NOT SECURED CLUSTER). - -## Edit the servicefabricdeploy.parameters.json file - -Edit the following params in `servicefabricdeploy.parameters.json` file to set your values: - -- clusterName: Name of your SF cluster -- clusterLocation: Datacenter location, like westus or westeurope -- computeLocation: Datacenter location, like westus or westeurope -- adminUserName: user-name for VMs administration -- adminPassword: user-password for VMs administration -- dnsName: Name assigned to your SF dns - -Optionally, you could modify which ports are opened in the LoadBalancer for the multiple eShopOnContainer apps and API services. -By default, they are setup as: -- webMvcHttpPort: 5100 -- webSpaHttpPort: 5104 -- webStatusHttpPort: 5107 -- IdSrvHttpRule: 5105 -- BasketApiHttpRule: 5103 -- CatalogApiHttpRule: 5101 -- OrderingApiHttpRule: 5102 -- MarketingApiHttpRule: 5110 -- LocationsApiHttpRule: 5109 - -## Deploy the Service Fabric cluster using the script and ARM templates - -Once parameter file is edited you can deploy it using [create-resources script](../readme.md). - -For example, to deploy the cluster to a new resourcegroup located in westus, using the Command Prompt, go to `deploy\az` folder and type: -``` -create-resources.cmd servicefabric\WindowsContainers\servicefabricdeploy qa-eshop-sfwin-resgrp -c westus -``` - -You should see a similar execution to the following: -![image](https://user-images.githubusercontent.com/1712635/31638979-4881d7aa-b28b-11e7-873c-e1185043a9eb.png) - -Now, if you go to your subscription in Azure, you should be able to see the SF cluster already created and available, like in the following image: - -![image](https://user-images.githubusercontent.com/1712635/31639043-9b26c786-b28b-11e7-8d59-eeea97f74176.png) - -In this case, this is an unsecured SF cluster with a single Windows node, good for initial tests and getting started with SF. - - -## B. Secured cluster (SF Windows cluster) - -Within eShopOnContainers root folder, at the folder [..\deploy\az\servicefabric\WindowsContainers](https://github.com/dotnet-architecture/eShopOnContainers/tree/dev/deploy/az/servicefabric/WindowsContainers), you can find the ARM template `servicefabricdeploysecured.json` and its parameter file (`servicefabricdeploysecured.parameters.json`) to create a secured Service Fabric cluster environment for Windows Containers (IN THIS CASE, IT IS A SECURED CLUSTER USING A CERTIFICATE). - -## Create Azure Keyvault service -Go to PortalAzure and create a Keyvault service. Make sure Enable access for deployment checkboxes are selected. - -![image](https://user-images.githubusercontent.com/1712635/31638848-9b266530-b28a-11e7-953b-1e3ec1a54f77.png) - -## Generate a certificate in Azure Keyvault -In a POWER-SHELL window, move to the folder [..\deploy\az\servicefabric\WindowsContainers](https://github.com/dotnet-architecture/eShopOnContainers/tree/dev/deploy/az/servicefabric/WindowsContainers). - -**Select your Azure subscription** You might have [several Azure subscriptions](https://docs.microsoft.com/en-us/cli/azure/account#set) as shown if you type the following. - - >``` - >az account list - >``` - If you have multiple subscription accounts, you first need to select the Azure subscription account you want to target. Type the following: - >``` - >az account set --subscription "Your Azure Subscription Name or ID" - >``` - -**Execute the gen-keyvaultcert.ps1 script** to generate and download a certificate from Keyvault. -Make sure you're going to run it against the Azure subscription you mean it. - -You might need to authenticate from the browser when running this PowerShell script. - -``` -.\gen-keyvaultcert.ps1 -vaultName -certName -certPwd -subjectName CN=.westus.cloudapp.azure.com -saveDir C:\Users\\Downloads - -``` -You should see a similar execution to the following: -![image](https://user-images.githubusercontent.com/1712635/31640172-93efcca0-b291-11e7-970e-5b5e6bf07042.png) - -IMPORTANT: At this point, copy/cut the .PFX certificate file saved in the downloads forlder and save it in a secure place. - -## Install the certificate -Install the certificate (by double-clicking on the .PFX file) under 'Current User' store location (by default location) and check it as exportable. - - - -Also, install the same certificate as CA (Certificate Authority) under Current User, too. - -![image](https://user-images.githubusercontent.com/1712635/31642795-c6ffa434-b2a1-11e7-8ff8-2a63549a780e.png) - -## Editing servicefabricdeploysecured.parameters.json file - -Edit the parameters in `servicefabricdeploysecured.parameters.json` in a similar way you can do with the unsecured .json file shown above (clusterName, dnsName, etc.), plus edit the following values: - -- sourceVaultValue: Your Azure Keyvault's RESOURCE ID (check Azure keyvault properties, similar to: /subscriptions/e1234ac1-c09c-3jaf-6767-98b3c5f1f246/resourceGroups/eshop-global-resgrp/providers/Microsoft.KeyVault/vaults/eshopkeyvault") - -- certificateUrlValue: Your certificate Secret Identifier (check Azure Keyvault secret certificate properties, should be in the format of https://.vault.azure.net:443/secrets/, similar to: -https://eshopkeyvault.vault.azure.net/secrets/pro-eshop-sfwin-cluster-cert/w647684642cGE2sj83b3hfe4h8e08963) - -- certificateThumbprint: certificate thumbprint (check azure Keyvault certificate thumbprint, something like 88JK453486D55A6818573G0DW9100365HDK70HDK) - -## Deploy the secured SF cluster (Windows nodes) - -Once parameters file is edited you can deploy it using [create-resources script](../readme.md). - -Use a command prompt window positioned into the deploy\az folder. - -``` -create-resources.cmd servicefabric\WindowsContainers\servicefabricdeploysecured pro-eshop-sfwin-resgrp -c westus -``` -The execution should be something like the following: - -![image](https://user-images.githubusercontent.com/1712635/31641955-0bc9d59e-b29d-11e7-9230-5ba02843d98a.png) - -Once the cluster is created you can explore it with Azure's portal, like in the following image: -![image](https://user-images.githubusercontent.com/1712635/31642431-bf1c409e-b29f-11e7-980f-a7685a45108c.png) - -In this case, the ARM template is creating a 5 node cluster when creating a SECURE cluster for "production". - - -# Deploy eShopOnServiceFabric with Visual Studio. - -Modify the cloud.xml file of each Service Fabric application in PublishProfile directory and set your certificate settings to be able to deploy eshopOnContainers in the secured cluster: - - - - - diff --git a/deploy/azure/az/servicefabric/WindowsContainers/servicefabricdeploy.json b/deploy/azure/az/servicefabric/WindowsContainers/servicefabricdeploy.json deleted file mode 100644 index b33d939ed..000000000 --- a/deploy/azure/az/servicefabric/WindowsContainers/servicefabricdeploy.json +++ /dev/null @@ -1,859 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "prefix": { - "type": "string" - }, - "clusterLocation": { - "type": "string", - "metadata": { - "description": "Location of the Cluster" - } - }, - "clusterName": { - "type": "string", - "defaultValue": "Cluster", - "metadata": { - "description": "Name of your cluster - Between 3 and 23 characters. Letters and numbers only" - } - }, - "nt0applicationStartPort": { - "type": "int", - "defaultValue": 20000 - }, - "nt0applicationEndPort": { - "type": "int", - "defaultValue": 30000 - }, - "nt0ephemeralStartPort": { - "type": "int", - "defaultValue": 49152 - }, - "nt0ephemeralEndPort": { - "type": "int", - "defaultValue": 65534 - }, - "nt0fabricTcpGatewayPort": { - "type": "int", - "defaultValue": 19000 - }, - "nt0fabricHttpGatewayPort": { - "type": "int", - "defaultValue": 19080 - }, - "nt0reverseProxyEndpointPort": { - "type": "int", - "defaultValue": 19081 - }, - "webMvcHttpPort": { - "type": "int", - "defaultValue": 5100 - }, - "webSpaHttpPort": { - "type": "int", - "defaultValue": 5104 - }, - "webStatusHttpPort": { - "type": "int", - "defaultValue": 5107 - }, - "IdSrvHttpRule": { - "type": "int", - "defaultValue": 5105 - }, - "BasketApiHttpRule": { - "type": "int", - "defaultValue": 5103 - }, - "CatalogApiHttpRule": { - "type": "int", - "defaultValue": 5101 - }, - "OrderingApiHttpRule": { - "type": "int", - "defaultValue": 5102 - }, - "MarketingApiHttpRule": { - "type": "int", - "defaultValue": 5110 - }, - "LocationsApiHttpRule": { - "type": "int", - "defaultValue": 5109 - }, - "subnet0Name": { - "type": "string", - "defaultValue": "Subnet-0" - }, - "subnet0Prefix": { - "type": "string", - "defaultValue": "10.0.0.0/24" - }, - "computeLocation": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string", - "defaultValue": "PublicIP-VM" - }, - "publicIPAddressType": { - "type": "string", - "allowedValues": [ - "Dynamic" - ], - "defaultValue": "Dynamic" - }, - "vmStorageAccountContainerName": { - "type": "string", - "defaultValue": "vhds" - }, - "adminUserName": { - "type": "string", - "defaultValue": "testadm", - "metadata": { - "description": "Remote desktop user Id" - } - }, - "adminPassword": { - "type": "securestring", - "metadata": { - "description": "Remote desktop user password. Must be a strong password" - } - }, - "virtualNetworkName": { - "type": "string", - "defaultValue": "VNet" - }, - "addressPrefix": { - "type": "string", - "defaultValue": "10.0.0.0/16" - }, - "dnsName": { - "type": "string" - }, - "nicName": { - "type": "string", - "defaultValue": "NIC" - }, - "lbName": { - "type": "string", - "defaultValue": "LoadBalancer" - }, - "lbIPName": { - "type": "string", - "defaultValue": "PublicIP-LB-FE" - }, - "overProvision": { - "type": "string", - "defaultValue": "false" - }, - "vmImagePublisher": { - "type": "string", - "defaultValue": "MicrosoftWindowsServer" - }, - "vmImageOffer": { - "type": "string", - "defaultValue": "WindowsServer" - }, - "vmImageSku": { - "type": "string", - "defaultValue": "2012-R2-Datacenter" - }, - "vmImageVersion": { - "type": "string", - "defaultValue": "latest" - }, - "storageAccountType": { - "type": "string", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS" - ], - "defaultValue": "Standard_LRS", - "metadata": { - "description": "Replication option for the VM image storage account" - } - }, - "supportLogStorageAccountType": { - "type": "string", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS" - ], - "defaultValue": "Standard_LRS", - "metadata": { - "description": "Replication option for the support log storage account" - } - }, - "supportLogStorageAccountName": { - "type": "string", - "defaultValue": "[toLower( concat('sflogs', uniqueString(resourceGroup().id),'2'))]", - "metadata": { - "description": "Name for the storage account that contains support logs from the cluster" - } - }, - "applicationDiagnosticsStorageAccountType": { - "type": "string", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS" - ], - "defaultValue": "Standard_LRS", - "metadata": { - "description": "Replication option for the application diagnostics storage account" - } - }, - "applicationDiagnosticsStorageAccountName": { - "type": "string", - "defaultValue": "[toLower(concat(uniqueString(resourceGroup().id), '3' ))]", - "metadata": { - "description": "Name for the storage account that contains application diagnostics data from the cluster" - } - }, - "nt0InstanceCount": { - "type": "int", - "defaultValue": 1, - "metadata": { - "description": "Instance count for node type" - } - }, - "vmNodeType0Name": { - "type": "string", - "defaultValue": "primary", - "maxLength": 9 - }, - "vmNodeType0Size": { - "type": "string", - "defaultValue": "Standard_D2_v2" - } - }, - "variables": { - "vmssApiVersion": "2017-03-30", - "lbApiVersion": "2015-06-15", - "vNetApiVersion": "2015-06-15", - "storageApiVersion": "2016-01-01", - "publicIPApiVersion": "2015-06-15", - "vnetID": "[resourceId('Microsoft.Network/virtualNetworks',parameters('virtualNetworkName'))]", - "subnet0Ref": "[concat(variables('vnetID'),'/subnets/',parameters('subnet0Name'))]", - "lbID0": "[resourceId('Microsoft.Network/loadBalancers', concat('LB','-', variables('clusterName'),'-',parameters('vmNodeType0Name')))]", - "lbIPConfig0": "[concat(variables('lbID0'),'/frontendIPConfigurations/LoadBalancerIPConfig')]", - "lbPoolID0": "[concat(variables('lbID0'),'/backendAddressPools/LoadBalancerBEAddressPool')]", - "lbProbeID0": "[concat(variables('lbID0'),'/probes/FabricGatewayProbe')]", - "lbHttpProbeID0": "[concat(variables('lbID0'),'/probes/FabricHttpGatewayProbe')]", - "lbNatPoolID0": "[concat(variables('lbID0'),'/inboundNatPools/LoadBalancerBEAddressNatPool')]", - "vmStorageAccountName0": "[toLower(concat(uniqueString(resourceGroup().id), '1', '0' ))]", - "supportLogStorageAccountName": "[take(concat(parameters('prefix'), parameters('supportLogStorageAccountName')),22)]", - "applicationDiagnosticsStorageAccountName" : "[take(concat(parameters('prefix'), parameters('applicationDiagnosticsStorageAccountName')),22)]", - "clusterName": "[concat(parameters('prefix'), parameters('clusterName'))]", - "uniqueStringArray0": [ - "[concat(variables('vmStorageAccountName0'), '0')]", - "[concat(variables('vmStorageAccountName0'), '1')]", - "[concat(variables('vmStorageAccountName0'), '2')]", - "[concat(variables('vmStorageAccountName0'), '3')]", - "[concat(variables('vmStorageAccountName0'), '4')]" - ] - }, - "resources": [ - { - "apiVersion": "[variables('storageApiVersion')]", - "type": "Microsoft.Storage/storageAccounts", - "name": "[variables('supportLogStorageAccountName')]", - "location": "[parameters('computeLocation')]", - "dependsOn": [], - "properties": {}, - "kind": "Storage", - "sku": { - "name": "[parameters('supportLogStorageAccountType')]" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[variables('clusterName')]" - } - }, - { - "apiVersion": "[variables('storageApiVersion')]", - "type": "Microsoft.Storage/storageAccounts", - "name": "[variables('applicationDiagnosticsStorageAccountName')]", - "location": "[parameters('computeLocation')]", - "dependsOn": [], - "properties": {}, - "kind": "Storage", - "sku": { - "name": "[parameters('applicationDiagnosticsStorageAccountType')]" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[variables('clusterName')]" - } - }, - { - "apiVersion": "[variables('vNetApiVersion')]", - "type": "Microsoft.Network/virtualNetworks", - "name": "[parameters('virtualNetworkName')]", - "location": "[parameters('computeLocation')]", - "dependsOn": [], - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[parameters('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[parameters('subnet0Name')]", - "properties": { - "addressPrefix": "[parameters('subnet0Prefix')]" - } - } - ] - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[variables('clusterName')]" - } - }, - { - "apiVersion": "[variables('publicIPApiVersion')]", - "type": "Microsoft.Network/publicIPAddresses", - "name": "[concat(parameters('lbIPName'),'-','0')]", - "location": "[parameters('computeLocation')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsName')]" - }, - "publicIPAllocationMethod": "Dynamic" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[variables('clusterName')]" - } - }, - { - "apiVersion": "[variables('lbApiVersion')]", - "type": "Microsoft.Network/loadBalancers", - "name": "[concat('LB','-', variables('clusterName'),'-',parameters('vmNodeType0Name'))]", - "location": "[parameters('computeLocation')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/',concat(parameters('lbIPName'),'-','0'))]" - ], - "properties": { - "frontendIPConfigurations": [ - { - "name": "LoadBalancerIPConfig", - "properties": { - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses',concat(parameters('lbIPName'),'-','0'))]" - } - } - } - ], - "backendAddressPools": [ - { - "name": "LoadBalancerBEAddressPool", - "properties": {} - } - ], - "loadBalancingRules": [ - { - "name": "LBRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('nt0fabricTcpGatewayPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('nt0fabricTcpGatewayPort')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "LBHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('nt0fabricHttpGatewayPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('nt0fabricHttpGatewayPort')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbHttpProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "ReverseProxyHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('nt0reverseProxyEndpointPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('nt0reverseProxyEndpointPort')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbHttpProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "WebMVCHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('webMvcHttpPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('webMvcHttpPort')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbHttpProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "WebSPAHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('webSpaHttpPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('webSpaHttpPort')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbHttpProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "WebStatusHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('webStatusHttpPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('webStatusHttpPort')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbHttpProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "IdSrvHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('IdSrvHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('IdSrvHttpRule')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbHttpProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "BasketApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('BasketApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('BasketApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "CatalogApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('CatalogApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('CatalogApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "OrderingApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('OrderingApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('OrderingApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "MarketingApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('MarketingApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('MarketingApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "LocationsApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('LocationsApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('LocationsApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - } - ], - "probes": [ - { - "name": "FabricGatewayProbe", - "properties": { - "intervalInSeconds": 5, - "numberOfProbes": 2, - "port": "[parameters('nt0fabricTcpGatewayPort')]", - "protocol": "tcp" - } - }, - { - "name": "FabricHttpGatewayProbe", - "properties": { - "intervalInSeconds": 5, - "numberOfProbes": 2, - "port": "[parameters('nt0fabricHttpGatewayPort')]", - "protocol": "tcp" - } - } - ], - "inboundNatPools": [ - { - "name": "LoadBalancerBEAddressNatPool", - "properties": { - "backendPort": "3389", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPortRangeEnd": "4500", - "frontendPortRangeStart": "3389", - "protocol": "tcp" - } - } - ] - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[variables('clusterName')]" - } - }, - { - "apiVersion": "[variables('storageApiVersion')]", - "type": "Microsoft.Storage/storageAccounts", - "name": "[variables('uniqueStringArray0')[copyIndex()]]", - "location": "[parameters('computeLocation')]", - "dependsOn": [], - "properties": {}, - "copy": { - "name": "storageLoop", - "count": 5 - }, - "kind": "Storage", - "sku": { - "name": "[parameters('storageAccountType')]" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[variables('clusterName')]" - } - }, - { - "apiVersion": "[variables('vmssApiVersion')]", - "type": "Microsoft.Compute/virtualMachineScaleSets", - "name": "[parameters('vmNodeType0Name')]", - "location": "[parameters('computeLocation')]", - "dependsOn": [ - "[concat('Microsoft.Network/virtualNetworks/', parameters('virtualNetworkName'))]", - "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[0])]", - "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[1])]", - "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[2])]", - "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[3])]", - "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[4])]", - "[concat('Microsoft.Network/loadBalancers/', concat('LB','-', variables('clusterName'),'-',parameters('vmNodeType0Name')))]", - "[concat('Microsoft.Storage/storageAccounts/', variables('supportLogStorageAccountName'))]", - "[concat('Microsoft.Storage/storageAccounts/', variables('applicationDiagnosticsStorageAccountName'))]" - ], - "properties": { - "overprovision": "[parameters('overProvision')]", - "upgradePolicy": { - "mode": "Automatic" - }, - "virtualMachineProfile": { - "extensionProfile": { - "extensions": [ - { - "name": "[concat(parameters('vmNodeType0Name'),'_ServiceFabricNode')]", - "properties": { - "type": "ServiceFabricNode", - "autoUpgradeMinorVersion": true, - "protectedSettings": { - "StorageAccountKey1": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('supportLogStorageAccountName')),'2015-05-01-preview').key1]", - "StorageAccountKey2": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('supportLogStorageAccountName')),'2015-05-01-preview').key2]" - }, - "publisher": "Microsoft.Azure.ServiceFabric", - "settings": { - "clusterEndpoint": "[reference(variables('clusterName')).clusterEndpoint]", - "nodeTypeRef": "[parameters('vmNodeType0Name')]", - "dataPath": "D:\\\\SvcFab", - "durabilityLevel": "Bronze", - "enableParallelJobs": true, - "nicPrefixOverride": "[parameters('subnet0Prefix')]" - }, - "typeHandlerVersion": "1.0" - } - }, - { - "name": "[concat('VMDiagnosticsVmExt','_vmNodeType0Name')]", - "properties": { - "type": "IaaSDiagnostics", - "autoUpgradeMinorVersion": true, - "protectedSettings": { - "storageAccountName": "[variables('applicationDiagnosticsStorageAccountName')]", - "storageAccountKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('applicationDiagnosticsStorageAccountName')),'2015-05-01-preview').key1]", - "storageAccountEndPoint": "https://core.windows.net/" - }, - "publisher": "Microsoft.Azure.Diagnostics", - "settings": { - "WadCfg": { - "DiagnosticMonitorConfiguration": { - "overallQuotaInMB": "50000", - "EtwProviders": { - "EtwEventSourceProviderConfiguration": [ - { - "provider": "Microsoft-ServiceFabric-Actors", - "scheduledTransferKeywordFilter": "1", - "scheduledTransferPeriod": "PT5M", - "DefaultEvents": { - "eventDestination": "ServiceFabricReliableActorEventTable" - } - }, - { - "provider": "Microsoft-ServiceFabric-Services", - "scheduledTransferPeriod": "PT5M", - "DefaultEvents": { - "eventDestination": "ServiceFabricReliableServiceEventTable" - } - } - ], - "EtwManifestProviderConfiguration": [ - { - "provider": "cbd93bc2-71e5-4566-b3a7-595d8eeca6e8", - "scheduledTransferLogLevelFilter": "Information", - "scheduledTransferKeywordFilter": "4611686018427387904", - "scheduledTransferPeriod": "PT5M", - "DefaultEvents": { - "eventDestination": "ServiceFabricSystemEventTable" - } - } - ] - } - } - }, - "StorageAccount": "[variables('applicationDiagnosticsStorageAccountName')]" - }, - "typeHandlerVersion": "1.5" - } - } - ] - }, - "networkProfile": { - "networkInterfaceConfigurations": [ - { - "name": "[concat(parameters('nicName'), '-0')]", - "properties": { - "ipConfigurations": [ - { - "name": "[concat(parameters('nicName'),'-',0)]", - "properties": { - "loadBalancerBackendAddressPools": [ - { - "id": "[variables('lbPoolID0')]" - } - ], - "loadBalancerInboundNatPools": [ - { - "id": "[variables('lbNatPoolID0')]" - } - ], - "subnet": { - "id": "[variables('subnet0Ref')]" - } - } - } - ], - "primary": true - } - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computernamePrefix": "[parameters('vmNodeType0Name')]" - }, - "storageProfile": { - "imageReference": { - "publisher": "[parameters('vmImagePublisher')]", - "offer": "[parameters('vmImageOffer')]", - "sku": "[parameters('vmImageSku')]", - "version": "[parameters('vmImageVersion')]" - }, - "osDisk": { - "caching": "ReadOnly", - "createOption": "FromImage", - "vhdContainers": [ - "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[0]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]", - "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[1]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]", - "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[2]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]", - "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[3]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]", - "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[4]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]" - ], - "name": "vmssosdisk" - } - } - } - }, - "sku": { - "name": "[parameters('vmNodeType0Size')]", - "capacity": "[parameters('nt0InstanceCount')]", - "tier": "Standard" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[variables('clusterName')]" - } - }, - { - "apiVersion": "2017-07-01-preview", - "type": "Microsoft.ServiceFabric/clusters", - "name": "[variables('clusterName')]", - "location": "[parameters('clusterLocation')]", - "dependsOn": [ - "[concat('Microsoft.Storage/storageAccounts/', variables('supportLogStorageAccountName'))]" - ], - "properties": { - "addonFeatures": [ - "DnsService" - ], - "clientCertificateCommonNames": [], - "clientCertificateThumbprints": [], - "clusterCodeVersion": "6.0.232.9494", - "clusterState": "Default", - "diagnosticsStorageAccountConfig": { - "blobEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', variables('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.blob]", - "protectedAccountKeyName": "StorageAccountKey1", - "queueEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', variables('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.queue]", - "storageAccountName": "[variables('supportLogStorageAccountName')]", - "tableEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', variables('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.table]" - }, - "fabricSettings": [], - "managementEndpoint": "[concat('http://',reference(concat(parameters('lbIPName'),'-','0')).dnsSettings.fqdn,':',parameters('nt0fabricHttpGatewayPort'))]", - "nodeTypes": [ - { - "name": "[parameters('vmNodeType0Name')]", - "applicationPorts": { - "endPort": "[parameters('nt0applicationEndPort')]", - "startPort": "[parameters('nt0applicationStartPort')]" - }, - "clientConnectionEndpointPort": "[parameters('nt0fabricTcpGatewayPort')]", - "durabilityLevel": "Bronze", - "ephemeralPorts": { - "endPort": "[parameters('nt0ephemeralEndPort')]", - "startPort": "[parameters('nt0ephemeralStartPort')]" - }, - "httpGatewayEndpointPort": "[parameters('nt0fabricHttpGatewayPort')]", - "isPrimary": true, - "reverseProxyEndpointPort": "[parameters('nt0reverseProxyEndpointPort')]", - "vmInstanceCount": "[parameters('nt0InstanceCount')]" - } - ], - "provisioningState": "Default", - "reliabilityLevel": "None", - "upgradeMode": "Manual", - "vmImage": "Windows" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[variables('clusterName')]" - } - } - ], - "outputs": { - "clusterProperties": { - "value": "[reference(variables('clusterName'))]", - "type": "object" - } - } -} \ No newline at end of file diff --git a/deploy/azure/az/servicefabric/WindowsContainers/servicefabricdeploy.parameters.json b/deploy/azure/az/servicefabric/WindowsContainers/servicefabricdeploy.parameters.json deleted file mode 100644 index af7e1a6ee..000000000 --- a/deploy/azure/az/servicefabric/WindowsContainers/servicefabricdeploy.parameters.json +++ /dev/null @@ -1,100 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "prefix": { - "value": "qa" - }, - "clusterName": { - "value": "-eshop-sfwin-cluster" - }, - "clusterLocation": { - "value": "westus" - }, - "computeLocation": { - "value": "westus" - }, - "adminUserName": { - "value": "testedu" - }, - "adminPassword": { - "value": "testedu1234!" - }, - "nicName": { - "value": "NIC-eshopsfwin" - }, - "publicIPAddressName": { - "value": "eshopsfwin-PubIP" - }, - "dnsName": { - "value": "testedu-eshop-sfwin-cluster" - }, - "virtualNetworkName": { - "value": "VNet-eshopsfwin" - }, - "lbName": { - "value": "LB-eshopsfwin" - }, - "lbIPName": { - "value": "LBIP-eshopsfwin" - }, - "applicationDiagnosticsStorageAccountName": { - "value": "sfdiageshopw" - }, - "supportLogStorageAccountName": { - "value": "sflogeshopw" - }, - "vmImageSku": { - "value": "2016-Datacenter-with-Containers" - }, - "nt0ephemeralStartPort": { - "value": 49152 - }, - "nt0ephemeralEndPort": { - "value": 65534 - }, - "nt0applicationStartPort": { - "value": 20000 - }, - "nt0applicationEndPort": { - "value": 30000 - }, - "nt0fabricTcpGatewayPort": { - "value": 19000 - }, - "nt0fabricHttpGatewayPort": { - "value": 19080 - }, - "nt0reverseProxyEndpointPort": { - "value": 19081 - }, - "webMvcHttpPort": { - "value": 5100 - }, - "webSpaHttpPort": { - "value": 5104 - }, - "webStatusHttpPort": { - "value": 5107 - }, - "IdSrvHttpRule": { - "value": 5105 - }, - "BasketApiHttpRule": { - "value": 5103 - }, - "CatalogApiHttpRule": { - "value": 5101 - }, - "OrderingApiHttpRule": { - "value": 5102 - }, - "MarketingApiHttpRule": { - "value": 5110 - }, - "LocationsApiHttpRule": { - "value": 5109 - } - } -} - diff --git a/deploy/azure/az/servicefabric/WindowsContainers/servicefabricdeploysecured.json b/deploy/azure/az/servicefabric/WindowsContainers/servicefabricdeploysecured.json deleted file mode 100644 index 843f5c0d1..000000000 --- a/deploy/azure/az/servicefabric/WindowsContainers/servicefabricdeploysecured.json +++ /dev/null @@ -1,924 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json", - "contentVersion": "1.0.0.0", - "parameters": { - "clusterLocation": { - "type": "string", - "metadata": { - "description": "Location of the Cluster" - } - }, - "clusterName": { - "type": "string", - "defaultValue": "Cluster", - "metadata": { - "description": "Name of your cluster - Between 3 and 23 characters. Letters and numbers only" - } - }, - "nt0applicationStartPort": { - "type": "int", - "defaultValue": 20000 - }, - "nt0applicationEndPort": { - "type": "int", - "defaultValue": 30000 - }, - "nt0ephemeralStartPort": { - "type": "int", - "defaultValue": 49152 - }, - "nt0ephemeralEndPort": { - "type": "int", - "defaultValue": 65534 - }, - "nt0fabricTcpGatewayPort": { - "type": "int", - "defaultValue": 19000 - }, - "nt0fabricHttpGatewayPort": { - "type": "int", - "defaultValue": 19080 - }, - "nt0reverseProxyEndpointPort": { - "type": "int", - "defaultValue": 19081 - }, - "webMvcHttpPort": { - "type": "int", - "defaultValue": 5100 - }, - "webSpaHttpPort": { - "type": "int", - "defaultValue": 5104 - }, - "webStatusHttpPort": { - "type": "int", - "defaultValue": 5107 - }, - "IdSrvHttpRule": { - "type": "int", - "defaultValue": 5105 - }, - "BasketApiHttpRule": { - "type": "int", - "defaultValue": 5103 - }, - "CatalogApiHttpRule": { - "type": "int", - "defaultValue": 5101 - }, - "OrderingApiHttpRule": { - "type": "int", - "defaultValue": 5102 - }, - "MarketingApiHttpRule": { - "type": "int", - "defaultValue": 5110 - }, - "LocationsApiHttpRule": { - "type": "int", - "defaultValue": 5109 - }, - "subnet0Name": { - "type": "string", - "defaultValue": "Subnet-0" - }, - "subnet0Prefix": { - "type": "string", - "defaultValue": "10.0.0.0/24" - }, - "computeLocation": { - "type": "string" - }, - "publicIPAddressName": { - "type": "string", - "defaultValue": "PublicIP-VM" - }, - "publicIPAddressType": { - "type": "string", - "allowedValues": [ - "Dynamic" - ], - "defaultValue": "Dynamic" - }, - "vmStorageAccountContainerName": { - "type": "string", - "defaultValue": "vhds" - }, - "adminUserName": { - "type": "string", - "defaultValue": "testadm", - "metadata": { - "description": "Remote desktop user Id" - } - }, - "adminPassword": { - "type": "securestring", - "metadata": { - "description": "Remote desktop user password. Must be a strong password" - } - }, - "virtualNetworkName": { - "type": "string", - "defaultValue": "VNet" - }, - "addressPrefix": { - "type": "string", - "defaultValue": "10.0.0.0/16" - }, - "dnsName": { - "type": "string" - }, - "nicName": { - "type": "string", - "defaultValue": "NIC" - }, - "lbName": { - "type": "string", - "defaultValue": "LoadBalancer" - }, - "lbIPName": { - "type": "string", - "defaultValue": "PublicIP-LB-FE" - }, - "overProvision": { - "type": "string", - "defaultValue": "false" - }, - "vmImagePublisher": { - "type": "string", - "defaultValue": "MicrosoftWindowsServer" - }, - "vmImageOffer": { - "type": "string", - "defaultValue": "WindowsServer" - }, - "vmImageSku": { - "type": "string", - "defaultValue": "2012-R2-Datacenter" - }, - "vmImageVersion": { - "type": "string", - "defaultValue": "latest" - }, - "clusterProtectionLevel": { - "type": "string", - "allowedValues": [ - "None", - "Sign", - "EncryptAndSign" - ], - "defaultValue": "EncryptAndSign", - "metadata": { - "description": "Protection level.Three values are allowed - EncryptAndSign, Sign, None. It is best to keep the default of EncryptAndSign, unless you have a need not to" - } - }, - "certificateStoreValue": { - "type": "string", - "allowedValues": [ - "My" - ], - "defaultValue": "My", - "metadata": { - "description": "The store name where the cert will be deployed in the virtual machine" - } - }, - "certificateThumbprint": { - "type": "string", - "metadata": { - "description": "Certificate Thumbprint" - } - }, - "sourceVaultValue": { - "type": "string", - "metadata": { - "description": "Resource Id of the key vault, is should be in the format of /subscriptions//resourceGroups//providers/Microsoft.KeyVault/vaults/" - } - }, - "certificateUrlValue": { - "type": "string", - "metadata": { - "description": "Refers to the location URL in your key vault where the certificate was uploaded, it is should be in the format of https://.vault.azure.net:443/secrets/" - } - }, - "storageAccountType": { - "type": "string", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS" - ], - "defaultValue": "Standard_LRS", - "metadata": { - "description": "Replication option for the VM image storage account" - } - }, - "supportLogStorageAccountType": { - "type": "string", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS" - ], - "defaultValue": "Standard_LRS", - "metadata": { - "description": "Replication option for the support log storage account" - } - }, - "supportLogStorageAccountName": { - "type": "string", - "defaultValue": "[toLower( concat('sflogs', uniqueString(resourceGroup().id),'2'))]", - "metadata": { - "description": "Name for the storage account that contains support logs from the cluster" - } - }, - "applicationDiagnosticsStorageAccountType": { - "type": "string", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS" - ], - "defaultValue": "Standard_LRS", - "metadata": { - "description": "Replication option for the application diagnostics storage account" - } - }, - "applicationDiagnosticsStorageAccountName": { - "type": "string", - "defaultValue": "[toLower(concat(uniqueString(resourceGroup().id), '3' ))]", - "metadata": { - "description": "Name for the storage account that contains application diagnostics data from the cluster" - } - }, - "nt0InstanceCount": { - "type": "int", - "defaultValue": 5, - "metadata": { - "description": "Instance count for node type" - } - }, - "vmNodeType0Name": { - "type": "string", - "defaultValue": "primary", - "maxLength": 9 - }, - "vmNodeType0Size": { - "type": "string", - "defaultValue": "Standard_D2_v2" - } - }, - "variables": { - "vmssApiVersion": "2017-03-30", - "lbApiVersion": "2015-06-15", - "vNetApiVersion": "2015-06-15", - "storageApiVersion": "2016-01-01", - "publicIPApiVersion": "2015-06-15", - "vnetID": "[resourceId('Microsoft.Network/virtualNetworks',parameters('virtualNetworkName'))]", - "subnet0Ref": "[concat(variables('vnetID'),'/subnets/',parameters('subnet0Name'))]", - "lbID0": "[resourceId('Microsoft.Network/loadBalancers', concat('LB','-', parameters('clusterName'),'-',parameters('vmNodeType0Name')))]", - "lbIPConfig0": "[concat(variables('lbID0'),'/frontendIPConfigurations/LoadBalancerIPConfig')]", - "lbPoolID0": "[concat(variables('lbID0'),'/backendAddressPools/LoadBalancerBEAddressPool')]", - "lbProbeID0": "[concat(variables('lbID0'),'/probes/FabricGatewayProbe')]", - "lbHttpProbeID0": "[concat(variables('lbID0'),'/probes/FabricHttpGatewayProbe')]", - "lbNatPoolID0": "[concat(variables('lbID0'),'/inboundNatPools/LoadBalancerBEAddressNatPool')]", - "vmStorageAccountName0": "[toLower(concat(uniqueString(resourceGroup().id), '1', '0' ))]", - "uniqueStringArray0": [ - "[concat(variables('vmStorageAccountName0'), '0')]", - "[concat(variables('vmStorageAccountName0'), '1')]", - "[concat(variables('vmStorageAccountName0'), '2')]", - "[concat(variables('vmStorageAccountName0'), '3')]", - "[concat(variables('vmStorageAccountName0'), '4')]" - ] - }, - "resources": [ - { - "apiVersion": "[variables('storageApiVersion')]", - "type": "Microsoft.Storage/storageAccounts", - "name": "[parameters('supportLogStorageAccountName')]", - "location": "[parameters('computeLocation')]", - "dependsOn": [], - "properties": {}, - "kind": "Storage", - "sku": { - "name": "[parameters('supportLogStorageAccountType')]" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "[variables('storageApiVersion')]", - "type": "Microsoft.Storage/storageAccounts", - "name": "[parameters('applicationDiagnosticsStorageAccountName')]", - "location": "[parameters('computeLocation')]", - "dependsOn": [], - "properties": {}, - "kind": "Storage", - "sku": { - "name": "[parameters('applicationDiagnosticsStorageAccountType')]" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "[variables('vNetApiVersion')]", - "type": "Microsoft.Network/virtualNetworks", - "name": "[parameters('virtualNetworkName')]", - "location": "[parameters('computeLocation')]", - "dependsOn": [], - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[parameters('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[parameters('subnet0Name')]", - "properties": { - "addressPrefix": "[parameters('subnet0Prefix')]" - } - } - ] - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "[variables('publicIPApiVersion')]", - "type": "Microsoft.Network/publicIPAddresses", - "name": "[concat(parameters('lbIPName'),'-','0')]", - "location": "[parameters('computeLocation')]", - "properties": { - "dnsSettings": { - "domainNameLabel": "[parameters('dnsName')]" - }, - "publicIPAllocationMethod": "Dynamic" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "[variables('lbApiVersion')]", - "type": "Microsoft.Network/loadBalancers", - "name": "[concat('LB','-', parameters('clusterName'),'-',parameters('vmNodeType0Name'))]", - "location": "[parameters('computeLocation')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/',concat(parameters('lbIPName'),'-','0'))]" - ], - "properties": { - "frontendIPConfigurations": [ - { - "name": "LoadBalancerIPConfig", - "properties": { - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses',concat(parameters('lbIPName'),'-','0'))]" - } - } - } - ], - "backendAddressPools": [ - { - "name": "LoadBalancerBEAddressPool", - "properties": {} - } - ], - "loadBalancingRules": [ - { - "name": "LBRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('nt0fabricTcpGatewayPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('nt0fabricTcpGatewayPort')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "LBHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('nt0fabricHttpGatewayPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('nt0fabricHttpGatewayPort')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbHttpProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "ReverseProxyHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('nt0reverseProxyEndpointPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('nt0reverseProxyEndpointPort')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbHttpProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "WebMVCHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('webMvcHttpPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('webMvcHttpPort')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbHttpProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "WebSPAHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('webSpaHttpPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('webSpaHttpPort')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbHttpProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "WebStatusHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('webStatusHttpPort')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('webStatusHttpPort')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbHttpProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "IdSrvHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('IdSrvHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('IdSrvHttpRule')]", - "idleTimeoutInMinutes": "5", - "probe": { - "id": "[variables('lbHttpProbeID0')]" - }, - "protocol": "tcp" - } - }, - { - "name": "BasketApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('BasketApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('BasketApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "CatalogApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('CatalogApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('CatalogApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "OrderingApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('OrderingApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('OrderingApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "MarketingApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('MarketingApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('MarketingApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - }, - { - "name": "LocationsApiHttpRule", - "properties": { - "backendAddressPool": { - "id": "[variables('lbPoolID0')]" - }, - "backendPort": "[parameters('LocationsApiHttpRule')]", - "enableFloatingIP": "false", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPort": "[parameters('LocationsApiHttpRule')]", - "idleTimeoutInMinutes": "5", - "protocol": "tcp" - } - } - ], - "probes": [ - { - "name": "FabricGatewayProbe", - "properties": { - "intervalInSeconds": 5, - "numberOfProbes": 2, - "port": "[parameters('nt0fabricTcpGatewayPort')]", - "protocol": "tcp" - } - }, - { - "name": "FabricHttpGatewayProbe", - "properties": { - "intervalInSeconds": 5, - "numberOfProbes": 2, - "port": "[parameters('nt0fabricHttpGatewayPort')]", - "protocol": "tcp" - } - } - ], - "inboundNatPools": [ - { - "name": "LoadBalancerBEAddressNatPool", - "properties": { - "backendPort": "3389", - "frontendIPConfiguration": { - "id": "[variables('lbIPConfig0')]" - }, - "frontendPortRangeEnd": "4500", - "frontendPortRangeStart": "3389", - "protocol": "tcp" - } - } - ] - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "[variables('storageApiVersion')]", - "type": "Microsoft.Storage/storageAccounts", - "name": "[variables('uniqueStringArray0')[copyIndex()]]", - "location": "[parameters('computeLocation')]", - "dependsOn": [], - "properties": {}, - "copy": { - "name": "storageLoop", - "count": 5 - }, - "kind": "Storage", - "sku": { - "name": "[parameters('storageAccountType')]" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "[variables('vmssApiVersion')]", - "type": "Microsoft.Compute/virtualMachineScaleSets", - "name": "[parameters('vmNodeType0Name')]", - "location": "[parameters('computeLocation')]", - "dependsOn": [ - "[concat('Microsoft.Network/virtualNetworks/', parameters('virtualNetworkName'))]", - "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[0])]", - "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[1])]", - "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[2])]", - "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[3])]", - "[concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[4])]", - "[concat('Microsoft.Network/loadBalancers/', concat('LB','-', parameters('clusterName'),'-',parameters('vmNodeType0Name')))]", - "[concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName'))]", - "[concat('Microsoft.Storage/storageAccounts/', parameters('applicationDiagnosticsStorageAccountName'))]" - ], - "properties": { - "overprovision": "[parameters('overProvision')]", - "upgradePolicy": { - "mode": "Automatic" - }, - "virtualMachineProfile": { - "extensionProfile": { - "extensions": [ - { - "name": "[concat(parameters('vmNodeType0Name'),'_ServiceFabricNode')]", - "properties": { - "type": "ServiceFabricNode", - "autoUpgradeMinorVersion": true, - "protectedSettings": { - "StorageAccountKey1": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('supportLogStorageAccountName')),'2015-05-01-preview').key1]", - "StorageAccountKey2": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('supportLogStorageAccountName')),'2015-05-01-preview').key2]" - }, - "publisher": "Microsoft.Azure.ServiceFabric", - "settings": { - "clusterEndpoint": "[reference(parameters('clusterName')).clusterEndpoint]", - "nodeTypeRef": "[parameters('vmNodeType0Name')]", - "dataPath": "D:\\\\SvcFab", - "durabilityLevel": "Bronze", - "enableParallelJobs": true, - "nicPrefixOverride": "[parameters('subnet0Prefix')]", - "certificate": { - "thumbprint": "[parameters('certificateThumbprint')]", - "x509StoreName": "[parameters('certificateStoreValue')]" - } - }, - "typeHandlerVersion": "1.0" - } - }, - { - "name": "[concat('VMDiagnosticsVmExt','_vmNodeType0Name')]", - "properties": { - "type": "IaaSDiagnostics", - "autoUpgradeMinorVersion": true, - "protectedSettings": { - "storageAccountName": "[parameters('applicationDiagnosticsStorageAccountName')]", - "storageAccountKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('applicationDiagnosticsStorageAccountName')),'2015-05-01-preview').key1]", - "storageAccountEndPoint": "https://core.windows.net/" - }, - "publisher": "Microsoft.Azure.Diagnostics", - "settings": { - "WadCfg": { - "DiagnosticMonitorConfiguration": { - "overallQuotaInMB": "50000", - "EtwProviders": { - "EtwEventSourceProviderConfiguration": [ - { - "provider": "Microsoft-ServiceFabric-Actors", - "scheduledTransferKeywordFilter": "1", - "scheduledTransferPeriod": "PT5M", - "DefaultEvents": { - "eventDestination": "ServiceFabricReliableActorEventTable" - } - }, - { - "provider": "Microsoft-ServiceFabric-Services", - "scheduledTransferPeriod": "PT5M", - "DefaultEvents": { - "eventDestination": "ServiceFabricReliableServiceEventTable" - } - } - ], - "EtwManifestProviderConfiguration": [ - { - "provider": "cbd93bc2-71e5-4566-b3a7-595d8eeca6e8", - "scheduledTransferLogLevelFilter": "Information", - "scheduledTransferKeywordFilter": "4611686018427387904", - "scheduledTransferPeriod": "PT5M", - "DefaultEvents": { - "eventDestination": "ServiceFabricSystemEventTable" - } - } - ] - } - } - }, - "StorageAccount": "[parameters('applicationDiagnosticsStorageAccountName')]" - }, - "typeHandlerVersion": "1.5" - } - } - ] - }, - "networkProfile": { - "networkInterfaceConfigurations": [ - { - "name": "[concat(parameters('nicName'), '-0')]", - "properties": { - "ipConfigurations": [ - { - "name": "[concat(parameters('nicName'),'-',0)]", - "properties": { - "loadBalancerBackendAddressPools": [ - { - "id": "[variables('lbPoolID0')]" - } - ], - "loadBalancerInboundNatPools": [ - { - "id": "[variables('lbNatPoolID0')]" - } - ], - "subnet": { - "id": "[variables('subnet0Ref')]" - } - } - } - ], - "primary": true - } - } - ] - }, - "osProfile": { - "adminPassword": "[parameters('adminPassword')]", - "adminUsername": "[parameters('adminUsername')]", - "computernamePrefix": "[parameters('vmNodeType0Name')]", - "secrets": [ - { - "sourceVault": { - "id": "[parameters('sourceVaultValue')]" - }, - "vaultCertificates": [ - { - "certificateStore": "[parameters('certificateStoreValue')]", - "certificateUrl": "[parameters('certificateUrlValue')]" - } - ] - } - ] - }, - "storageProfile": { - "imageReference": { - "publisher": "[parameters('vmImagePublisher')]", - "offer": "[parameters('vmImageOffer')]", - "sku": "[parameters('vmImageSku')]", - "version": "[parameters('vmImageVersion')]" - }, - "osDisk": { - "caching": "ReadOnly", - "createOption": "FromImage", - "vhdContainers": [ - "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[0]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]", - "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[1]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]", - "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[2]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]", - "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[3]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]", - "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('uniqueStringArray0')[4]), variables('storageApiVersion')).primaryEndpoints.blob, parameters('vmStorageAccountContainerName'))]" - ], - "name": "vmssosdisk" - } - } - } - }, - "sku": { - "name": "[parameters('vmNodeType0Size')]", - "capacity": "[parameters('nt0InstanceCount')]", - "tier": "Standard" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - }, - { - "apiVersion": "2017-07-01-preview", - "type": "Microsoft.ServiceFabric/clusters", - "name": "[parameters('clusterName')]", - "location": "[parameters('clusterLocation')]", - "dependsOn": [ - "[concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName'))]" - ], - "properties": { - "addonFeatures": [ - "DnsService" - ], - "certificate": { - "thumbprint": "[parameters('certificateThumbprint')]", - "x509StoreName": "[parameters('certificateStoreValue')]" - }, - "clientCertificateCommonNames": [], - "clientCertificateThumbprints": [], - "clusterCodeVersion": "5.7.207.9494", - "clusterState": "Default", - "diagnosticsStorageAccountConfig": { - "blobEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.blob]", - "protectedAccountKeyName": "StorageAccountKey1", - "queueEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.queue]", - "storageAccountName": "[parameters('supportLogStorageAccountName')]", - "tableEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', parameters('supportLogStorageAccountName')), variables('storageApiVersion')).primaryEndpoints.table]" - }, - "fabricSettings": [ - { - "parameters": [ - { - "name": "ClusterProtectionLevel", - "value": "[parameters('clusterProtectionLevel')]" - } - ], - "name": "Security" - } - ], - "managementEndpoint": "[concat('https://',reference(concat(parameters('lbIPName'),'-','0')).dnsSettings.fqdn,':',parameters('nt0fabricHttpGatewayPort'))]", - "nodeTypes": [ - { - "name": "[parameters('vmNodeType0Name')]", - "applicationPorts": { - "endPort": "[parameters('nt0applicationEndPort')]", - "startPort": "[parameters('nt0applicationStartPort')]" - }, - "clientConnectionEndpointPort": "[parameters('nt0fabricTcpGatewayPort')]", - "durabilityLevel": "Bronze", - "ephemeralPorts": { - "endPort": "[parameters('nt0ephemeralEndPort')]", - "startPort": "[parameters('nt0ephemeralStartPort')]" - }, - "httpGatewayEndpointPort": "[parameters('nt0fabricHttpGatewayPort')]", - "isPrimary": true, - "reverseProxyEndpointPort": "[parameters('nt0reverseProxyEndpointPort')]", - "vmInstanceCount": "[parameters('nt0InstanceCount')]" - } - ], - "provisioningState": "Default", - "reliabilityLevel": "Silver", - "upgradeMode": "Manual", - "vmImage": "Windows" - }, - "tags": { - "resourceType": "Service Fabric", - "clusterName": "[parameters('clusterName')]" - } - } - ], - "outputs": { - "clusterProperties": { - "value": "[reference(parameters('clusterName'))]", - "type": "object" - } - } -} \ No newline at end of file diff --git a/deploy/azure/az/servicefabric/WindowsContainers/servicefabricdeploysecured.parameters.json b/deploy/azure/az/servicefabric/WindowsContainers/servicefabricdeploysecured.parameters.json deleted file mode 100644 index bbc8eb663..000000000 --- a/deploy/azure/az/servicefabric/WindowsContainers/servicefabricdeploysecured.parameters.json +++ /dev/null @@ -1,106 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "clusterName": { - "value": "pro-eshop-sfwin-cluster" - }, - "clusterLocation": { - "value": "westus" - }, - "computeLocation": { - "value": "westus" - }, - "adminUserName": { - "value": "eshop" - }, - "adminPassword": { - "value": "Your_complex_Pass@word1" - }, - "nicName": { - "value": "NIC-eshopsfwin" - }, - "publicIPAddressName": { - "value": "eshopsfwin-PubIP" - }, - "dnsName": { - "value": "pro-eshop-sfwin-cluster" - }, - "virtualNetworkName": { - "value": "VNet-eshopsfwin" - }, - "lbName": { - "value": "LB-eshopsfwin" - }, - "lbIPName": { - "value": "LBIP-eshopsfwin" - }, - "applicationDiagnosticsStorageAccountName": { - "value": "sfdgqaeshopsfwinsec" - }, - "supportLogStorageAccountName": { - "value": "sflogsqaeshopsfwinsec" - }, - "sourceVaultValue": { - "value": "your-value-check-keyvault-at-azure" - }, - "certificateUrlValue": { - "value": "your-value-check-keyvault-at-azure" - }, - "certificateThumbprint": { - "value": "your-value-check-keyvault-at-azure" - }, - "vmImageSku": { - "value": "2016-Datacenter-with-Containers" - }, - "nt0ephemeralStartPort": { - "value": 49152 - }, - "nt0ephemeralEndPort": { - "value": 65534 - }, - "nt0applicationStartPort": { - "value": 20000 - }, - "nt0applicationEndPort": { - "value": 30000 - }, - "nt0fabricTcpGatewayPort": { - "value": 19000 - }, - "nt0fabricHttpGatewayPort": { - "value": 19080 - }, - "nt0reverseProxyEndpointPort": { - "value": 19081 - }, - "webMvcHttpPort": { - "value": 5100 - }, - "webSpaHttpPort": { - "value": 5104 - }, - "webStatusHttpPort": { - "value": 5107 - }, - "IdSrvHttpRule": { - "value": 5105 - }, - "BasketApiHttpRule": { - "value": 5103 - }, - "CatalogApiHttpRule": { - "value": 5101 - }, - "OrderingApiHttpRule": { - "value": 5102 - }, - "MarketingApiHttpRule": { - "value": 5110 - }, - "LocationsApiHttpRule": { - "value": 5109 - } - } -} - diff --git a/deploy/azure/az/vms/docker-machine.md b/deploy/azure/az/vms/docker-machine.md deleted file mode 100644 index 71cbbd4a7..000000000 --- a/deploy/azure/az/vms/docker-machine.md +++ /dev/null @@ -1,48 +0,0 @@ -# Create a VM using docker-machine - -Ensure you are logged in the desired subscription Refer to [this article](https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli) for more details. - -1. Use `az account show` to find your subscription id. -2. Use `docker-machine create --driver azure --azure-subscription-id --azure-resource-group --azure-ssh-user ` - -After use `docker-machine create` you'll need to authenticate in Azure (even thought if you are logged using `az`, because this is not an Azure CLI 2.0 command). This command will fully create the VM with all the needed settings to run Docker. - -**Note** Refer to this article with all the [parameters that docker-machine accepts when creating Azure VMs](https://docs.docker.com/machine/drivers/azure/#options) for finding more parameters. - -## Connecting your local environment with docker host running on the VM - -Using docker-machine you control the remote VM from your local development environment (you don't need to use ssh to login to remote VM). - -Connecting your local environment to a remote host is using by setting some environment variables, but the easiest way is to use again the docker-machine command. Just type `docker-machine env machine_name` (where machine_name is the name you gave when you created the VM). That command **do not change anything**, so do'nt do really nothing, but **outputs the environment variables you have to set**. This is the output of the command (running on a windows workstation): - -``` -SET DOCKER_TLS_VERIFY=1 -SET DOCKER_HOST=tcp://104.42.236.237:2376 -SET DOCKER_CERT_PATH=C:\Users\etoma\.docker\machine\machines\ufohost -SET DOCKER_MACHINE_NAME=ufohost -SET COMPOSE_CONVERT_WINDOWS_PATHS=true -REM Run this command to configure your shell: -REM @FOR /f "tokens=*" %i IN ('docker-machine env ufohost') DO @%i -``` - -You have to set all these environment variables, or (as the command suggest) just copy and paste the last line in your terminal. - -Once you did this, your local development machine is connected to VM running Docker on Azure: all docker and docker-compose commands will run in the VM instead of your local Docker machine! - - - - - - - - - - - - - - - - - - diff --git a/deploy/azure/az/vms/linux-vm/linuxvm.json b/deploy/azure/az/vms/linux-vm/linuxvm.json deleted file mode 100644 index 5b4778ebe..000000000 --- a/deploy/azure/az/vms/linux-vm/linuxvm.json +++ /dev/null @@ -1,199 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "newStorageAccountName": { - "type": "string", - "metadata": { - "description": "Unique DNS Name for the Storage Account where the Virtual Machine's disks will be placed." - } - }, - "adminUsername": { - "type": "string", - "metadata": { - "description": "Username for the Virtual Machine." - } - }, - "adminPassword": { - "type": "securestring", - "metadata": { - "description": "Password for the Virtual Machine." - } - }, - "dnsNameForPublicIP": { - "type": "string", - "metadata": { - "description": "Unique DNS Name for the Public IP used to access the Virtual Machine." - } - }, - "ubuntuOSVersion": { - "type": "string", - "defaultValue": "14.04.4-LTS", - "metadata": { - "description": "The Ubuntu version for deploying the Docker containers. This will pick a fully patched image of this given Ubuntu version. Allowed values: 14.04.4-LTS, 15.10, 16.04.0-LTS" - }, - "allowedValues": [ - "14.04.4-LTS", - "15.10", - "16.04.0-LTS" - ] - }, - "VMName": { - "type": "string", - "metadata": { - "description": "Name of VM in Azure" - } - } - }, - "variables": { - "newStorageAccountName": "[take(concat(parameters('newStorageAccountName'), uniqueString(resourceGroup().id)), 23)]", - "dnsNameForPublicIP": "[concat(parameters('dnsNameForPublicIP'), uniqueString(resourceGroup().id))]", - "imagePublisher": "Canonical", - "imageOffer": "UbuntuServer", - "OSDiskName": "osdiskfordockersimple", - "nicName": "myVMNicD", - "extensionName": "DockerExtension", - "addressPrefix": "10.0.0.0/16", - "subnetName": "Subnet", - "subnetPrefix": "10.0.0.0/24", - "storageAccountType": "Standard_LRS", - "publicIPAddressName": "myPublicIPD", - "publicIPAddressType": "Dynamic", - "vmStorageAccountContainerName": "vhds", - "vmName": "[parameters('VMName')]", - "vmSize": "Standard_F1", - "virtualNetworkName": "MyVNETD", - "vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]" - }, - "resources": [ - { - "type": "Microsoft.Storage/storageAccounts", - "name": "[variables('newStorageAccountName')]", - "apiVersion": "2015-05-01-preview", - "location": "[resourceGroup().location]", - "properties": { - "accountType": "[variables('storageAccountType')]" - } - }, - { - "apiVersion": "2015-05-01-preview", - "type": "Microsoft.Network/publicIPAddresses", - "name": "[variables('publicIPAddressName')]", - "location": "[resourceGroup().location]", - "properties": { - "publicIPAllocationMethod": "[variables('publicIPAddressType')]", - "dnsSettings": { - "domainNameLabel": "[variables('dnsNameForPublicIP')]" - } - } - }, - { - "apiVersion": "2015-05-01-preview", - "type": "Microsoft.Network/virtualNetworks", - "name": "[variables('virtualNetworkName')]", - "location": "[resourceGroup().location]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetPrefix')]" - } - } - ] - } - }, - { - "apiVersion": "2015-05-01-preview", - "type": "Microsoft.Network/networkInterfaces", - "name": "[variables('nicName')]", - "location": "[resourceGroup().location]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig1", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - } - }, - { - "apiVersion": "2015-05-01-preview", - "type": "Microsoft.Compute/virtualMachines", - "name": "[variables('vmName')]", - "location": "[resourceGroup().location]", - "dependsOn": [ - "[concat('Microsoft.Storage/storageAccounts/', variables('newStorageAccountName'))]", - "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]" - ], - "properties": { - "hardwareProfile": { - "vmSize": "[variables('vmSize')]" - }, - "osProfile": { - "computerName": "[variables('vmName')]", - "adminUsername": "[parameters('adminUsername')]", - "adminPassword": "[parameters('adminPassword')]" - }, - "storageProfile": { - "imageReference": { - "publisher": "[variables('imagePublisher')]", - "offer": "[variables('imageOffer')]", - "sku": "[parameters('ubuntuOSVersion')]", - "version": "latest" - }, - "osDisk": { - "name": "osdisk1", - "vhd": { - "uri": "[concat('http://',variables('newStorageAccountName'),'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/',variables('OSDiskName'),'.vhd')]" - }, - "caching": "ReadWrite", - "createOption": "FromImage" - } - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]" - } - ] - } - } - }, - { - "type": "Microsoft.Compute/virtualMachines/extensions", - "name": "[concat(variables('vmName'),'/', variables('extensionName'))]", - "apiVersion": "2015-05-01-preview", - "location": "[resourceGroup().location]", - "dependsOn": [ - "[concat('Microsoft.Compute/virtualMachines/', variables('vmName'))]" - ], - "properties": { - "publisher": "Microsoft.Azure.Extensions", - "type": "DockerExtension", - "typeHandlerVersion": "1.0", - "autoUpgradeMinorVersion": true, - "settings": { } - } - } - ] -} - diff --git a/deploy/azure/az/vms/linux-vm/linuxvm.parameters.json b/deploy/azure/az/vms/linux-vm/linuxvm.parameters.json deleted file mode 100644 index d34dfd1d9..000000000 --- a/deploy/azure/az/vms/linux-vm/linuxvm.parameters.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "newStorageAccountName": { "value": "eshopsrvmvstorage" }, - "adminUsername": { "value": "eshop" }, - "adminPassword": { "value": "Pass@word" }, - "dnsNameForPublicIP": { "value": "eshop-srv" }, - "VMName": {"value": "MyDockerVM2"} -} diff --git a/deploy/azure/az/vms/plain-vm.md b/deploy/azure/az/vms/plain-vm.md deleted file mode 100644 index 4e06ed0d3..000000000 --- a/deploy/azure/az/vms/plain-vm.md +++ /dev/null @@ -1,77 +0,0 @@ -# Deploy a VM to run the services - -Follow these instructions to deploy a Linux-based VM with the Docker Host installed, or a VM with Windows Server 2016 plus -windows containers and Docker Daemon. - -**Note**: Use this option, only if you want to provide an environment using images pulled from DockerHub (for example, to create a test environment). If you want to -be able to deploy images built by yourself (but not pushed to DockerHub) follow the [instructions about using docker-machine](./docker-machine.md). - -You can use this machine to install the microservices and having a "development" environment (useful to develop and test the client apps). - -Please note that this deployment is not a production deployment. In a production-based scenario, you should deploy all containers in ACS. - -## Create the VM - -Ensure you are logged in the desired subscription (use `az login` and `az account set` if needed. Refer to [this article](https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli) for more details. - -Go to `linux-vm` or `win-vm` folder (based on if you want a Linux or Windows VM). Then: - -1. Edit the file `linuxvm.parameters.json` or `windowsvm.parameters.json` (based on what VM do you want to create) with your desired values -2. Run the [create-resources script](../readme.md) to deploy the desired template (`linux-vm/linuxvm.json` or `win-vm/windowsvm.json`). - -I. e. if you are in Windows and want to deploy a linux based VM, in a new resourcegroup located in westus, go to `deploy\az` folder and type: - -``` -create-resources.cmd vms\linux-vm\linuxvm newResourceGroup -c westus -``` - -**Note:** To avoid errors, ARM template used generates unique names for: - -1. VM used storage -2. Public DNS - -Those public names are based on the parameters set in the parameters file. - -### The parameters file (linuxvm.parameters.json or winsowsvm.parameters.json) - -Both files are identical and contains the minimum set of parameters needed by the ARM template to deploy the VM. ARM template accepts some other parameters (set with default values). Look the template for more info. - -The parameters defined are: - -1. `newStorageAccountName`: Name of the storage created for the VM. To ensure uniqueness a unique suffix will be added to this value. -2. `adminUsername`: Admin login -3. `adminPassword`: Admin password -4. `dnsNameForPublicIP`: DNS of the VM. To ensure uniqueness a unique suffix will be added to this value. -5. `VMName`: Name of the VM inside Azure - -## Finding the IP and DNS of the VM - -To find the IP and FQDN of the VM you can type `az vm list --resource-group --output table --show-details` (where resourcegroup is the -name of the resourcegroup where you created the VM). This command will generate output like: - -``` -Name ResourceGroup PowerState PublicIps Fqdns Location ----------- --------------- ------------ ------------- ------------------------------------------------ ---------- -MyDockerVM MyResourceGroup VM running xx.xx.xxx.xxx eshop-srvxxxxxxxxxxxxx.westus.cloudapp.azure.com westus -``` - -You can use this information to connect your new VM. - -## Deploy services in the VM - -We are providing public images of the services in DockerHub (https://hub.docker.com/u/eshop/). To use these images, just create a folder in the VM and copy -following files to it (those files are in the root of the repo): - -1. `docker-compose.nobuild.yml` -2. `docker-compose.prod.yml` - -**Note:** The `docker-compose.nobuild.yml` is just a version of the `docker-compose.yml` without the `build` section. Is neede due [docker-compose bug](https://github.com/docker/compose/issues/2945). - -Then log into the VM and run the command `docker-compose -f docker-compose.nobuild.yml -f docker-compose.prod.yml up --no-build -d` to start all the microservices. - - - - - - - diff --git a/deploy/azure/az/vms/readme.md b/deploy/azure/az/vms/readme.md deleted file mode 100644 index 25085f75c..000000000 --- a/deploy/azure/az/vms/readme.md +++ /dev/null @@ -1,10 +0,0 @@ -## Create VM with Docker installed - -There are two options for creating VM machines with Docker installed: - -1. [Deploying a Linux VM to run single-server development environment using docker-machine (**Recommended for development environments**)](./docker-machine.md) -2. [Deploying a Linux VM or Windows Server 2016 to run a single-server development environment using ARM template (**Recommended for creating testing environments**)](./plain-vm.md) - -If you want to create a VM for deploying images you build locally, then use the first option. - -If you want to create a VM to run images deployed to DockerHub (to provide some test environment) then use the second option. \ No newline at end of file diff --git a/deploy/azure/az/vms/win-vm/windowsvm.json b/deploy/azure/az/vms/win-vm/windowsvm.json deleted file mode 100644 index 78bebdfef..000000000 --- a/deploy/azure/az/vms/win-vm/windowsvm.json +++ /dev/null @@ -1,290 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - - "VMName": { - "type": "string", - "metadata": { - "description": "This name will also be used to prefix the network security group, storage, virtual network, network card, subnet and public IP address name." - } - }, - - "adminUsername": { - "type": "string", - "metadata": { - "description": "Username for the Virtual Machine." - } - }, - - "adminPassword": { - "type": "securestring", - "metadata": { - "description": "Password for the Virtual Machine." - } - }, - - "dnsNameForPublicIP": { - "type": "string", - "metadata": { - "description": "Unique DNS Name for the Public IP used to access the Virtual Machine." - } - }, - - "newStorageAccountName": { - "type": "string", - "metadata": { - "description": "Storage name for the Virtual Machine." - } - }, - "vmSize": { - "type": "string", - "defaultValue": "Standard_D1", - "metadata": { - "description": "VM Size" - } - } - }, - - "variables": { - "newStorageAccountName": "[take(concat(parameters('newStorageAccountName'), uniqueString(resourceGroup().id)), 23)]", - "dnsNameForPublicIP": "[concat(parameters('dnsNameForPublicIP'), uniqueString(resourceGroup().id))]", - "windowsOSVersion": "2016-Datacenter", - "imagePublisher": "MicrosoftWindowsServer", - "imageOffer": "WindowsServer", - "OSDiskName": "[concat(parameters('VMName'),'_osdisk')]", - "nicName": "[concat(parameters('VMName'),'_nic')]", - "addressPrefix": "10.0.0.0/16", - "subnetName": "[concat(parameters('VMName'),'_subnet')]", - "subnetPrefix": "10.0.0.0/24", - "networkSecurityGroupName": "[concat(parameters('VMName'),'_nsg')]", - "storageAccountType": "Standard_LRS", - "publicIPAddressName": "[concat(parameters('VMName'),'_pubip')]", - "publicIPAddressType": "Dynamic", - "vmStorageAccountContainerName": "vhds", - "apiVersion": "2015-05-01-preview", - "virtualNetworkName": "[concat(parameters('VMName'),'_vnet')]", - "vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]", - "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]" - }, - "resources": [ - { - "type": "Microsoft.Network/networkSecurityGroups", - "name": "[variables('networkSecurityGroupName')]", - "apiVersion": "[variables('apiVersion')]", - "location": "[resourceGroup().location]", - "properties": { - "securityRules": [ - { - "name": "HTTP", - "properties": { - "description": "HTTP", - "protocol": "Tcp", - "sourcePortRange": "*", - "destinationPortRange": "80", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 100, - "direction": "Inbound" - } - }, - - { - "name": "RDP", - "properties": { - "description": "RDP", - "protocol": "Tcp", - "sourcePortRange": "*", - "destinationPortRange": "3389", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 200, - "direction": "Inbound" - } - }, - - { - "name": "Docker", - "properties": { - "description": "Docker", - "protocol": "Tcp", - "sourcePortRange": "*", - "destinationPortRange": "2375", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 300, - "direction": "Inbound" - } - } - - ] - } - }, - - { - "type": "Microsoft.Storage/storageAccounts", - "name": "[variables('newStorageAccountName')]", - "apiVersion": "[variables('apiVersion')]", - "location": "[resourceGroup().location]", - "tags": { - "displayName": "StorageAccount" - }, - "properties": { - "accountType": "[variables('storageAccountType')]" - } - }, - - { - "apiVersion": "[variables('apiVersion')]", - "type": "Microsoft.Network/publicIPAddresses", - "name": "[variables('publicIPAddressName')]", - "location": "[resourceGroup().location]", - "tags": { - "displayName": "PublicIPAddress" - }, - "properties": { - "publicIPAllocationMethod": "[variables('publicIPAddressType')]", - "dnsSettings": { - "domainNameLabel": "[tolower(variables('dnsNameForPublicIP'))]" - } - } - }, - - { - "apiVersion": "[variables('apiVersion')]", - "type": "Microsoft.Network/virtualNetworks", - "name": "[variables('virtualNetworkName')]", - "location": "[resourceGroup().location]", - "dependsOn": [ - "[concat('Microsoft.Network/networkSecurityGroups/', variables('networkSecurityGroupName'))]" - ], - "tags": { - "displayName": "VirtualNetwork" - }, - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetPrefix')]", - "networkSecurityGroup": { - "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]" - } - } - } - ] - } - }, - - { - "apiVersion": "[variables('apiVersion')]", - "type": "Microsoft.Network/networkInterfaces", - "name": "[variables('nicName')]", - "location": "[resourceGroup().location]", - "tags": { - "displayName": "NetworkInterface" - }, - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig1", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]" - }, - "subnet": { - "id": "[variables('subnetRef')]" - } - } - } - ] - } - }, - - { - "apiVersion": "[variables('apiVersion')]", - "type": "Microsoft.Compute/virtualMachines", - "name": "[parameters('VMName')]", - "location": "[resourceGroup().location]", - "tags": { - "displayName": "VirtualMachine" - }, - "dependsOn": [ - "[concat('Microsoft.Storage/storageAccounts/', variables('newStorageAccountName'))]", - "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]" - ], - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "osProfile": { - "computername": "[parameters('VMName')]", - "adminUsername": "[parameters('adminUsername')]", - "adminPassword": "[parameters('adminPassword')]" - }, - "storageProfile": { - "imageReference": { - "publisher": "[variables('imagePublisher')]", - "offer": "[variables('imageOffer')]", - "sku": "[variables('windowsOSVersion')]", - "version": "latest" - }, - "osDisk": { - "name": "osdisk", - "vhd": { - "uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('newStorageAccountName')), variables('apiVersion')).primaryEndpoints.blob, variables('vmStorageAccountContainerName'),'/',variables('OSDiskName'),'.vhd')]" - }, - "caching": "ReadWrite", - "createOption": "FromImage" - } - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]" - } - ] - } - }, - "resources": [ - { - "name": "containerConfiguration", - "type": "extensions", - "location": "[resourceGroup().location]", - "apiVersion": "2015-06-15", - "dependsOn": [ - "[concat('Microsoft.Compute/virtualMachines/', parameters('VMName'))]" - ], - "tags": { - "displayName": "containerConfiguration" - }, - "properties": { - "publisher": "Microsoft.Compute", - "type": "CustomScriptExtension", - "typeHandlerVersion": "1.2", - "autoUpgradeMinorVersion": true, - "settings": { - "fileUris": [ - "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/windows-server-containers-preview/azure-containers.ps1" - ], - "commandToExecute": "[concat('powershell.exe -ExecutionPolicy Unrestricted -File azure-containers.ps1 -adminuser ',parameters('adminUsername'))]" - } - } - } - ] - } - ] -} \ No newline at end of file diff --git a/deploy/azure/az/vms/win-vm/windowsvm.parameters.json b/deploy/azure/az/vms/win-vm/windowsvm.parameters.json deleted file mode 100644 index 7a2773a54..000000000 --- a/deploy/azure/az/vms/win-vm/windowsvm.parameters.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "newStorageAccountName": { "value": "eshopsrvmvstoragewin" }, - "adminUsername": { "value": "eshop" }, - "adminPassword": { "value": "Pass@word" }, - "dnsNameForPublicIP": { "value": "eshop-srv-win" }, - "VMName": {"value": "eshop-srv-win"} -} diff --git a/deploy/k8s/README.CICD.k8s.md b/deploy/k8s/README.CICD.k8s.md deleted file mode 100644 index 40dbb8739..000000000 --- a/deploy/k8s/README.CICD.k8s.md +++ /dev/null @@ -1,66 +0,0 @@ -# Kubernetes CI/CD VSTS -For k8s CI/CD pipeline delivery a series of tasks must be created in VSTS to deploy k8s in Azure - -## Prerequisites -* A Kubernetes cluster. Follow Azure Container Service's [walkthrough](https://docs.microsoft.com/en-us/azure/container-service/container-service-kubernetes-walkthrough) to create one. -* A private Docker registry. Follow Azure Container Registry's [guide](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-get-started-portal) to create one. -* Optionally, previous steps can be skipped if you run gen-k8s-env.ps1 (or gen-k8s-env-aks.ps1 if you would like to use AKS instead of ACS) script to automatically create the azure environment needed for kubernetes deployment. Azure cli 2.0 must be previously installed [installation guide](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli). For example: - ->``` ->./gen-k8s-env -resourceGroupName k8sGroup -location westeurope -registryName k8sregistry -orchestratorName k8s-cluster -dnsName k8s-dns ->``` -or using AKS instead of ACS ->``` ->./gen-k8s-env-aks -resourceGroupName k8sGroup -location westeurope -registryName k8sregistry -dnsName k8s-dns -serviceName k8s-cluster -createAcr true -nodeCount 3 -nodeVMSize Standard_D2_v2 ->``` -* An `Azure Blob storage`. It is needed for storing the kubernetes config file used by the hosted agent to access to Kubernetes cluster. Example: - - - -* Upload the `kubernetes config file` to the blob storage previously created. Execute the following command which will download the config file into the directory `c:\Users\\.kube\` and then, upload it to your blob storage: - ->``` ->https://eshopk8s.blob.core.windows.net/k8s-config/config ->``` - -## Create the VSTS tasks -1. Create a `Download File` task to download the kubernetes binary `kubectl` to the hosted agent. For example: - ->``` ->https://storage.googleapis.com/kubernetes-release/release/v1.8.5/bin/windows/386/kubectl.exe ->``` - - - -2. Create a Download File task to download the kubernetes config file to the hosted agent. For example: - ->``` ->https://eshopk8s.blob.core.windows.net/k8s-config/config ->``` - - -3. Create a powershell task to execute the k8s deployment script. For example: - -* Deployment script path - ->``` ->$(System.DefaultWorkingDirectory)/All Microservices/docker-compose/deploy.ps1 ->``` - -* Deployment script path arguments. Use value: - ->``` ->-deployCI $true -execPath '$(System.DefaultWorkingDirectory)/' -kubeconfigPath '$(System.DefaultWorkingDirectory)/' -deployInfrastructure $true -imageTag dev -configFile '$(System.DefaultWorkingDirectory)/$(Build.DefinitionName)/docker-compose/conf_local.yml' ->``` - - -- deployCI: Must be set to `$true`. This avoids create images (always are pulled from registry) and compile bits. -- deployInfrastructure: Can be set to `$false` if don't want to deploy infrastructure containers (like Redis, rabbit, SQL,...). -- imageTag: Image tag to pull from k8s. -- configFile: Configuration file (refer to [README.k8s.md](./README.k8s.md) for more info). This file is part of the VSTS build output. -- execPath: path where the k8s binary is stored -- kubeconfigPath: path where the k8s config file is stored - - You can use additional parameters (i.e. pass registry and user/password to use custom registry instead of DockerHub. Plase, refer to [README.k8s.md](./README.k8s.md) for more info. - - diff --git a/deploy/k8s/README.k8s.md b/deploy/k8s/README.k8s.md deleted file mode 100644 index 84d9a72f0..000000000 --- a/deploy/k8s/README.k8s.md +++ /dev/null @@ -1,98 +0,0 @@ -# eShopOnContainers on Kubernetes -The k8s directory contains Kubernetes configuration for the eShopOnContainers app and a PowerShell script to deploy it to a cluster. Each eShopOnContainers microservice has a deployment configuration in `deployments.yaml`, and is exposed to the cluster by a service in `services.yaml`. The microservices are exposed externally on individual routes (`/basket-api`, `/webmvc`, etc.) by an nginx reverse proxy specified in `frontend.yaml` and `nginx.conf`. - -## Prerequisites -* A Kubernetes cluster. Follow Azure Container Service's [walkthrough](https://docs.microsoft.com/en-us/azure/container-service/container-service-kubernetes-walkthrough) to create one. -* A private Docker registry. Follow Azure Container Registry's [guide](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-get-started-portal) to create one. -* Optionally, previous steps can be skipped if you run the **gen-k8s-env-aks.ps1** script to create an AKS cluster environment or gen-k8s-env.ps1 script to create an ACS for Kuberentes cluster environment including the creation of additional Azure environment needed like an Azure Resource Manager and ACR registry. - -Azure cli 2.0 must be previously installed [installation guide](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli). For example: - - **Important**: Note the parameter "-createAcr true". If you are creating the K8s cluster but you want to re-use and existing ACR, say "-createAcr false". - - -For AKS: - ->``` ->./gen-k8s-env-aks -resourceGroupName YoureShopAksResgroup -location centralus -serviceName YoureShopAksCluster -dnsNamePrefix youreshopaks -registryName YoureShopAcrRegistry -createAcr true -nodeCount 3 -nodeVMSize Standard_D2_v2 ->``` - -For ACS: - ->``` ->./gen-k8s-env-aks -resourceGroupName k8sGroup -location westeurope -registryName k8sregistry -serviceName k8s-cluster -createAcr true -nodeCount 3 -nodeVMSize Standard_D2_v2 ->``` - -* A Docker development environment with `docker` and `docker-compose`. - * Visit [docker.com](https://docker.com) to download the tools and set up the environment. Docker's [installation guide](https://docs.docker.com/engine/getstarted/step_one/#step-3-verify-your-installation) covers verifying your Docker installation. -* The Kubernetes command line client, `kubectl`. - * This can be installed with the `az` tool as described in the Azure Container Service [walkthrough](https://docs.microsoft.com/en-us/azure/container-service/container-service-kubernetes-walkthrough). `az` is also helpful for getting the credentials `kubectl` needs to access your cluster. For other installation options, and information about configuring `kubectl` yourself, see the [Kubernetes documentation](https://kubernetes.io/docs/tasks/kubectl/install/). - -## Deploy the application with the deployment script -1. Open a PowerShell command line at the `k8s` directory of your local eShopOnContainers repository. -1. Ensure `docker`, `docker-compose`, and `kubectl` are on the path, and configured for your Docker machine and Kubernetes cluster. -1. Run `deploy.ps1` with your registry information. The Docker username and password are provided by Azure Container Registry, and can be retrieved from the Azure portal. Optionally, ACR credentials can be obtained by running the following command: - ->``` ->az acr credential show -n eshopregistry ->``` - -Once the user and password are retrieved, run the following script for deployment. For example: - ->``` ->./deploy.ps1 -registry myregistry.azurecr.io -dockerUser User -dockerPassword SecretPassword -configFile file_with_config.yaml ->``` - -The parameter `configFile` is important (and mandatory) because it contains the configuration used for the Pods in Kubernetes. This allow deploying Pods that use your own resources in Azure or any other cloud provider. A configuration file `conf_local.yaml` is provided which configures Pods to use the infrastructure containers (that is sql server, rabbitmq, redis and mongodb must be deployed also in the k8s). - -The script will build the code and corresponding Docker images, push the later to your registry, and deploy the application to your cluster. You can watch the deployment unfold from the Kubernetes web interface: run `kubectl proxy` and open a browser to [http://localhost:8001/ui](http://localhost:8001/ui) - -### Pods configuration file - -When deploying to k8s the script needs the `configFile` parameter with the location of the YAML configuration file. This file contains the configuration of the pods. The file is a .YAML file. For reference another configuration file (conf_cloud.yaml) is provided but without valid values. - -If you deploy the infrastructure containers use `conf_local.yaml` as a value for `configFile` parameter. If you don't deploy the infrastructure containers use your own configuration file with the correct values. - -### Parameters of the deploy.ps1 script - -The script accepts following parameters: - -+ `registry`: Name of the Docker registry to use. If not passed DockerHub is assumed -+ `dockerUser`: Login to use for the Docker registry (if needed) -+ `dockerPassword`: Password to use for the Docker registry (if needed) -+ `execPath`: Location of `kubectl` (if not in the path). If passed must finish with the path character. -+ `kubeconfigPath`: Location of the `kubectl` configuration file. **This parameter is used only in the CI pipeline**, so you don't need to pass it when invoking the script using the CLI. -+ `configFile`: Location of the Yaml file with the `externalcfg` configmap to be deployed. This configmap is used to configure the Pod's environment **This parameter is mandatory** -+ `imageTag`: Tag of the images to deploy to k8s. If not passed the name of the current branch is used. -+ `externalDns`: External DNS name of the k8s. This is only needed if you have configured a DNS that points to your k8s external IP. If you don't have any DNS configured do not pass this parameter. -+ `deployCI`: If `true` means that script is running under the context of a VSTS Hosted Build Agent. **You should never use this parameter from CLI** -+ `buildBits`: means that the source code of eShopOnContainers will be built. If you have built your code (and have all projects published in `obj/Docker/publish`) do not pass this parameter. Default value is `false` -+ `buildImages`: If `true` (default value) Docker images are built and pushed in the Docker registry. If you set this parameter to `false`, Docker images won't be built nor pushed in the Docker registry (but k8s' deployments and services will be redeployed). -+ `deployInfrastructure`: If `true` infrastructure containers (rabbitmq, mongo, redis, sql) will be deployed in k8s. If `false` those containers (and its related deployments and services in k8s) won't be deployed. -+ `dockerOrg`: Name of the organization in the registry where the images are (or will be pushed). Default value is `eshop` (which has images provided by Microsoft) - -**Important:** If you **don't pass the `-buildBits $true` the script won't build and publish the projects** to their `obj/Docker/publish` folder. If any project is not published, you'll be receiving errors like: - -``` -ERROR: Service 'xxxxxxx' failed to build: COPY failed: stat /var/lib/docker/tmp/docker-builder123456789/obj/Docker/publish: no such file or directory -``` - -### Typical usages of the script: - -Build all projects, and deploy all them in k8s including infrastructure containers in a organization called `foo` in Docker Hub. Images will be tagged with my current git branch and containers will use the configuration set in `conf_local.yml` file: - -``` -./deploy.ps1 -buildBits $true -dockerOrg foo -dockerUser MY_USER -dockerPassword MY_PASSWORD -configFile conf_local.yml -``` - -Do not build any project and don't rebuild docker images. Create k8s deployments that will pull images from my private repository, in the `foo` organization, using the tag `latest`. Containers will use the configuration set in `conf_cloud` file. - -``` -./deploy.ps1 -buildImages $false -dockerOrg foo -registry MY_REGISTRY_FQDN -dockerUser MY_USER -dockerPassword MY_PASSWORD -configFile conf_cloud.yml -imageTag master -``` - -Deploy k8s using public images that Microsoft provides: - -``` -./deploy.ps1 -buildImages $false -configFile conf_local.yml -imageTag master -``` diff --git a/deploy/k8s/build-push-images.ps1 b/deploy/k8s/build-push-images.ps1 deleted file mode 100644 index e2c8e06b6..000000000 --- a/deploy/k8s/build-push-images.ps1 +++ /dev/null @@ -1,72 +0,0 @@ -Param( - [parameter(Mandatory=$false)][string]$registry, - [parameter(Mandatory=$false)][string]$dockerUser, - [parameter(Mandatory=$false)][string]$dockerPassword, - [parameter(Mandatory=$false)][string]$imageTag, - [parameter(Mandatory=$false)][bool]$buildImages=$true, - [parameter(Mandatory=$false)][bool]$pushImages=$true, - [parameter(Mandatory=$false)][string]$dockerOrg="eshop" -) - -# Initialization - -$useDockerHub = [string]::IsNullOrEmpty($registry) - -# Check required commands (only if not in CI environment) - -$requiredCommands = ("docker", "docker-compose") -foreach ($command in $requiredCommands) { - if ((Get-Command $command -ErrorAction SilentlyContinue) -eq $null) { - Write-Host "$command must be on path" -ForegroundColor Red - exit - } -} - -# Get tag to use from current branch if no tag is passed -if ([string]::IsNullOrEmpty($imageTag)) { - $imageTag = $(git rev-parse --abbrev-ref HEAD) -} -Write-Host "Docker image Tag: $imageTag" -ForegroundColor Yellow - -# Build docker images if needed -if ($buildImages) { - Write-Host "Building Docker images tagged with '$imageTag'" -ForegroundColor Yellow - $env:TAG=$imageTag - docker-compose -p .. -f ../docker-compose.yml build -} - -# Login to Docker registry -if (-not [string]::IsNullOrEmpty($dockerUser)) { - $registryFDQN = if (-not $useDockerHub) {$registry} else {"index.docker.io/v1/"} - - Write-Host "Logging in to $registryFDQN as user $dockerUser" -ForegroundColor Yellow - if ($useDockerHub) { - docker login -u $dockerUser -p $dockerPassword - } - else { - docker login -u $dockerUser -p $dockerPassword $registryFDQN - } - - if (-not $LastExitCode -eq 0) { - Write-Host "Login failed" -ForegroundColor Red - exit - } - -} - -# Push images to Docker registry -if ($pushImages) { - Write-Host "Pushing images to $registry/$dockerOrg..." -ForegroundColor Yellow - $services = ("basket.api", "catalog.api", "identity.api", "ordering.api", "ordering.backgroundtasks", "marketing.api","payment.api","locations.api", "webmvc", "webspa", "webstatus", "ocelotapigw", "mobileshoppingagg", "webshoppingagg", "ordering.signalrhub") - - foreach ($service in $services) { - $imageFqdn = if ($useDockerHub) {"$dockerOrg/${service}"} else {"$registry/$dockerOrg/${service}"} - docker tag eshop/${service}:$imageTag ${imageFqdn}:$imageTag - docker push ${imageFqdn}:$imageTag - } -} - - - - - diff --git a/deploy/k8s/conf-files.md b/deploy/k8s/conf-files.md deleted file mode 100644 index 3a74a86bd..000000000 --- a/deploy/k8s/conf-files.md +++ /dev/null @@ -1,17 +0,0 @@ -# YAML files used to deploy to k8s - -This is just a brief enumeration of the configuration files used to create the k8s objects. Use as reference to find where specific object is. - -- `deployments.yaml` Contains the definition of all deployments of the eShopOnContainers. Do not contain any infrastructure deployment (so no SQL, Redis, ...). -- `services.yaml` Contains the definition of all services of the eShopOnContainers. Do not contain any infrastructure service (so no SQL, Redis, ...). -- `basket-data.yaml` Contains the definition of the Redis (used by basket.api) deployment and service -- `nosql-data.yaml` Contains the definition of the Mongodb (used by locations and marketing) deployment and service -- `sql-data.yaml` Contains the definition of the SQL server deployment and service -- `rabbitmq.yaml` Contains the definition of the RabbitMQ deployment and service -- `keystore-data.yaml` Contains the deployment and service definition of the Redis used to mantain coherence between all the ASP.NET Identity keystores. -- `conf_local.yaml` Contains the configuration map that configures all the Pods to use "local" containers (that is all containers in k8s) -- `conf_cloud.yaml` Contains the configuration map that configures all the Pods to use "cloud" resources (that is use Azure resources instead infrastructure containers). This file is provided with no valid values, just for example. -- `frontend.yaml` Contains the deployment and service definition of the NGINX frontend used as reverse-proxy - -- For more information what kubernetes deployments are, read [Kubernetes help](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) -- For more information what kubernetes services are, read [Kubernetes help](https://kubernetes.io/docs/concepts/services-networking/service/) diff --git a/deploy/k8s/conf_cloud.yaml b/deploy/k8s/conf_cloud.yaml deleted file mode 100644 index a914105ae..000000000 --- a/deploy/k8s/conf_cloud.yaml +++ /dev/null @@ -1,34 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: externalcfg - labels: - app: eshop -data: -# Basket.API entries - basket__ConnectionString: REDIS CONNECTION STRING FOR BASKET -# Catalog.API entries - catalog__ConnectionString: Catalog SQL SERVER CONNECTION STRING (Server=xxxx;Intial Catalog=yyy;....) -# Identity.API entries - IdentitySqlDb: Identity SQL SERVER CONNECTION STRING (Server=xxxx;Intial Catalog=yyy;....) -# Locations.API entries - LocationsBus: CONNECTION_STRING (NAME OF RABBITMQ CONTAINER OR Endpoint=sb://XXXX for topic in case of using Azure) - LocationsNoSqlDb: Locations MongoDb ConnectionString - LocationsNoSqlDbName: Locations MongoDb database (LocationsDb) -# Marketing.API entries - MarketingBus: CONNECTION_STRING (NAME OF RABBITMQ CONTAINER OR Endpoint=sb://XXXX for topic in case of using Azure) - MarketingNoSqlDb: Marketing MongoDb ConnectionString - MarketingNoSqlDbName: Marketing MongoDb database (MarketingDb) - MarketingSqlDb: Marketing SQL SERVER CONNECTION STRING (Server=xxxx;Intial Catalog=yyy;....) -# Ordering.API entries - OrderingBus: CONNECTION_STRING (NAME OF RABBITMQ CONTAINER OR Endpoint=sb://XXXX for topic in case of using Azure) - OrderingSqlDb: Ordering SQL SERVER CONNECTION STRING (Server=xxxx;Intial Catalog=yyy;....) - GracePeriodManager_GracePeriodTime: "1" - GracePeriodManager_CheckUpdateTime: "15000" -# Payment.API entries - PaymentBus: CONNECTION_STRING (NAME OF RABBITMQ CONTAINER OR Endpoint=sb://XXXX for topic in case of using Azure) -# Global entries - all_UseAzureServiceBus: "TRUE" IF USE AZURE SB ("FALSE" FOR USING RABBITMQ) - keystore: REDIS CONNECTION STRING FOR KEYSTORE - all_EventBusConnection: CONNECTION_STRING (NAME OF RABBITMQ CONTAINER OR Endpoint=sb://XXXX in case of using Azure) - all_InstrumentationKey: APPINSIGHTS KEY diff --git a/deploy/k8s/conf_local.yaml b/deploy/k8s/conf_local.yaml deleted file mode 100644 index 615754bcf..000000000 --- a/deploy/k8s/conf_local.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: externalcfg - labels: - app: eshop -data: - basket__ConnectionString: basket-data - catalog__ConnectionString: Server=sql-data;Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word; - catalog__AzureStorageEnabled: "False" - identity__ConnectionString: Server=sql-data;Initial Catalog=Microsoft.eShopOnContainers.Services.IdentityDb;User Id=sa;Password=Pass@word; - locations__ConnectionString: mongodb://nosql-data - locations__Database: LocationsDb - marketing__MongoConnectionString: mongodb://nosql-data - marketing__MongoDatabase: MarketingDb - marketing__ConnectionString: Server=sql-data;Initial Catalog=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word; - ordering__ConnectionString: Server=sql-data;Initial Catalog=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word; - keystore: keystore-data - GracePeriodManager__GracePeriodTime: "1" - GracePeriodManager__CheckUpdateTime: "15000" - all__EventBusConnection: rabbitmq - all__InstrumentationKey: "" - all__EnableLoadTest: "False" - all__UseAzureServiceBus: "False" - - - diff --git a/deploy/k8s/deploy-ingress-azure.ps1 b/deploy/k8s/deploy-ingress-azure.ps1 deleted file mode 100644 index d0ff702df..000000000 --- a/deploy/k8s/deploy-ingress-azure.ps1 +++ /dev/null @@ -1 +0,0 @@ -kubectl apply -f nginx-ingress\cloud-generic.yaml \ No newline at end of file diff --git a/deploy/k8s/deploy-ingress-dockerlocal.ps1 b/deploy/k8s/deploy-ingress-dockerlocal.ps1 deleted file mode 100644 index 04ffad763..000000000 --- a/deploy/k8s/deploy-ingress-dockerlocal.ps1 +++ /dev/null @@ -1,2 +0,0 @@ -kubectl apply -f nginx-ingress\cm.yaml -kubectl apply -f nginx-ingress\cloud-generic.yaml \ No newline at end of file diff --git a/deploy/k8s/deploy-ingress.ps1 b/deploy/k8s/deploy-ingress.ps1 deleted file mode 100644 index 37abcbee2..000000000 --- a/deploy/k8s/deploy-ingress.ps1 +++ /dev/null @@ -1,5 +0,0 @@ -# Deploy nginx-ingress core files -kubectl apply -f nginx-ingress\mandatory.yaml - - - diff --git a/deploy/k8s/deploy-nodeports.ps1 b/deploy/k8s/deploy-nodeports.ps1 deleted file mode 100644 index a10462b0b..000000000 --- a/deploy/k8s/deploy-nodeports.ps1 +++ /dev/null @@ -1,2 +0,0 @@ -kubectl apply -f .\nodeports\rabbitmq-admin.yaml -kubectl apply -f .\nodeports\sql-services.yaml diff --git a/deploy/k8s/deploy.ps1 b/deploy/k8s/deploy.ps1 deleted file mode 100644 index 6a44a4b12..000000000 --- a/deploy/k8s/deploy.ps1 +++ /dev/null @@ -1,212 +0,0 @@ -Param( - [parameter(Mandatory=$false)][string]$registry, - [parameter(Mandatory=$false)][string]$dockerUser, - [parameter(Mandatory=$false)][string]$dockerPassword, - [parameter(Mandatory=$false)][string]$execPath, - [parameter(Mandatory=$false)][string]$kubeconfigPath, - [parameter(Mandatory=$true)][string]$configFile, - [parameter(Mandatory=$false)][string]$imageTag, - [parameter(Mandatory=$false)][bool]$deployCI=$false, - [parameter(Mandatory=$false)][bool]$buildImages=$true, - [parameter(Mandatory=$false)][bool]$pushImages=$true, - [parameter(Mandatory=$false)][bool]$deployInfrastructure=$true, - [parameter(Mandatory=$false)][string]$dockerOrg="eshop" -) - -function ExecKube($cmd) { - if($deployCI) { - $kubeconfig = $kubeconfigPath + 'config'; - $exp = $execPath + 'kubectl ' + $cmd + ' --kubeconfig=' + $kubeconfig - Invoke-Expression $exp - } - else{ - $exp = $execPath + 'kubectl ' + $cmd - Invoke-Expression $exp - } -} - -# Initialization -$debugMode = $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent -$useDockerHub = [string]::IsNullOrEmpty($registry) - -$externalDns = & ExecKube -cmd 'get svc ingress-nginx -n ingress-nginx -o=jsonpath="{.status.loadBalancer.ingress[0].ip}"' -Write-Host "Ingress ip detected: $externalDns" -ForegroundColor Yellow - -if (-not [bool]($externalDns -as [ipaddress])) { - Write-Host "Must install ingress first" -ForegroundColor Red - Write-Host "Run deploy-ingress.ps1 and deploy-ingress-azure.ps1" -ForegroundColor Red - exit -} - - -# Check required commands (only if not in CI environment) -if(-not $deployCI) { - $requiredCommands = ("docker", "docker-compose", "kubectl") - foreach ($command in $requiredCommands) { - if ((Get-Command $command -ErrorAction SilentlyContinue) -eq $null) { - Write-Host "$command must be on path" -ForegroundColor Red - exit - } - } -} -else { - $buildImages = false; # Never build images through CI, as they previously built -} - -# Get tag to use from current branch if no tag is passed -if ([string]::IsNullOrEmpty($imageTag)) { - $imageTag = $(git rev-parse --abbrev-ref HEAD) -} -Write-Host "Docker image Tag: $imageTag" -ForegroundColor Yellow - -# building docker images if needed -if ($buildImages) { - Write-Host "Building Docker images tagged with '$imageTag'" -ForegroundColor Yellow - $env:TAG=$imageTag - docker-compose -p .. -f ../docker-compose.yml build -} - -if ($pushImages) { - Write-Host "Pushing images to $registry/$dockerOrg..." -ForegroundColor Yellow - $services = ("basket.api", "catalog.api", "identity.api", "ordering.api", "ordering.backgroundtasks", "marketing.api","payment.api","locations.api", "webmvc", "webspa", "webstatus", "ocelotapigw", "mobileshoppingagg", "webshoppingagg", "ordering.signalrhub") - - foreach ($service in $services) { - $imageFqdn = if ($useDockerHub) {"$dockerOrg/${service}"} else {"$registry/$dockerOrg/${service}"} - docker tag eshop/${service}:$imageTag ${imageFqdn}:$imageTag - docker push ${imageFqdn}:$imageTag - } -} - -# if we have login/pwd add the secret to k8s -if (-not [string]::IsNullOrEmpty($dockerUser)) { - $registryFDQN = if (-not $useDockerHub) {$registry} else {"index.docker.io/v1/"} - - Write-Host "Logging in to $registryFDQN as user $dockerUser" -ForegroundColor Yellow - if ($useDockerHub) { - docker login -u $dockerUser -p $dockerPassword - } - else { - docker login -u $dockerUser -p $dockerPassword $registryFDQN - } - - if (-not $LastExitCode -eq 0) { - Write-Host "Login failed" -ForegroundColor Red - exit - } - - # Try to delete the Docker registry key secret - ExecKube -cmd 'delete secret docker-registry registry-key' - - # Create the Docker registry key secret - ExecKube -cmd 'create secret docker-registry registry-key ` - --docker-server=$registryFDQN ` - --docker-username=$dockerUser ` - --docker-password=$dockerPassword ` - --docker-email=not@used.com' -} - -# Removing previous services & deployments -Write-Host "Removing existing services & deployments.." -ForegroundColor Yellow -ExecKube -cmd 'delete deployments --all' -ExecKube -cmd 'delete services --all' -ExecKube -cmd 'delete configmap internalurls' -ExecKube -cmd 'delete configmap urls' -ExecKube -cmd 'delete configmap externalcfg' -ExecKube -cmd 'delete configmap ocelot' -ExecKube -cmd 'delete -f ingress.yaml' - -# start sql, rabbitmq, frontend deployments -if ($deployInfrastructure) { - Write-Host 'Deploying infrastructure deployments (databases, redis, RabbitMQ...)' -ForegroundColor Yellow - ExecKube -cmd 'create -f sql-data.yaml -f basket-data.yaml -f keystore-data.yaml -f rabbitmq.yaml -f nosql-data.yaml' -} - - -Write-Host 'Deploying ocelot APIGW' -ForegroundColor Yellow - -ExecKube "create configmap ocelot --from-file=mm=ocelot/configuration-mobile-marketing.json --from-file=ms=ocelot/configuration-mobile-shopping.json --from-file=wm=ocelot/configuration-web-marketing.json --from-file=ws=ocelot/configuration-web-shopping.json " -ExecKube -cmd "apply -f ocelot/deployment.yaml" -ExecKube -cmd "apply -f ocelot/service.yaml" - -Write-Host 'Deploying code deployments (Web APIs, Web apps, ...)' -ForegroundColor Yellow -ExecKube -cmd 'create -f services.yaml' - -ExecKube -cmd 'create -f internalurls.yaml' -ExecKube -cmd 'create configmap urls ` - --from-literal=PicBaseUrl=http://$($externalDns)/webshoppingapigw/c/api/v1/catalog/items/[0]/pic/ ` - --from-literal=Marketing_PicBaseUrl=http://$($externalDns)/webmarketingapigw/m/api/v1/campaigns/[0]/pic/ ` - --from-literal=mvc_e=http://$($externalDns)/webmvc ` - --from-literal=marketingapigw_e=http://$($externalDns)/webmarketingapigw ` - --from-literal=webshoppingapigw_e=http://$($externalDns)/webshoppingapigw ` - --from-literal=mobileshoppingagg_e=http://$($externalDns)/mobileshoppingagg ` - --from-literal=webshoppingagg_e=http://$($externalDns)/webshoppingagg ` - --from-literal=identity_e=http://$($externalDns)/identity ` - --from-literal=spa_e=http://$($externalDns) ` - --from-literal=locations_e=http://$($externalDns)/locations-api ` - --from-literal=marketing_e=http://$($externalDns)/marketing-api ` - --from-literal=basket_e=http://$($externalDns)/basket-api ` - --from-literal=ordering_e=http://$($externalDns)/ordering-api ` - --from-literal=xamarin_callback_e=http://$($externalDns)/xamarincallback' - -ExecKube -cmd 'label configmap urls app=eshop' - -Write-Host "Deploying configuration from $configFile" -ForegroundColor Yellow -ExecKube -cmd "create -f $configFile" - -Write-Host "Creating deployments..." -ForegroundColor Yellow -ExecKube -cmd 'create -f deployments.yaml' - -# update deployments with the correct image (with tag and/or registry) -$registryPath = "" -if (-not [string]::IsNullOrEmpty($registry)) { - $registryPath = "$registry/" -} - -Write-Host "Update Image containers to use prefix '$registry$dockerOrg' and tag '$imageTag'" -ForegroundColor Yellow - -ExecKube -cmd 'set image deployments/basket basket=${registryPath}${dockerOrg}/basket.api:$imageTag' -ExecKube -cmd 'set image deployments/catalog catalog=${registryPath}${dockerOrg}/catalog.api:$imageTag' -ExecKube -cmd 'set image deployments/identity identity=${registryPath}${dockerOrg}/identity.api:$imageTag' -ExecKube -cmd 'set image deployments/ordering ordering=${registryPath}${dockerOrg}/ordering.api:$imageTag' -ExecKube -cmd 'set image deployments/ordering-backgroundtasks ordering-backgroundtasks=${registryPath}${dockerOrg}/ordering.backgroundtasks:$imageTag' -ExecKube -cmd 'set image deployments/marketing marketing=${registryPath}${dockerOrg}/marketing.api:$imageTag' -ExecKube -cmd 'set image deployments/locations locations=${registryPath}${dockerOrg}/locations.api:$imageTag' -ExecKube -cmd 'set image deployments/payment payment=${registryPath}${dockerOrg}/payment.api:$imageTag' -ExecKube -cmd 'set image deployments/webmvc webmvc=${registryPath}${dockerOrg}/webmvc:$imageTag' -ExecKube -cmd 'set image deployments/webstatus webstatus=${registryPath}${dockerOrg}/webstatus:$imageTag' -ExecKube -cmd 'set image deployments/webspa webspa=${registryPath}${dockerOrg}/webspa:$imageTag' -ExecKube -cmd 'set image deployments/ordering-signalrhub ordering-signalrhub=${registryPath}${dockerOrg}/ordering.signalrhub:$imageTag' - -ExecKube -cmd 'set image deployments/mobileshoppingagg mobileshoppingagg=${registryPath}${dockerOrg}/mobileshoppingagg:$imageTag' -ExecKube -cmd 'set image deployments/webshoppingagg webshoppingagg=${registryPath}${dockerOrg}/webshoppingagg:$imageTag' - -ExecKube -cmd 'set image deployments/apigwmm apigwmm=${registryPath}${dockerOrg}/ocelotapigw:$imageTag' -ExecKube -cmd 'set image deployments/apigwms apigwms=${registryPath}${dockerOrg}/ocelotapigw:$imageTag' -ExecKube -cmd 'set image deployments/apigwwm apigwwm=${registryPath}${dockerOrg}/ocelotapigw:$imageTag' -ExecKube -cmd 'set image deployments/apigwws apigwws=${registryPath}${dockerOrg}/ocelotapigw:$imageTag' - -Write-Host "Execute rollout..." -ForegroundColor Yellow -ExecKube -cmd 'rollout resume deployments/basket' -ExecKube -cmd 'rollout resume deployments/catalog' -ExecKube -cmd 'rollout resume deployments/identity' -ExecKube -cmd 'rollout resume deployments/ordering' -ExecKube -cmd 'rollout resume deployments/ordering-backgroundtasks' -ExecKube -cmd 'rollout resume deployments/marketing' -ExecKube -cmd 'rollout resume deployments/locations' -ExecKube -cmd 'rollout resume deployments/payment' -ExecKube -cmd 'rollout resume deployments/webmvc' -ExecKube -cmd 'rollout resume deployments/webstatus' -ExecKube -cmd 'rollout resume deployments/webspa' -ExecKube -cmd 'rollout resume deployments/mobileshoppingagg' -ExecKube -cmd 'rollout resume deployments/webshoppingagg' -ExecKube -cmd 'rollout resume deployments/apigwmm' -ExecKube -cmd 'rollout resume deployments/apigwms' -ExecKube -cmd 'rollout resume deployments/apigwwm' -ExecKube -cmd 'rollout resume deployments/apigwws' -ExecKube -cmd 'rollout resume deployments/ordering-signalrhub' - -Write-Host "Adding/Updating ingress resource..." -ForegroundColor Yellow -ExecKube -cmd 'apply -f ingress.yaml' - -Write-Host "WebSPA is exposed at http://$externalDns, WebMVC at http://$externalDns/webmvc, WebStatus at http://$externalDns/webstatus" -ForegroundColor Yellow - diff --git a/deploy/k8s/deploy.sh b/deploy/k8s/deploy.sh deleted file mode 100644 index 0689c19c1..000000000 --- a/deploy/k8s/deploy.sh +++ /dev/null @@ -1,212 +0,0 @@ -#!/usr/bin/env bash - -# http://redsymbol.net/articles/unofficial-bash-strict-mode/ -set -euo pipefail - -# This script is comparable to the PowerShell script deploy.ps1 but to be used from a Mac bash environment. -# There are, however, the following few differences/limitations: - -# It assumes docker/container registry login was already performed -# It assumes K8s was given access to the registry—does not create any K8s secrets -# It does not support explicit kubectl config file (relies on kubectl config use-context to point kubectl at the right cluster/namespace) -# It always deploys infrastructure bits (redis, SQL Server etc) -# The script was tested only with Azure Container Registry (not Docker Hub, although it is expected to work with Docker Hub too) - -# Feel free to submit a PR in order to improve it. - -usage() -{ - cat < - Specifies container registry (ACR) to use (required), e.g. myregistry.azurecr.io - -t | --tag - Default: newly created, date-based timestamp, with 1-minute resolution - -b | --build-solution - Force solution build before deployment (default: false) - --skip-image-build - Do not build images (default is to build all images) - --skip-image-push - Do not upload images to the container registry (just run the Kubernetes deployment portion) - Default is to push images to container registry - -h | --help - Displays this help text and exits the script - -It is assumed that the Kubernetes AKS cluster has been granted access to ACR registry. -For more info see -https://docs.microsoft.com/en-us/azure/container-registry/container-registry-auth-aks - -WARNING! THE SCRIPT WILL COMPLETELY DESTROY ALL DEPLOYMENTS AND SERVICES VISIBLE -FROM THE CURRENT CONFIGURATION CONTEXT. -It is recommended that you create a separate namespace and confguration context -for the eShopOnContainers application, to isolate it from other applications on the cluster. -For more information see https://kubernetes.io/docs/tasks/administer-cluster/namespaces/ -You can use eshop-namespace.yaml file (in the same directory) to create the namespace. - -END -} - -image_tag=$(date '+%Y%m%d%H%M') -build_solution='' -container_registry='' -build_images='yes' -push_images='yes' - -while [[ $# -gt 0 ]]; do - case "$1" in - -r | --registry ) - container_registry="$2"; shift 2 ;; - -t | --tag ) - image_tag="$2"; shift 2 ;; - -b | --build-solution ) - build_solution='yes'; shift ;; - --skip-image-build ) - build_images=''; shift ;; - --skip-image-push ) - push_images=''; shift ;; - -h | --help ) - usage; exit 1 ;; - *) - echo "Unknown option $1" - usage; exit 2 ;; - esac -done - -if [[ ! $container_registry ]]; then - echo 'Container registry must be specified (e.g. myregistry.azurecr.io)' - echo '' - usage - exit 3 -fi - -if [[ $build_solution ]]; then - echo "#################### Building eShopOnContainers solution ####################" - dotnet publish -o obj/Docker/publish ../eShopOnContainers-ServicesAndWebApps.sln -fi - -export TAG=$image_tag - -if [[ $build_images ]]; then - echo "#################### Building eShopOnContainers Docker images ####################" - docker-compose -p .. -f ../docker-compose.yml build - - # Remove temporary images - docker rmi $(docker images -qf "dangling=true") -fi - -if [[ $push_images ]]; then - echo "#################### Pushing images to registry ####################" - services=(basket.api catalog.api identity.api ordering.api marketing.api payment.api locations.api webmvc webspa webstatus) - - for service in "${services[@]}" - do - echo "Pushing image for service $service..." - docker tag "eshop/$service:$image_tag" "$container_registry/$service:$image_tag" - docker push "$container_registry/$service:$image_tag" - done -fi - -echo "#################### Cleaning up old deployment ####################" -kubectl delete deployments --all -kubectl delete services --all -kubectl delete configmap config-files || true -kubectl delete configmap urls || true -kubectl delete configmap externalcfg || true - -echo "#################### Deploying infrastructure components ####################" -kubectl create configmap config-files --from-file=nginx-conf=nginx.conf -kubectl label configmap config-files app=eshop -kubectl create -f sql-data.yaml -f basket-data.yaml -f keystore-data.yaml -f rabbitmq.yaml -f nosql-data.yaml - -echo "#################### Creating application service definitions ####################" -kubectl create -f services.yaml -f frontend.yaml - -echo "#################### Waiting for Azure to provision external IP ####################" - -ip_regex='([0-9]{1,3}\.){3}[0-9]{1,3}' -while true; do - printf "." - frontendUrl=$(kubectl get svc frontend -o=jsonpath="{.status.loadBalancer.ingress[0].ip}") - if [[ $frontendUrl =~ $ip_regex ]]; then - break - fi - sleep 5s -done - -printf "\n" -externalDns=$frontendUrl -echo "Using $externalDns as the external DNS/IP of the K8s cluster" - -echo "#################### Creating application configuration ####################" - -# urls configmap -kubectl create configmap urls \ - "--from-literal=BasketUrl=http://basket" \ - "--from-literal=BasketHealthCheckUrl=http://basket/hc" \ - "--from-literal=CatalogUrl=http://$externalDns/catalog-api" \ - "--from-literal=CatalogHealthCheckUrl=http://catalog/hc" \ - "--from-literal=PicBaseUrl=http://$externalDns/catalog-api/api/v1/catalog/items/[0]/pic/" \ - "--from-literal=Marketing_PicBaseUrl=http://$externalDns/marketing-api/api/v1/campaigns/[0]/pic/" \ - "--from-literal=IdentityUrl=http://$externalDns/identity" \ - "--from-literal=IdentityHealthCheckUrl=http://identity/hc" \ - "--from-literal=OrderingUrl=http://ordering" \ - "--from-literal=OrderingHealthCheckUrl=http://ordering/hc" \ - "--from-literal=MvcClientExternalUrl=http://$externalDns/webmvc" \ - "--from-literal=WebMvcHealthCheckUrl=http://webmvc/hc" \ - "--from-literal=MvcClientOrderingUrl=http://ordering" \ - "--from-literal=MvcClientCatalogUrl=http://catalog" \ - "--from-literal=MvcClientBasketUrl=http://basket" \ - "--from-literal=MvcClientMarketingUrl=http://marketing" \ - "--from-literal=MvcClientLocationsUrl=http://locations" \ - "--from-literal=MarketingHealthCheckUrl=http://marketing/hc" \ - "--from-literal=WebSpaHealthCheckUrl=http://webspa/hc" \ - "--from-literal=SpaClientMarketingExternalUrl=http://$externalDns/marketing-api" \ - "--from-literal=SpaClientOrderingExternalUrl=http://$externalDns/ordering-api" \ - "--from-literal=SpaClientCatalogExternalUrl=http://$externalDns/catalog-api" \ - "--from-literal=SpaClientBasketExternalUrl=http://$externalDns/basket-api" \ - "--from-literal=SpaClientIdentityExternalUrl=http://$externalDns/identity" \ - "--from-literal=SpaClientLocationsUrl=http://$externalDns/locations-api" \ - "--from-literal=LocationsHealthCheckUrl=http://locations/hc" \ - "--from-literal=SpaClientExternalUrl=http://$externalDns" \ - "--from-literal=LocationApiClient=http://$externalDns/locations-api" \ - "--from-literal=MarketingApiClient=http://$externalDns/marketing-api" \ - "--from-literal=BasketApiClient=http://$externalDns/basket-api" \ - "--from-literal=OrderingApiClient=http://$externalDns/ordering-api" \ - "--from-literal=PaymentHealthCheckUrl=http://payment/hc" - -kubectl label configmap urls app=eshop - -# externalcfg configmap -- points to local infrastructure components (rabbitmq, SQL Server etc) -kubectl create -f conf_local.yml - -# Create application pod deployments -kubectl create -f deployments.yaml - -echo "#################### Deploying application pods ####################" - -# update deployments with the correct image (with tag and/or registry) -kubectl set image deployments/basket "basket=$container_registry/basket.api:$image_tag" -kubectl set image deployments/catalog "catalog=$container_registry/catalog.api:$image_tag" -kubectl set image deployments/identity "identity=$container_registry/identity.api:$image_tag" -kubectl set image deployments/ordering "ordering=$container_registry/ordering.api:$image_tag" -kubectl set image deployments/marketing "marketing=$container_registry/marketing.api:$image_tag" -kubectl set image deployments/locations "locations=$container_registry/locations.api:$image_tag" -kubectl set image deployments/payment "payment=$container_registry/payment.api:$image_tag" -kubectl set image deployments/webmvc "webmvc=$container_registry/webmvc:$image_tag" -kubectl set image deployments/webstatus "webstatus=$container_registry/webstatus:$image_tag" -kubectl set image deployments/webspa "webspa=$container_registry/webspa:$image_tag" - -kubectl rollout resume deployments/basket -kubectl rollout resume deployments/catalog -kubectl rollout resume deployments/identity -kubectl rollout resume deployments/ordering -kubectl rollout resume deployments/marketing -kubectl rollout resume deployments/locations -kubectl rollout resume deployments/payment -kubectl rollout resume deployments/webmvc -kubectl rollout resume deployments/webstatus -kubectl rollout resume deployments/webspa - -echo "WebSPA is exposed at http://$externalDns, WebMVC at http://$externalDns/webmvc, WebStatus at http://$externalDns/webstatus" -echo "eShopOnContainers deployment is DONE" diff --git a/deploy/k8s/img/blob_creation.png b/deploy/k8s/img/blob_creation.png deleted file mode 100644 index a9e386eadca24830e9ec9d985fc7820108a4f5a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26340 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 diff --git a/deploy/k8s/img/get_kubectlconfig_task.png b/deploy/k8s/img/get_kubectlconfig_task.png deleted file mode 100644 index 594e68ba7bd42e82051233847ac468c7b8681a27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31190 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 diff --git a/deploy/k8s/internalurls.yaml b/deploy/k8s/internalurls.yaml deleted file mode 100644 index df317b5d5..000000000 --- a/deploy/k8s/internalurls.yaml +++ /dev/null @@ -1,33 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: internalurls - labels: - app: eshop -data: -# Internal Services & healthchecks - basket: http://basket - basket__hc: http://basket/hc - catalog: http://catalog - catalog__hc: http://catalog/hc - identity: http://identity - identity__hc: http://identity/hc - ordering: http://ordering - ordering__hc: http://ordering/hc - ordering-background: http://ordering-background - ordering-background__hc: http://ordering-background/hc - marketing: http://marketing - marketing__hc: http://marketing/hc - locations: http://locations - locations__hc: http://locations/hc - payment__hc: http://payment/hc - mvc__hc: http://webmvc/hc - spa__hc: http://webspa/hc -# Aggreggators - mobileshoppingagg: http://mobileshoppingagg - webshoppingagg: http://webshoppingagg -# API GWs - apigwmm: http://ocelotapigw-mm - apigwms: http://ocelotapigw-ms - apigwwm: http://ocelotapigw-wm - apigwws: http://ocelotapigw-ws \ No newline at end of file diff --git a/deploy/k8s/nginx-ingress/mandatory-istio.yaml b/deploy/k8s/nginx-ingress/mandatory-istio.yaml deleted file mode 100644 index 56b1cc3b5..000000000 --- a/deploy/k8s/nginx-ingress/mandatory-istio.yaml +++ /dev/null @@ -1,238 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: ingress-nginx - ---- - -kind: ConfigMap -apiVersion: v1 -metadata: - name: nginx-configuration - namespace: ingress-nginx - labels: - app.kubernetes.io/name: ingress-nginx - app.kubernetes.io/part-of: ingress-nginx - ---- - -apiVersion: v1 -kind: ServiceAccount -metadata: - name: nginx-ingress-serviceaccount - namespace: ingress-nginx - labels: - app.kubernetes.io/name: ingress-nginx - app.kubernetes.io/part-of: ingress-nginx - ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRole -metadata: - name: nginx-ingress-clusterrole - labels: - app.kubernetes.io/name: ingress-nginx - app.kubernetes.io/part-of: ingress-nginx -rules: - - apiGroups: - - "" - resources: - - configmaps - - endpoints - - nodes - - pods - - secrets - verbs: - - list - - watch - - apiGroups: - - "" - resources: - - nodes - verbs: - - get - - apiGroups: - - "" - resources: - - services - verbs: - - get - - list - - watch - - apiGroups: - - "extensions" - resources: - - ingresses - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch - - apiGroups: - - "extensions" - resources: - - ingresses/status - verbs: - - update - ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: Role -metadata: - name: nginx-ingress-role - namespace: ingress-nginx - labels: - app.kubernetes.io/name: ingress-nginx - app.kubernetes.io/part-of: ingress-nginx -rules: - - apiGroups: - - "" - resources: - - configmaps - - pods - - secrets - - namespaces - verbs: - - get - - apiGroups: - - "" - resources: - - configmaps - resourceNames: - # Defaults to "-" - # Here: "-" - # This has to be adapted if you change either parameter - # when launching the nginx-ingress-controller. - - "ingress-controller-leader-nginx" - verbs: - - get - - update - - apiGroups: - - "" - resources: - - configmaps - verbs: - - create - - apiGroups: - - "" - resources: - - endpoints - verbs: - - get - ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: RoleBinding -metadata: - name: nginx-ingress-role-nisa-binding - namespace: ingress-nginx - labels: - app.kubernetes.io/name: ingress-nginx - app.kubernetes.io/part-of: ingress-nginx -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: nginx-ingress-role -subjects: - - kind: ServiceAccount - name: nginx-ingress-serviceaccount - namespace: ingress-nginx - ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding -metadata: - name: nginx-ingress-clusterrole-nisa-binding - labels: - app.kubernetes.io/name: ingress-nginx - app.kubernetes.io/part-of: ingress-nginx -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: nginx-ingress-clusterrole -subjects: - - kind: ServiceAccount - name: nginx-ingress-serviceaccount - namespace: ingress-nginx - ---- - -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: nginx-ingress-controller - namespace: ingress-nginx - labels: - app.kubernetes.io/name: ingress-nginx - app.kubernetes.io/part-of: ingress-nginx -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: ingress-nginx - app.kubernetes.io/part-of: ingress-nginx - template: - metadata: - labels: - app.kubernetes.io/name: ingress-nginx - app.kubernetes.io/part-of: ingress-nginx - annotations: - prometheus.io/port: "10254" - prometheus.io/scrape: "true" - spec: - serviceAccountName: nginx-ingress-serviceaccount - containers: - - name: nginx-ingress-controller - image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.20.0 - args: - - /nginx-ingress-controller - - --configmap=$(POD_NAMESPACE)/nginx-configuration - - --publish-service=$(POD_NAMESPACE)/ingress-nginx - - --annotations-prefix=nginx.ingress.kubernetes.io - securityContext: - capabilities: - drop: - - ALL - add: - - NET_BIND_SERVICE - # www-data -> 33 - runAsUser: 33 - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - ports: - - name: http - containerPort: 80 - - name: https - containerPort: 443 - livenessProbe: - failureThreshold: 3 - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - initialDelaySeconds: 10 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 1 - readinessProbe: - failureThreshold: 3 - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 1 diff --git a/deploy/k8s/nodeports/rabbitmq-admin.yaml b/deploy/k8s/nodeports/rabbitmq-admin.yaml deleted file mode 100644 index 30d2facf1..000000000 --- a/deploy/k8s/nodeports/rabbitmq-admin.yaml +++ /dev/null @@ -1,12 +0,0 @@ -kind: Service -apiVersion: v1 -metadata: - name: rabbitmq-admin -spec: - type: NodePort - selector: - app: rabbitmq - ports: - - port: 15672 - nodePort: 31672 - name: rabbitmq-port diff --git a/deploy/k8s/nodeports/sql-service.yaml b/deploy/k8s/nodeports/sql-service.yaml deleted file mode 100644 index 7b0233b68..000000000 --- a/deploy/k8s/nodeports/sql-service.yaml +++ /dev/null @@ -1,12 +0,0 @@ -kind: Service -apiVersion: v1 -metadata: - name: sql-service -spec: - type: NodePort - selector: - app: sql-data - ports: - - port: 1433 - nodePort: 31433 - name: sql-port diff --git a/deploy/k8s/readme.md b/deploy/k8s/readme.md deleted file mode 100644 index 43534d32e..000000000 --- a/deploy/k8s/readme.md +++ /dev/null @@ -1,12 +0,0 @@ -# Kubernetes (k8s) deploy information - -This folder contains files needed to **create** a ACS with Kubernetes in Azure and to **deploy** eShopServices in a existing Kubernetes: - -- `gen-k8s-env.ps1` Script to create a ACS with Kubernetes in Azure -- `deploy.ps1` Script to deploy eShopOnContainers in a existing k8s - -Refer to file [README.k8s.md](./README.k8s.md) for detailed information - -Refer to file [README.CICD.k8s.md](./README.CICD.k8s.md) for information about how to set a VSTS build for deploying on k8s - -Refer to file [conf-files.md](./conf-files.md) for a brief description of every YAML file in this folder \ No newline at end of file diff --git a/obsolete/cli-linux/build-bits-linux.sh b/obsolete/cli-linux/build-bits-linux.sh deleted file mode 100644 index ac68031e0..000000000 --- a/obsolete/cli-linux/build-bits-linux.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash - -declare -x path=$1 - -if [ -z "$path" ]; then - $path="$(pwd)/../src"; - echo -e "\e[33mNo path passed. Will use $path" -fi - -declare -a projectList=( - "$path/Web/WebSPA" - "$path/Services/Catalog/Catalog.API" - "$path/Services/Basket/Basket.API" - "$path/Services/Ordering/Ordering.API" - "$path/Services/Identity/Identity.API" - "$path/Services/Location/Locations.API" - "$path/Services/Marketing/Marketing.API" - "$path/Services/Payment/Payment.API" - "$path/Web/WebMVC" - "$path/Web/WebStatus" -) - -# Build SPA app -# pushd $(pwd)../src/Web/WebSPA -# npm run build:prod - -for project in "${projectList[@]}" -do - echo -e "\e[33mWorking on $path/$project" - echo -e "\e[33m\tRemoving old publish output" - pushd $path/$project - rm -rf obj/Docker/publish - echo -e "\e[33m\tBuilding and publishing $project" - dotnet publish -c Release -o obj/Docker/publish --verbosity quiet - popd -done - -## remove old docker images: -#images=$(docker images --filter=reference="eshop/*" -q) -#if [ -n "$images" ]; then -# docker rm $(docker ps -a -q) -f -# echo "Deleting eShop images in local Docker repo" -# echo $images -# docker rmi $(docker images --filter=reference="eshop/*" -q) -f -#fi - - -# No need to build the images, docker build or docker compose will -# do that using the images and containers defined in the docker-compose.yml file. -# -# \ No newline at end of file diff --git a/obsolete/cli-linux/docker-compose.local.build.yml b/obsolete/cli-linux/docker-compose.local.build.yml deleted file mode 100644 index a05c09089..000000000 --- a/obsolete/cli-linux/docker-compose.local.build.yml +++ /dev/null @@ -1,10 +0,0 @@ -version: '2' - -services: - ci-build: - image: microsoft/aspnetcore-build-nightly:1.0-1.1 - volumes: - - .:/src - working_dir: /src - command: /bin/bash -c "chmod -x ./cli-linux/build-bits-linux.sh && ./cli-linux/build-bits-linux.sh" - \ No newline at end of file diff --git a/obsolete/cli-linux/prepare-spa-app.sh b/obsolete/cli-linux/prepare-spa-app.sh deleted file mode 100644 index 422730116..000000000 --- a/obsolete/cli-linux/prepare-spa-app.sh +++ /dev/null @@ -1,4 +0,0 @@ -# Build SPA app -pushd $(pwd)/src/Web/WebSPA -npm rebuild node-sass -#npm run build:prod diff --git a/obsolete/cli-linux/run.sh b/obsolete/cli-linux/run.sh deleted file mode 100644 index d46f0a049..000000000 --- a/obsolete/cli-linux/run.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -docker stop $(docker ps -a -q) -docker rm $(docker ps -a -q) -docker images |grep -v REPOSITORY|awk '{print $1}'|xargs -L1 docker pull -export ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP=$(curl ipinfo.io/ip) -docker-compose -f docker-compose.images.yml -f docker-compose.prod.yml up -d --force-recreate diff --git a/obsolete/cli-mac/build-bits.sh b/obsolete/cli-mac/build-bits.sh deleted file mode 100644 index 8b4917144..000000000 --- a/obsolete/cli-mac/build-bits.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/sh - -# List of microservices here needs to be updated to include all the new microservices (Marketing, etc.) - -projectList=( - "../src/Web/WebMVC" - "../src/Web/WebSPA" - "../src/Services/Identity/Identity.API" - "../src/Services/Catalog/Catalog.API" - "../src/Services/Ordering/Ordering.API" - "../src/Services/Basket/Basket.API" - "../src/Services/Location/Locations.API" - "../src/Services/Marketing/Marketing.API" - "../src/Services/Payment/Payment.API" - "../src/Web/WebStatus" -) - - -pushd $(pwd)/../src/Web/WebSPA -npm install -npm rebuild node-sass -popd - -for project in "${projectList[@]}" -do - echo -e "\e[33mWorking on $(pwd)/$project" - echo -e "\e[33m\tRemoving old publish output" - pushd $(pwd)/$project - rm -rf obj/Docker/publish - echo -e "\e[33m\tBuilding and publishing projects" - dotnet publish -o obj/Docker/publish -c Release - popd -done - -# remove old docker images: -images=$(docker images --filter=reference="eshop/*" -q) -if [ -n "$images" ]; then - docker rm $(docker ps -a -q) -f - echo "Deleting eShop images in local Docker repo" - echo $images - docker rmi $(docker images --filter=reference="eshop/*" -q) -f -fi - -# No need to build the images, docker build or docker compose will -# do that using the images and containers defined in the docker-compose.yml file. -# -# diff --git a/obsolete/cli-windows/build-bits-simple.ps1 b/obsolete/cli-windows/build-bits-simple.ps1 deleted file mode 100644 index 008f4f599..000000000 --- a/obsolete/cli-windows/build-bits-simple.ps1 +++ /dev/null @@ -1,17 +0,0 @@ -# This approach still has issues, but would be the simplest approach for this script -# See: https://github.com/dotnet/eShopOnContainers/issues/74 - -Param([string] $rootPath) -$scriptPath = Split-Path $script:MyInvocation.MyCommand.Path - -Write-Host "Current script directory is $scriptPath" -ForegroundColor Yellow - -if ([string]::IsNullOrEmpty($rootPath)) { - $rootPath = "$scriptPath\.." -} -Write-Host "Root path used is $rootPath" -ForegroundColor Yellow - -$SolutionFilePath = [IO.Path]::Combine($rootPath, "eShopOnContainers-ServicesAndWebApps.sln") - -dotnet publish $SolutionFilePath -c Release -o .\obj\Docker\publish - diff --git a/obsolete/cli-windows/build-bits.ps1 b/obsolete/cli-windows/build-bits.ps1 deleted file mode 100644 index 3b3d8da3f..000000000 --- a/obsolete/cli-windows/build-bits.ps1 +++ /dev/null @@ -1,59 +0,0 @@ -Param([string] $rootPath) -$scriptPath = Split-Path $script:MyInvocation.MyCommand.Path - -Write-Host "Current script directory is $scriptPath" -ForegroundColor Yellow - -if ([string]::IsNullOrEmpty($rootPath)) { - $rootPath = "$scriptPath\.." -} -Write-Host "Root path used is $rootPath" -ForegroundColor Yellow - -workflow BuildAndPublish { - param ([string] $rootPath - ) -$projectPaths = - @{Path="$rootPath\src\Web\WebMVC";Prj="WebMVC.csproj"}, - @{Path="$rootPath\src\Web\WebSPA";Prj="WebSPA.csproj"}, - @{Path="$rootPath\src\Services\Identity\Identity.API";Prj="Identity.API.csproj"}, - @{Path="$rootPath\src\Services\Catalog\Catalog.API";Prj="Catalog.API.csproj"}, - @{Path="$rootPath\src\Services\Ordering\Ordering.API";Prj="Ordering.API.csproj"}, - @{Path="$rootPath\src\Services\Basket\Basket.API";Prj="Basket.API.csproj"}, - @{Path="$rootPath\src\Services\Location\Locations.API";Prj="Locations.API.csproj"}, - @{Path="$rootPath\src\Services\Marketing\Marketing.API";Prj="Marketing.API.csproj"}, - @{Path="$rootPath\src\Services\Payment\Payment.API";Prj="Payment.API.csproj"}, - @{Path="$rootPath\src\Web\WebStatus";Prj="WebStatus.csproj"} - - foreach -parallel ($item in $projectPaths) { - $projectPath = $item.Path - $projectFile = $item.Prj - $outPath = $item.Path + "\obj\Docker\publish" - $projectPathAndFile = "$projectPath\$projectFile" - #Write-Host "Deleting old publish files in $outPath" -ForegroundColor Yellow - remove-item -path $outPath -Force -Recurse -ErrorAction SilentlyContinue - #Write-Host "Publishing $projectPathAndFile to $outPath" -ForegroundColor Yellow - dotnet publish $projectPathAndFile -o $outPath -c Release - } -} - -BuildAndPublish $rootPath - -######################################################################################## -# Delete old eShop Docker images -######################################################################################## - -$imagesToDelete = docker images --filter=reference="eshop/*" -q - -If (-Not $imagesToDelete) {Write-Host "Not deleting eShop images as there are no eShop images in the current local Docker repo."} -Else -{ - # Delete all containers - Write-Host "Deleting all containers in local Docker Host" - docker rm $(docker ps -a -q) -f - - # Delete all eshop images - Write-Host "Deleting eShop images in local Docker repo" - Write-Host $imagesToDelete - docker rmi $(docker images --filter=reference="eshop/*" -q) -f -} - -# WE DON'T NEED DOCKER BUILD AS WE CAN RUN "DOCKER-COMPOSE BUILD" OR "DOCKER-COMPOSE UP" AND IT WILL BUILD ALL THE IMAGES IN THE .YML FOR US diff --git a/obsolete/cli-windows/build-images.ps1 b/obsolete/cli-windows/build-images.ps1 deleted file mode 100644 index bfd6e478b..000000000 --- a/obsolete/cli-windows/build-images.ps1 +++ /dev/null @@ -1,11 +0,0 @@ -Param([string] $imageTag) - -$scriptPath = Split-Path $script:MyInvocation.MyCommand.Path - -if ([string]::IsNullOrEmpty($imageTag)) { - $imageTag = $(git rev-parse --abbrev-ref HEAD) -} - -Write-Host "Building images with tag $imageTag" -ForegroundColor Yellow -$env:TAG=$imageTag -docker-compose -f "$scriptPath\..\docker-compose.yml" -f "$scriptPath\..\docker-compose.windows.yml" build \ No newline at end of file diff --git a/obsolete/cli-windows/delete-images.ps1 b/obsolete/cli-windows/delete-images.ps1 deleted file mode 100644 index 954faa37d..000000000 --- a/obsolete/cli-windows/delete-images.ps1 +++ /dev/null @@ -1,27 +0,0 @@ -$imagesToDelete = docker images --filter=reference="eshop/*" -q - -If (-Not $imagesToDelete) {Write-Host "Not deleting eShop images as there are no eShop images in the current local Docker repo."} -Else -{ - # Delete all containers - Write-Host "Deleting all containers in local Docker Host" - docker rm $(docker ps -a -q) -f - - # Delete all eshop images - Write-Host "Deleting eShop images in local Docker repo" - Write-Host $imagesToDelete - docker rmi $(docker images --filter=reference="eshop/*" -q) -f -} - - -# DELETE ALL IMAGES AND CONTAINERS - -# Delete all containers -# docker rm $(docker ps -a -q) -f - -# Delete all images -# docker rmi $(docker images -q) - -#Filter by image name (Has to be complete, cannot be a wildcard) -#docker ps -q --filter=ancestor=eshop/identity.api:dev - diff --git a/obsolete/cli-windows/delete-vs-and-eshop-images.ps1 b/obsolete/cli-windows/delete-vs-and-eshop-images.ps1 deleted file mode 100644 index f37dc6ea4..000000000 --- a/obsolete/cli-windows/delete-vs-and-eshop-images.ps1 +++ /dev/null @@ -1,46 +0,0 @@ - # Delete all containers - Write-Host "Deleting all running containers in the local Docker Host" - docker rm $(docker ps -a -q) -f - -$eShopImagesToDelete = docker images --filter=reference="eshop/*" -q -If (-Not $eShopImagesToDelete) {Write-Host "Not deleting eShop images as there are no eShop images in the current local Docker repo."} -Else -{ - # Delete all eshop images - Write-Host "Deleting eShop images in local Docker repo" - Write-Host $eShopImagesToDelete - docker rmi $(docker images --filter=reference="eshop/*" -q) -f -} - -$VSImagesToDelete = docker images --filter=reference="catalog.api:dev" -q -If (-Not $VSImagesToDelete) {Write-Host "Not deleting VS images as there are no VS images in the current local Docker repo."} -Else -{ - # Delete all eshop images - Write-Host "Deleting images created by VS in local Docker repo" - Write-Host $VSImagesToDelete - docker rmi $(docker images --filter=reference="*:dev" -q) -f - - #docker rmi $(docker images --filter=reference="eshop/payment.api:dev" -q) -f - #docker rmi $(docker images --filter=reference="eshop/webspa:dev" -q) -f - #docker rmi $(docker images --filter=reference="eshop/webmvc:dev" -q) -f - #docker rmi $(docker images --filter=reference="eshop/catalog.api:dev" -q) -f - #docker rmi $(docker images --filter=reference="eshop/marketing.api:dev" -q) -f - #docker rmi $(docker images --filter=reference="eshop/ordering.api:dev" -q) -f - #docker rmi $(docker images --filter=reference="eshop/basket.api:dev" -q) -f - #docker rmi $(docker images --filter=reference="eshop/identity.api:dev" -q) -f - #docker rmi $(docker images --filter=reference="eshop/locations.api:dev" -q) -f - #docker rmi $(docker images --filter=reference="eshop/webstatus:dev" -q) -f -} - -# DELETE ALL IMAGES AND CONTAINERS - -# Delete all containers -# docker rm $(docker ps -a -q) -f - -# Delete all images -# docker rmi $(docker images -q) - -#Filter by image name (Has to be complete, cannot be a wildcard) -#docker ps -q --filter=ancestor=eshop/identity.api:dev - diff --git a/obsolete/cli-windows/start-external.ps1 b/obsolete/cli-windows/start-external.ps1 deleted file mode 100644 index 514b7af7f..000000000 --- a/obsolete/cli-windows/start-external.ps1 +++ /dev/null @@ -1,11 +0,0 @@ -Param([string] $rootPath) -$scriptPath = Split-Path $script:MyInvocation.MyCommand.Path - -Write-Host "Current script directory is $scriptPath" -ForegroundColor Yellow - -if ([string]::IsNullOrEmpty($rootPath)) { - $rootPath = "$scriptPath\.." -} -Write-Host "Root path used is $rootPath" -ForegroundColor Yellow - -docker-compose -f "$rootPath\docker-compose-external.yml" -f "$rootPath\docker-compose-external.override.yml" up diff --git a/obsolete/cli-windows/start-windows-containers.ps1 b/obsolete/cli-windows/start-windows-containers.ps1 deleted file mode 100644 index 31e265322..000000000 --- a/obsolete/cli-windows/start-windows-containers.ps1 +++ /dev/null @@ -1,33 +0,0 @@ -# rootPath: Root path of the repo (where docker-compose*.yml are). If not passed ../cli-windows/ is assumed -# buildBits: If the projects must be built before. Default value: $true -# customEventBusLoginPassword: If a custom RabbitMQ image is used that do not use the default user login/pwd. Default: $false (means assume use default spring2/rabbitmq image) - -Param( - [parameter(Mandatory=$false)][string] $rootPath, - [parameter(Mandatory=$false)][bool] $customEventBusLoginPassword=$false, - [parameter(Mandatory=$false)][bool]$buildBits=$false -) - -$scriptPath = Split-Path $script:MyInvocation.MyCommand.Path -if ([string]::IsNullOrEmpty($rootPath)) { - $rootPath = "$scriptPath\.." -} -Write-Host "Root path used is $rootPath" -ForegroundColor Yellow - - -if ($buildBits) { - & $scriptPath\build-bits.ps1 -rootPath $rootPath -} - - -$env:ESHOP_EXTERNAL_DNS_NAME_OR_IP = "10.0.75.1" -$env:ESHOP_AZURE_STORAGE_CATALOG_URL ="http://10.0.75.1:5101/api/v1/catalog/items/[0]/pic/" -$env:ESHOP_AZURE_STORAGE_MARKETING_URL ="http://10.0.75.1:5110/api/v1/campaigns/[0]/pic/" -$env:ESHOP_OCELOT_VOLUME_SPEC ="C:\app\configuration" - -if (-Not $customEventBusLoginPassword) { - docker-compose -f "$rootPath\docker-compose.yml" -f "$rootPath\docker-compose.override.yml" -f "$rootPath\docker-compose.windows.yml" -f "$rootPath\docker-compose.override.windows.yml" up -} -else { - docker-compose -f "$rootPath\docker-compose.yml" -f "$rootPath\docker-compose.override.yml" -f "$rootPath\docker-compose.windows.yml" up -} diff --git a/obsolete/cli-windows/vsts/build-bits-no-parallel.ps1 b/obsolete/cli-windows/vsts/build-bits-no-parallel.ps1 deleted file mode 100644 index 4344bdcc8..000000000 --- a/obsolete/cli-windows/vsts/build-bits-no-parallel.ps1 +++ /dev/null @@ -1,56 +0,0 @@ -Param([string] $rootPath) -$scriptPath = Split-Path $script:MyInvocation.MyCommand.Path - -Write-Host "Current script directory is $scriptPath" -ForegroundColor Yellow - -if ([string]::IsNullOrEmpty($rootPath)) { - $rootPath = "$scriptPath\..\.." -} -Write-Host "Root path used is $rootPath" -ForegroundColor Yellow - - -$projectPaths = - @{Path="$rootPath\src\Web\WebMVC";Prj="WebMVC.csproj"}, - @{Path="$rootPath\src\Web\WebSPA";Prj="WebSPA.csproj"}, - @{Path="$rootPath\src\Services\Identity\Identity.API";Prj="Identity.API.csproj"}, - @{Path="$rootPath\src\Services\Catalog\Catalog.API";Prj="Catalog.API.csproj"}, - @{Path="$rootPath\src\Services\Ordering\Ordering.API";Prj="Ordering.API.csproj"}, - @{Path="$rootPath\src\Services\Basket\Basket.API";Prj="Basket.API.csproj"}, - @{Path="$rootPath\src\Services\Location\Locations.API";Prj="Locations.API.csproj"}, - @{Path="$rootPath\src\Services\Marketing\Marketing.API";Prj="Marketing.API.csproj"}, - @{Path="$rootPath\src\Services\Payment\Payment.API";Prj="Payment.API.csproj"}, - @{Path="$rootPath\src\Web\WebStatus";Prj="WebStatus.csproj"} - -$projectPaths | foreach { - $projectPath = $_.Path - $projectFile = $_.Prj - $outPath = $_.Path + "\obj\Docker\publish" - $projectPathAndFile = "$projectPath\$projectFile" - Write-Host "Deleting old publish files in $outPath" -ForegroundColor Yellow - remove-item -path $outPath -Force -Recurse -ErrorAction SilentlyContinue - Write-Host "Publishing $projectPathAndFile to $outPath" -ForegroundColor Yellow - dotnet restore $projectPathAndFile - dotnet build $projectPathAndFile - dotnet publish $projectPathAndFile -o $outPath - } - -######################################################################################## -# Delete old eShop Docker images -######################################################################################## - -$imagesToDelete = docker images --filter=reference="eshop/*" -q - -If (-Not $imagesToDelete) {Write-Host "Not deleting eShop images as there are no eShop images in the current local Docker repo."} -Else -{ - # Delete all containers - Write-Host "Deleting all containers in local Docker Host" - docker rm $(docker ps -a -q) -f - - # Delete all eshop images - Write-Host "Deleting eShop images in local Docker repo" - Write-Host $imagesToDelete - docker rmi $(docker images --filter=reference="eshop/*" -q) -f -} - -# WE DON'T NEED DOCKER BUILD AS WE CAN RUN "DOCKER-COMPOSE BUILD" OR "DOCKER-COMPOSE UP" AND IT WILL BUILD ALL THE IMAGES IN THE .YML FOR US