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

Ember.js, DevOps, and You - Wicked Good Ember 2016

Ember.js, DevOps, and You - Wicked Good Ember 2016

My talk on DevOps and Ember.js given at Wicked Good Ember 2016.

Iheanyi Ekechukwu

June 28, 2016
Tweet

More Decks by Iheanyi Ekechukwu

Other Decks in Programming

Transcript

  1. Ember.js, DevOps, and You
    Iheanyi Ekechukwu
    Wicked Good Ember 2016

    View Slide

  2. Iheanyi Ekechukwu
    Software Engineer @
    DigitalOcean
    @kwuchu

    View Slide

  3. Defining DevOps
    What exactly is DevOps?

    View Slide

  4. DevOps?

    View Slide

  5. View Slide

  6. DevOps.

    View Slide

  7. Development + Operations

    View Slide

  8. DevOps is deploying.

    View Slide

  9. DevOps is provisioning.

    View Slide

  10. DevOps is versioning.

    View Slide

  11. DevOps is complicated.

    View Slide

  12. Automation is

    View Slide

  13. Ember.js and DevOps
    What do Ember.js and DevOps have to
    do with one another?

    View Slide

  14. View Slide

  15. Ember-CLI-Deploy Plugins

    View Slide

  16. An Ember-CLI-Deploy Plugin
    can implement up to 11 hooks

    View Slide

  17. View Slide

  18. So, it doesn’t just deploy.

    View Slide

  19. Ember-CLI-Deploy can provision.

    View Slide

  20. Ember-CLI-Deploy can build.

    View Slide

  21. Ember-CLI-Deploy can deploy.

    View Slide

  22. Ember-CLI-Deploy can manage releases.

    View Slide

  23. Ember-CLI-Deploy

    View Slide

  24. Ember-CLI-DevOps

    View Slide

  25. Building a Plugin

    View Slide

  26. Create the Ember addon and
    install the Ember-CLI-Deploy
    base plugin.
    STEP ONE

    View Slide

  27. ember addon ember-cli-deploy-digitalocean

    View Slide

  28. cd ember-cli-deploy-digitalocean
    npm install ember-cli-deploy-plugin --save

    View Slide

  29. STEP TWO
    Manually deploy a Fastboot
    application, taking note of each
    action.
    (Provisioning, Deployment, etc.)

    View Slide

  30. Let’s go through the steps.

    View Slide

  31. Create a Droplet.

    View Slide

  32. SSH into the droplet.

    View Slide

  33. Install Nginx, Node, NPM, and
    Ember-Fastboot-Server on droplet

    View Slide

  34. On local machine, build the
    Fastboot application.

    View Slide

  35. SCP the built Ember
    application onto the droplet

    View Slide

  36. On droplet, go to the uploaded
    app and run the Fastboot
    application.

    View Slide

  37. Configure Nginx to proxy over the
    Fastboot’s server’s port and serve
    static assets.

    View Slide

  38. Reload Nginx.

    View Slide

  39. And you’re done.

    View Slide

  40. STEP THREE
    Translate each recorded step
    into code.
    (Automation)

    View Slide

  41. View Slide

  42. Automation Problems
    and Solutions

    View Slide

  43. PROBLEM
    How do I create a droplet for
    the user?

    View Slide

  44. SOLUTION
    Use DigitalOcean’s API and
    create an Ember command
    that creates the droplet.

    View Slide

  45. View Slide

  46. export DO_ACCESS_TOKEN=

    View Slide

  47. ember do:provision

    View Slide

  48. View Slide

  49. PROBLEM
    Installing all software
    dependencies on the droplet.
    (Provisioning)

    View Slide

  50. WITHOUT FASTBOOT
    One package dependency.
    Web Server (NGINX) serves
    the static assets.

    View Slide

  51. WITH FASTBOOT
    More dependencies. It’s not
    only NGINX. We now need
    Node, NPM, and Fastboot.

    View Slide

  52. SOLUTION
    DigitalOcean Images and
    execution of commands via
    Node SSH2.

    View Slide

  53. View Slide

  54. this.conn = new SSHClient();
    this.sshConfig = {
    host: config.ipAddress,
    port: 22,
    username: config.dropletUsername,
    privateKey:
    require('fs').readFileSync(config.privateKeyPath),
    password: config.dropletPassword,
    passphrase: config.passphrase,
    };

    View Slide

  55. willUpload: function() {
    var conn = this.conn;
    conn.on('ready', () => {
    conn.exec(‘sudo apt-get update -y; sudo apt-get
    upgrade -y; sudo apt-get install -y nginx gcc build-
    essential; rm /etc/nginx/sites-enabled/default', (err,
    stream) => {
    if (err) throw err;
    stream.on('data', (data) => {
    this.log('STDOUT: ' + data);
    }).on('end', (data) => {
    resolve();
    });
    })
    }).connect(this.sshConfig);
    })

    View Slide

  56. PROBLEM
    How do I build my Ember
    application and get it onto the
    droplet?

    View Slide

  57. SOLUTION
    Use ember-cli-deploy-build to
    build the application, NPM install
    dependencies, then SCP files
    onto the droplet.

    View Slide

  58. View Slide

  59. configure: function() {
    //…
    this.scpConfig = {
    host: config.ipAddress,
    port: 22,
    username: process.env.DROPLET_USERNAME || 'root',
    privateKey:
    require('fs').readFileSync(process.env.PRIVATE_KEY_DIR),
    password: process.env.DROPLET_PASSWORD,
    passphrase: process.env.PASSPHRASE,
    path: '/etc/nginx/sites-enabled/ember-app'
    };
    this.scpClient = SCPClient;
    },

    View Slide

  60. willUpload: function(context) {
    var npmInstallTask = new NPMInstallTask({
    log: this.log.bind(this),
    distDir: context.distDir
    });
    return npmInstallTask.run()
    // more code down here
    }

    View Slide

  61. upload: function(context) {
    this.log('Uploading assets to the droplet!');
    var scpClient = this.scpClient;
    return new Promise((resolve, reject) => {
    scpClient.scp(context.distDir, this.scpConfig, (err) => {
    if (err) {
    throw err;
    }
    //…
    return resolve();
    });
    });
    },

    View Slide

  62. context.distDir

    View Slide

  63. PROBLEM
    What if my droplet restarts
    and kills the Fastboot server?

    View Slide

  64. SOLUTION
    Create a Fastboot Upstart
    Service on the droplet.

    View Slide

  65. description "A job file for starting up the Fastboot service for Ember."
    author "Iheanyi Ekechukwu"
    start on filesystem or runlevel [2345]
    stop on shutdown
    pre-start script
    npm install -g ember-fastboot-server
    echo "Starting Fastboot server" >> /var/log/fastboot.log
    end script
    script
    export HOME
    echo $$ > /var/run/fastboot.pid
    exec ember-fastboot /etc/nginx/sites-enabled/ember-app >> /var/log/fastboot.log 2>&1
    end script
    pre-stop script
    rm /var/run/fastboot.pid
    echo "Fastboot Server Stopping" >> /var/log/fastboot.log
    end script

    View Slide

  66. didUpload: function(context) {
    // other code…upload fast boot
    fileClient.upload('./node_modules/ember-cli-
    deploy-digitalocean/templates/fastboot.conf', '/
    etc/init/fastboot.conf', err => {
    if (err) {
    this.log(err, {color: 'red'});
    throw err;
    }
    // other code…
    });

    View Slide

  67. PROBLEM
    How do I get the application
    up and served up to the user?

    View Slide

  68. SOLUTION
    Upload a custom NGINX
    config and restart everything.

    View Slide

  69. http {
    include /etc/nginx/mime.types*;
    default_type application/octet-stream;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    server {
    listen 80;
    root /etc/nginx/sites-enabled/ember-app;
    index index.html index.html;
    server_name localhost;
    location / {
    index index.html;
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-NginX-Proxy true;
    }
    location ~ \.(ttf|ttc|otf|eot|woff|font.css|css)$ {
    add_header Access-Control-Allow-Origin "*";
    }
    location /assets {
    autoindex on;
    }
    }
    }

    View Slide

  70. didUpload: function(context) {
    // upload nginx conf, other code left out
    fileClient.upload('./node_modules/ember-cli-deploy-digitalocean/
    templates/nginx.conf', '/etc/nginx/nginx.conf', (err) => {
    if (err) {
    this.log(err);
    throw err;
    }
    return resolve();
    });
    // other code…
    }

    View Slide

  71. didUpload: function(context) {
    // restart nginx and fastboot service, other code left out
    conn.exec("sudo service nginx restart; sudo service fastboot
    restart;",
    (err, stream) => {
    if (err) throw err;
    stream.on('data', (data) => {
    this.log('STDOUT: ' + data);
    }).on('end', (data) => {
    this.log("We're in business!");
    return resolve();
    }).stderr.on('data', (data) => {
    this.log('STDERR: ' + data);
    });
    });
    }

    View Slide

  72. And we’re done automating.

    View Slide

  73. View Slide

  74. One small NPM trick that
    makes building deploy plugins
    easier…

    View Slide

  75. View Slide

  76. g

    View Slide

  77. View Slide

  78. ember-cli-deploy-digitalocean
    (github.com/iheanyi/ember-cli-deploy-
    digitalocean)

    View Slide

  79. Plugin Limitations

    View Slide

  80. Deploys limited to one droplet.

    View Slide

  81. Provisioning tasks get re-run
    unnecessarily.

    View Slide

  82. No controlled release
    management.

    View Slide

  83. Old Fastboot Serving Logic

    View Slide

  84. Ideas for Future Enhancements

    View Slide

  85. Zero Downtime Deployments

    View Slide

  86. SSL Support?

    View Slide

  87. Semantic Versioning
    (semantic-release)

    View Slide

  88. The Future of DevOps?

    View Slide

  89. View Slide

  90. + ?

    View Slide

  91. View Slide

  92. Thanks to…
    @tomdale
    @lukemelia
    @davidpett
    @digitalocean
    and others!

    View Slide

  93. Thank you.
    @kwuchu

    View Slide