Introductie
Docker is een open-source containerplatform. Het is een lichtgewicht, gevirtualiseerde, draagbare, softwaregedefinieerde gestandaardiseerde omgeving waarin de software geïsoleerd kan draaien van andere software die op de fysieke hostmachine draait. Docker biedt een lichtgewicht alternatief voor virtuele machines. Tegelijkertijd biedt het portabiliteit, prestaties, flexibiliteit en schaalbaarheid van applicaties. Voor een uitgebreide gids over het Docker-ecosysteem, neem een kijkje in ons gedetailleerde overzicht van containerisatie met Docker.
Flask is een open-source minimaal webframework gebouwd met Python. Enkele van de geweldige functies van Flask zijn dat het lichtgewicht, flexibel en zeer gestructureerd is. Bovendien heeft het geen specifieke tools of plug-ins nodig om te draaien.
De combinatie van Flask en Docker geeft je een lichtgewicht, flexibele en schaalbare applicatie. Je kunt deze op veel servers en infrastructuren implementeren, dankzij het draagbare karakter van ge-Dockeriseerde containers. De focus van deze handleiding is om je te laten zien hoe je een Flask-applicatie implementeert met Docker. We zullen ook demonstreren hoe je ervoor zorgt dat toekomstige updates van je applicatie van kracht worden.
Vereisten
Dit wordt een praktische handleiding, en je moet een omgeving creëren waarin je de stappen kunt volgen:
- Je moet beschikken over een installatie van Ubuntu 20.04 als je initiële besturingsomgeving. Je moet ook een non-root gebruiker met sudo-rechten.
- Daarnaast moet je Docker installeren. We hebben een handleiding over hoe je Docker installeert en bedient op Ubuntu. Volg stappen 1, 2, 3 en 4. Dit zou moeten werken voor elke Ubuntu-distributie.
- Ten slotte moet je Nginx geïnstalleerd hebben. Volg onze handleiding over het installeren van Nginx op Ubuntu.
Laten we nu beginnen!
Stap 1: Bereid de Flask-applicatie voor
We beginnen met het maken van een map die onze Flask-applicatie zal bevatten. Je kunt een mapnaam naar keuze selecteren. Voor deze handleiding noemen we deze echter flask_demo. We slaan de projectbestanden op in de /var/www map, wat meestal de map is waartoe Ubuntu standaard toegang verleent tot het openbare internet. Voer eerst de volgende commando's uit om de map aan te maken en er naartoe te navigeren:
|
1 2 3 |
sudo mkdir /var/www/flask_demo cd /var/www/flask_demo |
Binnen deze hoofdmap van ons project maken we de basismapstructuur van een Flask-applicatie. Voer vervolgens het volgende commando uit om de basisstructuur te maken, waarbij je de -p vlag toevoegt om gaandeweg alle bovenliggende mappen aan te maken:
|
1 |
sudo mkdir -p app/static app/templates |
De map app bevat alle bestanden die gerelateerd zijn aan een Flask-app, inclusief views en blueprints. Views bevatten de code die je schrijft om te reageren op verzoeken die je applicatie bereiken. Blueprints helpen bij het maken van applicatiecomponenten en ondersteunen veelvoorkomende patronen in Flask-applicaties.
De toepasselijk genaamde static map bevat statische bestanden zoals afbeeldingen, CSS- en JavaScript-bestanden. De templates map bevat alle HTML-sjablonen voor het project.
Nu kunnen we beginnen met het schrijven van de bestanden die nodig zijn om een Flask-applicatie te initialiseren. Begin met het maken van een bestand genaamd __init__.py in de map app om de Python interpreter te vertellen dat de map app als een pakket moet worden behandeld. Voer het volgende commando uit in je terminal om het bestand te openen met de nano-editor:
|
1 |
sudo nano app/__init__.py |
We gebruiken pakketten in Python om modules te groeperen in logische namespaces of hiërarchieën. Modularisatie maakt het mogelijk om code op te splitsen in individuele en beheersbare blokken die specifieke functies uitvoeren.
Hierna voeg je in het geopende bestand __init__.py in je editor de volgende code-snippet toe om de Flask-instantie te starten, en importeer je de logica uit de views.py die je in de volgende stappen gaat maken:
|
1 2 3 4 5 |
from flask import Flask app = Flask(__name__) from app import views |
Wanneer je klaar bent, druk op Ctrl + O en ENTER om het bestand op te slaan, en sluit het vervolgens met Ctrl + X. Laten we vervolgens de views.py aanmaken in de app directory. Het views.py bestand zal het grootste deel van de applicatielogica bevatten:
|
1 |
sudo nano app/views.py |
Voeg het volgende codefragment toe aan het bestand. Deze code toont een eenvoudige string om te laten zien dat je app actief is wanneer gebruikers je website bezoeken:
|
1 2 3 4 5 |
from app import app @app.route('/') def home(): return "Onze Flask-applicatie is actief!" |
In dit bestand beginnen we met het importeren van de Flask-app-instantie. Vervolgens moeten we een regel toevoegen om de route te definiëren: @app.route(/). De @app.route(/) regel wordt in Flask een decorator genoemd. Je kunt decorators gebruiken om extra functionaliteiten in een of meer functies te injecteren. In dit geval geven we een aanroep naar de route / door aan de home-functie. Wanneer een gebruiker deze route bezoekt, ziet hij de tekst: "Onze Flask-applicatie is actief!".
Vervolgens maak je het bestand uwsgi.ini aan om de uWSGI-configuraties voor de applicatie te bevatten. uWSGI is een implementatieoptie voor Nginx die dient als een protocol en een applicatieserver. Voer de volgende opdracht uit om het bestand in de hoofdmap van het project aan te maken met de nano-editor:
|
1 |
sudo nano uwsgi.ini |
Voeg in het geopende bestand het volgende codefragment toe:
|
1 2 3 4 |
[uwsgi] module = main callable = app master = true |
Dit bestand bevat enkele richtlijnen. We definiëren hun doel hieronder:
- module – definieert de module van waaruit de Flask-applicatie wordt geserveerd. We hebben de module ingesteld als main, verwijzend naar het main.py bestand in de hoofdmap. We zullen dit bestand in de volgende stap aanmaken.
- callable – instrueert uWSGI om de app instantie te gebruiken die vanuit de applicatie is geëxporteerd.
- master – zorgt ervoor dat de applicatie blijft draaien om downtime te minimaliseren tijdens het herladen van de gehele applicatie.
Sla het bestand op en sluit het wanneer je klaar bent.
Nu kun je het bestand main.py aanmaken om het toegangspunt tot je applicatie te bepalen. uWSGI zal dit bestand lezen om te weten hoe het met de applicatie moet communiceren. Voer de volgende opdracht uit om het bestand main.py aan te maken met nano in de root directory van je project:
|
1 |
sudo nano main.py |
Voeg in het bestand de volgende regel toe die de Flask-instantie importeert die in het applicatiepakket is gemaakt:
|
1 |
from app import app |
Het laatste wat je in deze stap doet, is het definiëren van de afhankelijkheden die nodig zijn om de applicatie uit te voeren. We zullen deze afhankelijkheden definiëren in een bestand genaamd dependencies.txt. Wanneer Docker de image van je applicatie bouwt, zal het een pip (pakket beheerder) opdracht uitvoeren om de afhankelijkheden te installeren. Open het bestand in de hoofdmap met de volgende opdracht:
|
1 |
sudo nano dependencies.txt |
Tot dit punt in ons project willen we slechts één afhankelijkheid: Flask. Daarom kunnen we de volgende regel toevoegen om te verwijzen naar de juiste versie van Flask die we voor ons project willen:
|
1 |
Flask==2.0.1 |
We kiezen voor Flask versie 2.0.1 als de afhankelijkheid. Dit is de nieuwste versie op het moment van schrijven van deze handleiding. Je kunt meer informatie vinden over de verschillende versies op de pagina Flask Changes. Daarmee is de installatie van de Flask-applicatie voltooid. Laten we nu de Docker-configuraties voorbereiden voor implementatie.
Stap 2: Docker configureren
Om een Docker-implementatie op te zetten, maken we twee bestanden aan, Dockerfile en start.sh. De Dockerfile bevat declaratieve regels die een Docker-image vormen. De start.sh is een eenvoudig shellscript om de image te bouwen en de container te starten vanaf de Dockerfile. Voer in de hoofdmap van het project de volgende opdracht uit om de Dockerfile:
|
1 |
sudo nano Dockerfile |
Dit bestand bevat de benodigde configuraties voor een Docker-image. Voeg vervolgens het volgende codefragment toe om de afhankelijkheden te specificeren en hoe de image moet worden gebouwd:
|
1 2 3 4 5 6 7 8 9 10 11 |
FROM tiangolo/uwsgi-nginx-flask:python3.6-alpine3.7 RUN apk --update add bash nano git ENV STATIC_URL /static ENV STATIC_PATH /var/www/app/static COPY ./dependencies.txt /var/www/dependencies.txt RUN pip install -r /var/www/dependencies.txt |
De eerste regel in een Dockerfile definieert de basis-image van waaruit we onze image bouwen. In dit geval bouwen we op basis van de tiangolo/uwsgi-nginx-flask, beschikbaar via DockerHub. We hebben specifiek voor deze image gekozen omdat deze veel Python-versies ondersteunt.
We geven ook aan dat we de image willen bijwerken. Vervolgens moeten we de bash commando processo , de nano tekst editor, en de git client voor het pullen en pushen van broncode uit versiebeheersystemen zoals GitHub, Bitbucket, of Gitlab. De regels met ENV specificeren omgevingsvariabelen die in de container worden gebruikt.
Het COPY-commando kopieert de afhankelijkheden naar de container. Het RUN-commando roept de pip pakket beheerder aan om het dependencies.txt-bestand te analyseren en de afhankelijkheden te installeren. Sla het bestand op en sluit het wanneer u klaar bent met bewerken.
Vervolgens maakt u het start.sh-script. Dit script bevat Docker-commando's om de image te bouwen en te runnen . Hoewel u deze commando's stapsgewijs in de terminal kunt uitvoeren, vonden we het overzichtelijker om ze aan een shellscript toe te voegen en dit met één commando vanuit de terminal aan te roepen.
Voordat we de inhoud van dit bestand kunnen definiëren, moeten we eerst een vrije poort bepalen die niet door andere services wordt gebruikt. We gebruiken poort 45644. U kunt echter een andere poort kiezen. Voer de volgende regel uit om te controleren of de poort vrij is:
|
1 |
sudo nc localhost 45644 < /dev/null; echo $? |
Afhankelijk van de gekozen poort, als de uitvoer van het bovenstaande commando 1 is, dan is deze vrij. Anders moet u mogelijk een andere poort kiezen en het commando opnieuw proberen:

Nu we een vrije poort hebben vastgesteld, kunnen we het bestand met nano maken in de hoofdmap van het project door het volgende commando uit te voeren:
|
1 |
sudo nano start.sh |
Voeg het volgende codefragment toe aan dit bestand:
|
1 2 3 4 5 6 7 |
#!/bin/bash app_name="docker-flask-demo" docker build -t ${app_name} . docker run -d -p 45644:80 --name=${app_name} -v $PWD:/app ${app_name} |
De eerste regel, ook wel shebang genoemd, geeft aan dat dit een bash-bestand is en als commando's moet worden uitgevoerd. De tweede regel declareert een variabele genaamd app_name. We gebruiken deze variabele om de image- en containernamen in te stellen. De derde regel instrueert Docker om de image te bouwen op basis van de Dockerfile definitie in de huidige map. De image krijgt de naam docker-flask-demo volgens de variabele.
De laatste regel maakt een container genaamd docker-flask-demo volgens de variabele die we hebben gedefinieerd. De -d-vlag zorgt ervoor dat de container op de achtergrond blijft draaien in een losgekoppelde (detached) status nadat het commando is uitgevoerd. De -p-vlag koppelt een poort op de server aan een specifieke poort op de container. In dit geval koppelen we poort 45644 op de hostmachine aan poort 80 die Docker in de container zal blootstellen.
We gebruiken de -v-vlag om een Docker-volume te mounten op de container. De $PWD-variabele is een standaard Linux-variabele die het pad bevat naar de huidige map waarin u zich op een bepaald moment bevindt:

In ons geval mounten we de volledige projectmap aan de /var/www-map van de container. De Docker-configuratie is nu gereed. U kunt de image bouwen en de container starten op basis van de gebouwde image door het volgende commando uit te voeren:
|
1 |
sudo bash start.sh |
Wacht tot het script klaar is met uitvoeren en voer vervolgens het volgende Docker-commando uit om alle actieve containers op te sommen:
|
1 |
sudo docker ps |
De uitvoer toont de actieve containers:

Je zou onze container moeten zien met de naam docker-flask-demo in de lijst met actieve containers. Zoek het openbare van je serverIP en open dit in je browser op de opgegeven poort: http://your-server-public-ip:45644.
Je zou een vergelijkbare uitvoer moeten zien:

Als je het bovenstaande in je browser ziet, heb je met succes een Flask-applicatie geïmplementeerd. Vervolgens gaan we bestanden aanpassen en inhoud aan gebruikers aanbieden via templates.
Stap 3: Inhoud aanbieden via templatebestanden
In Flask worden templates gebruikt om statische en dynamische inhoud aan websitebezoekers te tonen. We laten je zien hoe je een HTML template maakt en deze aanbiedt aan je gebruikers wanneer ze een bepaalde route bezoeken. Dit kan bijvoorbeeld een Home-pagina of een Over-pagina zijn.
Voer het volgende commando uit in je terminal om een index.html bestand te maken in de app/templates map:
|
1 |
sudo nano app/templates/index.html |
Voeg vervolgens het volgende codefragment toe aan het bestand:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
<!DOCTYPE html> <html lang="nl"> <head> <meta charset="UTF-8"> <title>Flask Demo</title> </head> <body> <h2>Je bent thuis</h2> <p>Welkom op de Flask met Docker Demo pagina</p> </body> </html> |
Sla het bestand op en sluit het wanneer je klaar bent. Maak ook een andere pagina, laten we deze de Over-pagina noemen, met het volgende commando:
|
1 |
sudo nano app/templates/about.html |
Voeg het volgende codefragment toe aan het bestand:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<!DOCTYPE html> <html lang="nl"> <head> <meta charset="UTF-8"> <title>Over Flask Demo</title> </head> <body> <h2>Over-pagina</h2> <p>Dit was een demo-project. Het toont hoe je een Flask- app bouwt met Docker en Nginx.</p> <p>Je kunt zoveel pagina's en bestanden toevoegen als je maar wilt</p> </body> </html> |
Sla het bestand op en sluit het wanneer je klaar bent. Pas vervolgens het app/views.py bestand aan om naar de templates en de routes voor de daadwerkelijke pagina's te verwijzen:
|
1 |
sudo nano app/views.py |
Pas het bestand aan zodat het er als volgt uitziet:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
from flask import render_template from app import app @app.route('/') def home(): return "Onze Flask-applicatie is actief!" @app.route('/index') def index(): return render_template('index.html') @app.route('/about') def about(): return render_template('about.html') |
Sla het bestand op en sluit het wanneer u klaar bent. De wijzigingen die u hebt aangebracht, worden pas van kracht nadat u de container stopt en opnieuw opstart. Voer de volgende Docker-opdrachten uit om de container te stoppen en te starten. Let op de containernaam zoals we die eerder hebben gedefinieerd:
|
1 |
sudo docker stop docker-flask-demo && sudo docker start docker-flask-demo |
Zodra de container actief is, bezoekt u de Home-pagina en de About-pagina om een deel van de nieuwe inhoud te bekijken:
|
1 |
Home pagina: http://your-server-public-ip:45644/index |

|
1 |
Over pagina: http://your-server-public-ip:45644/about |

Tot nu toe hebt u een Flask-applicatie gemaakt die inhoud kan leveren aan uw websitebezoekers. Hier is de bestandsstructuur voor het project:

U hebt waarschijnlijk gemerkt dat we de Docker-container moesten herstarten om nieuwe wijzigingen door te voeren. In de volgende stap gaan we dit automatiseren om minder downtime te garanderen.
Stap 4: Updates van applicatiebestanden configureren om automatisch opnieuw te laden
Regelmatig brengen we wijzigingen aan in een applicatie om de logica of gebruikersinterfaces te verbeteren of om enkele afhankelijkheden toe te voegen. Om dergelijke wijzigingen van kracht te laten worden, kan het nodig zijn om de Docker-container opnieuw op te starten. Gelukkig uWSGI heeft een functie genaamd touch-reload voor het opnieuw laden van een Python-script zonder de container opnieuw op te starten.
Standaard heeft Python een auto-reloading-functie die het hele bestandssysteem controleert op wijzigingen en de applicatie vernieuwt wanneer er een wijziging optreedt. Hoewel automatisch herladen goed is voor het minimaliseren van downtime, kan het veel resources verbruiken. Daarom wordt het niet aanbevolen voor productieomgevingen.
Laten we eens kijken hoe u touch-reload kunt gebruiken om te controleren op wijzigingen in een specifiek bestand en de applicatie opnieuw te laden wanneer er wijzigingen zijn. Pas het uwsgi.ini-bestand aan met de nano-editor:
|
1 |
sudo nano uwsgi.ini |
Voeg de gemarkeerde regel toe zodat deze er als volgt uitziet:
|
1 2 3 4 5 |
[uwsgi] module = main callable = app master = true touch-reload = /app/uwsgi.ini |
Sla het bestand op en sluit het wanneer u klaar bent. De toegevoegde regel specificeert een bestand dat zal worden gewijzigd om het opnieuw laden van de applicatie te activeren. Om deze voorwaarde echter te activeren voor toekomstige wijzigingen, moet u eerst de container opnieuw opstarten:
|
1 |
sudo docker stop docker-flask-demo && sudo docker start docker-flask-demo |
U kunt nu het app/views.py-bestand wijzigen om te demonstreren hoe automatisch herladen werkt:
|
1 |
sudo nano app/views.py |
Wijzig de string die door de home-functie wordt geretourneerd zoals gemarkeerd:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
from flask import render_template from app import app @app.route('/') def home(): return "<h3>Enkele wijzigingen in onze Flask-applicatie om automatisch opnieuw te laden!</h3>" @app.route('/index') def index(): return render_template('index.html') @app.route('/about') def about(): return render_template('about.html') |
Sla het bestand op en sluit het zodra u klaar bent.
Open de startpagina van uw applicatie in de browser: http://your-server-public-ip:45644.
U zult nog geen wijzigingen zien. Dit komt omdat de touch-reload-voorwaarde een wijziging in het uwsgi.ini-bestand detecteert. U kunt touch gebruiken om de voorwaarde te activeren, waardoor de hele applicatie opnieuw wordt geladen met de volgende opdracht:
|
1 |
sudo touch uwsgi.ini |
Als u nu de startpagina herlaadt, ziet u de nieuwe wijzigingen:

Als u in de toekomst wijzigingen aanbrengt, hoeft u alleen de opdracht sudo touch uwsgi.ini en de volledige applicatie zal herladen met minder downtime. Dat brengt ons aan het einde van deze tutorial.
Conclusie
In deze tutorial heb je een Flask-applicatie geïmplementeerd en uitgerold met Docker-images en -containers. Om downtime te minimaliseren door te vermijden dat de container opnieuw moet opstarten, heb je touch-reload geconfigureerd om te luisteren naar wijzigingen in een specifiek bestand en automatisch de volledige applicatie te herladen. Tot slot heb je dit allemaal getest in de browser om te controleren of het werkt.
Docker zorgt voor snellere deployments en maakt het eenvoudig schalen van applicaties mogelijk. Als je meer wilt weten over de verschillende Docker-commando's, bekijk dan deze tutorial over hoe je Docker installeert en gebruikt op Ubuntu.
Voor meer bronnen over Docker op onze blog, kun je het volgende bekijken:
- Containerisatietechnologie: typen en toepassingen van verschillende containers op het PaaS-platform van CloudSigma
- Hoe je gegevens deelt tussen een Docker-container en een host
- Docker installeren en instellen op CentOS 7
- Laravel, Nginx en MySQL uitrollen met Docker Compose
- Docker-bronnen opschonen – Images, containers en volumes
Veel computerplezier!
Reacties
Nog geen reacties. Wees de eerste.