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.

Finance/Banking IdeasOrendaa wishlistTechnical Library IdeasAdaptor PatternDesign PatternsSoftware Design PrinciplesCaaS (Containers As A Service)DevOps NotesDocker Container RegistryDockerFaaS (Functions As A Service) - Serverless...IaaS (Infrastructure As A Service)KubernetesTerraformUsefulunixcommandsConcurrency vs ParallelismDistributed Service with GoDistributed System Learning NotesetcdMetrics, tracing, and loggingProtobufGoLang NotesGoLang ResourcesLearning from JPMakefileLinux NotesAanand Prasad - Creator of Fig/Docker composeMetaprogramming RubyRackDatabase SecuritySecuritySQL InjectionMVPMarket/Startup AnalysisBlue OceanHow to talk to your potential customers?How to work togetherBest way to Launch your startup (Again and Again)Business Process ModelJavascript NotesJavascript ToolsReactJSTypeScript NotesWeb APIs (Browser)Bon appétit!A note about catsTigersBackend DevelopmentBlog WishlistNotable websitesCI/CDHusky - Git commit hookConsistency is keyRedis NotesPostgresql NotesFunny / AmusingGit CLIGraphQL NotesJavascriptJSON Web Token (JWT)Move your body every dayUseful ToolsNot BehindLeslie LamportOpen AIPrivate-Public Key AuthProgramming LanguagesProject EulerRails credentialsRails Devise IntegrationRails Docker Issues and FixesRails-DockerRails NotesReproducible BuildsSemantic VersioningSoftware EngineeringSuccessChandan's TODOCraftman/EngineerYour first seed