Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Easy Ruby Development and Deployment with Otto

Easy Ruby Development and Deployment with Otto

Ruby is amazing, but it isn't always the easiest tool to get set up for local development. Vagrant continues to be a great tool for automated and reproducible development environments, but it often falls short of real production scenarios. Otto, the successor to Vagrant, encompasses the entire workflow managing local development environments, infrastructure creation, and application deployment in just three easy commands. You can have the Heroku-like workflow while maintaining full control over the stack, without all the overhead. Come meet Otto!

More and more, organizations desire extended control over their full stack. From development to production, controlling the entire stack ensures parity, reduces bugs in production, and ultimately makes for happier developers :). With Otto, you can say goodbye to staging/qa/testing environments because any user can easily create all the required infrastructure in a single command. This saves on infrastructure costs, maintenance, and makes for an amazing disaster recovery story!

Following the story of a fictitious Ruby app, I will deploy their application to AWS in just a two commands in live-demo format. Otto has codified knowledge of today's best practices for deploying applications, so even with no operational experience, a developer can create and manage infrastructure using today's best practices. Otto brings the "Heroku-like" workflow to the command line, but you control the entire stack from top to bottom!

After each phase, we will "uncover the magic", digging into the commands Otto is running, the decisions Otto is making, and the various customizations that can be injected along the way.

Seth Vargo

April 07, 2016
Tweet

More Decks by Seth Vargo

Other Decks in Technology

Transcript

  1. EASY DEVELOPMENT AND DEPLOYMENT
    Industry quality, self-service workflows with Otto

    View full-size slide

  2. SETH VARGO
    @sethvargo

    View full-size slide

  3. Otto and the HashiCorp Ecosystem

    View full-size slide

  4. Automate Development
    Environments

    View full-size slide

  5. $ otto dev
    ===> otto: detected app: ruby

    View full-size slide

  6. $ otto dev
    ===> otto: detected app: python

    View full-size slide

  7. Focus on
    Application Development

    View full-size slide

  8. $ otto dev ssh
    vagrant@precise64:/vagrant$

    View full-size slide

  9. Codify
    Deployments

    View full-size slide

  10. Today's Best Practices
    WEB DB MICRO
    SERVICES
    PRIVATE SUBNET

    PUBLIC SUBNET

    INTERNAL NETWORK
    LB
    BASTION NAT

    View full-size slide

  11. WEB DB MICRO
    SERVICES
    PRIVATE SUBNET

    PUBLIC SUBNET

    INTERNAL NETWORK
    LB
    BASTION NAT
    Today's Best Practices
    COMPLEXITY

    View full-size slide

  12. Simplify
    Microservices

    View full-size slide

  13. Microservices
    Monolithic Microservices

    View full-size slide

  14. Microservices

    View full-size slide

  15. Microservices

    View full-size slide

  16. application {
    name = "my-store"
    type = "ruby"
    dependency {
    source = "github.com/hashicorp/otto/examples/postgresql"
    }
    }
    customization "ruby" {
    ruby_version = "2.1"
    }
    Appfile

    View full-size slide

  17. Doin' it Live1

    1. Unless it breaks

    View full-size slide

  18. BOOTSTRAP
    APP
    1

    View full-size slide

  19. $ vi Gemfile

    View full-size slide

  20. source "https://rubygems.org"
    gem "pg", "~> 0.18"
    gem "shotgun", "~> 0.9"
    gem "sinatra", "~> 1.4"
    gem "sinatra-activerecord", "~> 2.0"
    Gemfile

    View full-size slide

  21. CONFIGURE
    DEV
    2

    View full-size slide

  22. $ otto compile

    View full-size slide

  23. $ otto compile
    ==> Loading Appfile...
    ==> No Appfile found! Detecting project information...
    No Appfile was found. If there is no Appfile, Otto will do its best
    to detect the type of application this is and set reasonable defaults.
    This is a good way to get started with Otto, but over time we recommend
    writing a real Appfile since this will allow more complex customizations,
    the ability to reference dependencies, versioning, and more.
    ==> Fetching all Appfile dependencies...
    Fetching dependency: git::github.com/hashicorp/otto.git//examples/postgresql
    ==> Compiling dependency 'postgresql'...
    ==> Compiling main application...
    ==> Detecting Ruby version to use...
    No desired Ruby version found! Will use the default: 2.2
    ==> Compilation success!

    View full-size slide

  24. $ otto compile
    ==> Loading Appfile...
    ==> No Appfile found! Detecting project information...
    No Appfile was found. If there is no Appfile, Otto will do its best
    to detect the type of application this is and set reasonable defaults.
    This is a good way to get started with Otto, but over time we recommend
    writing a real Appfile since this will allow more complex customizations,
    the ability to reference dependencies, versioning, and more.
    ==> Fetching all Appfile dependencies...
    Fetching dependency: git::github.com/hashicorp/otto.git//examples/postgresql
    ==> Compiling dependency 'postgresql'...
    ==> Compiling main application...
    ==> Detecting Ruby version to use...
    No desired Ruby version found! Will use the default: 2.2
    ==> Compilation success!

    View full-size slide

  25. $ otto dev
    ==> Creating development environment layers...
    Otto uses layers to speed up building development environments.
    Each layer only needs to be built once. We've detected that the
    layers below aren't created yet. These will be built this time.
    Future development environments will use the cached versions
    to be much, much faster.

    View full-size slide

  26. $ otto dev
    ==> Creating layer: consul
    Bringing machine 'default' up with 'virtualbox' provider...
    ...

    View full-size slide

  27. $ otto dev
    ==> Creating layer: ruby2.2
    Bringing machine 'default' up with 'virtualbox' provider...
    ...
    ==> default: [otto] Installing supporting packages...
    ==> default: [otto] Installing Ruby 2.2. This can take a few minutes...
    ==> default: [otto] Installing Bundler...

    View full-size slide

  28. $ otto dev
    ==> Creating local development environment with Vagrant
    ...
    ==> default: [otto] Bundling gem dependencies...
    ==> default: Fetching version metadata from https://rubygems.org/...
    ==> default: Resolving dependencies...
    ==> default: Installing rack 1.6.4
    ==> default: Installing tilt 2.0.2
    ==> default: Using bundler 1.11.2
    ==> default: Installing rack-protection 1.5.3
    ==> default: Installing shotgun 0.9.1
    ==> default: Installing sinatra 1.4.7
    ==> default: Bundle complete! 5 Gemfile dependencies, 24 gems now installed.
    ==> default: Use `bundle show [gemname]` to see where a bundled gem is installed.

    View full-size slide

  29. $ otto dev
    ==> Development environment successfully created!
    IP address: 100.117.7.132
    A development environment has been created for writing a generic
    Ruby-based app.
    Ruby is pre-installed. To work on your project, edit files locally on your
    own machine. The file changes will be synced to the development environment.
    When you're ready to build your project, run 'otto dev ssh' to enter
    the development environment. You'll be placed directly into the working
    directory where you can run 'bundle' and 'ruby' as you normally would.
    You can access any running web application using the IP above.

    View full-size slide

  30. $ otto dev
    ==> Verifying created layer: consul
    ==> Verifying created layer: ruby2.2
    ...

    View full-size slide

  31. DEVELOP
    LOCALLY
    3

    View full-size slide

  32. require "bundler"
    Bundler.require
    get "/" do
    "The app is running!"
    end
    app.rb

    View full-size slide

  33. $ vi config.ru

    View full-size slide

  34. require "./app"
    run Sinatra::Application
    config.ru

    View full-size slide

  35. $ otto dev ssh
    ==> Executing SSH. This may take a few seconds...
    Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic x86_64)

    View full-size slide

  36. vagrant@precise64:/vagrant$ shotgun --host 0.0.0.0 config.ru
    == Shotgun/WEBrick on http://0.0.0.0:9393/
    [2020-01-01 20:49:36] INFO WEBrick 1.3.1
    [2020-01-01 20:49:36] INFO ruby 2.2.4 (2015-12-16) [x86_64-linux]
    [2020-01-01 20:49:36] INFO WEBrick::HTTPServer#start: pid=2183 port=9393

    View full-size slide

  37. $ curl http://100.117.7.132:9393/
    The app is running!

    View full-size slide

  38. $ curl http://$(otto dev address):9393/
    The app is running!

    View full-size slide

  39. $ curl -I http://$(otto dev address):9393/
    HTTP/1.1 200 OK
    Content-Type: text/html;charset=utf-8
    Content-Length: 19
    X-Xss-Protection: 1; mode=block
    X-Content-Type-Options: nosniff
    X-Frame-Options: SAMEORIGIN
    Server: WEBrick/1.3.1 (Ruby/2.2.4/2015-12-16)
    Date: Mon, 01 Jan 2020 20:50:35 GMT
    Connection: Keep-Alive

    View full-size slide

  40. $ otto dev ssh
    vagrant@precise64:/vagrant$ nslookup postgresql.service.consul
    Server: 127.0.0.1
    Address: 127.0.0.1#53
    Name: postgresql.service.consul
    Address: 10.0.2.15

    View full-size slide

  41. vagrant@precise64:/vagrant$ ./scripts/createdb.sh

    View full-size slide

  42. require "bundler"
    Bundler.require
    configure do
    ActiveRecord::Base.establish_connection(
    adapter: "postgresql",
    host: "postgresql.service.consul",
    username: "postgres",
    database: "demo",
    encoding: "utf8",
    )
    end
    class Post < ActiveRecord::Base; end
    app.rb

    View full-size slide

  43. $ vi app.rb
    # ...
    get "/posts", provides: :json do
    Post.all.to_json
    end
    post "/posts", provides: :json do
    if post = Post.create(params)
    post.to_json
    else
    status 422
    post.errors.to_json
    end
    end

    View full-size slide

  44. vagrant@precise64:/vagrant$ rake db:migrate
    == 20160406140708 CreatePosts: migrating ======================================
    -- create_table(:posts)
    -> 0.0782s
    == 20160406140708 CreatePosts: migrated (0.0788s) =============================

    View full-size slide

  45. $ curl http://$(otto dev address):9393/posts
    []

    View full-size slide

  46. $ curl -XPOST http://$(otto dev address):9393/posts -F "title=hello" -F "body=world"
    {
    "id": 1,
    "title": "hello",
    "body": "world",
    "created_at": "2016-04-06T19:34:01.998Z",
    "updated_at": "2016-04-06T19:34:01.998Z"
    }

    View full-size slide

  47. $ curl http://$(otto dev address):9393/posts
    [
    {
    "id": 1,
    "title": "hello",
    "body": "world",
    "created_at": "2016-04-06T19:34:01.998Z",
    "updated_at": "2016-04-06T19:34:01.998Z"
    },
    ]

    View full-size slide

  48. CONSTRUCT
    INFRA
    4

    View full-size slide

  49. $ otto infra
    ==> Detecting infrastructure credentials for: demo (aws)
    Existing infrastructure credentials were not found! Otto will
    now ask you for infrastructure credentials. These will be encrypted
    and saved on disk so this doesn't need to be repeated.
    IMPORTANT: If you're re-entering new credentials, make sure the
    credentials are for the same account, otherwise you may lose
    access to your existing infrastructure Otto set up.

    View full-size slide

  50. $ otto infra
    AWS Access Key
    AWS access key used for API calls.
    Enter a value: ...
    AWS Secret Key
    AWS secret key used for API calls.
    Enter a value: ...
    SSH Public Key Path
    Path to an SSH public key that will be granted access to EC2 instances
    Default: ~/.ssh/id_rsa.pub
    Enter a value: ...
    Password for Encrypting Credentials
    This password will be used to encrypt and save the credentials so they
    don't need to be repeated multiple times.
    Enter a value: ...

    View full-size slide

  51. $ otto infra
    ==> Building main infrastructure...
    ==> Executing Terraform to manage infrastructure...
    Raw Terraform output will begin streaming in below. Otto
    does not create this output. It is mirrored directly from
    Terraform while the infrastructure is being created.
    Terraform may ask for input. For infrastructure provider
    credentials, be sure to enter the same credentials
    consistently within the same Otto environment.

    View full-size slide

  52. $ otto infra
    ...
    Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
    Outputs:
    infra_id = efa4b38b
    key_name = otto-efa4b38b
    region = us-east-1
    subnet_public = subnet-5435b57e
    vpc_cidr = 10.0.0.0/16
    vpc_id = vpc-efa4b38b
    ==> Infrastructure successfully created!
    The infrastructure necessary to deploy this application
    is now available. You can now deploy using `otto deploy`.

    View full-size slide

  53. $ otto status
    ==> App Info
    Application: demo (ruby)
    Project: demo
    Infrastructure: aws (simple)
    ==> Component Status
    Dev environment: CREATED
    Infra: READY
    Build: NOT BUILT
    Deploy: NOT DEPLOYED

    View full-size slide

  54. $ otto build
    ...
    ==> Building deployment archive...
    Error building app: error detecting VCS: no VCS found for path: /demo

    View full-size slide

  55. $ git init && git add -A && git commit -m "Initial commit"
    Reinitialized existing Git repository in /demo/.git/
    [master (root-commit) 5e57d71] Initial commit
    63 files changed, 1744 insertions(+)

    View full-size slide

  56. $ otto build
    ==> Building deployment archive...
    ==> Building deployment artifact with Packer...
    Raw Packer output will begin streaming in below. Otto
    does not create this output. It is mirrored directly from
    Packer while the build is being run.
    ==> otto: Prevalidating AMI Name...
    ==> otto: Inspecting the source AMI...
    ==> otto: Creating temporary keypair: packer 5702de4a-4f50-a189-6afd-25b0cd447ae2
    ==> otto: Creating temporary security group for this instance...
    ==> otto: Authorizing access to port 22 the temporary security group...
    ==> otto: Launching a source AWS instance...
    otto: Instance ID: i-d3796849
    ==> otto: Waiting for instance (i-d3796849) to become ready...

    View full-size slide

  57. $ otto build
    ...
    ==> Builds finished. The artifacts of successful builds are:
    --> otto: AMIs were created:
    us-east-1: ami-64f1e50e
    ==> Storing build data in directory...
    ==> Build success!
    The build was completed successfully and stored within
    the directory service, meaning other members of your team
    don't need to rebuild this same version and can deploy it
    immediately.

    View full-size slide

  58. $ otto status
    ==> App Info
    Application: demo (ruby)
    Project: demo
    Infrastructure: aws (simple)
    ==> Component Status
    Dev environment: CREATED
    Infra: READY
    Build: BUILD READY
    Deploy: NOT DEPLOYED

    View full-size slide

  59. $ otto deploy
    ==> Detecting infrastructure credentials for: demo (aws)
    Cached and encrypted infrastructure credentials found.
    Otto will now ask you for the password to decrypt these
    credentials.
    ...
    Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
    Outputs:
    url = http://ec2-54-164-91-52.compute-1.amazonaws.com/

    View full-size slide

  60. $ export URL="http://ec2-54-164-91-52.compute-1.amazonaws.com"
    $ curl $URL
    The app is running!
    $ curl $URL/posts
    []
    $ curl -XPOST $URL/posts -F "title=hello" -F "body=world"
    {
    "id": 1,
    "title": "hello",
    "body": "world",
    "created_at": "2016-04-06T19:34:01.998Z",
    "updated_at": "2016-04-06T19:34:01.998Z"
    }

    View full-size slide

  61. DESTROY
    IT ALL
    7

    View full-size slide

  62. $ otto dev destroy
    ==> Destroying the local development environment...
    $ otto deploy destroy
    Do you really want to destroy?
    Otto will delete all resources associated with the deploy.
    There is no undo. Only 'yes' will be accepted to confirm.
    Enter a value: yes
    $ otto infra destroy
    Do you really want to destroy?
    Otto will delete all your managed infrastructure.
    There is no undo. Only 'yes' will be accepted to confirm.
    Enter a value: yes

    View full-size slide

  63. COMPLEX
    REQS
    ?

    View full-size slide

  64. $ vi Appfile

    View full-size slide

  65. application {
    name = "demo"
    type = "ruby"
    dependency {
    source = "github.com/hashicorp/otto/examples/postgresql"
    }
    }
    customization "ruby" {
    ruby_version = "2.2"
    }
    Appfile

    View full-size slide

  66. $ otto compile
    ==> Loading Appfile...
    ==> Fetching all Appfile dependencies...
    Fetching dependency: git::github.com/hashicorp/otto.git/examples/postgresql
    ==> Compiling...
    Application: demo (ruby)
    Project: demo
    Infrastructure: aws (simple)
    Compiling infra...
    Compiling foundation: consul
    ==> Compiling dependency 'postgresql'...
    ==> Compiling main application...
    ==> Compilation success!

    View full-size slide

  67. SETH VARGO
    @sethvargo
    QUESTIONS?

    View full-size slide