Create new virtual environment
python3.10 -m venv .venv
Associate venv in VS Code
Create requirements.txt
flask
mongita
requests
Install requirements
$ pip install -r requirements.txt
Add app.py
import datetime
import uuid
from flask import Flask, redirect, render_template, request, url_for
from mongita import MongitaClientDisk
import requests
app = Flask(__name__)
client = MongitaClientDisk()
portfolio = client.portfolio
investments = portfolio.investments
@app.route("/")
@app.route("/<coin_id>")
def home(coin_id=None):
if coin_id is None:
all_investments = investments.find({})
else:
all_investments = investments.find({"coin_id": coin_id})
return render_template("index.html", all_investments=all_investments)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
Create templates folder
$ mkdir templates
Create templates/index.html
<html>
<body>
<a href="/new">New</a>
<a href="/">Show All Investments</a>
<ul>
{% for investment in all_investments %}
<li><a href="/{{investment.coin_id}}">{{ investment.coin_id }}</a> {{ investment.price }} {{ investment.currency}} {{ investment.timestamp }}</li>
{% endfor %}
</ul>
</body>
</html>
In app.py
@app.route("/new", methods=["GET", "POST"])
def add():
if request.method == "GET":
return render_template("new.html")
else:
coin_id = request.form["coin_id"]
currency = request.form["currency"]
data = requests.get(f"https://api.coingecko.com/api/v3/simple/price?ids={coin_id}&vs_currencies={currency}"). json()
new_coin = {
"id": str(uuid.uuid4()),
"coin_id": coin_id,
"currency": currency,
"price": data[coin_id][currency],
"timestamp": datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
}
investments.insert_one(new_coin)
return redirect(url_for("home"))
Create templates/new.html
<html>
<body>
<form method="post">
<div>
<label for="coin_id">Coin ID</label>
<input type="text" name="coin_id" id="coin_id">
</div>
<div>
<label for="currency">Currency</label>
<input type="text" name="currency" id="currency">
</div>
<input type="submit" value="Go">
</form>
</body>
</html>
Run the application
$ python app.py
Create Dockerfile
FROM python:3.10-alpine
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . /app/
ENTRYPOINT [ "python3" ]
CMD [ "app.py" ]
Build container image
$ docker build -t mempy-mar23:v1 .
Start new container
docker run -d -p 8000:8000 mempy-mar23:v1
Create a resource group named mempy-mar23-rg
Create an Azure Container Registry
-
Resource group:
mempy-mar23-rg
-
Name:
mempymar23registry
-
SKU:
Basic
Login to the registry
az acr login --name mempymar23registry
Tag the image
docker tag mempy-mar23:v1 mempymar23registry.azurecr.io/mempy-mar23:v1
Push the image to ACR
docker push mempymar23registry.azurecr.io/mempy-mar23:v1
Go to ACR in portal
-
Repositories
- Look for mempy-mar23:v1
-
Access Keys
- Set Admin user to Enabled
Create new Azure Container App
-
Resource Group:
mempy-mar23-rg
-
Container app name:
mempy-mar23-container-app
-
Region:
eastus
Create new Container Apps Environment
- Name:
mempy-mar23-container-env
App Settings tab
-
Uncheck Use quickstart image
-
Image source:
Azure Container Registry
-
Registry:
mempymar23registry.azurecr.io
-
Image:
mempy-mar23
-
Image tag:
v1
-
Ingress: Check Enabled
-
Ingress traffic: Accepting traffic from anywhere
-
Ingress type: HTTP
-
Target port:
8000
Review and create
Overview tab
Goto url
Add Cosmos DB
Create new Cosmos DB Account
Use NoSQL API
-
Resource group:
mempy-mar23-rg
-
Account name:
mempy-mar23-cdb
-
Location:
eastus
-
Capcity mode: Serverless
Review and create
In requirements.txt
azure-cosmos
Install dependencies
$ pip install -r requirements.txt
In app.py
from azure.cosmos import CosmosClient
# ...
COSMOS_KEY=""
COSMOS_ENDPOINT=""
client = CosmosClient(url=COSMOS_ENDPOINT, credential=COSMOS_KEY)
database = client.get_database_client("mempy-mar23-portfolio")
container = database.get_container_client("investments")
# Remove mongita setup
if coin_id is None:
all_investments = list(container.read_all_items())
else:
query = "SELECT * FROM i WHERE i.coin_id=@coin_id"
parameters = [
{"name": "@coin_id", "value": coin_id}
]
all_investments = list(container.query_items(query=query, parameters=parameters, enable_cross_partition_query=True))
container.create_item(new_coin)
Goto Cosmos DB account page
-
Data Explorer
-
New Container
-
Database id:
mempy-mar23-portfolio
-
Container id:
investments
-
Partition key:
/id
-
-
Keys
- Copy and past URI and Primary Key in
app.py
constantsCOSMOS_ENDPOINT
andCOSMOS_KEY
- Copy and past URI and Primary Key in
Run app
Goto Container App page
-
Identity
-
Set Status to On
Create Azure Key Vault
-
Resource group:
mempy-mar23-rg
-
Key vault name:
mempy-mar23-vault
-
Region:
eastus
-
Pricing tier:
Standard
-
Access Policy Tab:
-
Create
-
Select Secret Management template
-
Search for container app principal
-
Review and create
-
-
Review and create
Add secrets
Goto secrets tab
Generate/Import
Upload options: Manual
-
mempy-cosmos-endpoint
-
mempy-cosmos-key
Goto container app page
-
Containers
-
Edit and deploy
-
Select container
-
Add environment variables (Manual entry)
-
KEY_VAULT_NAME
mempy-mar23-vault
-
COSMOS_ENDPOINT_SECRET_NAME
mempy-cosmos-endpoint
-
COSMOS_KEY_SECRET_NAME
mempy-cosmos-key
-
-
-
In requirements.txt
azure-identity
azure-keyvault-secrets
Install dependencies
$ pip install -r requirements.txt
In app.py
import os
...
from azure.keyvault.secrets import SecretClient
from azure.identity import DefaultAzureCredential
key_vault_name = os.environ["KEY_VAULT_NAME"]
cosmos_key_secret_name = os.environ["COSMOS_KEY_SECRET_NAME"]
cosmos_key_endpoint_secret_name = os.environ["COSMOS_ENDPOINT_SECRET_NAME"]
key_vault_endpoint = f"https://{key_vault_name}.vault.azure.net"
credential = DefaultAzureCredential()
secret_client = SecretClient(vault_url=key_vault_endpoint, credential=credential)
cosmos_key_secret = secret_client.get_secret(cosmos_key_secret_name)
cosmos_endpoint_secret = secret_client.get_secret(cosmos_endpoint_secret_name)
COSMOS_KEY = cosmos_key_secret.value
COSMOS_ENDPOINT = cosmos_endpoint_secret.value
Rebuild image
Retag image as v2
Push image to ACR
Change container image version
Redeploy