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

Containerizing Rails: Techniques, Pitfalls, & Best Practices

Containerizing Rails: Techniques, Pitfalls, & Best Practices

Presentation by Daniel Azuma at RailsConf 2018. Covers best practices for designing Docker images for Rails applications. More information at http://daniel-azuma.com/railsconf2018

Daniel Azuma

April 18, 2018
Tweet

More Decks by Daniel Azuma

Other Decks in Programming

Transcript

  1. View Slide

  2. Containerizing Rails
    Techniques, Pitfalls, & Best Practices
    Daniel Azuma
    Google Cloud Platform

    View Slide

  3. Daniel Azuma
    http://daniel-azuma.com/
    @danielazuma

    View Slide

  4. View Slide

  5. Languages,
    Optimizations, and
    Libraries

    View Slide

  6. Languages,
    Optimizations, and
    Libraries

    View Slide

  7. View Slide

  8. Basic concepts

    View Slide

  9. Håkan Dahlström, "Multicolored Containers"
    Source: https://www.flickr.com/photos/dahlstroms/3144199355
    License: https://creativecommons.org/licenses/by/2.0/

    View Slide

  10. Isolation

    View Slide

  11. View Slide

  12. • File system

    View Slide

  13. • File system
    • CPU allocation

    View Slide

  14. • File system
    • CPU allocation
    • Memory

    View Slide

  15. • File system
    • CPU allocation
    • Memory
    • Network stack

    View Slide

  16. • File system
    • CPU allocation
    • Memory
    • Network stack
    • Users

    View Slide

  17. • File system
    • CPU allocation
    • Memory
    • Network stack
    • Users
    • Processes

    View Slide

  18. • File system
    • CPU allocation
    • Memory
    • Network stack
    • Users
    • Processes

    View Slide

  19. • File system
    • CPU allocation
    • Memory
    • Network stack
    • Users
    • Processes
    != VM

    View Slide

  20. • File system
    • CPU allocation
    • Memory
    • Network stack
    • Users
    • Processes Linux host

    View Slide

  21. • File system
    • CPU allocation
    • Memory
    • Network stack
    • Users
    • Processes
    CPU arch
    Linux kernel
    Linux host:

    View Slide

  22. • File system
    • CPU alloc
    • Memory
    • Network stack
    • Users
    • Processes
    CPU arch
    Linux kernel
    Linux host:
    • File system
    • CPU alloc
    • Memory
    • Network stack
    • Users
    • Processes
    • File system
    • CPU alloc
    • Memory
    • Network stack
    • Users
    • Processes

    View Slide

  23. Images

    View Slide

  24. View Slide

  25. Dockerfile

    View Slide

  26. # Rails Dockerfile
    FROM ruby
    WORKDIR /opt/app
    COPY . /opt/app
    RUN bundle install
    ENV PORT=8080
    CMD ["bundle", "exec",
    "rails", "server"]

    View Slide

  27. # Rails Dockerfile
    FROM ruby
    WORKDIR /opt/app
    COPY . /opt/app
    RUN bundle install
    ENV PORT=8080
    CMD ["bundle", "exec",
    "rails", "server"]

    View Slide

  28. # Rails Dockerfile
    FROM ruby
    WORKDIR /opt/app
    COPY . /opt/app
    RUN bundle install
    ENV PORT=8080
    CMD ["bundle", "exec",
    "rails", "server"]

    View Slide

  29. # Rails Dockerfile
    FROM ruby
    WORKDIR /opt/app
    COPY . /opt/app
    RUN bundle install
    ENV PORT=8080
    CMD ["bundle", "exec",
    "rails", "server"]

    View Slide

  30. # Rails Dockerfile
    FROM ruby
    WORKDIR /opt/app
    COPY . /opt/app
    RUN bundle install
    ENV PORT=8080
    CMD ["bundle", "exec",
    "rails", "server"]

    View Slide

  31. # Rails Dockerfile
    FROM ruby
    WORKDIR /opt/app
    COPY . /opt/app
    RUN bundle install
    ENV PORT=8080
    CMD ["bundle", "exec",
    "rails", "server"]

    View Slide

  32. Which base image?

    View Slide

  33. FROM ruby
    FROM alpine
    FROM phusion/baseimage
    ???
    Tip #1: Read and understand your base image

    View Slide

  34. Size does matter

    View Slide

  35. apt-get install

    View Slide

  36. RUN apt-get clean \
    && rm -f /var/lib/apt/lists/*_*

    View Slide

  37. RUN apt-get update -y
    RUN apt-get install -y -q mypackage
    RUN apt-get clean \
    && rm -f /var/lib/apt/lists/*_*

    View Slide

  38. RUN apt-get update -y \
    && apt-get install -y -q mypackage \
    && apt-get clean \
    && rm -f /var/lib/apt/lists/*_*

    View Slide

  39. FROM base-image

    View Slide

  40. FROM base-image
    RUN apt-get update

    View Slide

  41. FROM base-image
    RUN apt-get update
    RUN apt-get install mypkg

    View Slide

  42. FROM base-image
    RUN apt-get update
    RUN apt-get install mypkg
    RUN apt-get clean

    View Slide

  43. FROM base-image
    RUN apt-get update \
    && apt-get install mypkg \
    && apt-get clean
    Tip #2: Combine install commands with cleanup

    View Slide

  44. RUN apt-get install build-essential \
    && bundle install

    View Slide

  45. http://artgallery.msfc.nasa.gov/4459.html
    Source: NASA

    View Slide

  46. FROM my-base AS builder
    COPY . /app
    RUN apt-get install build-essential \
    && bundle install --deployment
    FROM my-base
    COPY --from=builder /app /app

    View Slide

  47. FROM my-base AS builder
    COPY . /app
    RUN apt-get install build-essential \
    && bundle install --deployment
    FROM my-base
    COPY --from=builder /app /app

    View Slide

  48. FROM my-base AS builder
    COPY . /app
    RUN apt-get install build-essential \
    && bundle install --deployment
    FROM my-base
    COPY --from=builder /app /app
    Ruby base image

    View Slide

  49. FROM my-base AS builder
    COPY . /app
    RUN apt-get install build-essential \
    && bundle install --deployment
    FROM my-base
    COPY --from=builder /app /app
    Ruby base image
    App source

    View Slide

  50. FROM my-base AS builder
    COPY . /app
    RUN apt-get install build-essential \
    && bundle install --deployment
    FROM my-base
    COPY --from=builder /app /app
    Ruby base image
    App source
    Compilers, etc.

    View Slide

  51. FROM my-base AS builder
    COPY . /app
    RUN apt-get install build-essential \
    && bundle install --deployment
    FROM my-base
    COPY --from=builder /app /app
    Ruby base image
    App source
    Vendored gems
    Compilers, etc.

    View Slide

  52. FROM my-base AS builder
    COPY . /app
    RUN apt-get install build-essential \
    && bundle install --deployment
    FROM my-base
    COPY --from=builder /app /app
    Ruby base image Ruby base image
    App source
    Vendored gems
    Compilers, etc.

    View Slide

  53. FROM my-base AS builder
    COPY . /app
    RUN apt-get install build-essential \
    && bundle install --deployment
    FROM my-base
    COPY --from=builder /app /app
    Ruby base image Ruby base image
    App source
    Vendored gems
    Compilers, etc.
    App w/vendored gems

    View Slide

  54. FROM my-base AS builder
    COPY . /app
    RUN apt-get install build-essential \
    && bundle install --deployment
    FROM my-base
    COPY --from=builder /app /app
    Ruby base image
    Ruby base image
    App source
    Vendored gems
    Compilers, etc.
    App w/vendored gems

    View Slide

  55. FROM my-base AS builder
    COPY . /app
    RUN apt-get install build-essential \
    && bundle install --deployment
    FROM my-base
    COPY --from=builder /app /app
    Ruby base image
    App w/vendored gems
    Tip #3: Use a separate build stage

    View Slide

  56. Gerd Rohs, "Image in the image"
    https://pixabay.com/en/image-in-the-image-mobile-phone-2204798/
    CC0

    View Slide

  57. View Slide

  58. RUN echo "en_US.UTF-8 UTF-8" > /etc/locale.gen \
    && locale-gen en_US.UTF-8
    ENV LANG en_US.UTF-8
    ENV LANGUAGE en_US:en
    Tip #4: Set the system locale

    View Slide

  59. "Australia in a Nutshell" (Sign contents modified)
    Photo by: Kristian Thøgersen
    Source: https://www.flickr.com/photos/flottenheimer/5534636006
    License: https://creativecommons.org/licenses/by/2.0/

    View Slide

  60. Tip #5: Create an unprivileged user
    # After building your app...
    RUN adduser -s /bin/sh -u 1001 -G root \
    -h /app -S -D rails \
    && chown -R rails /app
    USER rails

    View Slide

  61. # Exec form
    CMD ["bundle", "exec", "rails", "s"]
    # Shell form
    CMD bundle exec rails s

    View Slide

  62. # Exec form
    CMD ["bundle", "exec", "rails", "s"]
    # Shell form
    CMD bundle exec rails s
    Tip #6: Prefer exec form for CMD

    View Slide

  63. # Exec form
    CMD ["bundle", "exec", "rails", "s"]
    # Shell form
    CMD exec bundle exec rails s
    Tip #7: Prefix shell form with the “exec” keyword

    View Slide

  64. ONBUILD

    View Slide

  65. # Base image...
    ONBUILD COPY . /app
    ONBUILD RUN bundle install
    # ...

    View Slide

  66. # Base image...
    ONBUILD COPY . /app
    ONBUILD RUN bundle install
    # ...
    # App image...
    FROM base-image
    # (implicit commands)

    View Slide

  67. # Base image...
    ONBUILD COPY . /app
    ONBUILD RUN bundle install
    # ...
    # App image...
    FROM base-image
    # (implicit commands)
    Tip #8: Avoid ONBUILD

    View Slide

  68. Containers in
    production

    View Slide

  69. Containers == isolation

    View Slide

  70. Containers == isolation
    ⟹ predictability

    View Slide

  71. docker run --cpus=2.0 --memory=200M ...
    Tip #9: Always specify resource constraints

    View Slide

  72. apiVersion: v1
    kind: Pod
    spec:
    containers:
    - name: rails
    resources:
    requests:
    memory: "100Mi"
    cpu: 0.5
    limits:
    memory: "200Mi"
    cpu: 1.0
    ...

    View Slide

  73. View Slide

  74. View Slide

  75. View Slide

  76. Tip #10: Avoid preforking in a container
    ???

    View Slide

  77. Tip #11: Scale by adding containers

    View Slide

  78. https://pixabay.com/en/logs-timber-wood-logging-lumber-690888/
    CC0

    View Slide

  79. View Slide

  80. View Slide

  81. ENV RAILS_LOG_TO_STDOUT=true
    Tip #12: Log to STDOUT or an external agent

    View Slide

  82. • Optimizing for size/performance
    • Container contents
    • Containers in production

    View Slide

  83. http://daniel-azuma.com/railsconf2018

    View Slide

  84. Thank you!
    http://daniel-azuma.com/
    @danielazuma
    http://daniel-azuma.com/railsconf2018

    View Slide