Ich hatte heute das Problem, dass ich eine ältere Ruby on Rails App debuggen musste, die partout nicht auf meinem aktuellen Setup (macOS 10.13.4) starten wollte. Diverse Versionskonflikte usw.

Docker all the things!

Eigentlich will ich schon länger mal unsere ganzen Apps in Docker Container verpacken, um solchen Problemen aus dem Weg zu gehen. Aber wie das dann manchmal so ist, hat man andere Sachen im Kopf, bis es dann mal wirklich knallt.

Also den ganzen Mist in Docker verpacken.

Dockerfile

FROM ruby:2.3.3
RUN apt-get update -qq && apt-get install -y build-essential nodejs mysql-client
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
# COPY id_rsa /root/.ssh/id_rsa # Update: wird nicht gebraucht
RUN bundle install
COPY . /myapp
Sieht erstmal relativ normal aus. ABER: Wie hier zu sehen ist, kopiere ich einen Key (`id_rsa`) mit in den Container. Hier ist höchste Vorsicht geboten. Die `id_rsa` ist per .gitignore blockiert und der Container wird nicht als Image in eine Registry geladen, sondern nur lokal gestartet.


Ich bin gezwungen hier das Keyfile mit in den Container zu kopieren, weil es für mich sonst nicht möglich wäre, mit Capistrano aus dem Container heraus den Code zu deployen. Ein ganz schlimmer Hack.

docker-compose.yml

Update: Stellt sich heraus, dass ich mein lokales ~/.ssh/ Directory auch einfach als Volumen in den Container mounten kann. Siehe - /Users/<USERNAME>/.ssh:/root/.ssh

Das docker-compose File sieht relativ schlicht aus:

version: '3'
services:
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp
      - /Users/<USERNAME>/.ssh:/root/.ssh
    ports:
      - "3000:3000"

database.yml

Ich habe einen lokalen MySQL Server installiert, auf welchen die Rails App zugreifen soll. Theoretisch könnte ich einen Datenbankservice in meine docker-compose.yml eintragen, darauf wollte ich aber verzichten, um es so einfach wie möglich zu halten.

In der Rails app muss nun noch die config/database.yml angepasst werden:

development:
  adapter: mysql2
  encoding: utf8
  database: <databasename>
  username: <user>
  password: <password>
  host: host.docker.internal
  socket: /tmp/mysql.sock
  pool: 40

Hier ist eigentlich nur besonders, dass als Host host.docker.internal angegeben ist. Das ist die Adresse, mit der man aus einem Container heraus den Docker Host ansprechen kann (im Fall von Docker for Mac).

Danach kann der Container mit docker-compose up gestartet werden.

Arbeiten im Container

Ich kann nun einfach lokal an der App arbeiten, und der Container kümmert sich darum das die App läuft. Wenn alles fertig ist, einfach den Code per git einchecken und dann Capistrano im Container aufrufen:

docker-compose exec web bundle exec cap deploy

Zusammenfassung

Das ist eine furchtbare Lösung für ein noch furchtbareres Problem. Ich weiß nun aber, dass ich alle unsere Rails Apps in richtige Docker Container verpacken werde.