├── .gitignore ├── README.md ├── client ├── App.tsx ├── components │ ├── ChartTable.tsx │ ├── ClusterInput.tsx │ ├── GuageChart.tsx │ ├── GuageChart2.tsx │ ├── LineChart2.tsx │ ├── Navbar.tsx │ └── SnapshotButton.tsx ├── index.tsx ├── pages │ ├── Dashboard.tsx │ ├── History.tsx │ ├── NotFoundPage.tsx │ ├── SignIn.tsx │ ├── Signup.tsx │ ├── SnapshotPage.tsx │ ├── SplashPage.tsx │ └── WelcomePage.tsx ├── public │ ├── Assets │ │ ├── GPU image.jpg:Zone.Identifier │ │ ├── GPU-image.jpg │ │ ├── Ismael LinkedIn Headshot.jpg:Zone.Identifier │ │ ├── Ismael-Headshot.jpg │ │ ├── Jeff Headshot.jpg:Zone.Identifier │ │ ├── Jeff-Headshot.jpg │ │ ├── Jin Headshot.jpg:Zone.Identifier │ │ ├── Jin-Headshot.jpg │ │ ├── Sonia-Headshot.jpg │ │ ├── demo │ │ │ ├── auto_refresh.gif │ │ │ ├── input_url.gif │ │ │ ├── save_snapshot.gif │ │ │ └── signup.gif │ │ ├── favicon.png │ │ ├── kale logo.png:Zone.Identifier │ │ ├── kale-logo.png │ │ ├── kubernetes illustration.jpg:Zone.Identifier │ │ ├── kubernetes-illustration.jpg │ │ └── welcome-page.png │ └── index.html ├── slices │ ├── metricsApi.ts │ ├── snapshotsApi.ts │ ├── store.ts │ ├── uiSlice.ts │ ├── userApi.ts │ └── userSlice.ts └── stylesheets │ └── styles.css ├── cypress.config.ts ├── cypress ├── e2e │ ├── auth.cy.ts │ ├── dashboardPage.cy.ts │ ├── historyPage.cy.ts │ ├── navigation.cy.ts │ ├── splashPage.cy.ts │ └── welcomePage.cy.ts └── support │ ├── commands.ts │ ├── component-index.html │ ├── component.ts │ └── e2e.ts ├── package.json ├── server ├── Models │ ├── snapshotModel.ts │ └── userModel.ts ├── controllers │ ├── apiController.ts │ ├── authController.ts │ └── dbController.ts ├── router │ ├── authRouter.ts │ └── dbRouter.ts └── server.ts ├── tailwind.config.js ├── tsconfig.json ├── types.d.ts └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_STORE 2 | node_modules 3 | package-lock.json 4 | dist 5 | .env 6 | secret*.json -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
kale
5 | 6 | 7 |kale is an open-source Kubernetes tool for monitoring and autoscaling machine learning workloads, specializing in GPU metrics for optimized scaling decisions.
8 |
13 |
14 |
15 |
16 |
{metric}
77 | 78 |{metric}
73 |48 | Cluster URL:{' '} 49 |
50 | {url} 51 |
52 | 53 |55 | Name of GPU 56 |
57 |58 | NVIDIA GeForce RTX 3080 59 |
60 |63 | Driver Version 64 |
65 |66 | 465.19 67 |
68 |
247 |
248 |
253 |
256 |
257 | |
258 | 259 | Name 260 | | 261 |262 | Unit 263 | | 264 |265 | Unit Name 266 | | 267 |268 | Date 269 | | 270 |271 | |
---|
13 | Something's missing. 14 |
15 |16 | Sorry, we can't find that page. You'll find lots to explore on the 17 | home page.{' '} 18 |
19 | 23 | Back to Homepage 24 | 25 |113 | Here at Kale we leverage your unleashed talent, technology, and 114 | innovation to help improve flow of communication. 115 |
116 |36 | Cluster URL:{' '} 37 | 38 | {urlShow} 39 | 40 |
41 | 42 |44 | Name of GPU 45 |
46 |47 | NVIDIA GeForce RTX 3080 48 |
49 |52 | Driver Version 53 |
54 |55 | 465.19 56 |
57 |Data Loading
70 | )} 71 | > 72 | ); 73 | } 74 | -------------------------------------------------------------------------------- /client/pages/SplashPage.tsx: -------------------------------------------------------------------------------- 1 | import React, { useRef } from 'react'; 2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 3 | import { faLinkedin } from '@fortawesome/free-brands-svg-icons'; 4 | import { faEnvelope } from '@fortawesome/free-solid-svg-icons'; 5 | import { Link } from 'react-router-dom'; 6 | import { useSelector } from 'react-redux'; 7 | import { RootState, useAppDispatch } from '../slices/store'; 8 | import { setGifUrl, setActiveDemo } from '../slices/uiSlice'; 9 | import { useDispatch } from 'react-redux'; 10 | 11 | interface TeamMember { 12 | name: string; 13 | role: string; 14 | imageUrl: string; 15 | linkedInUrl: string; 16 | email: string; 17 | } 18 | 19 | //team member pictures 20 | const ismaelImageURL: string = './public/Assets/Ismael-Headshot.jpg'; 21 | const soniaImageURL: string = './public/Assets/Sonia-Headshot.jpg'; 22 | const jinImageURL: string = './public/Assets/Jin-Headshot.jpg'; 23 | const jeffImageURL: string = './public/Assets/Jeff-Headshot.jpg'; 24 | 25 | //team member linkedIn 26 | const soniaLinkedInUrl: string = 'https://www.linkedin.com/in/soheunhan/'; 27 | const jinLinkedInUrl: string = 28 | 'https://www.linkedin.com/in/jinseong-nam-8b6815212/'; 29 | const jeffLinkedInUrl: string = 30 | 'https://www.linkedin.com/in/jeffrey-chao-9479142a/'; 31 | const ismaelLinkedInUrl: string = 32 | 'https://www.linkedin.com/in/ismael-boussatta-2493b2126/'; 33 | 34 | //team member email 35 | const soniaEmail: string = 'sonia.han@hey.com'; 36 | const jinEmail: string = 'jjjinnam@gmail.com'; 37 | const ismaelEmail: string = 'boussatta.ismael@gmail.com'; 38 | const jeffEmail: string = 'jeffplv@gmail.com'; 39 | 40 | const teamMembers: TeamMember[] = [ 41 | { 42 | name: 'Sonia Han', 43 | role: 'Software Engineer', 44 | imageUrl: soniaImageURL, 45 | linkedInUrl: soniaLinkedInUrl, 46 | email: soniaEmail, 47 | }, 48 | { 49 | name: 'Jeffrey Chao', 50 | role: 'Software Engineer', 51 | imageUrl: jeffImageURL, 52 | linkedInUrl: jeffLinkedInUrl, 53 | email: jeffEmail, 54 | }, 55 | { 56 | name: 'Jinseong Nam', 57 | role: 'Software Engineer', 58 | imageUrl: jinImageURL, 59 | linkedInUrl: jinLinkedInUrl, 60 | email: jinEmail, 61 | }, 62 | { 63 | name: 'Ismael Boussatta', 64 | role: 'Software Engineer', 65 | imageUrl: ismaelImageURL, 66 | linkedInUrl: ismaelLinkedInUrl, 67 | email: ismaelEmail, 68 | }, 69 | ]; 70 | 71 | // demo GIF url 72 | const autoRefresh = './public/Assets/demo/auto_refresh.gif'; 73 | const inputUrl = './public/Assets/demo/input_url.gif'; 74 | const saveSnapshot = './public/Assets/demo/save_snapshot.gif'; 75 | const signUp = './public/Assets/demo/signup.gif'; 76 | 77 | export default function SplashPage() { 78 | const demoGifUrl = useSelector((state: RootState) => state.ui.demoGifUrl); 79 | const activeDemo = useSelector((state: RootState) => state.ui.activeDemo); 80 | const whatIsK8sSectionRef = useRefkale
141 | , your new favorite Kubernetes autoscaling tool 142 | 143 |144 | Deploying your Machine Learning models on Kubernetes just got 145 | easier 146 |
147 | 153 |183 | It's a feature in K8s that automatically scales the number of pods 184 | based on observed metrics. This helps ensure your application has 185 | the resources it needs to handle varying workloads without manual 186 | intervention. 187 |
188 |193 | HPA primarily focuses on resource-based metrics like CPU and 194 | memory usage. 195 |
196 |201 | A critical aspect of ML training processes is the utilization of 202 | GPUs to facilitate the simultaneous execution of computationally 203 | intensive tasks. While Kubernetes offers robust out-of-the-box 204 | autoscaling functionality, it currently lacks native support for 205 | scaling based on GPU metrics. 206 |
207 |225 | A monitoring and autoscaling tool designed for machine learning 226 | workloads on Kubernetes to provide more intelligent scaling 227 | decisions. 228 |
229 |238 | Click any links below to see the product demo. 239 |
240 |70 | {userDataShow ? userDataShow.firstName : 'Random Hacker'} 71 |
72 | 73 |74 | Please enter your cluster's Prometheus URL and the name of the pod 75 | you want to monitor*. 76 |
77 |85 | *Proof of Concept: Data is currently based on CPU metrics. 86 | More comprehensive metrics are in development. 87 |
88 |