Skip to content

Commit

Permalink
add fly deploy
Browse files Browse the repository at this point in the history
Signed-off-by: Jonathan Alvarez <j@jonalvarezz.com>
  • Loading branch information
jonalvarezz committed Dec 12, 2024
1 parent 5315b22 commit 9fd913b
Show file tree
Hide file tree
Showing 10 changed files with 440 additions and 1 deletion.
43 changes: 43 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# env files (can opt-in for committing if needed)
.env*

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

# Sentry Config File
.env.sentry-build-plugin
22 changes: 22 additions & 0 deletions .github/workflows/fly-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# 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 }}
POSTGRESQL_ENDPOINT: ${{ POSTGRESQL_ENDPOINT }}
SESSION_SECRET: ${{ SESSION_SECRET }}
LAUNCHDARKLY_SDK_KEY: ${{ LAUNCHDARKLY_SDK_KEY }}
SENTRY_DSN: ${{ SENTRY_DSN }}
60 changes: 60 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# syntax = docker/dockerfile:1

# Adjust NODE_VERSION as desired
ARG NODE_VERSION=20.12.2
FROM node:${NODE_VERSION}-slim as base

LABEL fly_launch_runtime="Next.js"

# Next.js app lives here
WORKDIR /app

# Set production environment
ENV NODE_ENV="production"

ARG POSTGRESQL_ENDPOINT=""
ARG SESSION_SECRET=""
ARG LAUNCHDARKLY_SDK_KEY=""
ARG SENTRY_DSN=""

ENV POSTGRESQL_ENDPOINT=${POSTGRESQL_ENDPOINT}
ENV SESSION_SECRET=${SESSION_SECRET}
ENV LAUNCHDARKLY_SDK_KEY=${LAUNCHDARKLY_SDK_KEY}
ENV SENTRY_DSN=${SENTRY_DSN}


# Install pnpm
ARG PNPM_VERSION=9.14.4
RUN npm install -g pnpm@$PNPM_VERSION


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

# Install packages needed to build node modules
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential node-gyp pkg-config python-is-python3

# Install node modules
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile --prod=false

# Copy application code
COPY . .

# Build application
RUN pnpm run build

# Remove development dependencies
RUN pnpm prune --prod


# Final stage for app image
FROM base

# Copy built application
COPY --from=build /app /app

# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD [ "pnpm", "run", "start" ]
89 changes: 89 additions & 0 deletions README.FLY_DEPLOY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Deploy en Fly.io

Esta página detalla puntos que se deben de tener en cuenta para desplegar una aplicación de Next.js con PostreSQL utilizando [Fly.io](https://fly.io)

1. Crear tu cuenta en Fly.io

Necesitarás agregar una tarjeta de crédito para esto. Te recomendamos activar las opciones de 2FA y utilizar contraseñas fuertes.

2. Creación de maquinas y bases de datos.

Desde la raíz del proyecto y luego de [instalar `flyctl`](https://fly.io/docs/flyctl/install/):

```bash
fly launch
```

Fly detectará que se trata de un proyecto de Next.js y dará una opción para configurar las opciones del proyecto.

En las opciones, debemos especificar que queremos una Base de Datos de tipo PostgreSQL.

Fly creará la base de datos y la adjuntará a nuestra app. Así mismo creará un archivo de `Dockerfile` y de `fly.toml`.

Debido a que nuestro proyecto depende de otros secretos (ver `env.example`), `fly launch` fallará pero nos servirá como base para continuar.

3. Base de datos pública

La base de datos que se crea por defecto es privada. Debido que utilizaremos esta misma base de datos para otros servicios (Clase de Despliegue en Cloudflare), la haremos pública.

Completa la guia de Fly.io de [External Connections](https://fly.io/docs/postgres/connecting/connecting-external/)

Es importante resaltar que la IP a asignar debe de ser de tipo IPV4 y dedicada. Esta IP tendrá un costo de 2 USD/ mensual.

El archivo de configuración de la DB, se guardó en este proyecto dentro de la carpeta [`fly-db`](./fly-db)

Aségurate de que este archivo tenga la siguiente sección:

```toml
[http_service]
internal_port = 5432
force_https = true
auto_stop_machines = 'stop'
auto_start_machines = true
min_machines_running = 0
processes = ['app']
```

Esto evitará el error de configuración de:

> WARNING The app is not listening on the expected address and will not be reachable by fly-proxy.
> You can fix this by configuring your app to listen on the following addresses:
>
> - 0.0.0.0:3000
Aplica los cambios haciendo deploy como se indica en el articulo.

La base de datos debería ahora ser accesible de la forma:

```
psql "postgres://postgres:<password>@<nombre-db-app>.fly.dev"
```

4. Preparar la DB

Accede a la base de datos utilizando la URL de arriba o creando un proxy local para crear las bases de datos y tablas según sea necesario:

- La mini app de `expenses` requiere DB y tabla. Ver `app/expenses-tracker/README.md`
- La mini app de `bookmarks` requiere que corras el comando de `pnpm bookmarks:db:push` y alternativamente `pnpm bookmarks:db:populate`. Asegúrate que la configuración en `drizzle.config.ts` sea correcta.

5. Configurar secretos

Los secretos de nuestra app (`env.example`) debemos configurarlos en dos partes.

La primera en el Dashboard de Fly.io. Y la segunda dentro de Docker.

La diferencia es que los secretos dentro Fly.io son usados durante tiempo de ejecución de la app (runtime). Sin embargo, Docker y nuestro build también los necesita, por tanto debemos especificarlos también.

Estos se secretos se pueden pasar con [`fly deploy --build-secrets`](https://fly.io/docs/apps/build-secrets/#main-content-start). O, recomendado, proveer a través de GitHub Actions a Docker.

En nuestro repo se ha dejado como referencia lo segundo. Ver `Dockerfile` y `.github/workflows/fly-deploy.yml`

6. Deploy

Solo resta hacer deploy de la app

```bash
fly deploy
```

Si todo sale bien, la app estará disponible en Fly.io
1 change: 0 additions & 1 deletion app/bookmarks/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export default function Bookmarks() {

useEffect(() => {
fetch("/bookmarks/api", {
cache: "force-cache",
next: { tags: ["bookmarks"] },
})
.then((response) => response.json() as Promise<{ data: BookmarkType[] }>)
Expand Down
77 changes: 77 additions & 0 deletions fly-db/fly.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# fly.toml app configuration file generated for postgres-platzi-next-15 on 2024-12-12T01:54:25-05:00
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#

app = 'postgres-platzi-next-15'
primary_region = 'bog'

[env]
PRIMARY_REGION = 'bog'

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

[[services]]
protocol = 'tcp'
internal_port = 5432
auto_start_machines = true

[[services.ports]]
port = 5432
handlers = ['pg_tls']

[services.concurrency]
type = 'connections'
hard_limit = 1000
soft_limit = 1000

[[services]]
protocol = 'tcp'
internal_port = 5433
auto_start_machines = true

[[services.ports]]
port = 5433
handlers = ['pg_tls']

[services.concurrency]
type = 'connections'
hard_limit = 1000
soft_limit = 1000

[checks]
[checks.pg]
port = 5500
type = 'http'
interval = '15s'
timeout = '10s'
path = '/flycheck/pg'

[checks.role]
port = 5500
type = 'http'
interval = '15s'
timeout = '10s'
path = '/flycheck/role'

[checks.vm]
port = 5500
type = 'http'
interval = '15s'
timeout = '10s'
path = '/flycheck/vm'

[[metrics]]
port = 9187
path = '/metrics'
https = false

[http_service]
internal_port = 5432
force_https = true
auto_stop_machines = 'stop'
auto_start_machines = true
min_machines_running = 0
processes = ['app']
22 changes: 22 additions & 0 deletions fly.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# fly.toml app configuration file generated for platzi-next-15 on 2024-12-12T01:51:21-05:00
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#

app = 'platzi-next-15'
primary_region = 'bog'

[build]

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

[[vm]]
memory = '1gb'
cpu_kind = 'shared'
cpus = 1
3 changes: 3 additions & 0 deletions next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ const getSentryConfig = () =>
hideSourceMaps: true,
disableLogger: true,
automaticVercelMonitors: false,
sourcemaps: {
deleteSourcemapsAfterUpload: true,
},
})

const CONFIG = enableSentry ? getSentryConfig() : nextConfig
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"react-dom": "19.0.0-rc-66855b96-20241106"
},
"devDependencies": {
"@flydotio/dockerfile": "^0.5.9",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
Expand Down
Loading

0 comments on commit 9fd913b

Please sign in to comment.