prelim service bench support + docs updates
parent
73d2ea3da5
commit
92dc948f5f
30
README.md
30
README.md
|
|
@ -117,20 +117,20 @@ k9s --context coolCtx
|
||||||
|
|
||||||
## Benchmarking (Way early Pupp!)
|
## Benchmarking (Way early Pupp!)
|
||||||
|
|
||||||
K9s integrates [Hey](https://github.com/rakyll/hey) from the brilliant Jaana Dogan of Google fame. This is a preliminary feature and is only supported for port-forwards at this time.
|
K9s integrates [Hey](https://github.com/rakyll/hey) from the brilliant and super talented [Jaana Dogan](https://github.com/rakyll) of Google fame. This is a preliminary feature and is only supports for port-forwards and very limited NodePort/LoadBalancer services at this time (Read the paint is way fresh!).
|
||||||
|
|
||||||
The Hey tool is currently being used to benchmark port-forwards. Services and ingresses will be enabled next. To setup a port-forward, you will need to navigate to the pod view, select a pod and then select a container that exposes a port. Using `SHIFT-F` a dialog will come up to allow you to pick a local port to forward to. Once successfull, K9s will take you the port-forward view (alias `pf`) listing out you currently active port-forwards. Selecting a port-forward and using `CTRL-B` will run a benchmark on that container. To view the results of your benchmarking runs go to the benchmark view (alias `be`). You should now be able to select a benchmark and view the run stats details by pressing `<ENTER>`.
|
The `Hey` tool is currently being used to benchmark port-forwards. Services and ingresses will be fully enabled next. To setup a port-forward, you will need to navigate to the pod view, select a pod and a container that exposes a port. Using `SHIFT-F` a dialog will come up to allow you to pick a local port to forward to. Once successfull, K9s will take you the port-forward view (alias `pf`) listing out you currently active port-forwards. Selecting a port-forward and using `CTRL-B` will run a benchmark on that container. To view the results of your benchmark runs, go to the benchmark view (alias `be`). You should now be able to select a benchmark and view the run stats details by pressing `<ENTER>`.
|
||||||
|
|
||||||
By default, the benchmark will be run with the following assumptions:
|
Initially, the benchmark will(may?) run with the following defaults:
|
||||||
|
|
||||||
* Concurrency Level: 1
|
* Concurrency Level: 1
|
||||||
* Number of Requests: 200
|
* Number of Requests: 200
|
||||||
* HTTP Verb: GET
|
* HTTP Verb: GET
|
||||||
* Path: /
|
* Path: /
|
||||||
|
|
||||||
NOTE: Granted, benchmarking a single container might not be all that useful, compared to benchmarking a service/ingress, etc... It does however given you some insights by putting a container under load to help with resources/auto-scaling settings or a quick first glance at comparing Canary's implementation. At this time, we're trying to steel-thread thru the basic mechanics and then escalate to wider use cases once the essentials are in place.
|
NOTE: In case it wasn't abundantly obvious this a super early release. It does however given you some insights by putting a container under load to help with resources/auto-scaling settings or a quick first glance at comparing Canary's implementation. At this time, we're trying to steel-thread thru the basic mechanics and then escalate to wider use cases once the essentials are in place. So please thread lightly and aim small as port-forwards and heavy benchmarking will most likely cause K9s to kick over.
|
||||||
|
|
||||||
The port forward view is backed by a new K9s config file namely: `$HOME/.k9s/benchmarks.yml`. Changes to this file should update the port-forward view to indicate how you want to run your benchmarks.
|
The port forward view is backed by a new K9s config file namely: `$HOME/.k9s/bench-mycluster.yml`. Each cluster you will connect to will have its own bench config file. Changes to this file should update the port-forward view to indicate how you want to run your benchmarks.
|
||||||
|
|
||||||
Here is a sample benchmarks.yml configuration. Please keep in mind this file will change!
|
Here is a sample benchmarks.yml configuration. Please keep in mind this file will change!
|
||||||
Provision for specifying auth, headers, payload, etc... will be coming soon...
|
Provision for specifying auth, headers, payload, etc... will be coming soon...
|
||||||
|
|
@ -151,28 +151,28 @@ benchmarks:
|
||||||
# Benchmark the container named nginx using GET HTTP verb using http://localhost:someport/
|
# Benchmark the container named nginx using GET HTTP verb using http://localhost:someport/
|
||||||
concurrency: 1
|
concurrency: 1
|
||||||
requests: 10000
|
requests: 10000
|
||||||
path: /
|
path: /bozo
|
||||||
method: POST
|
method: POST
|
||||||
body:
|
body:
|
||||||
{"fred":"blee"}
|
{"fred":"blee"}
|
||||||
http2: true
|
|
||||||
header:
|
header:
|
||||||
Accept: text/html
|
Accept:
|
||||||
Content-Type: application/json
|
- text/html
|
||||||
|
Content-Type:
|
||||||
|
- application/json
|
||||||
services:
|
services:
|
||||||
# NOTE Does nothing yet! ie NYI
|
# Benchmark a service exposed either via nodeport, loadbalancer.
|
||||||
# Benchmark a service exposed either via nodeport, loadbalancer or ingress.
|
|
||||||
default/nginx:
|
default/nginx:
|
||||||
concurrency: 1
|
concurrency: 1
|
||||||
requests: 500
|
requests: 500
|
||||||
method: GET
|
method: GET
|
||||||
# This setting will depend on whether service is nodeport or loadbalancer.
|
# This setting will depend on whether service is nodeport or loadbalancer.
|
||||||
# Set this to a node if nodeport or LB if applicable. IP or dns name.
|
# Set this to a node if nodeport or LB if applicable. IP or dns name.
|
||||||
address: jeanbaptistemmanuel.zorg
|
address: super.dev
|
||||||
path: /bumblebeetuna
|
path: /bumblebeetuna
|
||||||
auth:
|
auth:
|
||||||
user: zorg
|
user: jeanbaptiste
|
||||||
password: MultiPass
|
password: Zorg!
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -183,7 +183,7 @@ K9s uses aliases to navigate most K8s resources.
|
||||||
|
|
||||||
| Command | Result | Example |
|
| Command | Result | Example |
|
||||||
|-----------------------|----------------------------------------------------|----------------------------|
|
|-----------------------|----------------------------------------------------|----------------------------|
|
||||||
| `:`alias`<ENTER>` | View a Kubernetes resource | `:po<ENTER>` |
|
| `:`alias`<ENTER>` | View a Kubernetes resource aliases | `:po<ENTER>` |
|
||||||
| `?` | Show keyboard shortcuts and help | |
|
| `?` | Show keyboard shortcuts and help | |
|
||||||
| `Ctrl-a` | Show all available resource alias | select+`<ENTER>` to view |
|
| `Ctrl-a` | Show all available resource alias | select+`<ENTER>` to view |
|
||||||
| `/`filter`ENTER`> | Filter out a resource view given a filter | `/bumblebeetuna` |
|
| `/`filter`ENTER`> | Filter out a resource view given a filter | `/bumblebeetuna` |
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ Also if you dig this tool, please make some noise on social! [@kitesurfer](https
|
||||||
|
|
||||||
### Labor Day Weekend?
|
### Labor Day Weekend?
|
||||||
|
|
||||||
I've always seem to get this wrong. Does Labor Day weekend mean you get to work on you OSS projects all weekend? I am very excited about this drop and hopefully won't be hunamimous on that??
|
I've always seem to get this wrong! Does Labor Day weekend mean you get to work on your OSS projects all weekend?
|
||||||
|
I am very excited about this drop and hopefully won't be hunamimous on that 🐭??
|
||||||
|
|
||||||
### Service Traversals
|
### Service Traversals
|
||||||
|
|
||||||
|
|
@ -26,30 +27,31 @@ Provided your K8s service is head(Full), you can now navigate to the pods that m
|
||||||
|
|
||||||
### Moving Forward!
|
### Moving Forward!
|
||||||
|
|
||||||
K9s supports port-forwarding. Provided a pod's container exposes a port, you can navigate to the container view, select a container with an exposed port and activate a port-forward directly from K9s without needing to shell out. I think that's very handy. This was indeed a long time coming... Big Thank You and ATTABoy!! to [Brent](https://github.com/brentco) for this great issue.
|
K9s now supports port-forwarding! Provided a pod's container exposes a port, you can navigate to the container view, select a container with an exposed port and activate a port-forward directly from K9s without needing to shell out. I think that's very handy. This was indeed a long time coming... Big Thanks and ATTABOY! in full effect this week to [Brent](https://github.com/brentco) for filling the initial issue.
|
||||||
|
|
||||||
That said, these babies are a bit expensive to run, so make sure you choose wisely and delete any superflous forwards! To access the port-forward view directly use `:pf<enter>`.
|
That said, these babies are a bit expensive to run, so make sure you choose wisely and delete any superflous port-forwards!! To access the port-forward view directly use `:pf<enter>`.
|
||||||
BONUS: Pending your terminal of choice, you might even be able to pop the forwarded URL directly into your browse. On iTerm I think `command+click` does the trick.
|
BONUS: Pending your terminal of choice, you might even be able to pop the forwarded URL directly into your browse. On iTerm me thinkw `command+click` does the trick?
|
||||||
|
|
||||||
This feature is very much still work in progress, thinks like basic auth, http verbs, headers, etc... are coming next, so please thread lightly and checkout the README under the Benchmarking section.
|
This feature is very much still work in progress, thinks like basic auth, http verbs, headers, etc... are coming next, so please thread lightly and checkout the README under the Benchmarking section. Your feedback as always, is welcome and encouraged!
|
||||||
|
|
||||||
### Hey now!
|
### Hey now!
|
||||||
|
|
||||||
This is one feature that I think, pardon my french `Bitch'n`. K9s now encompassed [Hey](https://github.com/rakyll/hey) from the totaly brilliant and kind Jaana Dogan of Google fame.
|
This is one feature that I think is, pardon my french, `Bitch'n`. K9s now encompassed [Hey](https://github.com/rakyll/hey) from the totaly brilliant and kind Jaana Dogan of Google fame.
|
||||||
So along with the port-forward feature, you can now benchmark your containers and gather some interesting metrics that may help you configure resources, auto scalers, compare Canary builds, etc...
|
So along with the port-forward feature, you can now benchmark your containers and gather some interesting metrics that may help you configure resources, auto scalers, compare Canary builds, etc... You should also bench your services providing they export ports via NodePort or LoadBalancer, tho very lightly tested as this was a lot of code to punch thru.
|
||||||
|
|
||||||
That said, this feature is still a moving target, as much configuration still needs to be tuned to make it totally killer. Please checkout the README on how to configure this feature. There are many more improvements that need to happen notably bench'ing service, ingress, etc and will come in subsequent K9s drops...
|
Useless to say, this feature is still a moving target, as much code still needs to be tuned to make it totally killer. Please checkout the README on how to configure this feature. There are many more improvements that need to happen notably bench'ing service, ingress, etc and will come in subsequent K9s drops...
|
||||||
|
|
||||||
We think this port-forward/bench combo is a killer feature! Hopefully you'll agree. With the understanding the full-monty is coming soon, please help us mold and solidify these features as they are the base ingredients to setup for benchmarking services and ingresses...
|
We think this port-forward/bench combo is totally cool and hope you'll dig these new features? Hopefully you'll agree... With the understanding the full-monty is coming soon, please help us `bench and solidify these features as they are the base ingredients to more features along these lines...
|
||||||
|
|
||||||
|
> NOTE! Has with anything in life `Aim small, Miss small!`. You could totally hose K9s with over zealous benchmarks and forwards, so start small say C:1 N:100, measure and go from there.
|
||||||
|
|
||||||
> NOTE! Has with anything in life `Aim small, Miss small!`. You could totally hose K9s with over ambitious benchmarks, so start small say C:1 N:100, measure and go from there.
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Resolved Bugs
|
## Resolved Bugs
|
||||||
|
|
||||||
+ [Issue #198](https://github.com/derailed/k9s/issues/198)
|
+ [Issue #198](https://github.com/derailed/k9s/issues/198)
|
||||||
+ [Issue #197](https://github.com/derailed/k9s/issues/197)
|
+ [Issue #197](https://github.com/derailed/k9s/issues/197)
|
||||||
+ [Issue #195](https://github.com/derailed/k9s/issues/195) Thanks [Sebastiaan](https://github.com/tammert)!!
|
+ [Issue #195](https://github.com/derailed/k9s/issues/195) Thanks [Sebastiaan](https://github.com/tammert). You Rock!!
|
||||||
+ [Issue #194](https://github.com/derailed/k9s/issues/194)
|
+ [Issue #194](https://github.com/derailed/k9s/issues/194)
|
||||||
+ [Issue #69](https://github.com/derailed/k9s/issues/69)
|
+ [Issue #69](https://github.com/derailed/k9s/issues/69)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -257,6 +257,8 @@ func (a *appView) statusReset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *appView) status(l flashLevel, msg string) {
|
func (a *appView) status(l flashLevel, msg string) {
|
||||||
|
a.flash().info(msg)
|
||||||
|
|
||||||
switch l {
|
switch l {
|
||||||
case flashErr:
|
case flashErr:
|
||||||
a.logoView.err(msg)
|
a.logoView.err(msg)
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,9 @@ func (b *benchmark) init(base string) error {
|
||||||
} else {
|
} else {
|
||||||
ua += " " + k9sUA
|
ua += " " + k9sUA
|
||||||
}
|
}
|
||||||
|
if req.Header == nil {
|
||||||
|
req.Header = make(http.Header)
|
||||||
|
}
|
||||||
req.Header.Set("User-Agent", ua)
|
req.Header.Set("User-Agent", ua)
|
||||||
|
|
||||||
b.worker = &requester.Work{
|
b.worker = &requester.Work{
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,6 @@ func (v *forwardView) sortColCmd(col int, asc bool) func(evt *tcell.EventKey) *t
|
||||||
func (v *forwardView) benchStopCmd(evt *tcell.EventKey) *tcell.EventKey {
|
func (v *forwardView) benchStopCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
if v.bench != nil {
|
if v.bench != nil {
|
||||||
log.Debug().Msg(">>> Benchmark canceled!!")
|
log.Debug().Msg(">>> Benchmark canceled!!")
|
||||||
v.app.flash().info("Benchmark canceled!")
|
|
||||||
v.app.status(flashErr, "Benchmark Camceled!")
|
v.app.status(flashErr, "Benchmark Camceled!")
|
||||||
v.bench.cancel()
|
v.bench.cancel()
|
||||||
}
|
}
|
||||||
|
|
@ -171,7 +170,6 @@ func (v *forwardView) benchCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
if v.bench.canceled {
|
if v.bench.canceled {
|
||||||
v.app.status(flashInfo, "Benchmark canceled")
|
v.app.status(flashInfo, "Benchmark canceled")
|
||||||
} else {
|
} else {
|
||||||
v.app.flash().infof("Benchmark for %s is done!", sel)
|
|
||||||
v.app.status(flashInfo, "Benchmark Completed!")
|
v.app.status(flashInfo, "Benchmark Completed!")
|
||||||
v.bench.cancel()
|
v.bench.cancel()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
package views
|
package views
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal/k8s"
|
"github.com/derailed/k9s/internal/k8s"
|
||||||
"github.com/derailed/k9s/internal/resource"
|
"github.com/derailed/k9s/internal/resource"
|
||||||
|
|
@ -13,18 +15,23 @@ import (
|
||||||
|
|
||||||
type svcView struct {
|
type svcView struct {
|
||||||
*resourceView
|
*resourceView
|
||||||
|
|
||||||
|
bench *benchmark
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSvcView(t string, app *appView, list resource.List) resourceViewer {
|
func newSvcView(t string, app *appView, list resource.List) resourceViewer {
|
||||||
v := svcView{newResourceView(t, app, list).(*resourceView)}
|
v := svcView{resourceView: newResourceView(t, app, list).(*resourceView)}
|
||||||
v.extraActionsFn = v.extraActions
|
v.extraActionsFn = v.extraActions
|
||||||
|
|
||||||
return &v
|
return &v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *svcView) extraActions(aa keyActions) {
|
func (v *svcView) extraActions(aa keyActions) {
|
||||||
aa[KeyShiftT] = newKeyAction("Sort Type", v.sortColCmd(1, false), true)
|
aa[tcell.KeyCtrlB] = newKeyAction("Bench", v.benchCmd, true)
|
||||||
|
aa[KeyAltB] = newKeyAction("Bench Stop", v.benchStopCmd, true)
|
||||||
aa[tcell.KeyEnter] = newKeyAction("View Pods", v.showPodsCmd, true)
|
aa[tcell.KeyEnter] = newKeyAction("View Pods", v.showPodsCmd, true)
|
||||||
|
|
||||||
|
aa[KeyShiftT] = newKeyAction("Sort Type", v.sortColCmd(1, false), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *svcView) sortColCmd(col int, asc bool) func(evt *tcell.EventKey) *tcell.EventKey {
|
func (v *svcView) sortColCmd(col int, asc bool) func(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
|
|
@ -64,6 +71,106 @@ func (v *svcView) backCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *svcView) benchStopCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
|
if v.bench != nil {
|
||||||
|
log.Debug().Msg(">>> Benchmark canceled!!")
|
||||||
|
v.app.status(flashErr, "Benchmark Camceled!")
|
||||||
|
v.bench.cancel()
|
||||||
|
}
|
||||||
|
v.app.statusReset()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *svcView) benchCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
|
if !v.rowSelected() {
|
||||||
|
return evt
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.bench != nil {
|
||||||
|
v.app.flash().err(errors.New("Only one benchmark allowed at a time"))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sel := v.getSelectedItem()
|
||||||
|
tv := v.getTV()
|
||||||
|
r, _ := tv.GetSelection()
|
||||||
|
|
||||||
|
// BOZO!! Poorman Reload bench to make sure we pick up updates if any.
|
||||||
|
path := benchConfig(v.app.config.K9s.CurrentCluster)
|
||||||
|
if err := v.app.bench.Reload(path); err != nil {
|
||||||
|
log.Error().Err(err).Msg("Bench config reload")
|
||||||
|
v.app.flash().err(err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg, ok := v.app.bench.Benchmarks.Services[sel]
|
||||||
|
if !ok {
|
||||||
|
v.app.flash().errf("No bench config found for service %s", sel)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
svcType := strings.TrimSpace(tv.GetCell(r, tv.nameColIndex()+1).Text)
|
||||||
|
log.Debug().Msgf("Service Type %q", svcType)
|
||||||
|
if svcType != "NodePort" && svcType != "LoadBalancer" {
|
||||||
|
v.app.flash().err(errors.New("You must select a reachable service"))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ports := strings.TrimSpace(tv.GetCell(r, tv.nameColIndex()+5).Text)
|
||||||
|
// BOZO!! You Brute!!
|
||||||
|
// BOZO!! Will new much improv ie pop dialog and select port if multiport.
|
||||||
|
pp := strings.Split(ports, " ")
|
||||||
|
if len(pp) == 0 {
|
||||||
|
v.app.flash().err(errors.New("No ports found"))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Grap the first port pair for now...
|
||||||
|
tokens := strings.Split(pp[0], "►")
|
||||||
|
if len(tokens) < 2 {
|
||||||
|
v.app.flash().err(errors.New("No ports pair found"))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Found external nodeport
|
||||||
|
port := tokens[1]
|
||||||
|
cfg.Name = sel
|
||||||
|
log.Debug().Msgf(">>>>> BENCHCONFIG %#v", cfg)
|
||||||
|
|
||||||
|
base := "http://" + cfg.Host + ":" + port + cfg.Path
|
||||||
|
var err error
|
||||||
|
if v.bench, err = newBenchmark(base, cfg); err != nil {
|
||||||
|
log.Error().Err(err).Msg("Bench failed!")
|
||||||
|
v.app.flash().errf("Bench failed %v", err)
|
||||||
|
v.app.statusReset()
|
||||||
|
v.bench = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
v.app.status(flashWarn, "Benchmark in progress...")
|
||||||
|
log.Debug().Msg("Bench starting...")
|
||||||
|
go v.bench.run(v.app.config.K9s.CurrentCluster, func() {
|
||||||
|
log.Debug().Msg("Bench Completed!")
|
||||||
|
v.app.QueueUpdate(func() {
|
||||||
|
if v.bench.canceled {
|
||||||
|
v.app.status(flashInfo, "Benchmark canceled")
|
||||||
|
} else {
|
||||||
|
v.app.status(flashInfo, "Benchmark Completed!")
|
||||||
|
v.bench.cancel()
|
||||||
|
}
|
||||||
|
v.bench = nil
|
||||||
|
go func() {
|
||||||
|
<-time.After(2 * time.Second)
|
||||||
|
v.app.QueueUpdate(func() {
|
||||||
|
v.app.statusReset()
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (v *svcView) showSvcPods(ns string, sel map[string]string, b actionHandler) {
|
func (v *svcView) showSvcPods(ns string, sel map[string]string, b actionHandler) {
|
||||||
var s []string
|
var s []string
|
||||||
for k, v := range sel {
|
for k, v := range sel {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue