Skip to content

Instantly share code, notes, and snippets.

@sephraim
Last active August 15, 2023 21:17
Show Gist options
  • Save sephraim/4e19a54faacca3ab1c80f8a4a51387f1 to your computer and use it in GitHub Desktop.
Save sephraim/4e19a54faacca3ab1c80f8a4a51387f1 to your computer and use it in GitHub Desktop.
[Docker setup for Ruby gem development]

Example commands

Start a bash session

docker compose build && docker compose run client bash

Run tests

docker compose build && docker compose run client rspec
// FILE: .devcontainer/devcontainer.json
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-docker-compose
{
"name": "my-cool-gem",
// Update the 'dockerComposeFile' list if you have more compose files or use different names.
// The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
"dockerComposeFile": [
// "../docker-compose.yml"
"docker-compose.yml"
],
// The 'service' property is the name of the service for the container that VS Code should
// use. Update this value and .devcontainer/docker-compose.yml to the real service name.
"service": "app",
// The optional 'workspaceFolder' property is the path VS Code should open by default when
// connected. This is typically a file mount in .devcontainer/docker-compose.yml
// "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
"workspaceFolder": "/app",
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Uncomment the next line if you want start specific services in your Docker Compose config.
// "runServices": [],
// Uncomment the next line if you want to keep your containers running after VS Code shuts down.
// "shutdownAction": "none",
// Uncomment the next line to run commands (on the host machine) before the container is created.
"initializeCommand": "docker compose build",
// Uncomment the next line to run commands when the container is created.
// "onCreateCommand": "gem install debug solargraph", // put these gems in your Gemfile if you can
// Uncomment the next line to run commands after the container is created.
// "postCreateCommand": "cat /etc/os-release",
// Configure tool-specific properties.
"customizations": {
"vscode": {
"extensions": [
"kaiwood.endwise", // Endwise
"bung87.vscode-gemfile" // Gemfile syntax highlighting
"sevenc-nanashi.gemfile-lock-highlight", // Gemfile.lock syntax highlighting
"rebornix.ruby", // Ruby syntax highlighting
"wingrunr21.vscode-ruby", // Ruby syntax highlighting
"bung87.rails", // Rails syntax highlighting
"jemmyw.rails-fast-nav", // Rails fast navigation
"sianglim.slim", // Slim syntax highlighting
"castwide.solargraph", // Solargraph - Ruby language server + intellisense
]
}
}
// Uncomment to connect as an existing user other than the container default. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "devcontainer"
}
# FILE: .devcontainer/docker-compose.yml
# NOTE This will take precedence over docker-compose.yml in the project root
services:
# Update this to the name of the service you want to work with in your docker-compose.yml file
app:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
image: &image my-cool-gem
container_name: *image
env_file: ../.env
environment:
- SOLARGRAPH_GLOBAL_CONFIG=/root/.config/solargraph/config.yml
- SOLARGRAPH_CACHE=/root/.cache/solargraph
volumes:
- ..:/app
- /app/pkg # don't mount the pkg directory, it will be created by the build
- ${HOME}/.config:/root/.config # mount local config, specifically for solargraph
- ${HOME}/.cache:/root/.cache # mount local cache, specifically for solargraph
command: ["tail", "-f", "/dev/null"]
# Uncomment if you want to override the service's Dockerfile to one in the .devcontainer
# folder. Note that the path of the Dockerfile and context is relative to the *primary*
# docker-compose.yml file (the first in the devcontainer.json "dockerComposeFile"
# array). The sample below assumes your primary file is in the root of your project.
#
# build:
# context: .
# dockerfile: .devcontainer/Dockerfile
# volumes:
# # Update this to wherever you want VS Code to mount the folder of your project
# - ..:/workspaces:cached
# Uncomment the next four lines if you will use a ptrace-based debugger like C++, Go, and Rust.
# cap_add:
# - SYS_PTRACE
# security_opt:
# - seccomp:unconfined
# Overrides default command so things don't shut down after the process ends.
# command: /bin/sh -c "while sleep 1000; do :; done"
# FILE: docker-compose.yml (in the project root)
# NOTE: If you're using .devcontainer/docker-compose.yml then this won't be necessary
services:
app:
build: .
image: &image my-cool-gem
container_name: *image
env_file: .env
volumes:
- .:/app
- /app/pkg # don't mount the pkg directory, it will be created by the build
command: ["tail", "-f", "/dev/null"]
# FILE: Dockerfile (in the project root)
# NOTE: If you're using .devcontainer/Dockerfile then this won't be necessary
# STAGE 1: Initial setup
FROM ruby:2.6.6 as base
WORKDIR /app
# Install missing package(s)
RUN apt-get update -qq && apt-get install -yq --no-install-recommends \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Prep for gem installation
# NOTE: The following `gem update` command is necessary to avoid a RubyGems warning
# You can keep it, but it's probably not necessary for newer versions of Ruby
RUN gem update --system && gem install bundler
# STAGE 2: Install gems
# NOTE: Copy *only* the files you absolutely need for this stage, otherwise caching will become useless
FROM base as gems
COPY Gemfile Gemfile.lock *.gemspec ./
COPY lib/path/to/version.rb lib/path/to/version.rb
RUN bundle update --bundler && bundle install
# STAGE 3: Copy gems & project files and build gem executable
FROM base as final
COPY --from=gems /usr/local/bundle /usr/local/bundle
# NOTE: The following files are required for gem release and should match whatever is in the .gemspec (besides the Rakefile)
COPY Gemfile Gemfile.lock *.gemspec Rakefile ./
COPY bin bin
COPY exe exe
COPY lib lib
# Install the automation-client CLI
RUN bundle exec rake install
# Alternatively, you can run:
# RUN gem build *.gemspec && gem install *.gem
# Keep container running
CMD ["tail", "-f", "/dev/null"]
# FILE: .devcontainer/Dockerfile
# NOTE This will take precedence over Dockerfile in the project root
# STAGE 1: Initial setup
FROM ruby:3.2.1 as base
WORKDIR /app
# Install missing package(s)
RUN apt-get update -qq && apt-get install -yq --no-install-recommends \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Prep for gem installation
# NOTE: The following `gem update` command is necessary to avoid a RubyGems warning
# You can keep it, but it's probably not necessary for newer versions of Ruby
RUN gem update --system && gem install bundler
# STAGE 2: Install gems
# NOTE: Copy *only* the files you absolutely need for this stage, otherwise caching will become useless
FROM base as gems
COPY Gemfile Gemfile.lock ../*.gemspec ./
COPY lib/path/to/version.rb lib/path/to/version.rb
RUN bundle update --bundler && bundle install
# Install development gems for debugging/documentation
RUN gem install debug solargraph
# STAGE 3: Copy gems & project files and build gem executable
FROM base as final
COPY --from=gems /usr/local/bundle /usr/local/bundle
COPY .. /app
# Install the automation-client CLI
RUN bundle exec rake install
# Alternatively, you can run:
# RUN gem build *.gemspec && gem install *.gem
# Keep container running
CMD ["tail", "-f", "/dev/null"]
# Specify which files should be added to the gem when it is released
# NOTE: This should match whatever is added in Stage 3 of the Dockerfile (besides the Rakefile, which isn't necessary for release)
spec.files = Dir.glob("{bin,exe,lib}/**/*") + Dir.glob("*.gemspec") + ["Gemfile", "Gemfile.lock"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment