say hi to docker for ror

Serhii Koba, MobiDev

What's inside

Enjoy developing

headaches

  • Different environments
  • Manual launching
  • Portability
  • Scaling
  • Long deploy
  • Cleanup after trying new stuff
  • Security

docker vs Vms

installation

https://docs.docker.com/engine/installation/

Dockerfile

  • FROM (image)
  • RUN
  • ENV
  • WORKDIR
  • COPY
  • EXPOSE
  • ADD
  • CMD
  • VOLUME
FROM ruby:2.3.1

RUN apt-get update -qq && apt-get install \
    -y build-essential libpq-dev \
    imagemagick libmagickwand-dev libcurl3 \
    libcurl3-gnutls libcurl4-openssl-dev nodejs

ENV RAILS_ROOT /var/www/app

RUN mkdir -p $RAILS_ROOT/tmp/pids

WORKDIR $RAILS_ROOT

COPY . .

VOLUME .:/var/www/app

EXPOSE 3000

CMD bundle exec rails s -p 3000 -b '0.0.0.0'

# стоит избегать длинных списков команд вроде таких:
RUN apt-get update
RUN apt-get upgrade
RUN apt-get install nginx

# А вместо этого писать все одной строкой:
RUN apt-get update &&\
    apt-get upgrade &&\
    apt-get install nginx

Шпаргалка по командам Dockerfile

FROM <имя-образа> — какой образ использовать в качестве базы (должна быть первой строкой в любом Dockerfile).
MAINTAINER <имя> — имя мейнтейнера данного Dockerfile.
RUN <команда> — запустить указанную команду внутри контейнера.
CMD <команда> — выполнить команду при запуске контейнера (обычно идет последней).
EXPOSE <порт> — список портов, которые будет слушать контейнер (используется механизмом линковки).
ENV <ключ> <значение> — создать переменную окружения.
ADD <путь> <путь> — скопировать файл/каталог внутрь контейнера/образа (первый аргумент может быть URL).
ENTRYPOINT <команда> — команда для запуска приложения в контейнере (по умолчанию /bin/sh -c).
VOLUME <путь> — пробросить в контейнер указанный каталог (аналог опции -v).
USER <имя> — сменить юзера внутри контейнера.
WORKDIR <путь> — сменить каталог внутри контейнера.
ONBUILD [ИНСТРУКЦИЯ] — запустить указанную инструкцию Dockerfile только в том случае, если образ используется для сборки другого образа (с помощью FROM).

docker hub

docker run -d --name firefox -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix kennethkl/firefox

Basic commands

  • build
  • run
  • ps (-a)
  • kill
  • images
  • exec
  • rmi
  • attach
    (Ctrl+Q+P+Q)
> docker build -t "myapp:latest"
Building web
Step 1 : FROM growthhackers/ruby-node:2.3.1-6.3.1
 ---> dc04f4f6761b
Step 2 : RUN apt-get update -qq && apt-get install -y 
 ---> libmagickwand-dev libqt4-dev libqtwebkit-dev php5-cli
 ---> Using cache
 ---> 9ab61f9186d4
Step 3 : ENV RAILS_ROOT /app
 ---> Using cache
 ---> f75c7870dad7
...

> docker run -p 3000 myapp:latest

> docker exec -i -t 4c01db0b339c bash

> docker ps
CONTAINER ID        IMAGE                        COMMAND                CREATED              STATUS              PORTS               NAMES
d7886598dbe2        crosbymichael/redis:latest   /redis-server --dir    33 minutes ago       Up 33 minutes       6379/tcp            redis,webapp/db

> docker kill 4c01db0b339c

> docker images
REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
postgres                  9.3.5               746b819f315e        4 days ago          213.4 MB

> docker rmi 77af4d6b9913 

MANUAL LAUNCHING SUCKS

say hi to docker compose

Docker Compose

  • Works with a list of containers
  • All configuration is in one place
  • Builds, starts, stops containers

20 containers:

  • 5 Rails applications
  • 1 Database
  • 4 Workes
  • 4 Tests
  • 1 SMTP server
  • 1 AWS S3 server
  • 4 Caches (gems, Redis)

 

= 23s

docker-compose.yml

  • links
  • ports
  • image
  • volumes
  • environment
  • etc
db:
  image: postgres:latest
  volumes:
    - /var/lib/postgresql/data
  environment:
    POSTGRES_USER: "postgres"
    POSTGRES_PASSWORD: "development"

web:
  build: .
  command: bundle exec rails s -p 3000 -b '0.0.0.0'
  environment:
    RAILS_ENV: development
  links:
    - db:postgresdb
  ports:
    - "3000:3000"
  volumes:
    - .:/var/www/app

database.yml

/etc/hosts

postgres: &default
  adapter: postgresql
  encoding: utf8
  host: postgresdb
  username: postgres
  password: development
  min_messages: warning
  pool: 2
  timeout: 5000

development:
  <<: *default
  database: myapp_development

Basic commands

  • build
  • up (-d)
  • stop
  • run
# Стартуем все контейнеры
docker-compose up -d

# Стартует только контейнер web
docker-compose run web

# Запускаем команду в контейнере
docker-compose run web rake db:migrate

# Остановить контейнеры
docker-compose stop

real life example

dockerized ror app in the wild

what's included

  • Database (Postgres)
  • Caching  (Redis)
  • Shared bundle cache
  • Web app
  • Worker (Sidekiq)
  • Tests

Database

Postgres

db:
  image: postgres:latest
  volumes:
    - /var/lib/postgresql/data
  ports:
    - '5432'
  environment:
    POSTGRES_USER: 'postgres'
    POSTGRES_PASSWORD: 'development'
  command: 'postgres -c fsync=off'

Redis

Stores cache and

user sessions

# Redis caching container
redis:
  image: redis:2.8
  ports:
  # 6380 is for example
    - "6380:6379" 

Bundler Cache

Cache gems as volume

bundler-cache:
  image: ruby:2.3.1
  command: /bin/true
  volumes:
    - /usr/local/bundle

worker

Sidekiq

worker:
    build: .
    volumes_from:
      - bundler-cache
      - web
    links:
      - db:db
      - redis
    command: bundle exec sidekiq

Tests

Dockerfile.tests

  • Install ruby and etc
  • Install Chrome WebDriver
  • Configure xvfb
  • Use headless gem for tests...
tests:
  build: .
  dockerfile: Dockerfile.tests
  command: bundle exec rspec
  environment:
    RAILS_ENV: test
  links:
    - db:db
  volumes_from:
    - bundler-cache
    - web

WEB (RoR app)

Wrapping things up

web:
  build: .
  command: "bundle exec rails s -p 3000 -b '0.0.0.0'"
  environment:
    RAILS_ENV: development
  links:
    - db:postgresdb
    - redis:redis
  ports:
    - "3000:3000"
  volumes:
    - .:/var/www/app
  volumes_from:
    - bundler-cache

common initialization

Basic steps

# Setup application
docker-compose build
docker-compose run web bundle install
docker-compose run web rake db:create db:migrate db:seed 

# Run application
docker-compose up -d

# Setup tests
docker-compose run tests rake db:create db:migrate

# Run tests
docker-compose run tests

Docker for local dev

  • fast and easy infrastructure from images
  • auto launching
  • portability
  • close copy of production
  • easy and secure to try new stuff

docker for productIon

  • fast zero-downtime deploys
  • ci
  • scaling
  • docker hub
  • guaranteed to work the same as locally
  • migrate to new software versions easily

next topics

  • Docker networking
  • Docker Machine
  • Docker Swarm
  • Docker UI, Shipyard

docker run -d -p 9000:9000 --privileged -v /var/run/docker.sock:/var/run/docker.sock uifd/ui-for-docker

credentials

http://meetup.mobidev.com.ua/

https://www.linkedin.com/in/serhii-koba

https://slides.com/skoba/docker-for-ror

Made with Slides.com