# Dashboard Production Infrastructure (Drupal + GCP)

## Overview

- Production Drupal setup running on Google Cloud with 
  - Load Balancer
  - Managed Instance Group
  - Apache + PHP-FPM
  - Cloud SQL
  - Filestore.

------------------------------------------------------------------------

## Architecture

Internet → Load Balancer → MIG (us-central1-c) → Apache + PHP-FPM → Drupal → Cloud SQL → Filestore

------------------------------------------------------------------------

## Core Resources

- Project: budvue 
- Zone: us-central1-c 
- VPC: dashboard-vpc
  - Private Subnet IP Range: 172.16.1.0/24
  - Public Subnet IP Range: 172.16.0.0/24
- Base VM: dashboard-prob-web1-base
- Managed Instance Group: dashboard-web-mig 
- Image Family: dashboard-prod
- Machine Type: e2-standard-2

------------------------------------------------------------------------

## Web Stack

- OS: Ubuntu 22.04 
- Apache: 2.4 
- PHP: 8.3 (FPM/FastCGI) 
- Drupal: 10 
- Database: Cloud SQL MySQL
  - Cloud SQL:  dashboard-prod-db1
  - Cloud SQL User: dashboard-prod-db1
  - Cloud SQL Host: 10.176.224.3

------------------------------------------------------------------------

## Important Paths

- App root: /var/www/html/web 
- Settings: /var/www/html/web/sites/default/settings.php 
- Files: /var/www/html/web/sites/default/files 
- Filestore mount: /mnt/filestore
- Apache vhost: /etc/apache2/sites-enabled/cstv.conf 
- Logs: /var/log/apache2/cstv_error.log

------------------------------------------------------------------------

## Filestore (Shared Storage)

- Filestore: dashboard-filestore
- Reserved IP range: 10.176.225.0/26
- /mnt/filestore mounted on all VMs files → symlinked to /mnt/filestore
- fstab example: 10.x.x.x:/dashboard_filestore /mnt/filestore nfs defaults,\_netdev 0 0
- Permissions: chown -R www-data:www-data /mnt/filestore & chmod -R 775 /mnt/filestore

------------------------------------------------------------------------

## Apache PHP-FPM Config

\<FilesMatch .php\$\> SetHandler
"proxy:unix:/run/php/php8.3-fpm.sock\|fcgi://localhost/"
`</FilesMatch>`{=html}

------------------------------------------------------------------------

## Health Check

- Endpoint: /healthcheck (Always returns HTTP 200)

------------------------------------------------------------------------

## Drupal Reverse Proxy Settings

- \$settings\['reverse_proxy'\] = TRUE;
- \$settings\['reverse_proxy_addresses'\] = \[ '127.0.0.1', '10.0.0.0/8', '172.16.0.0/12',\];
- \$settings\['reverse_proxy_trusted_headers'\] =
Request::HEADER_X\_FORWARDED_FOR \| Request::HEADER_X\_FORWARDED_HOST \|
Request::HEADER_X\_FORWARDED_PORT \| Request::HEADER_X\_FORWARDED_PROTO;

------------------------------------------------------------------------

## Useful Commands

- Drush: vendor/bin/drush cr & vendor/bin/drush ws
- Services: systemctl restart apache2 & systemctl restart php8.3-fpm
- Logs: tail -f /var/log/apache2/cstv_error.log journalctl -u php8.3-fpm-f

------------------------------------------------------------------------

## Redis

Currently disabled. Enable only after external Redis server is
configured.

------------------------------------------------------------------------

## Connecting to VMs (Debugging & Deployment)

### Add SSH Key

Add your SSH key to **GCP Project Metadata**

IMPORTANT: Replace username with cloud-user

Example:

```
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ... cloud-user
```

---

### Connect to Bastion

```
ssh cloud-user@<bastion-ip>
```

---

### From Bastion → Base or MIG VM

```
ssh cloud-user@<base-vm-ip>
ssh cloud-user@<mig-vm-ip>
```

---

## SSH Shortcut (Recommended)

Edit local machine config:

```
~/.ssh/config
```

Add:

```
Host gcp-bastion
  HostName 34.56.32.65
  User cloud-user

Host 172.16.1.*
  User cloud-user
  ProxyJump gcp-bastion
```

Now simply run:

```
ssh 172.16.1.5
```

Tunnel is handled automatically.

------------------------------------------------------------------------

## Deployment Workflow

### Golden image approach

1. Update code/config on **base VM**
2. Run deployment script
3. Script:
   - snapshot boot disk
   - create image
   - create template
   - rolling update MIG

### Why this works

• Ensures every VM has identical config  
• Zero downtime rolling update  
• Easy rollback (use older image/template)

---

## Deployment Script Explanation

Script performs:

### Step 1 – Snapshot
Creates snapshot of base VM boot disk.

### Step 2 – Image
Creates reusable image from snapshot.

### Step 3 – Template
Creates instance template using:
- same machine type
- same subnet
- same service account
- new image

### Step 4 – Rolling Update
Updates MIG safely:

```
--max-surge=1
--max-unavailable=1
```

This replaces one VM at a time.

### Step 5 – Cleanup
Deletes old images automatically.

------------------------------------------------------------------------

## Code Deployment Steps

1. SSH to base VM
2. Pull latest code
3. Clear caches
4. Verify site
5. Run deployment script

Example:
Switch to deploy user
```
sudo su - deploy 
```
Run below commands in order:
```
cd /var/www/html
git pull
composer install
vendor/drush/drush/drush cim
vendor/drush/drush/drush cr
exit
```
Switch to root user to run auto-scaling
```
sudo -i
cd /home/scripts
./auto-scale.sh
```

------------------------------------------------------------------------

## Additional Information
### k6 Load Testing Setup
  - Install k6
    - macOS (Homebrew)
      ```brew install k6```
    - Linux (Ubuntu/Debian)
    ```
    sudo apt update
    sudo apt install -y gnupg software-properties-common

    # Add k6 repo
    sudo mkdir -p /etc/apt/keyrings
    curl -fsSL https://dl.k6.io/key.gpg | sudo gpg --dearmor -o /etc/apt/keyrings/k6-archive-keyring.gpg

    echo "deb [signed-by=/etc/apt/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list

    sudo apt update
    sudo apt install k6
    ```
    - Windows (Chocolatey)
    ```
    choco install k6
    ```
  - Verify installation
    ```k6 version```
  - Once done, run below command to exectue the test
    ```k6 run drupal-load-test.js``` 