Slide 1

Slide 1 text

Ember.js, DevOps, and You Iheanyi Ekechukwu Madison+Ruby 2016

Slide 2

Slide 2 text

Iheanyi Ekechukwu Software Engineer @ DigitalOcean @kwuchu

Slide 3

Slide 3 text

Defining DevOps What exactly is DevOps?

Slide 4

Slide 4 text

DevOps?

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

DevOps.

Slide 7

Slide 7 text

Development + Operations

Slide 8

Slide 8 text

DevOps is deploying.

Slide 9

Slide 9 text

DevOps is provisioning.

Slide 10

Slide 10 text

DevOps is versioning.

Slide 11

Slide 11 text

DevOps is complicated.

Slide 12

Slide 12 text

Automation is

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

Ember-CLI-Deploy Plugins

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

So, it doesn’t just deploy.

Slide 19

Slide 19 text

Ember-CLI-Deploy can provision.

Slide 20

Slide 20 text

Ember-CLI-Deploy can build.

Slide 21

Slide 21 text

Ember-CLI-Deploy can deploy.

Slide 22

Slide 22 text

Ember-CLI-Deploy can manage releases.

Slide 23

Slide 23 text

Ember-CLI-Deploy

Slide 24

Slide 24 text

Ember-CLI-DevOps

Slide 25

Slide 25 text

Building a Plugin

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

ember addon ember-cli-deploy-digitalocean

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

Let’s go through the steps.

Slide 31

Slide 31 text

Create a Droplet.

Slide 32

Slide 32 text

SSH into the droplet.

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

On local machine, build the Fastboot application.

Slide 35

Slide 35 text

SCP the built Ember application onto the droplet

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

Reload Nginx.

Slide 39

Slide 39 text

And you’re done.

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

Automation Problems and Solutions

Slide 43

Slide 43 text

PROBLEM How do I create a droplet for the user?

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

export DO_ACCESS_TOKEN=

Slide 47

Slide 47 text

ember do:provision

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

SOLUTION DigitalOcean Images and execution of commands via Node SSH2.

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

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, };

Slide 55

Slide 55 text

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); })

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

No content

Slide 59

Slide 59 text

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; },

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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(); }); }); },

Slide 62

Slide 62 text

context.distDir

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

SOLUTION Create a Fastboot Upstart Service on the droplet.

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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… });

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

SOLUTION Upload a custom NGINX config and restart everything.

Slide 69

Slide 69 text

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; } } }

Slide 70

Slide 70 text

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… }

Slide 71

Slide 71 text

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); }); }); }

Slide 72

Slide 72 text

And we’re done automating.

Slide 73

Slide 73 text

No content

Slide 74

Slide 74 text

One small NPM trick that makes building deploy plugins easier…

Slide 75

Slide 75 text

No content

Slide 76

Slide 76 text

g

Slide 77

Slide 77 text

No content

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

Plugin Limitations

Slide 80

Slide 80 text

Deploys limited to one droplet.

Slide 81

Slide 81 text

Provisioning tasks get re-run unnecessarily.

Slide 82

Slide 82 text

No controlled release management.

Slide 83

Slide 83 text

Old Fastboot Serving Logic

Slide 84

Slide 84 text

Ideas for Future Enhancements

Slide 85

Slide 85 text

Zero Downtime Deployments

Slide 86

Slide 86 text

SSL Support?

Slide 87

Slide 87 text

Semantic Versioning (semantic-release)

Slide 88

Slide 88 text

The Future of DevOps?

Slide 89

Slide 89 text

No content

Slide 90

Slide 90 text

+ ?

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

Thank you. @kwuchu