Skip to content

Latest commit

 

History

History
102 lines (74 loc) · 5.44 KB

2021-03-14-docker-devcontainer-series-docker-compose.markdown

File metadata and controls

102 lines (74 loc) · 5.44 KB
layout title excerpt tags
post
Using containers as a Rails development environment, part 4: Composing services
Before integrating additional services into a container-based development environment, we need to start thinking about the app as a collection of services. Here's how to begin that process.
docker legacy

In my notes on my previous experiment, I demonstrated that SQLite can be integrated into a Rails development container with minimal fuss. However, other common database engines do require some extra effort to integrate. It's not uncommon to run multiple services in a container-based development environment—for example, a database, a background job processor, and the actual application software being developed.

To make this all work, I'll need to break out of some of the default settings provided by Visual Studio Code's Remote-Container extension. So I'll do that in this article: A relatively quick refactor the configuration to use Docker Compose, so it'll be ready for additional services in future experiments. This experiment will be on the shorter side, but it will set up more complex additions to the setup going forward.

This post is part of my ongoing series of experiments on seeking developer happiness through Rails, Docker, and Visual Studio Code's Remote-Container feature. You may find background information from earlier posts useful here.

Making the change easy

Right now, .devcontainer/devcontainer.json does a lot of the lifting for our development container. The interesting part for this experiment is the build key:

{% highlight json %} { "name": "my-app", "build": { "dockerfile": "Dockerfile", "args": { // Update 'VARIANT' to pick a Ruby version: 2, 2.7, 2.6, 2.5 "VARIANT": "2.5", "NODE_VERSION": "lts/*" } }, // ... } {% endhighlight %}

For more complicated builds, VS Code supports integrating Docker Compose. Here's what my first pass looks like. Note that it sits inside the .devcontainer directory, to communicate that it's specific to development environments.

{% highlight yml %} version: '3'

services: my-app: user: vscode

build:
  context: ..
  dockerfile: .devcontainer/Dockerfile
  args:
    # Update 'VARIANT' to pick a Ruby version: 2, 2.7, 2.6, 2.5
    VARIANT: 2.6
    NODE_VERSION: lts/*

volumes:
  - ..:/workspace

# don't shut down after the process ends
command: sleep infinity

{% endhighlight %}

This may look familiar if you've worked with Docker in the past:

  • The file defines a service called my-app (for illustration purposes only here; name it something that makes sense to you).
  • Actions inside the container will be performed by the vscode user to match VS Code's defaults.
  • The build context is one directory up from the location of .devcontainer/docker-compose.yml, or the root of the Rails application.
  • Use the Dockerfile that's already in place for the development container.
  • Apply args that were previously set in devcontainer.json for Ruby and Node versions.
  • Map the local path to the Rails app (..) to the /workspace volume in the container, so edits made in the application code will be reflected within the container.
  • Use command to keep the container running after it's spun up. My understanding is this is is necessary for Remote-Container to be able to shell into the container via the VS Code terminal. My understanding is fuzzy and could be wrong.

Now, I can replace build in .devcontainer/devcontainer.json to use the new Docker Compose setup:

{% highlight json %} { "name": "my-app", "dockerComposeFile": "docker-compose.yml", "service": "my-app", "workspaceFolder": "/workspace", // ... } {% endhighlight %}

Here's a rundown of the new keys:

  • dockerComposeFile is the file created earlier, the one inside .devcontainer.
  • service is the service that VS Code will shell into. This value needs to match the Rails app's service name in the Docker Compose file.
  • workspaceFolder tells VS Code and Remote-Container where to mount the Rails application inside the VS Code terminal. The end result will be slightly different than what was in place before (/workspace vs. /workspace/my-app), but seems to work fine.

With this change, I can rebuild the dev container, and aside from workspaceFolder being a little different in my terminal prompt, I'm back in business!

Summary

People who work with me know I love Kent Beck's summation of refactoring: "for each desired change, make the change easy (warning: this may be hard), then make the easy change."

In this experiment, making the change easy didn't turn out to be that hard, but I'm hoping it'll still make the changes (additional functionality in the development container) relatively easy.

And thinking a little longer-term, will this change make breaking out of Visual Studio Code at some point easier? Time will tell. That's what's cool about treating all of this as an experiment!

Next steps

Okay, with this change in place, I'm ready to really, really get Postgres or MySQL wired in (or Redis, for that matter), and will start on that next unless I find another yak to shave. Thanks for reading, and see you in the next post.