• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 9+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Server Monitoring Best Practices: Keeping Your WordPress App and MongoDB Clusters Alive on Google Cloud

Server Monitoring Best Practices: Keeping Your WordPress App and MongoDB Clusters Alive on Google Cloud

Proactive Health Checks for WordPress on Compute Engine

Maintaining a high-availability WordPress deployment on Google Cloud Compute Engine requires a multi-layered monitoring strategy. Beyond basic CPU and memory utilization, we need to inspect application-level metrics and ensure critical services are responsive. This involves setting up custom checks that go beyond the default Google Cloud Monitoring metrics.

A robust approach involves a combination of external synthetic monitoring and internal health checks. For internal checks, we can leverage a simple PHP script that verifies WordPress core functionality, theme/plugin health, and database connectivity. This script can be executed periodically via cron.

WordPress Application Health Script

Create a file named wp-health-check.php in your WordPress root directory. This script will attempt to load the WordPress environment, check for critical errors, and verify database connection. We’ll also add a simple check for a specific plugin’s existence and activation.

<?php
// wp-health-check.php

// Define a constant to prevent WordPress from loading its full header
define('WP_USE_THEMES', false);
define('SHORTINIT', true); // Load only essential WordPress files

// Include WordPress core
require_once('wp-load.php');

// --- Configuration ---
$critical_plugin = 'woocommerce/woocommerce.php'; // Example: WooCommerce plugin slug
$log_file = '/var/log/wordpress-health.log'; // Ensure this path is writable by the web server user
// ---------------------

function log_message($message) {
    global $log_file;
    $timestamp = date('Y-m-d H:i:s');
    file_put_contents($log_file, "[$timestamp] $message\n", FILE_APPEND);
}

function check_wp_core() {
    if (!defined('ABSPATH')) {
        log_message("ERROR: WordPress ABSPATH not defined. Core files may be missing or corrupted.");
        return false;
    }
    if (!file_exists(ABSPATH . 'wp-settings.php')) {
        log_message("ERROR: wp-settings.php not found. WordPress installation is incomplete.");
        return false;
    }
    return true;
}

function check_db_connection() {
    global $wpdb;
    if (!$wpdb) {
        log_message("ERROR: \$wpdb object not initialized. Database connection failed.");
        return false;
    }
    // Attempt a simple query to verify connection
    $result = $wpdb->query("SELECT 1");
    if ($result === false) {
        log_message("ERROR: Database query failed. Connection established but subsequent operations failed. Error: " . $wpdb->last_error);
        return false;
    }
    return true;
}

function check_plugin_activation($plugin_slug) {
    if (!function_exists('get_plugins')) {
        require_once ABSPATH . 'wp-admin/includes/plugin.php';
    }
    $all_plugins = get_plugins();

    if (!isset($all_plugins[$plugin_slug])) {
        log_message("WARNING: Critical plugin '$plugin_slug' not found.");
        return false;
    }

    if (!is_plugin_active($plugin_slug)) {
        log_message("WARNING: Critical plugin '$plugin_slug' is not active.");
        return false;
    }
    return true;
}

// --- Execution ---
log_message("Starting WordPress health check...");

$is_healthy = true;

if (!check_wp_core()) {
    $is_healthy = false;
}

if ($is_healthy && !check_db_connection()) {
    $is_healthy = false;
}

if ($is_healthy && !empty($critical_plugin)) {
    if (!check_plugin_activation($critical_plugin)) {
        $is_healthy = false;
    }
}

// You can add more checks here:
// - Check for specific theme activation
// - Check for common fatal error patterns in logs (requires log parsing)
// - Check if wp-cron is running (more complex, often relies on external checks)

if ($is_healthy) {
    log_message("WordPress health check passed.");
    http_response_code(200); // Indicate success
    exit(0); // Exit with success code
} else {
    log_message("WordPress health check FAILED.");
    http_response_code(500); // Indicate failure
    exit(1); // Exit with failure code
}
?>

Next, configure a cron job to execute this script. For production, it’s best to run this script via wget or curl from a separate, trusted host or a dedicated monitoring VM to simulate an external check. However, for internal checks, you can run it directly.

Cron Job for Internal Health Check

On your Compute Engine instance, add a cron entry. Ensure the user running the cron job has read/write permissions to the log file and read permissions to the WordPress files.

# Edit crontab for the web server user (e.g., www-data)
sudo crontab -u www-data -e

# Add the following line to run the check every 5 minutes:
*/5 * * * * /usr/bin/php /var/www/html/wp-health-check.php >> /var/log/wordpress-cron-health.log 2>&1

This cron job executes the PHP script and logs its output (including errors) to a separate log file. The script itself also logs detailed messages to /var/log/wordpress-health.log. You can then use Google Cloud Monitoring’s log-based metrics or custom metrics to ingest these logs and trigger alerts.

MongoDB Cluster Health and Performance Monitoring on GKE

Monitoring a MongoDB replica set or sharded cluster deployed on Google Kubernetes Engine (GKE) requires a different set of tools and metrics. We’ll focus on Prometheus and Grafana, which are industry standards for Kubernetes monitoring, and leverage the official MongoDB exporter.

Deploying Prometheus and Grafana on GKE

The easiest way to get started is by using the Prometheus community Helm chart. This chart deploys Prometheus, Alertmanager, and Grafana, pre-configured to scrape metrics from your cluster.

# Add the Prometheus community Helm repository
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

# Create a namespace for monitoring
kubectl create namespace monitoring

# Install Prometheus, Grafana, and Alertmanager
helm install prometheus prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --set grafana.adminPassword='your-strong-password' \
  --set prometheus.prometheusSpec.retention='2w' \
  --set alertmanager.config.global.resolve_timeout='5m'

After installation, you can access Grafana by port-forwarding the service:

kubectl port-forward svc/prometheus-grafana 8080:80 -n monitoring
# Access Grafana at http://localhost:8080 (default user: admin, password: your-strong-password)

Deploying MongoDB Exporter

We’ll deploy the official MongoDB exporter as a Kubernetes Deployment. This exporter will connect to your MongoDB instances and expose metrics in Prometheus format. Ensure your MongoDB instances are accessible from your GKE cluster. For security, consider using Private Google Access or VPC Network Peering if MongoDB is in a separate VPC.

First, create a Kubernetes Secret to store your MongoDB credentials.

apiVersion: v1
kind: Secret
metadata:
  name: mongodb-exporter-creds
  namespace: default # Or the namespace where your MongoDB is deployed
type: Opaque
stringData:
  # For replica sets, use a user with clusterMonitor role
  # For sharded clusters, use a user with clusterMonitor role on the admin DB
  MONGODB_USERNAME: "monitor_user"
  MONGODB_PASSWORD: "your_mongodb_password"
  MONGODB_HOST: "your-mongodb-service-name.your-namespace.svc.cluster.local" # e.g., mongo-replica-set.default.svc.cluster.local
  MONGODB_PORT: "27017"
  MONGODB_AUTHENTICATION_DATABASE: "admin" # Usually 'admin' for auth

Then, deploy the exporter using a Deployment manifest. This example assumes a replica set. Adjust the MONGODB_URI for sharded clusters.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongodb-exporter
  namespace: default # Match the namespace of the secret
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongodb-exporter
  template:
    metadata:
      labels:
        app: mongodb-exporter
    spec:
      containers:
      - name: mongodb-exporter
        image: percona/mongodb_exporter:latest # Or a specific version
        ports:
        - containerPort: 9274 # Default exporter port
        env:
        - name: MONGODB_USERNAME
          valueFrom:
            secretKeyRef:
              name: mongodb-exporter-creds
              key: MONGODB_USERNAME
        - name: MONGODB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mongodb-exporter-creds
              key: MONGODB_PASSWORD
        - name: MONGODB_HOST
          valueFrom:
            secretKeyRef:
              name: mongodb-exporter-creds
              key: MONGODB_HOST
        - name: MONGODB_PORT
          valueFrom:
            secretKeyRef:
              name: mongodb-exporter-creds
              key: MONGODB_PORT
        - name: MONGODB_AUTHENTICATION_DATABASE
          valueFrom:
            secretKeyRef:
              name: mongodb-exporter-creds
              key: MONGODB_AUTHENTICATION_DATABASE
        # For replica sets, specify the replica set name and use a comma-separated list of hosts
        # Example: MONGODB_URI: "mongodb://monitor_user:[email protected]:27017,mongo2.svc.cluster.local:27017/admin?replicaSet=rs0&authSource=admin"
        # For sharded clusters, use the mongos service name
        # Example: MONGODB_URI: "mongodb://monitor_user:your_mongodb_password@your-mongos-service.default.svc.cluster.local:27017/admin?authSource=admin"
        command: ["/mongodb_exporter"]
        args:
          - "--mongodb.uri=mongodb://$(MONGODB_USERNAME):$(MONGODB_PASSWORD)@$(MONGODB_HOST):$(MONGODB_PORT)/$(MONGODB_AUTHENTICATION_DATABASE)?authSource=$(MONGODB_AUTHENTICATION_DATABASE)"
          # Add --mongodb.replicaSet=rs0 if using replica sets and it's not in the URI
          # Add --mongodb.sharded=true if using sharded clusters
          # Add --web.listen-address=":9274" if not default
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "200m"
            memory: "256Mi"

---
apiVersion: v1
kind: Service
metadata:
  name: mongodb-exporter
  namespace: default # Match the namespace of the deployment
spec:
  selector:
    app: mongodb-exporter
  ports:
  - protocol: TCP
    port: 9274
    targetPort: 9274
  type: ClusterIP

Once deployed, Prometheus will automatically discover and scrape metrics from the mongodb-exporter service if you’re using the kube-prometheus-stack chart, which includes a ServiceMonitor resource. You might need to create a ServiceMonitor resource manually if you’re not using the full stack or if your MongoDB exporter is in a different namespace.

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: mongodb-exporter-monitor
  namespace: monitoring # Namespace where Prometheus is running
spec:
  selector:
    matchLabels:
      app: mongodb-exporter # Label on your mongodb-exporter service
  namespaceSelector:
    matchNames:
      - default # Namespace where your mongodb-exporter service is running
  endpoints:
  - port: "9274" # The port your exporter is listening on
    interval: 30s
    path: /metrics # Default metrics path

Key MongoDB Metrics to Monitor

  • Replication Lag: mongodb_replset_member_state (check for secondary members not being in PRIMARY state or having significant oplog lag).
  • Connections: mongodb_connections_current, mongodb_connections_available.
  • Operations: mongodb_opcounters_insert, mongodb_opcounters_query, mongodb_opcounters_update, mongodb_opcounters_delete (rate of operations).
  • Locking: mongodb_locks_current_global, mongodb_locks_time_acquiring_micros (high values indicate contention).
  • Memory: mongodb_memory_resident, mongodb_memory_virtual, mongodb_wiredtiger_cache_bytes_used.
  • Disk I/O: mongodb_disk_read_bytes, mongodb_disk_write_bytes.
  • Network: mongodb_network_bytes_in, mongodb_network_bytes_out.
  • Cursor: mongodb_cursors_total, mongodb_cursors_timed_out.
  • Slow Operations: mongodb_slow_queries_total.

Import pre-built MongoDB dashboards into Grafana (e.g., from Grafana.com) or create custom ones focusing on these key metrics. Set up Alertmanager rules for critical conditions like replication lag exceeding a threshold, high connection counts, or excessive slow queries.

Integrating with Google Cloud Monitoring

While Prometheus provides deep Kubernetes and application-level insights, integrating critical alerts and metrics with Google Cloud Monitoring (formerly Stackdriver) offers a unified view and leverages GCP’s alerting infrastructure. This is crucial for centralized incident management.

Forwarding WordPress Health Check Alerts

For the WordPress health check script, we can create a log-based metric in Google Cloud Monitoring. This metric will count occurrences of “FAILED” in the /var/log/wordpress-health.log file.

# In Google Cloud Console:
# Navigate to Monitoring -> Logs-based Metrics -> Create Metric
# Metric Type: Counter
# Name: wordpress_health_failures
# Log query:
# resource.type="gce_instance"
# logName="projects/YOUR_PROJECT_ID/logs/wordpress-health.log"
# textPayload:"FAILED"
# Units: 1 (count)

Once the metric is created, you can set up an alerting policy in Google Cloud Monitoring that triggers when the value of wordpress_health_failures is greater than 0 over a specified period (e.g., 5 minutes).

Forwarding MongoDB Alerts from Alertmanager

To get MongoDB alerts into Google Cloud Monitoring, configure Alertmanager to send notifications to Google Cloud’s operations suite. This typically involves setting up a webhook receiver in Alertmanager that points to a Google Cloud Logging sink or a custom Pub/Sub topic that’s then processed.

A simpler approach for critical alerts is to use Prometheus’s native integration with Google Cloud Monitoring. The kube-prometheus-stack chart can be configured to send alerts directly to GCP.

# values.yaml for kube-prometheus-stack helm chart
alertmanager:
  config:
    global:
      resolve_timeout: 5m
    route:
      group_by: ['alertname', 'cluster', 'service']
      group_wait: 30s
      group_interval: 5m
      repeat_interval: 1h
      receiver: 'google-cloud' # Name of the receiver
    receivers:
    - name: 'google-cloud'
      webhook_configs:
      - url: 'http://google-cloud-monitoring-webhook.monitoring.svc.cluster.local/alert' # This requires a custom webhook receiver or a managed solution
        send_resolved: true

# Alternatively, configure Prometheus to push metrics to Google Cloud Monitoring
# This is often done via the Prometheus GCP Exporter or by configuring Prometheus itself
# to use the GCP remote_write endpoint if available.
# For Alertmanager, consider using a dedicated GCP integration or a Pub/Sub webhook.

A more direct method for Prometheus alerts is to configure Prometheus to use Google Cloud Monitoring as a remote write target. This pushes Prometheus metrics directly into GCP, allowing you to create alerting policies within GCP based on these metrics.

# values.yaml for kube-prometheus-stack helm chart
prometheus:
  prometheusSpec:
    retention: 2w
    remoteWrite:
      - url: "https://monitoring.googleapis.com/v1/projects/YOUR_PROJECT_ID/timeSeries:create"
        # Authentication might require additional configuration, e.g., service account credentials
        # or using workload identity for GKE.
        # This is a simplified example; actual configuration can be complex.
        # Consider using the GCP Managed Prometheus service for easier integration.

For Alertmanager, you can configure a receiver to send alerts to a Google Cloud Logging sink via Pub/Sub. Create a Pub/Sub topic, a Logging sink that routes Alertmanager logs to this topic, and then configure Alertmanager to send notifications to this Pub/Sub topic.

Conclusion

A comprehensive monitoring strategy for WordPress on Compute Engine and MongoDB on GKE involves combining application-specific checks, Kubernetes-native monitoring tools like Prometheus, and the centralized alerting and metric ingestion capabilities of Google Cloud Monitoring. By implementing these practices, you gain visibility into the health and performance of your critical services, enabling proactive issue detection and rapid response.

Primary Sidebar

A little about the Author

Having 9+ Years of Experience in Software Development.
Expertised in Php Development, WordPress Custom Theme Development (From scratch using underscores or Genesis Framework or using any blank theme or Premium Theme), Custom Plugin Development. Hands on Experience on 3rd Party Php Extension like Chilkat, nSoftware.

Recent Posts

  • How to Optimize Largest Contentful Paint (LCP) and Interaction to Next Paint (INP) in Large-Scale WooCommerce Enterprise Sites
  • Server Monitoring Best Practices: Keeping Your Laravel App and Elasticsearch Clusters Alive on Linode
  • Resolving thread pools deadlock during concurrent ActiveRecord transaction processing Under Peak Event Traffic on OVH
  • Eliminating PostgreSQL Bottlenecks: Tuning Queries for High-Performance Laravel Stores
  • The Ultimate DevOps Playbook: Tuning Nginx, Gunicorn/FPM, and DynamoDB on OVH for Magento 2

Copyright © 2026 · Vinay Vengala