chore(docker): dockerize app, add workflow to push image on gitea registry
Some checks failed
Build and Push Docker Images / Build app image (push) Failing after 3m4s
Build and Push Docker Images / Build database image (push) Failing after 15s

This commit is contained in:
thibaud-leclere
2026-03-28 09:22:47 +01:00
parent a196fac6c6
commit 21b0f681be
12 changed files with 285 additions and 84 deletions

10
.dockerignore Normal file
View File

@@ -0,0 +1,10 @@
vendor/
var/
.env.local
.env.*.local
/public/assets/
/assets/vendor/
.idea/
.git/
.phpunit.cache/
phpunit.xml

33
.env
View File

@@ -1,38 +1,13 @@
# In all environments, the following files are loaded if they exist,
# the latter taking precedence over the former:
#
# * .env contains default values for the environment variables needed by the app
# * .env.local uncommitted file with local overrides
# * .env.$APP_ENV committed environment-specific defaults
# * .env.$APP_ENV.local uncommitted environment-specific overrides
#
# Real environment variables win over .env files.
#
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
# https://symfony.com/doc/current/configuration/secrets.html
#
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
###> symfony/framework-bundle ###
APP_ENV=dev APP_ENV=dev
APP_SECRET= APP_SECRET=
APP_SHARE_DIR=var/share APP_SHARE_DIR=var/share
###< symfony/framework-bundle ###
###> symfony/routing ###
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
DEFAULT_URI=http://localhost DEFAULT_URI=http://localhost
###< symfony/routing ###
###> symfony/messenger ###
# Choose one of the transports below
# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0 MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
###< symfony/messenger ###
###> symfony/mailer ###
MAILER_DSN=null://null MAILER_DSN=null://null
###< symfony/mailer ###
TMDB_API_TOKEN=
SERVER_NAME=

View File

@@ -1,4 +0,0 @@
###> symfony/framework-bundle ###
APP_SECRET=6a816d705e23f36b271f975881f32be0
###< symfony/framework-bundle ###

View File

@@ -0,0 +1,86 @@
name: Build and Push Docker Images
on:
push:
branches:
- main
jobs:
build-app:
name: Build app image
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Check if app image should be rebuilt
id: changed
run: |
# Rebuild if docker/app/ or any PHP/config source changed
CHANGED=$(git diff --name-only HEAD~1 HEAD | grep -E '^(docker/app/|src/|config/|templates/|migrations/|composer\.(json|lock)|symfony\.lock|\.env)' | wc -l)
echo "changed=$([ "$CHANGED" -gt 0 ] && echo true || echo false)" >> $GITHUB_OUTPUT
- name: Set up Docker Buildx
if: steps.changed.outputs.changed == 'true'
uses: docker/setup-buildx-action@v3
- name: Login to Gitea registry
if: steps.changed.outputs.changed == 'true'
uses: docker/login-action@v3
with:
registry: git.lclr.dev
username: ${{ gitea.actor }}
password: ${{ secrets.GITEA_TOKEN }}
- name: Build and push app
if: steps.changed.outputs.changed == 'true'
uses: docker/build-push-action@v6
with:
context: .
file: docker/app/Dockerfile
target: prod
push: true
tags: |
git.lclr.dev/thibaud-lclr/ltbxd-actorle/app:latest
git.lclr.dev/thibaud-lclr/ltbxd-actorle/app:${{ github.sha }}
cache-from: type=registry,ref=git.lclr.dev/thibaud-lclr/ltbxd-actorle/app:buildcache
cache-to: type=registry,ref=git.lclr.dev/thibaud-lclr/ltbxd-actorle/app:buildcache,mode=max
build-database:
name: Build database image
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Check if database image should be rebuilt
id: changed
run: |
CHANGED=$(git diff --name-only HEAD~1 HEAD | grep -q '^docker/database/' && echo true || echo false)
echo "changed=$CHANGED" >> $GITHUB_OUTPUT
- name: Set up Docker Buildx
if: steps.changed.outputs.changed == 'true'
uses: docker/setup-buildx-action@v3
- name: Login to Gitea registry
if: steps.changed.outputs.changed == 'true'
uses: docker/login-action@v3
with:
registry: git.lclr.dev
username: ${{ gitea.actor }}
password: ${{ secrets.GITEA_TOKEN }}
- name: Build and push database
if: steps.changed.outputs.changed == 'true'
uses: docker/build-push-action@v6
with:
context: docker/database
push: true
tags: |
git.lclr.dev/thibaud-lclr/ltbxd-actorle/database:latest
git.lclr.dev/thibaud-lclr/ltbxd-actorle/database:${{ github.sha }}
cache-from: type=registry,ref=git.lclr.dev/thibaud-lclr/ltbxd-actorle/database:buildcache
cache-to: type=registry,ref=git.lclr.dev/thibaud-lclr/ltbxd-actorle/database:buildcache,mode=max

61
Makefile Normal file
View File

@@ -0,0 +1,61 @@
REGISTRY := git.lclr.dev
SHELL := /bin/bash
.DEFAULT_GOAL := help
docker\:build: ## Build les images en local
docker compose build
docker\:push: ## Build et push les images vers le registry Gitea
docker compose build
docker compose push
docker\:pull: ## Pull les images depuis le registry Gitea
docker compose pull
docker\:login: ## Connexion au registry Gitea
docker login $(REGISTRY)
dev\:up: ## Démarre l'environnement de développement
docker compose up --build -d
dev\:down: ## Arrête l'environnement de développement
docker compose down
dev\:logs: ## Affiche les logs en temps réel
docker compose logs -f
dev\:shell: ## Ouvre un shell dans le conteneur app
docker compose exec app sh
prod\:up: ## Démarre en production (pull depuis le registry)
docker compose -f docker-compose.yaml pull
docker compose -f docker-compose.yaml up -d
prod\:down: ## Arrête la production
docker compose -f docker-compose.yaml down
db\:migrate: ## Exécute les migrations Doctrine
docker compose exec app php bin/console doctrine:migrations:migrate --no-interaction
db\:migration: ## Génère une nouvelle migration depuis les entités
docker compose exec app php bin/console doctrine:migrations:diff --no-interaction
db\:reset: ## Recrée la base et rejoue les migrations (⚠ perd les données)
docker compose exec app php bin/console doctrine:database:drop --force --no-interaction
docker compose exec app php bin/console doctrine:database:create --no-interaction
docker compose exec app php bin/console doctrine:migrations:migrate --no-interaction
symfony\:console: ## Lance une commande Symfony (ex: make symfony:console CMD="cache:clear")
docker compose exec app php bin/console $(CMD)
symfony\:cache-clear: ## Vide le cache Symfony
docker compose exec app php bin/console cache:clear
test: ## Lance les tests PHPUnit
docker compose exec app php bin/phpunit
help: ## Affiche cette aide
@grep -E '^[a-zA-Z_\\:-]+:.*## ' $(MAKEFILE_LIST) \
| awk 'BEGIN {FS = "## "} {gsub(/\\:/, ":", $$1); sub(/:[^:]*$$/, "", $$1); printf "\033[36m%-25s\033[0m %s\n", $$1, $$2}'

View File

@@ -1,18 +0,0 @@
services:
###> doctrine/doctrine-bundle ###
database:
ports:
- "5432"
###< doctrine/doctrine-bundle ###
###> symfony/mailer ###
mailer:
image: axllent/mailpit
ports:
- "1025"
- "8025"
environment:
MP_SMTP_AUTH_ACCEPT_ANY: 1
MP_SMTP_AUTH_ALLOW_INSECURE: 1
###< symfony/mailer ###

View File

@@ -1,27 +0,0 @@
services:
###> doctrine/doctrine-bundle ###
database:
image: postgres:${POSTGRES_VERSION:-16}-alpine
environment:
POSTGRES_DB: ${POSTGRES_DB:-app}
# You should definitely change the password in production
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-pwd}
POSTGRES_USER: ${POSTGRES_USER:-app}
healthcheck:
test: ["CMD", "pg_isready", "-d", "${POSTGRES_DB:-app}", "-U", "${POSTGRES_USER:-app}"]
timeout: 5s
retries: 5
start_period: 60s
volumes:
- database_data:/var/lib/postgresql/data:rw
# You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data!
# - ./docker/db/data:/var/lib/postgresql/data:rw
ports:
- "0.0.0.0:5432:5432"
###< doctrine/doctrine-bundle ###
volumes:
###> doctrine/doctrine-bundle ###
database_data:
###< doctrine/doctrine-bundle ###

View File

@@ -1,10 +1,10 @@
parameters: parameters:
postgres_version: "16" postgres_version: "%env(POSTGRES_VERSION)%"
postgres_host: "127.0.0.1" postgres_host: "%env(POSTGRES_HOST)%"
postgres_port: "5432" postgres_port: "%env(int:POSTGRES_PORT)%"
postgres_db: "app" postgres_db: "%env(POSTGRES_DB)%"
postgres_user: "app" postgres_user: "%env(POSTGRES_USER)%"
postgres_password: "pwd" postgres_password: "%env(POSTGRES_PASSWORD)%"
tmdb_host: "https://api.themoviedb.org/3" tmdb_host: "https://api.themoviedb.org/3"

View File

@@ -0,0 +1,22 @@
services:
app:
build:
context: .
dockerfile: docker/app/Dockerfile
target: dev
environment:
APP_ENV: dev
volumes:
- .:/app
- vendor:/app/vendor
ports:
- "80:80"
database:
ports:
- "0.0.0.0:5432:5432"
volumes:
vendor:

34
docker-compose.yaml Normal file
View File

@@ -0,0 +1,34 @@
services:
app:
build:
context: .
dockerfile: docker/app/Dockerfile
target: prod
image: git.lclr.dev/thibaud-lclr/ltbxd-actorle/app:latest
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- caddy_data:/data
- caddy_config:/config
depends_on:
database:
condition: service_healthy
database:
build:
context: docker/database
image: git.lclr.dev/thibaud-lclr/ltbxd-actorle/database:latest
healthcheck:
test: ["CMD", "pg_isready", "-d", "app", "-U", "app"]
timeout: 5s
retries: 5
start_period: 60s
volumes:
- database_data:/var/lib/postgresql/data:rw
volumes:
database_data:
caddy_data:
caddy_config:

54
docker/app/Dockerfile Normal file
View File

@@ -0,0 +1,54 @@
FROM dunglas/frankenphp:php8.4-alpine AS base
RUN install-php-extensions \
intl \
opcache \
pdo_pgsql \
zip
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /app
###
# Dev stage
###
FROM base AS dev
COPY composer.json composer.lock symfony.lock ./
RUN composer install --no-scripts --no-autoloader --prefer-dist
COPY . .
RUN composer dump-autoload
ENV APP_ENV=dev \
SERVER_NAME=":80" \
POSTGRES_HOST=database \
POSTGRES_PORT=5432 \
POSTGRES_VERSION=16 \
POSTGRES_DB=app \
POSTGRES_USER=app \
POSTGRES_PASSWORD=pwd
###
# Prod stage
###
FROM base AS prod
COPY composer.json composer.lock symfony.lock ./
RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist
COPY . .
RUN APP_ENV=prod composer dump-autoload --classmap-authoritative \
&& APP_ENV=prod composer run-script post-install-cmd \
&& chown -R www-data:www-data var/
ENV APP_ENV=prod \
SERVER_NAME=localhost \
POSTGRES_HOST=database \
POSTGRES_PORT=5432 \
POSTGRES_VERSION=16 \
POSTGRES_DB=app \
POSTGRES_USER=app \
POSTGRES_PASSWORD=pwd

View File

@@ -0,0 +1,8 @@
FROM postgres:16-alpine
ENV POSTGRES_DB=app \
POSTGRES_USER=app \
POSTGRES_PASSWORD=pwd
# Add custom initialization scripts if needed:
# COPY initdb/ /docker-entrypoint-initdb.d/