Skip to content

Instantly share code, notes, and snippets.

@ziadsawalha
Last active August 29, 2015 14:21
Show Gist options
  • Save ziadsawalha/47b30f1b8a8f29631510 to your computer and use it in GitHub Desktop.
Save ziadsawalha/47b30f1b8a8f29631510 to your computer and use it in GitHub Desktop.
Code Deployment for Humans

Project [To Be Named]

Code Deployment for Humans

Keeping up with configuration management tools is a distraction from writing beautiful code.

Let's develop a simple, elegant way to describe how our app is installed, how to run it, and what it needs.

If the focus is on our application, the description should be independent of configuration management tools (ex. Chef, Puppet), languages (Ruby, Python, JavaScript) and should work for running the app on dev laptops (Vagrant, Docker) and popular clouds (ex. AWS, OpenStack/Rackspace).

Can this be simple?

A simple app should be very simple to describe.

With [foo] installed[add link], navigate to your code repository and describe your application using the app command:

$ app exposes http
$ app requires python --version ">=2.7.1,<3"
$ app define --start-command="python my_app.py"

Let's run an instance of our app in Docker:

$ app deploy --providers=docker
Deployed 5dff3e1 from master@d9520bba.
Browse to http://192.168.59.103:31654
RESOURCE ID   ROLE  TYPE       ADDRESS    CREATED        STATUS
docker:4f44e  app   container  31654/tcp  7 seconds ago  Up 3 seconds   

Let's run an instance of our app on AWS:

$ app deploy --providers=aws --key-id=$AWS_KEY_ID --access-key=$AWS_ACCESS_KEY
Deployed cc53228 from master@d9520bba.
Browse to http://173.12.56.205
RESOURCE ID           ROLE  TYPE    ADDRESS       CREATED         STATUS
aws:useast1:ffefc5c2  app   server  173.12.54.18  11 seconds ago  Up 2 seconds 

Let's scale the Docker instance out:

$ app scale-out 5dff3e1 --count app=2 --force
Created 2 resources.
RESOURCE ID   ROLE  TYPE        ADDRESS    CREATED        STATUS
docker:d7721  app   app:latest  31689/tcp  7 seconds ago  Up 3 seconds    
docker:a7a44  lb    lb:latest   31654/tcp  6 seconds ago  Up 3 seconds

Modified one resource.
RESOURCE ID   ROLE  TYPE        ADDRESS     CREATED        STATUS
docker:4f44e  app   app:latest  31686/tcp   3 minutes ago  Port changed

Let's publish the definition:

$ git add blueprint.yaml
$ git commit -m "Add blueprint for my_app"
$ git push

What about more complex apps?

Here's an example of how we could build a more complex app; specifying ports, environment variables, etc...

# Our web app defaults to port 8080 but falls back to any open
# port in case of conflict. Set the HTTP_PORT environment
# variable to the chosen port number and we use that below
# when defining the `start` command.
# This will create a `blueprint.yaml` file if it doesn't
# exist. We can commit the file to the repository to share
# the definition with others.

$ app exposes http --default-port 8080 --use-free-port --set-env HTTP_PORT

# Our app requires a mongo database with full text search
# enabled. We set the MongoDB URL to the MONGO_URL environment variable.

$ app requires mongodb --set-env MONGO_URL --options full_text=true

# Our app requires Python (but is not Python 3 compatible yet)

$ app requires python --version ">=2.7.1,<3"

# To run it on a debian distro, we need some packages

$ app supports debian --packages python-dev,git

# It works on OSX out of the box (no brew/macports packages
# needed)

$ app supports osx

# We can use a memcache instance if available. If so, set the
# CACHE_PORT and USE_CACHE environment variables.

$ app supports memcache --set-env CACHE_PORT=MEMCACHE_PORT,USE_CACHE=1

# This is how we start our app (use the HTTP_PORT that was
# preselected based on the `exposes` entry)

$ app define --start-command="bin/my_app START --eventlet --port HTTP_PORT"
# Here's what the yaml file looks like (edit in other tools
# if you want). Note how there is no tool-specific information
# in it

components:
  app:
    provides:
    - application: http[8080?]
      exposed: true
      set_env:
      - HTTP_PORT: ${settings.port}
    requires:
    - database: mongo
      config:
      - full_text: true
    - runtime: python
      constraints:
      - version: '>=2.7.1,<3'
    supports:
    - cache: memcache
      set_env:
      - CACHE_PORT: MEMCACHE_PORT
      - USE_CACHE: '1'
    - compute:
        from:
        - debian:
            packages: [python-dev, git]
        - osx
    commands:
      start: 'bin/my_app START --eventlet --port HTTP_PORT'

In Docker it will now create two containers:

$ app deploy --providers=docker
Deployed from master@d9520bba.
Browse to http://192.168.59.103:31654
RESOURCE ID   ROLE     TYPE       ADDRESS    CREATED        STATUS
docker:5f6ae  mongodb  container  27017/tcp  6 seconds ago  Up 4 seconds   
docker:4f44e  app      container  31654/tcp  7 seconds ago  Up 3 seconds    

Let's run an instance of our app on Rackspace:

$ app deploy --providers=core,rackspace --region=dfw --username=me --api-key=$API_KEY
Deployed from master@d9520bba.
Browse to http://173.12.56.205
RESOURCE ID       ROLE     TYPE    ADDRESS        CREATED        STATUS
rax:dwf:d5223afa  mongodb  server  173.12.56.205  12 seconds ago  Up 4 seconds 
rax:dfw:ffefc5c2  app      server  173.12.54.18   11 seconds ago  Up 2 seconds 

Let's manage our deployments:

$ app list deployments
ID       FROM             URL                          CREATED     STATUS
5dff3e1  master@d9520bba  http://192.168.59.103:31654  2 days ago  Up 3 hours
cc53228  master@d9520bba  http://173.12.56.205         2 days ago  Up 2 days

$ app destroy 5dff3e1 --force
5dff3e1 destroyed (two resources deleted)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment