Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
*

!/assets/
!/bin/
!/config/
!/lib/
!/public/
!/script/console
!/script/server
!/views
!/.ruby-version
!/config.ru
!/Gemfile
!/Gemfile.lock
!/package.json
!/package-lock.json
!/postcss.config.js
!/Rakefile

/assets/builds/
/public/assets/
**/*.key
1 change: 1 addition & 0 deletions .node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24.15.0
78 changes: 78 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# syntax=docker/dockerfile:1
# check=error=true

# This Dockerfile is designed for production, not development. Use with Kamal or build'n'run by hand:
# docker build --tag dev-training-web --build-arg RUBY_VERSION="$(cat .ruby-version)" --build-arg NODE_VERSION=$(cat .node-version) --platform linux/amd64 .
# docker run --interactive --tty --publish 80:80 --env MASTER_KEY="$(cat config/dev-training-web.key)" dev-training-web

# Make sure RUBY_VERSION matches the Ruby version in .ruby-version
ARG RUBY_VERSION=OVERRIDE_ME
FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base

# App lives here
WORKDIR /app

# Install base packages
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl libjemalloc2 && \
ln -s /usr/lib/$(uname -m)-linux-gnu/libjemalloc.so.2 /usr/local/lib/libjemalloc.so && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Set production environment variables and enable jemalloc for reduced memory usage and latency
ENV RACK_ENV="production" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_ONLY="default production" \
NODE_ENV="production" \
LD_PRELOAD="/usr/local/lib/libjemalloc.so"


# Throw-away build stage to reduce size of final image
FROM base AS build

# Install packages needed to build gems
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Install JavaScript dependencies
ARG NODE_VERSION=OVERRIDE_ME
ENV PATH=/usr/local/node/bin:$PATH
RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
/tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
rm -rf /tmp/node-build-master

# Install application gems
COPY .ruby-version Gemfile Gemfile.lock ./

RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git

# Install node modules
COPY package.json package-lock.json ./
RUN npm ci

# Copy application code
COPY . .

# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
RUN ./bin/rake assets:precompile

RUN rm -rf node_modules


# Final stage for app image
FROM base

# Copy built artifacts: gems, application
COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --from=build /app /app

# Run and own only the runtime files as a non-root user for security
RUN groupadd --system --gid 1000 dev-training-web && \
useradd dev-training-web --uid 1000 --gid 1000 --create-home --shell /bin/bash && \
mkdir -p /app/log /app/tmp && chown -R dev-training-web:dev-training-web /app/log /app/tmp
USER 1000:1000

EXPOSE 80
CMD ["./bin/thrust", "./script/server", "--port=3000"]
16 changes: 10 additions & 6 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,8 @@ gem 'rake'
gem 'sinatra', require: 'sinatra/base'
gem 'tilt'

group :test do
gem 'faker'
gem 'rack-test', require: 'rack/test'
gem 'rspec'
gem 'rspec-html-matchers'
gem 'simplecov'
group :production do
gem 'thruster'
end

group :development do
Expand All @@ -44,3 +40,11 @@ group :development, :test do
gem 'debug'
gem 'dotenv'
end

group :test do
gem 'faker'
gem 'rack-test', require: 'rack/test'
gem 'rspec'
gem 'rspec-html-matchers'
gem 'simplecov'
end
9 changes: 9 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,10 @@ GEM
sysexits (1.2.0)
temple (0.10.4)
thor (1.5.0)
thruster (0.1.20)
thruster (0.1.20-arm64-darwin)
thruster (0.1.20-x86_64-darwin)
thruster (0.1.20-x86_64-linux)
tilt (2.7.0)
tsort (0.2.0)
tzinfo (2.0.6)
Expand Down Expand Up @@ -339,6 +343,7 @@ DEPENDENCIES
rubocop-rspec
simplecov
sinatra
thruster
tilt

CHECKSUMS
Expand Down Expand Up @@ -460,6 +465,10 @@ CHECKSUMS
sysexits (1.2.0) sha256=598241c4ae57baa403c125182dfdcc0d1ac4c0fb606dd47fbed57e4aaf795662
temple (0.10.4) sha256=b7a1e94b6f09038ab0b6e4fe0126996055da2c38bec53a8a336f075748fff72c
thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73
thruster (0.1.20) sha256=c05f2fbcae527bbe093a6e6d84fb12d9d680617e7c162325d9b97e8e9d4b5201
thruster (0.1.20-arm64-darwin) sha256=630cf8c273f562063b92ea5ccd7a721d7ba6130cc422c823727f4744f6d0770e
thruster (0.1.20-x86_64-darwin) sha256=4cc245f3ea2ad238b518ae3934048eade6cc2543bdcfef91a7f95f8194306432
thruster (0.1.20-x86_64-linux) sha256=d579f252bf67aee6ba6d957e48f566b72e019d7657ba2f267a5db1e4d91d2479
tilt (2.7.0) sha256=0d5b9ba69f6a36490c64b0eee9f6e9aad517e20dcc848800a06eb116f08c6ab3
tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f
tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
Expand Down
114 changes: 0 additions & 114 deletions bin/bundle

This file was deleted.

27 changes: 0 additions & 27 deletions bin/puma

This file was deleted.

15 changes: 1 addition & 14 deletions bin/rake
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,7 @@
# this file is here to facilitate running it.
#

require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)

bundle_binstub = File.expand_path("../bundle", __FILE__)

if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
load(bundle_binstub)
else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
end
end
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)

require "rubygems"
require "bundler/setup"
Expand Down
5 changes: 5 additions & 0 deletions bin/thrust
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env ruby
require "rubygems"
require "bundler/setup"

load Gem.bin_path("thruster", "thrust")
10 changes: 5 additions & 5 deletions lib/dev_training_application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,7 @@ class DevTrainingApplication < Sinatra::Base
set :session_secret, ApplicationSecrets.session_secret
set :haml, layout: :application

# :nocov:
configure :production do
set :static, false
end
# :nocov:
use Rack::Sendfile
set :asset_assembly, AssetAssembly.new
configure :development, :test do
use Propshaft::Server, settings.asset_assembly
Expand All @@ -52,6 +48,10 @@ class DevTrainingApplication < Sinatra::Base
request.env['rack.errors'] = settings.error_log
end

before '/public/assets/*' do
cache_control :public, :immutable, max_age: 31_536_000
end

helpers do
def asset_path(file) # :nodoc:
settings.asset_assembly.resolver.resolve(file) || raise(Propshaft::MissingAssetError, file)
Expand Down
13 changes: 2 additions & 11 deletions script/server
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
#!/usr/bin/env ruby
#!/usr/bin/env bash

# frozen_string_literal: true

require 'fileutils'

# path to your application root.
APP_ROOT = File.expand_path('..', __dir__)

FileUtils.chdir APP_ROOT do
system 'bin/puma config.ru'
end
bundle exec puma config.ru "$@"