Lucky Framework deployment with Apex Up
Hosting a [Lucky Framework] application on AWS Lambda using [Apex Up].
Hosting a Lucky Framework application on AWS Lambda using Apex Up.
Crystal Version: 0.35.1 Lucky Version: 0.25
Building
The app needs to be build in a docker container. Crystal provides an image that we can use.
I used a make file to run on the docker image. I'm building an API and don't need Node/Yarn. Might need a custom docker image with those installed.
# Makefile
.PHONY: help
IS_PROD := $(filter prod, $(MAKECMDGOALS))
STAGE := $(if $(IS_PROD),prod,development)
help:
@perl -nle'print $& if m{^[a-zA-Z_-]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
prod: ## Set the deploy target to prod
@echo "Setting Prod"
build: ## Build server.go
shards install
crystal build -o server src/start_server.cr --release --static
clean: ## Remove exec
rm -f server
Apex Up Configuration
Apex docs are good, but you need to setup your VPC info before the first up
run.
There are environment secrets in this file with the OSS version. The Pro version allows encrypted environment variables.
up.json
configuration file
{
"name": "my-app",
"profile": "my_aws_profile",
"regions": [
"us-west-2"
],
"environment": {
"LUCKY_ENV": "production",
"SECRET_KEY_BASE": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=",
"DATABASE_URL": "postgresql://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.us-west-2.rds.amazonaws.com/my_app_staging",
"SEND_GRID_KEY": "unused",
"APP_DOMAIN": "https://xxxxxxxxxxxxxxxxxxxxxx.us-west-2.amazonaws.com"
},
"hooks": {
"build": "docker run --rm -v $(pwd):/src -w /src crystallang/crystal make prod clean build",
"clean": "rm server"
},
"lambda": {
"memory": 512,
"vpc": {
"subnets": [
"subnet-xxxxxxxx",
"subnet-xxxxxxxx",
"subnet-xxxxxxxx",
"subnet-xxxxxxxx"
],
"security_groups": [
"sg-xxxxxxxxxxxxxxxxx"
]
}
}
}
The APP_DOMAIN
environment variable won't be known until after the first deployment, update and then redeploy.
Add an .upignore
file to exclude everything except the server
binary and the ./config/watch.yml
file. The yml file
shouldn't be needed, but it seemed to error without it.
*
!./server
!./config/watch.yml
Database setup
I created a DB using AWS RDS service. Not sure why it didn't create a database, but I had to do that manually.
- Create an EC2 server and SSH to it.
- Install postgres-client
- Make sure the postgres security group allows connections from the VPC ip range.
- Connect to the
postgres
database & create the database
sudo apt-get update
sudo apt-get install postgresql-client
psql "postgresql://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.us-west-2.rds.amazonaws.com/postgres"
create database my_app_staging;
Lucky setup
Need to setup the DB when the app starts. Not the most effienct way, but I added the DB setup to the start_server.cr
file.
- Setup migration tracking tables
- Run migrations
- Ensure everything is good
- Run the required data seeds
# src/start_server.cr
require "./app"
require "../tasks/db/seed/required_data.cr"
Habitat.raise_if_missing_settings!
if Lucky::Env.development?
Avram::Migrator::Runner.new.ensure_migrated!
Avram::SchemaEnforcer.ensure_correct_column_mappings!
end
if Lucky::Env.production?
Avram::Migrator::Runner.setup_migration_tracking_tables
Db::Migrate.new(quiet: true).call
Avram::Migrator::Runner.new.ensure_migrated!
Db::Seed::RequiredData.new.call
end
app_server = AppServer.new
puts "Listening on http://#{app_server.host}:#{app_server.port}"
Signal::INT.trap do
app_server.close
end
app_server.listen
Deploy
Run the up
command to deploy.
Webmentions
These are webmentions via the IndieWeb and webmention.io. Mention this post from your site: