A modern web application for random selection from custom lists. Built with Java 17, deployed on GCP using Infrastructure as Code with complete CI/CD pipeline.
- 🎯 Random name selection from customizable lists
- ➕ Add new names dynamically via REST API
- 🎨 Modern gradient UI with responsive design
- 🔒 RESTful JSON API backend
- ☁️ Cloud-native deployment on GCP
- 🚀 Full CI/CD with GitHub Actions
- ✅ Unit testing with JUnit & Mockito
- 📊 Code quality with SonarCloud
- 🛡️ Security scanning with Snyk
┌─────────────────────────────────────────────────────┐
│ GitHub Actions │
│ Maven Build → SonarCloud → Snyk → Packer → Terraform│
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ Google Cloud Platform │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Compute │────│ VPC Network │ │
│ │ Instance │ │ & Firewall │ │
│ └──────────────┘ └──────────────┘ │
│ ↓ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Tomcat 9 │ │ Static IP │ │
│ │ + WAR File │ │ Address │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────┘
- Java: 17 (LTS)
- Servlet API: 4.0.1
- Gson: 2.10.1 (JSON processing)
- Build Tool: Apache Maven 3.6.3
- Cloud Provider: Google Cloud Platform
- VM OS: Ubuntu 22.04 LTS
- Web Server: Apache Tomcat 9.0.58
- IaC: Terraform (latest)
- Image Builder: Packer (latest)
- CI/CD: GitHub Actions
- Code Quality: SonarCloud
- Security: Snyk
- Testing: JUnit 4.13.2, Mockito 3.12.4
- State Management: GCS Backend
- Java 17 (JDK)
- Apache Maven 3.6+
- Git
- Google Cloud Platform account
- GCP Project with billing enabled
- Service Account with appropriate permissions
- GitHub account
- SonarCloud account (https://sonarcloud.io)
- Snyk account (https://snyk.io) - optional
git clone https://github.com/gcpt0801/pickstream.git
cd pickstreammvn clean packagemvn test# Deploy target/pickstream.war to your local Tomcat webapps/
# Access at http://localhost:8080/pickstream-
Create GCP Project
gcloud projects create YOUR_PROJECT_ID gcloud config set project YOUR_PROJECT_ID -
Enable Required APIs
gcloud services enable compute.googleapis.com gcloud services enable storage-api.googleapis.com
-
Create Service Account
gcloud iam service-accounts create pickstream-deployer \ --display-name="PickStream Deployer" gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \ --member="serviceAccount:pickstream-deployer@YOUR_PROJECT_ID.iam.gserviceaccount.com" \ --role="roles/compute.admin" gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \ --member="serviceAccount:pickstream-deployer@YOUR_PROJECT_ID.iam.gserviceaccount.com" \ --role="roles/iam.serviceAccountUser"
-
Generate Service Account Key
gcloud iam service-accounts keys create key.json \ --iam-account=pickstream-deployer@YOUR_PROJECT_ID.iam.gserviceaccount.com
-
Create GCS Bucket for Terraform State
gsutil mb -p YOUR_PROJECT_ID gs://YOUR-BUCKET-NAME
- Sign Up: https://sonarcloud.io
- Connect GitHub: Authorize SonarCloud to access your repository
- Create Organization: Use your GitHub username (e.g.,
gcpt0801) - Generate Token:
- Go to Account → Security → Generate Token
- Copy the token
- Sign Up: https://snyk.io
- Connect GitHub: Authorize Snyk
- Get API Token:
- Go to Account Settings → General → API Token
- Copy the token
Add the following secrets in your GitHub repository:
Settings → Secrets and variables → Actions → New repository secret
| Secret Name | Description | How to Get |
|---|---|---|
GCP_SA_KEY |
GCP Service Account JSON | Contents of key.json file |
SONAR_TOKEN |
SonarCloud API Token | From SonarCloud Account → Security |
SNYK_TOKEN |
Snyk API Token | From Snyk Account Settings (optional) |
-
Update
terraform/terraform.tfvars:project_id = "YOUR_PROJECT_ID" region = "us-central1" zone = "us-central1-a" instance_name = "pickstream-instance" machine_type = "e2-medium"
-
Update
terraform/backend.tf:terraform { backend "gcs" { bucket = "YOUR-BUCKET-NAME" prefix = "pickstream/terraform/state" } }
-
Update
packer/variables.pkrvars.hcl:project_id = "YOUR_PROJECT_ID" zone = "us-central1-a"
-
Commit and Push Changes:
git add terraform/terraform.tfvars terraform/backend.tf packer/variables.pkrvars.hcl git commit -m "Configure for deployment" git push
- Go to GitHub Actions: https://github.com/gcpt0801/pickstream/actions
- Select: "Build and Deploy to GCP"
- Click: "Run workflow"
- Select: Production environment
- Run workflow
The pipeline will:
- ✅ Build WAR file with Maven
- ✅ Run unit tests
- ✅ Analyze code with SonarCloud
- ✅ Scan for vulnerabilities with Snyk
- ✅ Create VM image with Packer
- ✅ Deploy infrastructure with Terraform
After successful deployment, the workflow will output:
🌐 Application URL: http://EXTERNAL_IP:8080/pickstream
📍 External IP: EXTERNAL_IP
- Open
http://EXTERNAL_IP:8080/pickstreamin browser - Click "Get Random Name" to select a random name
- Enter a name and click "Add Name" to add to the list
curl http://EXTERNAL_IP:8080/pickstream/api/random-nameResponse:
{
"name": "Alice Johnson"
}curl -X POST http://EXTERNAL_IP:8080/pickstream/api/random-name \
-d "name=John Doe"Response:
{
"success": true,
"message": "Name added successfully"
}pickstream/
├── src/
│ ├── main/
│ │ ├── java/com/example/webapp/
│ │ │ └── RandomNameServlet.java # Backend servlet
│ │ └── webapp/
│ │ └── index.html # Frontend UI
│ └── test/
│ └── java/com/example/webapp/
│ └── RandomNameServletTest.java # Unit tests
├── packer/
│ ├── image.pkr.hcl # Packer configuration
│ └── variables.pkrvars.hcl # Packer variables
├── terraform/
│ ├── backend.tf # Terraform backend
│ ├── compute.tf # GCP resources
│ ├── outputs.tf # Output values
│ ├── variables.tf # Variable definitions
│ └── terraform.tfvars # Variable values
├── .github/workflows/
│ ├── deploy-gcp.yml # Main deployment pipeline
│ ├── build.yml # Build & test only
│ ├── destroy.yml # Infrastructure cleanup
│ ├── pr-checks.yml # PR validation
│ └── cleanup.yml # Image cleanup
└── pom.xml # Maven configuration
# Run all tests
mvn test
# Run specific test class
mvn test -Dtest=RandomNameServletTest
# Run with coverage
mvn clean test jacoco:report# Run SonarCloud analysis locally (requires SONAR_TOKEN)
mvn sonar:sonar \
-Dsonar.projectKey=gcpt0801_pickstream \
-Dsonar.organization=gcpt0801 \
-Dsonar.host.url=https://sonarcloud.io \
-Dsonar.login=$SONAR_TOKEN# Clean build
mvn clean package
# Skip tests
mvn clean package -DskipTests
# Build with specific profile
mvn clean package -P productionTrigger: Manual (workflow_dispatch)
Purpose: Complete deployment pipeline
Stages:
- Maven Build & Test
- SonarCloud Analysis
- Snyk Security Scan
- Packer Image Build
- Terraform Destroy (existing resources)
- Terraform Apply (new deployment)
Trigger: Manual
Purpose: Quick validation without deployment
Trigger: Manual (requires typing "destroy")
Purpose: Clean up all cloud resources
Trigger: Manual
Purpose: Validate pull requests
Trigger: Manual
Purpose: Delete old Packer images
- Go to: https://github.com/gcpt0801/pickstream/actions
- Select: "Destroy GCP Infrastructure"
- Click: "Run workflow"
- Type:
destroyin confirmation field - Run workflow
This will remove:
- Compute Instance
- Static IP Address
- Firewall Rules
- VPC Network
Note: Packer images are retained. Delete manually if needed:
gcloud compute images list --filter="family:pickstream"
gcloud compute images delete IMAGE_NAME --project=YOUR_PROJECT_IDgcloud compute ssh pickstream-instance --zone=us-central1-a
sudo journalctl -u tomcat9 -fsudo systemctl status tomcat9https://sonarcloud.io/project/overview?id=gcpt0801_pickstream
# Check if instance is running
gcloud compute instances list
# Check firewall rules
gcloud compute firewall-rules list
# SSH into instance and check Tomcat
gcloud compute ssh pickstream-instance --zone=us-central1-a
sudo systemctl status tomcat9
sudo journalctl -u tomcat9 -n 50# Check JAVA_HOME
echo $JAVA_HOME
# Check Tomcat logs
sudo cat /var/log/tomcat9/catalina.out
# Verify WAR deployment
ls -la /var/lib/tomcat9/webapps/# Verify Java version
java -version
# Clean Maven cache
mvn dependency:purge-local-repository
# Rebuild
mvn clean install -U- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License.
- Repository: https://github.com/gcpt0801/pickstream
- SonarCloud: https://sonarcloud.io/project/overview?id=gcpt0801_pickstream
- GitHub Actions: https://github.com/gcpt0801/pickstream/actions
Ramesh Vellanki [ https://www.linkedin.com/in/ramesh-vellanki-b12760151/ ]
- GitHub: @gcpt0801
- Java Servlet API
- Google Cloud Platform
- HashiCorp (Terraform & Packer)
- SonarCloud
- Snyk
- GitHub Actions
Built with ❤️ using Java, GCP, and Infrastructure as Code