This commit is contained in:
kylebunting 2021-03-16 19:54:42 -04:00
Родитель 06479073af
Коммит ef1cdd3977
71 изменённых файлов: 2003 добавлений и 799 удалений

Просмотреть файл

@ -1,767 +0,0 @@
![](https://github.com/Microsoft/MCW-Template-Cloud-Workshop/raw/master/Media/ms-cloud-workshop.png 'Microsoft Cloud Workshops')
<div class="MCWHeader1">
Serverless architecture
</div>
<div class="MCWHeader2">
Hands-on lab unguided
</div>
<div class="MCWHeader3">
June 2018
</div>
Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places, and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.
The names of manufacturers, products, or URLs are provided for informational purposes only, and Microsoft makes no representations and warranties, either expressed, implied, or statutory, regarding these manufacturers or the use of the products with any Microsoft technologies. The inclusion of a manufacturer or product does not imply endorsement of Microsoft of the manufacturer or product. Links may be provided to third-party sites. Such sites are not under the control of Microsoft and Microsoft is not responsible for the contents of any linked site or any link contained in a linked site, or any changes or updates to such sites. Microsoft is not responsible for webcasting or any other form of transmission received from any linked site. Microsoft is providing these links to you only as a convenience, and the inclusion of any link does not imply endorsement of Microsoft of the site or the products contained therein.
© 2018 Microsoft Corporation. All rights reserved.
Microsoft and the trademarks listed at <https://www.microsoft.com/legal/intellectualproperty/Trademarks/Usage/General.aspx> are trademarks of the Microsoft group of companies. All other trademarks are the property of their respective owners.
**Contents**
<!-- TOC -->
- [Serverless architecture](#serverless-architecture)
- [Abstract and learning objectives](#abstract-and-learning-objectives)
- [Overview](#overview)
- [Solution architecture](#solution-architecture)
- [Requirements](#requirements)
- [Exercise 1: Azure data, storage, and serverless environment setup](#exercise-1-azure-data-storage-and-serverless-environment-setup)
- [Help references](#help-references)
- [Task 1: Provision the storage account](#task-1-provision-the-storage-account)
- [Tasks to complete](#tasks-to-complete)
- [Exit criteria](#exit-criteria)
- [Task 2: Provision the Function Apps](#task-2-provision-the-function-apps)
- [Tasks to complete](#tasks-to-complete-1)
- [Exit criteria](#exit-criteria-1)
- [Task 3: Provision the Event Grid topic](#task-3-provision-the-event-grid-topic)
- [Tasks to complete](#tasks-to-complete-2)
- [Exit criteria](#exit-criteria-2)
- [Task 4: Provision the Azure Cosmos DB account](#task-4-provision-the-azure-cosmos-db-account)
- [Tasks to complete](#tasks-to-complete-3)
- [Exit criteria](#exit-criteria-3)
- [Task 5: Provision the Computer Vision API service](#task-5-provision-the-computer-vision-api-service)
- [Tasks to complete](#tasks-to-complete-4)
- [Exit criteria](#exit-criteria-4)
- [Exercise 2: Develop and publish the photo processing and data export functions](#exercise-2-develop-and-publish-the-photo-processing-and-data-export-functions)
- [Help references](#help-references-1)
- [Task 1: Configure application settings](#task-1-configure-application-settings)
- [Tasks to complete](#tasks-to-complete-5)
- [Exit criteria](#exit-criteria-5)
- [Task 2: Finish the ProcessImage function](#task-2-finish-the-processimage-function)
- [Tasks to complete](#tasks-to-complete-6)
- [Exit criteria](#exit-criteria-6)
- [Task 3: Publish the Function App from Visual Studio](#task-3-publish-the-function-app-from-visual-studio)
- [Tasks to complete](#tasks-to-complete-7)
- [Exit criteria](#exit-criteria-7)
- [](#)
- [Exercise 3: Create functions in the portal](#exercise-3-create-functions-in-the-portal)
- [Help references](#help-references-2)
- [Task 1: Create function to save license plate data to Azure Cosmos DB](#task-1-create-function-to-save-license-plate-data-to-azure-cosmos-db)
- [Tasks to complete](#tasks-to-complete-8)
- [Exit criteria](#exit-criteria-8)
- [Task 2: Add an Event Grid subscription to the SavePlateData function](#task-2-add-an-event-grid-subscription-to-the-saveplatedata-function)
- [Tasks to complete](#tasks-to-complete-9)
- [Exit criteria](#exit-criteria-9)
- [Task 3: Add an Azure Cosmos DB output to the SavePlateData function](#task-3-add-an-azure-cosmos-db-output-to-the-saveplatedata-function)
- [Tasks to complete](#tasks-to-complete-10)
- [Exit criteria](#exit-criteria-10)
- [Task 4: Create function to save manual verification info to Azure Cosmos DB](#task-4-create-function-to-save-manual-verification-info-to-azure-cosmos-db)
- [Tasks to complete](#tasks-to-complete-11)
- [Exit criteria](#exit-criteria-11)
- [Task 5: Add an Event Grid subscription to the QueuePlateForManualCheckup function](#task-5-add-an-event-grid-subscription-to-the-queueplateformanualcheckup-function)
- [Tasks to complete](#tasks-to-complete-12)
- [Exit criteria](#exit-criteria-12)
- [Task 6: Add an Azure Cosmos DB output to the QueuePlateForManualCheckup function](#task-6-add-an-azure-cosmos-db-output-to-the-queueplateformanualcheckup-function)
- [Tasks to complete](#tasks-to-complete-13)
- [Exit criteria](#exit-criteria-13)
- [Task 7: Configure custom event types for the new Event Grid subscriptions](#task-7-configure-custom-event-types-for-the-new-event-grid-subscriptions)
- [Tasks to complete](#tasks-to-complete-14)
- [Exit criteria](#exit-criteria-14)
- [Exercise 4: Monitor your functions with Application Insights](#exercise-4-monitor-your-functions-with-application-insights)
- [Help references](#help-references-3)
- [Task 1: Provision an Application Insights instance](#task-1-provision-an-application-insights-instance)
- [Tasks to complete](#tasks-to-complete-15)
- [Exit criteria](#exit-criteria-15)
- [Task 2: Enable Application Insights integration in your Function Apps](#task-2-enable-application-insights-integration-in-your-function-apps)
- [Tasks to complete](#tasks-to-complete-16)
- [Task 3: Use the Live Metrics Stream to monitor functions in real time](#task-3-use-the-live-metrics-stream-to-monitor-functions-in-real-time)
- [Tasks to complete](#tasks-to-complete-17)
- [Exit criteria](#exit-criteria-16)
- [Task 4: Observe your functions dynamically scaling when resource-constrained](#task-4-observe-your-functions-dynamically-scaling-when-resource-constrained)
- [Tasks to complete](#tasks-to-complete-18)
- [Exit criteria](#exit-criteria-17)
- [Exercise 5: Explore your data in Azure Cosmos DB](#exercise-5-explore-your-data-in-azure-cosmos-db)
- [Help references](#help-references-4)
- [Task 1: Use the Azure Cosmos DB Data Explorer](#task-1-use-the-azure-cosmos-db-data-explorer)
- [Tasks to complete](#tasks-to-complete-19)
- [Exit criteria](#exit-criteria-18)
- [Exercise 6: Create the data export workflow](#exercise-6-create-the-data-export-workflow)
- [Help references](#help-references-5)
- [Task 1: Create the Logic App](#task-1-create-the-logic-app)
- [Tasks to complete](#tasks-to-complete-20)
- [Exit criteria](#exit-criteria-19)
- [Exercise 7: Configure continuous deployment for your Function App](#exercise-7-configure-continuous-deployment-for-your-function-app)
- [Help references](#help-references-6)
- [Task 1: Create a GitHub repository](#task-1-create-a-github-repository)
- [Tasks to complete](#tasks-to-complete-21)
- [Exit criteria](#exit-criteria-20)
- [Task 2: Add GitHub repository to your Visual Studio solution](#task-2-add-github-repository-to-your-visual-studio-solution)
- [Tasks to complete](#tasks-to-complete-22)
- [Exit criteria](#exit-criteria-21)
- [Task 3: Configure your Function App to use your GitHub repository for continuous deployment](#task-3-configure-your-function-app-to-use-your-github-repository-for-continuous-deployment)
- [Tasks to complete](#tasks-to-complete-23)
- [Exit criteria](#exit-criteria-22)
- [Task 4: Finish your ExportLicensePlates function code and push changes to GitHub to trigger deployment](#task-4-finish-your-exportlicenseplates-function-code-and-push-changes-to-github-to-trigger-deployment)
- [Tasks to complete](#tasks-to-complete-24)
- [Exit criteria](#exit-criteria-23)
- [Exercise 8: Rerun the workflow and verify data export](#exercise-8-rerun-the-workflow-and-verify-data-export)
- [Task 1: Run the Logic App](#task-1-run-the-logic-app)
- [Tasks to complete](#tasks-to-complete-25)
- [Exit criteria](#exit-criteria-24)
- [Task 2: View the exported CSV file](#task-2-view-the-exported-csv-file)
- [Tasks to complete](#tasks-to-complete-26)
- [Exit criteria](#exit-criteria-25)
- [After the hands-on lab](#after-the-hands-on-lab)
- [Task 1: Delete the Resource group in which you placed your Azure resources.](#task-1-delete-the-resource-group-in-which-you-placed-your-azure-resources)
<!-- /TOC -->
## Abstract and learning objectives
In this hand-on lab, you will be challenged to implement an end-to-end scenario using a supplied sample that is based on Microsoft Azure Functions, Azure Cosmos DB, Event Grid, and related services. The scenario will include implementing compute, storage, workflows, and monitoring, using various components of Microsoft Azure. The hands-on lab can be implemented on your own, but it is highly recommended to pair up with other members at the lab to model a real-world experience and to allow each member to share their expertise for the overall solution.
At the end of the hands-on-lab, you will have confidence in designing, developing, and monitoring a serverless solution that is resilient, scalable, and cost-effective.
## Overview
Litware, Inc. is rapidly expanding their toll booth management business to operate in a much larger area. As this is not their primary business, which is online payment services, they are struggling with scaling up to meet the upcoming demand to extract license plate information from a large number of new tollbooths, using photos of vehicles uploaded to cloud storage. Currently, they have a manual process where they send batches of photos to a 3rd-party who manually transcodes the license plates to CSV files that they send back to Litware to upload to their online processing system. They want to automate this process in a way that is cost effective and scalable. They believe serverless is the best route for them, but do not have the expertise to build the solution.
## Solution architecture
Below is a diagram of the solution architecture you will build in this lab. Please study this carefully, so you understand the whole of the solution as you are working on the various components.
![The Solution diagram is described in the text following this diagram.](images/Hands-onlabstep-by-step-Serverlessarchitectureimages/media/image2.png 'Solution diagram')
The solution begins with vehicle photos being uploaded to an Azure Storage blobs container, as they are captured. A blob storage trigger fires on each image upload, executing the photo processing **Azure Function** endpoint (on the side of the diagram), which in turn sends the photo to the **Cognitive Services Computer Vision API OCR** service to extract the license plate data. If processing was successful and the license plate number was returned, the function submits a new Event Grid event, along with the data, to an Event Grid topic with an event type called "savePlateData". However, if the processing was unsuccessful, the function submits an Event Grid event to the topic with an event type called "queuePlateForManualCheckup". Two separate functions are configured to trigger when new events are added to the Event Grid topic, each filtering on a specific event type, both saving the relevant data to the appropriate **Azure Cosmos DB** collection for the outcome, using the Cosmos DB output binding. A **Logic App** that runs on a 15-minute interval executes an Azure Function via its HTTP trigger, which is responsible for obtaining new license plate data from Cosmos DB and exporting it to a new CSV file saved to Blob storage. If no new license plate records are found to export, the Logic App sends an email notification to the Customer Service department via their Office 365 subscription. **Application Insights** is used to monitor all of the Azure Functions in real-time as data is being processed through the serverless architecture. This real-time monitoring allows you to observe dynamic scaling first-hand and configure alerts when certain events take place.
## Requirements
1. Microsoft Azure subscription (non-Microsoft subscription)
2. Local machine or a virtual machine configured with (**complete the day before the lab!**):
a. Visual Studio Community 2019 or greater
1. <https://www.visualstudio.com/vs/>
b. Azure development workload for Visual Studio
1. <https://docs.microsoft.com/azure/azure-functions/functions-develop-vs#prerequisites>
c. .NET Framework 4.7 runtime (or higher)
1. <https://www.microsoft.com/net/download/windows>
3. Office 365 account. If required, you can sign up for an Office 365 trial at:
a. <https://portal.office.com/Signup/MainSignup15.aspx?Dap=False&QuoteId=79a957e9-ad59-4d82-b787-a46955934171&ali=1>
4. GitHub account. You can create a free account at <https://github.com>.
5. Follow all the steps provided in [Before the Hands-on Lab](Before%20the%20HOL%20-%20Serverless%20architecture.md)
## Exercise 1: Azure data, storage, and serverless environment setup
**Duration**: 30 minutes
You must provision a few resources in Azure before you start developing the solution. Ensure all resources use the same resource group that was created for the App Service Environment.
In this exercise, you will provision a blob storage account using the Hot tier, and create two containers within to store uploaded photos and exported CSV files. You will then provision two Function Apps instances, one you will deploy from Visual Studio, and the other you will manage using the Azure portal. Next, you will create a new Event Grid topic. After that, you will create an Azure Cosmos DB account with two collections. Finally, you will provision a new Cognitive Services Computer Vision API service for applying object character recognition (OCR) on the license plates.
### Help references
| | |
| ------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------: |
| **Description** | **Links** |
| Creating a storage account (blob hot tier) | <https://docs.microsoft.com/azure/storage/common/storage-create-storage-account?toc=%2fazure%2fstorage%2fblobs%2ftoc.json%23create-a-storage-account> |
| Creating a function app | <https://docs.microsoft.com/azure/azure-functions/functions-create-first-azure-function%23create-a-function-app> |
| Concepts in Event Grid | <https://docs.microsoft.com/azure/event-grid/concepts> |
| Creating an Azure Cosmos DB account | <https://docs.microsoft.com/azure/cosmos-db/tutorial-develop-sql-api-dotnet%23create-an-azure-cosmos-db-account> |
### Task 1: Provision the storage account
In this exercise, you will provision a Blob storage account, using the Hot access tier and placing it in your resource group. You will copy the storage connection string from access keys, then create two private containers: images and export.
#### Tasks to complete
- Create a blob storage instance from within Azure
#### Exit criteria
- Save the storage connection string for later
- There should be two private containers: images and export
### Task 2: Provision the Function Apps
Provision two separate Function Apps. One will be deployed to from Visual Studio, and the other one will be managed through the portal.
#### Tasks to complete
- Create a Function App whose name ends with **Events**. Select the Consumption plan.
- Create a Function App whose name ends with **FunctionApp**. Make a note of the name, as this will be one deployed to from Visual Studio. Select the Consumption plan.
#### Exit criteria
- Save the names for later, marking which one you will be deploying to from Visual Studio
### Task 3: Provision the Event Grid topic
The Event Grid topic is the eventing backplane that allows the functions to trigger and send data to one another
#### Tasks to complete
- Create an Event Grid topic from within Azure
#### Exit criteria
- Save the topic endpoint for later
- Save the access key for later
### Task 4: Provision the Azure Cosmos DB account
Azure Cosmos DB will serve as your unstructured data store for processed license plates and those queued for manual review.
#### Tasks to complete
- Create an Azure Cosmos DB account from within Azure
- Select the SQL API
#### Exit criteria
- Create a collection named Processed with a Database Id of LicensePlates. It should have fixed storage capacity and have a throughput of 5000 RU/s.
- Create a collection named NeedsManualReview with a Database Id of LicensePlates. It should have fixed storage capacity and have a throughput of 5000 RU/s.
- Save the URI for later
- Save the key for later
### Task 5: Provision the Computer Vision API service
The Computer Vision API will provide OCR capability on-demand from your ProcessImages function.
#### Tasks to complete
- Create a Computer Vision API service from within Azure
- Select the S1 pricing tier
#### Exit criteria
- Save the Endpoint for later
- Save the key for later
## Exercise 2: Develop and publish the photo processing and data export functions
**Duration**: 45 minutes
Use Visual Studio and its integrated Azure Functions tooling to develop and debug the functions locally, then publish them to Azure. The starter project solution, TollBooths, contains most of the code needed. You will add in the missing code before deploying to Azure.
### Help references
| | |
| ------------------------------------- | :--------------------------------------------------------------------------: |
| **Description** | **Links** |
| Code and test Azure Functions locally | <https://docs.microsoft.com/azure/azure-functions/functions-run-local> |
### Task 1: Configure application settings
In this task, you will apply application settings using the Microsoft Azure Portal. You will then add the application settings to the TollBooth Starter Project.
#### Tasks to complete
- Open the TollBooth starter project in Visual Studio
- Open the local.settings.json file as a reference
- Navigate to the Function App you created whose name ends with **FunctionApp**. If you did not use this naming convention, that's fine. Just be sure to make a note of the name so you can distinguish it from the Function App you will be developing using the portal later on.
- Open the Function App's application settings, then add new application keys and values, using the local.settings.json file as a reference
#### Exit criteria
- Your Function App has the following new application settings populated with the correct values:
| | |
| ------------------------ | :-----------------------------------------------------------------------------------------------------------------------------------------------: |
| **Application Key** | **Value** |
| computerVisionApiUrl | Computer Vision API endpoint you copied earlier. Append **/ocr** to the end. Example: https://westus2.api.cognitive.microsoft.com/vision/v1.0/ocr |
| computerVisionApiKey | Computer Vision API key |
| eventGridTopicEndpoint | Event Grid Topic endpoint |
| eventGridTopicKey | Event Grid Topic access key |
| cosmosDBEndPointUrl | Cosmos DB URI |
| cosmosDBAuthorizationKey | Cosmos DB Primary Key |
| cosmosDBDatabaseId | Cosmos DB database id (LicensePlates) |
| cosmosDBCollectionId | Cosmos DB processed collection id (Processed) |
| exportCsvContainerName | Blob storage CSV export container name (export) |
| blobStorageConnection | Blob storage connection string |
- Populate the save values in your local.settings.json files if you plan on debugging your Function App locally
### Task 2: Finish the ProcessImage function
There are a few components within the starter project that must be completed, marked as TODO in the code. The first set of TODO items we will address are in the ProcessImage function, the FindLicensePlateText class that calls the Computer Vision API, and finally the SendToEventGrid.cs class, which is responsible for sending processing results to the Event Grid topic you created earlier.
#### Tasks to complete
- Complete TODO item found in ProcessImage.cs
- Complete TODO item found in FindLicensePlateText.cs
- Complete TODO items found in SendToEventGrid.cs. Make note of the event types you define here, as they will be used later on when creating new functions in the second Function App you provisioned earlier. Suggested event type names are savePlateData and queuePlateForManualCheckup.
#### Exit criteria
- You completed TODO items 1-4
- You copied the two event type names you defined under TODO 3 & 4, for future reference
### Task 3: Publish the Function App from Visual Studio
In this task, you will publish the Function App from the starter project in Visual Studio to the existing Function App you provisioned in Azure.
#### Tasks to complete
- Publish the TollBooth project to the existing Function App you created whose name ends in FunctionApp
#### Exit criteria
- Navigate to the Function App in Azure and verify that both functions appear within
###
## Exercise 3: Create functions in the portal
**Duration**: 45 minutes
Create two new Azure Functions written in Node.js, using the Azure portal. These will be triggered by Event Grid and output to Azure Cosmos DB to save the results of license plate processing done by the ProcessImage function.
### Help references
| | |
| ----------------------------------------------------------------- | :-----------------------------------------------------------------------------------------------------------: |
| **Description** | **Links** |
| Create your first function in the Azure portal | <https://docs.microsoft.com/azure/azure-functions/functions-create-first-azure-function> |
| Store unstructured data using Azure Functions and Azure Cosmos DB | <https://docs.microsoft.com/azure/azure-functions/functions-integrate-store-unstructured-data-cosmosdb> |
### Task 1: Create function to save license plate data to Azure Cosmos DB
In this task, you will create a new Node.js function triggered by Event Grid and that outputs successfully processed license plate data to Azure Cosmos DB.
#### Tasks to complete
- Open the Function App you created whose name ends with **Events**. If you did not use this naming convention, make sure you select the Function App that you [did not]{.underline} deploy in the previous exercise.
- Create a new Event Grid trigger function named SavePlateData with the language set to JavaScript
- Update the function code to set the context.bindings.outputDocument to a new JSON file with the following signature:
```
{
fileName : '',
licensePlateText : '',
timeStamp : '',
exported : false
}
```
- The values should be set by the incoming Event Grid data properties
#### Exit criteria
- You have a new function triggered by Event Grid, saving that Event Grid data to an Azure Cosmos DB output binding
### Task 2: Add an Event Grid subscription to the SavePlateData function
In this task, you will add an Event Grid subscription to the SavePlateData function. This will ensure that the events sent to the Event Grid topic containing the savePlateData event type are routed to this function.
#### Tasks to complete
- Add an Event Grid subscription to the new SavePlateData function
- This subscription should subscribe to EventGrid Topics, and to all event types
#### Exit criteria
- You have a new Event Grid Subscription URL configured for your function's Event Grid Trigger
### Task 3: Add an Azure Cosmos DB output to the SavePlateData function
In this task, you will add an Azure Cosmos DB output binding to the SavePlateData function, enabling it to save its data to the Processed collection.
#### Tasks to complete
- Add a new Azure Cosmos DB output binding to the SavePlateData function
- Connect it to the Azure Cosmos DB account you created earlier
- Set the Database name to LicensePlates, and the Collection name to Processed
#### Exit criteria
- Your function has a new Azure Cosmos DB output configured under Integrate
### Task 4: Create function to save manual verification info to Azure Cosmos DB
In this task, you will create a new Node.js function triggered by Event Grid, and that outputs information about photos that need to be manually verified to Azure Cosmos DB.
#### Tasks to complete
- Open the Function App you created whose name ends with **Events**. If you did not use this naming convention, make sure you select the Function App that you [did not]{.underline} deploy in the previous exercise.
- Create a new Event Grid trigger function named QueuePlateForManualCheckup with the language set to JavaScript
- Update the function code to set the context.bindings.outputDocument to a new JSON file with the following signature:
```
{
fileName : '',
licensePlateText : '',
timeStamp : '',
resolved : false
}
```
- The values should be set by the incoming Event Grid data properties
#### Exit criteria
- You have a new function triggered by Event Grid, saving that Event Grid data to an Azure Cosmos DB output binding
### Task 5: Add an Event Grid subscription to the QueuePlateForManualCheckup function
In this task, you will add an Event Grid subscription to the QueuePlateForManualCheckup function. This will ensure that the events sent to the Event Grid topic containing the queuePlateForManualCheckup event type are routed to this function.
#### Tasks to complete
- Add an Event Grid subscription to the new QueuePlateForManualCheckup function
- This subscription should subscribe to EventGrid Topics, and to all event types
#### Exit criteria
- You have a new Event Grid Subscription URL configured for your function's Event Grid Trigger
### Task 6: Add an Azure Cosmos DB output to the QueuePlateForManualCheckup function
In this task, you will add an Azure Cosmos DB output binding to the QueuePlateForManualCheckup function, enabling it to save its data to the NeedsManualReview collection.
#### Tasks to complete
- Add a new Azure Cosmos DB output binding to the QueuePlateForManualCheckup function
- Connect it to the Azure Cosmos DB account you created earlier
- Set the Database name to LicensePlates, and the Collection name to NeedsManualReview
#### Exit criteria
- Your function has a new Azure Cosmos DB output configured under Integrate
### Task 7: Configure custom event types for the new Event Grid subscriptions
In this task, you will configure a custom event type for each new Event Grid subscription you created for your functions in the previous steps of this exercise. Currently the event types are set to All. We want to narrow this down to only the event types specified within the SendToEventGrid class in the TollBooth solution. This will ensure that all other event types are ignored by your functions.
#### Tasks to complete
- Open your Event Grid Topic, then select the Event Grid subscription for the SavePlateData function
- Configure a custom event type named **savePlateData**. If you specified a different name in the SendToEventGrid class in the TollBooth solution, use that instead.
- Select the Event Grid subscription for the QueuePlateForManualCheckup function
- Configure a custom event type named **queuePlateForManualCheckup**. If you specified a different name in the SendToEventGrid class in the TollBooth solution, use that instead.
#### Exit criteria
- Both Event Grid subscriptions have custom event types assigned, as specified within the SendToEventGrid class, instead of All
## Exercise 4: Monitor your functions with Application Insights
**Duration**: 45 minutes
Application Insights can be integrated with Azure Function Apps to provide robust monitoring for your functions. In this exercise, you will provision a new Application Insights account and configure your Function Apps to send telemetry to it.
### Help references
| | |
| ------------------------------------------------------------- | :------------------------------------------------------------------------------------: |
| **Description** | **Links** |
| Monitor Azure Functions using Application Insights | <https://docs.microsoft.com/azure/azure-functions/functions-monitoring> |
| Live Metrics Stream: Monitor & Diagnose with 1-second latency | <https://docs.microsoft.com/azure/application-insights/app-insights-live-stream> |
### Task 1: Provision an Application Insights instance
#### Tasks to complete
- Create an Application Insights instance from within Azure
- Select the ASP.NET web application type
#### Exit criteria
- Save the Instrumentation Key
### Task 2: Enable Application Insights integration in your Function Apps
Both of the Function Apps need to be updated with the Application Insights instrumentation key so they can start sending telemetry to your new instance.
#### Tasks to complete
- Add the Application Insights instrumentation key to both Function Apps
### Task 3: Use the Live Metrics Stream to monitor functions in real time
Now that Application Insights has been integrated into your Function Apps, you can use the Live Metrics Stream to see the functions' telemetry in real time.
#### Tasks to complete
- Open the Live Metrics Stream in your Application Insights instance. You can open your instance directly from the Function App.
- Open the starter solution in Visual Studio and update the App.config file in the UploadImages project with your Blob storage connection string
- Run the UploadImages project and choose Option 1 to upload a handful of test photos. View the incoming telemetry in the Live Metrics Stream. **Please note**, since our function with the blob trigger is running on a Consumption plan, there can be up to a 10-minute delay in processing new blobs after the function app has gone idle. After the function app is running, blobs are processed immediately. To avoid this initial delay, consider one of the following options: Use an App Service plan with Always On enabled, or use another mechanism to trigger the blob processing, such as a queue message that contains the blob name or an Event Grid trigger. Sometimes simply opening the function on the portal speeds up the process.
- Re-run the UploadImages console application, this time choosing Option 2 to upload 1,000 photos
#### Exit criteria
- Take note of the number of servers online and the various graphs in the Live Metrics Stream, as you are uploading 1,000 photos. This data will be used as a comparison later.
### Task 4: Observe your functions dynamically scaling when resource-constrained
In this task, you will change the Computer Vision API to the Free tier. This will limit the number of requests to the OCR service to 10 per minute. Once changed, run the UploadImages console app to upload 1,000 images again. The resiliency policy programmed into the FindLicensePlateText.MakeOCRRequest method of the ProcessImage function will begin exponentially backing off requests to the Computer Vision API, allowing it to recover and lift the rate limit. This intentional delay will greatly increase the function's response time, thus causing the Consumption plan's dynamic scaling to kick in, allocating several more servers. You will watch all of this happen in real time using the Live Metrics Stream view.
#### Tasks to complete
- Set the Computer Vision API pricing tier to F0 Free
- Open the Live Metrics Stream in your Application Insights instance. You can open your instance directly from the Function App.
- Run the UploadImages console application, choosing Option 2 to upload 1,000 photos
#### Exit criteria
- Take note of the number of servers online and the various graphs in the Live Metrics Stream, as you are uploading 1,000 photos. After running for a couple of minutes, you should start to notice a few things. The Request Duration will start to increase over time. As this happens, you should notice more servers being brought online. Each time a server is brought online, you should see a message in the Sample Telemetry stating that it is "Generating 2 job function(s)", followed by a Starting Host message. You should also see messages logged by the resiliency policy that the Computer Vision API server is throttling the requests. This is known by the response codes sent back from the service (429). A sample message is "Computer Vision API server is throttling our requests. Automatically delaying for 32000ms".
- Stop uploading photos after some time, then set the Computer Vision API pricing tier back to S1 Standard
## Exercise 5: Explore your data in Azure Cosmos DB
**Duration**: 15 minutes
In this exercise, you will use the Azure Cosmos DB Data Explorer in the portal to view saved license plate data.
### Help references
| | |
| --------------------- | :-------------------------------------------------------------: |
| **Description** | **Links** |
| About Azure Cosmos DB | <https://docs.microsoft.com/azure/cosmos-db/introduction> |
### Task 1: Use the Azure Cosmos DB Data Explorer
In this exercise, the attendee will apply application settings using the Microsoft Azure Portal. The attendee will then deploy the Web API from the Starter Project.
#### Tasks to complete
- View a few documents saved to the Processed collection
- View a few documents saved to the NeedsManualReview collection
- Create a new SQL query on the Processed collection that counts the number of processed documents that have not been exported
#### Exit criteria
- You should see several documents in the Processed collection, and the license plate text that was extracted from the photos using the Computer Vision API's OCR capabilities
- Notice that the first four properties in the Processed document are properties added by your functions. The rest are standard properties assigned by Cosmos DB.
- You should see several documents in the NeedsManualReview collection
- Your SQL query should, at this point, equal to the number of total documents in the Processed collection
## Exercise 6: Create the data export workflow
**Duration**: 30 minutes
In this exercise, you create a new Logic App for your data export workflow. This Logic App will execute periodically and call your ExportLicensePlates function, then conditionally send an email if there were no records to export.
### Help references
| | |
| ------------------------------------ | :-------------------------------------------------------------------------------------------------------------------: |
| **Description** | **Links** |
| What are Logic Apps? | <https://docs.microsoft.com/azure/logic-apps/logic-apps-what-are-logic-apps> |
| Call Azure Functions from logic apps | <https://docs.microsoft.com/azure/logic-apps/logic-apps-azure-functions%23call-azure-functions-from-logic-apps> |
### Task 1: Create the Logic App
#### Tasks to complete
- Provision the Logic App service
- Design a new Logic App with a Recurrence trigger that fires every 15 minutes
- Add an action to the trigger using the Azure Functions connector to connect to your Function App whose name ends in **FunctionApp**, or contains the ExportLicensePlates function. Select the ExportLicensePlates function.
- Add a condition that evaluates your function's Status Code value where it is equal to 200. This evaluates the status code returned from the ExportLicensePlates function, which will return a 200 code when license plates are found and exported. Otherwise, it sends a 204 (NoContent) status code when no license plates were discovered that need to be exported. We will conditionally send an email if any response other than 200 is returned.
- Add an Office 365 Outlook Send Mail action to the condition's If false block. The email should be sent to you, have a subject of "Toll Booth license plate export failed" (or similar), and a message in the body that includes the Status code value from the ExportLicensePlates function.
- Save and run the Logic App
#### Exit criteria
- You should start receiving email alerts because the license plate data is not being exported. This is because we need to finish making changes to the ExportLicensePlates function so that it can extract the license plate data from Azure Cosmos DB, generate the CSV file, and upload it to Blob storage.
- While in the Logic Apps Designer, you will see the run result of each step of your workflow. A green checkmark is placed next to each step that successfully executed, showing the execution time to complete. This can be used to see how each step is working, and you can select the executed step and see the raw output.
![In the Logic App Designer, green check marks display next to Recurrence, ExportLicensePlates, Condition, and Send an email.](images/Hands-onlabunguided-Serverlessarchitectureimages/media/image11.png 'Logic App Designer')
- Disable the Logic App for now, so it doesn't keep emailing you while completing the next exercise
## Exercise 7: Configure continuous deployment for your Function App
**Duration**: 40 minutes
In this exercise, configure your Function App that contains the ProcessImages function for continuous deployment. You will first set up a GitHub source code repository, then set that as the deployment source for the Function App.
### Help references
| | |
| ----------------------------------------- | :--------------------------------------------------------------------------------------: |
| **Description** | **Links** |
| Creating a new GitHub repository | <https://help.github.com/articles/creating-a-new-repository/> |
| Continuous deployment for Azure Functions | <https://docs.microsoft.com/azure/azure-functions/functions-continuous-deployment> |
### Task 1: Create a GitHub repository
#### Tasks to complete
- Create a new public GitHub repository for this lab
#### Exit criteria
- Copy the repository's HTTPS git path and save for later
### Task 2: Add GitHub repository to your Visual Studio solution
#### Tasks to complete
- Commit your changes to the TollBooth starter project in Visual Studio
- Select Sync link after committing, then add the link to your GitHub repository under Push to Remote Repository. This should be the HTTPS git path you copied in the previous task.
- Publish to your GitHub repository
#### Exit criteria
- Refresh your GitHub repository page in your browser. You should see that the project files have been added. Navigate to the TollBooth folder of your repo. Notice that the local.settings.json file has not been uploaded. That's because the .gitignore file of the TollBooth project explicitly excludes that file from the repository, making sure you don't accidentally share your application secrets.
![On the GitHub Repository page for serverless-architecture-lab, on the Code tab, project files display.](images/Hands-onlabunguided-Serverlessarchitectureimages/media/image12.png 'GitHub Repository page')
### Task 3: Configure your Function App to use your GitHub repository for continuous deployment
#### Tasks to complete
- Open the Azure Function App you created whose name ends with **FunctionApp**, or the name you specified for the Function App containing the ProcessImage function
- Setup a new GitHub deployment option, pointing to your new GitHub repo
#### Exit criteria
- After continuous deployment is configured, all file changes in your deployment source are copied to the function app, and a full site deployment is triggered. The site is redeployed when files in the source are updated.
### Task 4: Finish your ExportLicensePlates function code and push changes to GitHub to trigger deployment
#### Tasks to complete
- Complete TODO items found in DatabaseMethods.cs
- Complete TODO item found in FileMethods.cs
- Commit and sync your changes to GitHub
#### Exit criteria
- You completed TODO items 5-7
- Go back to Deployments for your Function App in the portal. You should see an entry for the deployment kicked off by this last commit. Check the timestamp on the message to verify that you are looking at the latest one.
![On the Deployments blade, a partially-completed full-circle graph displays next to the message, Finished the ExportLicensePlates function, GitHub, building, 8:49 PM.](images/Hands-onlabunguided-Serverlessarchitectureimages/media/image13.png 'Deployments blade')
## Exercise 8: Rerun the workflow and verify data export
**Duration**: 10 minutes
With the latest code changes in place, run your Logic App and verify that the files are successfully exported.
### Task 1: Run the Logic App
#### Tasks to complete
- Re-enable your Logic App
- Run the Recurrence trigger
#### Exit criteria
- Select the latest run history item. If the expression result for the condition is **true**, then that means the CSV file should've been exported to Blob storage. Be sure to disable the Logic App so it doesn't keep sending you emails every 15 minutes.
![In Logic App Designer, in the Condition section, under Inputs, true is circled.](images/Hands-onlabunguided-Serverlessarchitectureimages/media/image14.png 'Logic App Designer')
### Task 2: View the exported CSV file
#### Tasks to complete
- Browse the export container in your Blob storage account
- Download the CSV file generated when you last ran your Logic App
#### Exit criteria
1. The CSV file should look similar to the following:
![A CSV file displays with the following columns: FileName, LicensePlateText, TimeStamp, and LicencePlateFound.](images/Hands-onlabunguided-Serverlessarchitectureimages/media/image15.png 'CSV file')
- The ExportLicensePlates function updates all of the records it exported by setting the exported value to true. This makes sure that only new records since the last export are included in the next one. Verify this by re-executing the script in Azure Cosmos DB that counts the number of documents in the Processed collection where exported is false. It should return 0 unless you've subsequently uploaded new photos.
## After the hands-on lab
**Duration**: 10 minutes
In this exercise, attendees will deprovision any Azure resources that were created in support of the lab.
### Task 1: Delete the Resource group in which you placed your Azure resources.
1. From the Portal, navigate to the blade of your **Resource Group** and select **Delete** in the command bar at the top
2. Confirm the deletion by re-typing the **resource group name** and selecting **Delete**
3. If you created a different resource group for your virtual machined, be sure to delete that as well
4. Optionally, delete the GitHub repository you created for this lab by selecting **settings** and then **Delete this repository** from the GitHub website
You should follow all steps provided _after_ attending the hands-on lab.

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 83 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 283 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 70 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 87 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 110 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 56 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 37 KiB

Просмотреть файл

@ -1,4 +1,4 @@
![Microsoft Cloud Workshops](https://github.com/Microsoft/MCW-Template-Cloud-Workshop/raw/master/Media/ms-cloud-workshop.png 'Microsoft Cloud Workshops')
![Microsoft Cloud Workshops](https://github.com/Microsoft/MCW-Template-Cloud-Workshop/raw/master/Media/ms-cloud-workshop.png "Microsoft Cloud Workshops")
<div class="MCWHeader1">
Serverless architecture
@ -25,7 +25,8 @@ The names of manufacturers, products, or URLs are provided for informational pur
- [Serverless architecture before the hands-on lab setup guide](#serverless-architecture-before-the-hands-on-lab-setup-guide)
- [Requirements](#requirements)
- [Before the hands-on lab](#before-the-hands-on-lab)
- [Task 1: Create a new Azure Resource group](#task-1-create-a-new-azure-resource-group)
- [Task 1: Create a resource group](#task-1-create-a-resource-group)
- [Task 2: Run ARM template to provision lab resources](#task-2-run-arm-template-to-provision-lab-resources)
- [Task 2: Set up a development environment](#task-2-set-up-a-development-environment)
- [Task 3: Disable IE Enhanced Security](#task-3-disable-ie-enhanced-security)
- [Task 4: Install Microsoft Edge](#task-4-install-microsoft-edge)
@ -50,21 +51,114 @@ The names of manufacturers, products, or URLs are provided for informational pur
## Before the hands-on lab
**Duration**: 10 minutes
**Duration**: 15 minutes
In this exercise, you set up your environment for use in the rest of the hands-on lab. You should follow all steps provided _before_ attending the hands-on lab.
> **Important**: Many Azure resources require globally unique names. Throughout these steps, the word "SUFFIX" appears as part of resource names. You should replace this with your Microsoft alias, initials, or another value to ensure uniquely named resources.
### Task 1: Create a resource group
1. In the [Azure portal](https://portal.azure.com), select **Resource groups** from the Azure services list.
![Resource groups is highlighted in the Azure services list.](media/azure-services-resource-groups.png "Azure services")
2. On the Resource groups blade, select **+Add**.
![+Add is highlighted in the toolbar on Resource groups blade.](media/resource-groups-add.png "Resource groups")
3. On the Create a resource group **Basics** tab, enter the following:
- **Subscription**: Select the subscription you are using for this hands-on lab.
- **Resource group**: Enter `hands-on-lab-SUFFIX` as the name of the new resource group.
- **Region**: Select the region you are using for this hands-on lab.
![The values specified above are entered into the Create a resource group Basics tab.](media/create-resource-group.png "Create resource group")
4. Select **Review + Create**.
5. On the **Review + create** tab, ensure the Validation passed message is displayed and then select **Create**.
### Task 2: Run ARM template to provision lab resources
In this task, you run an Azure Resource Manager (ARM) template to create the resources required for this hands-on lab. The components are deployed inside a new virtual network (VNet) to facilitate communication between the VMs and SQL MI. The ARM template also adds inbound and outbound security rules to the network security groups associated with SQL MI and the VMs, including opening port 3389 to allow RDP connections to the JumpBox. In addition to creating resources, the ARM template also executes PowerShell scripts on each of the VMs to install software and configure the servers. The resources created by the ARM template include:
- A virtual network with three subnets, ManagedInstance, Management, and a Gateway subnet.
- A virtual network gateway associated with the Gateway subnet.
- A route table.
- Azure SQL Managed Instance (SQL MI), added to the ManagedInstance subnet.
- A JumpBox with Visual Studio 2019 Community Edition and SQL Server Management Studio (SSMS installed, added to the Management subnet).
- A SQL Server 2008 R2 VM with the Data Migration Assistant (DMA) installed, added to the Management subnet.
- Azure Database Migration Service (DMS).
- Azure App Service Plan and App Service (Web App).
- Azure Blob Storage account.
> **Note**: You can review the steps to manually provision and configure the lab resources in the [Manual resource setup guide](./Manual-resource-setup.md).
1. In the [Azure portal](https://portal.azure.com/), select the **Show portal menu** icon and then select **+Create a resource** from the menu.
![The Show portal menu icon is highlighted, and the portal menu is displayed. Create a resource is highlighted in the portal menu.](media/create-a-resource.png "Create a resource")
2. Before running the ARM template, it is beneficial to quickly verify that you can provision SQL MI in your subscription. In the [Azure portal](https://portal.azure.com), select **+Create a resource**, enter "sql managed instance" into the Search the Marketplace box, and then select **Azure SQL Managed Instance** from the results.
![+Create a resource is selected in the Azure navigation pane, and "sql managed instance" is entered into the Search the Marketplace box. Azure SQL Managed Instance is selected in the results.](media/create-resource-sql-mi.png "Create SQL Managed Instance")
3. Select **Create** on the Azure SQL Managed Instance blade.
![The Create button is highlighted on the Azure SQL Managed Instance blade.](media/sql-mi-create.png "Create Azure SQL Managed Instance")
4. On the SQL managed instance blade, look for a message stating that "Managed instance creation is not available for the chosen subscription type...", which will be displayed near the bottom of the SQL managed instance blade.
![A message is displayed stating that SQL MI creation not available in the selected subscription.](media/sql-mi-creation-not-available.png "SQL MI creation not available")
> **Note**: If you see the message stating that Managed Instance creation is not available for the chosen subscription type, follow the instructions for [obtaining a larger quota for SQL Managed Instance](https://docs.microsoft.com/azure/sql-database/sql-database-managed-instance-resource-limits#obtaining-a-larger-quota-for-sql-managed-instance) before proceeding with the following steps.
5. You are now ready to begin the ARM template deployment. To open a custom deployment screen in the Azure portal, select the Deploy to Azure button below:
<a href ="https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fmicrosoft%2FMCW-Migrating-SQL-databases-to-Azure%2Fmaster%2FHands-on%20lab%2Flab-files%2FARM-template%2Fazure-deploy.json" target="_blank" title="Deploy to Azure">
<img src="http://azuredeploy.net/deploybutton.png"/>
</a>
> **Note**: Running the ARM template occasionally results in a `ResourceDeploymentFailure` error, with a code of `VnetSubnetConflictedWithIntendedPolicy`. This error is not caused by an issue with the ARM template and appears to be the result of backend resource deployment issues in Azure. At this time, the workaround is first to try the deployment in a different region. If that does not work, try going through the [Manual resource setup guide](./Manual-resource-setup.md) to create the SQL MI database.
6. On the custom deployment screen in the Azure portal, enter the following:
- **Subscription**: Select the subscription you are using for this hands-on lab.
- **Resource group**: Select the hands-on-lab-SUFFIX resource group from the dropdown list.
- **Region**: Select the region you used for the hands-on-lab-SUFFIX resource group.
- **Managed Instance Name**: Accept the default value, **sqlmi**. The actual name must be globally unique, so a unique string is generated from your Resource Group and appended to the name during provisioning.
- **Admin Username**: Accept the default value, **sqlmiuser**.
- **Admin Password**: Accept the default value, **Password.1234567890**.
- **V Cores**: Accept the default value, **4**.
- **Storage Size in GB**: Accept the default value, **32**.
![The Custom deployment blade is displayed, and the information above is entered on the Custom deployment blade.](media/azure-custom-deployment.png "Custom deployment blade")
7. Select **Review + create** to review the custom deployment.
8. On the Review + create blade, ensure the _Validation passed_ message is displayed and then select **Create** to begin the custom deployment.
![On the Review + create blade for the custom deployment, the Validation passed message is highlighted, and the Create button is highlighted.](media/azure-custom-deployment-review-create.png "Review + create custom deployment")
> **Note**: The deployment of the custom ARM template can take over 4 hours due to the inclusion of SQL MI. However, the deployment of most of the resources completes within a few minutes. The JumpBox and SQL Server 2008 R2 VMs should finish in about 15 minutes.
9. You can monitor the deployment's progress by navigating to the hands-on-lab-SUFFIX resource group in the Azure portal and then selecting **Deployments** from the left-hand menu. The deployment is named **Microsoft.Template**. Select that to view the progress of each item in the template.
![The Deployments menu item is selected in the left-hand menu of the hands-on-lab-SUFFIX resource group and the Microsoft.Template deployment is highlighted.](media/resource-group-deployments.png "Resource group deployments")
> Check back in a few hours to monitor the progress of your SQL MI provisioning. If the provisioning goes on for longer than 7 hours, you may need to issue a support ticket in the Azure portal to request the provisioning process be unblocked by Microsoft support.
You should follow all steps provided _before_ attending the Hands-on lab.
In this exercise, you will set up your environment you will use for the rest of the exercises. This will involve downloading the sample application and creating your Azure resource group for the lab.
### Task 1: Create a new Azure Resource group
1. Open the [Azure Portal](https://portal.azure.com).
2. Within the Azure Management Portal, open the **Resource groups** tile and select **Add**.
![In the menu of the Azure Portal, Resource groups is selected. In the Resource Groups blade, the Add button is selected.](images/Setup/image9.png 'Azure Portal')
3. Specify the name of the resource group as **ServerlessArchitecture**, and choose the Azure region to which you want to deploy the lab. This resource group will be used throughout the rest of the lab. Select **Review + Create**. This will show you a summary of changes. Select **Create** to create the resource group.
![In the Create a resource group blade, the Resource group field displays ServerlessArchitecture.](images/Setup/image10.png 'Resource group blade')
### Task 2: Set up a development environment
@ -116,15 +210,15 @@ If you do not have a machine with Visual Studio Community 2019 (or greater) and
3. Select **Local Server**.
![Local Server is selected from the Server Manager menu.](images/Setup/image5.png 'Server Manager menu')
![Local Server is selected from the Server Manager menu.](media/image5.png 'Server Manager menu')
4. On the side of the pane, for **IE Enhanced Security Configuration**, if it displays **On**, select it.
![The IE Enhanced Security Configuration setting is set to On. The On item is selected.](images/Setup/image6.png 'IE Enhanced Security Configuration')
![The IE Enhanced Security Configuration setting is set to On. The On item is selected.](media/image6.png 'IE Enhanced Security Configuration')
- Change to **Off** for Administrators and select **OK**.
![In the Internet Explorer Enhanced Security Configuration dialog box, under Administrators, the Off button is selected.](images/Setup/image7.png 'Internet Explorer Enhanced Security Configuration dialog box')
![In the Internet Explorer Enhanced Security Configuration dialog box, under Administrators, the Off button is selected.](media/image7.png 'Internet Explorer Enhanced Security Configuration dialog box')
### Task 4: Install Microsoft Edge
@ -146,13 +240,13 @@ If you do not have a machine with Visual Studio Community 2019 (or greater) and
### Task 6: Download and explore the TollBooth starter solution
1. From your LabVM, download the starter files by downloading a .zip copy of the Cosmos DB real-time advanced analytics GitHub repo.
1. From your LabVM, download the starter files by downloading a .zip copy of the Serverless architecture MCW GitHub repo.
2. In a web browser, navigate to the [MCW Serverless architecture repo](https://github.com/Microsoft/MCW-Serverless-architecture).
3. On the repo page, select **Clone or download**, then select **Download ZIP**.
![On the GitHub Repository web page, the Clone or Download drop down is expanded with the Download ZIP button selected.](images/Setup/github-download-repo.png)
![On the GitHub Repository web page, the Clone or Download drop down is expanded with the Download ZIP button selected.](media/github-download-repo.png)
4. Unzip the contents to the folder **C:\\ServerlessMCW\\**

Просмотреть файл

@ -0,0 +1,735 @@
# Manual resource deployment and setup guide
This guide provides step-by-step instructions to manually provision and the configure resources created by the ARM template referenced in the before the hands-on lab guide.
April 2021
**Contents**:
- [Manual resource deployment and setup guide](#manual-resource-deployment-and-setup-guide)
- [Task 1: Create a virtual network](#task-1-create-a-virtual-network)
- [Task 2: Create a VPN gateway](#task-2-create-a-vpn-gateway)
- [Task 3: Provision SQL MI](#task-3-provision-sql-mi)
- [Task 4: Create the JumpBox VM](#task-4-create-the-jumpbox-vm)
- [Task 5: Create SQL Server 2008 R2 virtual machine](#task-5-create-sql-server-2008-r2-virtual-machine)
- [Task 6: Create Azure Database Migration Service](#task-6-create-azure-database-migration-service)
- [Task 7: Provision a Web App](#task-7-provision-a-web-app)
- [Task 8: Create an Azure Blob Storage account](#task-8-create-an-azure-blob-storage-account)
- [Task 9: Connect to the JumpBox](#task-9-connect-to-the-jumpbox)
- [Task 10: Install required software on the JumpBox](#task-10-install-required-software-on-the-jumpbox)
- [Task 11: Connect to SqlServer2008 VM](#task-11-connect-to-sqlserver2008-vm)
- [Task 12: Configure the WideWorldImporters database on the SqlServer2008 VM](#task-12-configure-the-wideworldimporters-database-on-the-sqlserver2008-vm)
> **Important**: Many Azure resources require globally unique names. Throughout these steps, you will see the word "SUFFIX" as part of resource names. You should replace this with your Microsoft alias, initials, or another value to ensure resources are uniquely named.
## Task 1: Create a virtual network
In this task, you create and configure a virtual network (VNet), which will contain your SQL managed instance, JumpBox VM, and a few other resources use throughout this hands-on lab. Once provisioned, you will associate the route table with the ManagedInstance subnet, and add a Management subnet to the VNet.
1. In the [Azure portal](https://portal.azure.com/), select the **Show portal menu** icon and then select **+Create a resource** from the menu.
![The Show portal menu icon is highlighted, and the portal menu is displayed. Create a resource is highlighted in the portal menu.](media/create-a-resource.png "Create a resource")
2. Enter "virtual network" into the Search the Marketplace box, and then select **Virtual Network** from the results.
!["Virtual Network" is entered into the Search the Marketplace box. Virtual Network is selected in the results.](media/create-resource-vnet.png "Create virtual Network")
3. Select **Create** on the Virtual Network blade.
![The Create button is highlighted on the Virtual Network blade.](media/vnet-create.png "Create Virtual Network")
4. On the Create virtual network **Basics** tab, enter the following:
Project details:
- **Subscription**: Select the subscription you are using for this hands-on lab.
- **Resource group**: Select the **hands-on-lab-SUFFIX** resource group from the list.
Instance details:
- **Name**: Enter `hands-on-lab-SUFFIX-vnet`
- **Region**: Select the region you are using for resources in this hands-on lab.
![The values specified above are entered into the appropriate fields on the Create Virtual Network Basics tab.](media/create-virtual-network-basics-tab.png "Create virtual network Basics tab")
5. Select **Next: IP Addresses**.
6. On the **IP Addresses** tab, select **default** under subnets and edit the subnet's properties as follows:
- **Subnet Name**: Enter `ManagedInstance`
- **Address space**: Accept the default value. This should have a subnet mask of /24, and be within the address space indicated in the VNet's IPv4 address space, in the format **10.X.0.0/24**.
- Select **Save**.
![On the Create virtual IP Addresses tab, the values specified above are entered into the appropriate fields.](media/create-virtual-network-ip-addresses-tab.png "Create virtual network IP addresses tab")
7. Select **Review + create**. The default values will be used for the remaining tabs, so they can be skipped.
8. On the **Review + create** tab, ensure the **Validation passed** message is displayed and select **Create**. It will take a few seconds for the virtual network to provision.
9. When it completes, you will get a notification in the Azure portal that the deployment succeeded. Select **Go to resource** within the notification.
![The Go to resource button is highlighted in the deployment succeeded notification in the Azure portal.](media/vnet-go-to-resource.png "Deployment succeeded notification")
10. On the Virtual network blade, select **Subnets** under Settings in the left-hand menu, and then select **+ Subnet** from the top menu.
![The Subnets item is highlighted and selected in the left-hand menu of the Virtual network blade, and + Subnet is highlighted in the top menu.](media/vnet-subnets-add.png "Add subnet")
11. On the Add subnet blade, enter the following:
- **Name**: Enter `Management`
- **Address range**: Accept the default value, which should be a subnet mask of /24, within the address range of your VNet.
- **NAT gateway**: Leave set to **None**.
- **Network security group**: Leave set to **None**.
- **Route table**: Leave set to **None**.
- **Service endpoints**: Leave set to **0 selected**.
- **Subnet delegation**: Leave set to **None**.
![On the Add subnet blade, Management is entered into the name field, and the default values are specified for the remaining settings.](media/add-subnet-management.png "Add subnet")
12. Select **OK**.
13. Back on the **Subnets** blade, select **+ Gateway Subnet**.
![Subnets is selected and highlighted in the left-hand menu. On the Subnets blade, +Gateway subnet is highlighted.](media/vnet-add-gateway-subnet.png "Subnets")
14. The **Name** for gateway subnet is automatically filled in with the value `GatewaySubnet`. This value is required in order for Azure to recognize the subnet as the gateway subnet. Accept the auto-filled Address range value, and leave Route table, Service endpoints, and Subnet delegation set to their default values.
![The Add subnet form is displayed, with the default values.](media/vnet-add-gateway-subnet-form.png "Add subnet")
> **Note**: The default address range creates a gateway subnet with a CIDR block of /24. This provides enough IP addresses to accommodate additional future configuration requirements.
15. Select **OK**.
## Task 2: Create a VPN gateway
In this task, you set up a Virtual Network Gateway.
1. In the [Azure portal](https://portal.azure.com/), select the **Show portal menu** icon and then select **+Create a resource** from the menu.
![The Show portal menu icon is highlighted, and the portal menu is displayed. Create a resource is highlighted in the portal menu.](media/create-a-resource.png "Create a resource")
2. Enter "virtual network gateway" into the Search the Marketplace box, and select **Virtual network gateway** from the results.
!["Virtual network gateway" is entered into the Search the Marketplace box, and Virtual network gateway is highlighted in the results.](media/create-resource-virtual-network-gateway.png "Create a resource")
3. Select **Create** on the Virtual network gateway blade.
![The Create button is highlighted on the Virtual network gateway blade.](media/virtual-network-gateway-create.png "Virtual network gateway")
4. On the Create virtual network gateway **Basics** tab, enter the following:
- Project details:
- **Subscription**: Select the subscription you are using for this hands-on lab.
- **Resource group**: This will be derived from the virtual network's resource group.
- Instance details:
- **Name**: Enter `hands-on-lab-SUFFIX-vnet-gateway`
- **Region**: Select the location you are using for resources in this hands-on lab.
- **Gateway type**: Choose **VPN**.
- **VPN type**: Choose **Route-based**.
- **SKU**: Select **VpnGw1**.
- **Virtual network**: Select the **hands-on-lab-SUFFIX-vnet**.
- Public IP address:
- **Public IP address**: Choose **Create new**.
- **Public IP address name**: Enter **vnet-gateway-ip**.
- **Enable active-active mode**: Choose **Disabled**.
- **Configure BGP ASN**: Choose **Disabled**.
![The values specified above are entered into the appropriate fields in the Create virtual network gateway Basics tab.](media/virtual-network-gateway-create-basics.png "Create virtual network gateway")
5. Select **Review + create**.
6. On the **Review + create** tab, ensure the _Validation passed_ message is displayed and then select **Create**.
![The validation passed message is displayed on the Review + create tab.](media/virtual-network-gateway-create-summary.png "Create virtual network gateway")
7. It can take up to 45 minutes for the Virtual network gateway to provision.
## Task 3: Provision SQL MI
In this task, you create an Azure SQL Managed Instance.
1. In the [Azure portal](https://portal.azure.com/), select the **Show portal menu** icon and then select **+Create a resource** from the menu.
![The Show portal menu icon is highlighted, and the portal menu is displayed. Create a resource is highlighted in the portal menu.](media/create-a-resource.png "Create a resource")
2. Enter "sql managed instance" into the Search the Marketplace box, and then select **Azure SQL Managed Instance** from the results.
!["Sql managed instance" is entered into the Search the Marketplace box. Azure SQL Managed Instance is selected in the results.](media/create-resource-sql-mi.png "Create SQL Managed Instance")
3. Select **Create** on the Azure SQL Managed Instance blade.
![The Create button is highlighted on the Azure SQL Managed Instance blade.](media/sql-mi-create.png "Create Azure SQL Managed Instance")
4. On the Create Azure SQL Database Managed Instance Basics tab, enter the following:
- Project details:
- **Subscription**: Select the subscription you are using for this hands-on lab.
- **Resource group**: Select **hands-on-lab-SUFFIX** from the list.
- Managed Instance details:
- **Managed instance name**: Enter `sqlmi-SUFFIX`
- **Region**: Select the region you are using for resources in this hands-on lab.
- **Compute + storage**: Select **Configure Managed Instance**, and on the Configure performance blade, select **Business Critical**, **Gen5**, and set the vCores to **4** and the Storage to **32**, and then select **Apply**.
![On the Compute + storage blade, Business Critical is selected for the service tier, the vCores are set to 4, and storage size is set to 32 GB.](media/sql-mi-configure-performance.png "Compute + storage blade")
- Administrator account:
- **Managed instance admin login**: Enter `sqlmiuser`
- **Password**: Enter `Password.1234567890`
![On the Create SQL Managed Instance Basics tab, the values specified above are entered into the appropriate fields.](media/sql-managed-instance-basics-tab.png "Create SQL Managed Instance")
> **Note**: If you see a message stating that Managed Instance creation is not available for the chosen subscription type, follow the instructions for [obtaining a larger quota for SQL Managed Instance](https://docs.microsoft.com/azure/sql-database/sql-database-managed-instance-resource-limits#obtaining-a-larger-quota-for-sql-managed-instance).
![A message is displayed stating that SQL MI creation not available in the selected subscription.](media/sql-mi-creation-not-available.png "SQL MI creation not available")
5. Select **Next: Networking**, and on the **Networking** tab set the following configuration:
- **Virtual network**: Select **hands-on-lab-SUFFIX-vnet/ManagedInstance** from the dropdown list.
- **Prepare subnet for Managed Instance**: Select **Automatic**.
- **Connection type**: Leave **Proxy (Default)** selected.
- **Enable public endpoint**: Select **Disable**.
![On the Create SQL Managed Instance Networking tab, the configuration specified above is entered into the form.](media/sql-managed-instance-networking-tab.png "Create SQL Managed Instance")
6. Select **Next: Review + create**, and on the **Review + create** tab, review the configuration and then select **Create**.
> **Note**: Provisioning of SQL Managed Instance can take 4+ hours if this is the first instance being deployed into a subnet. You can move on to the remaining tasks while the provisioning is in process. If the deployment process goes beyond 6 hours, you may need to submit a support ticket to request assistance in completing the setup.
## Task 4: Create the JumpBox VM
In this task, you provision a virtual machine (VM) in Azure. The VM image used has the latest version of Visual Studio Community 2019 installed.
1. In the [Azure portal](https://portal.azure.com/), select the **Show portal menu** icon and then select **+Create a resource** from the menu.
![The Show portal menu icon is highlighted, and the portal menu is displayed. Create a resource is highlighted in the portal menu.](media/create-a-resource.png "Create a resource")
2. Enter "visual studio 2019" into the Search the Marketplace box, and then select **Visual Studio 2019 Latest** from the results.
!["Visual studio 2019" is entered into the Search the Marketplace box. Visual Studio 2019 Latest is selected in the search results.](./media/create-resource-visual-studio-vm.png "Create Visual Studio 2019 virtual machine")
3. On the Visual Studio 2019 blade, select **Visual Studio 2019 Community (latest release) on Windows Server 2019 (x64)** from the Select a software plan drop-down list and then select **Create**.
![Visual Studio 2019 Community (latest release) on Windows Server 2019 (x64) is highlighted in the Select a software plan list on the Visual Studio 2019 blade.](media/visual-studio-create.png "Visual Studio 2019")
4. On the Create a virtual machine **Basics** tab set the following configuration:
- Project details:
- **Subscription**: Select the subscription you are using for this hands-on lab.
- **Resource Group**: Select the **hands-on-lab-SUFFIX** resource group from the list of existing resource groups.
- Instance details:
- **Virtual machine name**: Enter `JumpBox`
- **Region**: Select the region you are using for resources in this hands-on lab.
- **Availability options**: Select **No infrastructure redundancy required**.
- **Image**: Leave **Visual Studio 2019 Community (latest release) on Windows Server 2019 (x64)** selected.
- **Azure Spot instance**: Choose **No**.
- **Size**: Accept the default size of **Standard_D4s_v3**.
- Administrator account:
- **Username**: Enter `sqlmiuser`
- **Password**: Enter `Password.1234567890`
- Inbound port rules:
- **Public inbound ports**: Choose **Allow selected ports**.
- **Select inbound ports**: Select **RDP (3389)** in the list.
![Screenshot of the Basics tab, with fields set to the previously mentioned settings.](media/lab-virtual-machine-basics-tab.png "Create a virtual machine Basics tab")
5. Select **Next: Disks** to move to the next step.
6. On the **Disks** tab, ensure the OS disk type is set to **Premium SSD**, and then select **Next: Networking**.
![On the Create a virtual machine Disks tab, the OS disk type is set to Standard SSD.](media/lab-virtual-machine-disks-tab.png "Create a virtual machine Disks tab")
7. On the **Networking** tab, set the following configuration:
- **Virtual network**: Select the **hands-on-lab-SUFFIX-vnet**.
- **Subnet**: Select the **Management** subnet.
- **Public IP**: Leave **(new) JumpBox-ip** selected.
- **NIC network security group**: Select **Basic**.
- **Public inbound ports**: Leave **Allow selected ports** selected.
- **Select inbound ports**: Leave **RDP** selected.
![On the Create a virtual machine Networking tab, the settings specified above are entered into the appropriate fields.](media/lab-virtual-machine-networking-tab.png "Create a virtual machine Networking tab")
8. Select **Review + create** to validate the configuration. The remaining tabs can be skipped, and default values will be used.
9. On the **Review + create** tab, ensure the Validation passed message is displayed, and then select **Create** to provision the virtual machine.
![The Review + create tab is displayed, with a Validation passed message.](media/lab-virtual-machine-review-create-tab.png "Create a virtual machine Review + create tab")
10. It takes approximately 15 minutes for the VM to finish provisioning. You can move on to the next task while you wait.
## Task 5: Create SQL Server 2008 R2 virtual machine
In this task, you provision another virtual machine (VM) in Azure, which will host your "on-premises" instance of SQL Server 2008 R2. The VM uses the SQL Server 2008 R2 SP3 Standard on Windows Server 2008 R2 image.
> **Note**: An older version of Windows Server is being used because SQL Server 2008 R2 is not supported on Windows Server 2016.
1. In the [Azure portal](https://portal.azure.com/), select the **Show portal menu** icon and then select **+Create a resource** from the menu.
![The Show portal menu icon is highlighted, and the portal menu is displayed. Create a resource is highlighted in the portal menu.](media/create-a-resource.png "Create a resource")
2. Enter "SQL Server 2008 R2 SP3 on Windows Server 2008 R2" into the Search the Marketplace box.
3. On the **SQL Server 2008 R2 SP3 on Windows Server 2008 R2** blade, select **SQL Server R2 SP3 Standard on Windows Server 2008 R2** for the software plan and then select **Create**.
![The SQL Server 2008 R2 SP3 on Windows Server 2008 R2 blade is displayed with the standard edition selected for the software plan. The Create button highlighted.](media/create-resource-sql-server-2008-r2.png "Create SQL Server 2008 R2 Resource")
4. On the Create a virtual machine **Basics** tab set the following configuration:
- Project Details:
- **Subscription**: Select the subscription you are using for this hands-on lab.
- **Resource Group**: Select the **hands-on-lab-SUFFIX** resource group from the list of existing resource groups.
- Instance Details:
- **Virtual machine name**: Enter `SqlServer2008`
- **Region**: Select the region you are using for resources in this hands-on lab.
- **Availability options**: Select **No infrastructure redundancy required**.
- **Image**: Leave **SQL Server 2008 R2 SP3 Standard on Windows Server 2008 R2** selected.
- **Azure Spot instance**: Choose **No**.
- **Size**: Accept the default size of **Standard_D4s_v3**.
- Administrator Account:
- **Username**: Enter `sqlmiuser`
- **Password**: Enter `Password.1234567890`
- Inbound Port Rules:
- **Public inbound ports**: Choose **Allow selected ports**.
- **Select inbound ports**: Select **RDP (3389)** in the list.
![Screenshot of the Basics tab, with fields set to the previously mentioned settings.](media/sql-server-2008-r2-vm-basics-tab.png "Create a virtual machine Basics tab")
5. Select **Next: Disks**, ensure the OS disk type is set to **Premium SSD**, and then select **Next: Networking**.
![On the Create a virtual machine Disks tab, the OS disk type is set to Standard SSD.](media/lab-virtual-machine-disks-tab.png "Create a virtual machine Disks tab")
6. On the **Networking** tab, set the following configuration:
- **Virtual network**: Select the **hands-on-lab-vnet**.
- **Subnet**: Select the **Management** subnet.
- **Public IP**: Leave **(new) SqlServer2008-ip** selected.
- **NIC network security group**: Select **Basic**.
- **Public inbound ports**: Leave **Allow selected ports** selected.
- **Select inbound ports**: Leave **RDP (3389)** selected.
![On the Create a virtual machine Networking tab, the settings specified above are entered into the appropriate fields.](media/sql-virtual-machine-networking-tab.png "Create a virtual machine Networking tab")
7. Select the **SQL Server settings** tab from the top menu.
![The SQL Server settings tab is highlighted in the create a virtual machine tabs list.](media/sql-server-2008-r2-vm-sql-settings-tab.png "Create a virtual machine SQL Server settings tab")
> **Note**: The Management and Advanced tabs can be skipped, and default values will be used.
8. On the **SQL Server settings** tab, set the following:
- Security & Networking:
- **SQL connectivity**: Select **Public (Internet)**
- **Port**: Set to `1433`
- SQL Authentication:
- **SQL Authentication**: Select **Enable**.
- **Login name**: Enter `sqlmiuser`
- **Password**: Enter `Password.1234567890`
![The previously specified values are entered into the SQL Server settings tab.](media/sql-server-2008-r2-vm-sql-settings.png "SQL Server settings")
9. Select **Review + create** to validate the configuration.
10. On the **Review + create** tab, ensure the Validation passed message is displayed, and then select **Create** to provision the virtual machine.
![The Review + create tab is displayed, with a Validation passed message.](media/sql-virtual-machine-review-create-tab.png "Create a virtual machine Review + create tab")
11. It takes approximately 10 minutes for the SQL VM to finish provisioning. You can move on to the next task while you wait.
## Task 6: Create Azure Database Migration Service
In this task, you provision an instance of the Azure Database Migration Service (DMS).
> **Important**: This service requires that you have registered the `Microsoft.DataMigration` resource provider within your subscription in Azure. You can find the steps to complete this in the Before the HOL guide.
1. In the [Azure portal](https://portal.azure.com/), select the **Show portal menu** icon and then select **+Create a resource** from the menu.
![The Show portal menu icon is highlighted, and the portal menu is displayed. Create a resource is highlighted in the portal menu.](media/create-a-resource.png "Create a resource")
2. Enter "database migration" into the Search the Marketplace box, select **Azure Database Migration Service** from the results, and select **Create** on the Azure Database Migration Service blade.
!["Database migration" is entered into the Search the Marketplace box. Azure Database Migration Service is selected in the results.](media/create-resource-azure-database-migration-service.png "Create Azure Database Migration Service")
3. On the Create Migration Service **Basics** tab, enter the following:
- Project details:
- **Subscription**: Select the subscription you are using for this hands-on lab.
- **Resource Group**: Select the **hands-on-lab-SUFFIX** resource group from the list of existing resource groups.
- Instance details:
- **Migration service Name**: Enter `wwi-dms`
- **Location**: Select the location you are using for resources in this hands-on lab.
- **Service mode**: Select **Azure**.
- **Pricing tier**: Select **Configure tier**, choose **Premium**, and select **Apply**.
![The Create Migration Service Basics tab is displayed, with the values specified above entered into the appropriate fields.](media/create-migration-service-basics-tab.png "Create Migration Service")
4. Select **Next: Networking**.
5. On the **Networking** tab, select the **hands-on-lab-SUFFIX-vnet/default** virtual network by checking the box next to it in the list of existing virtual networks. This places the DMS instance into the same VNet as your LabVM and SqlServer2008 virtual machines.
![The hands-on-lab-vnet/default virtual network in checked and selected in the list of existing virtual networks on the Networking tab.](media/create-migration-service-networking-tab.png "Create Migration Service")
6. Select **Review + create**.
7. Select **Create**.
8. It can take 15 minutes to deploy the Azure Data Migration Service. You can move on to the next task while you wait.
## Task 7: Provision a Web App
In this task, you provision an App Service (Web app), which will be used for hosting the Wide World Importers web application.
1. In the [Azure portal](https://portal.azure.com/), select the **Show portal menu** icon and then select **+Create a resource** from the menu.
![The Show portal menu icon is highlighted, and the portal menu is displayed. Create a resource is highlighted in the portal menu.](media/create-a-resource.png "Create a resource")
2. In the [Azure portal](https://portal.azure.com/), select **+Create a resource**, enter "web app" into the Search the Marketplace box, select **Web App** from the results.
![+Create a resource is selected in the Azure navigation pane, and "web app" is entered into the Search the Marketplace box. Web App is selected in the results.](media/create-resource-web-app.png "Create Web App")
3. On the Web App blade, select **Create**.
![On the Web App blade, the Create button is highlighted.](media/create-web-app.png "Create Web App")
4. On the Create Web App **Basics** tab, set the following configuration:
- Project Details:
- **Subscription**: Select the subscription you are using for this hands-on lab.
- **Resource Group**: Select the **hands-on-lab-SUFFIX** resource group from the list of existing resource groups.
- Instance Details:
- **Name**: Enter `wwi-web-SUFFIX`, to create a globally unique name.
- **Publish**: Select **Code**.
- **Runtime stack**: Select **.NET Core 3.1 (LTS)**.
- **Operating System**: Select **Windows**.
- **Region**: Select the region you are using for resources in this hands-on lab.
- App Service Plan:
- **Plan**: Accept the default value for creating a new App Service Plan.
- **Sku and size**: Accept the default value of **Standard S1**.
![The values specified above are entered into the appropriate fields in the Create Web App Basics tab.](media/create-web-app-basics-tab.png "Create Web App Basics tab")
5. Select **Review + create**.
6. On the **Review + create** tab, select **Create**.
7. It takes a few minutes for the Web App creation to complete. You can move on to the next task while you wait.
## Task 8: Create an Azure Blob Storage account
In this task, you create an Azure Storage account.
1. In the [Azure portal](https://portal.azure.com/), select the **Show portal menu** icon and then select **+Create a resource** from the menu.
![The Show portal menu icon is highlighted, and the portal menu is displayed. Create a resource is highlighted in the portal menu.](media/create-a-resource.png "Create a resource")
2. Enter "storage account" into the Search the Marketplace box, select **Storage account - blob, file, table, queue** from the results, and then select **Create** on the Storage account blade.
!["Storage account" is entered into the Search the Marketplace box. Storage account is selected in the results.](media/create-resource-storage-account.png "Create Storage account")
3. On the Create storage account blade, enter the following:
- Project details:
- **Subscription**: Select the subscription you are using for this hands-on lab.
- **Resource Group**: Select the **hands-on-lab-SUFFIX** resource group from the list of existing resource groups.
- Instance details:
- **Storage account name**: Enter `sqlmistoreSUFFIX`
- **Location**: Select the location you are using for resources in this hands-on lab.
- **Performance**: Choose **Standard**.
- **Account kind**: Select **StorageV2 (general purpose v2)**.
- **Replication**: Select **Locally-redundant storage (LRS)**.
- **Access tier**: Choose **Hot**.
![On the Create storage account blade, the values specified above are entered into the appropriate fields.](media/storage-create-account-basics-tab.png "Create storage account")
4. Select **Review + create**.
5. On the **Review + create** blade, ensure the Validate passed message is displayed and then select **Create**.
![On the Review + create blade, the Validation passed message is displayed at the top.](media/storage-create-account-review.png "Create storage account")
## Task 9: Connect to the JumpBox
In this task, you create an RDP connection to your JumpBox virtual machine (VM) and disable Internet Explorer Enhanced Security Configuration.
> **Note**: You do not need to wait for SQL MI to finish provisioning to complete the remaining tasks.
1. When your JumpBox VM provisioning completes, navigate to the [Azure portal](https://portal.azure.com) and select **Resource groups** from the Azure services list.
![Resource groups is highlighted in the Azure services list.](media/azure-services-resource-groups.png "Azure services")
2. Select the hands-on-lab-SUFFIX resource group from the list.
![Resource groups is selected in the Azure navigation pane, and the "hands-on-lab-SUFFIX" resource group is highlighted.](./media/resource-groups.png "Resource groups list")
3. In the list of resources for your resource group, select the JumpBox VM.
![The list of resources in the hands-on-lab-SUFFIX resource group are displayed, and JumpBox is highlighted.](./media/resource-group-resources-jumpbox.png "JumpBox in resource group list")
4. On your JumpBox VM blade, select **Connect** and **RDP** from the top menu.
![The JumpBox VM blade is displayed, with the Connect and RDP button highlighted in the top menu.](./media/connect-vm-rdp.png "Connect to JumpBox VM")
5. On the Connect with RDP blade, select **Download RDP File**, then open the downloaded RDP file.
![The Connect with RDP blade is displayed, and the Download RDP File button is highlighted.](./media/connect-to-virtual-machine-with-rdp.png "Connect with RDP")
6. Select **Connect** on the Remote Desktop Connection dialog.
![In the Remote Desktop Connection Dialog Box, the Connect button is highlighted.](./media/remote-desktop-connection.png "Remote Desktop Connection dialog")
7. Enter the following credentials when prompted, and then select **OK**:
- **Username**: `sqlmiuser`
- **Password**: `Password.1234567890`
![The credentials specified above are entered into the Enter your credentials dialog.](media/rdc-credentials.png "Enter your credentials")
8. Select **Yes** to connect, if prompted that the identity of the remote computer cannot be verified.
![In the Remote Desktop Connection dialog box, a warning states that the identity of the remote computer cannot be verified, and asks if you want to continue anyway. At the bottom, the Yes button is circled.](./media/remote-desktop-connection-identity-verification-jumpbox.png "Remote Desktop Connection dialog")
9. Once logged in, launch the **Server Manager**. This should start automatically, but you can access it via the Start menu if it does not.
10. Select **Local Server**, then select **On** next to **IE Enhanced Security Configuration**.
![Screenshot of the Server Manager. In the left pane, Local Server is selected. In the right, Properties (For LabVM) pane, the IE Enhanced Security Configuration, which is set to On, is highlighted.](./media/windows-server-manager-ie-enhanced-security-configuration.png "Server Manager")
11. In the Internet Explorer Enhanced Security Configuration dialog, select **Off** under both Administrators and Users, and then select **OK**.
![Screenshot of the Internet Explorer Enhanced Security Configuration dialog box, with Administrators set to Off.](./media/internet-explorer-enhanced-security-configuration-dialog.png "Internet Explorer Enhanced Security Configuration dialog box")
12. Close the Server Manager, but leave the connection to the JumpBox open for the next task.
## Task 10: Install required software on the JumpBox
In this task, you download the lab starter solution and install SQL Server Management Studio (SSMS) on the JumpBox.
1. First, download the lab starter solution from the [MCW Migrating SQL databases to Azure GitHub repo](https://github.com/microsoft/MCW-Migrating-SQL-databases-to-Azure/archive/master.zip).
2. If you receive a message that downloads are not allowed, select the Tools icon at the top right of the Internet Explorer browser window, and then select **Internet options** from the context menu.
![The Tools icon is highlighted in the Internet Explorer toolbar, and Internet Options is highlighted in the context menu.](media/ie-tools-context-menu.png "Internet Explorer")
3. In the **Internet Options** dialog, select **Custom level** in the Security level for this zone box.
![The Custom level button is highlighted in the Internet Options dialog.](media/ie-internet-options.png "Internet Options")
4. In the Security Settings - Internet Zone dialog, locate the **Downloads** settings and choose **Enable**, then select **OK**.
![The Downloads property is highlighted in the Security Settings dialog, and Enable is selected.](media/ie-security-settings-internet-zone.png "Security Settings")
5. Select **OK** on the Internet Options dialog, and then attempt the download again.
6. When prompted, choose to save the file and then select Open folder.
![The download bar is displayed in Internet Explorer, and Open folder is highlighted.](media/ie-download-open-folder.png "Internet Explorer")
7. Once it is download, extract the ZIP file to `C:\hands-on-lab`.
![In the Extract Compressed Zip File dialog, C:\hands-on-lab is entered into the destination field.](media/extract-compressed-zip.png "Extract Compressed Zip")
> **Important**: Ensure you use the path above, or something similarly short. Failure to do so could result in errors opening some of the files due to a long file path.
8. Next, install SQL Server Management Studio (SSMS) on the JumpBox. Open a web browser on your JumpBox, navigate to <https://docs.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms> and then select the **Download SQL Server Management Studio (SSMS).x** link to download the latest version of SSMS.
![The Download SQL Server Management Studio (SSMS) link is highlighted on the page specified above.](media/download-ssms.png "Download SSMS")
> **Note**: Versions change frequently, so if the version number you see does not match the screenshot, download and install the most recent version.
9. Run the downloaded installer.
10. On the Welcome screen, select **Install** to begin the installation.
![The Install button is highlighted on the SSMS installation welcome screen.](media/ssms-install.png "Install SSMS")
11. Select **Close** when the installation completes.
![The Close button is highlighted on the SSMS Setup Completed dialog.](media/ssms-install-close.png "Setup completed")
## Task 11: Connect to SqlServer2008 VM
In this task, you open an RDP connection to the SqlServer2008 VM, disable Internet Explorer Enhanced Security Configuration, and add a firewall rule to open port 1433 to inbound TCP traffic. You also install the Microsoft Data Migration Assistant (DMA).
1. As you did for the JumpBox, navigate to the SqlServer2008 VM blade in the Azure portal, select **Overview** from the left-hand menu, and then select **Connect** and **RDP** on the top menu.
![The SqlServer2008 VM blade is displayed, with the Connect button highlighted in the top menu.](./media/connect-vm-rdp.png "Connect to SqlServer2008 VM")
2. On the Connect with RDP blade, select **Download RDP File**, then open the downloaded RDP file.
3. Select **Connect** on the Remote Desktop Connection dialog.
![In the Remote Desktop Connection Dialog Box, the Connect button is highlighted.](./media/remote-desktop-connection-sql-2008.png "Remote Desktop Connection dialog")
4. Enter the following credentials when prompted, and then select **OK**:
- **Username**: `sqlmiuser`
- **Password**: `Password.1234567890`
![The credentials specified above are entered into the Enter your credentials dialog.](media/rdc-credentials-sql-2008.png "Enter your credentials")
5. Select **Yes** to connect, if prompted that the identity of the remote computer cannot be verified.
![In the Remote Desktop Connection dialog box, a warning states that the identity of the remote computer cannot be verified, and asks if you want to continue anyway. At the bottom, the Yes button is circled.](./media/remote-desktop-connection-identity-verification-sqlserver2008.png "Remote Desktop Connection dialog")
6. Once logged in, launch the **Server Manager**. This should start automatically, but you can access it via the Start menu if it does not.
7. On the **Server Manager** view, select **Configure IE ESC** under Security Information.
![Screenshot of the Server Manager. In the left pane, Local Server is selected. In the right, Properties (For LabVM) pane, the IE Enhanced Security Configuration, which is set to On, is highlighted.](./media/windows-server-2008-manager-ie-enhanced-security-configuration.png "Server Manager")
8. In the Internet Explorer Enhanced Security Configuration dialog, select **Off** under both Administrators and Users, and then select **OK**.
![Screenshot of the Internet Explorer Enhanced Security Configuration dialog box, with Administrators set to Off.](./media/2008-internet-explorer-enhanced-security-configuration-dialog.png "Internet Explorer Enhanced Security Configuration dialog box")
9. Close the Server Manager.
10. Next, you will install the Microsoft Data Migration Assistant v5.x by navigating to <https://www.microsoft.com/en-us/download/details.aspx?id=53595> in a web browser on the SqlServer2008 VM and then select the **Download** button.
![The Download button is highlighted on the Data Migration Assistant download page.](media/dma-download.png "Download Data Migration Assistant")
> **Note**: Versions change frequently, so if the version number you see does not match the screenshot, download and install the most recent version.
11. Run the downloaded installer.
12. Select **Next** on each of the screens, accepting the license terms and privacy policy in the process.
13. Select **Install** on the Privacy Policy screen to begin the installation.
14. On the final screen, select **Finish** to close the installer.
![The Finish button is selected on the Microsoft Data Migration Assistant Setup dialog.](./media/data-migration-assistant-setup-finish.png "Run the Microsoft Data Migration Assistant")
## Task 12: Configure the WideWorldImporters database on the SqlServer2008 VM
In this task, you restore and configure the `WideWorldImporters` database on the SQL Server 2008 R2 instance.
1. On the SqlServer2008 VM, download a [backup of the WideWorldImporters database](https://raw.githubusercontent.com/microsoft/Migrating-SQL-databases-to-Azure/master/Hands-on%20lab/lab-files/Database/WideWorldImporters.bak), and save it to the `C:\` of the VM.
2. Next, open **Microsoft SQL Server Management Studio 17** (SSMS) by entering "sql server" into the search bar in the Windows Start menu and selecting **Microsoft SQL Server Management Studio 17** from the search results.
![SQL Server is entered into the Windows Start menu search box, and Microsoft SQL Server Management Studio 17 is highlighted in the search results.](media/start-menu-ssms-17.png "Windows start menu search")
3. In the SSMS **Connect to Server** dialog, enter **SQLSERVER2008** into the Server name box, ensure **Windows Authentication** is selected, and then select **Connect**.
![The SQL Server Connect to Search dialog is displayed, with SQLSERVER2008 entered into the Server name and Windows Authentication selected.](media/sql-server-connect-to-server.png "Connect to Server")
4. Once connected, right-click **Databases** under **SQLSERVER2008** in the Object Explorer, and then select **Restore Database** from the context menu.
![In the SSMS Object Explorer, the context menu for Databases is displayed and Restore Database is highlighted.](media/ssms-databases-restore.png "SSMS Object Explorer")
5. You will now restore the `WideWorldImporters` database using the downloaded `WideWorldImporters.bak` file. On the **General** page of the Restore Database dialog, select **Device** under Source, and then select the Browse (`...`) button to the right of the Device box.
![Under Source in the Restore Database dialog, Device is selected and highlighted, and the Browse button is highlighted.](media/ssms-restore-database-source.png "Restore Database source")
6. In the **Select backup devices** dialog that appears, select **Add**.
![In the Select backup devices dialog, the Add button is highlighted.](media/ssms-restore-database-select-devices.png "Select backup devices")
7. In the **Locate Backup File** dialog, browse to the location you saved the downloaded `WideWorldImporters.bak` file, select that file, and then select **OK**.
![In the Location Backup File dialog, the WideWorldImporters.bak file is selected and highlighted.](media/ssms-restore-database-locate-backup-file.png "Locate Backup File")
8. Select **OK** on the **Select backup devices** dialog. This returns you to the Restore Database dialog. The dialog now contains the information required to restore the `WideWorldImporters` database.
![The completed Restore Database dialog is displayed, with the WideWorldImporters database specified as the target.](media/ssms-restore-database.png "Restore Database")
9. Select **OK** to start the restore.
10. Select **OK** in the dialog when the database restore is complete.
![A dialog is displayed with a message that the database WideWorldImporters was restored successfully.](media/ssms-restore-database-success.png "Restored successfully")
11. Next, you execute a script in SSMS to create the `WorkshopUser` account. To create the script, open a new query window in SSMS by selecting **New Query** in the SSMS toolbar.
![The New Query button is highlighted in the SSMS toolbar.](media/ssms-new-query.png "SSMS Toolbar")
12. Copy and paste the SQL script below into the new query window:
```sql
USE master;
GO
-- Create a login and user named WorkshopUser
CREATE LOGIN WorkshopUser WITH PASSWORD = N'Password.1234567890';
GO
EXEC sp_addsrvrolemember
@loginame = N'WorkshopUser',
@rolename = N'sysadmin';
GO
-- Assign the user to the WideWorldImporters database
USE WideWorldImporters;
GO
IF NOT EXISTS (SELECT * FROM sys.database_principals WHERE name = N'WorkshopUser')
BEGIN
CREATE USER [WorkshopUser] FOR LOGIN [WorkshopUser]
EXEC sp_addrolemember N'db_datareader', N'WorkshopUser'
END;
GO
```
13. To run the script, select **Execute** from the SSMS toolbar.
![The Execute button is highlighted in the SSMS toolbar.](media/ssms-execute.png "SSMS Toolbar")
14. Select **New Query** from the SSMS toolbar again.
![The New Query button is highlighted in the SSMS toolbar.](media/ssms-new-query.png "SSMS Toolbar")
15. Next, copy and paste the SQL script below into the new query window. This script enables Service broker on the `WideWorldImporters` database.
```sql
USE [WideWorldImporters];
GO
-- Grant the sqlmiuser ALTER database permissions
GRANT ALTER ON DATABASE:: WideWorldImporters TO sqlmiuser;
GO
-- Enable Service Broker
ALTER DATABASE WideWorldImporters
SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE;
GO
```
16. To run the script, select **Execute** from the SSMS toolbar.
![The Execute button is highlighted in the SSMS toolbar.](media/ssms-execute.png "SSMS Toolbar")

Двоичные данные
Hands-on lab/images/HeaderPic.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 152 KiB

Двоичные данные
Hands-on lab/images/Setup/image4.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 8.3 KiB

Двоичные данные
Hands-on lab/images/Setup/image5.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 13 KiB

Двоичные данные
Hands-on lab/images/Setup/image6.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.2 KiB

Двоичные данные
Hands-on lab/images/Setup/image7.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 116 KiB

Двоичные данные
Hands-on lab/images/Setup/image8.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 15 KiB

Двоичные данные
Hands-on lab/images/Setup/image9.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 41 KiB

Просмотреть файл

@ -0,0 +1,501 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.3.0.0",
"parameters": {
"resourceSuffix": {
"type": "string",
"minLength": 3,
"maxLength": 5,
"metadata": {
"description": "Enter a three to five character alpha-numeric string, such as your initials, to ensure unique resource names."
}
},
"vmUsername": {
"defaultValue": "demouser",
"type": "string",
"metadata": {
"description": "Administrator user name for logging into the Lab Virtual Machine."
}
},
"vmPassword": {
"defaultValue": "Password.1!!",
"type": "securestring",
"minLength": 8,
"maxLength": 128,
"metadata": {
"description": "The password must be between 8 and 128 characters in length and must contain at least one number, one non-alphanumeric character, and one upper or lower case letter. Default value is Password.1!!"
}
}
},
"variables": {
"location": "[resourceGroup().location]",
"dataLakeAccountName": "[concat('tollboothdl', parameters('resourceSuffix'))]",
"imagesContainerName": "images",
"cosmosDbAccountName": "[concat('tollbooth-db-', parameters('resourceSuffix'))]",
"cosmosDbDatabaseName": "LicensePlates",
"cosmosDbContainerProcessed": "Processed",
"cosmosDbContainerManual": "NeedsManualReview",
"vmSize": "Standard_D4s_v3",
"vmName": "LabVM",
"vmNetworkSecurityGroupName": "[concat(variables('vmName'), '-nsg')]",
"vmNetworkInterfaceName": "[concat(variables('vmName'), '-nic')]",
"vmPublicIpAddressName": "[concat(variables('vmName'), '-ip')]",
"vmCustomScriptFileName": "configure-labvm.ps1",
"vmCustomScriptUri": "[concat('https://raw.githubusercontent.com/kylebunting/MCW-Serverless-architecture/master/Hands-on%20lab/lab-files/arm-template/', variables('vmCustomScriptFileName'))]",
"virtualNetworkName": "[concat(resourceGroup().name, '-vnet')]",
"addressPrefix": "176.16.0.0/16",
"subnetName": "default",
"subnetPrefix": "176.16.0.0/24",
"apiAppName": "[concat('contoso-api-', uniqueString(resourceGroup().id))]",
"webAppName": "[concat('contoso-web-', uniqueString(resourceGroup().id))]",
"functionAppName": "[concat('contoso-func-', uniqueString(resourceGroup().id))]",
"cogServicesName": "[concat('cog-services-', uniqueString(resourceGroup().id))]",
"keyVaultName": "[concat('contoso-kv-', uniqueString(resourceGroup().id))]"
},
"resources": [
{
"name": "[variables('dataLakeAccountName')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2",
"location": "[variables('location')]",
"properties": {
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [],
"ipRules": [],
"defaultAction": "Allow"
},
"accessTier": "Hot",
"allowBlobPublicAccess": true,
"allowSharedKeyAccess": true,
"isHnsEnabled": true,
"minimumTlsVersion": "TLS1_2",
"supportsHttpsTrafficOnly": true
},
"resources": [
{
"type": "blobServices/containers",
"apiVersion": "2019-06-01",
"name": "[concat('default/', variables('imagesContainerName'))]",
"dependsOn": [
"[variables('dataLakeAccountName')]"
],
"properties": {
"publicAccess": "None"
}
}
]
},
{
"type": "Microsoft.DocumentDB/databaseAccounts",
"name": "[variables('cosmosDbAccountName')]",
"apiVersion": "2021-01-15",
"kind": "GlobalDocumentDB",
"location": "[variables('location')]",
"properties": {
"consistencyPolicy": {
"defaultConsistencyLevel": "Session"
},
"locations": [
{
"locationName": "[variables('location')]"
}
],
"databaseAccountOfferType": "Standard",
"enableAutomaticFailover": false,
"enableFreeTier": false,
"enableAnalyticalStorage": false,
"enableMultipleWriteLocations": false,
"networkAclBypass": "AzureServices",
"publicNetworkAccess": "Disabled"
},
"resources": [
{
"name": "[concat(variables('cosmosDbAccountName'), '/', variables('cosmosDbDatabaseName'))]",
"type": "sqlDatabases",
"apiVersion": "2021-01-15",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbAccountName'))]"
],
"properties": {
"resource": {
"id": "[variables('cosmosDbDatabaseName')]"
}
}
}
]
},
{
"name": "[concat(variables('cosmosDbAccountName'), '/', variables('cosmosDbDatabaseName'))]",
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases",
"apiVersion": "2021-01-15",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbAccountName'))]"
],
"properties": {
"resource": {
"id": "[variables('cosmosDbDatabaseName')]"
}
}
},
{
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers",
"name": "[concat(variables('cosmosDbAccountName'), '/', variables('cosmosDbDatabaseName'), '/', variables('cosmosDbContainerProcessed'))]",
"apiVersion": "2021-01-15",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', variables('cosmosDbAccountName'), variables('cosmosDbDatabaseName'))]"
],
"properties":
{
"resource":{
"id": "[variables('cosmosDbContainerProcessed')]",
"partitionKey": {
"paths": [
"/licensePlateText"
]
}
},
"options": {
"autoscaleSettings": {
"maxThroughput": 4000
}
}
}
},
{
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers",
"name": "[concat(variables('cosmosDbAccountName'), '/', variables('cosmosDbDatabaseName'), '/', variables('cosmosDbContainerManual'))]",
"apiVersion": "2021-01-15",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', variables('cosmosDbAccountName'), variables('cosmosDbDatabaseName'))]"
],
"properties":
{
"resource":{
"id": "[variables('cosmosDbContainerManual')]",
"partitionKey": {
"paths": [
"/fileName"
]
}
},
"options": {
"autoscaleSettings": {
"maxThroughput": 4000
}
}
}
},
{
"name": "[variables('vmName')]",
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2020-06-01",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/networkInterfaces/', variables('vmNetworkInterfaceName'))]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[variables('vmSize')]"
},
"storageProfile": {
"osDisk": {
"createOption": "FromImage",
"managedDisk": {
"storageAccountType": "Premium_LRS"
}
},
"imageReference": {
"publisher": "microsoftvisualstudio",
"offer": "visualstudio2019latest",
"sku": "vs-2019-comm-latest-ws2019",
"version": "latest"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', variables('vmNetworkInterfaceName'))]"
}
]
},
"osProfile": {
"computerName": "[variables('vmName')]",
"adminUsername": "[parameters('vmUsername')]",
"adminPassword": "[parameters('vmPassword')]",
"windowsConfiguration": {
"enableAutomaticUpdates": true,
"provisionVmAgent": true
}
}
},
"resources": [
{
"name": "SetupLabVm",
"type": "extensions",
"apiVersion": "2019-03-01",
"location": "[variables('location')]",
"properties": {
"publisher": "Microsoft.Compute",
"type": "CustomScriptExtension",
"typeHandlerVersion": "1.9",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": [
"[variables('vmCustomScriptUri')]"
],
"commandToExecute": "[concat('powershell -ExecutionPolicy Unrestricted -File ', variables('vmCustomScriptFileName'))]"
}
},
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', variables('vmName'))]"
],
"tags": {
"displayName": "SetupLabVm"
}
}
]
},
{
"type": "Microsoft.Web/serverfarms",
"name": "[variables('appServicePlanName')]",
"apiVersion": "2018-02-01",
"location": "[variables('location')]",
"sku": {
"name": "S1",
"tier": "Standard",
"size": "S1",
"family": "S",
"capacity": 1
},
"tags": {
},
"properties": {
"workerSize": 0,
"workerSizeId": 0,
"numberOfWorkers": 1
}
},
{
"type": "Microsoft.Web/sites",
"name": "[variables('webAppName')]",
"apiVersion": "2018-11-01",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Web/serverfarms/', variables('appServicePlanName'))]"
],
"properties": {
"enabled": true,
"siteConfig": {
"connectionStrings": [
],
"metadata": [
{
"name": "CURRENT_STACK",
"value": "dotnetcore"
}
],
"alwaysOn": true
},
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms/', variables('appServicePlanName'))]"
}
},
{
"type": "Microsoft.Web/sites",
"name": "[variables('apiAppName')]",
"apiVersion": "2018-11-01",
"location": "[variables('location')]",
"kind": "api",
"dependsOn": [
"[concat('Microsoft.Web/serverfarms/', variables('appServicePlanName'))]"
],
"properties": {
"enabled": true,
"siteConfig": {
"appSettings": []
},
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms/', variables('appServicePlanName'))]"
}
},
{
"type": "Microsoft.Web/sites",
"name": "[variables('functionAppName')]",
"apiVersion": "2018-11-01",
"location": "[variables('location')]",
"kind": "functionapp",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('dataLakeAccountName'))]"
],
"properties": {
"name": "[variables('functionAppName')]",
"siteConfig": {
"appSettings": [
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "dotnet"
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('dataLakeAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('dataLakeAccountName')), '2015-05-01-preview').key1)]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('dataLakeAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('dataLakeAccountName')), '2015-05-01-preview').key1)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[variables('dataLakeAccountName')]"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "10.14.1"
}
]
},
"clientAffinityEnabled": false,
"reserved": false
}
},
{
"name": "[variables('keyVaultName')]",
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2018-02-14",
"location": "[variables('location')]",
"properties": {
"sku": {
"name": "Standard",
"family": "A"
},
"tenantId": "[subscription().tenantId]",
"accessPolicies": []
}
},
{
"name": "[variables('cogServicesName')]",
"type": "Microsoft.CognitiveServices/accounts",
"apiVersion": "2017-04-18",
"sku": {
"name": "S0"
},
"location": "[variables('location')]",
"kind": "CognitiveServices",
"properties": {
"apiProperties": {
"statisticsEnabled": false
}
}
},
{
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('virtualNetworkName')]",
"apiVersion": "2020-06-01",
"location": "[variables('location')]",
"dependsOn": [],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[variables('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetPrefix')]"
}
}
]
}
},
{
"name": "[variables('vmNetworkInterfaceName')]",
"type": "Microsoft.Network/networkInterfaces",
"apiVersion": "2020-06-01",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]",
"[concat('Microsoft.Network/publicIpAddresses/', variables('vmPublicIpAddressName'))]",
"[concat('Microsoft.Network/networkSecurityGroups/', variables('vmNetworkSecurityGroupName'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('virtualNetworkName'), variables('subnetName'))]"
},
"privateIPAllocationMethod": "Dynamic",
"publicIpAddress": {
"id": "[resourceId('Microsoft.Network/publicIpAddresses', variables('vmPublicIpAddressName'))]"
}
}
}
],
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('vmNetworkSecurityGroupName'))]"
}
}
},
{
"name": "[variables('vmPublicIpAddressName')]",
"type": "Microsoft.Network/publicIPAddresses",
"apiVersion": "2020-06-01",
"location": "[variables('location')]",
"properties": {
"publicIPAllocationMethod": "Dynamic"
},
"sku": {
"name": "Basic"
}
},
{
"name": "[variables('vmNetworkSecurityGroupName')]",
"type": "Microsoft.Network/networkSecurityGroups",
"apiVersion": "2020-06-01",
"location": "[variables('location')]",
"properties": {
"securityRules": [
{
"name": "RDP",
"properties": {
"priority": 300,
"protocol": "Tcp",
"access": "Allow",
"direction": "Inbound",
"sourceApplicationSecurityGroups": [],
"destinationApplicationSecurityGroups": [],
"sourceAddressPrefix": "*",
"sourcePortRange": "*",
"destinationAddressPrefix": "*",
"destinationPortRange": "3389"
}
}
]
}
}
],
"outputs": {
"vmUsername": {
"type": "string",
"value": "[parameters('vmUsername')]"
}
}
}

Просмотреть файл

@ -0,0 +1,622 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.3.0.0",
"parameters": {
"resourceSuffix": {
"type": "string",
"minLength": 3,
"maxLength": 5,
"metadata": {
"description": "Enter a three to five character alpha-numeric string, such as your initials, to ensure unique resource names."
}
},
"vmUsername": {
"defaultValue": "demouser",
"type": "string",
"metadata": {
"description": "Administrator user name for logging into the Lab Virtual Machine."
}
},
"vmPassword": {
"defaultValue": "Password.1!!",
"type": "securestring",
"minLength": 8,
"maxLength": 128,
"metadata": {
"description": "The password must be between 8 and 128 characters in length and must contain at least one number, one non-alphanumeric character, and one upper or lower case letter. Default value is Password.1!!"
}
}
},
"variables": {
"location": "[resourceGroup().location]",
"dataLakeAccountName": "[concat('tollboothdl', parameters('resourceSuffix'))]",
"dataLakeConnectionSecretName": "dataLakeConnectionString",
"imagesContainerName": "images",
"exportContainerName": "export",
"cosmosDbAccountName": "[concat('tollbooth-db-', parameters('resourceSuffix'))]",
"cosmosDbDatabaseName": "LicensePlates",
"cosmosDbContainerProcessed": "Processed",
"cosmosDbContainerManual": "NeedsManualReview",
"cosmosDbAuthKeySecretName": "cosmosDBAuthorizationKey",
"virtualNetworkName": "[concat(resourceGroup().name, '-vnet')]",
"addressPrefix": "176.16.0.0/16",
"subnetName": "default",
"subnetPrefix": "176.16.0.0/24",
"vmName": "LabVM",
"vmSize": "Standard_D4s_v3",
"vmNetworkSecurityGroupName": "[concat(variables('vmName'), '-nsg')]",
"vmNetworkInterfaceName": "[concat(variables('vmName'), '-nic')]",
"vmPublicIpAddressName": "[concat(variables('vmName'), '-ip')]",
"vmCustomScriptFileName": "configure-labvm.ps1",
"vmCustomScriptUri": "[concat('https://raw.githubusercontent.com/kylebunting/MCW-Serverless-architecture/master/Hands-on%20lab/lab-files/arm-template/', variables('vmCustomScriptFileName'))]",
"tollBoothHostingPlanName": "tollbooth-asp",
"tollBoothFunctionAppName": "[concat('TollBoothFunctionApp-', parameters('resourceSuffix'))]",
"tollBoothEventsHostingPlanName": "tollboothevents-asp",
"tollBoothEventsFunctionAppName": "[concat('TollBoothEvents-', parameters('resourceSuffix'))]",
"tollBoothAppInsightsName": "[concat('tollbooth-monitor-', parameters('resourceSuffix'))]",
"eventGridTopicName": "[concat('tollbooth-event-grid-', parameters('resourceSuffix'))]",
"eventGridTopicKeySecretName": "eventGridTopicKey",
"computerVisionName": "[concat('tollbooth-vision-', parameters('resourceSuffix'))]",
"computerVisionSecretName": "computerVisionApiKey",
"keyVaultName": "[concat('tollbooth-kv-', parameters('resourceSuffix'))]"
},
"resources": [
{
"name": "[variables('dataLakeAccountName')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2",
"location": "[variables('location')]",
"properties": {
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [
],
"ipRules": [
],
"defaultAction": "Allow"
},
"accessTier": "Hot",
"allowBlobPublicAccess": true,
"allowSharedKeyAccess": true,
"isHnsEnabled": true,
"minimumTlsVersion": "TLS1_2",
"supportsHttpsTrafficOnly": true
},
"resources": [
{
"type": "containers",
"apiVersion": "2019-06-01",
"name": "[variables('imagesContainerName')]",
"dependsOn": ["[variables('dataLakeAccountName')]"],
"properties": {
"publicAccess": "None"
}
},
{
"type": "containers",
"apiVersion": "2019-06-01",
"name": "[variables('exportContainerName')]",
"dependsOn": ["[variables('dataLakeAccountName')]"],
"properties": {
"publicAccess": "None"
}
}
]
},
{
"type": "Microsoft.DocumentDB/databaseAccounts",
"name": "[variables('cosmosDbAccountName')]",
"apiVersion": "2021-01-15",
"kind": "GlobalDocumentDB",
"location": "[variables('location')]",
"properties": {
"consistencyPolicy": {
"defaultConsistencyLevel": "Session"
},
"locations": [
{
"locationName": "[variables('location')]"
}
],
"databaseAccountOfferType": "Standard",
"enableAutomaticFailover": false,
"enableFreeTier": false,
"enableAnalyticalStorage": false,
"enableMultipleWriteLocations": false,
"networkAclBypass": "AzureServices",
"publicNetworkAccess": "Disabled"
},
"resources": [
{
"name": "[variables('cosmosDbDatabaseName')]",
"type": "sqlDatabases",
"apiVersion": "2021-01-15",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbAccountName'))]"
],
"properties": {
"resource": {
"id": "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbAccountName'), variables('cosmosDbDatabaseName'))]"
}
},
"resources": [
{
"type": "containers",
"name": "[variables('cosmosDbContainerProcessed')]",
"apiVersion": "2021-01-15",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', variables('cosmosDbAccountName'), variables('cosmosDbDatabaseName'))]"
],
"properties": {
"resource": {
"id": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', variables('cosmosDbContainerProcessed'))]",
"partitionKey": {
"paths": ["/licensePlateText"]
}
},
"options": {
"autoscaleSettings": {
"maxThroughput": 4000
}
}
}
},
{
"type": "containers",
"name": "[variables('cosmosDbContainerManual')]",
"apiVersion": "2021-01-15",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', variables('cosmosDbAccountName'), variables('cosmosDbDatabaseName'))]"
],
"properties": {
"resource": {
"id": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', variables('cosmosDbContainerManual'))]",
"partitionKey": {
"paths": ["/fileName"]
}
},
"options": {
"autoscaleSettings": {
"maxThroughput": 4000
}
}
}
}
]
}
]
},
{
"name": "[variables('eventGridTopicName')]",
"type": "Microsoft.EventGrid/topics",
"apiVersion": "2020-06-01",
"location": "[variables('location')]",
"properties": {
"inputSchema": "EventGridSchema"
}
},
{
"name": "[variables('vmName')]",
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2020-06-01",
"location": "[variables('location')]",
"dependsOn": [
"[resourceId('Microsoft.Network/networkInterfaces/', variables('vmNetworkInterfaceName'))]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[variables('vmSize')]"
},
"storageProfile": {
"osDisk": {
"createOption": "FromImage",
"managedDisk": {
"storageAccountType": "Premium_LRS"
}
},
"imageReference": {
"publisher": "microsoftvisualstudio",
"offer": "visualstudio2019latest",
"sku": "vs-2019-comm-latest-ws2019",
"version": "latest"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', variables('vmNetworkInterfaceName'))]"
}
]
},
"osProfile": {
"computerName": "[variables('vmName')]",
"adminUsername": "[parameters('vmUsername')]",
"adminPassword": "[parameters('vmPassword')]",
"windowsConfiguration": {
"enableAutomaticUpdates": true,
"provisionVmAgent": true
}
}
},
"resources": [
{
"name": "SetupLabVm",
"type": "extensions",
"apiVersion": "2020-06-01",
"location": "[variables('location')]",
"properties": {
"publisher": "Microsoft.Compute",
"type": "CustomScriptExtension",
"protectedSettings": {},
"typeHandlerVersion": "1.9",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": ["[variables('vmCustomScriptUri')]"],
"commandToExecute": "[concat('powershell -ExecutionPolicy Unrestricted -File ', variables('vmCustomScriptFileName'))]"
}
},
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines/', variables('vmName'))]"
],
"tags": {
"displayName": "SetupLabVm"
}
}
]
},
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2020-06-01",
"name": "[variables('tollBoothHostingPlanName')]",
"location": "[variables('location')]",
"sku": {
"name": "Y1",
"tier": "Dynamic"
},
"properties": {
"name": "[variables('tollBoothHostingPlanName')]",
"computeMode": "Dynamic"
}
},
{
"type": "Microsoft.Web/sites",
"name": "[variables('tollBoothFunctionAppName')]",
"apiVersion": "2020-09-01",
"location": "[variables('location')]",
"kind": "functionapp",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('tollBoothHostingPlanName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('dataLakeAccountName'))]",
"[resourceId('Microsoft.Insights/components', variables('tollBoothAppInsightsName'))]"
],
"properties": {
"name": "[variables('tollBoothFunctionAppName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('tollBoothHostingPlanName'))]",
"siteConfig": {
"appSettings": [
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(resourceId('Microsoft.Insights/components', variables('tollBoothAppInsightsName')), '2020-02-02-Preview').InstrumentationKey]"
},
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "node"
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('dataLakeAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('dataLakeAccountName')), '2019-06-01').key1)]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('dataLakeAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('dataLakeAccountName')), '2019-06-01').key1)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[variables('dataLakeAccountName')]"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "10.14.1"
}
]
},
"clientAffinityEnabled": false,
"reserved": false
},
"identity": {
"type": "SystemAssigned"
}
},
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2020-06-01",
"name": "[variables('tollBoothEventsHostingPlanName')]",
"location": "[variables('location')]",
"sku": {
"name": "Y1",
"tier": "Dynamic"
},
"properties": {
"name": "[variables('tollBoothEventsHostingPlanName')]",
"computeMode": "Dynamic"
}
},
{
"type": "Microsoft.Web/sites",
"name": "[variables('tollBoothEventsFunctionAppName')]",
"apiVersion": "2020-09-01",
"location": "[variables('location')]",
"kind": "functionapp",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('tollBoothEventsHostingPlanName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('dataLakeAccountName'))]",
"[resourceId('Microsoft.Insights/components', variables('tollBoothAppInsightsName'))]"
],
"properties": {
"name": "[variables('tollBoothEventsFunctionAppName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('tollBoothEventsHostingPlanName'))]",
"siteConfig": {
"appSettings": [
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(resourceId('Microsoft.Insights/components', variables('tollBoothAppInsightsName')), '2020-02-02-Preview').InstrumentationKey]"
},
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "dotnet"
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('dataLakeAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('dataLakeAccountName')), '2019-06-01').key1)]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('dataLakeAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('dataLakeAccountName')), '2019-06-01').key1)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[variables('dataLakeAccountName')]"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "10.14.1"
}
]
},
"clientAffinityEnabled": false,
"reserved": false
},
"identity": {
"type": "SystemAssigned"
}
},
{
"name": "[variables('tollBoothAppInsightsName')]",
"type": "Microsoft.Insights/components",
"apiVersion": "2020-02-02-Preview",
"location": "[variables('location')]",
"kind": "web",
"properties": {
"Application_Type": "web"
}
},
{
"name": "[variables('computerVisionName')]",
"type": "Microsoft.CognitiveServices/accounts",
"apiVersion": "2017-04-18",
"sku": {
"name": "S1"
},
"location": "[variables('location')]",
"kind": "ComputerVision",
"properties": {
"apiProperties": {
"statisticsEnabled": false
}
}
},
{
"name": "[variables('keyVaultName')]",
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2019-09-01",
"location": "[variables('location')]",
"properties": {
"sku": {
"name": "Standard",
"family": "A"
},
"enableSoftDelete": true,
"softDeleteRetentionInDays": 90,
"enablePurgeProtection": false,
"tenantId": "[subscription().tenantId]",
"accessPolicies": [
{
"objectId": "[reference(resourceId('Microsoft.Web/sites', variables('tollBoothFunctionAppName')), '2019-08-01', 'Full').identity.principalId]",
"permissions": {
"secrets": [
"get"
]
},
"tenantId": "[subscription().tenantId]"
}
]
},
"resources": [
{
"type": "secrets",
"apiVersion": "2019-09-01",
"name": "[variables('cosmosDbAuthKeySecretName')]",
"location": "[variables('location')]",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]",
"[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbAccountName'))]"
],
"properties": {
"value": "[listKeys(resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDbAccountName')), '2021-01-15').primaryMasterKey]"
}
},
{
"type": "secrets",
"apiVersion": "2019-09-01",
"name": "[variables('dataLakeConnectionSecretName')]",
"location": "[variables('location')]",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('dataLakeAccountName'))]"
],
"properties": {
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('dataLakeAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('dataLakeAccountName')), '2019-06-01').key1)]"
}
},
{
"type": "secrets",
"apiVersion": "2019-09-01",
"name": "[variables('computerVisionSecretName')]",
"location": "[variables('location')]",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]",
"[resourceId('Microsoft.CognitiveServices/accounts', variables('computerVisionName'))]"
],
"properties": {
"value": "[listKeys(resourceId('Microsoft.CognitiveServices/accounts', variables('computerVisionName')), '2017-04-18').key1]"
}
},
{
"type": "secrets",
"apiVersion": "2019-09-01",
"name": "[variables('eventGridTopicKeySecretName')]",
"location": "[variables('location')]",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]",
"[resourceId('Microsoft.EventGrid/topics', variables('eventGridTopicName'))]"
],
"properties": {
"value": "[listKeys(resourceId('Microsoft.EventGrid/topics', variables('eventGridTopicName')), '2020-06-01').key1]"
}
}
]
},
{
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('virtualNetworkName')]",
"apiVersion": "2020-06-01",
"location": "[variables('location')]",
"properties": {
"addressSpace": {
"addressPrefixes": ["[variables('addressPrefix')]"]
},
"subnets": [
{
"name": "[variables('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetPrefix')]"
}
}
]
}
},
{
"name": "[variables('vmNetworkInterfaceName')]",
"type": "Microsoft.Network/networkInterfaces",
"apiVersion": "2020-06-01",
"location": "[variables('location')]",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]",
"[resourceId('Microsoft.Network/publicIpAddresses/', variables('vmPublicIpAddressName'))]",
"[resourceId('Microsoft.Network/networkSecurityGroups/', variables('vmNetworkSecurityGroupName'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('virtualNetworkName'), variables('subnetName'))]"
},
"privateIPAllocationMethod": "Dynamic",
"publicIpAddress": {
"id": "[resourceId('Microsoft.Network/publicIpAddresses', variables('vmPublicIpAddressName'))]"
}
}
}
],
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('vmNetworkSecurityGroupName'))]"
}
}
},
{
"name": "[variables('vmPublicIpAddressName')]",
"type": "Microsoft.Network/publicIPAddresses",
"apiVersion": "2020-06-01",
"location": "[variables('location')]",
"properties": {
"publicIPAllocationMethod": "Dynamic"
},
"sku": {
"name": "Basic"
}
},
{
"name": "[variables('vmNetworkSecurityGroupName')]",
"type": "Microsoft.Network/networkSecurityGroups",
"apiVersion": "2020-06-01",
"location": "[variables('location')]",
"properties": {
"securityRules": [
{
"name": "RDP",
"properties": {
"priority": 300,
"protocol": "Tcp",
"access": "Allow",
"direction": "Inbound",
"sourceAddressPrefix": "*",
"sourcePortRange": "*",
"destinationAddressPrefix": "*",
"destinationPortRange": "3389"
}
}
]
}
}
],
"outputs": {
"vmUsername": {
"type": "string",
"value": "[parameters('vmUsername')]"
},
"CosmosDbEndpoint": {
"type": "string",
"value": "[reference(concat('Microsoft.DocumentDb/databaseAccounts/', variables('cosmosDbAccountName'))).documentEndpoint]"
},
"EventGridTopicEndpoint" : {
"type": "string",
"value": "[reference(concat('Microsoft.EventGrid/topics/', variables('eventGridTopicName'))).endpoint]"
},
"ComputerVisionEndpoint" : {
"type": "string",
"value": "[reference(concat('Microsoft.CognitiveServices/accounts/', variables('computerVisionName'))).endpoint]"
}
}
}

Просмотреть файл

@ -0,0 +1,35 @@
function Disable-InternetExplorerESC {
$AdminKey = "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}"
$UserKey = "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A8-37EF-4b3f-8CFC-4F3A74704073}"
Set-ItemProperty -Path $AdminKey -Name "IsInstalled" -Value 0 -Force
Set-ItemProperty -Path $UserKey -Name "IsInstalled" -Value 0 -Force
Stop-Process -Name Explorer -Force
Write-Host "IE Enhanced Security Configuration (ESC) has been disabled." -ForegroundColor Green
}
# To resolve the error of https://github.com/microsoft/MCW-App-modernization/issues/68. The cause of the error is Powershell by default uses TLS 1.0 to connect to website, but website security requires TLS 1.2. You can change this behavior with running any of the below command to use all protocols. You can also specify single protocol.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls, [Net.SecurityProtocolType]::Tls11, [Net.SecurityProtocolType]::Tls12, [Net.SecurityProtocolType]::Ssl3
[Net.ServicePointManager]::SecurityProtocol = "Tls, Tls11, Tls12, Ssl3"
# Disable IE ESC
Disable-InternetExplorerESC
# Download and extract the starter solution files
Invoke-WebRequest 'https://github.com/kylebunting/MCW-Serverless-architecture/archive/master.zip' -OutFile 'C:\MCW.zip'
Expand-Archive -LiteralPath 'C:\MCW.zip' -DestinationPath 'C:\ServerlessMCW' -Force
# Download and istall Microsoft Edge
Invoke-WebRequest 'https://msedge.sf.dl.delivery.mp.microsoft.com/filestreamingservice/files/0a4291f0-226e-4d0a-a702-7aa901f20ff4/MicrosoftEdgeEnterpriseX64.msi' -OutFile 'C:\MicrosoftEdgeEnterpriseX64.msi'
$msiArgs = @(
"/i"
"C:\MicrosoftEdgeEnterpriseX64.msi"
"/qn"
"/norestart"
"/L*v C:\edge-install-log.txt"
)
Start-Process msiexec.exe -ArgumentList $msiArgs -Wait -NoNewWindow
# Download and install .NET Core 3.1
#Invoke-WebRequest 'https://download.visualstudio.microsoft.com/download/pr/279de74e-f7e3-426b-94d8-7f31d32a129c/e83e8c4c49bcb720def67a5c8fe0d8df/dotnet-sdk-2.2.207-win-x64.exe' -OutFile 'C:\dotnet-sdk-2.2.207-win-x64.exe'
#$pathArgs = {C:\dotnet-sdk-2.2.207-win-x64.exe /Install /Quiet /Norestart /Logs log.txt}
#Invoke-Command -ScriptBlock $pathArgs

Просмотреть файл

Просмотреть файл

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 140 KiB

После

Ширина:  |  Высота:  |  Размер: 140 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 1004 KiB

После

Ширина:  |  Высота:  |  Размер: 1004 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 111 KiB

После

Ширина:  |  Высота:  |  Размер: 111 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 111 KiB

После

Ширина:  |  Высота:  |  Размер: 111 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 46 KiB

После

Ширина:  |  Высота:  |  Размер: 46 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 523 KiB

После

Ширина:  |  Высота:  |  Размер: 523 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 150 KiB

После

Ширина:  |  Высота:  |  Размер: 150 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 30 KiB

После

Ширина:  |  Высота:  |  Размер: 30 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 51 KiB

После

Ширина:  |  Высота:  |  Размер: 51 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 46 KiB

После

Ширина:  |  Высота:  |  Размер: 46 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 523 KiB

После

Ширина:  |  Высота:  |  Размер: 523 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 150 KiB

После

Ширина:  |  Высота:  |  Размер: 150 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 182 KiB

После

Ширина:  |  Высота:  |  Размер: 182 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 30 KiB

После

Ширина:  |  Высота:  |  Размер: 30 KiB

Двоичные данные
Hands-on lab/media/azure-services-resource-groups.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 31 KiB

Двоичные данные
Hands-on lab/media/create-resource-group.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 51 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 84 KiB

После

Ширина:  |  Высота:  |  Размер: 84 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 125 KiB

После

Ширина:  |  Высота:  |  Размер: 125 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 153 KiB

После

Ширина:  |  Высота:  |  Размер: 153 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 8.3 KiB

После

Ширина:  |  Высота:  |  Размер: 8.3 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 13 KiB

После

Ширина:  |  Высота:  |  Размер: 13 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 3.2 KiB

После

Ширина:  |  Высота:  |  Размер: 3.2 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 116 KiB

После

Ширина:  |  Высота:  |  Размер: 116 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 15 KiB

После

Ширина:  |  Высота:  |  Размер: 15 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 41 KiB

После

Ширина:  |  Высота:  |  Размер: 41 KiB

Двоичные данные
Hands-on lab/media/resource-groups-add.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 14 KiB

Просмотреть файл

@ -1,17 +0,0 @@
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"computerVisionApiUrl": "",
"computerVisionApiKey": "",
"eventGridTopicEndpoint": "",
"eventGridTopicKey": "",
"cosmosDBEndPointUrl": "",
"cosmosDBAuthorizationKey": "",
"cosmosDBDatabaseId": "LicensePlates",
"cosmosDBCollectionId": "Processed",
"exportCsvContainerName": "export",
"blobStorageConnection": ""
}
}

Просмотреть файл

@ -45,6 +45,7 @@ At the end of the hands-on-lab, you will have confidence in designing, developin
- [Azure Functions](https://docs.microsoft.com/azure/azure-functions/functions-overview)
- [Azure Cognitive Services](https://docs.microsoft.com/azure/cognitive-services/what-are-cognitive-services)
- [Azure Computer Vision](https://docs.microsoft.com/azure/cognitive-services/custom-vision-service/overview)
- [Azure Event Grid](https://docs.microsoft.com/azure/event-grid/overview)
- [Azure Data Lake Storage Gen2](https://docs.microsoft.com/azure/storage/blobs/data-lake-storage-introduction)
- [Application Insights](https://docs.microsoft.com/azure/azure-monitor/app/app-insights-overview)