Create testbed to test beamer scenarios in Fizzy
This commit is contained in:
@@ -61,6 +61,7 @@ RUN apt-get update -qq && \
|
||||
COPY --from=build /usr/local/bundle /usr/local/bundle
|
||||
COPY --from=build /rails /rails
|
||||
COPY --from=beamer /home/beamer/bin/beamer.so /rails/bin/lib/beamer.so
|
||||
# COPY --from=beamer /home/beamer/bin/beamer /rails/bin/beamer
|
||||
|
||||
# Run and own only the runtime files as a non-root user for security
|
||||
RUN useradd rails --create-home --shell /bin/bash && \
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# syntax = docker/dockerfile:1
|
||||
|
||||
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version
|
||||
ARG RUBY_VERSION=3.4.7
|
||||
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim AS base
|
||||
|
||||
# Rails app lives here
|
||||
WORKDIR /rails
|
||||
|
||||
# Set development environment
|
||||
ENV RAILS_ENV="development" \
|
||||
BUNDLE_PATH="/usr/local/bundle"
|
||||
|
||||
# Install packages needed for development
|
||||
RUN apt-get update -qq && \
|
||||
apt-get install --no-install-recommends -y curl libsqlite3-0 libvips build-essential pkg-config git ffmpeg groff libreoffice-writer libreoffice-impress libreoffice-calc mupdf-tools libyaml-dev libssl-dev && \
|
||||
rm -rf /var/lib/apt/lists /var/cache/apt/archives
|
||||
|
||||
# Install application gems
|
||||
COPY Gemfile Gemfile.lock .ruby-version ./
|
||||
COPY lib/bootstrap.rb ./lib/bootstrap.rb
|
||||
COPY gems ./gems/
|
||||
RUN --mount=type=secret,id=GITHUB_TOKEN --mount=type=cache,id=fizzy-devbundle-${RUBY_VERSION},sharing=locked,target=/devbundle \
|
||||
gem install bundler && \
|
||||
BUNDLE_PATH=/devbundle BUNDLE_GITHUB__COM="$(cat /run/secrets/GITHUB_TOKEN):x-oauth-basic" bundle install && \
|
||||
cp -a /devbundle/. "$BUNDLE_PATH"/ && \
|
||||
bundle clean --force
|
||||
|
||||
# Fetch beamer library
|
||||
FROM registry.37signals.com/basecamp/beamer:vfs AS beamer
|
||||
|
||||
# Final stage
|
||||
FROM base
|
||||
|
||||
# Copy beamer
|
||||
COPY --from=beamer /home/beamer/bin/beamer.so /usr/local/lib/beamer/beamer.so
|
||||
COPY --from=beamer /usr/local/bin/beamer /usr/local/bin/beamer
|
||||
|
||||
# Entrypoint prepares the database
|
||||
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
|
||||
|
||||
# Start the server by default
|
||||
EXPOSE 3000
|
||||
EXPOSE 3006
|
||||
EXPOSE 5001
|
||||
CMD ["./bin/thrust", "./bin/rails", "server"]
|
||||
@@ -0,0 +1,3 @@
|
||||
web: bin/thrust bin/rails server
|
||||
beamer: beamer --debug --directory ./storage/ run --primary ${BEAMER_PRIMARY:-$(hostname)}
|
||||
migrations: ./bin/beamer-testbed run-migrations --debug --directory ./storage/
|
||||
Executable
+217
@@ -0,0 +1,217 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
COMPOSE_OPTIONS="-f docker-compose.beamer-testbed.yml"
|
||||
|
||||
# Show usage
|
||||
show_usage() {
|
||||
echo "Usage: $0 {start|stop|logs|console|bash|server|run-migrations} [options]"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " start Build and start all services"
|
||||
echo " stop Stop all services"
|
||||
echo " logs Show logs (pass -f to follow)"
|
||||
echo " console [node] Open Rails console (default: fizzy-01)"
|
||||
echo " bash [node] Open bash shell (default: fizzy-01)"
|
||||
echo " server Start web server and beamer using foreman"
|
||||
echo " run-migrations Wait for beamer, then run migrations if primary"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Get all fizzy-* services from docker compose
|
||||
get_fizzy_services() {
|
||||
fizzy_services=$(docker compose $COMPOSE_OPTIONS config --services | grep '^fizzy-')
|
||||
|
||||
if [ -z "$fizzy_services" ]; then
|
||||
echo "Error: No fizzy-* services found in docker-compose file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$fizzy_services"
|
||||
}
|
||||
|
||||
# Function to wait for a container to be healthy
|
||||
wait_for_container() {
|
||||
local container=$1
|
||||
local max_attempts=60
|
||||
local attempt=0
|
||||
|
||||
echo "Waiting for $container to be ready..."
|
||||
|
||||
while [ $attempt -lt $max_attempts ]; do
|
||||
if docker compose $COMPOSE_OPTIONS exec -T "$container" curl -f -s http://localhost:3000/up >/dev/null 2>&1; then
|
||||
echo "$container is ready!"
|
||||
return 0
|
||||
fi
|
||||
attempt=$((attempt + 1))
|
||||
echo "$container isn't yet ready on attempt $attempt/$max_attempts"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "Error: $container failed to become ready after $max_attempts attempts"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to register a container with kamal-proxy
|
||||
register_with_proxy() {
|
||||
local container=$1
|
||||
local target_name="fizzy-${container##*-}"
|
||||
|
||||
echo "Registering $container with kamal-proxy as $target_name..."
|
||||
|
||||
docker compose $COMPOSE_OPTIONS exec -T kamal-proxy \
|
||||
kamal-proxy deploy fizzy \
|
||||
--target "$container:3000" \
|
||||
--host "fizzy.localhost"
|
||||
|
||||
echo "$container registered successfully!"
|
||||
}
|
||||
|
||||
# Start command
|
||||
cmd_start() {
|
||||
local fizzy_services=$(get_fizzy_services)
|
||||
local first_fizzy=$(echo "$fizzy_services" | head -n 1)
|
||||
|
||||
# Get GitHub token from gh CLI
|
||||
echo "Getting GitHub token from gh CLI..."
|
||||
export GITHUB_TOKEN=$(gh auth token)
|
||||
|
||||
if [ -z "$GITHUB_TOKEN" ]; then
|
||||
echo "Error: Failed to get GitHub token from gh CLI"
|
||||
echo "Make sure you're authenticated with: gh auth login"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create tmp directories with proper permissions
|
||||
echo "Creating temporary directories..."
|
||||
for service in $fizzy_services; do
|
||||
mkdir -p "./tmp/beamer-testbed/$service/storage"
|
||||
mkdir -p "./tmp/beamer-testbed/$service/tmp"
|
||||
done
|
||||
|
||||
echo "Building Docker image for $first_fizzy..."
|
||||
docker compose $COMPOSE_OPTIONS build "$first_fizzy"
|
||||
|
||||
echo "Starting services in detached mode..."
|
||||
docker compose $COMPOSE_OPTIONS down
|
||||
docker compose $COMPOSE_OPTIONS up -d
|
||||
|
||||
# Wait for and register each fizzy container
|
||||
for container in $fizzy_services; do
|
||||
wait_for_container "$container"
|
||||
register_with_proxy "$container"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "All containers are ready and registered!"
|
||||
echo "You can access the application at: http://fizzy.localhost"
|
||||
}
|
||||
|
||||
# Stop command
|
||||
cmd_stop() {
|
||||
echo "Stopping services..."
|
||||
docker compose $COMPOSE_OPTIONS down
|
||||
echo "Services stopped."
|
||||
}
|
||||
|
||||
# Logs command
|
||||
cmd_logs() {
|
||||
docker compose $COMPOSE_OPTIONS logs "$@"
|
||||
}
|
||||
|
||||
# Console command
|
||||
cmd_console() {
|
||||
local node="${1:-fizzy-01}"
|
||||
|
||||
echo "Opening Rails console in $node..."
|
||||
docker compose $COMPOSE_OPTIONS exec "$node" bin/rails console
|
||||
}
|
||||
|
||||
# Bash command
|
||||
cmd_bash() {
|
||||
local node="${1:-fizzy-01}"
|
||||
|
||||
echo "Opening bash shell in $node..."
|
||||
docker compose $COMPOSE_OPTIONS exec "$node" bash
|
||||
}
|
||||
|
||||
# Server command (runs inside container)
|
||||
cmd_server() {
|
||||
# Check if foreman is installed
|
||||
if ! command -v foreman >/dev/null 2>&1; then
|
||||
echo "Foreman not found, installing..."
|
||||
gem install foreman
|
||||
fi
|
||||
|
||||
# Clean up any stale .beamer.sock files
|
||||
echo "Cleaning up stale socket files..."
|
||||
find . -path '*/.beamer/*/.beamer.sock' -type s -delete 2>/dev/null || true
|
||||
|
||||
echo "Starting web server and beamer with foreman..."
|
||||
exec foreman start -f Procfile.beamer-testbed
|
||||
}
|
||||
|
||||
# Run migrations command (runs inside container)
|
||||
cmd_run_migrations() {
|
||||
# Store all arguments as BEAMER_OPTIONS
|
||||
BEAMER_OPTIONS="$*"
|
||||
|
||||
echo "Waiting for beamer to be ready..."
|
||||
|
||||
# Wait for beamer status to succeed
|
||||
while ! beamer $BEAMER_OPTIONS status >/dev/null 2>&1; do
|
||||
echo "Beamer not ready yet, waiting..."
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "Beamer is ready!"
|
||||
sleep 1
|
||||
|
||||
# Check if this is the primary node
|
||||
if beamer $BEAMER_OPTIONS is-primary; then
|
||||
echo "This is the primary node, running migrations..."
|
||||
./bin/rails db:prepare
|
||||
echo "Migrations complete!"
|
||||
else
|
||||
echo "This is not the primary node, skipping migrations."
|
||||
fi
|
||||
|
||||
# Wait indefinitely until interrupted
|
||||
echo "Waiting indefinitely (press Ctrl-C to exit)..."
|
||||
while true; do
|
||||
sleep 3600
|
||||
done
|
||||
}
|
||||
|
||||
# Main command dispatch
|
||||
case "${1:-}" in
|
||||
start)
|
||||
cmd_start
|
||||
;;
|
||||
stop)
|
||||
cmd_stop
|
||||
;;
|
||||
logs)
|
||||
shift
|
||||
cmd_logs "$@"
|
||||
;;
|
||||
console)
|
||||
shift
|
||||
cmd_console "$@"
|
||||
;;
|
||||
bash)
|
||||
shift
|
||||
cmd_bash "$@"
|
||||
;;
|
||||
server)
|
||||
cmd_server
|
||||
;;
|
||||
run-migrations)
|
||||
shift
|
||||
cmd_run_migrations "$@"
|
||||
;;
|
||||
*)
|
||||
show_usage
|
||||
;;
|
||||
esac
|
||||
+3
-1
@@ -14,7 +14,9 @@ default: &default
|
||||
development:
|
||||
primary:
|
||||
<<: *default
|
||||
database: storage/tenants/<%= Rails.env %>/%{tenant}/db/main.sqlite3
|
||||
<% database_path = "storage/tenants/#{Rails.env}/%{tenant}/db/main.sqlite3" %>
|
||||
<% database_path = "file:#{database_path}?vfs=beamer" if %w[1 true].include?(ENV["BEAMER"]&.downcase) %>
|
||||
database: <%= database_path %>
|
||||
tenanted: true
|
||||
untenanted:
|
||||
<<: *default
|
||||
|
||||
@@ -76,7 +76,7 @@ Rails.application.configure do
|
||||
config.action_mailer.raise_delivery_errors = false
|
||||
end
|
||||
|
||||
config.hosts = %w[ fizzy.localhost localhost 127.0.0.1 ]
|
||||
config.hosts = %w[ fizzy.localhost localhost 127.0.0.1 ] + [ /^fizzy-\d+(:\d+)$/ ]
|
||||
|
||||
# Set host to be used by links generated in mailer and notification view templates.
|
||||
config.action_controller.default_url_options = { host: config.hosts.first, port: 3006 }
|
||||
|
||||
@@ -9,11 +9,17 @@
|
||||
# file will be removed.
|
||||
|
||||
Rails.application.config.after_initialize do
|
||||
beamer_extension_path = Rails.root.join("bin/lib/beamer.so")
|
||||
paths = [
|
||||
Rails.root.join("bin/lib/beamer.so"),
|
||||
Pathname("/usr/local/lib/beamer/beamer.so")
|
||||
]
|
||||
|
||||
if beamer_extension_path.exist?
|
||||
db = SQLite3::Database.new ":memory:"
|
||||
db.enable_load_extension(true)
|
||||
db.load_extension(beamer_extension_path)
|
||||
paths.each do |beamer_extension_path|
|
||||
if beamer_extension_path.exist?
|
||||
db = SQLite3::Database.new ":memory:"
|
||||
db.enable_load_extension(true)
|
||||
db.load_extension(beamer_extension_path)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
x-app: &app
|
||||
image: "basecamp/fizzy:dev"
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.dev
|
||||
secrets:
|
||||
- GITHUB_TOKEN
|
||||
volumes:
|
||||
- .:/rails
|
||||
environment:
|
||||
- RAILS_ENV=development
|
||||
- BINDING=0.0.0.0
|
||||
- BEAMER=true
|
||||
- BEAMER_PRIMARY=fizzy-01
|
||||
command: [ "./bin/beamer-testbed", "server" ]
|
||||
|
||||
services:
|
||||
kamal-proxy:
|
||||
image: basecamp/kamal-proxy:next
|
||||
ports:
|
||||
- 127.0.0.1:80:80
|
||||
- 127.0.0.1:443:443
|
||||
command: [ "kamal-proxy", "run", "--debug" ]
|
||||
|
||||
fizzy-01:
|
||||
<<: *app
|
||||
hostname: fizzy-01
|
||||
volumes:
|
||||
- .:/rails
|
||||
- ./tmp/beamer-testbed/fizzy-01/storage:/rails/storage
|
||||
- ./tmp/beamer-testbed/fizzy-01/:/rails/tmp
|
||||
|
||||
fizzy-02:
|
||||
<<: *app
|
||||
hostname: fizzy-02
|
||||
volumes:
|
||||
- .:/rails
|
||||
- ./tmp/beamer-testbed/fizzy-02/storage:/rails/storage
|
||||
- ./tmp/beamer-testbed/fizzy-02/:/rails/tmp
|
||||
|
||||
fizzy-03:
|
||||
<<: *app
|
||||
hostname: fizzy-03
|
||||
volumes:
|
||||
- .:/rails
|
||||
- ./tmp/beamer-testbed/fizzy-03/storage:/rails/storage
|
||||
- ./tmp/beamer-testbed/fizzy-03/:/rails/tmp
|
||||
|
||||
secrets:
|
||||
GITHUB_TOKEN:
|
||||
environment: GITHUB_TOKEN
|
||||
Reference in New Issue
Block a user