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*
|
||||
vendor/
|
||||
|
||||
# Produced by the builder stages; never copy a local build in.
|
||||
public/build/
|
||||
public/hot
|
||||
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
|
@ -18,5 +22,12 @@ storage/framework/cache/*
|
|||
storage/framework/sessions/*
|
||||
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/
|
||||
README.md
|
||||
docs/
|
||||
compose.yaml
|
||||
.forgejo/
|
||||
|
|
|
|||
|
|
@ -20,7 +20,13 @@ LOG_STACK=single
|
|||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
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_PORT=3306
|
||||
# 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
|
||||
/.zed
|
||||
/.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": [
|
||||
{
|
||||
"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",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "421410120a87c8f8ec2456627557bc36",
|
||||
"content-hash": "1b36d4e3f53a631da85cf21b05c1a2b6",
|
||||
"packages": [
|
||||
{
|
||||
"name": "anagram-finder/core",
|
||||
"version": "v0.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "ssh://git@forge.lvl0.xyz:2222/anagram-finder/core.git",
|
||||
"url": "https://forge.lvl0.xyz/anagram-finder/core.git",
|
||||
"reference": "4b8ce74729fa9a6d0ca91c5d661256ca256e5291"
|
||||
},
|
||||
"require": {
|
||||
|
|
|
|||
12
package-lock.json
generated
12
package-lock.json
generated
|
|
@ -11,6 +11,9 @@
|
|||
"tailwindcss": "^4.0.7",
|
||||
"vite": "^8.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lvl0/ui": "git+https://forge.lvl0.xyz/lvl0/ui.git#v0.1.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@laravel/multiplex": "^0.4.1",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.9.5",
|
||||
|
|
@ -102,6 +105,15 @@
|
|||
"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": {
|
||||
"version": "0.146.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.146.0.tgz",
|
||||
|
|
|
|||
|
|
@ -20,6 +20,6 @@
|
|||
"lightningcss-linux-x64-gnu": "^1.29.1"
|
||||
},
|
||||
"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