Rails + PostgreSQL + Docker – začetna predloga

Predloga za razvojno okolje Ruby on Rails v Dockerju. Vsebuje samo infrastrukturo (Docker, Compose, okoljske spremenljivke, ignore datoteke). Rails aplikacijo ustvariš znotraj kontejnerja z rails new, zato na računalniku ne potrebuješ nameščenega Rubyja.

Sklad

Komponenta Različica Opomba
Ruby 4.0.9 uradna slika ruby:4.0.9-slim (minimalen Debian)
Ruby on Rails zadnja stabilna namesti se z gem install rails
PostgreSQL 18 (PG_MAJOR) uradna slika postgres:18; klient iz repozitorija PGDG
JavaScript importmap privzeto v Rails 8; Node.js ni potreben (glej Če potrebuješ Node.js)
Docker Compose v2 servisa app in db

Datoteke

Datoteka Namen
Dockerfile slika za razvoj: Ruby, sistemske knjižnice (build-essential, git, libpq-dev, libyaml-dev, pkg-config, postgresql-client-18), repozitorij PGDG, uporabnik app (UID 1000)
docker-compose.yml servis app (Rails na vratih 3000) in servis db (PostgreSQL) ter volumna bundle in pgdata
.env.example predloga okoljskih spremenljivk (različica PostgreSQL in dostop do baze); kopiraš jo v .env
.gitea/template seznam datotek, v katerih Gitea ob ustvarjanju repozitorija iz predloge zamenja spremenljivke z imenom repozitorija
.dockerignore v sliko ne kopira skrivnosti, .git, dnevnikov in začasnih datotek
.gitignore v Git ne shrani .env, ključev za credentials, dnevnikov ipd.

Zasnova

  • Osnova je ruby:4.0.9-slim, enako kot v Dockerfile, ki ga ustvari Rails. Je precej manjša od polne slike, glibc pa omogoča uporabo vnaprej prevedenih gemov (nokogiri, pg ...). Razvojna orodja, ki jih slim nima, so dodana z apt-get:
    • build-essential in pkg-config za prevajanje nativnih gemov,
    • libpq-dev za gem pg,
    • libyaml-dev za gem psych,
    • git za geme, nameščene iz Git repozitorijev,
    • postgresql-client-<PG_MAJOR> za rails dbconsole in db:schema:dump v formatu SQL.
  • Klient PostgreSQL je iz uradnega repozitorija PGDG (apt.postgresql.org), ne iz Debiana. Debian ima navadno starejšo glavno različico, pg_dump pa zavrne izvoz iz novejšega strežnika. Različico za strežnik (postgres:<PG_MAJOR>) in klient določa ena spremenljivka PG_MAJOR v .env (privzeto 18). Compose jo preda Dockerfile kot build argument. Po spremembi PG_MAJOR zgradi sliko znova (docker compose build). Pri prehodu na novo glavno različico strežnika obstoječi podatki v volumnu pgdata niso združljivi, zato jih je treba izvoziti in uvoziti (ali volume izbrisati).
  • Geme hrani volume bundle, ki je priklopljen na /usr/local/bundle. To je GEM_HOME uradne Ruby slike in je že v PATH. gem install in bundle install zato pišeta v isto mapo, gemi pa se ohranijo med zagoni kontejnerja.
  • BUNDLE_PATH namenoma ni nastavljen. Z njim bi bundle install geme nameščal v drugo mapo kot gem install, izvršljive datoteke (rails, rake) pa ne bi bile v PATH.
  • Kontejner teče kot uporabnik app (UID 1000), zato so datoteke, ki jih ustvari (npr. rails new, migracije), na računalniku v lasti tvojega uporabnika. Če ima tvoj uporabnik drug UID (preveri z id -u), ga spremeni v Dockerfile in v docker-compose.yml (user:).
  • Koda je priklopljena z .:/app, zato se spremembe takoj vidijo v kontejnerju, brez ponovne gradnje slike.
  • Podatke baze hrani volume pgdata, zato ostanejo tudi po docker compose down. Priklopljen je na /var/lib/postgresql (ne na /var/lib/postgresql/data), kot zahteva slika postgres od različice 18 naprej. Podatki so v podmapi <PG_MAJOR>/docker, kar omogoča nadgradnjo s pg_upgrade --link.
  • Servis db ima healthcheck (pg_isready), servis app pa se zažene šele, ko je baza pripravljena na povezave.
  • Ob zagonu servisa app se najprej izvede bin/rails db:prepare, ki ustvari bazo (če še ne obstaja) in izvede čakajoče migracije. Po docker compose down -v zato baze ni treba ustvarjati ročno.

Nov projekt iz predloge

1. Ustvari repozitorij iz predloge

Repozitorij rails-docker-starter je v Gitei označen kot predloga (Make repository a template).

  1. V Gitei izberi + → New Repository.
  2. V polju Template izberi rails-docker-starter.
  3. Obkljukaj Git Content. Ostale možnosti (webhooki, oznake ...) niso potrebne.
  4. Vpiši ime novega repozitorija (npr. moj-projekt) in klikni Create Repository.

Nov repozitorij dobi datoteke predloge brez njene zgodovine. Gitea v datotekah, naštetih v .gitea/template, zamenja spremenljivke z imenom repozitorija: v .env.example tako ${REPO_NAME_SNAKE}_development postane moj_projekt_development.

Nato repozitorij kloniraj:

git clone <url-novega-repozitorija>
cd moj-projekt

Če predlogo namesto tega kloniraš neposredno (git clone, nato rm -rf .git && git init), Gitea spremenljivk ne zamenja. V .env moraš ${REPO_NAME_SNAKE} zamenjati ročno, sicer Compose spremenljivko razume kot prazno in baza se imenuje _development.

2. Nastavi okoljske spremenljivke

cp .env.example .env

V .env preveri ime baze in vpiši uporabnika in geslo. APP_DATABASE_HOST naj ostane db (ime servisa v Compose).

3. Zgradi sliko in namesti Rails

docker compose build
docker compose run --rm app gem install rails

4. Ustvari Rails aplikacijo

docker compose run --rm app rails new . --database=postgresql --skip-docker
  • --skip-docker prepreči, da bi Rails ustvaril svoj (produkcijski) Dockerfile in prepisal obstoječega.
  • Ko vpraša, ali naj prepiše .gitignore, odgovori n. Predloga že vsebuje vse vrstice, ki jih doda Rails.
  • Ko vpraša, ali naj prepiše README.md, odgovori n, sicer izgubiš ta navodila. Navodila za aplikacijo lahko pozneje dopišeš sem.

5. Poveži Rails z bazo

V config/database.yml dodaj nastavitve povezave v razdelek default, da veljajo za development in test:

default: &default
  adapter: postgresql
  encoding: unicode
  max_connections: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  # Povezava na bazo v kontejnerju db (vrednosti iz .env)
  host: <%= ENV["APP_DATABASE_HOST"] %>
  port: <%= ENV.fetch("APP_DATABASE_PORT") { 5432 } %>
  username: <%= ENV["APP_DATABASE_USERNAME"] %>
  password: <%= ENV["APP_DATABASE_PASSWORD"] %>

development:
  <<: *default
  database: <%= ENV["APP_DATABASE"] %>

test:
  <<: *default
  database: <%= ENV["APP_DATABASE"] %>_test

Brez teh nastavitev se Rails poskuša povezati prek lokalnega socketa in javi PG::ConnectionBad: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed.

6. Dovoli web-console iz omrežja Docker

Brskalnik dostopa do aplikacije prek omrežja Docker (npr. 172.27.0.1), web-console pa privzeto dovoli le 127.0.0.1. V dnevniku se zato izpiše Cannot render console from 172.27.0.1!, konzola na strani z napako pa se ne prikaže. V config/environments/development.rb dodaj:

  # Dovoli web-console za zahteve iz omrežij Docker (privzeti bazeni naslovov).
  config.web_console.allowed_ips = %w[172.16.0.0/12 192.168.0.0/16]

7. Zaženi aplikacijo

docker compose up

Ob zagonu se samodejno izvede bin/rails db:prepare, ki ustvari bazo. Aplikacija je dosegljiva na http://localhost:3000.

8. Odkomentiraj namestitev gemov v Dockerfile

Ko obstajata Gemfile in Gemfile.lock, v Dockerfile odkomentiraj:

COPY --chown=app:app Gemfile Gemfile.lock ./
RUN bundle install

Ob gradnji slike se tako namestijo gemi, Docker pa to plast shrani v predpomnilnik.

Pogosti ukazi

Opravilo Ukaz
Zagon docker compose up
Zagon v ozadju docker compose up -d
Ustavitev docker compose down
Rails konzola docker compose run --rm app bin/rails console
Migracije docker compose run --rm app bin/rails db:migrate
Generator docker compose run --rm app bin/rails generate model Company name:string
Testi docker compose run --rm app bin/rails test
Lupina v kontejnerju docker compose run --rm app bash
Konzola PostgreSQL docker compose exec db psql -U <uporabnik> <baza>
Dnevnik docker compose logs -f app

Če aplikacija že teče (docker compose up), lahko namesto run --rm uporabiš exec, ki ukaz izvede v obstoječem kontejnerju.

Dodajanje gemov

docker compose run --rm app bundle add <ime_gema>

Po ročni spremembi Gemfile:

docker compose run --rm app bundle install

Volume bundle prekrije geme, nameščene ob gradnji slike. Po spremembi Gemfile zato vedno poženi bundle install v kontejnerju; samo ponovna gradnja slike ni dovolj.

Če potrebuješ Node.js

Privzeti Rails 8 projekt Node.js ne potrebuje: JavaScript se naloži prek importmap, sredstva obdela Propshaft. Tudi Tailwind (--css=tailwind) in Dart Sass (dartsass-rails) uporabljata samostojni izvršljivi datoteki brez npm.

Node.js je potreben, če pri rails new izbereš:

  • --javascript=esbuild, rollup ali webpack (jsbundling-rails),
  • --css=bootstrap, bulma, postcss ali sass (cssbundling-rails),

ali če uporabljaš knjižnice, ki jih je treba prevesti (npr. React z JSX).

Paket nodejs iz Debiana za to ne zadošča, ker ne vsebuje npm in je pogosto zastarel. Node.js raje prekopiraj iz uradne slike (pred vrstico USER app):

COPY --from=node:24-slim /usr/local/bin/node /usr/local/bin/
COPY --from=node:24-slim /usr/local/lib/node_modules /usr/local/lib/node_modules
RUN ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
 && ln -s /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx

Različico (24) izberi glede na aktualni LTS. Če potrebuješ yarn, dodaj še RUN npm install -g yarn (prav tako pred USER app).

Odpravljanje težav

Permission denied pri gem install ali bundle install Volume bundle je verjetno nastal s starejšo različico slike, ko je bila mapa v lasti uporabnika root. Odstrani ga in zgradi sliko znova:

docker compose down
docker volume ls                      # poišči <projekt>_bundle
docker volume rm <projekt>_bundle
docker compose build

could not translate host name "db" ali connection refused Preveri, da je v .env nastavljeno APP_DATABASE_HOST=db in da teče servis baze (docker compose ps, stanje healthy). Pri docker compose run Compose sicer počaka na healthcheck, pri ročnem zagonu servisa db pa PostgreSQL ob prvem zagonu potrebuje nekaj sekund za inicializacijo.

PG::ConnectionBad: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed Rails ne uporablja nastavitev iz .env in se poskuša povezati lokalno. Preveri config/database.yml (glej korak 5) in znova zaženi servis app (docker compose restart app).

Kontejner db se ustavi z Error: in 18+, these Docker images are configured to store database data in a format which is compatible with "pg_ctlcluster" Volume pgdata je priklopljen na /var/lib/postgresql/data, slika postgres od različice 18 naprej pa pričakuje /var/lib/postgresql. Popravi priklop v docker-compose.yml. Če so v volumnu podatki starejše glavne različice, jih nadgradi s pg_upgrade ali izvozi in uvozi, sicer volume izbriši (docker volume rm <projekt>_pgdata).

A server is already running Ostala je datoteka s PID-om strežnika:

rm tmp/pids/server.pid

Ponastavitev baze od začetka

docker compose down -v               # izbriše VSE volumne, tudi podatke v bazi

Opombe

  • Predloga je namenjena razvoju. Za produkcijo uporabi Dockerfile, ki ga ustvari rails new (brez --skip-docker), ali Kamal.
  • .env nikoli ne shranjuj v Git. V repozitorij gre samo .env.example.
S
Description
Predloga za razvoj Ruby on Rails v Dockerju: Ruby 4.0, PostgreSQL 18 in Docker Compose, brez lokalne namestitve Rubyja.
Readme
41 KiB
Languages
Dockerfile 100%