Git Product home page Git Product logo

broadside's Introduction

Broadside Build Status

A GLI based command-line tool for deploying applications on AWS EC2 Container Service (ECS)

The wiki has all kinds of useful information on it so don't just rely on this README.

Overview

Amazon ECS presents a low barrier to entry for production-level docker applications. Combined with ECS's built-in blue-green deployment, Elastic Load Balancers, Autoscale Groups, and CloudWatch, one can theoretically set up a robust cluster that can scale to serve any number of applications in a short amount of time. The ECS GUI, CLI, and overall architecture are not the easiest to work with, however, so Broadside seeks to leverage the ECS ruby API to dramatically simplify and improve the configuration and deployment process for developers, offering a simple command line interface and configuration format that should meet most needs.

Broadside does not attempt to handle operational tasks like infrastructure setup and configuration, which are better suited to tools like terraform.

Capabilities

  • Trigger ECS deployments
  • Inject environment variables into ECS containers from local configuration files
  • Launch a bash shell on container in the cluster
  • SSH directly onto a host running a container
  • Execute an arbitrary shell command on a container (or all containers)
  • Tail logs of a running container
  • Scale an existing deployment on the fly

Example Config for Quickstarters

Applications using broadside employ a configuration file that looks something like:

Broadside.configure do |config|
  config.application = 'hello_world'
  config.default_docker_image = 'lumoslabs/hello_world'
  config.aws.ecs_default_cluster = 'production-cluster'
  config.aws.region = 'us-east-1'                  # 'us-east-1 is the default
  config.targets = {
    production_web: {
      scale: 7,
      command: %w(bundle exec unicorn -c config/unicorn.conf.rb),
      env_file: '.env.production'
      predeploy_commands: [
        %w(bundle exec rake db:migrate),
        %w(bundle exec rake data:migrate)
      ]
    },
    # If you have multiple images or clusters, you can configure them per target
    staging_web: {
      scale: 1,
      command: %w(bundle exec puma),
      env_file: '.env.staging',
      tag: 'latest',                                # Set a default tag for this target
      cluster: 'staging-cluster',                   # Overrides config.aws.ecs_default_cluster
      docker_image: 'lumoslabs/staging_hello_world' # Overrides config.default_docker_image
    },
    json_stream: {
      scale: 1,
      command: %w(java -cp *:. path.to.MyClass),
      # This target has a task_definition and service config which you use to bootstrap a new AWS Service
      service_config: { deployment_configuration: { minimum_healthy_percent: 0.5 } },
      task_definition_config: { container_definitions: [ { cpu: 1, memory: 2000, } ] }
    }
  }
end

From here, developers can use broadside's command-line interface to initiate a basic deployment and launch the configured command as an ECS Service:

bundle exec broadside deploy full --target production_web --tag v.1.1.example.tag

In the case of an error or timeout during a deploy, broadside will automatically rollback to the latest stable version. You can perform manual rollbacks as well through the command-line.

Installation

Via Gemfile

First, install broadside by adding it to your application Gemfile:

gem 'broadside'

Then run

bundle install

You can now run the executable in your app directory:

bundle exec broadside --help

You may also generate binstubs using

bundle binstubs broadside

System Wide

Alternatively, you can install broadside using:

gem install broadside

Configuration

For full application setup, see the detailed instructions in the wiki.

Debugging

Use the --debug switch to enable stacktraces and debug output.

Contributing

Pull requests, bug reports, and feature suggestions are welcome!

Before starting on a contribution, we recommend opening an issue or replying to an existing one to give others some initial context on the work needing to be done.

Specs must pass on pull requests for them to be considered.

Running Specs

Broadside has a lot of tests for most of its behaviors - just run

bundle exec rspec

in the broadside directory. Don't open pull requests without passing specs.

broadside's People

Contributors

albertrdixon avatar apurvis avatar camertron avatar matl33t avatar slpsys avatar srhaber 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

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

broadside's Issues

Execute command does not execute on all tasks in a service

when issuing a broadside execute --all command to a particular service that includes more than one task and two or more tasks are found on the same EC2 instance, broadside will only perform the execute command on one of the multiple tasks on the same ec2 instance. A workaround at the moment is to define the placement strategy of the service to distinctInstance. (This will require recreating the service in ECS before deploying and executing a command against.)

Fixing how we target the tasks from looking at ip addresses to looking at the tasks themselves will solve the issue.

Pass more to Pre/Post hooks

Would love to get more information in the pre and post hook blocks, in particular the command line flags and their values.

Different image for targets?

Is it possible to supply a different image for different targets?

My use case is this:

I have a staging image - quay.io/me/widget-staging - and a trimmed production image - quay.io/me/widget-production - and I would like to do something like this if I want to deploy staging: broadside deploy short --target staging_web --image quay.io/me/widget-staging --tag feature-branch

container_definitions should allow `name` overrides

In configured_container_definition, the name is always set to the family.

I was poking around in #37 earlier this morning--and I think this is actually already possible if you've already got an ELB set up--BUT the biggest issue is that you need the container name inside your task definition and the container_name inside the load_balancers portion of the service definition to match . This is knowable, currently, because the container_name is derived, and is just "#{application}_#{target}", but this is both subject to potential change and also, frankly, annoying. I'd rather be able to override it like:

web: {
      service_config: {
        role: 'ecsServiceRole',
        load_balancers: [
          {
            container_name: 'my-app',
            container_port: 5000,
            ...
          }
        ]
      },
      task_definition_config: {
        container_definitions: [
          {
            name: 'my-app',

Right now, i'd have to set the web.service_config.load_balancers.container_name to be my-app_web.

Opening as an issue because this is up for debate; not hard to do (merge then reverse_merge?), but it's policy, not code.

can't get running task logs if > 1 container

D, [2016-09-26_12:37:30#28562] DEBUG -- : Running command to find container id:
ssh core@xxx "docker ps -aqf 'label=com.amazonaws.ecs.task-arn=arn:aws:ecs:xxx:xxx:task/xxx'"
Killed by signal 1.
D, [2016-09-26_12:37:31#28562] DEBUG -- : Running command to get logs of container 4f41cd4f6261
17209aa4c283: 
ssh core@xxx "docker logs 4f41cd4f6261
17209aa4c283"
I, [2016-09-26_12:37:31#28562]  INFO -- : python script/config_to_db.py task container logs:
STDOUT:--

STDERR:--
bash: line 1: 17209aa4c283: command not found
Killed by signal 1.
D, [2016-09-26_12:37:31#28562] DEBUG -- : python script/config_to_db.py task arn:aws:ecs:xxx:xxx:task/xxx exited with status code 0

The first command grabbed two container ids, since the task definition had two containers. Attempting to grab the logs had an issue, though this didn't impede the deployment.

support for bootstrapping service with a load balancer

Currently bootstrap only works with services that do not need a load balancer. Because ECS does not allow modification of a service at a later point to attach to a load balancer, this needs to be done at creation.

CLI --quiet flag

By default, debug logs are printed out, but would be nice to have a quiet flag or loglevel option to pass in.

killed by signal 1

@matl33t

I, [2016-07-19_14:24:12#22530] INFO -- : airflow upgradedb task container logs:
STDOUT:--
[2016-07-19 21:24:09,077] {init.py:36} INFO - Using executor CeleryExecutor
[2016-07-19 21:24:09,148] {driver.py:120} INFO - Generating grammar tables from /usr/lib/python2.7/lib2to3/Grammar.txt
[2016-07-19 21:24:09,168] {driver.py:120} INFO - Generating grammar tables from /usr/lib/python2.7/lib2to3/PatternGrammar.txt
DB: mysql://airflow:***@airflow-analytics.cluster-cdiwpivlvfxt.us-east-1.rds.amazonaws.com/airflow
[2016-07-19 21:24:09,380] {db.py:222} INFO - Creating tables

STDERR:--
INFO [alembic.runtime.migration] Context impl MySQLImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
Killed by signal 1.

D, [2016-07-19_14:24:12#22530] DEBUG -- : Deregistered arn:aws:ecs:us-east-1:447374670232:task-definition/airflow_web:188
error: airflow upgradedb task arn:aws:ecs:us-east-1:447374670232:task/5ad56f33-2cc8-4093-b7bd-0a66c4c5df73 exited with a non-zero status code !

is this an ssh problem?
http://stackoverflow.com/questions/12639615/cygwin-ssh-gives-killed-by-signal-1-on-exit

catch docker tag doesn't exist failure

deploys and tasks fail if the docker tag for the image doesn't exist with a non-descriptive error message. Maybe give a number of retries to wait for it to exist (e.g. in a case where waiting for a docker push to complete)

Possibility to define Service name

Actually I see that Service name is calculated with application + target.name, so if I want to use this tool I have to remake my clusters and services to match this naming protocol? Would be reasonable to be able to specify service_name the same way I specify cluster, so I can tell the app "Deploy the new version of the service X on cluster Y"

Maybe I have understood something wrong.

Thanks for your time!

ctrl-c doesn't rollback

note the warning. cc @matl33t

[~/beacon] == OPS lumoslabs@[catapult.aws.lumoslabs.com,catapult-aws,catapult] ==
Tue Oct 18 14:19:02 [61:0]$ RAILS_ENV=staging bundle exec broadside deploy short --target staging_web --tag master
I, [2016-10-18_14:19:21#655]  INFO -- : Deploying quay.io/lumoslabs/beacon:master to beacon_staging_web...
D, [2016-10-18_14:19:21#655] DEBUG -- : Successfully created arn:aws:ecs:us-east-1:447374670232:task-definition/beacon_staging_web:116
D, [2016-10-18_14:19:21#655] DEBUG -- : Updating beacon_staging_web with scale=1 using task arn:aws:ecs:us-east-1:447374670232:task-definition/beacon_staging_web:116...
D, [2016-10-18_14:19:22#655] DEBUG -- : (1/300) Polling ECS for events...
D, [2016-10-18_14:19:24#655] DEBUG -- : (2/300) Polling ECS for events...
D, [2016-10-18_14:19:24#655] DEBUG -- : (service beacon_staging_web) was unable to place a task because no container instance met all of its requirements. The closest matching (container-instance dbd55f88-8d21-40dc-a2c2-c32f463e04b8) has insufficient memory available. For more information, see the Troubleshooting section of the Amazon ECS Developer Guide.
D, [2016-10-18_14:19:26#655] DEBUG -- : (3/300) Polling ECS for events...
D, [2016-10-18_14:19:28#655] DEBUG -- : (4/300) Polling ECS for events...
D, [2016-10-18_14:19:30#655] DEBUG -- : (5/300) Polling ECS for events...
^C/opt/rbenv/versions/2.1.9/lib/ruby/gems/2.1.0/bundler/gems/broadside-975921c598f1/lib/broadside/deploy/ecs_deploy.rb:33: warning: toplevel constant Interrupt referenced by SignalException::Interrupt
error: exit

error: undefined local variable or method `ecs' for #<Broadside::EcsDeploy:0x007f57c16d06d0>

@apurvis

[~/lumos_aleph] == OPS lumoslabs@[catapult.aws.lumoslabs.com,catapult-aws,catapult] ==
Mon Oct 03 12:26:48 [2:0]$ broadside deploy status --target production_web
I, [2016-10-03_12:27:02#29311]  INFO -- : Getting status information about aleph_production_web
error: undefined local variable or method `ecs' for #<Broadside::EcsDeploy:0x007f57c16d06d0>

[~/lumos_aleph] == OPS lumoslabs@[catapult.aws.lumoslabs.com,catapult-aws,catapult] ==
Mon Oct 03 12:27:02 [3:0]$ broadside --version
broadside version 1.1.0

Unknown option --config

Can we specify a config file path via CLI? By the wiki, it is possible to do using --config option, but it does not work with error: Unknown option --config .

$ bundle exec broadside bootstrap --target app --config config/deploy/development.yml 
error: Unknown option --config

By default, the CLI will assume the existence of a config/broadside.conf.rb file in your application root directory. You can also manually specify a config file for an individual execution with --config config/to/my/other/broadside.conf.rb.

https://github.com/lumoslabs/broadside/wiki/Configuration#configuring-broadside

Or this option is removed?

broadside ver 3.3.2

Bootstrap should detect task def changes

Right now, the bootstrap command detects if there is a most-recent task definition, but only tries register_task_definition if there is nonesuch. In reality, calling register_task_definition creates a new version of the task definition; it'd be likely useful to detect this, because...quite frankly, most people are going to mess things up at least once.

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.