- Azure subscription
Important: The user initiating the deployment process must have access to the Microsoft.Authorization/roleAssignments/write permission. For more information, see the Container Insights doc
- Azure CLI 2.0.49 or later
- Docker
- JQ
Note: in linux systems, it is possible to run the docker command without prefacing with sudo. For more information, please refer to the Post-installation steps for linux
Clone or download this repo locally.
git clone --recurse-submodules https://github.com/mspnp/microservices-reference-implementation.git && \
cd microservices-reference-implementation/
The deployment steps shown here use Bash shell commands. On Windows, you can use the Windows Subsystem for Linux to run Bash.
the SSH rsa key pair can be generated using ssh-keygen, among other tools, on Linux, Mac, or Windows. If you already have an ~/.ssh/id_rsa.pub file, you could provide the same later on. If you need to create an SSH key pair, see How to create and use an SSH key pair.
Note: the SSH rsa public key will be requested when deploying your Kubernetes cluster in Azure.
Set environment variables.
export SSH_PUBLIC_KEY_FILE=[YOUR_RECENTLY_GENERATED_SSH_RSA_PUBLIC_KEY_FILE_HERE]
export LOCATION=eastus2
export RESOURCE_GROUP=rg-shipping-microservices
Gather infrastructure Prerequisites.
# Log in to Azure
az login
# if you have several subscriptions, select one
# az account set -s <subscription id>
# Create service principal for AKS
export SP_DETAILS=$(az ad sp create-for-rbac --role="Contributor" -o json) && \
export SP_APP_ID=$(echo $SP_DETAILS | jq ".appId" -r) && \
export SP_CLIENT_SECRET=$(echo $SP_DETAILS | jq ".password" -r)
export DEPLOYMENT_SUFFIX=$(date +%S%N)
Note: this deployment might take up to 20 minutes
Infrastructure
# Deploy the managed identities (This takes less than two minutes.)
export PREREQS_DEPLOYMENT_NAME=workload-stamp-prereqs-main
az deployment sub create --name $PREREQS_DEPLOYMENT_NAME --location eastus2 --template-file ./workload/workload-stamp-prereqs.json --parameters resourceGroupName=$RESOURCE_GROUP resourceGroupLocation=$LOCATION
# Get the Azure Container Registry resource group name and the user identities
export WORKLOAD_PREREQS_DEPLOYMENT_NAME=workload-stamp-prereqs-dep && \
export DELIVERY_ID_NAME=$(az deployment group show -g $RESOURCE_GROUP -n $WORKLOAD_PREREQS_DEPLOYMENT_NAME --query properties.outputs.deliveryIdName.value -o tsv) && \
export DELIVERY_ID_PRINCIPAL_ID=$(az identity show -g $RESOURCE_GROUP -n $DELIVERY_ID_NAME --query principalId -o tsv) && \
export DRONESCHEDULER_ID_NAME=$(az deployment group show -g $RESOURCE_GROUP -n $WORKLOAD_PREREQS_DEPLOYMENT_NAME --query properties.outputs.droneSchedulerIdName.value -o tsv) && \
export DRONESCHEDULER_ID_PRINCIPAL_ID=$(az identity show -g $RESOURCE_GROUP -n $DRONESCHEDULER_ID_NAME --query principalId -o tsv) && \
export WORKFLOW_ID_NAME=$(az deployment group show -g $RESOURCE_GROUP -n $WORKLOAD_PREREQS_DEPLOYMENT_NAME --query properties.outputs.workflowIdName.value -o tsv) && \
export WORKFLOW_ID_PRINCIPAL_ID=$(az identity show -g $RESOURCE_GROUP -n $WORKFLOW_ID_NAME --query principalId -o tsv) && \
export PACKAGE_ID_NAME=$(az deployment group show -g $RESOURCE_GROUP -n $WORKLOAD_PREREQS_DEPLOYMENT_NAME --query properties.outputs.packageIdName.value -o tsv) && \
export PACKAGE_ID_PRINCIPAL_ID=$(az identity show -g $RESOURCE_GROUP -n $PACKAGE_ID_NAME --query principalId -o tsv) && \
export INGESTION_ID_NAME=$(az deployment group show -g $RESOURCE_GROUP -n $WORKLOAD_PREREQS_DEPLOYMENT_NAME --query properties.outputs.ingestionIdName.value -o tsv) && \
export INGESTION_ID_PRINCIPAL_ID=$(az identity show -g $RESOURCE_GROUP -n $INGESTION_ID_NAME --query principalId -o tsv) && \
export RESOURCE_GROUP_ACR=$(az deployment sub show -n $PREREQS_DEPLOYMENT_NAME --query properties.outputs.acrResourceGroupName.value -o tsv)
# Wait for AAD propagation
until az ad sp show --id $DELIVERY_ID_PRINCIPAL_ID &> /dev/null ; do echo "Waiting for AAD propagation" && sleep 5; done
until az ad sp show --id $DRONESCHEDULER_ID_PRINCIPAL_ID &> /dev/null ; do echo "Waiting for AAD propagation" && sleep 5; done
until az ad sp show --id $WORKFLOW_ID_PRINCIPAL_ID &> /dev/null ; do echo "Waiting for AAD propagation" && sleep 5; done
until az ad sp show --id $INGESTION_ID_PRINCIPAL_ID &> /dev/null ; do echo "Waiting for AAD propagation" && sleep 5; done
until az ad sp show --id $PACKAGE_ID_PRINCIPAL_ID &> /dev/null ; do echo "Waiting for AAD propagation" && sleep 5; done
# Export the kubernetes cluster version
export KUBERNETES_VERSION=$(az aks get-versions -l $LOCATION --query "orchestrators[?default!=null].orchestratorVersion" -o tsv)
# Deploy all the workload related resources (This step takes about 10 minutes)
az deployment group create -f ./workload/workload-stamp.json -g $RESOURCE_GROUP -p droneSchedulerPrincipalId=$DRONESCHEDULER_ID_PRINCIPAL_ID -p workflowPrincipalId=$WORKFLOW_ID_PRINCIPAL_ID -p deliveryPrincipalId=$DELIVERY_ID_PRINCIPAL_ID -p ingestionPrincipalId=$INGESTION_ID_PRINCIPAL_ID -p packagePrincipalId=$PACKAGE_ID_PRINCIPAL_ID -p acrResourceGroupName=$RESOURCE_GROUP_ACR
# Get outputs from workload deploy
export ACR_NAME=$(az deployment group show -g $RESOURCE_GROUP -n workload-stamp --query properties.outputs.acrName.value -o tsv) && \
export ACR_SERVER=$(az acr show -n $ACR_NAME --query loginServer -o tsv)
The Secrets Store CSI Driver for Kubernetes allows for the integration of Azure Key Vault as a secrets store with a Kubernetes cluster via a CSI volume. Before creating a managed AKS cluster that can use the Secrets Store CSI Driver, you must enable the AKS-AzureKeyVaultSecretsProvider feature flag on your subscription.
# Register the AKS-AzureKeyVaultSecretsProvider feature flag by using the az feature register command
az feature register --namespace "Microsoft.ContainerService" --name "AKS-AzureKeyVaultSecretsProvider"
# It may take almost 30 minutes for the status to show Registered. Verify the registration status by using the az feature list command:
az feature list -o table --query "[?contains(name, 'Microsoft.ContainerService/AKS-AzureKeyVaultSecretsProvider')].{Name:name,State:properties.state}"
# When ready, refresh the registration of the Microsoft.ContainerService resource provider by using the az provider register command:
az provider register --namespace Microsoft.ContainerService
Deploy the managed cluster and all related resources (This step takes about 15 minutes)
export DEPLOYMENT_NAME=azuredeploy-$DEPLOYMENT_SUFFIX
az deployment group create -g $RESOURCE_GROUP --name $DEPLOYMENT_NAME --template-file azuredeploy.json \
--parameters servicePrincipalClientId=$SP_APP_ID \
servicePrincipalClientSecret=$SP_CLIENT_SECRET \
kubernetesVersion=$KUBERNETES_VERSION \
sshRSAPublicKey="$(cat $SSH_PUBLIC_KEY_FILE)" \
deliveryIdName=$DELIVERY_ID_NAME \
ingestionIdName=$INGESTION_ID_NAME \
packageIdName=$PACKAGE_ID_NAME \
droneSchedulerIdName=$DRONESCHEDULER_ID_NAME \
workflowIdName=$WORKFLOW_ID_NAME \
acrResourceGroupName=$RESOURCE_GROUP_ACR \
acrName=$ACR_NAME
Get the cluster name output from Azure Deploy.
export CLUSTER_NAME=$(az deployment group show -g $RESOURCE_GROUP -n $DEPLOYMENT_NAME --query properties.outputs.aksClusterName.value -o tsv)
Download kubectl and create a Kubernetes namespace.
# Install kubectl
az aks install-cli
# Get the Kubernetes cluster credentials
az aks get-credentials --resource-group=$RESOURCE_GROUP --name=$CLUSTER_NAME
# Create namespaces
kubectl create namespace backend-dev
Install and initialize Helm.
# install helm 3
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
Integrate Application Insights instance.
# Acquire Instrumentation Key
export AI_NAME=$(az deployment group show -g $RESOURCE_GROUP -n workload-stamp --query properties.outputs.appInsightsName.value -o tsv)
export AI_IKEY=$(az resource show -g $RESOURCE_GROUP -n $AI_NAME --resource-type "Microsoft.Insights/components" --query properties.InstrumentationKey -o tsv)
# add RBAC for AppInsights
kubectl apply -f k8s/k8s-rbac-ai.yaml
Verify that the secrets-store pods are running in the kube-system namespace
kubectl get pods -n kube-system
You should see an output similar to this:
NAME READY STATUS RESTARTS AGE
aks-secrets-store-csi-driver-4bjzx 3/3 Running 2 28m
aks-secrets-store-csi-driver-b22bj 3/3 Running 1 28m
aks-secrets-store-provider-azure-2k5mx 1/1 Running 0 28m
aks-secrets-store-provider-azure-l5w98 1/1 Running 0 28m
To use and configure the Secrets Store CSI driver for your AKS cluster, create a SecretProviderClass custom resource for the Workflow and the Ingestion service.
export WORKFLOW_KEYVAULT_NAME=$(az deployment group show -g $RESOURCE_GROUP -n workload-stamp --query properties.outputs.workflowKeyVaultName.value -o tsv)
export INGESTION_KEYVAULT_NAME=$(az deployment group show -g $RESOURCE_GROUP -n workload-stamp --query properties.outputs.ingestionKeyVaultName.value -o tsv)
export PACKAGE_KEYVAULT_NAME=$(az deployment group show -g $RESOURCE_GROUP -n workload-stamp --query properties.outputs.packageKeyVaultName.value -o tsv)
export DELIVERY_KEYVAULT_NAME=$(az deployment group show -g $RESOURCE_GROUP -n workload-stamp --query properties.outputs.deliveryKeyVaultName.value -o tsv)
export TENANT_ID=$(az account show --query tenantId --output tsv)
export INGRESS_TLS_SECRET_NAME=ingestion-ingress-tls
export DELIVERY_INGRESS_TLS_SECRET_NAME=delivery-ingress-tls
# Create secrets
# Note: Ingress TLS key and certificate secrets cannot be exported as outputs in ARM deployments
# So we create an access policy to allow these secrets to be created imperatively.
# The policy is deleted right after the secret creation commands are executed
export SIGNED_IN_OBJECT_ID=$(az ad signed-in-user show --query 'objectId' -o tsv)
az keyvault set-policy --secret-permissions set --object-id $SIGNED_IN_OBJECT_ID -n $INGESTION_KEYVAULT_NAME
az keyvault secret set --name Ingestion-Ingress-Tls-Key --vault-name $INGESTION_KEYVAULT_NAME --value "$(cat ingestion-ingress-tls.key)"
az keyvault secret set --name Ingestion-Ingress-Tls-Crt --vault-name $INGESTION_KEYVAULT_NAME --value "$(cat ingestion-ingress-tls.crt)"
az keyvault delete-policy --object-id $SIGNED_IN_OBJECT_ID -n $INGESTION_KEYVAULT_NAME
cat <<EOF | kubectl apply -f -
apiVersion: secrets-store.csi.x-k8s.io/v1alpha1
kind: SecretProviderClass
metadata:
name: workflow-secrets-csi-akv
namespace: backend-dev
spec:
provider: azure
parameters:
usePodIdentity: "true"
keyvaultName: "${WORKFLOW_KEYVAULT_NAME}"
objects: |
array:
- |
objectName: QueueName
objectAlias: QueueName
objectType: secret
- |
objectName: QueueEndpoint
objectAlias: QueueEndpoint
objectType: secret
- |
objectName: QueueAccessPolicyName
objectAlias: QueueAccessPolicyName
objectType: secret
- |
objectName: QueueAccessPolicyKey
objectAlias: QueueAccessPolicyKey
objectType: secret
- |
objectName: ApplicationInsights--InstrumentationKey
objectAlias: ApplicationInsights--InstrumentationKey
objectType: secret
tenantId: "${TENANT_ID}"
EOF
cat <<EOF | kubectl apply -f -
apiVersion: secrets-store.csi.x-k8s.io/v1alpha1
kind: SecretProviderClass
metadata:
name: ingestion-secrets-csi-akv
namespace: backend-dev
spec:
provider: azure
secretObjects:
- secretName: "${INGRESS_TLS_SECRET_NAME}"
type: Opaque
data:
- objectName: Ingestion-Ingress-Tls-Key
key: tls.key
- objectName: Ingestion-Ingress-Tls-Crt
key: tls.crt
- secretName: ingestion-secrets
type: Opaque
data:
- objectName: Queue--Key
key: queue-keyvalue
- objectName: ApplicationInsights--InstrumentationKey
key: appinsights-ikey
parameters:
usePodIdentity: "true"
keyvaultName: "${INGESTION_KEYVAULT_NAME}"
objects: |
array:
- |
objectName: Queue--Key
objectAlias: Queue--Key
objectType: secret
- |
objectName: ApplicationInsights--InstrumentationKey
objectAlias: ApplicationInsights--InstrumentationKey
objectType: secret
- |
objectName: Ingestion-Ingress-Tls-Key
objectAlias: Ingestion-Ingress-Tls-Key
objectType: secret
- |
objectName: Ingestion-Ingress-Tls-Crt
objectAlias: Ingestion-Ingress-Tls-Crt
objectType: secret
tenantId: "${TENANT_ID}"
EOF
cat <<EOF | kubectl apply -f -
apiVersion: secrets-store.csi.x-k8s.io/v1alpha1
kind: SecretProviderClass
metadata:
name: package-secrets-csi-akv
namespace: backend-dev
spec:
provider: azure
secretObjects:
- secretName: package-secrets
type: Opaque
data:
- objectName: CosmosDb--ConnectionString
key: cosmosdb-connstr
- objectName: ApplicationInsights--InstrumentationKey
key: appinsights-ikey
parameters:
usePodIdentity: "true"
keyvaultName: "${PACKAGE_KEYVAULT_NAME}"
objects: |
array:
- |
objectName: CosmosDb--ConnectionString
objectAlias: CosmosDb--ConnectionString
objectType: secret
- |
objectName: ApplicationInsights--InstrumentationKey
objectAlias: ApplicationInsights--InstrumentationKey
objectType: secret
tenantId: "${TENANT_ID}"
EOF
cat <<EOF | kubectl apply -f -
apiVersion: secrets-store.csi.x-k8s.io/v1alpha1
kind: SecretProviderClass
metadata:
name: delivery-secrets-csi-akv
namespace: backend-dev
spec:
provider: azure
secretObjects:
- secretName: "${INGRESS_TLS_SECRET_NAME}"
type: Opaque
data:
- objectName: Delivery-Ingress-Tls-Key
key: tls.key
- objectName: Delivery-Ingress-Tls-Crt
key: tls.crt
parameters:
usePodIdentity: "true"
keyvaultName: "${DELIVERY_KEYVAULT_NAME}"
objects: |
array:
- |
objectName: Delivery-Ingress-Tls-Key
objectAlias: Delivery-Ingress-Tls-Key
objectType: secret
- |
objectName: Delivery-Ingress-Tls-Crt
objectAlias: Delivery-Ingress-Tls-Crt
objectType: secret
tenantId: "${TENANT_ID}"
EOF
# setup AAD pod identity
helm repo add aad-pod-identity https://raw.githubusercontent.com/Azure/aad-pod-identity/master/charts
helm repo update
helm install aad-pod-identity aad-pod-identity/aad-pod-identity --set installCRDs=true --set nmi.allowNetworkPluginKubenet=true --namespace kube-system --version 4.0.0
⚠️ WARNINGDo not use the certificates created by these scripts for production. The certificates are provided for demonstration purposes only. For your production cluster, use your security best practices for digital certificates creation and lifetime management.
❗ In the following instructions you will proceed using a public container registry to install NGINX. But please take into account that public registries may be subject to faults such as outages (no SLA) or request throttling. Interruptions like these can be crippling for an application that needs to pull an image right now. To minimize the risks of using public registries, store all applicable container images in a registry that you control, such as the SLA-backed Azure Container Registry.
# Deploy the ngnix ingress controller
kubectl create namespace ingress-controllers
helm install nginx-ingress-dev stable/nginx-ingress --namespace ingress-controllers --version 1.24.7 --set rbac.create=true --set controller.ingressClass=nginx-dev
# Obtain the load balancer ip address and assign a domain name
until export INGRESS_LOAD_BALANCER_IP=$(kubectl get services/nginx-ingress-dev-controller -n ingress-controllers -o jsonpath="{.status.loadBalancer.ingress[0].ip}" 2> /dev/null) && test -n "$INGRESS_LOAD_BALANCER_IP"; do echo "Waiting for load balancer deployment" && sleep 20; done
export INGRESS_LOAD_BALANCER_IP_ID=$(az network public-ip list --query "[?ipAddress!=null]|[?contains(ipAddress, '$INGRESS_LOAD_BALANCER_IP')].[id]" --output tsv) && \
export EXTERNAL_INGEST_DNS_NAME="${RESOURCE_GROUP}-${RANDOM}-ing" && \
export EXTERNAL_INGEST_FQDN=$(az network public-ip update --ids $INGRESS_LOAD_BALANCER_IP_ID --dns-name $EXTERNAL_INGEST_DNS_NAME --query "dnsSettings.fqdn" --output tsv)
# Create a self-signed certificate for TLS
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-out ingestion-ingress-tls.crt \
-keyout ingestion-ingress-tls.key \
-subj "/CN=${EXTERNAL_INGEST_FQDN}/O=fabrikam"
kubectl apply -f k8s/k8s-resource-quotas-dev.yaml
Extract resource details from deployment.
export COSMOSDB_NAME=$(az deployment group show -g $RESOURCE_GROUP -n workload-stamp --query properties.outputs.deliveryCosmosDbName.value -o tsv) && \
export DATABASE_NAME="${COSMOSDB_NAME}-db" && \
export COLLECTION_NAME="${DATABASE_NAME}-col" && \
export DELIVERY_KEYVAULT_URI=$(az deployment group show -g $RESOURCE_GROUP -n workload-stamp --query properties.outputs.deliveryKeyVaultUri.value -o tsv)
Build and publish the Delivery service container image.
az acr build -r $ACR_NAME -t $ACR_SERVER/delivery:0.1.0 ./workload/src/shipping/delivery/.
Deploy the Delivery service.
# Extract pod identity outputs from deployment
export DELIVERY_PRINCIPAL_RESOURCE_ID=$(az deployment group show -g $RESOURCE_GROUP -n $DEPLOYMENT_NAME --query properties.outputs.deliveryPrincipalResourceId.value -o tsv) && \
export DELIVERY_PRINCIPAL_CLIENT_ID=$(az identity show -g $RESOURCE_GROUP -n $DELIVERY_ID_NAME --query clientId -o tsv)
# Create secrets
# Note: Ingress TLS key and certificate secrets cannot be exported as outputs in ARM deployments
# So we create an access policy to allow these secrets to be created imperatively.
# The policy is deleted right after the secret creation commands are executed
export SIGNED_IN_OBJECT_ID=$(az ad signed-in-user show --query 'objectId' -o tsv)
az keyvault set-policy --secret-permissions set --object-id $SIGNED_IN_OBJECT_ID -n $DELIVERY_KEYVAULT_NAME
az keyvault secret set --name Delivery-Ingress-Tls-Key --vault-name $DELIVERY_KEYVAULT_NAME --value "$(cat ingestion-ingress-tls.key)"
az keyvault secret set --name Delivery-Ingress-Tls-Crt --vault-name $DELIVERY_KEYVAULT_NAME --value "$(cat ingestion-ingress-tls.crt)"
az keyvault delete-policy --object-id $SIGNED_IN_OBJECT_ID -n $DELIVERY_KEYVAULT_NAME
# Deploy the service
helm package charts/delivery/ -u && \
helm install delivery-v0.1.0-dev delivery-v0.1.0.tgz \
--set image.tag=0.1.0 \
--set image.repository=delivery \
--set dockerregistry=$ACR_SERVER \
--set ingress.hosts[0].name=$EXTERNAL_INGEST_FQDN \
--set ingress.hosts[0].serviceName=delivery \
--set ingress.hosts[0].tls=true \
--set ingress.hosts[0].tlsSecretName=$INGRESS_TLS_SECRET_NAME \
--set identity.clientid=$DELIVERY_PRINCIPAL_CLIENT_ID \
--set identity.resourceid=$DELIVERY_PRINCIPAL_RESOURCE_ID \
--set cosmosdb.id=$DATABASE_NAME \
--set cosmosdb.collectionid=$COLLECTION_NAME \
--set keyvault.uri=$DELIVERY_KEYVAULT_URI \
--set reason="Initial deployment" \
--set tags.dev=true \
--namespace backend-dev \
--dependency-update
# Verify the pod is created
helm status delivery-v0.1.0-dev --namespace backend-dev
Extract resource details from deployment.
export COSMOSDB_NAME=$(az deployment group show -g $RESOURCE_GROUP -n workload-stamp --query properties.outputs.packageMongoDbName.value -o tsv)
export PACKAGE_PRINCIPAL_RESOURCE_ID=$(az deployment group show -g $RESOURCE_GROUP -n $DEPLOYMENT_NAME --query properties.outputs.packagePrincipalResourceId.value -o tsv) && \
export PACKAGE_PRINCIPAL_CLIENT_ID=$(az identity show -g $RESOURCE_GROUP -n $PACKAGE_ID_NAME --query clientId -o tsv)
Build the Package service.
az acr build -r $ACR_NAME -t $ACR_SERVER/package:0.1.0 ./workload/src/shipping/package/.
Deploy the Package service.
# Create secret
# Note: Connection strings cannot be exported as outputs in ARM deployments
# So we create an access policy to allow the secret to be created imperatively.
# The policy is deleted right after the secret creation command is executed
export COSMOSDB_CONNECTION=$(az cosmosdb keys list --type connection-strings --name $COSMOSDB_NAME --resource-group $RESOURCE_GROUP --query "connectionStrings[0].connectionString" -o tsv | sed 's/==/%3D%3D/g') && \
export COSMOSDB_COL_NAME=packages && \
az keyvault set-policy --secret-permissions set --object-id $SIGNED_IN_OBJECT_ID -n $PACKAGE_KEYVAULT_NAME
az keyvault secret set --name CosmosDb--ConnectionString --vault-name $PACKAGE_KEYVAULT_NAME --value $COSMOSDB_CONNECTION
az keyvault delete-policy --object-id $SIGNED_IN_OBJECT_ID -n $PACKAGE_KEYVAULT_NAME
# Deploy service
helm package charts/package/ -u && \
helm install package-v0.1.0-dev package-v0.1.0.tgz \
--set image.tag=0.1.0 \
--set image.repository=package \
--set identity.clientid=$PACKAGE_PRINCIPAL_CLIENT_ID \
--set identity.resourceid=$PACKAGE_PRINCIPAL_RESOURCE_ID \
--set ingress.hosts[0].name=$EXTERNAL_INGEST_FQDN \
--set ingress.hosts[0].serviceName=package \
--set ingress.hosts[0].tls=false \
--set cosmosDb.collectionName=$COSMOSDB_COL_NAME \
--set dockerregistry=$ACR_SERVER \
--set reason="Initial deployment" \
--set tags.dev=true \
--namespace backend-dev \
--dependency-update
# Verify the pod is created
helm status package-v0.1.0-dev --namespace backend-dev
Extract resource details from deployment.
export WORKFLOW_KEYVAULT_NAME=$(az deployment group show -g $RESOURCE_GROUP -n workload-stamp --query properties.outputs.workflowKeyVaultName.value -o tsv)
Build the workflow service.
az acr build -r $ACR_NAME -t $ACR_SERVER/workflow:0.1.0 ./workload/src/shipping/workflow/.
Create and set up pod identity.
# Extract outputs from deployment and get Azure account details
export WORKFLOW_PRINCIPAL_RESOURCE_ID=$(az deployment group show -g $RESOURCE_GROUP -n $DEPLOYMENT_NAME --query properties.outputs.workflowPrincipalResourceId.value -o tsv) && \
export WORKFLOW_PRINCIPAL_CLIENT_ID=$(az identity show -g $RESOURCE_GROUP -n $WORKFLOW_ID_NAME --query clientId -o tsv) && \
export SUBSCRIPTION_ID=$(az account show --query id --output tsv) && \
export TENANT_ID=$(az account show --query tenantId --output tsv)
Deploy the Workflow service.
# Deploy the service
helm package charts/workflow/ -u && \
helm install workflow-v0.1.0-dev workflow-v0.1.0.tgz \
--set image.tag=0.1.0 \
--set image.repository=workflow \
--set dockerregistry=$ACR_SERVER \
--set identity.clientid=$WORKFLOW_PRINCIPAL_CLIENT_ID \
--set identity.resourceid=$WORKFLOW_PRINCIPAL_RESOURCE_ID \
--set keyvault.name=$WORKFLOW_KEYVAULT_NAME \
--set keyvault.resourcegroup=$RESOURCE_GROUP \
--set keyvault.subscriptionid=$SUBSCRIPTION_ID \
--set keyvault.tenantid=$TENANT_ID \
--set reason="Initial deployment" \
--set tags.dev=true \
--namespace backend-dev \
--dependency-update
# Verify the pod is created
helm status workflow-v0.1.0-dev --namespace backend-dev
Extract resource details and pod identity outputs from deployment.
export INGESTION_QUEUE_NAMESPACE=$(az deployment group show -g $RESOURCE_GROUP -n workload-stamp --query properties.outputs.ingestionQueueNamespace.value -o tsv) && \
export INGESTION_QUEUE_NAME=$(az deployment group show -g $RESOURCE_GROUP -n workload-stamp --query properties.outputs.ingestionQueueName.value -o tsv)
export INGESTION_PRINCIPAL_RESOURCE_ID=$(az deployment group show -g $RESOURCE_GROUP -n $DEPLOYMENT_NAME --query properties.outputs.ingestionPrincipalResourceId.value -o tsv) && \
export INGESTION_PRINCIPAL_CLIENT_ID=$(az identity show -g $RESOURCE_GROUP -n $INGESTION_ID_NAME --query clientId -o tsv)
Build the Ingestion service.
az acr build -r $ACR_NAME -t $ACR_SERVER/ingestion:0.1.0 ./workload/src/shipping/ingestion/.
# Deploy service
helm package charts/ingestion/ -u && \
helm install ingestion-v0.1.0-dev ingestion-v0.1.0.tgz \
--set image.tag=0.1.0 \
--set image.repository=ingestion \
--set dockerregistry=$ACR_SERVER \
--set identity.clientid=$INGESTION_PRINCIPAL_CLIENT_ID \
--set identity.resourceid=$INGESTION_PRINCIPAL_RESOURCE_ID \
--set ingress.hosts[0].name=$EXTERNAL_INGEST_FQDN \
--set ingress.hosts[0].serviceName=ingestion \
--set ingress.hosts[0].tls=true \
--set ingress.hosts[0].tlsSecretName=$INGRESS_TLS_SECRET_NAME \
--set secrets.queue.keyname=IngestionServiceAccessKey \
--set secrets.queue.name=${INGESTION_QUEUE_NAME} \
--set secrets.queue.namespace=${INGESTION_QUEUE_NAMESPACE} \
--set reason="Initial deployment" \
--set tags.dev=true \
--namespace backend-dev \
--dependency-update
# Verify the pod is created
helm status ingestion-v0.1.0-dev --namespace backend-dev
Extract resource details from deployment.
export DRONESCHEDULER_KEYVAULT_URI=$(az deployment group show -g $RESOURCE_GROUP -n workload-stamp --query properties.outputs.droneSchedulerKeyVaultUri.value -o tsv)
export DRONESCHEDULER_COSMOSDB_NAME=$(az deployment group show -g $RESOURCE_GROUP -n workload-stamp --query properties.outputs.droneSchedulerCosmosDbName.value -o tsv) && \
export ENDPOINT_URL=$(az cosmosdb show -n $DRONESCHEDULER_COSMOSDB_NAME -g $RESOURCE_GROUP --query documentEndpoint -o tsv) && \
export AUTH_KEY=$(az cosmosdb keys list -n $DRONESCHEDULER_COSMOSDB_NAME -g $RESOURCE_GROUP --query primaryMasterKey -o tsv) && \
export DATABASE_NAME="invoicing" && \
export COLLECTION_NAME="utilization"
Create and set up pod identity.
# Extract outputs from deployment
export DRONESCHEDULER_PRINCIPAL_RESOURCE_ID=$(az deployment group show -g $RESOURCE_GROUP -n $DEPLOYMENT_NAME --query properties.outputs.droneSchedulerPrincipalResourceId.value -o tsv) && \
export DRONESCHEDULER_PRINCIPAL_CLIENT_ID=$(az identity show -g $RESOURCE_GROUP -n $DRONESCHEDULER_ID_NAME --query clientId -o tsv)
Build and publish the container image.
az acr build -r $ACR_NAME -f ./workload/src/shipping/dronescheduler/Dockerfile -t $ACR_SERVER/dronescheduler:0.1.0 ./workload/src/shipping/.
Deploy the dronescheduler service.
# Deploy the service
helm package charts/dronescheduler/ -u && \
helm install dronescheduler-v0.1.0-dev dronescheduler-v0.1.0.tgz \
--set image.tag=0.1.0 \
--set image.repository=dronescheduler \
--set dockerregistry=$ACR_SERVER \
--set ingress.hosts[0].name=$EXTERNAL_INGEST_FQDN \
--set ingress.hosts[0].serviceName=dronescheduler \
--set ingress.hosts[0].tls=false \
--set identity.clientid=$DRONESCHEDULER_PRINCIPAL_CLIENT_ID \
--set identity.resourceid=$DRONESCHEDULER_PRINCIPAL_RESOURCE_ID \
--set keyvault.uri=$DRONESCHEDULER_KEYVAULT_URI \
--set cosmosdb.id=$DATABASE_NAME \
--set cosmosdb.collectionid=$COLLECTION_NAME \
--set reason="Initial deployment" \
--set tags.dev=true \
--namespace backend-dev \
--dependency-update
# Verify the pod is created
helm status dronescheduler-v0.1.0-dev --namespace backend-dev
You can send delivery requests and check their statuses using curl.
Since the certificate used for TLS is self-signed, the request disables TLS validation using the '-k' option.
curl -X POST "https://$EXTERNAL_INGEST_FQDN/api/deliveryrequests" --header 'Content-Type: application/json' --header 'Accept: application/json' -k -d '{
"confirmationRequired": "None",
"deadline": "",
"dropOffLocation": "drop off",
"expedited": true,
"ownerId": "myowner",
"packageInfo": {
"packageId": "mypackage",
"size": "Small",
"tag": "mytag",
"weight": 10
},
"pickupLocation": "my pickup",
"pickupTime": "2019-05-08T20:00:00.000Z"
}' > deliveryresponse.json
DELIVERY_ID=$(cat deliveryresponse.json | jq -r .deliveryId)
curl "https://$EXTERNAL_INGEST_FQDN/api/deliveries/$DELIVERY_ID" --header 'Accept: application/json' -k