–
add folder to workspace)app, ajoutez une petite application python identidock.py:from flask import Flask, Response, request
import requests
import hashlib
import redis
app = Flask(__name__)
cache = redis.StrictRedis(host='redis', port=6379, db=0)
salt = "UNIQUE_SALT"
default_name = 'Joe Bloggs'
@app.route('/', methods=['GET', 'POST'])
def mainpage():
name = default_name
if request.method == 'POST':
name = request.form['name']
salted_name = salt + name
name_hash = hashlib.sha256(salted_name.encode()).hexdigest()
header = '<html><head><title>Identidock</title></head><body>'
body = '''<form method="POST">
Hello <input type="text" name="name" value="{0}">
<input type="submit" value="submit">
</form>
<p>You look like a:
<img src="/monster/{1}"/>
'''.format(name, name_hash)
footer = '</body></html>'
return header + body + footer
@app.route('/monster/<name>')
def get_identicon(name):
image = cache.get(name)
if image is None:
print ("Cache miss", flush=True)
r = requests.get('http://dnmonster:8080/monster/' + name + '?size=80')
image = r.content
cache.set(name, image)
return Response(image, mimetype='image/png')
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
Nous allons dockeriser cette application python de façon classique
Flask uWSGI requests redis à installer avec pip. Pas besoin de `virtualenv pour isoler car on a déjà un conteneur : installer les dépendance à la racine du conteneur.Nous allons utiliser uWSGI qui est un serveur python de production très adapté pour servir des applications flask (mieux que le serveur intégré flask).
Dans le Dockerfile, créez l’instruction pour ajouter un utilisateur et groupe dédié à uWSGI avec groupadd -r uwsgi && useradd -r -g uwsgi uwsgi.
Exposez le port 9090 et 9191 qui seront les deux ports de norte mini backend. L’instruction expose est indicative elle n’ouvre pas effectivement les ports.
Juste avant de lancer l’application, changez d’utilisateur vers uwsgi avec l’instruction USER.
A la fin , plutôt que d’utiliser flask run pour lancer l’application nous allons appeler uwsgi avec CMD :
CMD ["uwsgi", "--http", "0.0.0.0:9090", "--wsgi-file", "/app/identidock.py", "--callable", "app", "--stats", "0.0.0.0:9191"]
–
docker exec, whoami et id l’utilisateur avec lequel tourne le conteneur.CORRECTION:
docker build -t identidock .docker run --detach --name identidock -p 9090:9090 identidockdocker exec -it identidock /bin/bashUne fois dans le conteneur lancez:
whoami et idps aux que le serveur est bien lancé.hub.docker.com.docker login pour vous identifier en CLI.docker tag identidock <votre_hub_login>/identidock:0.1docker push <votre_hub_login>/identidock:0.1Finalement le serveur de développement flask est bien pratique pour debugger en situation de développement bien que pas adapté à la production.
Nous pourrions créer deux images pour les deux situations mais ce serait aller contre l’imperatif DevOps de rapprochement du dév et de la production.
boot.sh pour adapter le lancement de l’application au contexte:#!/bin/bash
set -e
if [ "$CONTEXT" = 'DEV' ]; then
echo "Running Development Server"
exec python3 "/app/identidock.py"
else
echo "Running Production Server"
exec uwsgi --http 0.0.0.0:9090 --wsgi-file /app/identidock.py --callable app --stats 0.0.0.0:9191
fi
Ajoutez au Dockerfile une deuxième instruction COPY en dessous de la précédente pour mettre le script dans le conteneur.
Ajoutez un RUN chmod a+x /boot.sh pour le rendre executable.
Modifiez l’instruction CMD pour lancer le script de boot plutôt que uwsgi directement.
Modifiez l’instruction expose pour déclarer le port 5000 en plus.
Ajoutez au dessus une instruction ENV ENV PROD pour définir la variable d’environnement ENV à la valeur PROD par défaut.
Testez votre conteneur en mode DEV avec docker run --env CONTEXT=DEV -p 5000:5000 identidock, visitez localhost:5000
Et en mode PROD avec docker run --env CONTEXT=PROD -p 9090:9090 identidock. Visitez localhost:9090.
–
Conclusions:
docker-compose.yml avec à l’intérieur:version: "3"
services:
identidock:
build: .
ports:
- "5000:5000"
environment:
- CONTEXT=DEV
volumes:
- ./app:/app
Plusieurs remarques:
build: . d’abord l’image d’origine de notre conteneur est le résultat de la construction du répertoire courantapp dans le conteneur sera le contenu de notre dossier de code) de cette façon si on modifie le code pas besoin de rebuilder l’application !!!Lancez le service (pour le moment mono conteneur) avec docker-compose up.
Visitez la page web.
Essayez de modifier l’application et de recharger la page web. Voilà comment, grâce à un volume on peut développer sans reconstruire l’image à chaque fois ! (grace au volume /app)
Ajoutons maintenant un deuxième conteneur. Nous allons tirer parti d’une image déjà créée qui permet de récupérer une “identicon” et l’afficher dans l’application identidock. Ajoutez à la suite du compose file (attention aux identation !!):
networks:
- identinet
dnmonster:
image: amouat/dnmonster:1.0
networks:
- identinet
image:.identidock pour mettre les deux conteneurs de notre application.networks:
identinet:
driver: bridge
redis:
image: redis
networks:
- identinet
–
Lancez l’application et vérifiez que le cache fonctionne en chercheant les cache miss dans les logs de l’application.
Créez un deuxième fichier compose docker-compose.prod.yml (à compléter) pour lancer l’application en configuration de production:
version: "3"
services:
identidock:
image: <votre_hub_login>/identidock:0.1
ports:
- "9090:9090"
- "9191:9191"
environment:
- CONTEXT=PROD
networks:
- identinet
dnmonster:
image: amouat/dnmonster:1.0
networks:
- identinet
redis:
image: redis
networks:
- identinet
volumes:
- identiredis_volume:/data
redis-commander:
image: rediscommander/redis-commander:latest
environment:
- REDIS_HOSTS=local:redis:6379
ports:
- "8081:8081"
networks:
- identinet
networks:
identinet:
driver: bridge
volumes:
identiredis_volume:
driver: local
Commentons ce code:
/app pour identidock car nous sommes en proddocker-compose. Ainsi que la documentation du langage (DSL) des compose-file.