Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Heroku 102
Search
Rhys Elsmore
June 18, 2014
Programming
210
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Heroku 102
Rhys Elsmore
June 18, 2014
More Decks by Rhys Elsmore
See All by Rhys Elsmore
How to Lose Friends and Influence Burnout
rhyselsmore
0
86
Other Decks in Programming
See All in Programming
1B+ /day規模のログを管理する技術
broadleaf
0
130
そのテスト、説明できますか?~LWテスト戦略FW~のご紹介
nakahara
0
200
【やさしく解説 設計編・中級 #4】ルールの寿命と、システムの年輪
panda728
PRO
2
120
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
460
エンジニア向け会社紹介/Findy Company Profile
findyinc
6
360k
AIエージェントで 変わるAndroid開発環境
takahirom
2
570
トークンをケチるな、設計しろ:GitHub Copilotを賢く使うコンテキスト戦略
ochtum
0
310
SREは、MCPとSRE Agentをこう使え!
kazumax55
0
150
音楽のための関数型プログラミング言語mimiumにおける多段階計算の活用
tomoyanonymous
1
310
AI駆動開発を妨げる技術的負債の解消アプローチ / ai-refactoring-approach
minodriven
17
8.9k
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
110
継続モナドとリアクティブプログラミング
yukikurage
3
520
Featured
See All Featured
Writing Fast Ruby
sferik
630
63k
Ten Tips & Tricks for a 🌱 transition
stuffmc
0
150
Kristin Tynski - Automating Marketing Tasks With AI
techseoconnect
PRO
0
290
Building Applications with DynamoDB
mza
96
7.1k
We Have a Design System, Now What?
morganepeng
55
8.2k
Typedesign – Prime Four
hannesfritz
42
3.1k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
55k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
330
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
201
75k
Paper Plane (Part 1)
katiecoart
PRO
0
9.6k
What's in a price? How to price your products and services
michaelherold
247
13k
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
Transcript
[email protected]
102 @rhyselsmore
@rhyselsmore >>> import rhyselsmore Platform Security Engineer at Heroku. I
focus on Anti-Abuse Systems. I develop using a mixture of Python/Go.
@rhyselsmore Heroku is a Platform as a Service
@rhyselsmore You build your application, not infrastructure
@rhyselsmore Deploying is as easy as ‘git push’
@rhyselsmore Scaling and upgrading is simple
@rhyselsmore tl;dr: Spend time on your application’s code
@rhyselsmore 3,000,000+ apps created. 130+ add-ons services. 90,000+ requests per
second. 500,000+ log entries per second.
@rhyselsmore Run anything* on Heroku
@rhyselsmore Python & Ruby & PHP & Java & NodeJS
@rhyselsmore Play & Scala & Clojure & Gradle & Grails
& C & Common Lisp & Dart & Elixir & Erlang & Go & Haskell & JRuby & Lua & Perl & Rust & …
@rhyselsmore
@rhyselsmore The Twelve-Factor App 12factor.net
@rhyselsmore The Twelve-Factor Flask App 12factor.net
@rhyselsmore Lets assume that You want to learn about Heroku
You know (a bit) of Python You have Python, pip, and can create a virtualenv
@rhyselsmore Lets assume that You want to learn about Heroku
You know (a bit) of Python You have Python, pip, and can create a virtualenv install.python-guide.org
@rhyselsmore Get an account at heroku.com
@rhyselsmore Install the Heroku Toolbelt toolbelt.heroku.com
@rhyselsmore $ heroku login Login
@rhyselsmore The Twelve-Factor App 12factor.net
@rhyselsmore $ mkdir heroku101 $ cd heroku101 $ git init
@rhyselsmore $ heroku create Creating myapp... done, stack is cedar
http://myapp.herokuapp.com/ |
[email protected]
:myapp.git Git remote heroku added
@rhyselsmore $ cat .git/config [core] repositoryformatversion = 0 filemode =
true bare = false logallrefupdates = true ignorecase = true precomposeunicode = true [remote "heroku"] url =
[email protected]
:myapp.git fetch = +refs/heads/*:refs/remotes/heroku/*
@rhyselsmore $ virtualenv venv $ pip install flask gunicorn $
pip freeze > requirements.txt
@rhyselsmore $ cat requirements.txt Flask==0.10.1 Jinja2==2.7.3 MarkupSafe==0.23 Werkzeug==0.9.6 gunicorn==19.0.0 itsdangerous==0.24
wsgiref==0.1.2
@rhyselsmore import os! from flask import Flask! ! app =
Flask(__name__)! ! @app.route('/')! def index():! return "Hello, World!" heroku101.py
@rhyselsmore web: gunicorn heroku101:app Procfile
@rhyselsmore $ foreman start 21:51:53 web.1 | started with pid
20276 Launch your application locally
@rhyselsmore Visit http://localhost:5000/ in your browser.
@rhyselsmore venv *.pyc .gitignore
@rhyselsmore $ git add . $ git commit -m ‘initial
commit’ Store our changes in git
@rhyselsmore Now, lets send it up to Heroku
@rhyselsmore $ git push heroku master ! -----> Python app
detected -----> Preparing Python runtime (python-2.7.7) -----> Installing Setuptools (3.6) -----> Installing Pip (1.5.6) ! …. ! -----> Discovering process types Procfile declares types -> web ! -----> Compressing... done, 31.6MB -----> Launching... done, v3 http://myapp.herokuapp.com/ deployed to Heroku ! To
[email protected]
:myapp.git * [new branch] master -> master
@rhyselsmore $ heroku open Check out our new application
@rhyselsmore Codebase Recap Dependencies Dev/Prod Parity Port Binding Processes
@rhyselsmore Codebase Recap Dependencies Dev/Prod Parity Port Binding Processes
@rhyselsmore I. Codebase One codebase tracked in revision control, many
deploys
@rhyselsmore Codebase Recap Dependencies Dev/Prod Parity Port Binding Processes
@rhyselsmore II. Dependencies Explicitly declare and isolate dependencies
@rhyselsmore Codebase Recap Dependencies Dev/Prod Parity Port Binding Processes
@rhyselsmore X. Dev/Prod Parity Keep development, staging, and production as
similar as possible
@rhyselsmore Codebase Recap Dependencies Dev/Prod Parity Port Binding Processes
@rhyselsmore VII. Port Binding Export services via port binding
@rhyselsmore Codebase Recap Dependencies Dev/Prod Parity Port Binding Processes
@rhyselsmore VI. Processes Execute the app as one or more
stateless processes
@rhyselsmore Runs processes concurrently locally via a Procfile Foreman Exposes
a configuration to our processes Creates parity between production and development
@rhyselsmore web: gunicorn heroku101:app Procfile
@rhyselsmore web: gunicorn heroku101:app worker: bin/celeryd worker clock: bin/clock monitor:
bin/monitor Procfile
@rhyselsmore Runs processes concurrently locally via a Procfile Foreman Exposes
a configuration to our processes Creates parity between production and development
@rhyselsmore VIII. Concurrency Scale out via the process model
@rhyselsmore web
@rhyselsmore $ heroku ps:scale web=6
@rhyselsmore web web web web web web
@rhyselsmore web: gunicorn heroku101:app worker: bin/celeryd worker clock: bin/clock monitor:
bin/monitor Procfile
@rhyselsmore $ heroku ps:scale clock=1 monitor=1 worker=6
@rhyselsmore web web web web web worker worker worker worker
worker clock monitor web worker
@rhyselsmore $ heroku ps:scale monitor=1:2X
@rhyselsmore web web web web web worker worker worker worker
worker clock ! monitor web worker
@rhyselsmore $ heroku ps:scale worker=1:PX
@rhyselsmore web web web web web clock ! monitor web
! ! ! ! ! worker ! ! ! !
@rhyselsmore $ heroku ps:scale clock=0
@rhyselsmore web web web web web ! monitor web !
! ! ! ! worker ! ! ! !
@rhyselsmore Runs processes concurrently locally via a Procfile Foreman Exposes
a configuration to our processes Creates parity between production and development
@rhyselsmore III. Config Store config in the environment
@rhyselsmore import os! from flask import Flask! ! app =
Flask(__name__)! ! @app.route('/')! def index():! name = os.environ.get('PAGE_NAME', 'Rhys')! return "Hello, {0}!".format(name)! heroku101.py
@rhyselsmore PAGE_NAME=‘Heroku User’ .env (Be sure to add ‘.env’ to
.gitignore)
@rhyselsmore $ foreman start 21:51:53 web.1 | started with pid
20276 Launch your application locally. Did it work?
@rhyselsmore $ git add heroku101.py $ git commit -m ‘loading
name from configuration’ $ git push heroku master … $ heroku open Commit our changes, and push to Heroku
@rhyselsmore Now, lets set our configuration on Heroku.
@rhyselsmore $ heroku config:set PAGE_NAME=‘App User’ $ heroku open Launch
your application locally. Did it work?
@rhyselsmore V. Build, Release, Run Strictly separate build and run
stages
@rhyselsmore $ heroku releases === myapp v5 Set PAGE_NAME config
vars
[email protected]
2014/06/17 22:49:44 v4 Deploy 0b7df5b
[email protected]
2014/06/17 22:49:33 v3 Deploy f6fc054
[email protected]
2014/06/17 22:00:32 v2 Enable Logplex
[email protected]
2014/06/17 21:10:58 v1 Initial release
[email protected]
2014/06/17 21:10:57 Viewing your Releases
@rhyselsmore $ heroku rollback v4 Rolling back myapp... done, v4
! Warning: rollback affects code and config vars; it doesn't add or remove addons. To undo, run: heroku rollback v5 Rolling back to another Release
@rhyselsmore IV. Backing Services Treat backing services as attached resources
@rhyselsmore ! app ! postgres ! redis ! s3 !
outbound mail
@rhyselsmore ! app ! redis Dev ! app ! redis
Prod redis://my.production.redis redis://localhost
@rhyselsmore X. Dev/Prod Parity Keep development, staging, and production as
similar as possible
@rhyselsmore ! app ! sqlite Dev ! app ! postgres
Prod
@rhyselsmore CREATE TABLE ips ( id serial primary key, ip
inet not null …
@rhyselsmore CREATE TABLE ips ( id serial primary key, ip
inet not null …
@rhyselsmore ! app ! postgres Dev ! app ! postgres
Prod
@rhyselsmore Homebrew (http://brew.sh) Vagrant (http://vagantup.com) Docker (http://docker.io) Some Solutions Postgres.app
(http://postgresapp.com)
@rhyselsmore
@rhyselsmore $ pip install redis $ pip freeze > requirements.txt
@rhyselsmore import os! from flask import Flask! import redis! !
app = Flask(__name__)! db = redis.from_url(os.environ.get('REDISCLOUD_URL'))! ! ! @app.route('/name/<name>')! def setname(name):! db.set('PAGE_NAME', name)! return "Name successfully updated"! ! ! @app.route('/')! def index():! name = db.get('PAGE_NAME') or "Rhys"! return "Hello, {0}!".format(name)! heroku101.py
@rhyselsmore $heroku addons:add rediscloud Adding rediscloud on myapp... done, v7
(free) Use `heroku addons:docs rediscloud` to view documentation. Add RedisCloud
@rhyselsmore $ heroku config REDISCLOUD_URL=xxxxxxx PAGE_NAME=Rhys Addons are exposed to
your application as config vars
@rhyselsmore $ git add heroku101.py requirements.txt $ git commit -m
‘using redis as our db store’ $ git push heroku master … $ heroku open Commit our changes, and push to Heroku
@rhyselsmore XI. Logs Treat logs as event streams
@rhyselsmore $ heroku logs —tail
@rhyselsmore 2014-06-17T16:03:07.702584+00:00 heroku[router]: at=info method=GET path="/" host=whispering-lake-5026.herokuapp.com request_id=7be32154-cbca-4e9c-b235-2a86a204f32d fwd="50.31.252.204" dyno=web.1
connect=1ms service=3ms status=200 bytes=172 2014-06-17T16:03:21.624306+00:00 heroku[router]: at=info method=GET path="/" host=whispering-lake-5026.herokuapp.com request_id=180ee5c1-5c7e-4370-925c-4532bab44bb1 fwd="50.31.252.204" dyno=web.1 connect=1ms service=7ms status=200 bytes=172 2014-06-17T16:03:26.160610+00:00 heroku[router]: at=info method=GET path="/" host=whispering-lake-5026.herokuapp.com request_id=71337d5d-ca00-49ed-98f6-e007123142de fwd="50.31.252.204" dyno=web.1 connect=0ms service=2ms status=200 bytes=172 2014-06-17T16:03:31.690643+00:00 heroku[router]: at=info method=GET path="/" host=whispering-lake-5026.herokuapp.com request_id=b156826f-6db3-480d-bcc0-34239b2ad5a2 fwd="50.31.252.204" dyno=web.1 connect=1ms service=3ms status=200 bytes=172 2014-06-17T16:03:33.123754+00:00 heroku[router]: at=info method=GET path="/" host=whispering-lake-5026.herokuapp.com request_id=a3768595-4fa5-41b7-aa2b-24ac4fa81880 fwd="50.31.252.204" dyno=web.1 connect=1ms service=3ms status=200 bytes=172 2014-06-17T16:03:34.186475+00:00 heroku[router]: at=info method=GET path="/" host=whispering-lake-5026.herokuapp.com request_id=2e02b838-bdd6-47b2-b9c9-cd4d999ef1bc fwd="50.31.252.204" dyno=web.1 connect=0ms service=30ms status=200 bytes=172 2014-06-17T16:03:38.245823+00:00 heroku[router]: at=info method=GET path="/" host=whispering-lake-5026.herokuapp.com request_id=c50b652a-1632-4727-b27a-03b0e89cdc4f fwd="50.31.252.204" dyno=web.1 connect=8ms service=30ms status=200 bytes=172 2014-06-17T16:03:48.101998+00:00 heroku[router]: at=info method=GET path="/" host=whispering-lake-5026.herokuapp.com request_id=94bd1cb4-446e-4309-9a67-94b210cdc3b2 fwd="50.31.252.204" dyno=web.1 connect=1ms service=2ms status=200 bytes=172 2014-06-17T16:03:49.663855+00:00 heroku[router]: at=info method=GET path="/" host=whispering-lake-5026.he
@rhyselsmore XI. Logs Treat logs as event streams
@rhyselsmore $ heroku labs:enable log-runtime-metrics Enabling log-runtime-metrics for myapp... done
log-runtime-metrics
@rhyselsmore log2viz.herokuapp.com
@rhyselsmore $ heroku addons:add librato $ heroku addons:open librato Librato
@rhyselsmore
@rhyselsmore $ pip install log-metrics $ pip freeze > requirements.txt
@rhyselsmore import os! from flask import Flask! import log_metrics, random,
time! ! app = Flask(__name__)! ! ! @app.route('/')! def index():! with log_metrics.timer('timed-function'):! time.sleep(random.uniform(0.5, 1.5))! log_metrics.increment('requests')! return "Hello, Librato!"! heroku101.py
@rhyselsmore 00:18:20 web.1 | measure#timed-function.ms=1261.87 00:18:20 web.1 | count#requests=1 00:18:24
web.1 | measure#timed-function.ms=925.83 00:18:24 web.1 | count#requests=1
@rhyselsmore
@rhyselsmore $ heroku addons:add papertrail $ heroku addons:add loggly Log
Retention
@rhyselsmore $ heroku drains:add https://my-drain-app.com Log Drains
@rhyselsmore $ heroku domains:add mycustomdomain.com Custom Domains
@rhyselsmore The Heroku Platform API
@rhyselsmore >>> import requests! >>> import json! ! >>> heroku
= requests.session()! >>> heroku.auth = ('', '<my API token>')! >>> heroku.headers.update({! "Accept": "application/vnd.heroku+json; version=3",! "Content-Type": "application/json"! })! ! >>> heroku.get('/apps').json()! {! "id":49939049,! "name":"my-app-1",! "dynos":0,! "workers":0,! "repo_size":null,! "slug_size":null,! "stack":"cedar",! "requested_stack":null,
@rhyselsmore >>> heroku.get('/apps/myapp/config-vars').json()! {! "NAME": "My App",! "SECRET_KEY": "hunter2"! }
>>> heroku.patch(‘/apps/myapp/config-vars’, json.dumps({! ! "NAME": "My Apps new config var",! }))
@rhyselsmore Thanks!
@rhyselsmore Further Questions… ! SSL Endpoints? File Storage? Multiple Languages?
Free Limits? Does an add-on for $task exist? EU vs US region? Show us how to…