{"id":28480541,"url":"https://github.com/remla25-team21/operation","last_synced_at":"2026-04-10T03:01:01.410Z","repository":{"id":291138170,"uuid":"976204937","full_name":"remla25-team21/operation","owner":"remla25-team21","description":null,"archived":false,"fork":false,"pushed_at":"2025-06-26T09:21:20.000Z","size":1162,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-03T19:45:21.258Z","etag":null,"topics":["ansible","docker-compose","grafana","helm","istio","k8s","kubernetes","prometheus","vagrant"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/remla25-team21.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-01T17:29:16.000Z","updated_at":"2025-06-25T22:39:21.000Z","dependencies_parsed_at":"2025-05-02T16:57:21.399Z","dependency_job_id":"1588a748-b19a-4310-a510-83635b1908e1","html_url":"https://github.com/remla25-team21/operation","commit_stats":null,"previous_names":["remla25-team21/operation"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/remla25-team21/operation","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remla25-team21%2Foperation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remla25-team21%2Foperation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remla25-team21%2Foperation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remla25-team21%2Foperation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/remla25-team21","download_url":"https://codeload.github.com/remla25-team21/operation/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remla25-team21%2Foperation/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265575530,"owners_count":23790784,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","docker-compose","grafana","helm","istio","k8s","kubernetes","prometheus","vagrant"],"created_at":"2025-06-07T19:06:43.467Z","updated_at":"2026-04-10T03:01:01.362Z","avatar_url":"https://github.com/remla25-team21.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Operation Repository\r\n\r\nThis is the central repository for a REMLA project by Group 21. The application performs sentiment analysis on user feedback using a machine learning model. This repository orchestrates the following components hosted in separate repositories:\r\n\r\n- [`model-training`](https://github.com/remla25-team21/model-training): Contains the machine learning training pipeline.\r\n- [`lib-ml`](https://github.com/remla25-team21/lib-ml): Contains data pre-processing logic used across components.\r\n- [`model-service`](https://github.com/remla25-team21/model-service): A wrapper service for the trained ML model. Exposes API endpoints to interact with the model.\r\n- [`lib-version`](https://github.com/remla25-team21/lib-version): A version-aware utility library that exposes version metadata.\r\n- [`app`](https://github.com/remla25-team21/app): Contains the application frontend and backend (user interface and service logic). \r\n\r\n## Table of Contents \r\n- [How to Start the Application (Assignment 1)](#how-to-start-the-application-assignment-1)\r\n- [Kubernetes Cluster Provisioning (Assignment 2)](#kubernetes-cluster-provisioning-assignment-2)\r\n- [Kubernetes Cluster Monitoring (Assignment 3)](#kubernetes-cluster-monitoring-assignment-3)\r\n- [ML Configuration Management \\\u0026 ML Testing （Assignment 4）](#ml-configuration-management--ml-testing-assignment-4)\r\n- [Istio Service Mesh（Assignment 5）](#istio-service-meshassignment-5)\r\n   - [Method 1: Using Vagrant/Ansible Cluster](#method-1-using-vagrantansible-cluster)\r\n   - [Deploy the Istio-based Setup](#deploy-the-istio-based-setup)\r\n   - [Verify Sticky Sessions](#verify-sticky-sessions)\r\n   - [Method 2: Using Local Minikube](#method-2-using-local-minikube)\r\n   - [Quick Start with Automated Script](#quick-start-with-automated-script)\r\n   - [Manual Setup and Deploy](#manual-setup-and-deploy)\r\n   - [Verify Sticky Sessions](#verify-sticky-sessions-1)\r\n   - [Continuous Experimentation](#continuous-experimentation)\r\n   - [Additional Use Case: Rate Limiting](#additional-use-case-rate-limiting)\r\n- [Known Issue: macOS Port Conflict (AirPlay Receiver)](#known-issue-macos-port-conflict-airplay-receiver)\r\n- [Activity Tracking](#activity-tracking)\r\n- [Grade Expectation](#grade-expectation)\r\n\r\n## How to Start the Application (Assignment 1)\r\n\r\n1. Clone the repository:\r\n\r\n   ```bash\r\n   git clone https://github.com/remla25-team21/operation.git\r\n   ```\r\n\r\n2. Navigate into the project directory and start the app with Docker Compose:\r\n\r\n   ```bash\r\n   cd kubernetes\r\n   docker-compose pull \u0026\u0026 docker-compose up -d\r\n   ```\r\n\r\nThe frontend will be available at [`http://localhost:3000`](http://localhost:3000) by default.\r\n\r\n## Kubernetes Cluster Provisioning (Assignment 2)\r\n\r\nKindly refer to additonal steps provided in instructions related to Assignment 5 since introducing Istio brought additional complexities, and certain initial setups need to be done before proceeding. (Especially moving the correct `rate-limit.yaml` file)\r\n\r\nThese steps guide you through setting up the Kubernetes cluster on your local machine using Vagrant and Ansible, and deploying the Kubernetes Dashboard.\r\n\r\n1. Install GNU parallel:\r\n   Before running the setup script, make sure GNU parallel is installed on your system:\r\n   - For Debian/Ubuntu:\r\n\r\n      ```bash\r\n      sudo apt-get install parallel\r\n      ```\r\n\r\n   - For Red Hat/CentOS:\r\n\r\n      ```bash\r\n      sudo yum install parallel\r\n      ```\r\n\r\n   - For macOS:\r\n\r\n      ```bash\r\n      brew install parallel\r\n      ```\r\n\r\n2. Run the setup script:\r\n\r\n   ```bash\r\n   chmod +x setup_cluster.sh\r\n   ./setup_cluster.sh\r\n   ```\r\n\r\n3. Access Kubernetes dashboard:\r\n   - After the script completes, open your web browser and navigate to: [`https://dashboard.local`](https://dashboard.local) (**HTTPS** is required).\r\n   - You will see a token displayed in your terminal. Copy and paste this token into the Kubernetes Dashboard login page. \r\n\r\n4. Remove the cluster:\r\n   If you want to remove the cluster, run the following command:\r\n\r\n   ```bash\r\n   vagrant destroy -f\r\n   ```\r\n\r\n   This will remove all the VMs and the Kubernetes cluster.\r\n\r\n## Kubernetes Cluster Monitoring (Assignment 3)\r\n\r\nRefer to [`README.md`](./kubernetes/helm/sentiment-analysis/README.md) in the `kubernetes/helm/sentiment-analysis` directory for instructions to set up Prometheus and Grafana for monitoring.\r\n\r\n## ML Configuration Management \u0026 ML Testing （Assignment 4）\r\n\r\nWork for Assignment 4 is mainly in the following repositories:\r\n\r\n- [`model-training`](https://github.com/remla25-team21/model-training)\r\n- [`model-service`](https://github.com/remla25-team21/model-service)\r\n\r\nSee their READMEs for setup and testing details.\r\n\r\n## Istio Service Mesh（Assignment 5）\r\n\r\nTwo methods are available for deploying the application with Istio service mesh:\r\n\r\n- [Method 1](#method-1-using-vagrantansible-cluster): Using Vagrant/Ansible Cluster from Assignment 2\r\n- [Method 2](#method-2-using-local-minikube): Using Local Minikube\r\n\r\n### Method 1: Using Vagrant/Ansible Cluster\r\n\r\nRun the following command to start up the local Kubernetes cluster. (Make sure that you have GNU Parallel installed. Details in [Section 2](#kubernetes-cluster-provisioning-assignment-2). )\r\n\r\n#### Deploy the Istio-based Setup\r\n1. Run the following commands to properly configure the setup for Vagrant:\r\n   First, backing up the existing file:\r\n   ```bash\r\n   mv kubernetes/helm/sentiment-analysis/templates/rate-limit.yaml \\\r\n   kubernetes/extra/rate-limit.minikube.yaml\r\n   ```\r\n   Then, moving the required file:\r\n   ```bash\r\n   mv kubernetes/extra/rate-limit.vagrant.yaml \\\r\n   kubernetes/helm/sentiment-analysis/templates/rate-limit.yaml\r\n   ```\r\n\r\n2. Start the local cluster:\r\n\r\n   ```bash\r\n   chmod +x setup_cluster.sh\r\n   ./setup_cluster.sh\r\n   ```\r\n\r\n3. SSH into the control node:  \r\n\r\n   ```bash\r\n   vagrant ssh ctrl\r\n   ```\r\n\r\n4. Deploy the application using Helm:\r\n\r\n   ```bash\r\n   cd /vagrant\r\n   GATEWAY_IP=$(kubectl get svc istio-ingressgateway -n istio-system -o jsonpath='{.status.loadBalancer.ingress[0].ip}')\r\n   helm install my-sentiment-analysis ./kubernetes/helm/sentiment-analysis --set istio.ingressGateway.host=$GATEWAY_IP\r\n   ```\r\n\r\n   \u003e [!NOTE]\r\n   \u003e It may take a few minutes for all pods to become ready.\r\n   \u003e You can monitor the status with:\r\n   \u003e\r\n   \u003e ```bash\r\n   \u003e kubectl get pods\r\n   \u003e ```\r\n\r\n5. Access the frontend from [`http://192.168.56.91`](http://192.168.56.91).\r\n\r\n#### Verify Sticky Sessions\r\n\r\nSticky routing is enabled in `DestinationRule`. You can use `curl` to simulate multiple users:\r\n\r\n```bash\r\nfor i in {1..5}; do curl -s -H \"user: 6\" http://192.168.56.91/env-config.js; done\r\nfor i in {1..5}; do curl -s -H \"user: 10\" http://192.168.56.91/env-config.js; done\r\n```\r\n\r\nUsers `6` and `10` should always see the same version on each reload.\r\n\r\n### Method 2: Using Local Minikube\r\n\r\nThis alternative approach uses Minikube directly on your local machine without Vagrant/Ansible.\r\n\r\n#### Before Starting:\r\nIf you previously configured the rate limiting setup for Vagrant, and now want to revert to the default Minikube setup, follow these steps:\r\n```bash\r\nmv kubernetes/helm/sentiment-analysis/templates/rate-limit.yaml \\\r\nkubernetes/extra/rate-limit.vagrant.yaml\r\n```\r\n```bash\r\nmv kubernetes/extra/rate-limit.minikube.yaml \\\r\nkubernetes/helm/sentiment-analysis/templates/rate-limit.yaml\r\n```\r\n\r\n**Note:** If you never configured the project for Vagrant, you can ignore this step — the default Minikube configuration is already in place.\r\n\r\n#### Quick Start with Automated Script\r\n\r\nWe provide an automated script that handles the entire setup process:\r\n\r\n```bash\r\nchmod +x start_minikube.sh\r\n./start_minikube.sh --step 1\r\n\r\nminikube tunnel  # Keep this running in a separate terminal\r\n\r\n./start_minikube.sh --step 2\r\n```\r\n\r\n\u003e [!NOTE]\r\n\u003e\r\n\u003e Please refer to the [Manual Setup and Deploy](#manual-setup-and-deploy) section below if you encounter any issues with the script or prefer to run commands individually.\r\n\r\nThis script will:\r\n\r\n- Delete any existing Minikube clusters\r\n- Start Minikube with appropriate resources\r\n- Install Prometheus stack\r\n- Install Istio and its add-ons\r\n- Deploy the application\r\n- Start the Minikube tunnel\r\n- Display access URLs for all services\r\n\r\nThe script will output instructions for accessing all components when it completes.\r\n\r\n#### Manual Setup and Deploy\r\n\r\nIf you prefer to run commands individually:\r\n\r\n1. Clean up any existing Minikube clusters:\r\n\r\n   ```bash\r\n   minikube delete --all \r\n   ```\r\n\r\n2. Start and configure Minikube:\r\n\r\n   ```bash\r\n   minikube start  --memory=4096 --cpus=4 --driver=docker\r\n   minikube addons enable ingress\r\n   ```\r\n\r\n   \u003e Note: Resource requirements (4GB RAM, 4 CPUs) can be adjusted based on your machine's capabilities.\r\n\r\n3. Install Prometheus stack using Helm:\r\n\r\n   ```bash\r\n   helm repo add prometheus-community https://prometheus-community.github.io/helm-charts\r\n   helm repo update\r\n   helm install prometheus prometheus-community/kube-prometheus-stack --namespace monitoring --create-namespace\r\n   ```\r\n\r\n4. Install Istio and its add-ons:\r\n\r\n   ```bash\r\n   istioctl install -y\r\n   kubectl apply -f kubernetes/istio-addons/prometheus.yaml\r\n   kubectl apply -f kubernetes/istio-addons/jaeger.yaml\r\n   kubectl apply -f kubernetes/istio-addons/kiali.yaml\r\n   kubectl label ns default istio-injection=enabled --overwrite\r\n   ```\r\n\r\n⚠️ Important Note for Apple Silicon (M1/M2/M3) Users (Else you can skip this step)\r\n\r\nOn Apple Silicon Macs, the default file-sharing mechanism for Minikube is more restrictive. To allow the application's hostPath volume to mount correctly, you must first manually create a link between your Mac and the Minikube VM.\r\n\r\nCreate a local directory on your Mac (y:\r\n\r\n```bash\r\nmkdir -p ~/data/shared\r\n```\r\n\r\nOpen the mount tunnel:\r\n\r\n```bash\r\nminikube mount ~/data/shared:/mnt/shared # Keep this running in a separate terminal\r\n```\r\nYou must keep this mount command running in its own terminal before proceeding with the steps below.\r\n\r\n\r\n5. Open the tunnel for Istio ingress gateway:\r\n\r\n   ```bash\r\n   minikube tunnel  # Keep this running in a `separate` terminal\r\n   ```\r\n\r\n\r\n\r\n6. Deploy the application using Helm:\r\n\r\n   ```bash\r\n   GATEWAY_IP=$(kubectl get svc istio-ingressgateway -n istio-system -o jsonpath='{.status.loadBalancer.ingress[0].ip}')\r\n\r\n   helm install my-sentiment-analysis ./kubernetes/helm/sentiment-analysis --set istio.ingressGateway.host=$GATEWAY_IP\r\n   ```\r\n\r\n7. Forward necessary ports in separate terminals:\r\n\r\n   ```bash\r\n   kubectl -n monitoring port-forward svc/prometheus-kube-prometheus-prometheus 9090:9090\r\n   kubectl -n monitoring port-forward service/prometheus-grafana 3300:80\r\n   kubectl -n istio-system port-forward svc/kiali 20001:20001\r\n   ```\r\n\r\n   \u003e Note: Keep these commands running in separate terminals.\r\n\r\n8. Access different interfaces:\r\n\r\n   ```bash\r\n   kubectl get svc istio-ingressgateway -n istio-system\r\n   ```\r\n\r\n   - Application: Access the url output by `kubectl get svc istio-ingressgateway -n istio-system` as [EXTERNAL-IP].\r\n   - Prometheus: [`http://localhost:9090`](http://localhost:9090)\r\n   - Grafana: [`http://localhost:3300`](http://localhost:3300)\r\n   - Kiali: [`http://localhost:20001`](http://localhost:20001)\r\n\r\n#### Verify Sticky Sessions\r\n\r\nFor this setup, test sticky sessions with:\r\n\r\n```bash\r\nfor i in {1..5}; do curl -s -H \"user: 6\" http://[EXTERNAL-IP]/env-config.js; done\r\nfor i in {1..5}; do curl -s -H \"user: 10\" http://[EXTERNAL-IP]/env-config.js; done\r\n```\r\n### Continuous Experimentation \r\n\r\nWe used Istio’s traffic routing to run an A/B test between two frontend versions. Prometheus collected usage and satisfaction metrics, and the outcome was visualized in Grafana. Details are in [`docs/continuous-experimentation.md`](./docs/continuous-experimentation.md). \r\n\r\n### Additional Use Case: Rate Limiting \r\n\r\nTo protect the application from abuse and ensure fair usage across users, we implemented rate limiting using an Istio `EnvoyFilter`. This configuration limits each unique `x-user-id` header to 10 requests per minute on the inbound sidecar. \r\n\r\nWe used two `EnvoyFilter` resources:\r\n   - The first inserts the `envoy.filters.http.local_ratelimit` filter into the inbound HTTP filter chain. It defines a token bucket allowing 10 requests every 60 seconds per user.\r\n   - The second configures route-level rate limits by matching the `x-user-id` header and enforcing the per-user descriptor.\r\n\r\nThe response will include a custom header `x-local-rate-limit: true` when rate limiting is triggered.\r\n\r\nTo test rate limiting:\r\n**Vagrant:** Send more than 10 requests a minute, rate limiting will be applied, however, at a global scale.\r\n**Minikube:** Run the following:\r\n```bash\r\nfor i in {1..12}; do curl -s -o /dev/null -w \"User 6 - Request $i: %{http_code}\\n\" -H \"x-user-id: 6\" http://127.0.0.1/env-config.js; done    \r\n```\r\nAnd then run immediately after:\r\n```bash\r\nfor i in {1..12}; do curl -s -o /dev/null -w \"User 8 - Request $i: %{http_code}\\n\" -H \"x-user-id: 8\" http://127.0.0.1/env-config.js; done    \r\n```\r\nYou will be able to see that both users are able to send 10 requests individually, before being rate limited, proving that rate limiting of 10 is applied per unique user id.\r\n\r\n## Known Issue: macOS Port Conflict (AirPlay Receiver)\r\n\r\nIf `app-service` fails to bind to port 5000, macOS's AirPlay Receiver may be using it.\r\n\r\n**Temporary Workaround**\r\n\r\n1. Go to System Settings -\u003e General -\u003e Airdrop \u0026 Handoff and switch off Airplay Receiver.\r\n2. Go to the terminal and use kill any process on port 5000:\r\n   ```bash\r\n   lsof -i :5000\r\n   kill -9 \u003cPID\u003e\r\n   ```\r\n\r\n**Long Term Fix**\r\n\r\nWe plan to eventually change `app-service` to accommodate environment variables, which should allow users to freely change ports via the `docker-compose.yml` file. \r\n\r\n## Activity Tracking\r\n\r\nSee [`ACTIVITY.md`](./ACTIVITY.md) for an overview of team contributions. \r\n\r\n## Grade Expectation\r\n\r\nTo assist with the evaluation of our project, we have included a [`Grade_Expectation.md`](./Grade_Expectation.md) that outlines how our implementation aligns with the grading criteria. This document is intended to make the grading process more straightforward and transparent. \r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremla25-team21%2Foperation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fremla25-team21%2Foperation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremla25-team21%2Foperation/lists"}