2 - Add production Dockerfile and release image pipeline
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m39s
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m39s
This commit is contained in:
parent
49fe4bf72d
commit
f267bac8e1
12 changed files with 268 additions and 55 deletions
|
|
@ -2,6 +2,10 @@ node_modules/
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
vendor/
|
vendor/
|
||||||
|
|
||||||
|
# Produced by the builder stages; never copy a local build in.
|
||||||
|
public/build/
|
||||||
|
public/hot
|
||||||
|
|
||||||
.env
|
.env
|
||||||
.env.*
|
.env.*
|
||||||
!.env.example
|
!.env.example
|
||||||
|
|
@ -18,5 +22,12 @@ storage/framework/cache/*
|
||||||
storage/framework/sessions/*
|
storage/framework/sessions/*
|
||||||
storage/framework/views/*
|
storage/framework/views/*
|
||||||
|
|
||||||
|
# Generated on the host with dev dependencies present; packages.php would
|
||||||
|
# register providers (laravel/pail, sail, ...) that --no-dev never installs.
|
||||||
|
bootstrap/cache/*.php
|
||||||
|
|
||||||
tests/
|
tests/
|
||||||
README.md
|
README.md
|
||||||
|
docs/
|
||||||
|
compose.yaml
|
||||||
|
.forgejo/
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,13 @@ LOG_STACK=single
|
||||||
LOG_DEPRECATIONS_CHANNEL=null
|
LOG_DEPRECATIONS_CHANNEL=null
|
||||||
LOG_LEVEL=debug
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
DB_CONNECTION=sqlite
|
DB_CONNECTION=mariadb
|
||||||
|
DB_HOST=db
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_DATABASE=anagram
|
||||||
|
DB_USERNAME=anagram
|
||||||
|
DB_PASSWORD=
|
||||||
|
DB_ROOT_PASSWORD=
|
||||||
# DB_HOST=127.0.0.1
|
# DB_HOST=127.0.0.1
|
||||||
# DB_PORT=3306
|
# DB_PORT=3306
|
||||||
# DB_DATABASE=laravel
|
# DB_DATABASE=laravel
|
||||||
|
|
|
||||||
41
.forgejo/workflows/build.yml
Normal file
41
.forgejo/workflows/build.yml
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
name: Build and Push Docker Image
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
tags: ['v*']
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: docker
|
||||||
|
container:
|
||||||
|
image: catthehacker/ubuntu:act-latest
|
||||||
|
steps:
|
||||||
|
- uses: https://data.forgejo.org/actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: https://data.forgejo.org/docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Login to Forgejo Registry
|
||||||
|
uses: https://data.forgejo.org/docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: forge.lvl0.xyz
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
|
|
||||||
|
- name: Determine tags
|
||||||
|
id: meta
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
|
||||||
|
TAG="${{ github.ref_name }}"
|
||||||
|
echo "tags=forge.lvl0.xyz/anagram-finder/web:${TAG},forge.lvl0.xyz/anagram-finder/web:latest" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "tags=forge.lvl0.xyz/anagram-finder/web:latest" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: https://data.forgejo.org/docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: Dockerfile
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
12
.github/dependabot.yml
vendored
12
.github/dependabot.yml
vendored
|
|
@ -1,12 +0,0 @@
|
||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "weekly"
|
|
||||||
cooldown:
|
|
||||||
default-days: 5
|
|
||||||
groups:
|
|
||||||
github-actions:
|
|
||||||
patterns:
|
|
||||||
- "*"
|
|
||||||
38
.github/workflows/tests.yml
vendored
38
.github/workflows/tests.yml
vendored
|
|
@ -1,38 +0,0 @@
|
||||||
name: tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
ci:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- name: Setup PHP
|
|
||||||
uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # v2
|
|
||||||
with:
|
|
||||||
php-version: '8.3'
|
|
||||||
tools: composer:v2
|
|
||||||
coverage: none
|
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
||||||
with:
|
|
||||||
node-version: '22'
|
|
||||||
|
|
||||||
- name: Setup Application
|
|
||||||
run: composer setup
|
|
||||||
|
|
||||||
- name: Run CI Checks
|
|
||||||
run: composer ci:check
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -23,3 +23,4 @@ yarn-error.log
|
||||||
/.vscode
|
/.vscode
|
||||||
/.zed
|
/.zed
|
||||||
/.php-cs-fixer.cache
|
/.php-cs-fixer.cache
|
||||||
|
compose.override.yaml
|
||||||
|
|
|
||||||
123
Dockerfile
Normal file
123
Dockerfile
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
# ---- vendor ----------------------------------------------------------------
|
||||||
|
FROM composer:2 AS vendor
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# anagram-finder/core is a VCS repository, so composer needs git.
|
||||||
|
RUN apk add --no-cache git
|
||||||
|
|
||||||
|
COPY composer.json composer.lock ./
|
||||||
|
RUN composer install \
|
||||||
|
--no-dev \
|
||||||
|
--no-scripts \
|
||||||
|
--no-autoloader \
|
||||||
|
--prefer-dist \
|
||||||
|
--no-interaction
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
# --no-scripts: Laravel's post-autoload-dump hook runs artisan, which wants an
|
||||||
|
# environment that does not exist at build time. Package discovery happens on boot.
|
||||||
|
RUN composer dump-autoload --no-dev --optimize --classmap-authoritative --no-scripts
|
||||||
|
|
||||||
|
# ---- assets ----------------------------------------------------------------
|
||||||
|
FROM node:22-alpine AS assets
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# @lvl0/ui is a git dependency, so npm needs git available.
|
||||||
|
RUN apk add --no-cache git
|
||||||
|
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
COPY vite.config.js ./
|
||||||
|
COPY resources ./resources
|
||||||
|
|
||||||
|
# app.css imports Flux's stylesheet from vendor/ and scans three vendor globs
|
||||||
|
# for class names, so the asset build needs composer's output present.
|
||||||
|
COPY --from=vendor /app/vendor ./vendor
|
||||||
|
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# ---- runtime ---------------------------------------------------------------
|
||||||
|
FROM dunglas/frankenphp:1-php8.4-alpine
|
||||||
|
|
||||||
|
RUN apk add --no-cache mariadb-client curl
|
||||||
|
|
||||||
|
RUN install-php-extensions \
|
||||||
|
pdo_mysql \
|
||||||
|
opcache \
|
||||||
|
zip \
|
||||||
|
gd \
|
||||||
|
intl \
|
||||||
|
bcmath \
|
||||||
|
pcntl
|
||||||
|
|
||||||
|
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY --from=vendor /app /app
|
||||||
|
COPY --from=assets /app/public/build /app/public/build
|
||||||
|
|
||||||
|
# The dev server writes public/hot and only removes it on a clean shutdown; a
|
||||||
|
# stray copy makes @vite() point at a dev server that does not exist here.
|
||||||
|
RUN rm -f /app/public/hot
|
||||||
|
|
||||||
|
RUN cat > /etc/caddy/Caddyfile <<'EOF'
|
||||||
|
{
|
||||||
|
frankenphp
|
||||||
|
order php_server before file_server
|
||||||
|
}
|
||||||
|
|
||||||
|
:8000 {
|
||||||
|
root * /app/public
|
||||||
|
|
||||||
|
php_server {
|
||||||
|
index index.php
|
||||||
|
}
|
||||||
|
|
||||||
|
encode gzip
|
||||||
|
file_server
|
||||||
|
|
||||||
|
header {
|
||||||
|
X-Frame-Options "SAMEORIGIN"
|
||||||
|
X-Content-Type-Options "nosniff"
|
||||||
|
Referrer-Policy "strict-origin-when-cross-origin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
RUN cat > /start.sh <<'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -n "$DB_HOST" ]; then
|
||||||
|
echo "Waiting for database..."
|
||||||
|
until mariadb -h "$DB_HOST" -u "$DB_USERNAME" -p"$DB_PASSWORD" -e "SELECT 1" >/dev/null 2>&1; do
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Rebuild the package manifest from what is actually installed. Any manifest
|
||||||
|
# baked in at build time could name a dev provider that --no-dev omitted.
|
||||||
|
rm -f bootstrap/cache/packages.php bootstrap/cache/services.php
|
||||||
|
php artisan package:discover --ansi
|
||||||
|
|
||||||
|
php artisan migrate --force
|
||||||
|
|
||||||
|
# Cached at boot rather than at build: config:cache bakes in environment values,
|
||||||
|
# which are not known until the container runs.
|
||||||
|
php artisan config:cache
|
||||||
|
php artisan route:cache
|
||||||
|
php artisan view:cache
|
||||||
|
|
||||||
|
exec frankenphp run --config /etc/caddy/Caddyfile
|
||||||
|
EOF
|
||||||
|
RUN chmod +x /start.sh
|
||||||
|
|
||||||
|
RUN chown -R www-data:www-data /app/storage /app/bootstrap/cache
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
CMD ["/start.sh"]
|
||||||
69
compose.yaml
Normal file
69
compose.yaml
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
# Anagram Finder — self-hosting stack.
|
||||||
|
#
|
||||||
|
# Copy .env.example to .env, set APP_KEY and the database passwords, then:
|
||||||
|
# docker compose up -d
|
||||||
|
#
|
||||||
|
# The app binds to 127.0.0.1 only. Put a reverse proxy in front of it for
|
||||||
|
# anything public-facing, and set APP_URL to the address people will use.
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
image: forge.lvl0.xyz/anagram-finder/web:latest
|
||||||
|
container_name: anagram_app
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:8000:8000"
|
||||||
|
environment:
|
||||||
|
APP_NAME: "Anagram Finder"
|
||||||
|
APP_ENV: production
|
||||||
|
APP_DEBUG: "false"
|
||||||
|
APP_KEY: "${APP_KEY}"
|
||||||
|
APP_URL: "${APP_URL:-http://localhost:8000}"
|
||||||
|
DB_CONNECTION: mariadb
|
||||||
|
DB_HOST: db
|
||||||
|
DB_PORT: "3306"
|
||||||
|
DB_DATABASE: "${DB_DATABASE:-anagram}"
|
||||||
|
DB_USERNAME: "${DB_USERNAME:-anagram}"
|
||||||
|
DB_PASSWORD: "${DB_PASSWORD}"
|
||||||
|
SESSION_DRIVER: database
|
||||||
|
CACHE_STORE: database
|
||||||
|
QUEUE_CONNECTION: database
|
||||||
|
# A plain dependency, not condition: service_healthy — podman-compose 1.5.0
|
||||||
|
# hangs waiting on that. The app's start script polls for the database itself.
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-fsS", "http://localhost:8000/up"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
networks:
|
||||||
|
- anagram
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: mariadb:11
|
||||||
|
container_name: anagram_db
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
MARIADB_DATABASE: "${DB_DATABASE:-anagram}"
|
||||||
|
MARIADB_USER: "${DB_USERNAME:-anagram}"
|
||||||
|
MARIADB_PASSWORD: "${DB_PASSWORD}"
|
||||||
|
MARIADB_ROOT_PASSWORD: "${DB_ROOT_PASSWORD}"
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/mysql
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 30s
|
||||||
|
networks:
|
||||||
|
- anagram
|
||||||
|
|
||||||
|
networks:
|
||||||
|
anagram:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db_data:
|
||||||
|
|
@ -115,7 +115,7 @@
|
||||||
"repositories": [
|
"repositories": [
|
||||||
{
|
{
|
||||||
"type": "vcs",
|
"type": "vcs",
|
||||||
"url": "ssh://git@forge.lvl0.xyz:2222/anagram-finder/core.git"
|
"url": "https://forge.lvl0.xyz/anagram-finder/core.git"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
4
composer.lock
generated
4
composer.lock
generated
|
|
@ -4,14 +4,14 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "421410120a87c8f8ec2456627557bc36",
|
"content-hash": "1b36d4e3f53a631da85cf21b05c1a2b6",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "anagram-finder/core",
|
"name": "anagram-finder/core",
|
||||||
"version": "v0.1.0",
|
"version": "v0.1.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "ssh://git@forge.lvl0.xyz:2222/anagram-finder/core.git",
|
"url": "https://forge.lvl0.xyz/anagram-finder/core.git",
|
||||||
"reference": "4b8ce74729fa9a6d0ca91c5d661256ca256e5291"
|
"reference": "4b8ce74729fa9a6d0ca91c5d661256ca256e5291"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
|
||||||
12
package-lock.json
generated
12
package-lock.json
generated
|
|
@ -11,6 +11,9 @@
|
||||||
"tailwindcss": "^4.0.7",
|
"tailwindcss": "^4.0.7",
|
||||||
"vite": "^8.0.0"
|
"vite": "^8.0.0"
|
||||||
},
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@lvl0/ui": "git+https://forge.lvl0.xyz/lvl0/ui.git#v0.1.1"
|
||||||
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@laravel/multiplex": "^0.4.1",
|
"@laravel/multiplex": "^0.4.1",
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.9.5",
|
"@rollup/rollup-linux-x64-gnu": "4.9.5",
|
||||||
|
|
@ -102,6 +105,15 @@
|
||||||
"node": ">=22.13.0"
|
"node": ">=22.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@lvl0/ui": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "git+https://forge.lvl0.xyz/lvl0/ui.git#e235cec8a3cfe4060a4fda5857ac2bd1fc9bb7b1",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"tailwindcss": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@oxc-project/types": {
|
"node_modules/@oxc-project/types": {
|
||||||
"version": "0.146.0",
|
"version": "0.146.0",
|
||||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.146.0.tgz",
|
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.146.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,6 @@
|
||||||
"lightningcss-linux-x64-gnu": "^1.29.1"
|
"lightningcss-linux-x64-gnu": "^1.29.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@lvl0/ui": "git+ssh://git@forge.lvl0.xyz:2222/lvl0/ui.git#v0.1.0"
|
"@lvl0/ui": "git+https://forge.lvl0.xyz/lvl0/ui.git#v0.1.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue