Skip to content
This repository has been archived by the owner on Jul 14, 2022. It is now read-only.

Add rkt and docker support, new logging package #8

Merged
merged 6 commits into from
Feb 25, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ deps:
@GOPATH=$(GOPATH) go get github.com/coreos/fleet/client
@GOPATH=$(GOPATH) go get github.com/coreos/fleet/schema
@GOPATH=$(GOPATH) go get github.com/golang/glog
@GOPATH=$(GOPATH) go get github.com/op/go-logging
@GOPATH=$(GOPATH) go get github.com/gorilla/mux
@GOPATH=$(GOPATH) go get gopkg.in/yaml.v2
@GOPATH=$(GOPATH) go get github.com/ajstarks/svgo
Expand Down
91 changes: 20 additions & 71 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

[![Build Status](https://api.travis-ci.org/giantswarm/fleemmer.svg)](https://travis-ci.org/giantswarm/fleemmer)
[![](https://godoc.org/github.com/giantswarm/fleemmer?status.svg)](http://godoc.org/github.com/giantswarm/fleemmer)
[![](https://img.shields.io/docker/pulls/giantswarm/fleemmer.svg)](http://hub.docker.com/giantswarm/fleemmer)
[![IRC Channel](https://img.shields.io/badge/irc-%23giantswarm-blue.svg)](https://kiwiirc.com/client/irc.freenode.net/#giantswarm)

**Fleemmer** is a benchmarking tool that tests a [fleet](https://github.com/coreos/fleet) cluster. Fleemer is able to collect some metrics and generates some plots. To make use of Fleemmer, you just need to define your own benchmark using a YAML file. Fleemmer parses this file and runs the benchmark according to the instructions defined in it. Additionally, Fleemmer also provides the possibility to define instructions in one line using the parameter `raw-instructions`.
**Fleemmer** is a benchmarking tool that tests a [fleet](https://github.com/coreos/fleet) cluster. With Fleemmer, you can deploy benchmark units that employ [Docker](https://github.com/docker/docker), [rkt](https://github.com/coreos/rkt) containers, or just raw `systemd` units. Fleemer is able to collect some metrics and generate some plots from those. To make use of Fleemmer, you just need to define your own benchmark using a YAML file. Fleemmer parses this file and runs the benchmark according to the instructions defined in it. Additionally, Fleemmer provides the possibility to define instructions in one line using the parameter `raw-instructions`.

## Requirements

Expand All @@ -13,91 +14,39 @@ Fleemmer requires to be installed on a fleet cluster-node to run properly.
Dependencies:

- fleet and systemd running on the host machine.
- In case you want to run Docker or rkt containers, the respective tool needs to be running on the host machines, too.
- Optional: To generate gnu plots, support for gnuplot is required on the host machine. Alternatively, you can run Fleemmer as a Docker container, which comes with gnuplot installed, as shown below.

## Benchmark file definition
## Getting Fleemmer

In the following, we detail the purpose of each one of the elements that composes a benchmark definition.
Download the latest tarball from here: https://downloads.giantswarm.io/fleemmer/latest/fleemmer.tar.gz

- **instancegroup-size**: indicates the amount of units that will conform an instance group.
- **instructions**: contains a list of instructions that will be executed in descending order. Each instruction can optionally have one of the following elements:
- **start**:
- **max**: represents the amount of units to start.
- **interval**: In **Milliseconds**, it represents the interval of time between start operations.
- **sleep**: is the amount of time in **Seconds** to go to sleep.
- **float**:
- **rate**: represents the rate of (float).
- **duration**: represents the duration in Seconds.
- **expect-running**:
- **amount**: represents the amount of expected running units.
- **symbol**: used to indicate whether you expect `[<|>]` `expect-running/amount` units to be running.
- **stop**: indicates the directive used to stop the current units (stop-all|). At this moment, we only offer `stop-all` as an alternative to stop units.
Clone the latest git repository version from here: `git@github.com:giantswarm/fleemmer.git`

**NOTE:** The order of the elements in an instruction indicates, in which order such an action will be triggered.
Get the latest docker image from here: https://hub.docker.com/r/giantswarm/fleemmer/

**Example:**
## Running Fleemmer:

```
instancegroup-size: 1
instructions:
- start:
max: 8
interval: 200
- expect-running:
symbol: <
amount: 10
- sleep: 10
- start:
max: 3
interval: 300
- sleep: 200
- stop: stop-all
```

## Fleemmer parameters
`fleemmer help`

- **addr**: address to listen on. Fleemmer extracts the public CoreOS IP of the host machine automatically (from `/etc/environment`). Note that you should use this parameter when using a different distro than CoreOS, a Docker container, or a different address to listen on. The `default` port to listen on is `40302`.
- **dump-json**: dump JSON stats to stdout.
- **dump-html-tar**: dump tarred HTML stats to stdout.
- **benchmark-file**: YAML file with the actions to be triggered and the size of the instance groups.
- **raw-instructions**: benchmark raw instructions to be triggered, (requires `instancegroup-size` parameter) and the size of the instance groups.
- **instancegroup-size**: size of the instance group in terms of units, (only if you use `raw-instructions`).
- **generate-gnuplots**: generate gnuplots out of the collected metrics. It is preferable to use `raw-instructions` instead of `benchmark-file` to avoid specifying a docker volume to pass a YAML benchmark definition.
- **IMPORTANT:** You have to run Fleemmer as a Docker container in your CoreOS machine.
### Run Fleemmer from source:

## Run Fleemmer:

Using a benchmark YAML file to run a test:

`./fleemmer --instancegroup-size=1 --dump-html-tar --benchmark-file="./examples/sample01.yaml" &>> outputFile `
```
make
./fleemmer help
```

Using `raw-instructions` and `instancegroup-size` parameters to run a benchmark:
More information on how to run Fleemmer and its required parameters in: [docs](docs)

`./fleemmer --instancegroup-size=1 --dump-json --raw-instructions="(sleep 1) (start 200 100) (sleep 200) (stop-all)" &>>outfile`
## Further Steps

Example of a script to send Fleemmer to a remote fleet cluster-node:
Check more detailed documentation: [docs](docs)

```
scp fleemmer core@100.25.10.2:
ssh core@100.25.10.2 './fleemmer --instancegroup-size=1 --dump-html-tar --benchmark-file="./examples/sample01.yaml"'
```
Check code documentation: [godoc](https://godoc.org/github.com/giantswarm/fleemmer)

If you want to generate the plots with `gnuplot` in a specific directory `$PLOTS_DIR` use the Docker build:
## Future Development

```
PLOTS_DIR=/tmp
...

docker run -ti \
-v $PLOTS_DIR:/fleemmer_plots \
-v /var/run/fleet.sock:/var/run/fleet.sock \
--net=host \
--pid=host \
giantswarm/fleemmer:latest \
--addr=192.68.10.101:54541 \
--generate-gnuplots \
--raw-instructions="(sleep 1) (start 10 100) (sleep 60) (stop-all)"
```
- Future directions/vision

## Contact

Expand Down
66 changes: 34 additions & 32 deletions cmd/run.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
package cmd

import (
"flag"
"log"
"os"
"os/exec"
"strings"
"sync"

"github.com/golang/glog"
"github.com/spf13/cobra"

"github.com/giantswarm/fleemmer/definition"
"github.com/giantswarm/fleemmer/fleet"
"github.com/giantswarm/fleemmer/log"
"github.com/giantswarm/fleemmer/output"
"github.com/giantswarm/fleemmer/unit"
)
Expand All @@ -32,33 +30,32 @@ type runCmdFlags struct {
dumpHTMLTarFlag bool
generatePlots bool
igSize int
verbose bool
useDocker bool
useRkt bool
}

func (f runCmdFlags) Validate() {
if f.dumpJSONFlag && f.dumpHTMLTarFlag {
glog.Fatalln("dump option is required. Please, choose between: dump-json OR dump-html-tar")
}

if !f.dumpJSONFlag && !f.dumpHTMLTarFlag {
glog.Warningln("output mode option is required")
log.Logger().Fatal("dump option is required. Please, choose between: dump-json OR dump-html-tar")
}

if f.benchmarkFile == "" && f.rawInstructions == "" {
glog.Fatalln("benchmark file definition or raw instructions is required")
log.Logger().Fatal("benchmark file definition or raw instructions is required")
}

if f.benchmarkFile != "" && f.rawInstructions != "" {
glog.Fatalln("benchmark file definition or raw instructions are mutual exclusive")
log.Logger().Fatal("benchmark file definition or raw instructions are mutual exclusive")
}

if f.benchmarkFile == "" && f.rawInstructions != "" && f.igSize <= 0 {
glog.Fatalln("instance group size has to be greater than 0 when using raw-instructions parameter")
log.Logger().Fatal("instance group size has to be greater than 0 when using raw-instructions parameter")
}

if f.generatePlots {
if _, err := exec.LookPath("gnuplot"); err != nil {
glog.V(2).Infof("generate-gnuplots: could not find path to 'gnuplot':\n%v\n", err)
glog.Fatalln("generate-gnuplots option requires 'gnuplot' software installed")
log.Logger().Infof("generate-gnuplots: could not find path to 'gnuplot':\n%v\n", err)
log.Logger().Fatal("generate-gnuplots option requires 'gnuplot' software installed")
}
}
}
Expand All @@ -80,18 +77,17 @@ func init() {
runCmd.Flags().StringVar(&runFlags.rawInstructions, "raw-instructions", "", "instructions to spawn/stop/float units")
runCmd.Flags().BoolVar(&runFlags.dumpJSONFlag, "dump-json", false, "dump json stats to stdout")
runCmd.Flags().BoolVar(&runFlags.dumpHTMLTarFlag, "dump-html-tar", false, "dump tarred html stats to stdout")
runCmd.Flags().BoolVar(&runFlags.verbose, "verbose", false, "verbose output")
runCmd.Flags().BoolVar(&runFlags.useDocker, "use-docker", false, "use systemd units that deploy docker containers")
runCmd.Flags().BoolVar(&runFlags.useRkt, "use-rkt", false, "use systemd units that deploy rkt containers")
runCmd.Flags().BoolVar(&runFlags.generatePlots, "generate-gnuplots", false, "generate plots using GNUPLOT (output directory=/fleemmer_plots)")
runCmd.Flags().IntVar(&runFlags.igSize, "instancegroup-size", 1, "instance group size")
}

func runRun(cmd *cobra.Command, args []string) {
log.SetFlags(0)
log.SetPrefix("fleemmer: ")
flag.Set("logtostderr", "true")

runFlags.Validate()
fleetPool := fleet.NewFleetPool(20)

if runFlags.listenAddr == "" {
// We extract the public CoreOS ip of the host machine
ip, err := fleet.CoreosHostPublicIP()
Expand All @@ -104,25 +100,25 @@ func runRun(cmd *cobra.Command, args []string) {

existingUnits, err := fleetPool.ListUnits()
if err != nil {
glog.Fatalln(err)
log.Logger().Fatal(err)
}

var benchmark definition.BenchmarkDef
if runFlags.benchmarkFile == "" {
benchmark, err = definition.BenchmarkDefByRawInstructions(runFlags.rawInstructions, runFlags.igSize)
if err != nil {
glog.Fatalln("unable to parse the introduced raw instructions")
log.Logger().Fatal("unable to parse the introduced raw instructions")
}
} else {
benchmark, err = definition.BenchmarkDefByFile(runFlags.benchmarkFile)
}
if err != nil {
glog.Fatalln(err)
log.Logger().Fatal(err)
}

unitEngine, err := unit.NewEngine(benchmark)
unitEngine, err := unit.NewEngine(benchmark, runFlags.verbose)
if err != nil {
glog.Fatalln(err)
log.Logger().Fatal(err)
}

observer := unit.NewBeaconObserver(unitEngine)
Expand All @@ -132,28 +128,34 @@ func runRun(cmd *cobra.Command, args []string) {
fleetPool.StartUnit(unit.MakeStatsDumper("systemd", "echo `hostname` `docker run --rm --pid=host ragnarb/toolbox pidstat -h -r -u -p 1 10 1 | tail -n 1 | awk \\'{print $7 \" \" $12}\\'`", "systemd", runFlags.listenAddr))

unitEngine.SpawnFunc = func(id string) error {
glog.V(2).Infof("spawning unit with id %s\n", id)
return fleetPool.StartUnitGroup(unit.MakeUnitChain(id, runFlags.listenAddr, unitEngine.InstanceGroupSize()))
if runFlags.verbose {
log.Logger().Infof("spawning unit with id %s\n", id)
}
return fleetPool.StartUnitGroup(unit.MakeUnitChain(id, runFlags.listenAddr, unitEngine.InstanceGroupSize(), runFlags.useDocker, runFlags.useRkt))
}

unitEngine.StopFunc = func(id string) error {
glog.V(2).Infof("stopping unit with id %s\n", id)
if runFlags.verbose {
log.Logger().Infof("stopping unit with id %s\n", id)
}
return fleetPool.Stop(beaconUnitPrefix + "-0@" + id + ".service")
}

unitEngine.Run()

existingUnits, err = fleetPool.ListUnits()
if err != nil {
glog.Errorf("error listing units %v", err)
log.Logger().Errorf("error listing units %v", err)
}

wg := new(sync.WaitGroup)
for _, unit := range existingUnits {
if strings.HasPrefix(unit.Name, beaconUnitPrefix) {
wg.Add(1)
go func(unitName string) {
glog.V(2).Infoln("destroying old unit: " + unitName)
if runFlags.verbose {
log.Logger().Infof("destroying old unit: %s", unitName)
}
fleetPool.Destroy(unitName)
wg.Done()
}(unit.Name)
Expand All @@ -168,20 +170,20 @@ func runRun(cmd *cobra.Command, args []string) {
if runFlags.dumpHTMLTarFlag {
html, err := output.Asset("output/embedded/render.html")
if err != nil {
glog.Fatalln(err)
log.Logger().Fatal(err)
}

scriptJs, err := output.Asset("output/embedded/script.js")
if err != nil {
glog.Fatalln(err)
log.Logger().Fatal(err)
}

output.DumpHTMLTar(html, scriptJs, unitEngine.Stats())
}

if runFlags.generatePlots {
output.GeneratePlots(unitEngine.Stats())
output.GeneratePlots(unitEngine.Stats(), runFlags.verbose)
}

output.PrintHistogram(unitEngine.Stats(), os.Stderr)
output.PrintReport(unitEngine.Stats(), os.Stderr)
}
Loading