diff --git a/docs/roadmap.md b/docs/roadmap.md index 3c7966f..0751c87 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -20,17 +20,24 @@ Comprehensive progression of Kubernetes examples designed to teach MyceliumCloud - **Template**: Same efficient pattern with `nginx-static.md` + `nginx-static-deployment.yaml` + `nginx-static-service.yaml` + `default-index.html` - **Key Concepts**: Static files, nginx deployment, custom configuration, ConfigMaps, HTML serving +#### 3. Python Flask API ✅ +- **Difficulty**: ⭐ Easy-Medium +- **Status**: ✅ **COMPLETED** +- **Learning Focus**: Application containerization, Python web services +- **Template**: Same efficient pattern with `python-flask.md` + `python-flask-deployment.yaml` + `python-flask-service.yaml` + `app.py` +- **Key Concepts**: Python containers, API development, HTTP services, JSON responses, RESTful design + ### Planned Examples (In Progress) ### Planned Examples (Future) -#### 3. Python Flask API 🔄 -- **Difficulty**: ⭐ Easy-Medium +#### 4. Redis Cache 🔄 +- **Difficulty**: ⭐⭐ Medium - **Status**: 🔄 **NEXT UP** -- **Learning Focus**: Application containerization, Python web services +- **Learning Focus**: Data storage, caching patterns, stateful services - **Template**: Same efficient pattern -- **Key Concepts**: Python containers, API development, HTTP services -- **Next Step**: Create python-flask directory using nginx-static template +- **Key Concepts**: Redis deployment, data persistence, cache strategies +- **Next Step**: Create redis-cache directory using python-flask template #### 4. Redis Cache - **Difficulty**: ⭐⭐ Medium diff --git a/examples/python-flask/app.py b/examples/python-flask/app.py new file mode 100644 index 0000000..390e101 --- /dev/null +++ b/examples/python-flask/app.py @@ -0,0 +1,126 @@ +from flask import Flask, jsonify, request +import random +import datetime +import platform +import os +import math + +app = Flask(__name__) + +@app.route('/') +def home(): + return jsonify({ + 'api': 'Python Flask Tools API', + 'version': '1.0.0', + 'description': 'A practical API with useful endpoints for testing and development', + 'endpoints': { + '/': 'API information', + '/time': 'Current timestamp', + '/random': 'Random data and quotes', + '/health': 'Health check', + '/calc': 'Mathematical calculations', + '/info': 'System information' + }, + 'examples': { + 'time': '/time', + 'random': '/random', + 'calc': '/calc?operation=add&a=5&b=3', + 'health': '/health' + } + }) + +@app.route('/time') +def get_time(): + return jsonify({ + 'current_time': datetime.datetime.now().isoformat(), + 'timestamp': datetime.datetime.now().timestamp(), + 'timezone': 'UTC', + 'date': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + }) + +@app.route('/random') +def get_random(): + quotes = [ + 'The only way to do great work is to love what you do. - Steve Jobs', + 'Life is what happens to you while you are busy making other plans. - John Lennon', + 'The future belongs to those who believe in the beauty of their dreams. - Eleanor Roosevelt', + 'It is during our darkest moments that we must focus to see the light. - Aristotle', + 'The only impossible journey is the one you never begin. - Tony Robbins', + 'In the middle of difficulty lies opportunity. - Albert Einstein', + 'Success is not final, failure is not fatal: it is the courage to continue that counts. - Winston Churchill', + 'The way to get started is to quit talking and begin doing. - Walt Disney' + ] + + return jsonify({ + 'quote': random.choice(quotes), + 'number': random.randint(1, 100), + 'boolean': random.choice([True, False]), + 'list_item': random.choice(['apple', 'banana', 'cherry', 'date', 'elderberry']), + 'uuid': str(random.randint(1000, 9999)) + '-' + str(random.randint(100, 999)), + 'color': random.choice(['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7']) + }) + +@app.route('/health') +def health_check(): + return jsonify({ + 'status': 'healthy', + 'uptime': 'running', + 'service': 'Python Flask Tools API', + 'timestamp': datetime.datetime.now().isoformat() + }), 200 + +@app.route('/calc') +def calculate(): + try: + operation = request.args.get('operation', 'add') + a = float(request.args.get('a', 0)) + b = float(request.args.get('b', 0)) if request.args.get('b') is not None else None + + operations = { + 'add': lambda x, y: x + y, + 'subtract': lambda x, y: x - y, + 'multiply': lambda x, y: x * y, + 'divide': lambda x, y: x / y if y != 0 else 'Cannot divide by zero', + 'power': lambda x, y: x ** y, + 'sqrt': lambda x, y: math.sqrt(x) if b is None else 'Only one parameter needed for sqrt', + 'modulo': lambda x, y: x % y + } + + if operation not in operations: + return jsonify({ + 'error': f'Operation {operation} not supported', + 'available_operations': list(operations.keys()) + }), 400 + + result = operations[operation](a, b) + + return jsonify({ + 'operation': operation, + 'a': a, + 'b': b, + 'result': result, + 'calculation': f"{a} {operation} {b} = {result}" + }) + + except ValueError: + return jsonify({'error': 'Invalid numbers provided. Use /calc?operation=add&a=5&b=3'}), 400 + except Exception as e: + return jsonify({'error': str(e)}), 500 + +@app.route('/info') +def system_info(): + return jsonify({ + 'python_version': platform.python_version(), + 'platform': platform.platform(), + 'processor': platform.processor(), + 'hostname': platform.node(), + 'machine': platform.machine(), + 'current_directory': os.getcwd(), + 'environment': { + 'HOSTNAME': os.getenv('HOSTNAME', 'N/A'), + 'POD_NAME': os.getenv('POD_NAME', 'N/A') + } + }) + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000, debug=False) \ No newline at end of file diff --git a/examples/python-flask/python-flask-deployment.yaml b/examples/python-flask/python-flask-deployment.yaml new file mode 100644 index 0000000..9f73a38 --- /dev/null +++ b/examples/python-flask/python-flask-deployment.yaml @@ -0,0 +1,31 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: python-flask +spec: + replicas: 1 + selector: + matchLabels: + app: python-flask + template: + metadata: + labels: + app: python-flask + spec: + containers: + - name: python-flask + image: python:3.11-alpine + ports: + - containerPort: 5000 + command: ["/bin/sh", "-c"] + args: + - | + pip install flask && + python /app/app.py + volumeMounts: + - name: app-code + mountPath: /app + volumes: + - name: app-code + configMap: + name: python-flask-app \ No newline at end of file diff --git a/examples/python-flask/python-flask-service.yaml b/examples/python-flask/python-flask-service.yaml new file mode 100644 index 0000000..67d0aec --- /dev/null +++ b/examples/python-flask/python-flask-service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: python-flask-service +spec: + selector: + app: python-flask + ports: + - port: 5000 + targetPort: 5000 + type: LoadBalancer \ No newline at end of file diff --git a/examples/python-flask/python-flask.md b/examples/python-flask/python-flask.md new file mode 100644 index 0000000..a9bc3a1 --- /dev/null +++ b/examples/python-flask/python-flask.md @@ -0,0 +1,533 @@ +# Mycelium Cloud - Python Flask API Example + +A complete, production-ready Python Flask API for deploying dynamic web services on Mycelium Cloud Kubernetes cluster. + +## 📁 What This Contains + +This directory contains everything you need to deploy a practical Flask API: + +- **python-flask.md** - This comprehensive guide +- **python-flask-deployment.yaml** - Flask application deployment +- **python-flask-service.yaml** - Service configuration +- **app.py** - The Flask application source code + +## 🚀 Quick Start (2 minutes) + +```bash +# 1. Deploy the application +kubectl apply -f python-flask-deployment.yaml + +# 2. Create ConfigMap with the Flask app +kubectl create configmap python-flask-app --from-file=app.py + +# 3. Create the service +kubectl apply -f python-flask-service.yaml + +# 4. Access your API via port-forward + +**Option 1: Simple (Recommended)** +```bash +# Keep terminal open, see connection logs (Ctrl+C to stop) +kubectl port-forward service/python-flask-service 5000:5000 +``` + +**Option 2: Advanced (Background)** +```bash +# Start in background +nohup kubectl port-forward service/python-flask-service 5000:5000 > /dev/null 2>&1 & + +# Kill when done +lsof -ti:5000 | xargs kill -9 +``` + +# 5. Test the API +curl http://localhost:5000 +curl http://localhost:5000/time +curl http://localhost:5000/health +curl http://localhost:5000/random +curl "http://localhost:5000/calc?operation=add&a=5&b=3" +``` + +**Expected Result:** You'll see a complete API with multiple useful endpoints. + +## 📋 What You'll Learn + +- ✅ Flask web framework deployment +- ✅ Python application containerization +- ✅ API development and JSON responses +- ✅ RESTful endpoints with parameters +- ✅ Error handling and status codes +- ✅ Container management with ConfigMaps +- ✅ Service creation and networking +- ✅ Port-forwarding for external access (Mycelium Cloud method) +- ✅ Advanced Flask patterns and best practices + +## 🏗️ Architecture + +This example demonstrates: + +``` +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ User │ │ Port-Forward │ │ Flask API │ │ Python │ +│ (cURL/HTTP) │────│ localhost:5000 │────│ Service │────│ Container │ +│ │ │ │ │ :5000 │ │ (Python 3.11) │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ └─────────────────┘ + │ + ┌───────────────┐ + │ ConfigMap │ + │ (app.py) │ + └───────────────┘ +``` + +**Components:** +- **Flask Pod**: Python web application serving multiple endpoints +- **ConfigMap**: Stores the Flask application code (app.py) +- **Service**: LoadBalancer exposing the Flask API +- **Port-Forward**: Mycelium Cloud method for external access +- **Endpoints**: 6 useful API endpoints for testing and development + +## 🔥 API Endpoints + +### 1. Root Information +```bash +GET / +``` +**Response:** +```json +{ + "api": "Python Flask Tools API", + "version": "1.0.0", + "description": "A practical API with useful endpoints for testing and development", + "endpoints": { + "/": "API information", + "/time": "Current timestamp", + "/random": "Random data and quotes", + "/health": "Health check", + "/calc": "Mathematical calculations", + "/info": "System information" + }, + "examples": { + "time": "/time", + "random": "/random", + "calc": "/calc?operation=add&a=5&b=3", + "health": "/health" + } +} +``` + +### 2. Current Time +```bash +GET /time +``` +**Response:** +```json +{ + "current_time": "2025-11-04T17:31:40.387484", + "date": "2025-11-04 17:31:40", + "timestamp": 1762277500.387502, + "timezone": "UTC" +} +``` + +### 3. Random Data +```bash +GET /random +``` +**Response:** +```json +{ + "boolean": false, + "color": "#FF6B6B", + "list_item": "banana", + "number": 91, + "quote": "The way to get started is to quit talking and begin doing. - Walt Disney", + "uuid": "8351-328" +} +``` + +### 4. Health Check +```bash +GET /health +``` +**Response:** +```json +{ + "service": "Python Flask Tools API", + "status": "healthy", + "timestamp": "2025-11-04T17:31:48.464063", + "uptime": "running" +} +``` + +### 5. Mathematical Calculations +```bash +GET /calc?operation=add&a=5&b=3 +``` +**Operations supported:** `add`, `subtract`, `multiply`, `divide`, `power`, `sqrt`, `modulo` + +**Response:** +```json +{ + "operation": "add", + "a": 5, + "b": 3, + "result": 8, + "calculation": "5 add 3 = 8" +} +``` + +### 6. System Information +```bash +GET /info +``` +**Response:** +```json +{ + "python_version": "3.11.14", + "platform": "Linux-6.1.21-x86_64-with-musl", + "processor": "", + "hostname": "python-flask-55fdbf5cb4-cnxrc", + "machine": "x86_64", + "current_directory": "/", + "environment": { + "HOSTNAME": "python-flask-55fdbf5cb4-cnxrc", + "POD_NAME": "N/A" + } +} +``` + +## 📊 Resource Details + +```bash +# Expected output +kubectl get pods +NAME READY STATUS RESTARTS AGE +python-flask-xxxxxx-xxxxx 1/1 Running 0 2m + +kubectl get svc +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) +python-flask-service LoadBalancer 10.43.xx.x 10.20.x.x,10.20.x.x 5000:xxxxx/TCP + +kubectl get configmap +NAME DATA AGE +python-flask-app 1 1m +``` + +## 🛠️ API Testing Examples + +### Test All Endpoints +```bash +# Test root endpoint +curl http://localhost:5000 + +# Test time endpoint +curl http://localhost:5000/time + +# Test random data +curl http://localhost:5000/random + +# Test health check +curl http://localhost:5000/health + +# Test calculations +curl "http://localhost:5000/calc?operation=add&a=10&b=5" +curl "http://localhost:5000/calc?operation=multiply&a=7&b=8" +curl "http://localhost:5000/calc?operation=divide&a=20&b=4" +curl "http://localhost:5000/calc?operation=power&a=2&b=3" + +# Test system info +curl http://localhost:5000/info +``` + +### Advanced Testing +```bash +# Test with JSON response formatting +curl -s http://localhost:5000 | jq '.' +curl -s http://localhost:5000/time | jq '.current_time' + +# Test error handling +curl "http://localhost:5000/calc?operation=unknown&a=5&b=3" +curl "http://localhost:5000/calc?operation=add&a=invalid&b=3" + +# Test multiple random calls +for i in {1..5}; do + curl -s http://localhost:5000/random | jq -r '.quote' +done +``` + +## 🔧 Customization Guide + +### Add New Endpoints + +Edit `app.py` to add custom endpoints: + +```python +@app.route('/custom') +def custom_endpoint(): + return jsonify({ + 'message': 'This is a custom endpoint', + 'data': {'key': 'value'}, + 'timestamp': datetime.datetime.now().isoformat() + }) +``` + +### Modify Existing Endpoints + +```python +@app.route('/random') +def get_random(): + # Add your own quotes or data + quotes = [ + 'Your custom quote here', + 'Another custom quote' + ] + # ... rest of the function +``` + +### Update Container Image + +To use a different Python version or add packages: + +```yaml +# In python-flask-deployment.yaml +- name: python-flask + image: python:3.12-alpine # Use different version +``` + +```yaml +# In python-flask-deployment.yaml +args: +- | + pip install flask requests && # Add more packages + python /app/app.py +``` + +### Environment Variables + +Add environment-specific configuration: + +```yaml +# In python-flask-deployment.yaml +env: +- name: FLASK_ENV + value: "production" +- name: DEBUG + value: "False" +``` + +## 🚪 Access Methods + +### Method 1: Port-Forward (Recommended for Mycelium Cloud) + +**Option 1: Simple (Recommended)** +```bash +# Keep terminal open, see connection logs (Ctrl+C to stop) +kubectl port-forward service/python-flask-service 5000:5000 + +# Access via browser or curl +curl http://localhost:5000 +``` + +**Option 2: Advanced (Background)** +```bash +# Start in background +nohup kubectl port-forward service/python-flask-service 5000:5000 > /dev/null 2>&1 & + +# Access via browser or curl +curl http://localhost:5000 +``` + +**Why this works in Mycelium Cloud:** +- LoadBalancer external IPs are internal cluster addresses +- Port-forward creates local tunnel to cluster service +- Reliable and consistent access method + +### Method 2: LoadBalancer (For Reference) + +Note: In Mycelium Cloud, LoadBalancer external IPs (like 10.20.x.x) are internal cluster IPs and not externally accessible. Use port-forward for external access. + +### Method 3: Direct API Testing + +Create a test script: + +```python +import requests +import json + +# Test all endpoints +base_url = "http://localhost:5000" + +endpoints = ['/', '/time', '/random', '/health', '/calc?operation=add&a=5&b=3', '/info'] + +for endpoint in endpoints: + response = requests.get(f"{base_url}{endpoint}") + print(f"GET {endpoint}") + print(json.dumps(response.json(), indent=2)) + print("-" * 50) +``` + +## 🗑️ Resource Cleanup + +```bash +# Remove all resources +kubectl delete -f python-flask-deployment.yaml -f python-flask-service.yaml + +# Remove the ConfigMap +kubectl delete configmap python-flask-app + +# Verify cleanup +kubectl get all -l app=python-flask # Should return nothing +``` + +## 🔍 Troubleshooting + +### Pod Won't Start +```bash +# Check pod status +kubectl get pods -l app=python-flask + +# Check pod logs +kubectl logs deployment/python-flask + +# Check pod events +kubectl describe pod -l app=python-flask + +# Common issues: +# - ConfigMap not found +# - Python package installation failed +# - Port binding errors +``` + +### API Not Responding +```bash +# Check service endpoints +kubectl get endpoints python-flask-service + +# Check if port-forward is working +kubectl port-forward service/python-flask-service 5001:5000 & +curl -v http://localhost:5001 + +# Test from within cluster +kubectl run test-flask --rm -it --image=curlimages/curl:8.7.1 -- \ + sh -lc 'curl http://python-flask-service:5000' +``` + +### ConfigMap Issues +```bash +# Verify ConfigMap exists +kubectl get configmap python-flask-app + +# Check ConfigMap content +kubectl get configmap python-flask-app -o yaml + +# Recreate ConfigMap +kubectl delete configmap python-flask-app +kubectl create configmap python-flask-app --from-file=app.py +``` + +### Flask App Errors +```bash +# Check Flask app logs +kubectl logs deployment/python-flask + +# Test Flask app locally +python app.py # Test locally first + +# Check for syntax errors +python -m py_compile app.py +``` + +### Port Forward Fails +```bash +# Check if port is in use +lsof -i :5000 + +# Try different port +kubectl port-forward service/python-flask-service 5002:5000 +curl http://localhost:5002 +``` + +## 📚 More Examples + +This is currently one of the complete examples. Future examples will include: +- **python-flask/** - This example (COMPLETED) +- **redis-cache/** - In-memory data caching +- **postgresql/** - Persistent database services +- **wordpress/** - Multi-container CMS deployment +- **nodejs-api/** - Modern JavaScript applications +- **jenkins-cicd/** - Infrastructure automation +- **nextcloud/** - Enterprise file sharing + +## 💡 Pro Tips + +1. **Start Simple**: Begin with foreground port-forward (`kubectl port-forward`) +2. **Background Optional**: Use `nohup` only when you need persistent access +3. **Port Management**: Use `lsof -ti:PORT` to find and kill processes +4. **Resource Monitoring**: `kubectl get pods -o wide` shows pod distribution +5. **Quick Testing**: Use `curl` for all API testing +6. **Flask Logs**: `kubectl logs deployment/python-flask` for debugging +7. **Config Updates**: Update ConfigMap then restart deployment: `kubectl rollout restart deployment/python-flask` +8. **API Documentation**: The root endpoint (`/`) provides complete API documentation +9. **Error Handling**: Test error cases like invalid operations or missing parameters +10. **Environment Testing**: Test in both development and production modes + +## 🎉 Success Indicators + +You'll know everything is working when: +- ✅ `kubectl get pods` shows python-flask pod in "Running" status +- ✅ `kubectl get svc` shows python-flask-service created +- ✅ `curl http://localhost:5000` returns API information +- ✅ All endpoints (`/time`, `/random`, `/health`, `/calc`, `/info`) return proper JSON +- ✅ `kubectl logs deployment/python-flask` shows Flask starting without errors +- ✅ ConfigMap `python-flask-app` exists and contains app.py + +## 🏆 Next Steps + +After completing this example, you can: +1. **Customize Endpoints**: Add your own API endpoints +2. **Database Integration**: Connect to persistent databases +3. **Add More Examples**: Try the Redis cache example +4. **Scale Up**: Learn about load balancing with multiple replicas +5. **Advanced Patterns**: Learn about secrets, config maps, and persistent volumes + +## 🚀 API Testing Tools + +### Postman/Insomnia +Import the API into API testing tools: +``` +http://localhost:5000/ +http://localhost:5000/time +http://localhost:5000/random +http://localhost:5000/health +http://localhost:5000/calc?operation=add&a=5&b=3 +http://localhost:5000/info +``` + +### Command Line Tools +```bash +# Install jq for JSON formatting +curl http://localhost:5000 | jq '.' + +# Create an API test script +cat > test-api.sh << 'EOF' +#!/bin/bash +echo "Testing Python Flask API..." +curl -s http://localhost:5000 | jq '.api' +curl -s http://localhost:5000/time | jq '.current_time' +curl -s http://localhost:5000/random | jq '.quote' +echo "All tests completed!" +EOF +chmod +x test-api.sh +./test-api.sh +``` + +## 📞 Getting Help + +- **Troubleshooting**: Check the troubleshooting section above +- **Mycelium Cloud Docs**: See main repository README +- **Flask Documentation**: https://flask.palletsprojects.com/ +- **Kubectl Help**: `kubectl get pods --help` for command reference +- **API Testing**: Use Postman, Insomnia, or curl for testing +- **Support**: Contact Mycelium Cloud support team + +For more help, visit our [documentation](../../README.md) or contact support. \ No newline at end of file