diff --git a/Dockers/puppeteer-healtcheck/Dockerfile b/Dockers/puppeteer-healtcheck/Dockerfile new file mode 100644 index 0000000..26f66b0 --- /dev/null +++ b/Dockers/puppeteer-healtcheck/Dockerfile @@ -0,0 +1,33 @@ +FROM python:3.9-slim + +# Install required system dependencies +RUN apt-get update && apt-get install -y \ + curl \ + docker.io \ + && rm -rf /var/lib/apt/lists/* + +# Set working directory +WORKDIR /app + +# Copy requirements first to leverage Docker cache +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +# Copy the healthcheck script +COPY healthcheck.py . + +# Set environment variables +ENV PYTHONUNBUFFERED=1 +ENV BASE_URL="https://puppeteer.workwithkora.com" +ENV TEST_URL="https://www.google.com" +ENV API_KEY="Q7Sd#hhFkyHy*T" +ENV TARGET_CONTAINER="puppeteer-api" +ENV CHECK_INTERVAL=60 + +# Create a non-root user +RUN useradd -m healthcheck && chown -R healthcheck:healthcheck /app + +USER healthcheck + +# Run the healthcheck script +CMD ["python", "healthcheck.py"] diff --git a/Dockers/puppeteer-healtcheck/README.md b/Dockers/puppeteer-healtcheck/README.md new file mode 100644 index 0000000..0657d17 --- /dev/null +++ b/Dockers/puppeteer-healtcheck/README.md @@ -0,0 +1,110 @@ +# Puppeteer API Healthcheck + +A Docker container that monitors the Puppeteer API and automatically restarts the target container when the API becomes unresponsive. + +## Features + +- Monitors the Puppeteer API endpoint every minute +- Automatically restarts the target container after 3 consecutive failures +- Configurable via environment variables +- Comprehensive logging +- Docker socket access for container management + +## Environment Variables + +| Variable | Default | Description | +| ------------------ | ------------------------------------ | -------------------------------- | +| `BASE_URL` | `https://puppeteer.workwithkora.com` | Base URL of the Puppeteer API | +| `TEST_URL` | `https://www.google.com` | URL to test the API with | +| `API_KEY` | `Q7Sd#hhFkyHy*T` | API key for authentication | +| `TARGET_CONTAINER` | `puppeteer-api` | Name of the container to restart | +| `CHECK_INTERVAL` | `60` | Health check interval in seconds | + +## Usage + +### Docker Run + +```bash +docker run -d \ + --name puppeteer-healthcheck \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -e BASE_URL="https://puppeteer.workwithkora.com" \ + -e TEST_URL="https://www.google.com" \ + -e API_KEY="your-api-key" \ + -e TARGET_CONTAINER="puppeteer-api" \ + -e CHECK_INTERVAL="60" \ + your-registry/puppeteer-healthcheck:latest +``` + +### Docker Compose + +```yaml +version: "3.8" + +services: + puppeteer-healthcheck: + build: . + container_name: puppeteer-healthcheck + volumes: + - /var/run/docker.sock:/var/run/docker.sock + environment: + - BASE_URL=https://puppeteer.workwithkora.com + - TEST_URL=https://www.google.com + - API_KEY=your-api-key + - TARGET_CONTAINER=puppeteer-api + - CHECK_INTERVAL=60 + restart: unless-stopped + depends_on: + - puppeteer-api +``` + +## How It Works + +1. The healthcheck container makes a GET request to the Puppeteer API every minute +2. It uses the configured test URL and API key for authentication +3. If the request fails (non-200 status or timeout), it increments a failure counter +4. After 3 consecutive failures, it attempts to restart the target container +5. If the restart is successful, the failure counter is reset +6. The process continues indefinitely + +## Logging + +The container logs all health check activities to both stdout and a log file (`/app/healthcheck.log`). Log levels include: + +- INFO: Normal operations and successful health checks +- WARNING: Failed health checks +- ERROR: Container restart attempts and failures + +## Security Considerations + +- The container requires access to the Docker socket to restart other containers +- Ensure proper API key management +- Consider running with limited privileges where possible +- The container runs as a non-root user for security + +## Troubleshooting + +### Container not found + +- Ensure the `TARGET_CONTAINER` environment variable matches the exact name of your puppeteer-api container +- Verify the container is running and accessible + +### Permission denied + +- Ensure the Docker socket is properly mounted +- Check that the container has the necessary permissions to access the Docker daemon + +### API key issues + +- Verify the API key is correct and has the necessary permissions +- Check that the base URL is accessible from the container + +## Building + +```bash +docker build -t puppeteer-healthcheck . +``` + +## Version + +Current version: 1.0.0 diff --git a/Dockers/puppeteer-healtcheck/healthcheck.py b/Dockers/puppeteer-healtcheck/healthcheck.py new file mode 100644 index 0000000..a9622e2 --- /dev/null +++ b/Dockers/puppeteer-healtcheck/healthcheck.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 +""" +Healthcheck script for Puppeteer API +Monitors the API endpoint and restarts the container if it fails +""" + +import os +import time +import logging +import requests +import docker +from urllib.parse import quote +from datetime import datetime + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=[ + logging.StreamHandler(), + logging.FileHandler('/app/healthcheck.log') + ] +) +logger = logging.getLogger(__name__) + +class PuppeteerHealthcheck: + def __init__(self): + self.base_url = os.getenv('BASE_URL', 'https://puppeteer.workwithkora.com') + self.test_url = os.getenv('TEST_URL', 'https://www.google.com') + self.api_key = os.getenv('API_KEY', 'Q7Sd#hhFkyHy*T') + self.target_container = os.getenv('TARGET_CONTAINER', 'puppeteer-api') + self.check_interval = int(os.getenv('CHECK_INTERVAL', '60')) + + # Initialize Docker client + try: + self.docker_client = docker.from_env() + logger.info("Docker client initialized successfully") + except Exception as e: + logger.error(f"Failed to initialize Docker client: {e}") + raise + + logger.info(f"Healthcheck initialized with:") + logger.info(f" Base URL: {self.base_url}") + logger.info(f" Test URL: {self.test_url}") + logger.info(f" Target Container: {self.target_container}") + logger.info(f" Check Interval: {self.check_interval} seconds") + + def perform_health_check(self): + """Perform the health check by making a request to the puppeteer API""" + try: + # Construct the URL with the test URL as a parameter + encoded_test_url = quote(self.test_url, safe='') + url = f"{self.base_url}/?url={encoded_test_url}" + + headers = { + 'x-api-key': self.api_key, + 'User-Agent': 'Puppeteer-Healthcheck/1.0' + } + + logger.info(f"Performing health check: {url}") + + response = requests.get( + url, + headers=headers, + timeout=30, + allow_redirects=True + ) + + if response.status_code == 200: + logger.info("Health check passed - API is responding correctly") + return True + else: + logger.warning(f"Health check failed - Status code: {response.status_code}") + logger.warning(f"Response: {response.text[:200]}...") + return False + + except requests.exceptions.RequestException as e: + logger.error(f"Health check failed - Request error: {e}") + return False + except Exception as e: + logger.error(f"Health check failed - Unexpected error: {e}") + return False + + def restart_container(self): + """Restart the target puppeteer-api container""" + try: + logger.info(f"Attempting to restart container: {self.target_container}") + + # Get the container + container = self.docker_client.containers.get(self.target_container) + + # Restart the container + container.restart(timeout=30) + + logger.info(f"Successfully restarted container: {self.target_container}") + return True + + except docker.errors.NotFound: + logger.error(f"Container not found: {self.target_container}") + return False + except docker.errors.APIError as e: + logger.error(f"Docker API error while restarting container: {e}") + return False + except Exception as e: + logger.error(f"Unexpected error while restarting container: {e}") + return False + + def run(self): + """Main loop for the healthcheck""" + logger.info("Starting Puppeteer API healthcheck service") + + consecutive_failures = 0 + max_consecutive_failures = 3 # Restart after 3 consecutive failures + + while True: + try: + # Perform health check + if self.perform_health_check(): + consecutive_failures = 0 + logger.info("Health check passed - resetting failure counter") + else: + consecutive_failures += 1 + logger.warning(f"Health check failed - consecutive failures: {consecutive_failures}") + + # Restart container if we've had too many consecutive failures + if consecutive_failures >= max_consecutive_failures: + logger.error(f"Health check failed {consecutive_failures} times consecutively - restarting container") + if self.restart_container(): + consecutive_failures = 0 + logger.info("Container restarted successfully - resetting failure counter") + else: + logger.error("Failed to restart container") + + # Wait before next check + logger.info(f"Waiting {self.check_interval} seconds before next health check...") + time.sleep(self.check_interval) + + except KeyboardInterrupt: + logger.info("Healthcheck service stopped by user") + break + except Exception as e: + logger.error(f"Unexpected error in main loop: {e}") + time.sleep(self.check_interval) + +def main(): + """Main entry point""" + try: + healthcheck = PuppeteerHealthcheck() + healthcheck.run() + except Exception as e: + logger.error(f"Failed to start healthcheck service: {e}") + exit(1) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Dockers/puppeteer-healtcheck/requirements.txt b/Dockers/puppeteer-healtcheck/requirements.txt new file mode 100644 index 0000000..0659670 --- /dev/null +++ b/Dockers/puppeteer-healtcheck/requirements.txt @@ -0,0 +1,2 @@ +requests==2.31.0 +docker==6.1.3 \ No newline at end of file diff --git a/Dockers/puppeteer-healtcheck/version b/Dockers/puppeteer-healtcheck/version new file mode 100644 index 0000000..b9bc2fd --- /dev/null +++ b/Dockers/puppeteer-healtcheck/version @@ -0,0 +1 @@ +latest \ No newline at end of file