Python Web Apps Deployen
Inleiding
In alle lessen ontwikkelden en gebruikten we onze Python web applicaties volledig lokaal. Op een bepaald moment wil je natuurlijk die applicatie ook publiek toegankelijk maken en delen met de wereld.
We verlaten hier het domein van (Python) software ontwikkeling en betreden dat van systeembeheer, infrastructuur en DevOps. Dit is zeer uitgebreid. Zo kan je bijvoorbeeld …
- Thuis een server installeren en toegankelijke maken vanaf je Internet router (selfhosting)
- Een virtueel systeem huren bij een cloud provider (AWS, Digital Ocean, OVH, …)
- Een eigen domeinnaam registreren en DNS beheren
- Een reverse webproxy (nginx, Caddy) configureren met TLS certificates (HTTPS)
- Met GitHub/GitLab een CI/CD pipeline opzetten die je web project deployt
- Een database (PostgreSQL) installeren en configureren
- Een deel van deze zaken uitbesteden aan een cloud service (bvb database)
- Vrijwel alles uitbesteden aan een zogenaamd app hosting platform
Genoeg om een volledige opleiding mee te vullen dus. Daarom zullen we ons hier beperken tot de meeste toegankelijke optie, een app hosting platform. Ook wel gekend als Platform-as-a-Service of PaaS.
Met zo een platform wordt vrijwel alle complexiteit van de infrastructuur (servers, besturingssystemen, netwerk), security (patching, secrets, credentials, TLS) en aanvullende services (PostgreSQL database, logging, monitoring, …) overgenomen door het platform. Je werkt dan op een hoger abstractieniveau waarbij je op een eenvoudige manier definieert hoe je applicatie is samengesteld en het platform zorgt voor de rest.
Flask-tutorial project aanpassen
Als voorbeeld zullen we het bestaande flask-tutorial project deployen.
Op de railway branch staan een aantal kleine aanpassingen om het deployen via Render of Railway te vereenvoudigen:
gunicornpackage toevoegen, een productie webserver voor Python web apps als Flask- Een eenvoudige
main.pyvoor gebruik met gunicorn - Een lege SQLite database om mee te starten
Render
Eerste Service
Een eerste optie is Render. Dit is een heel fijne optie om mee te beginnen experimenteren omdat er een volledig gratis eerste prijs-niveau wordt aangeboden (uiteraard met een aantal belangrijke beperkingen)
Klik rechtsboven op Get Started. Gebruik bij voorkeur GitHub als authenticatie provider. Er wordt later toch al gekoppeld met GitHub om toegang te krijgen tot je project repository.
Bij het configureren van de eerste webservice zijn volledige velden belangrijk:
- Repository: gebruik je eigen
flask-tutorialrepo - Branch: kies de branch die je hebt voorbereid, bvb
railway - Build Command:
uv sync --frozen && uv cache prune --ci(default) - Start Command:
uv run gunicorn --bind 0.0.0.0:${PORT:-8000} main:app
De belangrijkste beperking bij het kosteloos prijsniveau van Render is dat een inactieve (geen requests) deployment opnieuw wordt verwijderd. De volgende keer dat je die service bezoekt wordt er wel opnieuw automatisch gedeployed. Daardoor kan het wel tot een minuut duren voordat je service opnieuw toegankelijk is.
PostgreSQL Database Toevoegen
Met slechts enkele klikken kan je in Render een PostgreSQL database toevoegen aan je omgeving.
- New Service ➡️ Postgres
- Database en User kan je instellen (bvb
flaskr) om gewoon als randomly generated laten - Instance Type: Free
Eenmaal aangemaakt krijg je toegang tot de interne en externe connection details. Je krijgt zelfs een kant-en-klaar psql commando om in te loggen op je database.
De juiste DATABASE_URL voor SQLAlchemy kunnen we zo meteen eenvoudig beschikbaar maken in de applicatie vie een environment variable. Om daar gebruik van te maken is een kleine aanpassing nodig in de SQLAlchemy versie van ons flask-tutorial project. Tegelijk zorgen we er ook voor dat de database bij het opstarten van de applicatie wordt geïnitialiseerd.
https://github.com/dvx76/flask-tutorial/commit/19692eb9bc6cb22d246ae8222e4dca596e235de9
flaskr/__init__.py
import os
from typing import Any, Mapping, Optional
from flask import Flask
from . import auth, blog, db
def create_app(test_config: Optional[Mapping[str, Any]] = None) -> Flask:
app = Flask(__name__)
app.config.from_object("flaskr.settings")
app.config.from_envvar("FLASKR_SETTINGS", silent=True)
if test_config:
app.config.from_mapping(test_config)
app.jinja_options["autoescape"] = True
database_url = os.getenv("DATABASE_URL") or app.config["DATABASE_URL"]
db.init_db(database_url)
db_session, remove_session = db.create_db_session(database_url)
app.config["DB_SESSION"] = db_session
app.teardown_appcontext(remove_session)
app.register_blueprint(auth.bp)
app.register_blueprint(blog.bp)
return appIn Render kan je nu een tweede Web Service toevoegen met bijvoorbeeld de naam flask-tutorial-pg die gebruik maakt van het project/branch waarop bovenstaande code is gecommit (bijvoorbeeld render-sqlalchemy).
Eenmaal aangemaakt kan je in de Web Service configuratie onder Manage ➡️ Environment een DATABASE_URL variable aanmaken. I.p.v. gewoon Add Variable kies je voor Datastore URL. Daar kan je de PostgreSQL database selecteren. Op die manier zal DATABASE_URL altijd de correcte waarde hebben - bijvoorbeeld ook als het password van de database wordt geroteerd!
De belangrijkste beperking bij het kosteloos prijsniveau van Render is dat je maar één PostgreSQL database kan hebben en dat deze na 30 dagen niet meer toegankelijk zal zijn. Om opnieuw toegang te krijgen moet je upgraden naar een betalend account. Je kan de database natuurlijk wel verwijderen en een nieuwe aanmaken.
Railway
Railway is een heel gelijkaardig platform. In tegenstelling tot Render bestaat er geen gratis prijsniveau, maar er is wel een 30-dagen trial optie.
Net zoals bij Render is het handig om the authentificeren via GitHub. Eenmaal gelinkt kan je ook hier een web service deployen vanaf een GitHub repo+branch.
Een Eigen Server
Wil je toch experimenteren met een eigen server, dan zijn volgende tutorials uit Corey Schafer’s FastAPI reeks aan te raden: