Attempt to be prod ready
This commit is contained in:
@@ -1,20 +1,74 @@
|
|||||||
name: CI - Build Tonehaus Docker image
|
name: CI (Gitea)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ main ]
|
branches:
|
||||||
|
- main
|
||||||
|
- prod
|
||||||
pull_request:
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- prod
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
IMAGE_NAME: tonehaus
|
APP_ENV: test
|
||||||
|
APP_SECRET: ci-secret
|
||||||
|
DATABASE_DRIVER: sqlite
|
||||||
|
DATABASE_SQLITE_PATH: ${{ gitea.workspace }}/var/data/database.test.sqlite
|
||||||
DOCKERFILE: docker/php/Dockerfile
|
DOCKERFILE: docker/php/Dockerfile
|
||||||
BUILD_TARGET: prod
|
BUILD_TARGET: prod
|
||||||
PLATFORMS: linux/amd64
|
IMAGE_NAME: tonehaus-app
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
tonehaus-ci-build:
|
php-tests:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: '8.2'
|
||||||
|
extensions: intl, mbstring, pdo_pgsql, pdo_sqlite, zip, gd
|
||||||
|
coverage: none
|
||||||
|
ini-values: memory_limit=512M
|
||||||
|
tools: composer:v2
|
||||||
|
|
||||||
|
- name: Validate Composer manifest
|
||||||
|
run: composer validate --strict
|
||||||
|
|
||||||
|
- name: Cache Composer downloads
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.cache/composer/files
|
||||||
|
~/.cache/composer/vcs
|
||||||
|
key: composer-${{ runner.os }}-${{ hashFiles('**/composer.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
composer-${{ runner.os }}-
|
||||||
|
|
||||||
|
- name: Install Composer dependencies
|
||||||
|
run: composer install --prefer-dist --no-interaction --no-progress
|
||||||
|
|
||||||
|
- name: Prepare SQLite database
|
||||||
|
run: |
|
||||||
|
mkdir -p "$(dirname "$DATABASE_SQLITE_PATH")"
|
||||||
|
touch "$DATABASE_SQLITE_PATH"
|
||||||
|
php bin/console doctrine:migrations:migrate --no-interaction --allow-no-migration
|
||||||
|
|
||||||
|
- name: Run PHPUnit
|
||||||
|
run: vendor/bin/phpunit --colors=always
|
||||||
|
|
||||||
|
docker-image:
|
||||||
|
needs: php-tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
REGISTRY: ${{ secrets.REGISTRY }}
|
||||||
|
REGISTRY_IMAGE: ${{ secrets.REGISTRY_IMAGE }}
|
||||||
|
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
|
||||||
|
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -22,62 +76,40 @@ jobs:
|
|||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Compute tags
|
- name: Build prod image (local)
|
||||||
id: meta
|
uses: docker/build-push-action@v6
|
||||||
run: |
|
with:
|
||||||
SHA="${GITHUB_SHA:-${GITEA_SHA:-unknown}}"
|
context: .
|
||||||
SHORT_SHA="${SHA:0:7}"
|
file: ${{ env.DOCKERFILE }}
|
||||||
echo "short_sha=$SHORT_SHA" >> "$GITHUB_OUTPUT"
|
target: ${{ env.BUILD_TARGET }}
|
||||||
|
tags: ${{ env.IMAGE_NAME }}:ci
|
||||||
|
load: true
|
||||||
|
|
||||||
- name: Optional registry login
|
- name: Verify baked APP_ENV
|
||||||
|
run: docker run --rm --entrypoint sh ${{ env.IMAGE_NAME }}:ci -c 'test "$APP_ENV" = "prod"'
|
||||||
|
|
||||||
|
- name: Verify Symfony artifacts exist
|
||||||
|
run: |
|
||||||
|
docker run --rm --entrypoint sh ${{ env.IMAGE_NAME }}:ci -c 'test -f /var/www/html/public/index.php'
|
||||||
|
docker run --rm --entrypoint sh ${{ env.IMAGE_NAME }}:ci -c 'test -f /var/www/html/bin/console'
|
||||||
|
|
||||||
|
- name: Smoke-test entrypoint & migrations
|
||||||
|
run: docker run --rm --entrypoint /entrypoint.sh ${{ env.IMAGE_NAME }}:ci true
|
||||||
|
|
||||||
|
- name: Login to registry
|
||||||
if: ${{ env.REGISTRY != '' && env.REGISTRY_USERNAME != '' && env.REGISTRY_PASSWORD != '' }}
|
if: ${{ env.REGISTRY != '' && env.REGISTRY_USERNAME != '' && env.REGISTRY_PASSWORD != '' }}
|
||||||
env:
|
|
||||||
REGISTRY: ${{ secrets.REGISTRY }}
|
|
||||||
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
|
|
||||||
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
|
||||||
run: |
|
run: |
|
||||||
echo "$REGISTRY_PASSWORD" | docker login "$REGISTRY" -u "$REGISTRY_USERNAME" --password-stdin
|
echo "$REGISTRY_PASSWORD" | docker login "$REGISTRY" -u "$REGISTRY_USERNAME" --password-stdin
|
||||||
|
|
||||||
- name: Docker Build
|
- name: Push prod image
|
||||||
if: ${{ env.REGISTRY != '' && env.REGISTRY_IMAGE != '' }}
|
if: ${{ env.REGISTRY != '' && env.REGISTRY_IMAGE != '' && env.REGISTRY_USERNAME != '' && env.REGISTRY_PASSWORD != '' }}
|
||||||
env:
|
uses: docker/build-push-action@v6
|
||||||
REGISTRY: ${{ secrets.REGISTRY }}
|
with:
|
||||||
REGISTRY_IMAGE: ${{ secrets.REGISTRY_IMAGE }}
|
context: .
|
||||||
run: |
|
file: ${{ env.DOCKERFILE }}
|
||||||
TAG_SHA=${{ steps.meta.outputs.short_sha }}
|
target: ${{ env.BUILD_TARGET }}
|
||||||
docker buildx build \
|
push: true
|
||||||
--platform "$PLATFORMS" \
|
tags: |
|
||||||
--file "$DOCKERFILE" \
|
${{ env.REGISTRY }}/${{ env.REGISTRY_IMAGE }}:ci
|
||||||
--target "$BUILD_TARGET" \
|
${{ env.REGISTRY }}/${{ env.REGISTRY_IMAGE }}:${{ github.sha }}
|
||||||
--build-arg APP_ENV=prod \
|
|
||||||
--tag "$REGISTRY/$REGISTRY_IMAGE:$TAG_SHA" \
|
|
||||||
--tag "$REGISTRY/$REGISTRY_IMAGE:ci" \
|
|
||||||
--push \
|
|
||||||
.
|
|
||||||
|
|
||||||
# - name: Build single-arch images for artifacts (no registry)
|
|
||||||
# if: ${{ env.REGISTRY == '' }}
|
|
||||||
# run: |
|
|
||||||
# TAG_SHA=${{ steps.meta.outputs.short_sha }}
|
|
||||||
# for P in $PLATFORMS; do \
|
|
||||||
# ARCH=${P#linux/}; \
|
|
||||||
# docker buildx build \
|
|
||||||
# --platform "$P" \
|
|
||||||
# --file "$DOCKERFILE" \
|
|
||||||
# --target "$BUILD_TARGET" \
|
|
||||||
# --build-arg APP_ENV=prod \
|
|
||||||
# --output type=docker \
|
|
||||||
# --tag "$IMAGE_NAME:$TAG_SHA-$ARCH" \
|
|
||||||
# . ; \
|
|
||||||
# docker save "$IMAGE_NAME:$TAG_SHA-$ARCH" -o "tonehaus-image-$ARCH.tar" ; \
|
|
||||||
# done
|
|
||||||
|
|
||||||
## Artifacts not configured yet..
|
|
||||||
# - name: Upload artifacts
|
|
||||||
# if: ${{ env.REGISTRY == '' }}
|
|
||||||
# uses: actions/upload-artifact@v4
|
|
||||||
# with:
|
|
||||||
# name: tonehaus-images
|
|
||||||
# path: |
|
|
||||||
# tonehaus-image-amd64.tar
|
|
||||||
|
|
||||||
|
|||||||
102
.github/workflows/ci.yml
vendored
Normal file
102
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- prod
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- prod
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ci-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
APP_ENV: test
|
||||||
|
APP_SECRET: ci-secret
|
||||||
|
DATABASE_DRIVER: sqlite
|
||||||
|
DATABASE_SQLITE_PATH: ${{ github.workspace }}/var/data/database.test.sqlite
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
php-tests:
|
||||||
|
name: PHPUnit + migrations
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: '8.2'
|
||||||
|
extensions: intl, mbstring, pdo_pgsql, pdo_sqlite, zip, gd
|
||||||
|
coverage: none
|
||||||
|
ini-values: memory_limit=512M
|
||||||
|
tools: composer:v2
|
||||||
|
|
||||||
|
- name: Validate Composer manifest
|
||||||
|
run: composer validate --strict
|
||||||
|
|
||||||
|
- name: Cache Composer downloads
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.cache/composer/files
|
||||||
|
~/.cache/composer/vcs
|
||||||
|
key: composer-${{ runner.os }}-${{ hashFiles('**/composer.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
composer-${{ runner.os }}-
|
||||||
|
|
||||||
|
- name: Install Composer dependencies
|
||||||
|
run: composer install --prefer-dist --no-interaction --no-progress
|
||||||
|
|
||||||
|
- name: Prepare SQLite database
|
||||||
|
run: |
|
||||||
|
mkdir -p "$(dirname "$DATABASE_SQLITE_PATH")"
|
||||||
|
touch "$DATABASE_SQLITE_PATH"
|
||||||
|
php bin/console doctrine:migrations:migrate --no-interaction --allow-no-migration
|
||||||
|
|
||||||
|
- name: Run PHPUnit
|
||||||
|
run: vendor/bin/phpunit --colors=always
|
||||||
|
|
||||||
|
docker-image:
|
||||||
|
name: Build production image
|
||||||
|
needs: php-tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Build prod image
|
||||||
|
id: build-prod
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: docker/php/Dockerfile
|
||||||
|
target: prod
|
||||||
|
load: true
|
||||||
|
push: false
|
||||||
|
tags: tonehaus-app:ci
|
||||||
|
|
||||||
|
- name: Verify baked APP_ENV
|
||||||
|
run: docker run --rm --entrypoint sh tonehaus-app:ci -c 'test "$APP_ENV" = "prod"'
|
||||||
|
|
||||||
|
- name: Verify Symfony artifacts exist
|
||||||
|
run: |
|
||||||
|
docker run --rm --entrypoint sh tonehaus-app:ci -c 'test -f /var/www/html/public/index.php'
|
||||||
|
docker run --rm --entrypoint sh tonehaus-app:ci -c 'test -f /var/www/html/bin/console'
|
||||||
|
|
||||||
|
- name: Smoke-test entrypoint & migrations
|
||||||
|
run: docker run --rm --entrypoint /entrypoint.sh tonehaus-app:ci true
|
||||||
|
|
||||||
41
README.md
41
README.md
@@ -39,6 +39,47 @@ docker compose exec php php bin/console app:seed-demo-albums --count=40 --attach
|
|||||||
docker compose exec php php bin/console app:seed-demo-reviews --cover-percent=70 --max-per-album=8
|
docker compose exec php php bin/console app:seed-demo-reviews --cover-percent=70 --max-per-album=8
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Production container (immutable)
|
||||||
|
|
||||||
|
The repository ships with a single-container production target that bundles PHP-FPM, Nginx, your code, and a self-contained SQLite database. The build bakes in the `APP_ENV=prod` flag so production-only Symfony config is used automatically, and no bind mounts are required at runtime.
|
||||||
|
|
||||||
|
1. Build the image (uses `docker/php/Dockerfile`'s `prod` stage):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build \
|
||||||
|
--target=prod \
|
||||||
|
-t tonehaus-app:latest \
|
||||||
|
-f docker/php/Dockerfile \
|
||||||
|
.
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Run the container (listens on port 8080 inside the container):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d \
|
||||||
|
--name tonehaus \
|
||||||
|
-p 8080:8080 \
|
||||||
|
-e APP_ENV=prod \
|
||||||
|
-e APP_SECRET=change_me \
|
||||||
|
-e SPOTIFY_CLIENT_ID=your_client_id \
|
||||||
|
-e SPOTIFY_CLIENT_SECRET=your_client_secret \
|
||||||
|
tonehaus-app:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
- The runtime defaults to `DATABASE_DRIVER=sqlite` and stores the database file inside the image at `var/data/database.sqlite`. On each boot the entrypoint runs Doctrine migrations (safe to re-run) so the schema stays current while the container filesystem remains immutable from the host's perspective.
|
||||||
|
- To point at Postgres (or any external database), override `DATABASE_DRIVER` and `DATABASE_URL` at `docker run` time and optionally disable auto-migration with `RUN_MIGRATIONS_ON_START=0`.
|
||||||
|
- Health endpoint: `GET /healthz` on the published port (example: `curl http://localhost:8080/healthz`).
|
||||||
|
|
||||||
|
3. Rebuild/redeploy by re-running the `docker build` command; no manual steps or bind mounts are involved.
|
||||||
|
|
||||||
|
## Continuous integration
|
||||||
|
|
||||||
|
- `.github/workflows/ci.yml` runs on pushes and pull requests targeting `main` or `prod`.
|
||||||
|
- Job 1 installs Composer deps, prepares a SQLite database, runs Doctrine migrations, and executes the PHPUnit suite under PHP 8.2 so functional regressions are caught early.
|
||||||
|
- Job 2 builds the production Docker image (`docker/php/Dockerfile` prod stage), checks that key Symfony artifacts (e.g., `public/index.php`, `bin/console`) are present, ensures `APP_ENV=prod` is baked in, and smoke-tests the `/entrypoint.sh` startup path.
|
||||||
|
- The resulting artifact mirrors the immutable container described above, so a green CI run guarantees the repo can be deployed anywhere via `docker run`.
|
||||||
|
- Self-hosted runners can use `.gitea/workflows/ci.yml`, which mirrors the GitHub workflow but also supports optional registry pushes after the image passes the same verification steps.
|
||||||
|
|
||||||
## Database driver
|
## Database driver
|
||||||
|
|
||||||
- Set `DATABASE_DRIVER=postgres` (default) to keep using the Postgres 16 container defined in `docker-compose.yml`.
|
- Set `DATABASE_DRIVER=postgres` (default) to keep using the Postgres 16 container defined in `docker-compose.yml`.
|
||||||
|
|||||||
@@ -1,52 +1,47 @@
|
|||||||
# FROM php:8.2-fpm
|
|
||||||
|
|
||||||
# # Install dependencies
|
|
||||||
# RUN apt-get update && apt-get install -y \
|
|
||||||
# git \
|
|
||||||
# unzip \
|
|
||||||
# libzip-dev \
|
|
||||||
# libpng-dev \
|
|
||||||
# libjpeg-dev \
|
|
||||||
# libonig-dev \
|
|
||||||
# libxml2-dev \
|
|
||||||
# zip \
|
|
||||||
# && docker-php-ext-install pdo pdo_mysql zip gd mbstring exif pcntl bcmath intl opcache
|
|
||||||
|
|
||||||
# # Install Composer
|
|
||||||
# COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
|
||||||
|
|
||||||
# # Copy PHP config
|
|
||||||
# COPY docker/php/php.ini /usr/local/etc/php/
|
|
||||||
|
|
||||||
# WORKDIR /var/www/html
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Base PHP-FPM with Composer + Symfony-friendly extensions
|
# Base PHP-FPM with Composer + Symfony-friendly extensions
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
FROM php:8.2-fpm-alpine AS base
|
FROM php:8.2-fpm-alpine AS base
|
||||||
WORKDIR /var/www/html
|
|
||||||
|
|
||||||
# System dependencies
|
ARG APP_ENV=dev
|
||||||
RUN apk add --no-cache \
|
ENV APP_ENV=${APP_ENV}
|
||||||
bash git unzip icu-dev libpng-dev libjpeg-turbo-dev libwebp-dev \
|
|
||||||
libzip-dev oniguruma-dev libxml2-dev postgresql-dev zlib-dev
|
|
||||||
|
|
||||||
# PHP extensions commonly used by Symfony
|
WORKDIR /var/www/html
|
||||||
RUN docker-php-ext-configure gd --with-jpeg --with-webp \
|
|
||||||
|
# System dependencies shared across images
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
bash \
|
||||||
|
git \
|
||||||
|
unzip \
|
||||||
|
icu-dev \
|
||||||
|
libpng-dev \
|
||||||
|
libjpeg-turbo-dev \
|
||||||
|
libwebp-dev \
|
||||||
|
libzip-dev \
|
||||||
|
oniguruma-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
postgresql-dev \
|
||||||
|
sqlite-dev \
|
||||||
|
zlib-dev \
|
||||||
|
su-exec
|
||||||
|
|
||||||
|
# PHP extensions commonly used by Symfony (plus both Postgres + SQLite)
|
||||||
|
RUN docker-php-ext-configure gd --with-jpeg --with-webp \
|
||||||
&& docker-php-ext-install -j"$(nproc)" \
|
&& docker-php-ext-install -j"$(nproc)" \
|
||||||
intl \
|
intl \
|
||||||
gd \
|
gd \
|
||||||
pdo_pgsql \
|
pdo_pgsql \
|
||||||
|
pdo_sqlite \
|
||||||
opcache \
|
opcache \
|
||||||
mbstring \
|
mbstring \
|
||||||
zip \
|
zip \
|
||||||
xml
|
xml
|
||||||
|
|
||||||
# Composer available in the running container (dev + prod)
|
# Composer available in every stage (dev + prod)
|
||||||
COPY --from=composer:2.7 /usr/bin/composer /usr/bin/composer
|
COPY --from=composer:2.7 /usr/bin/composer /usr/bin/composer
|
||||||
|
|
||||||
# Recommended PHP settings (tweak as needed)
|
# Recommended PHP settings (tweak as needed)
|
||||||
RUN { \
|
RUN { \
|
||||||
echo "memory_limit=512M"; \
|
echo "memory_limit=512M"; \
|
||||||
echo "upload_max_filesize=50M"; \
|
echo "upload_max_filesize=50M"; \
|
||||||
echo "post_max_size=50M"; \
|
echo "post_max_size=50M"; \
|
||||||
@@ -63,56 +58,79 @@
|
|||||||
echo "opcache.jit_buffer_size=128M"; \
|
echo "opcache.jit_buffer_size=128M"; \
|
||||||
} > /usr/local/etc/php/conf.d/opcache-recommended.ini
|
} > /usr/local/etc/php/conf.d/opcache-recommended.ini
|
||||||
|
|
||||||
# Small healthcheck file for Nginx
|
# Small healthcheck file for HTTP probes
|
||||||
RUN mkdir -p public && printf "OK" > public/healthz
|
RUN mkdir -p public && printf "OK" > public/healthz
|
||||||
|
|
||||||
# Ensure correct user
|
# Ensure unprivileged app user exists
|
||||||
RUN addgroup -g 1000 app && adduser -D -G app -u 1000 app
|
RUN addgroup -g 1000 app && adduser -D -G app -u 1000 app \
|
||||||
# php-fpm uses www-data; keep both available
|
&& chown -R www-data:www-data /var/www
|
||||||
RUN chown -R www-data:www-data /var/www
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Development image (mount your code via docker-compose volumes)
|
# Development image (mount your code via docker-compose volumes)
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
FROM base AS dev
|
FROM base AS dev
|
||||||
ENV APP_ENV=dev
|
ARG APP_ENV=dev
|
||||||
# Optional: enable Xdebug (uncomment to use)
|
ENV APP_ENV=${APP_ENV}
|
||||||
# RUN apk add --no-cache $PHPIZE_DEPS \
|
ENV APP_DEBUG=1
|
||||||
# && pecl install xdebug \
|
|
||||||
# && docker-php-ext-enable xdebug \
|
|
||||||
# && { \
|
|
||||||
# echo "xdebug.mode=debug,develop"; \
|
|
||||||
# echo "xdebug.client_host=host.docker.internal"; \
|
|
||||||
# } > /usr/local/etc/php/conf.d/xdebug.ini
|
|
||||||
# Composer cache directory (faster installs inside container)
|
|
||||||
ENV COMPOSER_CACHE_DIR=/tmp/composer
|
|
||||||
CMD ["php-fpm"]
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# Optional: enable Xdebug by uncommenting below
|
||||||
# Production image (copies your app + installs deps + warms cache)
|
# RUN apk add --no-cache $PHPIZE_DEPS \
|
||||||
# -----------------------------------------------------------------------------
|
# && pecl install xdebug \
|
||||||
FROM base AS prod
|
# && docker-php-ext-enable xdebug \
|
||||||
ENV APP_ENV=prod
|
# && { \
|
||||||
# Copy only manifests first (better layer caching); ignore if missing
|
# echo "xdebug.mode=debug,develop"; \
|
||||||
COPY composer.json composer.lock* symfony.lock* ./
|
# echo "xdebug.client_host=host.docker.internal"; \
|
||||||
# Install vendors (no scripts here; run later with console if needed)
|
# } > /usr/local/etc/php/conf.d/xdebug.ini
|
||||||
RUN --mount=type=cache,target=/tmp/composer \
|
|
||||||
|
ENV COMPOSER_CACHE_DIR=/tmp/composer
|
||||||
|
CMD ["php-fpm"]
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Production image (copies your app + installs deps + warms cache)
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
FROM base AS prod
|
||||||
|
ARG APP_ENV=prod
|
||||||
|
ENV APP_ENV=${APP_ENV}
|
||||||
|
ENV APP_DEBUG=0 \
|
||||||
|
DATABASE_DRIVER=sqlite \
|
||||||
|
DATABASE_SQLITE_PATH=/var/www/html/var/data/database.sqlite \
|
||||||
|
RUN_MIGRATIONS_ON_START=1
|
||||||
|
|
||||||
|
# Copy only composer manifests for layer caching
|
||||||
|
COPY composer.json composer.lock* symfony.lock* ./
|
||||||
|
|
||||||
|
# Install vendors (cached)
|
||||||
|
RUN --mount=type=cache,target=/tmp/composer \
|
||||||
if [ -f composer.json ]; then \
|
if [ -f composer.json ]; then \
|
||||||
composer install --no-dev --prefer-dist --no-interaction --no-progress --no-scripts; \
|
composer install --no-dev --prefer-dist --no-interaction --no-progress --no-scripts; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Copy the rest of the app
|
# Copy the rest of the app
|
||||||
COPY . /var/www/html
|
COPY . /var/www/html
|
||||||
|
|
||||||
# If Symfony console exists, finalize install & warm cache
|
# Finalize install & warm cache
|
||||||
RUN if [ -f bin/console ]; then \
|
RUN if [ -f bin/console ]; then \
|
||||||
set -ex; \
|
set -ex; \
|
||||||
composer dump-autoload --no-dev --optimize; \
|
composer dump-autoload --no-dev --optimize; \
|
||||||
php bin/console cache:clear --no-warmup; \
|
php bin/console cache:clear --no-warmup; \
|
||||||
php bin/console cache:warmup; \
|
php bin/console cache:warmup; \
|
||||||
mkdir -p var && chown -R www-data:www-data var; \
|
mkdir -p var var/data public/uploads; \
|
||||||
|
chown -R www-data:www-data var public/uploads; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
USER www-data
|
# Runtime web stack (nginx + supervisor) for a single immutable container
|
||||||
CMD ["php-fpm"]
|
RUN apk add --no-cache nginx supervisor curl
|
||||||
|
|
||||||
|
COPY docker/prod/nginx.conf /etc/nginx/http.d/default.conf
|
||||||
|
COPY docker/prod/supervisord.conf /etc/supervisor/conf.d/app.conf
|
||||||
|
COPY docker/prod/entrypoint.sh /entrypoint.sh
|
||||||
|
|
||||||
|
RUN chmod +x /entrypoint.sh \
|
||||||
|
&& mkdir -p /run/nginx /var/log/supervisor \
|
||||||
|
&& chown -R www-data:www-data /var/www/html
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
|
CMD ["supervisord", "-c", "/etc/supervisor/conf.d/app.conf"]
|
||||||
|
|
||||||
19
docker/prod/entrypoint.sh
Executable file
19
docker/prod/entrypoint.sh
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
if [ "${RUN_MIGRATIONS_ON_START:-1}" = "1" ] && [ -f bin/console ]; then
|
||||||
|
if [ "${DATABASE_DRIVER:-sqlite}" = "sqlite" ]; then
|
||||||
|
SQLITE_PATH="${DATABASE_SQLITE_PATH:-/var/www/html/var/data/database.sqlite}"
|
||||||
|
SQLITE_DIR=$(dirname "${SQLITE_PATH}")
|
||||||
|
mkdir -p "${SQLITE_DIR}"
|
||||||
|
if [ ! -f "${SQLITE_PATH}" ]; then
|
||||||
|
touch "${SQLITE_PATH}"
|
||||||
|
fi
|
||||||
|
chown -R www-data:www-data "${SQLITE_DIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
su-exec www-data php bin/console doctrine:migrations:migrate --no-interaction --allow-no-migration
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$@"
|
||||||
|
|
||||||
29
docker/prod/nginx.conf
Normal file
29
docker/prod/nginx.conf
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
server {
|
||||||
|
listen 8080;
|
||||||
|
server_name _;
|
||||||
|
root /var/www/html/public;
|
||||||
|
|
||||||
|
index index.php;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri /index.php$is_args$args;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ \.php$ {
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_pass 127.0.0.1:9000;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
||||||
|
fastcgi_param DOCUMENT_ROOT $realpath_root;
|
||||||
|
internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /healthz {
|
||||||
|
access_log off;
|
||||||
|
add_header Content-Type text/plain;
|
||||||
|
return 200 "OK";
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log /var/log/nginx/error.log;
|
||||||
|
access_log /var/log/nginx/access.log;
|
||||||
|
}
|
||||||
|
|
||||||
21
docker/prod/supervisord.conf
Normal file
21
docker/prod/supervisord.conf
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
logfile=/var/log/supervisor/supervisord.log
|
||||||
|
pidfile=/var/run/supervisord.pid
|
||||||
|
|
||||||
|
[program:php-fpm]
|
||||||
|
command=/usr/local/sbin/php-fpm --nodaemonize
|
||||||
|
autorestart=true
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
|
[program:nginx]
|
||||||
|
command=/usr/sbin/nginx -g "daemon off;"
|
||||||
|
autorestart=true
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
Reference in New Issue
Block a user