Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Infrastructure as code with updated documentatiom #75

Open
wants to merge 18 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/python
{
"name": "Python 3",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/python:0-3.9",

// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
"ghcr.io/devcontainers/features/azure-cli:1": {
"version": "latest"
},
"ghcr.io/rchaganti/vsc-devcontainer-features/azurebicep:1": {
"version": "latest"
}
},

// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
"settings": {},
"extensions": [
"ms-python.python",
"ms-vscode.azure-account",
"prompt-flow.prompt-flow"
]
}
},



// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [9000],

// Use 'portsAttributes' to set default properties for specific forwarded ports.
// More info: https://containers.dev/implementors/json_reference/#port-attributes
"portsAttributes": {
"9000": {
"label": "Hello World",
"onAutoForward": "notify"
}
},

// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "pip3 install -r \"./.devcontainer/requirements.txt\" && az extension add --name \"ml\""

// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
3 changes: 3 additions & 0 deletions .devcontainer/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
promptflow
promptflow-tools
promptflow-sdk[builtins]
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
llmops_config.json
ssh/

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
43 changes: 43 additions & 0 deletions deployment_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"azure_managed_endpoint": {
"ENV_NAME": "dev",
"TEST_FILE_PATH": "sample-request.json",
"PUBLIC_ACCESS": "true",
"ENDPOINT_NAME": "",
"ENDPOINT_DESC": "An online endpoint serving a flow for [task]",
"DEPLOYMENT_DESC": "prompt flow deployment",
"PRIOR_DEPLOYMENT_NAME": "",
"PRIOR_DEPLOYMENT_TRAFFIC_ALLOCATION": "",
"CURRENT_DEPLOYMENT_NAME": "",
"CURRENT_DEPLOYMENT_TRAFFIC_ALLOCATION": "100",
"DEPLOYMENT_VM_SIZE": "Standard_F4s_v2",
"DEPLOYMENT_BASE_IMAGE_NAME": "mcr.microsoft.com/azureml/promptflow/promptflow-runtime:latest",
"DEPLOYMENT_CONDA_PATH": "environment/conda.yml",
"DEPLOYMENT_INSTANCE_COUNT": 1,
"ENVIRONMENT_VARIABLES": {
"example-name": "example-value"
}
},
"kubernetes_endpoint": {
"ENV_NAME": "dev",
"TEST_FILE_PATH": "sample-request.json",
"PUBLIC_ACCESS": "true",
"ENDPOINT_NAME": "",
"ENDPOINT_DESC": "An kubernetes endpoint serving a flow for [task]",
"DEPLOYMENT_DESC": "prompt flow deployment",
"PRIOR_DEPLOYMENT_NAME": "",
"PRIOR_DEPLOYMENT_TRAFFIC_ALLOCATION": "",
"CURRENT_DEPLOYMENT_NAME": "",
"CURRENT_DEPLOYMENT_TRAFFIC_ALLOCATION": 100,
"COMPUTE_NAME": "",
"DEPLOYMENT_VM_SIZE": "promptinstancetype",
"DEPLOYMENT_BASE_IMAGE_NAME": "mcr.microsoft.com/azureml/promptflow/promptflow-runtime:latest",
"DEPLOYMENT_CONDA_PATH": "environment/conda.yml",
"DEPLOYMENT_INSTANCE_COUNT": 1,
"CPU_ALLOCATION": "",
"MEMORY_ALLOCATION": "",
"ENVIRONMENT_VARIABLES": {
"example-name": "example-value"
}
}
}
47 changes: 47 additions & 0 deletions deployment_config.json.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"azure_managed_endpoint":[
{
"ENV_NAME": "dev",
"TEST_FILE_PATH": "sample-request.json",
"PUBLIC_ACCESS": "true",
"ENDPOINT_NAME": "",
"ENDPOINT_DESC": "An online endpoint serving a flow for [task]",
"DEPLOYMENT_DESC": "prompt flow deployment",
"PRIOR_DEPLOYMENT_NAME": "",
"PRIOR_DEPLOYMENT_TRAFFIC_ALLOCATION": "",
"CURRENT_DEPLOYMENT_NAME": "",
"CURRENT_DEPLOYMENT_TRAFFIC_ALLOCATION": "100",
"DEPLOYMENT_VM_SIZE": "Standard_F4s_v2",
"DEPLOYMENT_BASE_IMAGE_NAME": "mcr.microsoft.com/azureml/promptflow/promptflow-runtime:latest",
"DEPLOYMENT_CONDA_PATH": "environment/conda.yml",
"DEPLOYMENT_INSTANCE_COUNT": 1,
"ENVIRONMENT_VARIABLES": {
"example-name": "example-value"
}
}
],
"kubernetes_endpoint":[
{
"ENV_NAME": "dev",
"TEST_FILE_PATH": "sample-request.json",
"PUBLIC_ACCESS": "true",
"ENDPOINT_NAME": "",
"ENDPOINT_DESC": "An kubernetes endpoint serving a flow for [task]",
"DEPLOYMENT_DESC": "prompt flow deployment",
"PRIOR_DEPLOYMENT_NAME": "",
"PRIOR_DEPLOYMENT_TRAFFIC_ALLOCATION": "",
"CURRENT_DEPLOYMENT_NAME": "",
"CURRENT_DEPLOYMENT_TRAFFIC_ALLOCATION": 100,
"COMPUTE_NAME": "",
"DEPLOYMENT_VM_SIZE": "promptinstancetype",
"DEPLOYMENT_BASE_IMAGE_NAME": "mcr.microsoft.com/azureml/promptflow/promptflow-runtime:latest",
"DEPLOYMENT_CONDA_PATH": "environment/conda.yml",
"DEPLOYMENT_INSTANCE_COUNT": 1,
"CPU_ALLOCATION": "",
"MEMORY_ALLOCATION": "",
"ENVIRONMENT_VARIABLES": {
"example-name": "example-value"
}
}
]
}
191 changes: 191 additions & 0 deletions infra/bicep/main.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
@description('Location for all resources.')
param location string = resourceGroup().location

@description('Type of environment (dev, qa, prod, ...).')
param environmentType string

@description('The SKU for Key Vault.')
param keyVaultSku string = 'premium'

@description('Public SSH key to connect to the Linux jumpbox')
param jumpboxSshKey string

@description('Associated private SSH key to connect to the Linux jumpbox')
@secure()
param jumpboxSshPrivateKey string

@description('Enable public access to ease dev tests?')
param enableNetworkIsolation bool = false

@description('Set of tags to apply to all resources.')
param tags object = {
environmentType: environmentType
}
// Parameters for the storage account
param storageSku string ='Standard_LRS'

module nsg 'modules/nsg.bicep' = {
name: 'nsg-${uniqueString(resourceGroup().id)}'
params: {
location: location
tags: tags
nameNsg: 'nsg-${uniqueString(resourceGroup().id)}'
}
}

module network 'modules/network.bicep' = {
name: 'vnet'
params: {
location: location
environmentType: environmentType
idNetworkSecurityGroup: nsg.outputs.networkSecurityGroup
vnetName: 'vnet-${uniqueString(resourceGroup().id)}'
vnetAddressSpace: '10.1.0.0/16'
llmopsSubnet: '10.1.4.0/24'
jumpboxSubnet: '10.1.6.0/24'
enableNetworkIsolation: enableNetworkIsolation
}
}

module appInsights 'modules/app-insights.bicep' = {
name: 'appInsights'
params: {
location: location
environmentType: environmentType
enableNetworkIsolation: enableNetworkIsolation
}
}


module keyVault 'modules/key-vault.bicep' = {
name: 'keyVault'
params: {
location: location
environmentType: environmentType
skuName: keyVaultSku
enableNetworkIsolation: enableNetworkIsolation
sshPrivateKey: jumpboxSshPrivateKey
virtualNetworkId: network.outputs.vnetId
subnetId: network.outputs.llmopsSubnetId
}
}



// Creating two storage accounts:
// - one for the Azure Machine Learning workspace
module storage 'modules/storage.bicep' = {
name: 'storagellmops'
params: {
location: location
nameStorage: 'stllmops${uniqueString(resourceGroup().id)}'
nameStoragePleBlob: 'pep-blob-stllmops${uniqueString(resourceGroup().id)}'
nameStoragePleFile: 'pep-file-stllmops${uniqueString(resourceGroup().id)}'
nameStorageSku: storageSku
subnetId: network.outputs.llmopsSubnetId
virtualNetworkId: network.outputs.vnetId
enableNetworkIsolation: enableNetworkIsolation
tags: tags
}
}


// Creating the Azure Container registry required by
// Azure machine Learning to serve as a model registry
module containerRegistry 'modules/container-registry.bicep' = {
name: 'llmopsContainerRegistry'
params: {
location: location
nameContainerRegistry: 'acr${uniqueString(resourceGroup().id)}'
nameContainerRegistryPep: 'pep-acr-${uniqueString(resourceGroup().id)}'
subnetId: network.outputs.llmopsSubnetId
virtualNetworkId: network.outputs.vnetId
enableNetworkIsolation: enableNetworkIsolation
tags: tags
}
}


// Creating the Azure Machine Learning workspace, compute and networking resources
module azuremlWorkspace 'modules/machine-learning-workspace.bicep' = {
name: 'azuremlWorkspace'
params: {
// workspace organization
nameMachineLearning: 'amlws-${environmentType}-${uniqueString(resourceGroup().id)}'
nameMachineLearningFriendly: 'Azure ML ${environmentType} workspace'
descriptionMachineLearning: 'This is an AML workspace for ${environmentType} environment'
location: location
tags: tags

// dependant resources
applicationInsightsId: appInsights.outputs.id
containerRegistryId: containerRegistry.outputs.containerRegistryId
keyVaultId: keyVault.outputs.keyVaultId
storageAccountId: storage.outputs.storageId
azureOpenAIId: azureOpenAI.outputs.azureOpenAIId

// networking
subnetId: network.outputs.llmopsSubnetId
virtualNetworkId: network.outputs.vnetId
machineLearningPepName: 'pep-amlws-${uniqueString(resourceGroup().id)}'

enableNetworkIsolation: enableNetworkIsolation
}
dependsOn: [
keyVault
containerRegistry
appInsights
storage
]
}

// Creating all the role assignments required for the end-to-end flow to work
module rolesAssignments 'modules/rolesAssignments.bicep' = {
name: 'rolesAssignments-${uniqueString(resourceGroup().id)}'
params: {
nameStorage: storage.outputs.nameStorage
azuremlWorkspacePrincipalId: azuremlWorkspace.outputs.machineLearningPrincipalId
}
}

// Creating the Azure OpenAI resource
module azureOpenAI 'modules/azure-openai.bicep' = {
name: 'azureOpenAI'
params: {
//Azure OpenAI resource
nameAOAI: 'aoai-eastus-${environmentType}-${uniqueString(resourceGroup().id)}'
location: location
nameDeploymentAOAI: 'gpt-35-turbo'
nameDeployedModel: 'gpt-35-turbo'
versionDeployedModel: '0301'
skuAOAI: {
name: 'S0'
}
environmentType: environmentType
enableNetworkIsolation: enableNetworkIsolation

// Networking
subnetId: network.outputs.llmopsSubnetId
virtualNetworkId: network.outputs.vnetId
namePepAOAI: 'pep-aoai-eastus-${uniqueString(resourceGroup().id)}'
privateDnsZoneName: 'privatelink.openai.azure.com'

}
}


// Creating the SSH linux VM
module linuxmachine 'modules/linux-machine.bicep' = if (enableNetworkIsolation) {
name: 'sshmachine'
params: {
location: location
nameVm: 'VMsshLinux'
subnetId: network.outputs.jumpboxSubnetId
adminUsername: 'azureuser'
sshKey: jumpboxSshKey
networkSecurityGroupId: nsg.outputs.networkSecurityGroup
}
}

output keyVaultName string = keyVault.outputs.keyVaultName
output amlWorkspaceName string = azuremlWorkspace.outputs.nameMachineLearning
38 changes: 38 additions & 0 deletions infra/bicep/modules/app-insights.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
@description('The type of the environment')
param environmentType string
@description('Application Insight name')
param appInsightsName string = 'appinsights-${environmentType}-${uniqueString(resourceGroup().id)}'
@description('Application Insight name')
param logAnalyticsWorkspaceName string = 'loganalyticsw-${environmentType}-${uniqueString(resourceGroup().id)}'
@description('Location for all resources.')
param location string = resourceGroup().location
@description('Enable public access to ease dev tests?')
param enableNetworkIsolation bool

resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = {
name: logAnalyticsWorkspaceName
location: location
properties: {
sku: {
name: 'PerGB2018'
}
retentionInDays: 30
publicNetworkAccessForIngestion: 'Enabled'
publicNetworkAccessForQuery: ( enableNetworkIsolation ? 'Enabled' : 'Disabled' )
}
}

resource appInsights 'Microsoft.Insights/components@2020-02-02' = {
name: appInsightsName
location: location
kind: 'web'
properties: {
Application_Type: 'web'
Request_Source: 'rest'
WorkspaceResourceId: logAnalyticsWorkspace.id
Flow_Type: 'Bluefield'
}
}

output connectionString string = appInsights.properties.ConnectionString
output id string = appInsights.id
Loading
Loading