diff --git a/Dockerfile.prod b/Dockerfile.prod index cdcd251..ab7e7d4 100644 --- a/Dockerfile.prod +++ b/Dockerfile.prod @@ -1,51 +1,76 @@ -# syntax = docker/dockerfile:1 +# syntax=docker/dockerfile:1 +# check=error=true -# Make sure it matches the Ruby version in .ruby-version and Gemfile +# This Dockerfile is designed for production, not development. Use with Kamal or build'n'run by hand: +# docker build -t today . +# docker run -d -p 80:80 -e RAILS_MASTER_KEY= --name today today + +# For a containerized dev environment, see Dev Containers: https://guides.rubyonrails.org/getting_started_with_devcontainer.html + +# Make sure RUBY_VERSION matches the Ruby version in .ruby-version ARG RUBY_VERSION=3.4.7 -FROM ruby:$RUBY_VERSION-slim AS base +FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base # Rails app lives here WORKDIR /rails -# Set production environment +# Install base packages +RUN apt-get update -qq && \ + apt-get install --no-install-recommends -y curl libjemalloc2 libvips sqlite3 && \ + 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 RAILS_ENV="production" \ + BUNDLE_DEPLOYMENT="1" \ + BUNDLE_PATH="/usr/local/bundle" \ BUNDLE_WITHOUT="development" \ - SOLID_QUEUE_IN_PUMA="true" - + LD_PRELOAD="/usr/local/lib/libjemalloc.so" # Throw-away build stage to reduce size of final image FROM base AS build -# Install packages need to build gems +# Install packages needed to build gems RUN apt-get update -qq && \ - apt-get install -y build-essential git libyaml-dev + apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config && \ + rm -rf /var/lib/apt/lists /var/cache/apt/archives # Install application gems -COPY Gemfile Gemfile.lock ./ -RUN bundle install +COPY Gemfile Gemfile.lock vendor ./ + +RUN bundle install && \ + rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \ + # -j 1 disable parallel compilation to avoid a QEMU bug: https://github.com/rails/bootsnap/issues/495 + bundle exec bootsnap precompile -j 1 --gemfile # Copy application code COPY . . +# Precompile bootsnap code for faster boot times. +# -j 1 disable parallel compilation to avoid a QEMU bug: https://github.com/rails/bootsnap/issues/495 +RUN bundle exec bootsnap precompile -j 1 app/ lib/ + # Precompiling assets for production without requiring secret RAILS_MASTER_KEY RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile + + # Final stage for app image FROM base -RUN apt-get update -qq && \ - apt-get install --no-install-recommends -y curl vim && \ - rm -rf /var/lib/apt/lists /var/cache/apt/archives +# Run and own only the runtime files as a non-root user for security +RUN groupadd --system --gid 1000 rails && \ + useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash +USER 1000:1000 # Copy built artifacts: gems, application -COPY --from=build /usr/local/bundle /usr/local/bundle -COPY --from=build /rails /rails +COPY --chown=rails:rails --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}" +COPY --chown=rails:rails --from=build /rails /rails -ENV TZ=America/Denver # Entrypoint prepares the database. -ENTRYPOINT ["/rails/bin/docker-entrypoint"] +#ENTRYPOINT ["/rails/bin/docker-entrypoint"] -# Start the server by default, this can be overwritten at runtime -EXPOSE 3000 +# Start server via Thruster by default, this can be overwritten at runtime +EXPOSE 80 CMD ["./bin/rails", "server"] diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc index 837bee1..fc59b60 100644 --- a/config/credentials.yml.enc +++ b/config/credentials.yml.enc @@ -1 +1 @@ -BMFEDZ8EjyPIj2UxZ7E5uPo9BuHH04cp7hqAD3K90wd8JqJQqrrRodgNYkPRp3wLWmLdoSxpP87xsZaOOBgzaCbzV0MsBLd3WnT0ZdLTNxFRquZrV5a6htrK0Rk6Vc8No6nlrBDagv+P83pKmGYaACVuu8K1SK4Bs+xSqjHyfedtHluSozOhYOAccNnsTfAmrS0Qc3h4KZRV87zI/LvSQlTMqYyhFRiXIqaX2q0RunQEDFxjKkP1Jxox1s/WxNdt7U5/brJbsquALbXuTfrcZF5uN0tL8N9C6aDon7uB2dJ7qGBIRQZUEsGqhl94QYasBHzLkzZ3EzVBrcmAkxk5Wmlt81nDEBuGA5kgTsa3jTDCwyjy7/beXK1EySL+luWlO7ZOqx8Djtj8fbVwIGrrHrrmIdrfjP40buSO/5ysJMpIiueHhx9egjfr0tbHQDIQvQfpPY9U5CfiNhSWbWxQ7rviGAKrarfaqyQq3/W3oa8vnLgBlD92PEAShWYCko2GbWRNuoYvT0oZtCtxYYHM7EvtwJ85q483OgtEZyskXA2XLTN1WWA7weW/HPm8D48ZS6sEtavUCTlCmxzXQoKgOSWdULlNJsGkUT2kWWwlTiSNBe8H0/dGinWVjJjHnTQAmaFSU0GXlxPUuhGhZOauCodv54fvacQPWT/1QFRlWTHvpNf6BR5f3+wVZqlA5TmxVh833pyhJkdDysVYgWk=--4UN56E53YvkUOMIc--bJQMYy7lcTFIXFsD6iaD9Q== \ No newline at end of file +jYH1BpY8mSBfQEcsAjd5sufEhNNSQFb3h88zb/yy4CyDGAMh7E0/7AiJUdxOgfsxrtgG85vS88CXUOKdKbIT8Fss0kPF2pBev+SnA6iIKyxNty4qEv92T9yHjI91jsqj6BofKBd8RGG6ce3gVT1yuO685NnlQrFDBjIQOg2oNnIEEksV2Gr483/7zl8nF3IAmnL0KE8J4P3nnbMnQgYcycBAB5FehsmDj2eh8pgwb6jFwkXlkg73iML4A84Wm7wFLIDMIc4zL9FGFSTQqpxsKUzXyFlcUwfTj83RqvpY3h1Zkh23dhO5S5xM6n8Q/VYFlf8nD30ZA7BlJGkPR3W2yYNAfFoaVUEBnBVoEZWP4POWRnVcrkZgEOcRkcerr9CabU9RaVdbQXfQxReD5HvCQg2T6LgiCXsbV42ghwOnDZE2/HAAUV9fEULmvvWyIMRziNnnjYPcX1g5MdX1IL7A+t8XA2XPBgjKtQ6afnWb6bGE3w1ud4o8o517B+4MbHo6+6gOtpVzvO/vGQYadAadrl35/3+ZMBPVzNpZalbBDJ3Sxw7w+bnv3Q7ftRV+03lYfZeBe0HJL/2BBfXJMMIw8zR8D0S/pvHXRPiqi9dax2qluqKrpOOiM7Cq7X3pb+Z4Gd1S/UraqNJIk1fSQ6GW37qzgAghcNXVZOXp/q0gVaMgsZ0FN7fx5BZhf0MnzJenx0gWJxL0tvKKJcHuKkvM9dOpGJ2a0TRjvrLXACfHaimCTYcaMjuo6aHmOKRquPhEpByTrBXTeV3mxegzYdIKTsXl+qhSB4f3i9FnrA==--ec2oW2lu4n1aPii/--vjxJ5dHXtOoAneRDfjdCRw== \ No newline at end of file diff --git a/config/deploy.yml b/config/deploy.yml index 744440e..8cc6570 100644 --- a/config/deploy.yml +++ b/config/deploy.yml @@ -1,37 +1,109 @@ -service: sum-dev -image: travisdock/sum-dev +# Name of your application. Used to uniquely configure containers. +service: sum -servers: - - 143.198.160.36 +# Name of the container image. +image: travisdock/sum -ssh: - user: 'root' - keys: ["/home/user/.ssh/id_ed25519"] +# Deploy to these servers. +servers: + web: + - 64.23.239.243 + #job: + # hosts: + # - 64.23.239.243 + # cmd: bin/jobs +# Enable SSL auto certification via Let's Encrypt and allow for multiple apps on a single web server. +# Remove this section when using multiple web servers and ensure you terminate SSL at your load balancer. +# +# Note: If using Cloudflare, set encryption mode in SSL/TLS setting to "Full" to enable CF-to-app encryption. proxy: ssl: true - host: dev.sum-finance.com + host: sum-finance.com + # Proxy connects to your container on port 80 by default. app_port: 3000 +# Credentials for your image host. +registry: + server: localhost:5555 + # Specify the registry server, if you're not using Docker Hub + # server: registry.digitalocean.com / ghcr.io / ... + # username: my-user + + # Always use an access token rather than real password (pulled from .kamal/secrets). + # password: + # - KAMAL_REGISTRY_PASSWORD + +# Configure builder setup. builder: arch: amd64 dockerfile: Dockerfile.prod + # Pass in additional build args needed for your Dockerfile. + # args: + # RUBY_VERSION: <%= ENV["RBENV_VERSION"] || ENV["rvm_ruby_string"] || "#{RUBY_ENGINE}-#{RUBY_ENGINE_VERSION}" %> -registry: - username: travisdock - password: - - KAMAL_REGISTRY_PASSWORD - +# Inject ENV variables into containers (secrets come from .kamal/secrets). +# env: secret: - - SECRET_KEY_BASE - RAILS_MASTER_KEY + - HONEYBADGER_API_KEY clear: SOLID_QUEUE_IN_PUMA: true +# env: +# clear: +# DB_HOST: 192.168.0.2 +# secret: +# - RAILS_MASTER_KEY + +# Aliases are triggered with "bin/kamal ". You can overwrite arguments on invocation: +# "bin/kamal app logs -r job" will tail logs from the first server in the job section. +# +# aliases: +# shell: app exec --interactive --reuse "bash" + +# Use a different ssh user than root +# +# ssh: +# user: app +# Use a persistent storage volume. +# volumes: - - "/app_storage/sum-dev:/rails/storage" + - "/app_storage:/rails/storage" -asset_path: /rails/public/assets +# Bridge fingerprinted assets, like JS and CSS, between versions to avoid +# hitting 404 on in-flight requests. Combines all files from new and old +# version inside the asset_path. +# +# asset_path: /app/public/assets +# Configure rolling deploys by setting a wait time between batches of restarts. +# +# boot: +# limit: 10 # Can also specify as a percentage of total hosts, such as "25%" +# wait: 2 +# Use accessory services (secrets come from .kamal/secrets). +# +# accessories: +# db: +# image: mysql:8.0 +# host: 192.168.0.2 +# port: 3306 +# env: +# clear: +# MYSQL_ROOT_HOST: '%' +# secret: +# - MYSQL_ROOT_PASSWORD +# files: +# - config/mysql/production.cnf:/etc/mysql/my.cnf +# - db/production.sql:/docker-entrypoint-initdb.d/setup.sql +# directories: +# - data:/var/lib/mysql +# redis: +# image: valkey/valkey:8 +# host: 192.168.0.2 +# port: 6379 +# directories: +# - data:/data