Code Monkey home page Code Monkey logo

bamboo's Introduction

Bamboo GoDoc Build Status Coverage Status

bamboo-logo

Bamboo is a web daemon that automatically configures HAProxy for web services deployed on Apache Mesos and Marathon.

It features:

  • User interface for configuring HAProxy ACL rules for each Marathon application
  • Rest API for configuring proxy ACL rules
  • Auto configure HAProxy configuration file based your template; you can provision your own template in production to enable SSL and HAProxy stats interface, or configuring different load balance strategy
  • Optionally handles health check endpoint if Marathon app is configured with Healthchecks
  • Daemon itself is stateless; enables horizontal replication and scalability
  • Developed in Golang, deployment on HAProxy instance has no additional dependency
  • Optionally integrates with StatsD to monitor configuration reload event

Compatibility

v0.1.1 supports Marathon 0.6 and Mesos 0.19.x

v0.2.2 supports both DNS and non-DNS proxy ACL rules

v0.2.8 supports both HTTP & TCP via custom Marathon enviroment variables (read below for details)

v0.2.9 supports Marathon 0.7.* (with http_callback enabled) and Mesos 0.21.x

v0.2.11 improves API, deprecate previous API endpoint

Marathon Compatibility

Marathon >= 1.5.0 Deprecated event registration method; Make sure configure Bamboo with "UseEventStream": true

Releases and changelog

Since Marathon API and behaviour may change over time, especially in this early days. You should expect we aim to catch up those changes, improve design and adding new features. We aim to maintain backwards compatibility when possible. Releases and changelog are maintained in the releases page. Please read them when upgrading.

Deployment Guide

You can deploy Bamboo with HAProxy on each Mesos slave. Each web service being allocated on Mesos Slave can discover services via localhost or domain you assigned by ACL rules. Alternatively, you can deploy Bamboo and HAProxy on separate instances, which means you need to loadbalance HAProxy cluster.

bamboo-setup-guide

User Interface

UI is useful to manage and visualize current state of proxy rules. Of course, you can configure HAProxy template to load balance Bamboo.

user-interface-list

user interface

StatsD Monitoring

bamboo-graphite

Configuration and Template

Bamboo binary accepts -config option to specify application configuration JSON file location. Type -help to get current available options.

Example configuration and HAProxy template can be found under config/production.example.json and config/haproxy_template.cfg This section tries to explain usage in code comment style:

{
  // Marathon instance configuration
  "Marathon": {
    // Marathon service HTTP endpoints
    "Endpoint": "http://marathon1:8080,http://marathon2:8080,http://marathon3:8080",
    // Use the Marathon HTTP event streaming feature (Bamboo 0.2.16, Marathon v0.9.0)
    // Required set to true if Marathon version is >= 1.5.0
    "UseEventStream": true
  },

  "Bamboo": {
    // Bamboo's HTTP address can be accessed by Marathon
    // This is used for Marathon HTTP callback, and each instance of Bamboo
    // must be provided a unique Endpoint directly addressable by Marathon
    // (e.g., the IP address of each server)
    "Endpoint": "http://localhost:8000",

    // Proxy setting information is stored in Zookeeper
    // Bamboo will create this path if it does not already exist
    "Zookeeper": {
      // Use the same ZK setting if you run on the same ZK cluster
      "Host": "zk01.example.com:2812,zk02.example.com:2812",
      "Path": "/marathon-haproxy/state",
      "ReportingDelay": 5
    }
  }


  // Make sure using absolute path on production
  "HAProxy": {
    "TemplatePath": "/var/bamboo/haproxy_template.cfg",
    "OutputPath": "/etc/haproxy/haproxy.cfg",
    "ReloadCommand": "haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -D -sf $(cat /var/run/haproxy.pid)",
    // A command that will validate the config before running reload command.
    // '{{.}}' will be expanded to a temporary path that contains the config contents
    "ReloadValidationCommand": "haproxy -c -f {{.}}",
    // A command that will always be run after ReloadCommand, even if the reload fails
    "ReloadCleanupCommand": "exit 0"
  },

  // Enable or disable StatsD event tracking
  "StatsD": {
    "Enabled": false,
    // StatsD or Graphite server host
    "Host": "localhost:8125",
    // StatsD namespace prefix
    // If you have multiple Bamboo instances, you might want to label each node
    // by bamboo-server.production.n1.
    "Prefix": "bamboo-server.production."
  }
}

Customize HAProxy Template with Marathon App Environment Variables

Marathon app env variables are available to be called in the template. The default template shipped with Bamboo is aware of BAMBOO_TCP_PORT. When this variable is specified in Marathon app creation, the application will be configured with TCP mode. For example:

{
  "id": "FileServer",
  "cmd": "python -m SimpleHTTPServer $PORT0",
  "cpus": 0.1,
  "mem": 90,
  "ports": [0],
  "instances": 2,
  "env": {
    "BAMBOO_TCP_PORT": "1080",
    "MY_CUSTOM_ENV": "hello"
  }
}

In this example, both BAMBOO_TCP_PORT and MY_CUSTOM_ENV can be accessed in HAProxy template. This enables flexible template customization depending on your preferences.

Default Haproxy Template ACL

The default acl rule in the haproxy_template.cfg uses the full marathon app id, which may include slash-separated groups.

        # This is the default proxy criteria
        acl {{ $app.EscapedId }}-aclrule path_beg -i {{ $app.Id }}

For example if your app is named "/mygroup/appname", your default acl will be path_beg -i /mygroup/appname. This can always be changed using the bamboo web UI.

There is also a DNS friendly version of your marathon app Id which can be used instead of the slash-separated one. MesosDnsId includes the groups as hyphenated suffixes. For example, if your appname is "/another/group/app" then the MesosDnsId will be "app-group-another".

You can edit the haproxy_template.cfg and use the DNS friendly name for your default ACL instead.

    acl {{ $app.EscapedId }}-aclrule hdr_dom(host) -i {{ $app.MesosDnsId }}

Environment Variables

Configuration in the production.json file can be overridden with environment variables below. This is generally useful when you are building a Docker image for Bamboo and HAProxy. If they are not specified then the values from the configuration file will be used.

Environment Variable Corresponds To
MARATHON_ENDPOINT Marathon.Endpoint
MARATHON_USER Marathon.User
MARATHON_PASSWORD Marathon.Password
BAMBOO_ENDPOINT Bamboo.Endpoint
BAMBOO_ZK_HOST Bamboo.Zookeeper.Host
BAMBOO_ZK_PATH Bamboo.Zookeeper.Path
HAPROXY_TEMPLATE_PATH HAProxy.TemplatePath
HAPROXY_OUTPUT_PATH HAProxy.OutputPath
HAPROXY_RELOAD_CMD HAProxy.ReloadCommand
BAMBOO_DOCKER_AUTO_HOST Sets BAMBOO_ENDPOINT=$HOST when Bamboo container starts. Can be any value.
STATSD_ENABLED StatsD.Enabled
STATSD_PREFIX StatsD.Prefix
STATSD_HOST StatsD.Host

REST APIs

GET /api/state

Shows the data structure used for rendering template

curl -i http://localhost:8000/api/state

GET /api/services

Shows all service configurations

curl -i http://localhost:8000/api/services

Example result:

{
    "/authentication-service": {
        "Id": "/authentication-service",
        "Acl": "path_beg -i /authentication-service"
    },
    "/payment-service": {
        "Id": "/payment-service",
        "Acl": "path_beg -i /payment-service"
    }
}

POST /api/services

Creates a service configuration for a Marathon Application ID

curl -i -X POST -d '{"id":"/ExampleAppGroup/app1","acl":"hdr(host) -i app-1.example.com"}' http://localhost:8000/api/services

PUT /api/services/:id

Updates an existing or creates a new service configuration for a Marathon application. :id is the Marathon Application ID

curl -i -X PUT -d '{"id":"/ExampleAppGroup/app1", "acl":"path_beg -i /group/app-1"}' http://localhost:8000/api/services//ExampleAppGroup/app1

Note: Create semantics are available since version 0.2.11.

DELETE /api/services/:id

Deletes an existing service configuration. :id Marathon Application ID

curl -i -X DELETE http://localhost:8000/api/services//ExampleAppGroup/app1

GET /status

Bamboo webapp's healthcheck point

curl -i http://localhost:8000/status

Deployment

We recommend installing binary with deb or rpm package.

The repository includes an example deb package build script called builder/build.sh which generates a deb package in ./output. For this install fpm and run:

go build bamboo.go
./builder/build.sh

Moreover, there is

docker build -f Dockerfile-deb -t bamboo-build .
docker run -it -v $(pwd)/output:/output bamboo-build

Independently how you build the deb package, you can copy it to a server or publish to your own apt repository.

The example deb package deploys:

  • Upstart job bamboo-server, e.g. upstart assumes /var/bamboo/production.json is configured correctly.
  • Application directory is under /opt/bamboo/
  • Configuration and logs is under /var/bamboo/
  • Log file is rotated automatically

In case you're not using upstart, a template init.d service is provided in init.d-bamboo-server. Install it with

sudo cp builder/init.d-bamboo-server /etc/init.d/bamboo-server
sudo chown root:root /etc/init.d/bamboo-server
sudo chmod 755 /etc/init.d/bamboo-server
sudo update-rc.d "bamboo-server" defaults

You can then start the server with sudo service bamboo-server start. Other commands: status, restart, stop

As a Docker container

There is a Dockerfile that will allow Bamboo to be built and run from within a Docker container.

Building the image

The Docker image can be built and added to your local repository with the following command from within the project root directory:

docker build -t bamboo .

Running Bamboo as a Docker container

Once the image has been built, running as a container is straightforward - you do however still need to provide the configuration to the image as environment variables. Docker allows two options for this - using the -e option or by putting them in a file and using the --env-file option. Bamboo use Marathon event bus to get app info, so make sure set --event_subscriber http_callback or env MARATHON_EVENT_SUBSCRIBER=http_callback before start marathon instance.For this example we will use the former and we will map through ports 8000 and 80 to the docker host (obviously the hosts configured here will need to be reachable from this container):

docker run -t -i --rm -p 8000:8000 -p 80:80 \
    -e MARATHON_ENDPOINT=http://marathon1:8080,http://marathon2:8080,http://marathon3:8080 \
    -e BAMBOO_ENDPOINT=http://bamboo:8000 \
    -e BAMBOO_ZK_HOST=zk01.example.com:2181,zk02.example.com:2181 \
    -e BAMBOO_ZK_PATH=/bamboo \
    -e BIND=":8000" \
    -e CONFIG_PATH="config/production.example.json" \
    -e BAMBOO_DOCKER_AUTO_HOST=true \
    bamboo

Bamboo is started by supervisord in this Docker image. The default Supervisord configuration redirects stderr/stdout logs to the terminal. If you wish to turn the debug information off in production, you can use an alternative configuration.

Development and Contribution

We use godep managing Go package dependencies; Goconvey for unit testing; CommonJS and SASS for frontend development and build distribution.

  • Golang 1.7
  • Node.js 0.10.x+

Golang:

# Pakcage manager
go get github.com/tools/godep
# Testing Toolkit
go get -t github.com/smartystreets/goconvey

cd $GOPATH/src/github.com/QubitProducts/bamboo

# Build your binary
go build

# Run test (requires a local zookeeper running)
goconvey

Node.js UI dependencies:

# Global 
npm install -g grunt-cli napa browserify node-static foreman karma-cli
# Local
npm install && napa

# Start a foreman configured with Procfile for building SASS and JavaScript 
nf start

License

Bamboo is released under Apache License 2.0

bamboo's People

Contributors

albertsj1 avatar apriendeau avatar bateau84 avatar boomfish avatar bsideup avatar cwegrzyn avatar dkesler avatar gmitre avatar hyper0x avatar j1n6 avatar jdubs avatar jhmartin avatar lclarkmichalek avatar lowstz avatar malterb avatar mbabineau avatar michaelscheetz-hpe avatar mvallerie avatar pdpi avatar pingz avatar raravena80 avatar rasputnik avatar sergesyrota avatar sttts avatar timoreimann avatar willbern avatar xianlubird avatar xperimental avatar zariel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bamboo's Issues

no change in marathon but haproxy reloads

Hi,

haproxy reloads every 30 seconds even if there are no changes in marathon.

2014/09/11 13:24:45 qzk.go:55: No further debouncing. Posting event
2014/09/11 13:24:50.935589 Marathon: State changed
2014/09/11 13:24:51.104599 HAProxy: Configuration updated
2014/09/11 13:24:51.142967 Exec cmd: haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid)
2014/09/11 13:25:15 qzk.go:51: Got event. Delaying post
2014/09/11 13:25:15 qzk.go:55: No further debouncing. Posting event
2014/09/11 13:25:20.936585 Marathon: State changed
2014/09/11 13:25:21.102402 HAProxy: Configuration updated
2014/09/11 13:25:21.135208 Exec cmd: haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid)
2014/09/11 13:25:45 qzk.go:51: Got event. Delaying post
2014/09/11 13:25:45 qzk.go:55: No further debouncing. Posting event
2014/09/11 13:25:50.933389 Marathon: State changed
2014/09/11 13:25:51.095557 HAProxy: Configuration updated
2014/09/11 13:25:51.132177 Exec cmd: haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid)
2014/09/11 13:26:15 qzk.go:51: Got event. Delaying post
2014/09/11 13:26:15 qzk.go:55: No further debouncing. Posting event
2014/09/11 13:26:20.933709 Marathon: State changed
2014/09/11 13:26:21.107363 HAProxy: Configuration updated
2014/09/11 13:26:21.144372 Exec cmd: haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid)

Best,

Mike

panic: runtime error: index out of range

I deployed bamboo on ubuntu 14.04 (master) and created a new app:
marathon Id: "jenkins"
domain: "jenkins.rnatest.brightcove.com"
Nothing seems to update in the UI and looking a the logs i see:

2014/09/09 21:11:04.189694 [ip-10-146-205-81/tF2Zg1BkAD-000001] Started POST "/api/state/domains" from 50.197.95.1:34552
2014/09/09 21:11:04.192254 [ip-10-146-205-81/tF2Zg1BkAD-000001] Returning 200 in 2.499162ms
2014/09/09 21:11:04.295404 [ip-10-146-205-81/tF2Zg1BkAD-000002] Started GET "/api/state" from 50.197.95.1:34552
2014/09/09 21:11:04.438776 [ip-10-146-205-81/tF2Zg1BkAD-000002] panic: runtime error: index out of range
2014/09/09 21:11:04.439196 [ip-10-146-205-81/tF2Zg1BkAD-000002] Returning 500 in 143.765582ms
2014/09/09 21:11:06.030963 [ip-10-146-205-81/tF2Zg1BkAD-000003] Started GET "/" from 50.197.95.1:34552
2014/09/09 21:11:06.031108 [ip-10-146-205-81/tF2Zg1BkAD-000003] Returning 304 in 95.871us
2014/09/09 21:11:06.231419 [ip-10-146-205-81/tF2Zg1BkAD-000004] Started GET "/dist/main-app.js" from 50.197.95.1:52581
2014/09/09 21:11:06.231478 [ip-10-146-205-81/tF2Zg1BkAD-000004] Returning 304 in 31.071us
2014/09/09 21:11:06.231700 [ip-10-146-205-81/tF2Zg1BkAD-000005] Started GET "/dist/main.css" from 50.197.95.1:59688
2014/09/09 21:11:06.231743 [ip-10-146-205-81/tF2Zg1BkAD-000005] Returning 304 in 22.723us
2014/09/09 21:11:06.231938 [ip-10-146-205-81/tF2Zg1BkAD-000006] Started GET "/dist/main-libs.js" from 50.197.95.1:34552
2014/09/09 21:11:06.231980 [ip-10-146-205-81/tF2Zg1BkAD-000006] Returning 304 in 21.994us
2014/09/09 21:11:06.490896 [ip-10-146-205-81/tF2Zg1BkAD-000007] Started GET "/api/state" from 50.197.95.1:59688
2014/09/09 21:11:06.642818 [ip-10-146-205-81/tF2Zg1BkAD-000007] panic: runtime error: index out of range
2014/09/09 21:11:06.643170 [ip-10-146-205-81/tF2Zg1BkAD-000007] Returning 500 in 152.238341ms
2014/09/09 21:11:07.015312 [ip-10-146-205-81/tF2Zg1BkAD-000008] Started GET "/" from 50.197.95.1:59688
2014/09/09 21:11:07.017793 [ip-10-146-205-81/tF2Zg1BkAD-000008] Returning 200 in 2.421628ms
2014/09/09 21:11:07.189494 [ip-10-146-205-81/tF2Zg1BkAD-000009] Started GET "/dist/main-libs.js" from 50.197.95.1:59688
2014/09/09 21:11:07.195451 [ip-10-146-205-81/tF2Zg1BkAD-000010] Started GET "/dist/main-app.js" from 50.197.95.1:52581
2014/09/09 21:11:07.195998 [ip-10-146-205-81/tF2Zg1BkAD-000011] Started GET "/dist/main.css" from 50.197.95.1:34552
2014/09/09 21:11:07.297142 [ip-10-146-205-81/tF2Zg1BkAD-000010] Returning 200 in 101.650699ms
2014/09/09 21:11:07.297552 [ip-10-146-205-81/tF2Zg1BkAD-000011] Returning 200 in 101.5153ms
2014/09/09 21:11:07.863142 [ip-10-146-205-81/tF2Zg1BkAD-000009] Returning 200 in 673.584726ms
2014/09/09 21:11:08.155449 [ip-10-146-205-81/tF2Zg1BkAD-000012] Started GET "/fonts/ionicons.ttf?v=1.5.2" from 50.197.95.1:52581
2014/09/09 21:11:08.155677 [ip-10-146-205-81/tF2Zg1BkAD-000013] Started GET "/api/state" from 50.197.95.1:59688
2014/09/09 21:11:08.156843 Marathon: State changed
2014/09/09 21:11:08.545464 [ip-10-146-205-81/tF2Zg1BkAD-000012] Returning 200 in 389.94999ms
2014/09/09 21:11:08.742842 [ip-10-146-205-81/tF2Zg1BkAD-000014] Started GET "/favicon.ico" from 50.197.95.1:52581
2014/09/09 21:11:08.742926 [ip-10-146-205-81/tF2Zg1BkAD-000014] Returning 404 in 41.233us
2014/09/09 21:11:08.776081 [ip-10-146-205-81/tF2Zg1BkAD-000013] panic: runtime error: index out of range
2014/09/09 21:11:08.776480 [ip-10-146-205-81/tF2Zg1BkAD-000013] Returning 500 in 620.766409ms
2014/09/09 21:11:08.834330 Starting Goji on [::]:8000
2014/09/09 21:11:10.854234 [ip-10-146-205-81/ZJyf9oeUzk-000001] Started GET "/api/state/domains" from 127.0.0.1:50246
2014/09/09 21:11:10.855212 [ip-10-146-205-81/ZJyf9oeUzk-000001] Returning 200 in 930.746us
2014/09/09 21:11:38.142537 Marathon: State changed
2014/09/09 21:11:38.472626 Starting Goji on [::]:8000
2014/09/09 21:12:08.153508 Marathon: State changed
2014/09/09 21:12:08.424940 Starting Goji on [::]:8000
2014/09/09 21:12:38.143537 Marathon: State changed
2014/09/09 21:12:38.471640 Starting Goji on [::]:8000
2014/09/09 21:13:08.636313 Marathon: State changed
2014/09/09 21:13:08.951384 Starting Goji on [::]:8000
2014/09/09 21:13:38.144468 Marathon: State changed
2014/09/09 21:13:38.418398 Starting Goji on [::]:8000
2014/09/09 21:14:08.143968 Marathon: State changed
2014/09/09 21:14:08.447555 Starting Goji on [::]:8000
2014/09/09 21:14:36.398245 [ip-10-146-205-81/I7hhxpqesc-000001] Started GET "/" from 50.197.95.1:13641
2014/09/09 21:14:36.401455 [ip-10-146-205-81/I7hhxpqesc-000001] Returning 200 in 3.141018ms
2014/09/09 21:14:36.645516 [ip-10-146-205-81/I7hhxpqesc-000002] Started GET "/dist/main-libs.js" from 50.197.95.1:13641
2014/09/09 21:14:36.645762 [ip-10-146-205-81/I7hhxpqesc-000003] Started GET "/dist/main-app.js" from 50.197.95.1:60232
2014/09/09 21:14:36.649878 [ip-10-146-205-81/I7hhxpqesc-000004] Started GET "/dist/main.css" from 50.197.95.1:24151
2014/09/09 21:14:36.832260 [ip-10-146-205-81/I7hhxpqesc-000003] Returning 200 in 186.448961ms
2014/09/09 21:14:36.832417 [ip-10-146-205-81/I7hhxpqesc-000004] Returning 200 in 182.492761ms
2014/09/09 21:14:37.412150 [ip-10-146-205-81/I7hhxpqesc-000002] Returning 200 in 766.568162ms
2014/09/09 21:14:37.759763 [ip-10-146-205-81/I7hhxpqesc-000005] Started GET "/api/state" from 50.197.95.1:13641
2014/09/09 21:14:37.763757 [ip-10-146-205-81/I7hhxpqesc-000006] Started GET "/fonts/ionicons.ttf?v=1.5.2" from 50.197.95.1:24151
2014/09/09 21:14:37.902539 [ip-10-146-205-81/I7hhxpqesc-000005] panic: runtime error: index out of range
2014/09/09 21:14:37.903141 [ip-10-146-205-81/I7hhxpqesc-000005] Returning 500 in 143.334318ms
2014/09/09 21:14:38.154143 [ip-10-146-205-81/I7hhxpqesc-000006] Returning 200 in 390.338903ms
2014/09/09 21:14:38.438154 [ip-10-146-205-81/I7hhxpqesc-000007] Started GET "/favicon.ico" from 50.197.95.1:24151
2014/09/09 21:14:38.438222 [ip-10-146-205-81/I7hhxpqesc-000007] Returning 404 in 31.211us
2014/09/09 21:14:38.601105 Marathon: State changed
2014/09/09 21:14:38.892008 Starting Goji on [::]:8000
2014/09/09 21:15:08.148493 Marathon: State changed
2014/09/09 21:15:08.416597 Starting Goji on [::]:8000
2014/09/09 21:15:38.203455 Marathon: State changed
2014/09/09 21:15:38.506437 Starting Goji on [::]:8000
2014/09/09 21:16:08.147463 Marathon: State changed
2014/09/09 21:16:08.449516 Starting Goji on [::]:8000

Looks like there is a problem but the error message isn't descriptive enough to diagnose it.

service on Debian Wheezy

I built the pkg on Debian Wheezy and installed it successfully. However there is something wrong with the start script as my system tells me the files dont exist how do I get the service to start?

Marathon timeout during HTTP POST to bamboo on bigger installations

The http handler of Bamboo does a lot of work, e.g. querying Zookeeper, reloading haproxy. This can take seconds on non-trivial installations.

Marathon sometimes sends a series of events to Marathon, each with its own POST request. This obviously times out (timeout 10 sec in Marathon). Hence, we are easily loosing events in Bamboo.

Custom key/value map to specify custom attributes for template rendering

Currently, the mode needs to be hardcoded e.g. "mode tcp" or "mode http". Can we make it configurable by adding tags for a given service so that we can use "$services.mode" to get the value ?

We can probably store key/value map to make it generic e.g. $services.param["mode"] to make any key referenced in ha proxy template.

Bamboo on every mesos slave and Marathon callback

Not sure if bug, but...
When running Bamboo on every mesos slave should I have callback in Marathon for each instance of Bamboo?
I thought one callback will be enough, but updates doesn't seem to propagate to other instances.

Allow automatic configuration of Host based routing

This is dependent on this issue in marathon: mesosphere/marathon#599

It would be great if I could configure Bamboo to automatically configure apps to hostnames via specifying metadata to Marathon.

For example, if I could specify a tag in Marathon of bamboo.hostname: my-app.example.com and have bamboo automatically configure that application when it sees it.

This would allow us to automatically configure and provision the load balancing for services based off of metadata for the application itself, rather than making a separate api call to provision load balancing.

Allow creating entries using PUT

Currently, to get a "create or update" behaviour, clients have to implement it themselves, because POSTing with an existing id will fail, as will putting with a non-existing id. It would be convenient if PUT could be used for creating new configurations too.

Allow multiple template file rendering

In my use case i use bamboo for update HAproxy and for Redis failover.
Today i need to have one instance of Bamboo for HAproxy and one instance of Bamboo for redis failover.
It will be nice if i can use only once instance of Bamboo to udpate HAproxy and Redis failover.

Index out of range with jobs without ports

With the new 0.2.1 release, Mesos 0.2, Marathon 0.7.0rc3, I get the backtrace shown below just after startup. I have a Docker task in Marathon without ports. I registered that with the old bamboo version.

2014/09/19 06:48:47.715526 Using environment override MARATHON_ENDPOINT=http://10.0.0.1:5080
2014/09/19 06:48:47.718157 Using environment override BAMBOO_ENDPOINT=http://10.0.0.1:9000
2014/09/19 06:48:47.719109 Using environment override BAMBOO_ZK_HOST=10.0.0.1:2181,10.0.0.2:2181,10.0.0.3:2181
2014/09/19 06:48:47.719512 Using environment override BAMBOO_ZK_PATH=/bamboo
2014/09/19 06:48:47.853548 Starting Goji on [::]:8000
2014/09/19 06:48:47.865740 �[30;1m[f061086f5cad/MZc8sXsCMT-000001] �[0mStarted �[35;1mPOST �[0m�[34m"/api/marathon/event_callback" �[0mfrom 10.0.0.1:53546
2014/09/19 06:48:47.868047 subscribe_event => 2014-09-19T06:48:47.807Z
2014/09/19 06:48:48.039152 �[30;1m[f061086f5cad/MZc8sXsCMT-000001] �[0m�[31;1mpanic: runtime error: index out of range�[0m
/opt/go/src/github.com/zenazn/goji/web/middleware/recoverer.go:24 (0x55dbed)
    com/zenazn/goji/web/middleware.func.006: debug.PrintStack()
/usr/lib/go/src/pkg/runtime/panic.c:248 (0x4149f6)
    panic: runtime·newstackcall(d->fn, (byte*)d->args, d->siz);
/usr/lib/go/src/pkg/runtime/panic.c:482 (0x41529d)
    panicstring: runtime·panic(err);
/usr/lib/go/src/pkg/runtime/panic.c:433 (0x4150b7)
    panicindex: runtime·panicstring("index out of range");
/opt/go/src/github.com/QubitProducts/bamboo/services/marathon/marathon.go:151 (0x5e3f45)
    com/QubitProducts/bamboo/services/marathon.createApps: simpleTasks = append(simpleTasks, Task{ Host: task.Host, Port: task.Ports[0] })
/opt/go/src/github.com/QubitProducts/bamboo/services/marathon/marathon.go:194 (0x5e406c)
    com/QubitProducts/bamboo/services/marathon.FetchApps: apps := createApps(tasks, marathonApps)
/opt/go/src/github.com/QubitProducts/bamboo/services/haproxy/haproxy.go:19 (0x575f61)
    com/QubitProducts/bamboo/services/haproxy.GetTemplateData: apps, _ := marathon.FetchApps(config.Marathon.Endpoint)
/opt/go/src/github.com/QubitProducts/bamboo/services/event_bus/event_handler.go:52 (0x48a3de)
    com/QubitProducts/bamboo/services/event_bus.handleHAPUpdate: templateData := haproxy.GetTemplateData(conf, conn)
/opt/go/src/github.com/QubitProducts/bamboo/services/event_bus/event_handler.go:36 (0x48a0a8)
    com/QubitProducts/bamboo/services/event_bus.(*Handlers).MarathonEventHandler: handleHAPUpdate(h.Conf, h.Zookeeper)
/opt/go/src/github.com/QubitProducts/bamboo/bamboo.go:52 (0x401d3d)
    com/QubitProducts/bamboo/services/event_bus.*Handlers.MarathonEventHandler.fm: eventBus.Register(handlers.MarathonEventHandler)
/usr/lib/go/src/pkg/runtime/asm_amd64.s:339 (0x425832)
    call32: CALLFN(call32, 32)
/usr/lib/go/src/pkg/reflect/value.go:474 (0x5428ab)
    Value.call: call(fn, ptr, uint32(size))
/usr/lib/go/src/pkg/reflect/value.go:345 (0x54199d)
    Value.Call: return v.call("Call", in)
/opt/go/src/github.com/QubitProducts/bamboo/services/event_bus/event_bus.go:66 (0x489d6a)
    com/QubitProducts/bamboo/services/event_bus.(*EventBus).Publish: fn.Call(args[:])
/opt/go/src/github.com/QubitProducts/bamboo/api/event_subscription.go:29 (0x484e46)
    com/QubitProducts/bamboo/api.(*EventSubscriptionAPI).Callback: sub.EventBus.Publish(event)
/opt/go/src/github.com/QubitProducts/bamboo/bamboo.go:77 (0x401f84)
    com/QubitProducts/bamboo/api.*EventSubscriptionAPI.Callback.fm: goji.Post("/api/marathon/event_callback", eventSubAPI.Callback)
/usr/lib/go/src/pkg/net/http/server.go:1220 (0x443c50)
    HandlerFunc.ServeHTTP: f(w, r)
/opt/go/src/github.com/zenazn/goji/web/router.go:113 (0x557c00)
    com/zenazn/goji/web.netHTTPWrap.ServeHTTPC: h.Handler.ServeHTTP(w, r)
/opt/go/src/github.com/zenazn/goji/web/atomic.go:1 (0x55ad32)
    com/zenazn/goji/web.(*netHTTPWrap).ServeHTTPC: // +build !appengine
/opt/go/src/github.com/zenazn/goji/web/router.go:210 (0x55849f)
    com/zenazn/goji/web.routeMachine.route: rm.routes[si].handler.ServeHTTPC(*c, w, r)
/opt/go/src/github.com/zenazn/goji/web/router.go:251 (0x55880f)
    com/zenazn/goji/web.(*router).route: methods, ok := rm.route(c, w, r)
/opt/go/src/github.com/zenazn/goji/web/middleware.go:100 (0x5596d5)
    com/zenazn/goji/web.func.002: router.route(&cs.C, w, r)
/usr/lib/go/src/pkg/net/http/server.go:1220 (0x443c50)
    HandlerFunc.ServeHTTP: f(w, r)
/opt/go/src/github.com/zenazn/goji/web/middleware/options.go:70 (0x55db3e)
    com/zenazn/goji/web/middleware.func.004: h.ServeHTTP(w, r)
/usr/lib/go/src/pkg/net/http/server.go:1220 (0x443c50)
    HandlerFunc.ServeHTTP: f(w, r)
/opt/go/src/github.com/zenazn/goji/web/middleware/recoverer.go:29 (0x55dd23)
    com/zenazn/goji/web/middleware.func.007: h.ServeHTTP(w, r)
/usr/lib/go/src/pkg/net/http/server.go:1220 (0x443c50)
    HandlerFunc.ServeHTTP: f(w, r)
/opt/go/src/github.com/zenazn/goji/web/middleware/logger.go:27 (0x55d8ec)
    com/zenazn/goji/web/middleware.func.002: h.ServeHTTP(lw, r)
/usr/lib/go/src/pkg/net/http/server.go:1220 (0x443c50)
    HandlerFunc.ServeHTTP: f(w, r)
/opt/go/src/github.com/zenazn/goji/web/middleware/request_id.go:68 (0x55dfdb)
    com/zenazn/goji/web/middleware.func.008: h.ServeHTTP(w, r)
/usr/lib/go/src/pkg/net/http/server.go:1220 (0x443c50)
    HandlerFunc.ServeHTTP: f(w, r)
/opt/go/src/github.com/zenazn/goji/web/middleware.go:54 (0x554ee5)
    com/zenazn/goji/web.(*cStack).ServeHTTP: s.m.ServeHTTP(w, r)
/opt/go/src/github.com/zenazn/goji/web/mux.go:77 (0x555fff)
    com/zenazn/goji/web.(*Mux).ServeHTTP: stack.ServeHTTP(w, r)
/usr/lib/go/src/pkg/net/http/server.go:1496 (0x4450f3)
    (*ServeMux).ServeHTTP: h.ServeHTTP(w, r)
/opt/go/src/github.com/zenazn/goji/graceful/middleware.go:46 (0x561b99)
    com/zenazn/goji/graceful.func.002: h.ServeHTTP(&fancyWriter{bw}, r)
/usr/lib/go/src/pkg/net/http/server.go:1220 (0x443c50)
    HandlerFunc.ServeHTTP: f(w, r)
/usr/lib/go/src/pkg/net/http/server.go:1597 (0x4458fe)
    serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/lib/go/src/pkg/net/http/server.go:1167 (0x4438a7)
    (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/lib/go/src/pkg/runtime/proc.c:1394 (0x418d00)
    goexit: runtime·goexit(void)
2014/09/19 06:48:48.065102 �[30;1m[f061086f5cad/MZc8sXsCMT-000001] �[0mReturning �[31;1m500�[0m in �[32m199.234144ms�[0m

multiple master configuration

Hi,

sorry for posting this question, but I cannot get it to work properly:

I have a 3 master setup and the following config.json:

{
  "Marathon": {
    "Endpoint": "http://localhost:8080"
  },

  "Bamboo": {
    "Endpoint": "http://masterN:8000", # this is the local IP of this master
    "Zookeeper": {
      "Host": "master0:2181,master1:2181,master2:2181",
      "Path": "/marathon-haproxy/state",
      "ReportingDelay": 5
    }
  },

  "HAProxy": {
    "TemplatePath": "/opt/bamboo/config/haproxy_template.cfg",
    "OutputPath": "/etc/haproxy/haproxy.cfg",
    "ReloadCommand": "PIDS=`pidof haproxy`; haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $PIDS && while ps -p $PIDS; do sleep 0.2; done"
  },

  "StatsD": {
    "Enabled": false,
    "Host": "localhost:8125",
    "Prefix": "bamboo-server.development."
  }
}

explanation: as a bamboo endpoint I used each master's ip address, marathon endpoint is localhost and the zookeeper hosts are my three master ip addresses. Now my website switches between available and 503 in a millisecond manner. How do I make this setup work?

URI encoded marathon application ids are double encoded

The README about the REST API says that marathon application ids have to be URI encoded. The given examples in the documentation are actually double encoded. I’ve tried both, single encoded and double encoded marathon app ids, the REST API only works with double encoded ids.

  1. Example from documentdation: curl -i -X DELETE http://localhost:8000/api/services/%252Fapp-1
  2. Decoded: http://localhost:8000/api/services/%2Fapp-1
  3. Decoded again: http://localhost:8000/api/services//app-1

Healthcheck on different port?

With portIndex, Marathon health checks can be configured to run against any port associated with the task:

{
  "path": "/api/health",
  "portIndex": 0,
  "protocol": "HTTP",
  "gracePeriodSeconds": 30,
  "intervalSeconds": 30,
  "timeoutSeconds": 30,
  "maxConsecutiveFailures": 3
}

The health check port isn't currently available within Bamboo - it's simply assumed that it's equal to $task.Port. Consequently, configuring a Marathon app with a health check on a different port results in the app always failing HAProxy's checks.

Is there a way we could get something like $task.HealthCheckPort?

server {{ $app.EscapedId}}...check inter 30000 check port {{ $task.HealthCheckPort }}

bamboo to read marathon endpoint from zookeeper

Is it possible to define MARATHON_ENDPOINT by specifying zookeeper path like you can when running for example mesos frameworks?

Path could be:
zk://10.0.1.45:2181,10.0.1.47:2181,10.0.1.46:2181/marathon

unknown lumberjack.Logger field

Hi,

im new to go so maybe just a simple error on my side.

Downloaded all the git stated in bamboo.go (zookeeper etc.) and did go bamboo.go which results in:

# command-line-arguments
./bamboo.go:119: unknown lumberjack.Logger field 'Filename' in struct literal

Best,

Mike

qzk.sinkSelfEvents panic

I'm not quite sure why or what the error is but I'm getting a panic in qzk.sinkSelfEvents:

goroutine 30 [chan receive]:
github.com/samuel/go-zookeeper/zk.(*Conn).request(0xc210068750, 0xc200000004, 0x641ea0, 0xc2100598e0, 0x641ee0, ...)
    /tmp/src/github.com/samuel/go-zookeeper/zk/conn.go:595 +0x8f
github.com/samuel/go-zookeeper/zk.(*Conn).GetW(0xc210068750, 0xc210059e80, 0x1b, 0x0, 0x0, ...)
    /tmp/src/github.com/samuel/go-zookeeper/zk/conn.go:638 +0x15f
github.com/QubitProducts/bamboo/qzk.func·004()
    /tmp/src/github.com/QubitProducts/bamboo/qzk/qzk.go:82 +0x5d
created by github.com/QubitProducts/bamboo/qzk.sinkSelfEvents
    /tmp/src/github.com/QubitProducts/bamboo/qzk/qzk.go:98 +0xfb

I've been trying with different Zookeeper settings and tried to purge all data in both /marathon as well as /bamboo (/bamboo/state is set as DomainMapping path).

Do you have any pointers or can I provide anything else to help investigating?

Thanks!

bamboo - newbie question

i am reading alot about mesos and marathon in specific since i'm interested in using mesos for managing long lived micro services. I would like to know what bamboo gives that mesos / marathon in it's latest version does not provide out of the box.

also - do you think that this project could be converged into marathon at some point or do you see this project continues to grow side by side.

finally - what is the current status of bamboo (known production installations etc) and what is your roadmap?

thanks for the very well and organised documentation!

Chen.

Missing app in Marathon

I have trouble adding app to bamboo from gui.

I've added app called /luigi-test and it says Missing app in Marathon.

I am running bamboo as docker container with command:

/usr/bin/docker run --rm --name bamboo -p 8000:8000 -p 80:80 -e MARATHON_ENDPOINT=10.0.1.149:8081 -e BAMBOO_ENDPOINT=10.0.1.151:8000 -e BAMBOO_ZK_HOST="10.0.1.149:2181,10.0.1.151:2181,10.0.1.150:2181" -e BAMBOO_ZK_PATH=/bamboo quay.io/appuri/bamboo -bind=":8000" -config="config/production.example.json"

docker container logs:
Nov 01 22:08:56 ip-10-0-1-151.us-west-2.compute.internal bash[16882]: 2014/11/01 22:08:56 Starting update loop
Nov 01 22:08:56 ip-10-0-1-151.us-west-2.compute.internal bash[16882]: 2014/11/01 22:08:56.052755 Using environment override MARATHON_ENDPOINT=10.0.1.149:8081
Nov 01 22:08:56 ip-10-0-1-151.us-west-2.compute.internal bash[16882]: 2014/11/01 22:08:56.052823 Using environment override BAMBOO_ENDPOINT=10.0.1.151:8000
Nov 01 22:08:56 ip-10-0-1-151.us-west-2.compute.internal bash[16882]: 2014/11/01 22:08:56.052891 Using environment override BAMBOO_ZK_HOST=10.0.1.149:2181,10.0.1.151:2181,10.0.1.150:2181
Nov 01 22:08:56 ip-10-0-1-151.us-west-2.compute.internal bash[16882]: 2014/11/01 22:08:56.052949 Using environment override BAMBOO_ZK_PATH=/bamboo

When app added:
From bamboo logs:
Nov 02 06:05:37 ip-10-0-1-151.us-west-2.compute.internal bash[16882]: 2014/11/02 06:05:37.653968 Domain mapping: Stated changed
Nov 02 06:05:37 ip-10-0-1-151.us-west-2.compute.internal bash[16882]: 2014/11/02 06:05:37.653983 Queuing an haproxy update.
Nov 02 06:05:37 ip-10-0-1-151.us-west-2.compute.internal bash[16882]: 2014/11/02 06:05:37.655489 HAProxy: Same content, no need to reload

From marathon, only relevant info I've found:

Nov 02 06:06:29 ip-10-0-1-149.us-west-2.compute.internal bash[6143]: [2014-11-02 06:06:29,066] INFO 10.0.1.151 - - [02/Nov/2014:06:06:29 +0000] "GET /v2/tasks HTTP/1.1" 200 252 "-" "curl/7.26.0" (mesosphere.chaos.http.ChaosRequestLog:15)

I can add marathon callback and call to /v2/tasks returns following:
curl -X GET -H "Content-Type: application/json" 10.0.1.149:8081/v2/tasks
{"tasks":[{"appId":"/luigi-test","id":"luigi-test.70583548-5f32-11e4-8166-56847afe9799","host":"ip-10-0-1-149.us-west-2.compute.internal","ports":[31001],"startedAt":"2014-11-02T06:07:11.580Z","stagedAt":"2014-10-29T06:11:36.580Z","version":"2014-10-29T06:11:36.379Z","servicePorts":[9001]},{"appId":"/marathon-tcp-haproxy-dev","id":"marathon-tcp-haproxy-dev.9e92e270-606f-11e4-8166-56847afe9799","host":"ip-10-0-1-151.us-west-2.compute.internal","ports":[31187],"startedAt":"2014-11-02T06:07:11.602Z","stagedAt":"2014-10-30T20:02:04.602Z","version":"2014-10-29T09:20:19.048Z","servicePorts":[30000]},{"appId":"/demo-dev","id":"demo-dev.f56bbeb8-5ee8-11e4-8166-56847afe9799","host":"ip-10-0-1-149.us-west-2.compute.internal","ports":[31000],"startedAt":"2014-11-02T06:07:11.563Z","stagedAt":"2014-10-28T21:25:37.088Z","version":"2014-10-28T21:25:34.948Z","servicePorts":[9000]},{"appId":"/demo-dev","id":"demo-dev.f69d39da-5ee8-11e4-8166-56847afe9799","host":"ip-10-0-1-151.us-west-2.compute.internal","ports":[31000],"startedAt":"2014-11-02T06:07:11.572Z","stagedAt":"2014-10-28T21:25:39.089Z","version":"2014-10-28T21:25:34.948Z","servicePorts":[9000]}]}%

I am using mesos 0.20.1
marathon 0.7.3
latest bamboo

Do you have any advice on how I could debug this further?

Healthcheck improvments

  • Support multiple healthcheck per app
  • Support TCP, HTTP, COMMAND check specified in Marathon
  • Try not re-invent the wheel by getting health check information from marathon

Also related to #56 #62

Order of acl rules

The web ui allows to define haproxy ACLs, but not the order they are applied, i.e. the order of use_backend lines in the config. I propose to add an order either by drag'n'drop in the UI or by a priority value in order to allow use cases like these:

  • route requests with a certain header to canary instances of an app
  • route unknown domains to a default app.

serviceports aren't available in templates

Our current setup involves running each app on a standard port on the haproxy layer
(this is how marathons old haproxy_cfg used to generate configs).

Apps are deployed with a specific port as a way to 'tag' them for a given service.

Would be useful to expose that port for Bamboo templates too
(I notice Bamboo currently only exposes 1 port for tasks so I propose to keep that behaviour).

When zookeeper goes away, bamboo dies

Not sure if bug, but when running haproxy in the same container as bamboo, haproxy dies too and all requests all terminated.
It'd be cool if bamboo waited for zookeeper to be available doing nothing with haproxy config in the meantime.
Second solution would be running haproxy in separate container. If that's preferred - feel free to close the issue.
Some logs: https://gist.github.com/gregory90/00658376bc08dbe979da

bamboo not using service ports

I think current bamboo implementation does not take into account tasks service port(s).

Let me demonstrate it on one example with 2 exposed service ports:
Lets say I have following marathon app:

{
    "id": "marattest-dev",
    "cmd": "curl -q -o /app.py https://gist.githubusercontent.com/veverjak/b8607526f071f296bd8c/raw/3545a22d421d1f041ca5a8b305ea00f7edf967c6/get_file_content.py && python /app.py /etc/ip",
    "instances": 3,
    "cpus": 0.1,
    "mem": 10,
    "constraints": [],
    "uris": ["/.dockercfg"],
    "taskRateLimit": 1,
    "container": {
      "type": "DOCKER",
      "volumes": [
            {
                "containerPath": "/var/lib/scripts/create_configs.sh",
                "hostPath": "/var/lib/scripts/create_configs.sh",
                "mode": "RO"
            },
            {
                "containerPath": "/usr/bin/etcdctl",
                "hostPath": "/usr/bin/etcdctl",
                "mode": "RO"
            },
            {
                "containerPath": "/etc/ip",
                "hostPath": "/etc/ip",
                "mode": "RO"
            }
      ],
      "docker": {
        "image": "quay.io/appuri/get_file_content",
        "portMappings": [
          { "containerPort": 5000, "hostPort": 0, "servicePort": 9001, "protocol": "tcp" },
          { "containerPort": 5001, "hostPort": 0, "servicePort": 9002, "protocol": "tcp" }

        ],
        "network": "BRIDGE"
      }
    }
}

result for /v2/tasks gives:

{
  "tasks": [
    {
      "appId": "/marattest-dev",
      "id": "marattest-dev.46b9ab9c-6738-11e4-b85e-1645b8de8fb1",
      "host": "ip-10-0-1-151.us-west-2.compute.internal",
      "ports": [
        31003,
        31004
      ],
      "startedAt": "2014-11-08T11:38:08.063Z",
      "stagedAt": "2014-11-08T11:13:33.038Z",
      "version": "2014-11-08T11:13:29.557Z",
      "servicePorts": [
        9001,
        9002
      ]
    },
    {
      "appId": "/marattest-dev",
      "id": "marattest-dev.c2f5c97a-6736-11e4-b85e-1645b8de8fb1",
      "host": "ip-10-0-1-149.us-west-2.compute.internal",
      "ports": [
        31006,
        31007
      ],
      "startedAt": "2014-11-08T11:38:08.051Z",
      "stagedAt": "2014-11-08T11:02:42.474Z",
      "version": "2014-11-08T11:02:39.555Z",
      "servicePorts": [
        9001,
        9002
      ]
    },
    {
      "appId": "/marattest-dev",
      "id": "marattest-dev.4752421f-6738-11e4-b85e-1645b8de8fb1",
      "host": "ip-10-0-1-149.us-west-2.compute.internal",
      "ports": [
        31008,
        31009
      ],
      "startedAt": "2014-11-08T11:38:08.022Z",
      "stagedAt": "2014-11-08T11:13:34.037Z",
      "version": "2014-11-08T11:13:29.557Z",
      "servicePorts": [
        9001,
        9002
      ]
    },

If I am using default marathon bash script to create haproxy.cfg, I get:

listen marattest-dev-9001
  bind 0.0.0.0:9001
  mode tcp
  option tcplog
  balance leastconn
  server marattest-dev-3 ip-10-0-1-151.us-west-2.compute.internal:31003 check
  server marattest-dev-2 ip-10-0-1-149.us-west-2.compute.internal:31006 check
  server marattest-dev-1 ip-10-0-1-149.us-west-2.compute.internal:31008 check

listen marattest-dev-9002
  bind 0.0.0.0:9002
  mode tcp
  option tcplog
  balance leastconn
  server marattest-dev-3 ip-10-0-1-151.us-west-2.compute.internal:31004 check
  server marattest-dev-2 ip-10-0-1-149.us-west-2.compute.internal:31007 check
  server marattest-dev-1 ip-10-0-1-149.us-west-2.compute.internal:31009 check

If I want the same from bamboo, it generates:

## listen ::marattest-dev_0
##   bind *:0
##   mode http
##
##   balance leastconn
##   option forwardfor
##
##         server ::marattest-dev-ip-10-0-1-149.us-west-2.compute.internal-31006 ip-10-0-1-149.us-west-2.compute.internal:31006
##         server ::marattest-dev-ip-10-0-1-151.us-west-2.compute.internal-31003 ip-10-0-1-151.us-west-2.compute.internal:31003
##         server ::marattest-dev-ip-10-0-1-149.us-west-2.compute.internal-31008 ip-10-0-1-149.us-west-2.compute.internal:31008
#

It is because listen endpoint is created only per app and first app port is considered to be the only service port which I didn't define because I expected same behavior like default bash script has.

Workaround for me will be defining ports: [] per app and use only one port, which is fine for now, but I believe this can be easily fixed by adding proper structure in Create Apps.

hardcoded marathon URL makes HA tricky

Just wondered if it's possible to look up the current marathon master via zookeeper somehow?

As it stands a single URL seems to be the only way to find marathon, which breaks
if that marathon node is down.

Docker Container Fails to Deploy

Hi,

I'm attempting to deploy bamboo in a docker container as described in the documentation. I've built the docker image, but it is unable to find the config file when I run it. Here's what I'm seeing:

[root@bamboo bamboo-0.2.9]# ls -l config/bamboo_test.json
-rw-r--r--. 1 root root 642 Mar  6 20:51 config/bamboo_test.json
[root@bamboo bamboo-0.2.9]# docker run -t -i --rm -p 8000:8000 -p 80:80 \
     -e MARATHON_ENDPOINT=http://xxx.xxx.xxx.xxx:8080 \
     -e BAMBOO_ENDPOINT=http://xxx.xxx.xxx.xxx:8000 \
     -e BAMBOO_ZK_HOST=xxx.xxx.xxx.xxx:2181 \
     -e BAMBOO_ZK_PATH=/bamboo \
     -e BIND=":8000" \
     -e CONFIG_PATH="config/bamboo_test.json" \
     -e BAMBOO_DOCKER_AUTO_HOST=true \
     bamboo
sed: can't read config/bamboo_test.json: No such file or directory

Thanks in advance for the help.

bamboo is proxying even to hosts that are not started by marathon yet

When I scale my app up and there are 4 of 10 apps running bamboo creates config for all of them.
Currently I do not have health checks (that is how I've found out about this) and I am aware I should have those implemented.
IMO this could be handled by bamboo which would create haproxy configuration only for the apps which are currenly up.

Is this info available from marathon?
Is marathon sending callbacks about another app up?

EscapedId

Hi,

any specific reason for the colons in

EscapedId: strings.Replace(appId, "/", "::", -1),
?

The colons mess up my host acl

acl ::socketchat-host hdr(host) -i ::socketchat.example.io

Best,

Mike

Multiple HAProxy Instances Started on Deployment

Using Mesos 0.20.1 and Marathon 0.7.0 I commonly see multiple HAProxy instances after a deployment event. It looks like Marathon doesn't batch events so Bamboo ends up restarting HAProxy multiple times in rapid succession. This leads to HAProxy not being able properly reload and thus multiple instances.

Bamboo does not detect/receive modification from marathon

Hello.

I'm testing bamboo on a 1 master/3 slaves mesos cluster. Marathon, zk, mesos master, haproxy and bamboo are all on master server.

When I scale up or down a app in Marathon, I have to clic on "update" button in bamboo ui for bamboo to update haproxy configuration. The number of instances is reflected correctly, but the log does not show anything, and haproxy is not reconfigured.

Here is the production.json:
{
"Marathon": {
"Endpoint": "http://localhost:8080",
"Zookeeper": {
"Host": "localhost:2181",
"Path": "/marathon/state",
"ReportingDelay": 5
}
},

"Bamboo": {
"Endpoint": "http://localhost:8000",
"Zookeeper": {
"Host": "localhost",
"Path": "/marathon-haproxy/state",
"ReportingDelay": 5
}
},

"HAProxy": {
"TemplatePath": "/root/gopath/src/github.com/QubitProducts/bamboo/config/haproxy_template.cfg",
"OutputPath": "/usr/local/etc/haproxy/haproxy.cfg",
"ReloadCommand": "read PIDS < /var/run/haproxy.pid; haproxy -f /usr/local/etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $PIDS && while ps -p $PIDS; do sleep 0.2; done"
},

"StatsD": {
"Enabled": false,
"Host": "localhost:8125",
"Prefix": "bamboo-server.development."
}
}

Is there any other configuration to debug te (marathon | zk) /bamboo communication?

Thanks.

default haproxy ReloadCommand locks up

The haproxy reload script frequently locks up, prevent config updates for haproxy. I found two related commits: 3bf7fd5 d1d3b65

Note how the second one changes from reading the PID file to using pidof. On our server where the reload hangs, pidof reports two running haproxy processes, while there is only one PID in the file - which seems to be the issue mentioned by @sttts in the first commit. The existence of the extra PID, in combination with the while loop from the first commit causes updates to hang: While haproxy reloads sucessfully, the while will never terminate, so further updates will not trigger reloads anymore.

$ cat /var/run/haproxy.pid
25296
$ pidof haproxy
25296 22555
$ ps aux|grep haproxy
haproxy  22555  0.0  0.1  30512  3072 ?        Ss   09:27   0:01 haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf 22492
1000     22707  0.0  0.0   9356   644 pts/2    R+   13:57   0:00 grep --color=auto haproxy
root     25293  0.3  0.0   4400   636 ?        S    10:34   0:41 sh -c PIDS=`pidof haproxy`; haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $PIDS && while ps -p $PIDS; do sleep 0.2; done
haproxy  25296  0.0  0.1  30696  3072 ?        Ss   10:34   0:02 haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf 22555

I wonder why the production.example.json was updated in that second commit (cc @activars): to me, it seems that reading the PIDs from the PID file is the correct way.

haproxy zombies in docker container

Every reload cmd leaves the previous haproxy process as zombie. Because neither bamboo nor docker waits for them, they don't go away.

In a real unix system (if bamboo is installed as package) init is waiting for the exited processes and this doesn't happen.

haproxy not updated

I run the latest (as of today) bamboo version and run into the following issue:

  • I update my marathon app (scaling or other changes, tried various combinations)
  • Changes show up on http://localhost:8000/api/state
  • haproxy does not get updated
  • I receive 503 Service Unavailable
  • I change ACL in UI and change it back
  • haproxy is now updated

config:

{
  "Marathon": {
    "Endpoint": "http://localhost:8080"
  },

  "Bamboo": {
    "Endpoint": "http://10.218.146.232:8000",
    "Zookeeper": {
      "Host": "10.218.146.232:2181",
      "Path": "/marathon-haproxy/state",
      "ReportingDelay": 5
    }
  },

  "HAProxy": {
    "TemplatePath": "/opt/bamboo/config/haproxy_template.cfg",
    "OutputPath": "/etc/haproxy/haproxy.cfg",
    "ReloadCommand": "PIDS=`pidof haproxy`; haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $PIDS && while ps -p $PIDS; do sleep 0.2; done"
  },

  "StatsD": {
    "Enabled": false,
    "Host": "localhost:8125",
    "Prefix": "bamboo-server.development."
  }
}

HAProxy http_check configuration setting treats non-empty 404 errors as healthy indicator

Using a version of Bamboo that includes commit 6791f26, it comes with a change to the HAProxy configuration template backend section that treats a HTTP response with a non-empty body as a positive health signal. The configuration change in questions is this:

http-check expect rstring .*

What this means is that even if you specify an non-existing URI in the httpchk option leading to a 404 response, you will still end up with a health check considered valid if the response contains some string like Not Found. In fact, this is the exact scenario that we ran into using Bamboo.

I couldn't fully understand from the git commit message what the reason was to make the change, so I am uncertain how a proper fix would look like. The http-check regular expression could be extended to cover 2xx and 3xx responses (as in ^[23]\d{2}.*), but that seems no different to leaving out the entire parameter (as httpchkdefaults to considering 2xx/3xx as valid).

Maybe @activars (the commit author) can shed some light on what the intention for the change was in the first place.

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.