Sample app deployed on containers in kubernetes.
- Python 3 Flask REST API
- Docker and docker-compose configs included
- Kubernetes charts for fluentd, Elasticsearch & Kibana integration for logs
- Various helper scripts for minikube and other local development
- Integration with External OpenWeather API
- Request Header API Key Authorization
- (@TODO) Input Validation and better error handling within application
- (@TODO) Unit tests for services
- (@TODO) Integration Tests for secured endpoints
- (@TODO) Kubernetes Service Healthcheck
- (@TODO) Dockerize the Load test script
- (@TODO) Elastic APM / Prometheus integration
- (@TODO) Caching for external API calls
You will need an api key for OpenWeather
# Copy and then Populate the .env file
cp example.env .env
python3 -m venv env
source env/bin/activate
pip install -e .
export FLASK_ENV=dev
python wsgi.py
Access the App via: http://localhost:5000/health
Build and Run the app via a docker container:
docker-compose up -d
Access the App via: http://localhost:5000/health
kubectl apply -f kubernetes/deployment.yml
There is an included script to build image, setup elasticsearch, and deploy the app
eval $(minikube docker-env)
./minikube-startup.sh
# Get URL for app
minikube service kibana -n logging --url
minikube service prime-weather-service
# Get URL for kibana
minikube service kibana -n logging --url
# Build docker container
./docker-build.sh
# Minikube startup (apply all charts)
./minikube-startup.sh
#### Minikube Temporary Workaround Scripts ####
# Port forward the api to allow access on http://localhost:5000
./scripts/minikube-open-api.sh
# Port forward Kibana to allow access on http://localhost:5601
./scripts/minikube-open-kibana.sh
# Load testing script (does not hit weather endpoint)
python ./scripts/load-test.py
An API Key is required to access certain endpoints. This key should be passed in via a request header with the header name of "apiKey". This key is configurable via an Environment Variable "API_KEY".
Example Request:
curl --request POST \
--url http://localhost:5000/api/weather \
--header 'apikey: xqkJUQ2ykcjK' \
--header 'content-type: application/json' \
--data '{
"zipcode": "02771"
}'
Endpoints can be secured via a decorator @require_apikey:
from ..security import require_apikey
@api.route("/weather")
class PrimeResource(Resource):
@require_apikey
def post(self):
Note: When app is running, visit http://localhost:5000/ for full swagger docs
Return a JSON dictionary with the name and version of the application.
Return a JSON dictionary with the version of the application.
Takes a number and returns true if the provided number is prime or false if not prime.
API Key Required
Takes a US zipcode and returns the current weather.
Example Response:
{
"coord": {
"lon": -71.32,
"lat": 41.84
},
"weather": [
{
"id": 801,
"main": "Clouds",
"description": "few clouds",
"icon": "02d"
}
],
"base": "stations",
"main": {
"temp": 294.48,
"feels_like": 288.97,
"temp_min": 293.15,
"temp_max": 296.15,
"pressure": 1012,
"humidity": 64
},
"visibility": 10000,
"wind": {
"speed": 9.8,
"deg": 210,
"gust": 13.4
},
"clouds": {
"all": 20
},
"dt": 1602363393,
"sys": {
"type": 1,
"id": 5441,
"country": "US",
"sunrise": 1602327138,
"sunset": 1602367899
},
"timezone": -14400,
"id": 0,
"name": "Seekonk",
"cod": 200
}