Skip to main content

Developing and deploying a Python Application

In this tutorial we will look at all steps needed to crate, build and deploy a Python application to an Avassa system.

For more advanced Python use cases

Developing with Python

Virtual Environments for local development

For these types of projects you can use Pipenv to keep track of the Python dependencies. Pipenv creates Python virtual environments and can generate requirements.txt files, which are great when later building a container image.

To create a virtual environment for your project, run

pipenv install

This generates a Pipfile with dependencies that looks like: The Pipfile for this project looks like:

Pipfile
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]

[dev-packages]

[requires]
python_version = "3"
note

The use of Pipenv is optional.

Note on target platforms

Note that containers are built for the underlying platform Intel or ARM. You can also build multi-architecture images that contain both. For simplicity in this example we assume that you build your container on the same platform as your edge sites. The virtual demo sites in the Avassa trial electric-cinema and metrograph are Intel based so if you want to use them make sure you run this tutorial on an Intel platform.

Python code

And the main python file we will use for this demo below.

demo.py
import logging
import os
import time

logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)

app_version=os.environ.get("VERSION", "unknown version")
logger.info(f"Starting {app_version}")

while True:
logger.info("I'm still alive...")
time.sleep(10)
tip

It can be useful to have a parameter that is set during build (VERSION in this example) when troubleshooting CI/CD pipelines. By setting a build parameter it becomes trivial to verify you're running the correct version, once deployed.

Docker

Build container image

First, generate the requirements.txt file using pipenv

pipenv requirements > requirements.txt

The Dockerfile is really simple and is pretty much vanilla from the python container on dockerhub.

Dockerfile
FROM python:3-alpine

# Optional to be able to feed a version into the application
ARG VERSION
ENV VERSION=${VERSION}

WORKDIR /usr/src/app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY demo.py .

CMD [ "python", "./demo.py" ]

Publish container image

This assumes you are logged into a registry, in this case we will push to dockerhub

Note that we provide the VERSION argument, both into the docker build but also as a tag.

docker buildx build -t fredrikjanssonse/avassa-app-tutorial:v1.0 --build-arg VERSION=v1.0 --push .
note

If you get errors on authenticating check your ~/.docker/config.json

[+] Building 12.1s (12/12) FINISHED                                                        docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 303B 0.0s
=> [internal] load metadata for docker.io/library/python:3-alpine 0.7s
=> [auth] library/python:pull token for registry-1.docker.io 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/5] FROM docker.io/library/python:3-alpine@sha256:25a82f6f8b720a6a257d58e478a0a5517448006e010 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 64B 0.0s
=> CACHED [2/5] WORKDIR /usr/src/app 0.0s
=> CACHED [3/5] COPY requirements.txt ./ 0.0s
=> [4/5] RUN pip install --no-cache-dir -r requirements.txt 1.7s
=> [5/5] COPY demo.py . 0.1s
=> exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:d49a9376507f9ea271f58060b59e179bfa165b3d83d234bb3897758f01ae6a02 0.0s
=> => naming to docker.io/fredrikjanssonse/avassa-app-tutorial:v1.0 0.0s
=> pushing fredrikjanssonse/avassa-app-tutorial:v1.0 with docker 7.7s
=> => pushing layer 6f07ea4f0b74 2.9s
=> => pushing layer 8086c9cadf15 4.1s
=> => pushing layer 7831fdc9a96f 7.3s
=> => pushing layer b79f77b26250 7.3s
=> => pushing layer 508dfc87ccb1 7.3s
=> => pushing layer 4078a022c6e3 7.3s
=> => pushing layer f5403ef07884 7.3s
=> => pushing layer 4c9c2b9681ab 7.3s
=> => pushing layer d4fc045c9e3a 7.3s
tip

Make sure you change the tag (fredrikjanssonse/avassa-app-tutorial) to match your registry. Example for Gitlab: registry.gitlab.com/avassa-public/edge-ai/torchserve:v2.0

Testing the built application

docker run --rm --pull=always fredrikjanssonse/avassa-app-tutorial:v1.0
v1.0: Pulling from fredrikjanssonse/avassa-app-tutorial
Digest: sha256:d02f9f1bb6c73798dbbe5de1c0c3e51aa2cca5de3289d5791f1b11308b939192
Status: Image is up to date for fredrikjanssonse/avassa-app-tutorial:v1.0
INFO:__main__:Starting v1.0
INFO:__main__:I'm still alive
^CTraceback (most recent call last):
File "/usr/src/app/./demo.py", line 14, in <module>
time.sleep(30)
KeyboardInterrupt

Deploying

Setup supctl or copy and paste in the Control Tower UI.

First we create a very simple application specification

demo.app.yaml
name: demo
# During development I keep version commented out
# otherwise I have to change the version every time I test a new app spec.
# Once out of the development phase, I always set a version.
# version: "1.0"
services:
- name: demo-svc
mode: replicated
replicas: 1
containers:
- name: demo
image: registry-1.docker.io/fredrikjanssonse/avassa-app-tutorial:v1.0

Load the application spec

supctl replace applications demo < demo.app.yaml

app edit

Load the deployment

demo.dep.yaml
name: demo
application: demo
placement:
all-sites: true
application-version: "*"
supctl replace application-deployments demo < demo.dep.yaml

Once deployed, you should see something like this in Control Tower. app deployed