Skip to content

Commit e660d7a

Browse files
UbuntuUbuntu
authored andcommitted
.
1 parent 287c0c3 commit e660d7a

60 files changed

Lines changed: 61645 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
# Azure Web App with Azure CosmosDB for MongoDB
2+
3+
This sample demonstrates a Python Flask single-page web application called *Vacation Planner* hosted on an [Azure Web App](https://learn.microsoft.com/en-us/azure/app-service/overview). The app runs on an Azure App Service Plan and stores activity data in the `activities` collection of the `sampledb` MongoDB database on an [Azure CosmosDB for MongoDB](https://learn.microsoft.com/en-us/azure/cosmos-db/mongodb/introduction) account.
4+
5+
## Architecture
6+
7+
The following diagram illustrates the architecture of the solution:
8+
9+
![Architecture Diagram](./images/architecture.png)
10+
11+
- **Azure Web App**: Hosts the Python Flask application
12+
- **Azure App Service Plan**: Provides compute resources for the web app
13+
- **Azure CosmosDB for MongoDB**: Stores activity data in a MongoDB collection
14+
15+
## Prerequisites
16+
17+
- [Azure Subscription](https://azure.microsoft.com/free/)
18+
- [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli)
19+
- [Python 3.11+](https://www.python.org/downloads/)
20+
- [Flask](https://flask.palletsprojects.com/)
21+
- [pymongo](https://pymongo.readthedocs.io/en/stable/)
22+
- [Bicep extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep), if you plan to install the sample via Bicep.
23+
- [Terraform](https://developer.hashicorp.com/terraform/downloads), if you plan to install the sample via Terraform.
24+
25+
## Deployment
26+
27+
Set up the Azure emulator using the LocalStack for Azure Docker image. Before starting, ensure you have a valid `LOCALSTACK_AUTH_TOKEN` to access the Azure emulator. Refer to the [Auth Token guide](https://docs.localstack.cloud/getting-started/auth-token/?__hstc=108988063.8aad2b1a7229945859f4d9b9bb71e05d.1743148429561.1758793541854.1758810151462.32&__hssc=108988063.3.1758810151462&__hsfp=3945774529) to obtain your Auth Token and set it in the `LOCALSTACK_AUTH_TOKEN` environment variable. The Azure Docker image is available on the [LocalStack Docker Hub](https://hub.docker.com/r/localstack/localstack-azure-alpha). To pull the image, execute:
28+
29+
```bash
30+
docker pull localstack/localstack-azure-alpha
31+
```
32+
33+
Start the LocalStack Azure emulator by running:
34+
35+
```bash
36+
export LOCALSTACK_AUTH_TOKEN=<your_auth_token>
37+
IMAGE_NAME=localstack/localstack-azure-alpha localstack start
38+
```
39+
40+
Deploy the application to LocalStack for Azure using one of these methods:
41+
42+
- [Azure CLI Deployment](./scripts/README.md)
43+
- [Bicep Deployment](./bicep/README.md)
44+
- [Terraform Deployment](./terraform/README.md)
45+
46+
All deployment methods have been fully tested against Azure and the LocalStack for Azure local emulator.
47+
48+
> **Note**
49+
> When you deploy the application to LocalStack for Azure for the first time, the initialization process involves downloading and building Docker images. This is a one-time operation—subsequent deployments will be significantly faster. Depending on your internet connection and system resources, this initial setup may take several minutes.
50+
51+
## Test
52+
53+
1. Retrieve the port published and mapped to port 80 by the Docker container hosting the emulated Web App.
54+
2. Open a web browser and navigate to `http://localhost:<published-port>`.
55+
3. If the deployment was successful, you will see the following user interface for adding and removing activities:
56+
57+
![Architecture Diagram](./images/vacation-planner.png)
58+
59+
You can use the `call-web-app.sh` Bash script below to call the web app. The script demonstrates three methods for calling web apps:
60+
61+
1. **Through the LocalStack for Azure emulator**: Call the web app via the emulator using its default host name. The emulator acts as a proxy to the web app.
62+
2. **Via localhost and host port mapped to the container's port**: Use `127.0.0.1` with the host port mapped to the container's port `80`.
63+
3. **Via container IP address**: Use the app container's IP address on port `80`. This technique is only available when accessing the web app from the Docker host machine.
64+
4. **Via Runtime Gateway**: Use the `{web_app_name}website.localhost.localstack.cloud:4566` URL to call the web app via the LocalStack runtime gateway.
65+
66+
```bash
67+
#!/bin/bash
68+
69+
get_docker_container_name_by_prefix() {
70+
local app_prefix="$1"
71+
local container_name
72+
73+
# Check if Docker is running
74+
if ! docker info >/dev/null 2>&1; then
75+
echo "Error: Docker is not running" >&2
76+
return 1
77+
fi
78+
79+
echo "Looking for containers with names starting with [$app_prefix]..." >&2
80+
81+
# Find the container using grep
82+
container_name=$(docker ps --format "{{.Names}}" | grep "^${app_prefix}" | head -1)
83+
84+
if [ -z "$container_name" ]; then
85+
echo "Error: No running container found with name starting with [$app_prefix]" >&2
86+
return 1
87+
fi
88+
89+
echo "Found matching container [$container_name]" >&2
90+
echo "$container_name"
91+
}
92+
93+
get_docker_container_ip_address_by_name() {
94+
local container_name="$1"
95+
local ip_address
96+
97+
if [ -z "$container_name" ]; then
98+
echo "Error: Container name is required" >&2
99+
return 1
100+
fi
101+
102+
# Get IP address
103+
ip_address=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_name")
104+
105+
if [ -z "$ip_address" ]; then
106+
echo "Error: Container [$container_name] has no IP address assigned" >&2
107+
return 1
108+
fi
109+
110+
echo "$ip_address"
111+
}
112+
113+
get_docker_container_port_mapping() {
114+
local container_name="$1"
115+
local container_port="$2"
116+
local host_port
117+
118+
if [ -z "$container_name" ] || [ -z "$container_port" ]; then
119+
echo "Error: Container name and container port are required" >&2
120+
return 1
121+
fi
122+
123+
# Get host port mapping
124+
host_port=$(docker inspect -f "{{(index (index .NetworkSettings.Ports \"${container_port}/tcp\") 0).HostPort}}" "$container_name")
125+
126+
if [ -z "$host_port" ]; then
127+
echo "Error: No host port mapping found for container [$container_name] port [$container_port]" >&2
128+
return 1
129+
fi
130+
131+
echo "$host_port"
132+
}
133+
134+
call_web_app() {
135+
# Get the web app name
136+
echo "Getting web app name..."
137+
web_app_name=$(azlocal webapp list --query '[0].name' --output tsv)
138+
139+
if [ -n "$web_app_name" ]; then
140+
echo "Web app [$web_app_name] successfully retrieved."
141+
else
142+
echo "Error: No web app found"
143+
exit 1
144+
fi
145+
146+
# Get the resource group name
147+
echo "Getting resource group name for web app [$web_app_name]..."
148+
resource_group_name=$(azlocal webapp list --query '[0].resourceGroup' --output tsv)
149+
150+
if [ -n "$resource_group_name" ]; then
151+
echo "Resource group [$resource_group_name] successfully retrieved."
152+
else
153+
echo "Error: No resource group found for web app [$web_app_name]"
154+
exit 1
155+
fi
156+
157+
# Get the the default host name of the web app
158+
echo "Getting the default host name of the web app [$web_app_name]..."
159+
app_host_name=$(azlocal webapp show \
160+
--name "$web_app_name" \
161+
--resource-group "$resource_group_name" \
162+
--query 'defaultHostName' \
163+
--output tsv)
164+
165+
if [ -n "$app_host_name" ]; then
166+
echo "Web app default host name [$app_host_name] successfully retrieved."
167+
else
168+
echo "Error: No web app default host name found"
169+
exit 1
170+
fi
171+
172+
# Get the Docker container name
173+
echo "Finding container name with prefix [ls-$web_app_name]..."
174+
container_name=$(get_docker_container_name_by_prefix "ls-$web_app_name")
175+
176+
if [ $? -eq 0 ] && [ -n "$container_name" ]; then
177+
echo "Container [$container_name] found successfully"
178+
else
179+
echo "Failed to get container name"
180+
exit 1
181+
fi
182+
183+
# Get the container IP address
184+
echo "Getting IP address for container [$container_name]..."
185+
container_ip=$(get_docker_container_ip_address_by_name "$container_name")
186+
187+
if [ $? -eq 0 ] && [ -n "$container_ip" ]; then
188+
echo "IP address [$container_ip] retrieved successfully for container [$container_name]"
189+
else
190+
echo "Failed to get container IP address"
191+
exit 1
192+
fi
193+
194+
# Get the mapped host port for web app HTTP trigger (internal port 80)
195+
echo "Getting the host port mapped to internal port 80 in container [$container_name]..."
196+
host_port=$(get_docker_container_port_mapping "$container_name" "80")
197+
198+
if [ $? -eq 0 ] && [ -n "$host_port" ]; then
199+
echo "Mapped host port [$host_port] retrieved successfully for container [$container_name]"
200+
else
201+
echo "Failed to get mapped host port for container [$container_name]"
202+
exit 1
203+
fi
204+
205+
# Retrieve LocalStack proxy port
206+
proxy_port=$(curl http://localhost:4566/_localstack/proxy -s | jq '.proxy_port')
207+
208+
if [ -n "$proxy_port" ]; then
209+
# Call the web app via emulator proxy
210+
echo "Calling web app [$web_app_name] via emulator..."
211+
curl --proxy "http://localhost:$proxy_port/" -s "http://$app_host_name/" 1> /dev/null
212+
213+
if [ $? == 0 ]; then
214+
echo "Web app call via emulator proxy port [$proxy_port] succeeded."
215+
else
216+
echo "Web app call via emulator proxy port [$proxy_port] failed."
217+
fi
218+
else
219+
echo "Failed to retrieve LocalStack proxy port"
220+
fi
221+
222+
if [ -n "$container_ip" ]; then
223+
# Call the web app via the container IP address
224+
echo "Calling web app [$web_app_name] via container IP address [$container_ip]..."
225+
curl -s "http://$container_ip/" 1> /dev/null
226+
227+
if [ $? == 0 ]; then
228+
echo "Web app call via container IP address [$container_ip] succeeded."
229+
else
230+
echo "Web app call via container IP address [$container_ip] failed."
231+
fi
232+
else
233+
echo "Failed to retrieve container IP address"
234+
fi
235+
236+
if [ -n "$host_port" ]; then
237+
# Call the web app via the host port
238+
echo "Calling web app [$web_app_name] via host port [$host_port]..."
239+
curl -s "http://127.0.0.1:$host_port/" 1> /dev/null
240+
241+
if [ $? == 0 ]; then
242+
echo "Web app call via host port [$host_port] succeeded."
243+
else
244+
echo "Web app call via host port [$host_port] failed."
245+
fi
246+
else
247+
echo "Failed to retrieve host port"
248+
fi
249+
250+
gateway_port=4566
251+
252+
if [ -n "$gateway_port" ]; then
253+
# Call the web app via the runtime gateway
254+
echo "Calling web app [$web_app_name] via runtime gateway on port [$gateway_port]..."
255+
curl -s "http://${web_app_name}website.localhost.localstack.cloud:$gateway_port/" 1> /dev/null
256+
257+
if [ $? == 0 ]; then
258+
echo "Web app call via runtime gateway on port [$gateway_port] succeeded."
259+
else
260+
echo "Web app call via runtime gateway on port [$gateway_port] failed."
261+
fi
262+
else
263+
echo "Failed to retrieve runtime gateway port"
264+
fi
265+
}
266+
267+
call_web_app
268+
```
269+
270+
## MongoDB Tooling
271+
272+
You can utilize [MongoDB Compass](https://www.mongodb.com/try/download/compass) to explore and manage your MongoDB databases and collections. Ensure you connect using `mongodb://localhost:port` connection string, where `port` corresponds to the port published by the MongoDB container on the host and mapped to the internal MongoDB port `27017`.
273+
274+
![MongoDB Compass](./images/mongodb-compass.png)
275+
276+
Alternatively, you can use the [MongoDB Shell](https://www.mongodb.com/docs/mongodb-shell/) to interact with and administer your MongoDB instance, as shown in the following table:
277+
278+
```bash
279+
~$ mongosh mongodb://localhost:32770
280+
Current Mongosh Log ID: 6914588406320f60899dc29c
281+
Connecting to: mongodb://localhost:32770/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.5.9
282+
Using MongoDB: 8.0.15
283+
Using Mongosh: 2.5.9
284+
285+
For mongosh info see: https://www.mongodb.com/docs/mongodb-shell/
286+
287+
------
288+
The server generated these startup warnings when booting
289+
2025-11-12T09:28:07.726+00:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem
290+
2025-11-12T09:28:07.892+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
291+
2025-11-12T09:28:07.892+00:00: For customers running the current memory allocator, we suggest changing the contents of the following sysfsFile
292+
2025-11-12T09:28:07.892+00:00: We suggest setting the contents of sysfsFile to 0.
293+
2025-11-12T09:28:07.892+00:00: vm.max_map_count is too low
294+
2025-11-12T09:28:07.892+00:00: We suggest setting swappiness to 0 or 1, as swapping can cause performance problems.
295+
------
296+
297+
test> show dbs
298+
admin 100.00 KiB
299+
config 108.00 KiB
300+
local 40.00 KiB
301+
sampledb 180.00 KiB
302+
test> use sampledb
303+
switched to db sampledb
304+
sampledb> show collections
305+
activities
306+
sampledb> db.activities.find().pretty()
307+
[
308+
{
309+
_id: '39ab62c2aaa0015ed5309876053e4146',
310+
username: 'Paolo',
311+
activity: 'Go to Paris',
312+
timestamp: '2025-11-12T09:31:43.338268'
313+
},
314+
{
315+
_id: '4fb8f53442d3ebe9167245f9555bac51',
316+
username: 'Paolo',
317+
activity: 'Go to Madrid',
318+
timestamp: '2025-11-12T09:31:50.109456'
319+
},
320+
{
321+
_id: '84646160cb1db21a7083b4c5b6e2d9d0',
322+
username: 'Paolo',
323+
activity: 'Go to Rome',
324+
timestamp: '2025-11-12T09:32:21.781936'
325+
}
326+
]
327+
```
328+
329+
## References
330+
331+
- [Azure Web Apps Documentation](https://learn.microsoft.com/en-us/azure/app-service/)
332+
- [Azure CosmosDB for MongoDB API](https://learn.microsoft.com/en-us/azure/cosmos-db/mongodb/introduction)
333+
- [Quickstart: Python Flask on Azure](https://learn.microsoft.com/en-us/azure/app-service/quickstart-python?tabs=flask%2Cbrowser)
334+
- [Quickstart: CosmosDB for MongoDB](https://learn.microsoft.com/en-us/azure/cosmos-db/mongodb/quickstart?tabs=azure-portal)
335+
- [Azure Identity Client Library for Python](https://learn.microsoft.com/en-us/python/api/overview/azure/identity-readme?view=azure-python)
336+
- [LocalStack for Azure](https://azure.localstack.cloud/)
57.1 KB
Loading
96.7 KB
Loading
211 KB
Loading

0 commit comments

Comments
 (0)