- First, clone an example Flask application:
git clone https://github.com/uptime-formation/microblog/
- Open VSCode with the microblog directory by typing `code microblog` or by launching VSCode with `code` and then clicking on Open Folder.
- In VSCode, you can go to `Terminal > New Terminal` to get a terminal at the bottom of the screen.
- Let's explore the code together in VSCode.
Manually deploying a Flask application each time can be relatively cumbersome. To prevent the dependencies of two Python projects from conflicting, you should normally use a virtual environment like virtualenv to separate these two apps. With Docker, projects are already isolated in containers. Therefore, we will build a container image to package the application and handle it more easily. Make sure Docker is installed.
To know the list of Dockerfile instructions and their usage, refer to the reference manual on Dockerfiles.
RUN apt-get update -y RUN apt-get install -y python3-pip
COPY ./requirements.txt /requirements.txt RUN pip3 install -r requirements.txt ENV FLASK_APP microblog.py
COPY ./ /microblog WORKDIR /microblog
The first line instructs to copy all the contents of the current host directory into a directory /microblog inside the container. We didn't copy the requirements at the same time to take advantage of Docker's cache features, avoiding having to redownload the application dependencies every time we modify the app's content.
Then, in the second line, the current directory in the container is moved to /.
CMD ["./boot.sh"]
Using docker login, docker tag, and docker push, push the microblog image to Docker Hub. Create an account on Docker Hub if necessary.
Using the `python:3-alpine` image and replacing the necessary instructions (no need to install `python3-pip` as this program is now included in the base image), repackage the microblog app into an image tagged `microblog:slim` or `microblog:light`. Compare the size between the two built images.
The Flask development server is handy for debugging in a development environment but is not suitable for production. We could create two images for the two situations, but this would go against the DevOps imperative of bringing dev and prod closer together.
To start the application, a boot script named `boot.sh` is utilized. This script handles the initialization of the application environment and starts the appropriate server based on the environment variable `APP_ENVIRONMENT`.
set -e if [ "$APP_ENVIRONMENT" = 'DEV' ]; then echo "Running Development Server" exec flask run -h 0.0.0.0 else echo "Running Production Server" exec gunicorn -b :5000 --access-logfile - --error-logfile - app_name:app fi
Add the `EXPOSE 5000` instruction to inform Docker that this application is intended to be accessed via its port 5000.
Note: Publishing the port with the `-p host_port:container_port` option remains necessary; the EXPOSE instruction is there for documenting the image.
In this Dockerfile, use the `HEALTHCHECK` instruction to verify if the application inside the container is healthy.
In a new directory, create a Dockerfile with the following content:
FROM python:alpine RUN apk add curl RUN pip install flask==0.10.1 ADD /app.py /app/app.py WORKDIR /app HEALTHCHECK CMD curl --fail http://localhost:5000/health || exit 1 CMD python
Also, create an app.py file with the following content:
from flask import Flask healthy = True app = Flask(__name__) @app.route('/health') def health(): global healthy if healthy: return 'OK', 200 else: return 'NOT OK', 500 @app.route('/kill') def kill(): global healthy healthy = False return 'You have killed your app.', 200 if __name__ == "__main__": app.run(host="0.0.0.0")
Carefully observe the Python code and the `HEALTHCHECK` line of the Dockerfile, then launch the application. Use `docker ps` to see where Docker indicates the health of your application.
Visit the URL /kill of your application in a browser. Repeat `docker ps`. What happened?
(Optional) Add a HEALTHCHECK instruction to the Dockerfile of our microblog application.
An image is composed of several layers stacked together by the Docker Engine and metadata.
You can also use the command `docker save your_image -o image.tar`, then use `tar -C decompressed_image/ -xvf image.tar` to decompress a Docker image and explore the different layers of the image.
To explore the image hierarchy, you can install [dive](https://github.com/wagoodman/dive).
By retrieving the command indicated in the official documentation, create your own registry.
Then find out how to push an image to it.
Finally, delete your image locally and retrieve it from your registry.
Create a new Dockerfile to allow a cow to say things using the cowsay command. The goal is to run our program in a container with commands like:
Should we use the `ENTRYPOINT` command or the `CMD` command? Consult the Dockerfile reference manual if necessary.
For information, cowsay is installed in `/usr/games/cowsay`.
The list of (essential) cowsay options can be found [here](https://debian-facile.org/doc:jeux:cowsay).
Solution:
Transform the Dockerfile of the dnmonster application located at the following address to perform a multi-stage build to obtain the lightest possible final image: [https://github.com/amouat/dnmonster/](https://github.com/amouat/dnmonster/)
The documentation for multi-stage builds can be found [here](https://docs.docker.com/develop/develop-images/multistage-build/).