Splitting Up A Rails And React App Into Separate Docker Containers?

- 1 answer

I have an app with a Rails backend and a React frontend. I am deploying it in Docker containers: one for the app, one for postgres, and one as a data volume container. I have it working, but the app image file is huge (3Gb!) and takes a long time to build.

I'd love a way to split it up. The React app needs a bunch of Node packages, but only for development; once it's all webpack-ed the React app is essentially static files. And the Rails app doesn't need Node at all.

I don't need all the development-time tooling in the production image, but as it is, I feel like I need to have it all in the same codebase so I can (eventually) set up a CI/CD environment that can build the app and run all the tests. Is there a way to do this such that I'd have a container for the React/Node app and a container for Rails, and connect them at runtime?



I think that you may have found the answer to your question already - split the code bases.

We all have some kind of knee-jerk reflex to want to keep everything in a project in the same repo. It feels safe. Dealing with separate repos seems quite scary, but so does not moshing CSS and JS into HTML for most beginners.

I feel like I need to have it all in the same codebase so I can (eventually) set up a CI/CD environment that can build the app and run all the tests

Well that would be nice - however testing javascript through Ruby or automated browsers is painfully slow. You end up with a "fast" suite of unit tests and a slow "suite" of integration tests that take 15+ minutes.

So whats the alternative?

Your API and your SPA application (angular) actually do very different things.

The API takes HTTP requests and poops out JSON. It runs on a Ruby on Rails server and talks with a database and even other API's.

You would do integration tests of you API by sending HTTP requests and testing the response.

Your API should not really care if the request comes from a Fuzzle widget and renders a happy face or not. Its not the API's job.

RSpec.describe 'Pets API' do

  let!(:pet) { create(:pet) }
  let(:json) { JSON.parse(response.body) }

  describe 'GET /pets' do
    get '/pets'
    expect(json["name"]).to eq

The SPA server basically just needs to serve static HTML and just enough javascript to get stuff rolling.

A docker container seems almost overkill here - you just want a nginx server behind a reverse proxy or a load balancer as you're only serving up one thing.

You should have tests written in javascript that either mock out the API server or talk to a fake API server. If you really have to you could automate a browser and let it talk to test version of the API.

Your SPA will most likely have its own JS based toolkit and build process, and most importantly - its own test suite.

Of course this highly opinionated, but think about it - both projects will benefit from having their own infrastructure and a clear focus. Especially the API part which can end up really strange if you start building it around a user interface.