Skip to content

Commit

Permalink
Deployment (#3)
Browse files Browse the repository at this point in the history
* prepare for deployment

* point database yml to database url

* add dummy url to dockerfile

* new db for prod instead of trying to share

* add default host

* turn mail sending on

* host needs to be set

* slightly different option

* setup sendgrid for emails

* setup mailgun instead

* finish setting up mailgun domain correctly with sandbox
  • Loading branch information
sharkby7e authored Oct 7, 2024
1 parent cbb5082 commit 9fa3b7d
Show file tree
Hide file tree
Showing 12 changed files with 170 additions and 23 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/fly-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/

name: Fly Deploy
on:
push:
branches:
- main
jobs:
deploy:
name: Deploy app
runs-on: ubuntu-latest
concurrency: deploy-group # optional: ensure only one action runs at a time
steps:
- uses: actions/checkout@v4
- uses: superfly/flyctl-actions/setup-flyctl@master
- run: flyctl deploy --remote-only
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
34 changes: 21 additions & 13 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,37 @@

# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.2.2
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
FROM ruby:$RUBY_VERSION-slim AS base

LABEL fly_launch_runtime="rails"

# Rails app lives here
WORKDIR /rails

# Set production environment
ENV RAILS_ENV="production" \
BUNDLE_DEPLOYMENT="1" \
ENV BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_WITHOUT="development"
BUNDLE_WITHOUT="development:test" \
RAILS_ENV="production" \
DATABASE_URL="dummy.url"

# Update gems and bundler
RUN gem update --system --no-document && \
gem install -N bundler


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

# Install packages needed to build gems
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential git libvips pkg-config
apt-get install --no-install-recommends -y build-essential git libpq-dev pkg-config

# Install application gems
COPY Gemfile Gemfile.lock ./
RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
bundle exec bootsnap precompile --gemfile
bundle exec bootsnap precompile --gemfile && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git

# Copy application code
COPY . .
Expand All @@ -42,17 +49,18 @@ FROM base

# Install packages needed for deployment
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl libsqlite3-0 libvips && \
apt-get install --no-install-recommends -y curl libsqlite3-0 postgresql-client && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Copy built artifacts: gems, application
COPY --from=build /usr/local/bundle /usr/local/bundle
COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --from=build /rails /rails

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

# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
Expand Down
5 changes: 5 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ gem 'bootsnap', require: false
gem 'devise', github: 'heartcombo/devise', ref: 'f8d1ea90bc3'
gem 'importmap-rails'
gem 'jbuilder'
gem 'mailgun-ruby', '~>1.2.14'
gem 'omniauth'
gem 'puma', '>= 5.0'
gem 'rails', '~> 7.1.4'
Expand Down Expand Up @@ -56,3 +57,7 @@ group :test do
end

gem 'tailwindcss-rails', '~> 2.7'

gem 'dockerfile-rails', '>= 1.6', group: :development

gem 'pg', '~> 1.5'
22 changes: 22 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ GEM
irb (~> 1.10)
reline (>= 0.3.8)
diff-lcs (1.5.1)
dockerfile-rails (1.6.22)
rails (>= 3.0.0)
domain_name (0.6.20240107)
drb (2.2.1)
erubi (1.13.0)
factory_bot (6.4.6)
Expand All @@ -140,6 +143,9 @@ GEM
globalid (1.2.1)
activesupport (>= 6.1)
hashie (5.0.0)
http-accept (1.7.0)
http-cookie (1.0.7)
domain_name (~> 0.5)
i18n (1.14.5)
concurrent-ruby (~> 1.0)
importmap-rails (2.0.1)
Expand Down Expand Up @@ -170,8 +176,14 @@ GEM
net-imap
net-pop
net-smtp
mailgun-ruby (1.2.14)
rest-client (>= 2.0.2)
marcel (1.0.4)
matrix (0.4.2)
mime-types (3.6.0)
logger
mime-types-data (~> 3.2015)
mime-types-data (3.2024.1001)
mini_mime (1.1.5)
minitest (5.25.1)
msgpack (1.7.2)
Expand All @@ -185,6 +197,7 @@ GEM
timeout
net-smtp (0.5.0)
net-protocol
netrc (0.11.0)
nio4r (2.7.3)
nokogiri (1.16.7-aarch64-linux)
racc (~> 1.4)
Expand All @@ -203,6 +216,7 @@ GEM
rack (>= 2.2.3)
rack-protection
orm_adapter (0.5.0)
pg (1.5.8)
psych (5.1.2)
stringio
public_suffix (6.0.1)
Expand Down Expand Up @@ -270,6 +284,11 @@ GEM
responders (3.1.1)
actionpack (>= 5.2)
railties (>= 5.2)
rest-client (2.1.0)
http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
rexml (3.3.6)
strscan
rspec-core (3.13.0)
Expand Down Expand Up @@ -375,12 +394,15 @@ DEPENDENCIES
capybara
debug
devise!
dockerfile-rails (>= 1.6)
factory_bot_rails
faker
importmap-rails
jbuilder
letter_opener
mailgun-ruby (~> 1.2.14)
omniauth
pg (~> 1.5)
puma (>= 5.0)
rails (~> 7.1.4)
rails_live_reload
Expand Down
2 changes: 1 addition & 1 deletion app/views/layouts/_header.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<%= link_to root_path do %>
<div class="flex flex-col text-xl font-bold italic text-amber-50">
<p>Hudson Valley</p>
<p>Tool Library</p>
<p>Tool Share</p>
</div>
<% end %>

Expand Down
5 changes: 3 additions & 2 deletions config/database.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ test:
database: storage/test.sqlite3

production:
<<: *default
database: storage/production.sqlite3
adapter: postgresql
url: <%= ENV.fetch("DATABASE_URL", 'fake') %>
encoding: unicode
7 changes: 7 additions & 0 deletions config/dockerfile.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# generated by dockerfile-rails

---
options:
label:
fly_launch_runtime: rails
postgresql: true
4 changes: 3 additions & 1 deletion config/environment.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

# Load the Rails application.
require_relative "application"
require_relative 'application'

# Initialize the Rails application.
Rails.application.initialize!
27 changes: 21 additions & 6 deletions config/environments/production.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
require "active_support/core_ext/integer/time"
# frozen_string_literal: true

require 'active_support/core_ext/integer/time'

Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
Expand All @@ -16,6 +18,19 @@
config.consider_all_requests_local = false
config.action_controller.perform_caching = true

# mail stuff
config.action_mailer.delivery_method = :mailgun
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.mailgun_settings = {
api_key: ENV.fetch('MAILGUN_API_KEY', ''),
domain: ENV.fetch('MAILGUN_DOMAIN', '')
# api_host: 'api.eu.mailgun.net' # Uncomment this line for EU region domains
# timeout: 20 # Default depends on rest-client, whose default is 60s. Added in 1.2.3.
}
config.action_mailer.default_options = { from: '[email protected]' }
config.action_mailer.default_url_options = { host: ENV.fetch('DEFAULT_HOST', '') }

# Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment
# key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files).
# config.require_master_key = true
Expand Down Expand Up @@ -52,17 +67,17 @@
config.force_ssl = true

# Log to STDOUT by default
config.logger = ActiveSupport::Logger.new(STDOUT)
.tap { |logger| logger.formatter = ::Logger::Formatter.new }
.then { |logger| ActiveSupport::TaggedLogging.new(logger) }
config.logger = ActiveSupport::Logger.new($stdout)
.tap { |logger| logger.formatter = ::Logger::Formatter.new }
.then { |logger| ActiveSupport::TaggedLogging.new(logger) }

# Prepend all log lines with the following tags.
config.log_tags = [ :request_id ]
config.log_tags = [:request_id]

# "info" includes generic and useful information about system operation, but avoids logging too much
# information to avoid inadvertent exposure of personally identifiable information (PII). If you
# want to log everything, set the level to "debug".
config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info")
config.log_level = ENV.fetch('RAILS_LOG_LEVEL', 'info')

# Use a different cache store in production.
# config.cache_store = :mem_cache_store
Expand Down
5 changes: 5 additions & 0 deletions config/initializers/mailgun.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

Mailgun.configure do |config|
config.api_key = ENV.fetch('MAILGUN_API_KEY', '')
end
49 changes: 49 additions & 0 deletions fly.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# fly.toml app configuration file generated for hvtl on 2024-10-06T18:28:19-04:00
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#

app = 'hvtl'
primary_region = 'ewr'
console_command = '/rails/bin/rails console'

[build]

[env]
DATABASE_URL = 'sqlite3:///data/production.sqlite3'

[[mounts]]
source = 'data'
destination = '/data'

[http_service]
internal_port = 3000
force_https = true
auto_stop_machines = 'stop'
auto_start_machines = true
min_machines_running = 0
processes = ['app']

[checks]
[checks.status]
port = 3000
type = 'http'
interval = '10s'
timeout = '2s'
grace_period = '5s'
method = 'GET'
path = '/up'
protocol = 'http'
tls_skip_verify = false

[checks.status.headers]
X-Forwarded-Proto = 'https'

[[vm]]
memory = '1gb'
cpu_kind = 'shared'
cpus = 1

[[statics]]
guest_path = '/rails/public'
url_prefix = '/'
15 changes: 15 additions & 0 deletions lib/tasks/fly.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

namespace :fly do
task :ssh do
sh 'fly ssh console --pty -C "sudo -iu rails"'
end

task :console do
sh 'fly ssh console --pty -C "/rails/bin/rails console"'
end

task :dbconsole do
sh 'fly ssh console --pty -C "/rails/bin/rails dbconsole"'
end
end

0 comments on commit 9fa3b7d

Please sign in to comment.