Python Flask Application Template to be tested via GHA and deployed via Docker-Compose, K8s Manifests and Helm.
- Python 3.9.14
- Docker 20.10.17
- Docker Compose v2.10.2
- Haskell Dockerfile Linter 2.10.0
- Container-structure-test 1.11.0
- Kubernetes server: v1.25.4
- kubectl v1.26.0
- Helm v3.10.2
- Helm Chart Testing 3.7.1
- Checkov 2.1.270
- Act 0.2.32
Status |
---|
Path | Description |
---|---|
.github/workflows/ | CI pipelines to test app, build Docker image, test Docker-compose config, K8s manifests and test & package Helm chart |
app/ | App for API with Prometheus client and migrations |
cs-test/ | Container Structure Test config to test Docker image |
data/ | DB secrets |
Helm/ | Helm chart with test and migration hooks |
K8s-kind/ | Kubernetes Kind cluster config |
K8s-manifests/ | Kubernetes manifests (an alternative to Helm charts) |
tests/ | App unittests |
.checkov.yaml | |
.dockerignore | |
.flake8 | |
.hadolint.yaml | Hadlint config to test Dockerfile |
.markdownlint.yaml | |
.pre-commit-config.yaml | Pre-commit hooks to test the code |
.pylitrc | |
.python-version | |
.yamllint.yaml | |
docker-compose.yaml | Docker-compose file |
Dockerfile | Docker File |
# Format
python -m pip install -r ./tests/requirements.txt
flake8 ./tests/*.py
flake8 ./app/*.py
# Lint
pylint --rcfile ./.pylintrc ./tests/*.py
pylint --rcfile ./.pylintrc ./app/*.py
python -m unittest tests.test
python -m unittest tests.test_noDB
# Start MariaDB
docker run -d \
--name db \
--user "999:999" \
-v $(pwd)/data/mysql-root-password:/run/secrets/mysql-root-password \
-v $(pwd)/data/mysql-user-name:/run/secrets/mysql-user-name \
-v $(pwd)/data/mysql-user-password:/run/secrets/mysql-user-password \
-v $(pwd)/data/mysql-conf-file:/run/secrets/mysql-conf-file \
--read-only \
-v /run/mysqld/ \
-v /var/lib/mysql/ \
-v /tmp/ \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql-root-password \
-e MYSQL_DATABASE=db1 \
-e MYSQL_USER_FILE=/run/secrets/mysql-user-name \
-e MYSQL_PASSWORD_FILE=/run/secrets/mysql-user-password \
--health-cmd="mysql --defaults-extra-file=/run/secrets/mysql-conf-file -e 'SHOW databases;'" \
mariadb:10.9.4
# Start the app
export DB_HOST='127.0.0.1'
export DB_PORT=3306
export DB_NAME='db1'
python ./app.py
# Start via Flask CLI
export FLASK_APP=app.py
flask run \
--host 0.0.0.0 \
--port 3000 \
--reload
# Start via Gunicorn
gunicorn --bind 0.0.0.0:3000 --access-logfile - --error-logfile - wsgi:app
# Create migration script after Schema Change
flask db migrate -m "migration1"
# Do the migration
flask db upgrade
# Create
curl -X GET http://127.0.0.1:3000/create
# Root
curl -X GET http://127.0.0.1:3000/
# Health
curl -X GET http://127.0.0.1:3000/health
# Metrics
curl -X GET http://127.0.0.1:3000/metrics
# Crash
curl -X GET http://127.0.0.1:3000/crash
checkov -d . --config-file ./.checkov.yaml
# Test
hadolint --config ./.hadolint.yaml Dockerfile
# Docker build
docker build -t andreyasoskovwork/cat-app:0.1.15 -f Dockerfile .
# Docker push
docker login -u andreyasoskovwork
docker push andreyasoskovwork/cat-app:0.1.15
# Test
container-structure-test test --image andreyasoskovwork/cat-app:0.1.14 --config ./cs-test/config.yaml
# Start as docker container
docker run -d \
--user "10001:10001" \
-v $(pwd)/data/mysql-user-name:/run/secrets/mysql-user-name \
-v $(pwd)/data/mysql-user-password:/run/secrets/mysql-user-password \
--read-only \
-v /tmp/ \
-p 3000:3000 \
-e DB_NAME=db1 \
-e DB_PORT=3306 \
-e DB_HOST=10.1.3.80 \
andreyasoskovwork/cat-app:0.1.14
# Test docker-compose
docker-compose -f docker-compose.yaml config
# Start as Docker-compose
docker-compose up -d --wait --build
# Start Kind Cluster
kind create cluster --config ./K8s-kind/kind-config.yaml
# Create Nginx Ingress Controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
# Delete Kind Cluster
kind delete cluster
# Test manifests
kubectl apply --validate --dry-run=client -f ./K8s-manifests/0.namespace.yaml
kubectl apply --validate --dry-run=client -f ./K8s-manifests/1.db.yaml
kubectl apply --validate --dry-run=client -f ./K8s-manifests/2.app.yaml
kubectl apply --validate --dry-run=client -f ./K8s-manifests/3.test.yaml
kubectl apply --dry-run=client -f ./K8s-manifests/0.namespace.yaml -o yaml
kubectl apply --dry-run=client -f ./K8s-manifests/1.db.yaml -o yaml
kubectl apply --dry-run=client -f ./K8s-manifests/2.app.yaml -o yaml
kubectl apply --dry-run=client -f ./K8s-manifests/3.test.yaml -o yaml
# Deploy manifests
kubectl apply -f ./K8s-manifests/0.namespace.yaml
kubectl -n app-manifests apply -f ./K8s-manifests/1.db.yaml
kubectl -n app-manifests apply -f ./K8s-manifests/2.app.yaml
# Test
kubectl -n app-manifests apply -f ./K8s-manifests/3.test.yaml
kubectl -n app-manifests get pod
# Test Nginx Ingress
curl --resolve www.example.com:80:127.0.0.1 -H 'Host: www.example.com' localhost/health
# Test Chart
ct lint --config ./Helm/ct-lint.yaml \
--charts ./Helm/charts/app
helm lint ./Helm/charts/app
helm template --namespace app-helm app \
./Helm/charts/app --values ./Helm/app_values.yaml \
--validate
helm install --namespace app-helm app \
./Helm/charts/app --values ./Helm/app_values.yaml \
--dry-run
# DB
helm repo add bitnami https://charts.bitnami.com/bitnami
helm template --namespace app-helm db \
bitnami/mariadb --version 11.3.3 --values ./Helm/mariadb_values.yaml \
--validate
helm install --namespace app-helm db \
bitnami/mariadb --version 11.3.3 --values ./Helm/mariadb_values.yaml \
--dry-run
kubectl apply -f ./Helm/namespace.yaml
helm install --create-namespace --namespace app-helm db \
bitnami/mariadb --version 11.3.3 --values ./Helm/mariadb_values.yaml \
--wait
helm upgrade --namespace app-helm db \
bitnami/mariadb --version 11.3.3 --values ./Helm/mariadb_values.yaml \
--wait
# App
kubectl apply -f ./Helm/namespace.yaml
helm install app --create-namespace --namespace app-helm \
./Helm/charts/app --values ./Helm/app_values.yaml --wait
## Update with DB migration
helm upgrade app --namespace app-helm \
./Helm/charts/app --values ./Helm/app_values.yaml
## List
helm list --namespace app-helm
## Test
helm test --namespace app-helm app
kubectl -n app-helm get pod
# Test Nginx Ingress
curl --resolve www.example.com:80:127.0.0.1 -H 'Host: www.example.com' localhost/health
## Delete
helm uninstall --namespace app-helm app
helm uninstall --namespace app-helm db
kubectl delete namespace app-helm
helm package ./Helm/charts/app -d ./Helm
## Via Docker or local
# Create data
curl http://127.0.0.1:3000/create
# Query the data
curl http://127.0.0.1:3000 | jq .
# Query prometheus Metrics
curl http://127.0.0.1:3000/metrics
## Via K8s Ingress
# Create data
curl --resolve www.example.com:80:127.0.0.1 -H 'Host: www.example.com' http://127.0.0.1/create
# Query the data
curl --resolve www.example.com:80:127.0.0.1 -H 'Host: www.example.com' http://127.0.0.1 | jq .
# Query prometheus Metrics
curl --resolve www.example.com:80:127.0.0.1 -H 'Host: www.example.com' http://127.0.0.1/metrics
# Test using medium image
act --rm -r -W ./.github/workflows/Python-test.yml -P ubuntu-22.04=ghcr.io/catthehacker/ubuntu:act-22.04
# Test using full image 20.04
act --rm -r -W ./.github/workflows/Python-test.yml -P ubuntu-22.04=catthehacker/ubuntu:full-20.04