diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3461183 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +vendor/ +var/ +.env.local +.env.*.local +/public/assets/ +/assets/vendor/ +.idea/ +.git/ +.phpunit.cache/ +phpunit.xml diff --git a/.env b/.env index e678897..27933eb 100644 --- a/.env +++ b/.env @@ -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_SECRET= 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 -###< 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 -###< symfony/messenger ### -###> symfony/mailer ### MAILER_DSN=null://null -###< symfony/mailer ### + +TMDB_API_TOKEN= + +SERVER_NAME= diff --git a/.env.dev b/.env.dev deleted file mode 100644 index 86cfa07..0000000 --- a/.env.dev +++ /dev/null @@ -1,4 +0,0 @@ - -###> symfony/framework-bundle ### -APP_SECRET=6a816d705e23f36b271f975881f32be0 -###< symfony/framework-bundle ### diff --git a/.gitea/workflows/docker.yml b/.gitea/workflows/docker.yml new file mode 100644 index 0000000..a3013d8 --- /dev/null +++ b/.gitea/workflows/docker.yml @@ -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 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c7848ee --- /dev/null +++ b/Makefile @@ -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}' + diff --git a/compose.override.yaml b/compose.override.yaml deleted file mode 100644 index 8dc54de..0000000 --- a/compose.override.yaml +++ /dev/null @@ -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 ### diff --git a/compose.yaml b/compose.yaml deleted file mode 100644 index 9d86ef4..0000000 --- a/compose.yaml +++ /dev/null @@ -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 ### diff --git a/config/parameters.yml b/config/parameters.yml index 24d5e21..3106ac1 100644 --- a/config/parameters.yml +++ b/config/parameters.yml @@ -1,10 +1,10 @@ parameters: - postgres_version: "16" - postgres_host: "127.0.0.1" - postgres_port: "5432" - postgres_db: "app" - postgres_user: "app" - postgres_password: "pwd" + postgres_version: "%env(POSTGRES_VERSION)%" + postgres_host: "%env(POSTGRES_HOST)%" + postgres_port: "%env(int:POSTGRES_PORT)%" + postgres_db: "%env(POSTGRES_DB)%" + postgres_user: "%env(POSTGRES_USER)%" + postgres_password: "%env(POSTGRES_PASSWORD)%" tmdb_host: "https://api.themoviedb.org/3" diff --git a/docker-compose.override.yaml b/docker-compose.override.yaml new file mode 100644 index 0000000..005628f --- /dev/null +++ b/docker-compose.override.yaml @@ -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: diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..aa3367c --- /dev/null +++ b/docker-compose.yaml @@ -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: diff --git a/docker/app/Dockerfile b/docker/app/Dockerfile new file mode 100644 index 0000000..89a8f37 --- /dev/null +++ b/docker/app/Dockerfile @@ -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 diff --git a/docker/database/Dockerfile b/docker/database/Dockerfile new file mode 100644 index 0000000..eb71c01 --- /dev/null +++ b/docker/database/Dockerfile @@ -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/