<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: JaafarMehdi</title>
    <description>The latest articles on DEV Community by JaafarMehdi (@jaafarmehdi).</description>
    <link>https://dev.to/jaafarmehdi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F169577%2F1e21f24d-7334-4e19-a49f-979d50966970.png</url>
      <title>DEV Community: JaafarMehdi</title>
      <link>https://dev.to/jaafarmehdi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jaafarmehdi"/>
    <language>en</language>
    <item>
      <title>Using Docker for Rails development</title>
      <dc:creator>JaafarMehdi</dc:creator>
      <pubDate>Tue, 14 Mar 2023 09:32:27 +0000</pubDate>
      <link>https://dev.to/2nit/using-docker-for-rails-development-1928</link>
      <guid>https://dev.to/2nit/using-docker-for-rails-development-1928</guid>
      <description>&lt;p&gt;Recently I got assigned to an old project and while luckily it had instructions on how to set it up locally in the Read.me the number of steps was damn too high. So instead of wasting half a day executing them, I wasted 2 days automating them (future devs will thank me… maybe).&lt;br&gt;
I wanted to get as close as possible to a one command local env setup.&lt;/p&gt;

&lt;p&gt;To simplify the process as you have guessed from the title of the article I decided to set up docker and docker-compose. I started with an example config from awesome-compose. &lt;/p&gt;
&lt;h2&gt;
  
  
  Level 0: just get the app to run on docker
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM ruby:2.6.5


WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install


COPY . /myapp
COPY config/database.yml.example /myapp/config/database.yml


CMD bundle exec rails s -p 8080 -b '0.0.0.0'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I won’t enter into details too much the main concept is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;first, copy just the gemfiles and install gems (this is done to take advantage of the caching mechanism in building images to speed up rebuilding)&lt;/li&gt;
&lt;li&gt;copy the rest of the app code&lt;/li&gt;
&lt;li&gt;create a config file for the database based on a template (the details will be passed through ENV variables)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since this time the goal is local developments assets compilation is not an issue we want to optimize.&lt;/p&gt;

&lt;p&gt;Next, the maestro orchestrating the local env: docker-compose&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: password
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid &amp;amp;&amp;amp; bundle exec rails s -p 3000 -b '0.0.0.0'"
    ports:
      - "3000:3000"
    environment:
      POSTGRES_HOST: db
      REDIS_URL: redis://redis
      REDIS_HOST: redis
    depends_on:
      - db
      - redis
  redis:
    image: 'redis:5-alpine'
    command: redis-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of it is thanks to the help of awesome-compose&lt;br&gt;
What we want to achieve here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run our app alongside a postgres database and a redis server&lt;/li&gt;
&lt;li&gt;Have the postgres database data persist&lt;/li&gt;
&lt;li&gt;Use env variables to pass the component names for routing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a warning note: avoid mapping any port that’s not necessary. So no mapping of 3456:3456 for postgres db. While it’s not an issue for local dev if you use a similar config on a production server it could open you to some brute-force attacks.&lt;/p&gt;

&lt;p&gt;The odd thing: you may have noticed that we have both a REDIS_URL and a REDIS_HOST env. It’s because the default redis cache use requires the url param to have the protocol redis:// at the beginning, but our app also uses redis_store for session_store which requires just the host without the protocol. Chances are you don’t use redis_store and can safely remove the unnecessary env.&lt;/p&gt;
&lt;h2&gt;
  
  
  Level 1: add some dev quality-of-life configs
&lt;/h2&gt;

&lt;p&gt;So this config was enough for me to get rolling and work on the project and contribute but it’s not the most comfortable thing due to a couple of issues:&lt;/p&gt;

&lt;p&gt;Any change to the code required turning off the docker-compose instances, rebuilding and turning the infrastructure on again and that adds up.&lt;br&gt;
I can't use binding.pry do debug&lt;/p&gt;

&lt;p&gt;So to be able to cut on the restarts necessary and auto update code we will use volumes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  web:
    build: .
    volumes:
      - .:/myapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding a volume will mirror the current dir to the app dir in the image will automatically mirror any change we make to the code. While this won't help with changes to config files it will handle most changes in real-time (Assuming we run on typical dev env configs)&lt;/p&gt;

&lt;p&gt;To enable access to binding.pry you need to add the following to the web service&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  web:
    build: .
    volumes:
      - .:/myapp
    tty: true # for binding.pry
    stdin_open: true # for binding.pry
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But adding this won’t allow us to just access the debug console from the console used to run docker-compose we will need to find the id of the web process and connect to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker ps
 docker attach 75cde1ab8133
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Level 2: add some reusability and sidekiq
&lt;/h2&gt;

&lt;p&gt;One last thing missing now in my case was the possibility to also run sidekiq. It was not necessary in the beginning but once the development went on we needed to work on some async tasks to handle long data import processes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x-my-app: &amp;amp;my_app
 build: .
 volumes:
   - .:/myapp
 environment:
   POSTGRES_HOST: db
   REDIS_URL: redis://redis
   REDIS_HOST: redis
 depends_on:
   - db
   - redis
 tty: true # for binding.pry
 stdin_open: true # for binding.pry


services:
 db:
   image: postgres
   volumes:
     - ./tmp/db:/var/lib/postgresql/data
   environment:
     POSTGRES_PASSWORD: password
 web:
   &amp;lt;&amp;lt;: *my_app
   command: bash -c "rm -f tmp/pids/server.pid &amp;amp;&amp;amp; bundle exec rails s -p 3000 -b '0.0.0.0'"
   ports:
     - "3000:3000"
 sidekiq:
   &amp;lt;&amp;lt;: *my_app
   command: 'sidekiq -L ./log/sidekiq.log -C ./config/sidekiq-dev.yml -P tmp/pids/sidekiq.pid'
 redis:
   image: 'redis:5-alpine'
   command: redis-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So as you can see before starting to define services we created a block that will contain all the common configs between the rails app and the sidekiq process containers. The only differences are the command and the ports since sidekiq doesn't need any open and we can’t have 2 containers trying to occupy the same port anyway.&lt;/p&gt;

&lt;p&gt;And with this addition, I’d consider the docker config done for this project. While it still requires more than one command to setup initially with the database creation/migration/seeding it’s a step requiring additional scripting on top of docker-compose. Maybe for another article.&lt;br&gt;
The commands toolbox&lt;/p&gt;

&lt;p&gt;As a parting note i’d like to list the docker command i found myself using most often:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;docker-compose up --build  // start the app&lt;/li&gt;
&lt;li&gt;docker-compose down // stop it if running in the background&lt;/li&gt;
&lt;li&gt;docker-compose ps // check the status of currently running images&lt;/li&gt;
&lt;li&gt;docker-compose run web bash // run commands&lt;/li&gt;
&lt;li&gt;docker images // show list of built images&lt;/li&gt;
&lt;li&gt;docker image prune // delete unused images since they can take up a lot of hard drive&lt;/li&gt;
&lt;li&gt;docker ps / docker kill // if docker-compose not doing the job&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tip: you may consider creating an alias for docker-compose to avoid typing it every time.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>rails</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Docker on Rails?</title>
      <dc:creator>JaafarMehdi</dc:creator>
      <pubDate>Wed, 22 May 2019 13:34:46 +0000</pubDate>
      <link>https://dev.to/2nit/how-to-docker-on-rails-5h2d</link>
      <guid>https://dev.to/2nit/how-to-docker-on-rails-5h2d</guid>
      <description>&lt;p&gt;One of the most interesting thing in starting a new project is the possibility to learn new things. For the last year, I had the occasion to work on the ops side of running an app and not just limit myself to the backend programming. It was the occasion to learn more about docker and also aws services and kubernetes. Now I want to share a bit of what I would have wanted to know as a series of articles. The first one will be about running a rails app in docker.&lt;/p&gt;

&lt;h2&gt;
  
  
  I. the starting point
&lt;/h2&gt;

&lt;p&gt;I know you are probably like "Show me your dockerfile already" so here it is.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bV_pQZBA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ecwnbwyjidbdn6ed5z2g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bV_pQZBA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ecwnbwyjidbdn6ed5z2g.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now I'll explain briefly the steps described above:&lt;/p&gt;

&lt;p&gt;1.1 The first step is the base image you will use. While you can build a docker image from scratch by yourself it's easier to start from a prebuilt image containing most of the needed tools. In our case, we start from the official ruby image that comes with ruby and bundler preinstalled.&lt;/p&gt;

&lt;p&gt;1.2 Install the system libraries required for the gems you will use. We will clean the downloaded packages after that to have a lighter image that's easier to upload.&lt;/p&gt;

&lt;p&gt;1.3 Prepare a place for your code&lt;/p&gt;

&lt;p&gt;1.4 Copy your application's code. The first param to the copy command is the location of the code you want to have in your docker image, the second one is where do you want it on the image's file system.&lt;/p&gt;

&lt;p&gt;1.5 Install any gems required to run your application.&lt;/p&gt;

&lt;p&gt;1.6 Define the command that will be executed when you run the docker image. In the case of a rails app it will be rails s. Note unlike the previous steps this command will  be executed when running the image not when building it.&lt;/p&gt;

&lt;p&gt;Now we can test it by using the command : &lt;strong&gt;docker build&lt;/strong&gt; .&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IfSoPNEF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/yj3xh4gxyl5s1g52jres.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IfSoPNEF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/yj3xh4gxyl5s1g52jres.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I cut a bit the logs in step 6 to save space.&lt;/p&gt;

&lt;p&gt;Note how every command in the dockerfile result in a step. The result of each step is cached so the next builds will be faster. If let say you change your code but no new general library is defined in the dockerfile the new build will reuse the cached versions for steps 1 to 4.&lt;/p&gt;

&lt;p&gt;You can check if the image was built successfully by using the command: &lt;strong&gt;docker images&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nIl9TSzF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ww4rathqh7viunp08036.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nIl9TSzF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ww4rathqh7viunp08036.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since we built the image without passing any extra params the name and tag of the resulting image is none. The most important info to us is image id that will be useful to run the image.&lt;/p&gt;

&lt;p&gt;Now that you have the image id you can also run it: &lt;strong&gt;docker run -p 8000:80 e33b3d9250ff&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The -p param will map the ports. the first one is the port from which you want to be able to access your container, the second one should be the one set in the dockerfile (Check the -p argument in the CMD command at the end). You can now access the rails application on &lt;em&gt;localhost:8000&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  II. the next step
&lt;/h2&gt;

&lt;p&gt;The simple flow described in the previous part is enough to run your application but if you need to build often we can optimize it a bit.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. bundle install
&lt;/h3&gt;

&lt;p&gt;One of the most time-consuming steps is gem installation and it's executed with even the smallest change made to the codebase of the application. But we can use the step caching I mentioned before to help us avoid it when it's not necessary.&lt;/p&gt;

&lt;p&gt;To achieve this we will first copy just the gemfile of the app and install it and then copy the rest of the files. This way if no changes to the gemfile were made we won't need to reinstall the gems.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Assets
&lt;/h3&gt;

&lt;p&gt;When hosting the website in production you may need to also generate assets. we will add this step also. This will recompile assets with each build which is okay for now.&lt;/p&gt;

&lt;p&gt;So this is the final dockerfile:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wafQ2EPH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ykbhjg4xk8rqdhj0aymv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wafQ2EPH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ykbhjg4xk8rqdhj0aymv.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading!:)&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pxjNHL2m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/abqcl2eqj16i0towp9cb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pxjNHL2m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/abqcl2eqj16i0towp9cb.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>rails</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
