github.com/gianarb/orbiter
Gianluca Arbezzano
@gianarb
Building clouds at InfluxDB (SRE)
Why?
● To create a use case around metrics, InfluxDB and Docker.
● Docker Swarm at the moment doesn’t provider autoscale capabilities.
● To design an application easy to manage and well integrated in Docker Swarm.
Orbiter is a general-purpose multi vendor autoscaler
Orbiter is a general-purpose multi vendor autoscaler
Orbiter is a Docker Swarm autoscaler
swarm cluster
manager
get metrics:
● cadvidor
● telegraf
● ….
alert:
● custom
● kapacitor
● alert
manager
Why Docker Swarm doesn’t have autoscaling?
● I don’t know.
● As you can see the architecture required is not small.
● Probably it will have autoscaling at some point.
Orbiter is designed to be Only-Swarm
● To make it easy to start
● To remove abstractions
● Because less is more! cit unknown but for sure a lazy person
What does it?
● It lists all your services and it gets only who has label orbiter=true
● Expose and HTTP API to trigger up and down scale event
○ curl -X POST -v http://$(IP):8081/v1/orbiter/handle/autoswarm/stack_micro/up
○ curl -X POST -v http://$(IP):8081/v1/orbiter/handle/autoswarm/stack_micro/down
● It uses Docker Swarm Api to keep in sync the managed services
● You can configure a service via label orbiter.up=3, orbiter.donw=2, orbiter.cooldown = 2
Requirement:
● Deploy it in a manager.
Deploy it as service in
Docker Swarm
version: '3'
services:
orbiter:
image: gianarb/orbiter
command: daemon
ports:
- 8081:8000
volumes:
- /var/run/docker.sock:/var/run/docker.sock
deploy:
placement:
constraints:
- node.role == manager
mode: replicated
replicas: 1
How Orbiter communicate with Swarm
func NewSwarmProvider(c map[string]string) (autoscaler.Provider, error) {
var p autoscaler.Provider
client, err := docker.NewEnvClient()
if err != nil {
logrus.WithField("error", err).Warn("problem to communicate with docker")
return p, err
} else {
logrus.Info("Successfully connected to a Docker daemon")
}
p = SwarmProvider{
dockerClient: client,
}
return p, nil
}
Scale a service - 1.Find the service
service, _, err := p.dockerClient.ServiceInspectWithRaw(ctx, serviceId, types.ServiceInspectOptions{
InsertDefaults: true,
})
if err != nil {
logrus.WithFields(logrus.Fields{
"error": err.Error(),
"provider": "swarm",
}).Debugf("Service %s didn't scale. We didn't get it from docker.", serviceId)
return err
}
filters := filters.NewArgs()
filters.Add("service", serviceId)
tasks, err := p.dockerClient.TaskList(ctx, types.TaskListOptions{Filters: filters})
if err != nil { … }
err = p.isAcceptable(tasks, target, direction)
Scale a service - 2.Update the Spec
spec := service.Spec
var ptrFromSystem uint64
base := p.calculateActiveTasks(tasks)
if direction == true {
ptrFromSystem = uint64(base + target)
} else {
ptrFromSystem = uint64(base - target)
}
spec.Mode.Replicated.Replicas = &ptrFromSystem
_, err = p.dockerClient.ServiceUpdate(ctx, serviceId, service.Version, spec, types.ServiceUpdateOptions{})
if err != nil {...}
Background job to sync services with Docker
services, err := dockerClient.ServiceList(ctx, types.ServiceListOptions{})
if err != nil {
logrus.WithField("error", err).Debug("Bad communication with Docker.")
return
}
prov, _ := provider.NewSwarmProvider(map[string]string{})
for _, service := range services {
s, err := getAutoscalerByService(prov, service.Spec.Annotations)
if err != nil {
continue
}
c.Autoscalers[fmt.Sprintf("autoswarm/%s", service.Spec.Annotations.Name)] = s
}
Is orbiter just a wrapper on Docker Swarm API?
Let’s put that in a cooler way.
Orbiter provides easy to use rest API to
scale your services up and down.
T-shirt time
Demo
Thanks a lot
https://twitter.com/gianarb
https://github.com/gianarb
https://gianarb.it

Orbiter and how to extend Docker Swarm

  • 1.
  • 2.
  • 3.
    Why? ● To createa use case around metrics, InfluxDB and Docker. ● Docker Swarm at the moment doesn’t provider autoscale capabilities. ● To design an application easy to manage and well integrated in Docker Swarm.
  • 4.
    Orbiter is ageneral-purpose multi vendor autoscaler
  • 5.
    Orbiter is ageneral-purpose multi vendor autoscaler Orbiter is a Docker Swarm autoscaler
  • 6.
    swarm cluster manager get metrics: ●cadvidor ● telegraf ● …. alert: ● custom ● kapacitor ● alert manager
  • 7.
    Why Docker Swarmdoesn’t have autoscaling? ● I don’t know. ● As you can see the architecture required is not small. ● Probably it will have autoscaling at some point.
  • 8.
    Orbiter is designedto be Only-Swarm ● To make it easy to start ● To remove abstractions ● Because less is more! cit unknown but for sure a lazy person
  • 9.
    What does it? ●It lists all your services and it gets only who has label orbiter=true ● Expose and HTTP API to trigger up and down scale event ○ curl -X POST -v http://$(IP):8081/v1/orbiter/handle/autoswarm/stack_micro/up ○ curl -X POST -v http://$(IP):8081/v1/orbiter/handle/autoswarm/stack_micro/down ● It uses Docker Swarm Api to keep in sync the managed services ● You can configure a service via label orbiter.up=3, orbiter.donw=2, orbiter.cooldown = 2
  • 10.
  • 11.
    Deploy it asservice in Docker Swarm version: '3' services: orbiter: image: gianarb/orbiter command: daemon ports: - 8081:8000 volumes: - /var/run/docker.sock:/var/run/docker.sock deploy: placement: constraints: - node.role == manager mode: replicated replicas: 1
  • 12.
    How Orbiter communicatewith Swarm func NewSwarmProvider(c map[string]string) (autoscaler.Provider, error) { var p autoscaler.Provider client, err := docker.NewEnvClient() if err != nil { logrus.WithField("error", err).Warn("problem to communicate with docker") return p, err } else { logrus.Info("Successfully connected to a Docker daemon") } p = SwarmProvider{ dockerClient: client, } return p, nil }
  • 14.
    Scale a service- 1.Find the service service, _, err := p.dockerClient.ServiceInspectWithRaw(ctx, serviceId, types.ServiceInspectOptions{ InsertDefaults: true, }) if err != nil { logrus.WithFields(logrus.Fields{ "error": err.Error(), "provider": "swarm", }).Debugf("Service %s didn't scale. We didn't get it from docker.", serviceId) return err } filters := filters.NewArgs() filters.Add("service", serviceId) tasks, err := p.dockerClient.TaskList(ctx, types.TaskListOptions{Filters: filters}) if err != nil { … } err = p.isAcceptable(tasks, target, direction)
  • 15.
    Scale a service- 2.Update the Spec spec := service.Spec var ptrFromSystem uint64 base := p.calculateActiveTasks(tasks) if direction == true { ptrFromSystem = uint64(base + target) } else { ptrFromSystem = uint64(base - target) } spec.Mode.Replicated.Replicas = &ptrFromSystem _, err = p.dockerClient.ServiceUpdate(ctx, serviceId, service.Version, spec, types.ServiceUpdateOptions{}) if err != nil {...}
  • 16.
    Background job tosync services with Docker services, err := dockerClient.ServiceList(ctx, types.ServiceListOptions{}) if err != nil { logrus.WithField("error", err).Debug("Bad communication with Docker.") return } prov, _ := provider.NewSwarmProvider(map[string]string{}) for _, service := range services { s, err := getAutoscalerByService(prov, service.Spec.Annotations) if err != nil { continue } c.Autoscalers[fmt.Sprintf("autoswarm/%s", service.Spec.Annotations.Name)] = s }
  • 17.
    Is orbiter justa wrapper on Docker Swarm API? Let’s put that in a cooler way. Orbiter provides easy to use rest API to scale your services up and down.
  • 18.
  • 19.
  • 21.