This is a sample microservice solution for Azure Container Apps. It will create a store microservice which will need to call into an order service and an inventory service. Dapr is used to secure communication and calls between services, and Azure API Management and Azure Cosmos DB are created alongside the microservices.
The entire solution is configured with GitHub Actions and Bicep for CI/CD.
IMPORTANT: In general, each microservice should have an independent release and deployment. For the sake of this sample we are building and deploying as part of a single repo.
- Fork the sample repo
- Create the following required encrypted secrets for the sample
Name | Value |
---|---|
AZURE_CREDENTIALS | The JSON credentials for an Azure subscription. Learn more |
RESOURCE_GROUP | The name of the resource group to create |
PACKAGES_TOKEN | A GitHub personal access token with the read:packages scope. Learn more |
-
Open the GitHub Actions, select the Build and Deploy action and choose to run the workflow.
This will start the GitHub Actions which will build the code, publish them to your GitHub repository as private container images, create an Azure Container App environment, a Cosmos DB database, and Container Apps for each of the microservices.
-
Once the GitHub Actions have completed successfully, navigate to the Azure Portal and select the resource group you created. Open the
node-app
container, and browse to the URL. You should see the sample application running. You can go through the UX to create an order through the order microservice, and then navigate to the/orders?id=foo
endpoint and/inventory?id=foo
to get the status via other microservices. -
After calling each microservice, you can open the application insights resource created and select the Application Map, you should see a visualization of your calls between Container Apps (note: it may take a few minutes for the app insights data to ingest and process into the app map view).
You can also deploy the solution at anytime using the Azure CLI.
- Clone the repo and navigate to the folder
- Run the following CLI command (with appropiate values for $variables)
az group create -n $resourceGroup -l canadacentral
az deployment group create -g $resourceGroup -f ./deploy/main.bicep \
-p \
minReplicas=0 \
nodeImage='ghcr.io/jeffhollan/container-apps-store-api-microservice/node-service:main' \
nodePort=3000 \
isNodeExternalIngress=true \
pythonImage='ghcr.io/jeffhollan/container-apps-store-api-microservice/python-service:main' \
pythonPort=5000 \
isPythonExternalIngress=false \
goImage='ghcr.io/jeffhollan/container-apps-store-api-microservice/go-service:main' \
goPort=8050 \
isGoExternalIngress=false \
containerRegistry=ghcr.io \
containerRegistryUsername=$username \
containerRegistryPassword=$GitHubPackagesToken
- Continue with Step #4 in the GitHub Actions flow above to test your solution
There are three main microservices in the solution.
The node-app
is an express.js API that exposes three endpoints. /
will return the primary index page, /order
will return details on an order (retrieved from the order service), and /inventory
will return details on an inventory item (retrieved from the inventory service).
The python-app
is a Python flask app that will retrieve and store the state of orders. It uses Dapr state management to store the state of the orders. When deployed in Container Apps, Dapr is configured to point to an Azure Cosmos DB to back the state.
The go-app
is a Go mux app that will retrieve and store the state of inventory. For this sample, the mux app just returns back a static value.
- Option 1: Build and run with GitHub Codespaces (recommended)
- Option 2: Build and run with VS Code Dev Containers
- Option 3: Build and run with VS Code directly
- Option 4: Build and run manually
- A GitHub account with access to GitHub Codespaces
- Select Code and open in Codespace from GitHub
- After the codespaces has initialized, select to debug and run All Containers to run the sample locally
- Docker (with docker-compose)
- VS Code with the remote containers extension installed
- Fork the sample repo
- Clone the repo:
git clone https://github.com/{username}/container-apps-store-api-microservice
- Open the cloned repo in VS Code
- Follow the prompt to open in a dev container
- Select the debug All Containers and run the sample locally
Any changes made to the project and checked into your GitHub repo will trigger a GitHub action to build and deploy
- VS Code with the recommended extensions installed
- Node.js
- Python 3.x
- Go
- Dapr
- Azure CLI
- Azure Container Apps CLI extension
- Fork the sample repo
- Clone the repo:
git clone https://github.com/{username}/container-apps-store-api-microservice
- Open the cloned repo in VS Code
- Follow the prompt to install recommended extensions
- Select the debug All Containers and run the sample locally
Any changes made to the project and checked into your GitHub repo will trigger a GitHub action to build and deploy
- Fork the sample repo
- Clone the repo:
git clone https://github.com/{username}/container-apps-store-api-microservice
- Build the sample:
cd node-service
npm install
cd ../go-service
go install
cd ../python-service
pip install -r requirements.txt
cd ..
- Run the sample
Dapr will be used to start microservices and enable APIs for things like service discovery, state management, and observability. The code for store-api
service invokes other services at the localhost:daprport host address, and sets the dapr-app-id
HTTP header to enable service discovery using an HTTP proxy feature.
Run the node-app
(store-api) service in a new terminal window:
dapr run --app-id node-app --app-port 3000 --dapr-http-port 3501 --components-path ./components -- npm run start
Run the python-app
(order) service in a new terminal window:
dapr run --app-id python-app --app-port 5000 --dapr-http-port 3500 --components-path . -- python3 app.py
Run the go-app
(inventory) service in a new terminal window:
dapr run --app-id go-app --app-port 8050 --dapr-http-port 3502 -- go run .
State management
: orders app calls the Dapr State Store APIs which are bound to a Redis container that is preinstalled with Dapr. When the application is later deployed to Azure Container Apps, the component config yaml will be modified to point to an Azure CosmosDb instance. No code changes will be needed since the Dapr State Store API is completely portable.
Observability
: distributed tracing is enabled by default on (http://localhost:9411/). Browse to this URL to inspect any distributed trace or to inspect dependencies in real time. When the application is deployed to Azure we recommend modifying the component config YAML to enable Open Telemetry and Application Insights.
Tye is a new tool that makes it easy to run multiple microservices, observe in a dashboard, and tail the logs. This is an alternative to manually doing the three dapr run
commands above. This step requires a pre-requistite install of Tye from (https://aka.ms/tye).
To run all services using Tye simply:
tye run
Once the microservices are started by Tye you can observe in the Tye dashboard. The Tye dashboard will be listed in the standard output, and typically this is available at (http://localhost:8000). In the dashboard you can view each microservice, endpoint, and view Logs.