Todos
Steps to deploy to sec.joostagterhoek.nl
Manual
Install and configure a Flask app on my server
Following the steps described in this Yunohost-forum-post, I managed to install a ‘Hello World’-app on sec.joostagterhoek.nl.
Deploy to production according to Flask-documentation
source: link to Flask-documentation on production deployment
To deploy a Flask app, the documentation recommends to:
- Build a wheel (
.whl) file. - Configure a secret key
- Run the app with a production server
How to build a wheel
- Look this up and note here
Docker
Dockerize the Flask application
- Take notes from this walkthrough
Enable the container registry in Gitlab
The commands/configuration code below works, but I had to rework the paths to the *.pem files. Below is what I found in this Yunohost-package issue:
/etc/gitlab/gitlab-persistent.rb
registry_external_url 'https://git.example.com:5050'
registry_nginx['ssl_certificate'] = "/etc/ssl/private/yunohost_crt.pem"
registry_nginx['ssl_certificate_key'] = "/etc/ssl/private/yunohost_key.pem"
Then
sudo gitlab-ctl reconfigure
I then had to find out where the actual current pem files are:
/etc/ssl/certs/yunohost_crt.pem
/etc/ssl/private/yunohost_key.pem
Configure the registry to receive Docker containers
Authentication:
- With only a username and password:
- docker login registry.example.com -u
-p - Probably unsafe (you also get a warning that your hashed password is stored in
home/$USER/.docker/config.json).
- docker login registry.example.com -u
- Use Gitlab CI/CD to authenticate
- Upside: per-job user and password managed by Gitlab CI/CD pipeline.
- Authenticate with a token
- Downside: token management (tokens should have a limited lifespan)
Approach
- Build and push the local dockerized Flask image with a temporary token
- Create a Gitlab deployment pipeline that does the following:
- SSH into production server as Gitlab Runner-account
- Use the
CI job token(unique to each CI/CD pipeline) which only hasread_registryscope for read (pull) access.
Managing Docker secrets
Adding secrets to Docker
From https://docs.docker.com/engine/swarm/secrets/#simple-example-get-started-with-secrets:
printf "This is a secret" | docker secret create my_secret_data -(…). The docker secret create command reads standard input because the last argument, which represents the file to read the secret from, is set to -.
Thinking it through: in no way would adding ‘reusable’ secrets like an API key or a Flask secret key in an image build be a good idea: even if someone would not be able to access those secret values directly because of Docker’s encryption or access levels, the built image would still allow the secrets to be used by others (and for example exceed API key usage limits). Instead, it would be better to add those secrets at runtime, in the case of my preferred DevOps-flow, when the Docker Compose file uses the prebuilt image from the most current code (which both have no baked in secrets) and adds the secret at/before runtime.
Like this flowchart:
flowchart TD code --> pipeline --> container_registry --> compose -->|secrets injected| production_server code[Code commited and pushed to remote] pipeline[GitLab pipeline to build Docker image] container_registry[image pushed to Docker container registry] compose[Docker Compose runs built image on production server] production_server[Provides Flask app]