Dockerizing Ruby Applications - The Best Practices

33
Dockerizing Ruby Applications- The Best Practices Lauri Nevala, Co-Founder and Software Engineer

Transcript of Dockerizing Ruby Applications - The Best Practices

Dockerizing Ruby Applications- The Best Practices

Lauri Nevala, Co-Founder and Software Engineer

Kontena briefly

© 2015 Kontena, Inc.

What is Kontena?

Open Source container platform built to maximize developer happiness. Works on

any cloud, easy to setup, simple to use.

Quick Facts

650+GITHUB STARGAZERS

>100kNUMBER OF INSTALLS

FEATURED IN

The Container Platform

All Batteries Included!

Built-In Image RegistrySometimes projects can not use publicly hosted

container image registries like DockerHub. Kontena comes with built-in container image

registry providing private and secure solution.

Built-In VPN AccessAll containers are run inside a virtual private

network by default. Nothing is exposed to Internet unless explicitly defined. With

Kontena’s built-in VPN access developers can securely access those resources.

Built-In Load BalancerKontena comes with built-in load balancer.

Based on Haproxy. It features fully automatic, zero-downtime operation due to deep

integration with Kontena’s service discovery and orchestration technology.

Aggregated Stats & LogsKontena provides real-time log and statistics streams containers. The streams may be grouped and aggregated to produce service level streams. This allows easy viewing of logs and statistics for your application CPU, memory, disk and network usage.

User Management with Audit TrailAll events and actions performed through Kontena CLI or APIs are logged into audit trail. Combined with users and access control, the audit trail support makes Kontena a reliable and secure solution for any enterprise deployments.

Built-In Secrets ManagementWhen your application requires access to APIs or databases, you'll often need to use secrets such as passwords and access tokens for authenticating the access. Kontena Vault is a secure key/value storage that can be used to manage secrets in Kontena.

“Includes all that sh*it you don’t need to implement by yourself”

Dockerizing Ruby Application

© 2015 Kontena, Inc.

Containers vs. VMs

INFRA

HOST OS

APP

INFRA

HOST OS

APP

INFRA

HOST OS

APP

INFRA

HOST OS

HYPERVISOR

GUEST OS

GUEST OS

GUEST OS

APP APP APP

INFRA

HOST OS

CONTAINER ENGINE

APP APP APP

Legacy Virtualization ContainerizationYear 2014

© 2015 Kontena, Inc.

Docker Core Concepts

• Dockerfile• Describes a Docker image

• Docker image • “Compiled” version of the Dockerfile

• Docker container• Running instance of the Docker image

© 2015 Kontena, Inc.

Docker Image

• Packs up the application and environment required by the application to run• Consist of image layers• Extends a base image

© 2015 Kontena, Inc.

Ruby Base Image Strategies

• Official Ruby images• ruby:version

• defacto image, has a large number of extremely common Debian packages• ruby:onbuild

• really useful for "getting off the ground running”.• it's not recommended for long-term usage within a project due to the lack of control over when the ONBUILD triggers fire 

• ruby:slim•  contains the minimal packages needed to run ruby

• ruby:alpine• based on Alpine Linux. The main caveat to note is that it does use musl libc instead of glibc and friends, so

certain software might run into issues depending on the depth of their libc requirements

• Build your own Ruby image• Include only those libraries that are needed for your app

© 2015 Kontena, Inc.

Sometimes size does matter

© 2015 Kontena, Inc.

Ruby:2.3.1 729 MiB

Ruby:2.3.1-slim283 MiB

Ruby:2.3.1-alpine

125 MiB

Sizes of the Official Ruby Images

© 2015 Kontena, Inc.

Docker Containers – Best practices

• Run one process per container• Twelve-Factor App FTW!• Store config in the environment• Treat backing services as attached resources• Export services via port binding• Treat logs as event streams• Etc.

• Don’t rely on IP addresses

Example

DockerfileFROM ruby:2.3.1-alpineADD Gemfile /app/ADD Gemfile.lock /app/RUN apk --update add --virtual build-dependencies ruby-dev build-base && \ gem install bundler --no-ri --no-rdoc && \ cd /app ; bundle install --without development test && \ apk del build-dependenciesADD . /appRUN chown -R nobody:nogroup /appUSER nobodyENV RACK_ENV productionEXPOSE 9292WORKDIR /app

Sending build context to Docker daemon 29.7 kBStep 1 : FROM ruby:2.3.1-alpine ---> adae74697505Step 2 : ADD Gemfile /app/ ---> 81f926a9e4d6Removing intermediate container 1000f93a8025Step 3 : ADD Gemfile.lock /app/ ---> ed3e4a1dfe0eRemoving intermediate container 5920c0c209e6Step 4 : RUN apk --update add --virtual build-dependencies ruby-dev build-base && gem install bundler --no-ri --no-rdoc && cd /app ; bundle install --without development test && apk del build-dependencies ---> Running in 09029fc13d73fetch http://dl-cdn.alpinelinux.org/alpine/v3.3/main/x86_64/APKINDEX.tar.gzfetch http://dl-cdn.alpinelinux.org/alpine/v3.3/community/x86_64/APKINDEX.tar.gz(1/23) Installing gmp (6.1.0-r0)(2/23) Installing libgcc (5.3.0-r0)(3/23) Installing libstdc++ (5.3.0-r0)(4/23) Installing libgmpxx (6.1.0-r0)(5/23) Installing gmp-dev (6.1.0-r0)(6/23) Installing libedit (20150325.3.1-r3)(7/23) Installing ruby-libs (2.2.4-r0)(8/23) Installing ruby-dev (2.2.4-r0)(9/23) Installing binutils-libs (2.25.1-r0)(10/23) Installing binutils (2.25.1-r0)(11/23) Installing isl (0.14.1-r0)(12/23) Installing libgomp (5.3.0-r0)(13/23) Installing libatomic (5.3.0-r0)(14/23) Installing mpfr3 (3.1.2-r0)(15/23) Installing mpc1 (1.0.3-r0)(16/23) Installing gcc (5.3.0-r0)(17/23) Installing make (4.1-r0)

[email protected] ~/helsinki-ruby-brigade/todo$ docker build -t kontena/todo-example:latest .

© 2015 Kontena, Inc.

(18/23) Installing musl-dev (1.1.12-r5)(19/23) Installing libc-dev (0.7-r0)(20/23) Installing fortify-headers (0.7-r0)(21/23) Installing g++ (5.3.0-r0)(22/23) Installing build-base (0.4-r1)(23/23) Installing build-dependencies (0)Executing busybox-1.24.1-r7.triggerOK: 192 MiB in 55 packagesSuccessfully installed bundler-1.12.51 gem installedFetching gem metadata from https://rubygems.org/Fetching version metadata from https://rubygems.org/Installing i18n 0.7.0Using json 1.8.3Installing minitest 5.9.0Installing thread_safe 0.3.5Installing builder 3.2.2Installing bson 4.1.1 with native extensionsInstalling origin 2.2.0Installing puma 3.4.0 with native extensionsInstalling rack 1.5.2Installing tilt 1.4.1Using bundler 1.12.5Installing tzinfo 1.2.2Installing mongo 2.2.5Installing rack-protection 1.5.3Installing activesupport 4.2.6Installing sinatra 1.4.5Installing activemodel 4.2.6Installing mongoid 5.1.3Bundle complete! 3 Gemfile dependencies, 18 gems now installed.Gems in the groups development and test were not installed.

© 2015 Kontena, Inc.

Bundled gems are installed into /usr/local/bundle.(1/23) Purging build-dependencies (0)(2/23) Purging ruby-dev (2.2.4-r0)(3/23) Purging gmp-dev (6.1.0-r0)(4/23) Purging libgmpxx (6.1.0-r0)(5/23) Purging ruby-libs (2.2.4-r0)(6/23) Purging build-base (0.4-r1)(7/23) Purging make (4.1-r0)(8/23) Purging fortify-headers (0.7-r0)(9/23) Purging g++ (5.3.0-r0)(10/23) Purging gcc (5.3.0-r0)(11/23) Purging binutils (2.25.1-r0)(12/23) Purging isl (0.14.1-r0)(13/23) Purging libatomic (5.3.0-r0)(14/23) Purging libc-dev (0.7-r0)(15/23) Purging musl-dev (1.1.12-r5)(16/23) Purging libstdc++ (5.3.0-r0)(17/23) Purging mpc1 (1.0.3-r0)(18/23) Purging mpfr3 (3.1.2-r0)(19/23) Purging gmp (6.1.0-r0)(20/23) Purging libgcc (5.3.0-r0)(21/23) Purging libedit (20150325.3.1-r3)(22/23) Purging binutils-libs (2.25.1-r0)(23/23) Purging libgomp (5.3.0-r0)Executing busybox-1.24.1-r7.triggerOK: 23 MiB in 32 packages ---> 829379018bc7Removing intermediate container 09029fc13d73Step 5 : ADD . /app ---> 66705b32dc48Removing intermediate container c7f73596c9aeStep 6 : RUN chown -R nobody:nogroup /app

© 2015 Kontena, Inc.

---> Running in be356cda2cd6 ---> 0673c22b8d74Removing intermediate container be356cda2cd6Step 7 : USER nobody ---> Running in fd495cb3838a ---> 83cb7493aa53Removing intermediate container fd495cb3838aStep 8 : ENV RACK_ENV production ---> Running in edac524bbd44 ---> e3b6c26647b2Removing intermediate container edac524bbd44Step 9 : EXPOSE 9292 ---> Running in 4369855c3ab4 ---> 3d82b78a2213Removing intermediate container 4369855c3ab4Step 10 : WORKDIR /app ---> Running in 6172a5c18269 ---> e73df80077b5Removing intermediate container 6172a5c18269Successfully built [email protected] ~/helsinki-ruby-brigade/todo$

From Containers to Microservices

• Docker Compose• Tool for defining and running multi-container Docker applications• Services and their configurations are defined in YAML file(s)

© 2015 Kontena, Inc.

docker-compose.ymlversion: '2’services: web: image: kontena/todo-example:latest command: bundle exec puma -p 9292 -e production environment: - MONGODB_URI=mongodb://mongodb:27017/todo_production ports: - 9292:9292 links: - mongodb:mongodb

mongodb: image: mongo:3.2 command: mongod --smallfiles

© 2015 Kontena, Inc.

Rolling to Production

• How big this app will be? How many users it will serve?• Do you want your application to be infrastructure agnostic or lean

heavily on some cloud provider?• How to run databases or save other persistent data?• How to scale the application and handle load balancing?• How do you pass sensitive data to your application and where to

store that data?• How the application can be deployed and updated with zero down-

time?

Example

kontena.ymlversion: '2’services: mongodb: image: mongo:3.2 instances: 3 stateful: true command: --replSet kontena –smallfiles hooks: post_start: - cmd: sleep 10 name: sleep instances: 1 oneshot: true - cmd: mongo --eval "printjson(rs.initiate());” name: rs_initiate instances: 1 oneshot: true - cmd: mongo --eval "printjson(rs.add('%{project}-mongodb-2'))” name: rs_add2 instances: 1 oneshot: true - cmd: mongo --eval "printjson(rs.add('%{project}-mongodb-3'))” name: rs_add3 instances: 1 oneshot: true

© 2015 Kontena, Inc.

app: image: kontena/todo-example:latest links: - mongodb:mongodb - loadbalancer environment: - MONGODB_URI=mongodb://%{project}-mongodb-1.kontena.local:27017,%{project}-mongodb-2.kontena.local:27017,%{project}-mongodb-3.kontena.local:27017/todo_production - KONTENA_LB_VIRTUAL_PATH=/ - KONTENA_LB_INTERNAL_PORT=9292 command: bundle exec puma -p 9292 -e production

loadbalancer: image: kontena/lb:latest deploy: strategy: daemon ports: - 80:80

© 2015 Kontena, Inc.

Deploying Application

[email protected] ~/helsinki-ruby-brigade/todo$ kontena app deploy

© 2015 Kontena, Inc.

Scaling Application

[email protected] ~/helsinki-ruby-brigade/todo$ kontena app scale app 10

© 2015 Kontena, Inc.

Resources

• Todo Example: https://github.com/kontena/helsinki-meetup-hackathon• Getting started: http://www.kontena.io• GitHub: https://github.com/kontena/kontena• Gitter: https://gitter.im/kontena/kontena• Kontena Meetup: http://www.meetup.com/Kontena-Helsinki/

Thank You!www.kontena.io

We are hiring!kontena.io/jobs