Share
Embed
How to Build 12-Factor Application in NodeJS Using Docker
Nowadays, most applications are deployed on the cloud. It's important to build our application in cloud-native way so that it can gain the full potential of the cloud. The best practice to write cloud-native app is by following the 12-factor rule set, something published by Heroku in 2011 but still relevant today. In this talk, it will be discussed how to build a NodeJS application that follows 12-factor using Docker.
Aditya Satrya
September 28, 2019
Transcript
79 slides
-
How to Build 12-Factor Application in NodeJS using Docker Aditya
Satrya Head of IT Development Jabar Digital Service JSDay Indonesia 2019 -
Outline 2 ▷ Cloud-native ▷ Docker ▷ Twelve-factor app ▷
How to write NodeJS app that follows 12-factor -
7 ...in modern, dynamic environments such as public, private, and
hybrid clouds Keyword: cloud -
Cloud-Native application Able to get the maximum benefit from cloud
computing: ▷ Portability ▷ Scalable ▷ Resilient ▷ Minimize time & cost with automation ▷ Continuous deployment 8 -
9 Cloud-Native Trail-map 1. Containerization 2. CI/CD 3. Orchestration --below
this are optional-- 4. Observability 5. Service Discovery 6. Networking & Policy 7. Distributed database & storage 8. Streaming & messaging 9. Container registry 10. Software distribution -
Containerization 11 ▷ You can’t do cloud-native without containerization ▷
Docker is the most popular -
Containerization 12 ▷ a standard way to package your application's
code, configurations, and dependencies into a single object. https://aws.amazon.com/containers/ -
Benefit 14 ▷ Run anywhere ▷ Scale quickly ▷ Better
resource utilization -
What is 12-Factor app? ▷ Best practices to build app
optimized for the cloud (cloud-native) 18 -
Code I. One Codebase One codebase tracked in revision control,
many deploys II. Dependencies Explicitly declare and isolate dependencies III. Config Store config in the environment VI. Processes Execute the app as one or more stateless processes 20 IV. Backing services Treat backing services as attached resources V. Build, release, run Strictly separate build and run stages X. Dev/prod parity Keep development, staging, and production as similar as possible VII. Port binding Export services via port binding VIII. Concurrency Scale out via the process model IX. Disposability Maximize robustness with fast startup and graceful shutdown XI. Logs Treat logs as event streams XII. Admin processes Run admin tasks as one-off processes Deploy Operate -
File:index.js var app = express(); ... app.get('/', function (req, res)
{ connection.query('SELECT * FROM names LIMIT 1' , function (err, rows, fields) { res.send('Hello ' + rows[0].first_name + ' ' + rows[0].last_name); }) }); app.listen(8000, function () { console.log('Server is listening on port 8000' ); }) 24 -
Code I. One Codebase One codebase tracked in revision control,
many deploys II. Dependencies Explicitly declare and isolate dependencies III. Config Store config in the environment VI. Processes Execute the app as one or more stateless processes 26 IV. Backing services Treat backing services as attached resources V. Build, release, run Strictly separate build and run stages X. Dev/prod parity Keep development, staging, and production as similar as possible VII. Port binding Export services via port binding VIII. Concurrency Scale out via the process model IX. Disposability Maximize robustness with fast startup and graceful shutdown XI. Logs Treat logs as event streams XII. Admin processes Run admin tasks as one-off processes Deploy Operate -
I. One Codebase 27 ▷ only one codebase per app
▷ many deploys of the app -
I. One Codebase 28 ▷ Violation: ◦ Multiple app sharing
one codebase ▷ Solution: ◦ Treat as dependency -
I. One Codebase 29 ▷ Violation: ◦ Different code for
different version of an app ▷ Solution: ◦ Use git branch/tag for different version -
I. One Codebase 30 ▷ Benefit: ◦ Easy for automation
(CI/CD) ◦ Encourage smaller codebase (build & run faster, improve maintainability) -
One Codebase, Many Deploys $ docker build -t asatrya/nodejs-12factor-app:1.0 .
$ docker build -t asatrya/nodejs-12factor-app:2.0 . $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE asatrya/nodejs-12factor-app 1.0 ca4305291fb1 4 minutes ago 907MB asatrya/nodejs-12factor-app 2.0 eec4a2c8a951 2 minutes ago 907MB 33 -
Code I. One Codebase One codebase tracked in revision control,
many deploys II. Dependencies Explicitly declare and isolate dependencies III. Config Store config in the environment VI. Processes Execute the app as one or more stateless processes 34 IV. Backing services Treat backing services as attached resources V. Build, release, run Strictly separate build and run stages X. Dev/prod parity Keep development, staging, and production as similar as possible VII. Port binding Export services via port binding VIII. Concurrency Scale out via the process model IX. Disposability Maximize robustness with fast startup and graceful shutdown XI. Logs Treat logs as event streams XII. Admin processes Run admin tasks as one-off processes Deploy Operate -
II. Explicitly declare and isolate dependencies 35 ▷ Never relies
on implicit existence of system-wide packages ▷ Isolation -
II. Explicitly declare and isolate dependencies 36 ▷ Benefit: ◦
Improve predictability ◦ Simplifies setup -
File:package.json { "name": "nodejs_12factor_app", "version": "1.0.0", ... "dependencies": { "express":
"^4.17.1", "mysql": "^2.17.1" } } 38 -
File:Dockerfile FROM node:10 # Create app directory RUN mkdir /app
WORKDIR /app # Install app dependencies COPY package.json . RUN npm install COPY . . # Copy app source EXPOSE 8080 # Expose listened port CMD [ "node", "index.js" ] 39 -
Build Docker Image $ docker build -t asatrya/nodejs-12factor-app:1.0 . $
docker images REPOSITORY TAG IMAGE ID CREATED SIZE asatrya/nodejs-12factor-app 1.0 ca4305291fb1 4 minutes ago 907MB 40 -
Code I. One Codebase One codebase tracked in revision control,
many deploys II. Dependencies Explicitly declare and isolate dependencies III. Config Store config in the environment VI. Processes Execute the app as one or more stateless processes 41 IV. Backing services Treat backing services as attached resources V. Build, release, run Strictly separate build and run stages X. Dev/prod parity Keep development, staging, and production as similar as possible VII. Port binding Export services via port binding VIII. Concurrency Scale out via the process model IX. Disposability Maximize robustness with fast startup and graceful shutdown XI. Logs Treat logs as event streams XII. Admin processes Run admin tasks as one-off processes Deploy Operate -
III. Store config in the environment 42 ▷ Config could
be: ◦ Resource handles to backing services ◦ Credentials to external services ▷ Config varies across deploys, code does not -
III. Store config in the environment 43 ▷ Strict separation
of config from code ▷ Litmus test: ◦ Ready to be made open source anytime? -
III. Store config in the environment 44 ▷ Violation: ◦
Store config as constants in the code ▷ Solution: ◦ Store config as environment variables -
File:index.js ... var mysql = require('mysql'); var connection = mysql.createConnection({
host: process.env.MYSQL_HOST, user: process.env.MYSQL_USER, password: process.env.MYSQL_PASSWORD, database: process.env.MYSQL_DATABASE, }); ... 45 -
Run Container $ docker run --rm \ -e MYSQL_HOST=db \
-e MYSQL_USER=dbuser \ -e MYSQL_PASSWORD=dbpassword \ -e MYSQL_DATABASE=dbname \ asatrya/nodejs-12factor-app:1.0 46 -
Code I. One Codebase One codebase tracked in revision control,
many deploys II. Dependencies Explicitly declare and isolate dependencies III. Config Store config in the environment VI. Processes Execute the app as one or more stateless processes 47 IV. Backing services Treat backing services as attached resources V. Build, release, run Strictly separate build and run stages X. Dev/prod parity Keep development, staging, and production as similar as possible VII. Port binding Export services via port binding VIII. Concurrency Scale out via the process model IX. Disposability Maximize robustness with fast startup and graceful shutdown XI. Logs Treat logs as event streams XII. Admin processes Run admin tasks as one-off processes Deploy Operate -
▷ Assume local resource are temporal and disposable ▷ Share-nothing
architecture VI. Execute the app as stateless processes 48 -
▷ Violation: ◦ Store persistent data/files in local filesystem ▷
Solution: ◦ Store in S3 VI. Execute the app as stateless processes 49 -
▷ Benefit: ◦ Easy to scale out ◦ Resilient VI.
Execute the app as stateless processes 50 -
Code I. One Codebase One codebase tracked in revision control,
many deploys II. Dependencies Explicitly declare and isolate dependencies III. Config Store config in the environment VI. Processes Execute the app as one or more stateless processes 51 IV. Backing services Treat backing services as attached resources V. Build, release, run Strictly separate build and run stages X. Dev/prod parity Keep development, staging, and production as similar as possible VII. Port binding Export services via port binding VIII. Concurrency Scale out via the process model IX. Disposability Maximize robustness with fast startup and graceful shutdown XI. Logs Treat logs as event streams XII. Admin processes Run admin tasks as one-off processes Deploy Operate -
IV. Treat backing services as attached resources 53 ▷ Able
to attach/detach backing services without any code change -
IV. Treat backing services as attached resources 54 ▷ Benefit:
◦ Flexibility ◦ Resilience ◦ Loose coupling -
Code I. One Codebase One codebase tracked in revision control,
many deploys II. Dependencies Explicitly declare and isolate dependencies III. Config Store config in the environment VI. Processes Execute the app as one or more stateless processes 55 IV. Backing services Treat backing services as attached resources V. Build, release, run Strictly separate build and run stages X. Dev/prod parity Keep development, staging, and production as similar as possible VII. Port binding Export services via port binding VIII. Concurrency Scale out via the process model IX. Disposability Maximize robustness with fast startup and graceful shutdown XI. Logs Treat logs as event streams XII. Admin processes Run admin tasks as one-off processes Deploy Operate -
V. Strictly separate build and run stages 57 ▷ Violation:
◦ Include config values in build artefact ◦ Alter code when running app -
V. Strictly separate build and run stages 58 ▷ Benefit:
◦ Easy for rollback ◦ Promotes the separation of concerns -
Separate Build,Release & Run # build $ docker build -t
asatrya/nodejs-12factor-app:1.0 . # release $ docker push asatrya/nodejs-12factor-app:1.0 # run $ docker run --rm \ -e MYSQL_HOST=db \ -e MYSQL_USER=dbuser \ -e MYSQL_PASSWORD=dbpassword \ -e MYSQL_DATABASE=dbname \ asatrya/nodejs-12factor-app:1.0 59 -
Code I. One Codebase One codebase tracked in revision control,
many deploys II. Dependencies Explicitly declare and isolate dependencies III. Config Store config in the environment VI. Processes Execute the app as one or more stateless processes 60 IV. Backing services Treat backing services as attached resources V. Build, release, run Strictly separate build and run stages X. Dev/prod parity Keep development, staging, and production as similar as possible VII. Port binding Export services via port binding VIII. Concurrency Scale out via the process model IX. Disposability Maximize robustness with fast startup and graceful shutdown XI. Logs Treat logs as event streams XII. Admin processes Run admin tasks as one-off processes Deploy Operate -
X. Dev/prod parity 61 Traditional app 12-Factor App Code push
to deploy Days Minutes/Hours Code authors vs code deployers Different people Same people Dev vs production environments Different Similar as possible -
X. Dev/prod parity 62 ▷ Benefit: ◦ Faster delivery ◦
More predictability -
Code I. One Codebase One codebase tracked in revision control,
many deploys II. Dependencies Explicitly declare and isolate dependencies III. Config Store config in the environment VI. Processes Execute the app as one or more stateless processes 63 IV. Backing services Treat backing services as attached resources V. Build, release, run Strictly separate build and run stages X. Dev/prod parity Keep development, staging, and production as similar as possible VII. Port binding Export services via port binding VIII. Concurrency Scale out via the process model IX. Disposability Maximize robustness with fast startup and graceful shutdown XI. Logs Treat logs as event streams XII. Admin processes Run admin tasks as one-off processes Deploy Operate -
▷ your application might run as ◦ http://localhost:12001 on local
◦ http://192.168.1.10:2000 on staging ◦ http://app.company.com on production ▷ without having to change any code. VII. Export services via port binding 64 -
▷ Benefit: ◦ Your apps can be a backing services
for another app ◦ Flexibility VII. Export services via port binding 65 -
File:index.js var app = express(); ... app.get('/', function (req, res)
{ connection.query('SELECT * FROM names LIMIT 1' , function (err, rows, fields) { res.send('Hello ' + rows[0].first_name + ' ' + rows[0].last_name); }) }); app.listen(8000, function () { console.log('Server is listening on port 8000' ); }) 66 -
Run Container $ docker run --rm \ -e MYSQL_HOST=db \
-e MYSQL_USER=dbuser \ -e MYSQL_PASSWORD=dbpassword \ -e MYSQL_DATABASE=dbname \ -p 8001:8000 asatrya/nodejs-12factor-app:1.0 67 -
Code I. One Codebase One codebase tracked in revision control,
many deploys II. Dependencies Explicitly declare and isolate dependencies III. Config Store config in the environment VI. Processes Execute the app as one or more stateless processes 69 IV. Backing services Treat backing services as attached resources V. Build, release, run Strictly separate build and run stages X. Dev/prod parity Keep development, staging, and production as similar as possible VII. Port binding Export services via port binding VIII. Concurrency Scale out via the process model IX. Disposability Maximize robustness with fast startup and graceful shutdown XI. Logs Treat logs as event streams XII. Admin processes Run admin tasks as one-off processes Deploy Operate -
VI. Concurrency 71 ▷ Promotes separation of concerns (microservices) ▷
Scale out instead of scale up -
Code I. One Codebase One codebase tracked in revision control,
many deploys II. Dependencies Explicitly declare and isolate dependencies III. Config Store config in the environment VI. Processes Execute the app as one or more stateless processes 72 IV. Backing services Treat backing services as attached resources V. Build, release, run Strictly separate build and run stages X. Dev/prod parity Keep development, staging, and production as similar as possible VII. Port binding Export services via port binding VIII. Concurrency Scale out via the process model IX. Disposability Maximize robustness with fast startup and graceful shutdown XI. Logs Treat logs as event streams XII. Admin processes Run admin tasks as one-off processes Deploy Operate -
Code I. One Codebase One codebase tracked in revision control,
many deploys II. Dependencies Explicitly declare and isolate dependencies III. Config Store config in the environment VI. Processes Execute the app as one or more stateless processes 74 IV. Backing services Treat backing services as attached resources V. Build, release, run Strictly separate build and run stages X. Dev/prod parity Keep development, staging, and production as similar as possible VII. Port binding Export services via port binding VIII. Concurrency Scale out via the process model IX. Disposability Maximize robustness with fast startup and graceful shutdown XI. Logs Treat logs as event streams XII. Admin processes Run admin tasks as one-off processes Deploy Operate -
XI. Treat logs as event streams 75 ▷ Write logs
to stdout ▷ External system to collect logs into a centralized location -
Code I. One Codebase One codebase tracked in revision control,
many deploys II. Dependencies Explicitly declare and isolate dependencies III. Config Store config in the environment VI. Processes Execute the app as one or more stateless processes 76 IV. Backing services Treat backing services as attached resources V. Build, release, run Strictly separate build and run stages X. Dev/prod parity Keep development, staging, and production as similar as possible VII. Port binding Export services via port binding VIII. Concurrency Scale out via the process model IX. Disposability Maximize robustness with fast startup and graceful shutdown XI. Logs Treat logs as event streams XII. Admin processes Run admin tasks as one-off processes Deploy Operate -
XII. Run admin tasks as one-off processes 77 ▷ Examples
of administrative processes: ◦ Database migrations ◦ Interactive programming consoles (REPLs) ◦ Timed scripts (ex: batch job) ◦ Executes custom code only once