Rails-Docker

Docker Notes

Run ruby code without installing Ruby

$> docker run [OPTIONS] <image> <command>
# This command starts a new container based on <image>, and executes <command> inside the container. 
# You may find it helpful to think about it in two parts: docker run [OPTIONS] <image> says what type 
# of container we’re going to run, whereas <command> says what we want to run inside the container.
$> docker run ruby:3.2.2 ruby -e "puts :hello"
hello

# Mount PWD in docker's  `/usr/src/app` volume `-v`, with `-i` input to `bash`, `--rm` for ephemeral/throwaway, 
# `-t` for pseudoterminal/pty
# whenever you need a long-lived, interactive session, you need to specify both the -i and -t options.
$> docker run -i -t --rm -v ${PWD}:/usr/src/app ruby:3.2.2 bash

Run multiple commands via docker run

$> docker run <options> [image:version] \
bash -c "command1 && command2 && command3..."

Dockerfile

# Install required image of Ruby
# Every Dockerfile start with "FROM" base image 
FROM ruby:3.2.2

# Download latest package information
# -y : Yes to any prompt, -qq : Really queit mode
RUN apt-get update -yqq
# install nodejs and DO NOT install other recommended packages as we don't need them
# NOTE: nodejs is NOT required with Rails 7
RUN apt-get install -yqq --no-install-recommends nodejs

# Copy the all files in current folder (.) i.e. Application root to `/usr/src/app`
COPY . /usr/src/app

# docker run [OPTIONS] <our custom image> bin/rails server
# This command will fail, because by default container's working directory is `/`
# which doesn't have our rails application. Our rails application is IN `/usr/src/app`
# Thus change the working directory with WORKDIR
WORKDIR /usr/src/app

# Now we can run any command with `RUN`
RUN bundle install
.dockerignore

Add unnecessary/sensitive files to .dockerignore to ensure it’s not added to docker image

Image build cache

Docker creates a cache of each step in Dockerfile. Any change in the file at line x, line x onwards will be built fresh. However, x- will be reusing docker cache. Adding non-relevant files to .dockerignore helps docker build run faster as cache will not be invalidated due to change in these files.

Best practices

Always:

  1. Combine apt-get update with apt-get install command, so that we’ve latest version of new packages. Because earlier RUN apt-get update -yqq was cached, so in next build, it won’t pull latest packages.
  2. list each package in new line in alphabetical order for easier search and maintenance ```shell RUN apt-get update -yqq && apt-get install -yqq –no-install-recommends \ nodejs
    vim

#### docker-compose.yml
```yaml
version: '3' # Version of docker-compose - https://docs.docker.com/compose/compose-file/compose-versioning/

services:

  web: # Service name
    build: . # build image from `Dockerfile` in current directory
    ports:
      - "3000:3000" # <host-machine-port>:<docker-container-service-port>
    volumes:
      - .:/usr/src/app # <host-directory>:<docker-container-directory> - Ensures our host machine current dir/code is sync with docker container, i.e. change in our app in host machine will immediately reflect on browser reload
  redis:
    image: redis

  database:
    image: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: root
      POSTGRES_DB: orendaa_development
docker-compose commands
$> docker-compose start
$> docker-compose start <service-name>
$> docker-compose stop
$> docker-compose stop <service-name>
$> docker-compose restart <service-name>
$> docker-compose up
$> docker-compose up <service-name>
Logs
# NOTE: This follows docker's log, not service(i.e. rails s) logs here
$> docker-compose logs -f web # -f means follow the logs from `web` service - similar to tail
$> docker-compose logs -f redis
Running one time commands

If the docker container is NOT running:

$> docker-compose run --rm web echo "I'm spinning up a container, run the echo and then deleting it, i.e. in ephemeral mode"

If the docker container is running:

$> docker-compose exec web echo "Since the web docker image is running , just execute echo on same"

Docker compose up/down

± ➜ docker compose up
[+] Building 0.0s (0/0)                                                                                                                                                     
[+] Running 2/2
 ✔ Network orendaa_default  Created                                                                                                                                    0.0s 
 ✔ Container orendaa-web-1  Created                                                                                                                                    0.0s 
Attaching to orendaa-web-1
orendaa-web-1  | => Booting Puma
orendaa-web-1  | => Rails 7.0.5 application starting in development 
orendaa-web-1  | => Run `bin/rails server --help` for more startup options
orendaa-web-1  | Puma starting in single mode...
orendaa-web-1  | * Puma version: 5.6.6 (ruby 3.2.2-p53) ("Birdie's Version")
orendaa-web-1  | *  Min threads: 5
orendaa-web-1  | *  Max threads: 5
orendaa-web-1  | *  Environment: development
orendaa-web-1  | *          PID: 1
orendaa-web-1  | * Listening on http://0.0.0.0:3000
orendaa-web-1  | Use Ctrl-C to stop
^CGracefully stopping... (press Ctrl+C again to force)
Aborting on container exit...
[+] Stopping 1/1
 ✔ Container orendaa-web-1  Stopped                                                                                                                                    0.4s 
canceled

chandan@~/Workspace/2023/orendaa (main_dockerize_app) ± ➜ docker-compose down
[+] Running 2/2
 ✔ Container orendaa-web-1  Removed                                                                                                                                    0.0s 
 ✔ Network orendaa_default  Removed 

Interact with redis container

$> docker-compose up -d redis # Run redis in detached mode
[+] Building 0.0s (0/0)                                                                                                                                                     
[+] Running 1/1
 ✔ Container orendaa-redis-1  Started   
$> docker-compose run --rm redis redis-cli -h redis # The option -h redis says, “Connect to the host named redis.”
[+] Building 0.0s (0/0)                                                                                                                                                     
[+] Building 0.0s (0/0)                                                                                                                                                     
redis:6379> ping
PONG
$> docker-compose stop redis
± ➜ docker-compose exec redis redis-cli -h redis 
service "redis" is not running container #1

± ➜ docker-compose up -d redis                      
[+] Building 0.0s (0/0)                                                                                                                                                     
[+] Running 1/1
 ✔ Container orendaa-redis-1  Started                                                                                                                                  0.3s 

± ➜ docker-compose exec redis redis-cli -h redis # The option -h redis says, “Connect to the host named redis.”
redis:6379> 

Interact with database container

Startup the database container and check it’s running

± ➜ docker-compose up -d database
[+] Running 14/1
 ✔ database 13 layers [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿]      0B/0B      Pulled                                                                                                          22.4s 
[+] Building 0.0s (0/0)                                                                                                                                                     
[+] Running 1/1
 ✔ Container orendaa-database-1  Started                                                                                                                               1.1s 

chandan@~/Workspace/2023/orendaa (main_dockerize_app) ± ➜ docker-compose ps            
NAME                 IMAGE               COMMAND                  SERVICE             CREATED             STATUS              PORTS
orendaa-database-1   postgres            "docker-entrypoint.s…"   database            6 seconds ago       Up 4 seconds        5432/tcp
orendaa-redis-1      redis               "docker-entrypoint.s…"   redis               About an hour ago   Up 38 minutes       6379/tcp
orendaa-web-1        orendaa-web         "bin/rails s -b 0.0.…"   web                 44 minutes ago      Up 38 minutes       0.0.0.0:3000->3000/tcp

Interact with postgres via CLI

± ➜ docker-compose run --rm database psql -U postgres -h database
[+] Building 0.0s (0/0)                                                                                                                                                     
[+] Building 0.0s (0/0)                                                                                                                                                     
Password for user postgres: 
psql (15.3 (Debian 15.3-1.pgdg120+1))
Type "help" for help.

postgres=# \l
                                                     List of databases
        Name         |  Owner   | Encoding |  Collate   |   Ctype    | ICU Locale | Locale Provider |   Access privileges   
---------------------+----------+----------+------------+------------+------------+-----------------+-----------------------
 orendaa_development | postgres | UTF8     | en_US.utf8 | en_US.utf8 |            | libc            | 
 postgres            | postgres | UTF8     | en_US.utf8 | en_US.utf8 |            | libc            | 
 template0           | postgres | UTF8     | en_US.utf8 | en_US.utf8 |            | libc            | =c/postgres          +
                     |          |          |            |            |            |                 | postgres=CTc/postgres
 template1           | postgres | UTF8     | en_US.utf8 | en_US.utf8 |            | libc            | =c/postgres          +
                     |          |          |            |            |            |                 | postgres=CTc/postgres
(4 rows)

postgres=# \du
                                   List of roles
 Role name |                         Attributes                         | Member of 
-----------+------------------------------------------------------------+-----------
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS | {}

postgres=# \q

Access rails console

$> docker-compose exec web rails console # Assuming container running
$> docker-compose run --rm  web rails console


Force recreate

  • Force recreate service(s)
    $> docker-compose up -d --force-recreate <service-name> 
    $> docker-compose up -d --force-recreate # Recreates all services and start them in detached mode
    

Connecting to PSQL/Redis terminal from docker

$> docker-compose run --rm <service-name> <command> -h <service-name>
$> docker-compose run --rm database psql -U postgres -h database
$> docker-compose run --rm redis redis-cli -h redis
Access the bash shell inside a service container
$> docker-compose run --rm <service-name> bash
$> docker-compose run --rm web bash 
Remove a service container
$> docker-compose rm -f <service-container-name>
$> docker-compose rm -f database
Inspect a volume

docker-compose.yml

version: '3'

services:

  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/usr/src/app
    env_file:
      - .docker/development/web
      - .docker/development/database # TODO - It has to be dynamic

  redis:
    image: redis

  database:
    image: postgres
    build:
      context: .
      dockerfile: Dockerfile-database
    env_file:
      - .docker/development/database
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:

Inspect the db_data volume:

$> docker volume inspect --format '' <app-name>_db_data || ls
$> docker volume inspect --format '' orendaa_db_data || ls
/var/lib/docker/volumes/orendaa_db_data/_data

Rails Notes Rails Docker

References:
  1. rails-development-environment-with-docker-compose
  2. Digital Ocean : containerizing-a-ruby-on-rails-application-for-development-with-docker-compose

This is a sapling 🌱 in my digital garden 🏡.

Notes mentioning this note


Here are all the notes in this garden, along with their links, visualized as a graph.