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

The Twelve-Factor App for Node.js Developers at KharkivJS

The Twelve-Factor App for Node.js Developers at KharkivJS

Nikita Galkin

October 05, 2019
Tweet

More Decks by Nikita Galkin

Other Decks in Programming

Transcript

  1. The Twelve-Factor App
    for Node.js Developers
    by Nikita Galkin
    Oct 5, 2019

    View Slide

  2. What is Quality?
    2
    Motivation
    Reduce onboarding time
    A common language with
    DevOps Engineers
    Scale-ready app
    Cloud-ready app
    Production-ready app
    Etc-ready app

    View Slide

  3. View Slide

  4. Nikita
    Galkin
    Love and Know:
    ▰ How to make developers and business happy
    ▰ Technical and process debt elimination
    Believe that:
    ▰ Any problem must be solved at the right level
    ▰ Software is easy. People Are Complicated
    ▰ A problem should be highlighted, an idea should
    be "sold", a solution should be demonstrated
    Links:
    Site GitHub Twitter Facebook

    View Slide

  5. 12factor.net

    View Slide

  6. I. Codebase
    One codebase
    tracked in revision control,
    many deploys

    View Slide

  7. What is Quality?
    9

    View Slide

  8. View Slide

  9. 11
    Scoped packages

    View Slide

  10. What is Quality?
    12
    Shared code:
    ▰ Don’t use gitsubmodules, use scoped packages
    ▰ @project/code-style is good first chose
    Check Code Style and Violence by Anton Nemtsev
    ▰ On self-hosted repo
    npm config set @myco:registry http://reg.example.com
    ▰ With a self-hosted repo, use add .npmrc to git

    View Slide

  11. II. Dependencies
    Explicitly declare
    and isolate dependencies

    View Slide

  12. View Slide

  13. What is Quality?
    15
    Package.json
    ▰ avoid npm install -g ...
    ▰ package-lock.json should published in git
    ▰ node & npm versions fixed
    ▰ post-install script is a good place for hacking
    node_modules

    View Slide

  14. What is Quality?
    16

    View Slide

  15. FROM node:10.16.3-alpine
    ENV APP_WORKDIR=/usr/src/app
    RUN apk update && apk upgrade && \
    apk add --virtual build-deps git openssh-client py-pip make
    COPY package.json package-lock.json $APP_WORKDIR
    WORKDIR $APP_WORKDIR
    RUN npm install
    COPY . $APP_WORKDIR
    RUN npm run build
    RUN rm -rf tsconfig.json src
    RUN apk del build-deps
    RUN npm prune --production
    CMD ["node", "dist/index.js"]

    View Slide

  16. III. Config
    Store config
    in the environment

    View Slide

  17. What is Quality?
    19
    ▰ Config is not part of the
    artifact
    ▰ App could be made open
    source at any moment,
    without compromising
    any credentials.

    View Slide

  18. What is Quality?
    20
    .env
    ▰ Use .env.example file for description
    ▰ Use .env file for local development
    ▰ Use environment variables for any other
    environment
    ▰ Don’t use default config values in your code
    ▰ Break your start process if any value missed

    View Slide

  19. # .env.example
    # Default log level
    LOG_LEVEL=info
    # Graceful shutdown timeout in milliseconds
    SHUTDOWN_TIMEOUT=1000
    # HTTP Boundary port
    HTTP_PORT=8000
    # Redis connection string
    REDIS_URI=redis://127.0.0.1:6379

    View Slide

  20. require('dotenv-safe').load({
    allowEmptyValues: true,
    path: join(__dirname, '..', '.env'),
    sample: join(__dirname, '..', '.env.example')
    });
    const logger = require('./logger');
    logger.levels('stdout', process.env.LOG_LEVEL);
    const settings = {
    shutdownTimeout: process.env.SHUTDOWN_TIMEOUT,
    http: {
    port: process.env.HTTP_PORT,
    },
    redis: {
    uri: process.env.REDIS_URI,
    },
    };
    module.exports = settings;

    View Slide

  21. What is Quality?
    23
    Dima: process.env knows
    every env var. This is
    risky!
    Nikita: Then your project
    uses only 11 factors.

    View Slide

  22. IV. Backing services
    Treat backing services
    as attached resources

    View Slide

  23. What is Quality?
    25
    ▰ local and third party parity
    ▰ Use connection string is URL and can be used
    as locator/credentials
    ▰ Native Node.js module url has parse method
    ▰ Repeat III. Config one more time

    View Slide

  24. What is Quality?
    26
    Nice to have
    ▰ Tech stack for project
    or Readme.md with strict versions
    ▰ For local development
    docker-compose file
    or minikube config file

    View Slide

  25. V. Build, release, run
    Strictly separate build
    and run stages

    View Slide

  26. What is Quality?
    28
    ▰ Artifact
    ▰ Build
    ▰ Release
    ▰ Run time
    ▰ Dry run

    View Slide

  27. What is Quality?
    29
    Node.js artifact
    ▰ N/A
    ▰ Docker
    ▰ Lambda zip
    ▰ Application Zip
    ▻ Big size
    ▻ node-gyp compiled code can be broken on
    another computer

    View Slide

  28. VI. Processes
    Execute the app as one or
    more stateless processes

    View Slide

  29. What is Quality?
    31

    View Slide

  30. Awesome Pair!
    Docker and Node.js
    has a common thing
    – single process

    View Slide

  31. View Slide

  32. VII. Port binding
    Export services
    via port binding

    View Slide

  33. What is Quality?
    35
    ▰ Don’t hardcode port at the code,
    use env vars
    ▰ Bootstrap should fail,
    if the port is not available
    ▰ Dockerfile EXPOSE directive
    depence on deploy, but 9229...

    View Slide

  34. VIII. Concurrency
    Scale out via
    the process model

    View Slide

  35. What is Quality?
    37
    ▰ Unix process model
    ▰ should never daemonize
    ▰ Use process manager like
    systemd/pm2/etc
    ▰ process and cluster are first
    class citizen

    View Slide

  36. IX. Disposability
    Maximize robustness with
    fast startup and graceful
    shutdown

    View Slide

  37. const server = app.listen(settings.port, () => {
    logger.info(`Server started on port ${settings.port}`);
    });
    function stopHandler(){
    logger.info(`Stopping server on port ${settings.port}`);
    const timeout = setTimeout(() => {
    logger.info(`Server on port ${settings.port} stop forcefully`);
    process.exit(1);
    }, settings.stopTimeout);
    server.close(() => {
    logger.info(`Server on port ${settings.port} stopped`);
    clearTimeout(timeout);
    });
    };
    process.on('exit', (code) => logger.info(`Exit with code: ${code}`));
    ['SIGTERM','SIGINT','SIGHUP']
    .forEach(signal => process.on(signal, stopHandler);

    View Slide

  38. X. Dev/prod parity
    Keep development,
    staging, and production as
    similar as possible

    View Slide

  39. What is Quality?
    41
    ▰ Same backing services
    ▰ Same lib versions
    ▰ Same bla-bla for
    Reproducibility

    View Slide

  40. XI. Logs
    Treat logs
    as event streams

    View Slide

  41. What is Quality?
    43
    ▰ A twelve-factor app never concerns itself with
    routing or storage of its output stream
    ▰ Writes event stream, unbuffered, to
    stdout/stderr
    ▰ JSON format for simplification log parsing
    ▰ pino has this format from the box
    ▰ for local development use pino pretty

    View Slide

  42. stdout stderr

    View Slide

  43. XII. Admin processes
    Run admin/management
    tasks as one-off processes

    View Slide

  44. What is Quality?
    46
    ▰ Node.js has REPL, so be DevOps Engineer
    ▰ Check node_modules/.bin
    every script starts with
    #!/usr/bin/env node
    ▰ Write your own script or reuse packages
    ▰ Database migrations
    ▰ Your own CLI with typescript decorators with
    clime package

    View Slide

  45. 12factor.net

    View Slide

  46. 49
    THANKS!
    Happy coding
    with 12 factors!
    You can find me on Twitter as @galk_in
    Slides are available at speakerdeck.com/galkin
    or at my site galk.in

    View Slide