mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-09-07 18:57:12 +02:00
Compare commits
12 Commits
0a588023a7
...
00c99e58e9
Author | SHA1 | Date | |
---|---|---|---|
00c99e58e9 | |||
904040589e | |||
9f3d300bca | |||
9e253a2d09 | |||
49120b0dcf | |||
b6f91ab9d3 | |||
77e8e7ed7e | |||
32bc17e0c3 | |||
e294637cb6 | |||
577767bed6 | |||
e77f8da510 | |||
4738b263ec |
21
filter_plugins/volume_path.py
Normal file
21
filter_plugins/volume_path.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from ansible.errors import AnsibleFilterError
|
||||
|
||||
def docker_volume_path(volume_name: str) -> str:
|
||||
"""
|
||||
Returns the absolute filesystem path of a Docker volume.
|
||||
|
||||
Example:
|
||||
"akaunting_data" -> "/var/lib/docker/volumes/akaunting_data/_data/"
|
||||
"""
|
||||
if not volume_name or not isinstance(volume_name, str):
|
||||
raise AnsibleFilterError(f"Invalid volume name: {volume_name}")
|
||||
|
||||
return f"/var/lib/docker/volumes/{volume_name}/_data/"
|
||||
|
||||
class FilterModule(object):
|
||||
"""Docker volume path filters."""
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
"docker_volume_path": docker_volume_path,
|
||||
}
|
@@ -8,10 +8,10 @@
|
||||
path: "{{ docker_compose.directories.env }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
- name: "For '{{ application_id }}': Create {{database_env}}"
|
||||
- name: "For '{{ application_id }}': Create {{ database_env }}"
|
||||
template:
|
||||
src: "env/{{database_type}}.env.j2"
|
||||
dest: "{{database_env}}"
|
||||
src: "env/{{ database_type }}.env.j2"
|
||||
dest: "{{ database_env }}"
|
||||
notify: docker compose up
|
||||
when: not applications | get_app_conf(application_id, 'features.central_database', False)
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
# I don't know why this includes leads to that the application_id in vars/main.yml of the database role isn't used
|
||||
# This is the behaviour which I want, but I'm still wondering why ;)
|
||||
include_role:
|
||||
name: "svc-db-{{database_type}}"
|
||||
name: "svc-db-{{ database_type }}"
|
||||
when: applications | get_app_conf(application_id, 'features.central_database', False)
|
||||
|
||||
- name: "For '{{ application_id }}': Add Entry for Backup Procedure"
|
||||
|
@@ -5,10 +5,10 @@
|
||||
container_name: {{ application_id | get_entity_name }}-database
|
||||
logging:
|
||||
driver: journald
|
||||
image: mariadb
|
||||
image: {{ database_image }}:{{ database_version }}
|
||||
restart: {{ DOCKER_RESTART_POLICY }}
|
||||
env_file:
|
||||
- {{database_env}}
|
||||
- {{ database_env }}
|
||||
command: "--transaction-isolation=READ-COMMITTED --binlog-format=ROW"
|
||||
volumes:
|
||||
- database:/var/lib/mysql
|
||||
|
@@ -2,13 +2,13 @@
|
||||
|
||||
{% if not applications | get_app_conf(application_id, 'features.central_database', False) %}
|
||||
{{ database_host }}:
|
||||
image: postgres:{{ applications['svc-db-postgres'].version}}-alpine
|
||||
image: {{ database_image }}:{{ database_version }}
|
||||
container_name: {{ application_id | get_entity_name }}-database
|
||||
env_file:
|
||||
- {{database_env}}
|
||||
- {{ database_env }}
|
||||
restart: {{ DOCKER_RESTART_POLICY }}
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U {{ database_name }}"]
|
||||
test: ["CMD-SHELL", "pg_isready -U {{ database_username }}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 6
|
||||
|
@@ -1,20 +1,23 @@
|
||||
# Helper variables
|
||||
_dbtype: "{{ (database_type | d('') | trim) }}"
|
||||
_database_id: "{{ ('svc-db-' ~ _dbtype) if _dbtype else '' }}"
|
||||
_database_central_name: "{{ (applications | get_app_conf(_database_id, 'docker.services.' ~ _dbtype ~ '.name', False, '')) if _dbtype else '' }}"
|
||||
_database_consumer_id: "{{ database_application_id | d(application_id) }}"
|
||||
_database_consumer_entity_name: "{{ _database_consumer_id | get_entity_name }}"
|
||||
_database_central_enabled: "{{ (applications | get_app_conf(_database_consumer_id, 'features.central_database', False)) if _dbtype else False }}"
|
||||
_dbtype: "{{ (database_type | d('') | trim) }}"
|
||||
_database_id: "{{ ('svc-db-' ~ _dbtype) if _dbtype else '' }}"
|
||||
_database_central_name: "{{ (applications | get_app_conf(_database_id, 'docker.services.' ~ _dbtype ~ '.name', False, '')) if _dbtype else '' }}"
|
||||
_database_consumer_id: "{{ database_application_id | d(application_id) }}"
|
||||
_database_consumer_entity_name: "{{ _database_consumer_id | get_entity_name }}"
|
||||
_database_central_enabled: "{{ (applications | get_app_conf(_database_consumer_id, 'features.central_database', False)) if _dbtype else False }}"
|
||||
_database_default_version: "{{ applications | get_app_conf(_database_id, 'docker.services.' ~ _dbtype ~ '.version') }}"
|
||||
|
||||
# Definition
|
||||
|
||||
database_name: "{{ _database_consumer_entity_name }}"
|
||||
database_instance: "{{ _database_central_name if _database_central_enabled else database_name }}" # This could lead to bugs at dedicated database @todo cleanup
|
||||
database_host: "{{ _database_central_name if _database_central_enabled else 'database' }}" # This could lead to bugs at dedicated database @todo cleanup
|
||||
database_username: "{{ _database_consumer_entity_name }}"
|
||||
database_password: "{{ applications | get_app_conf(_database_consumer_id, 'credentials.database_password', true) }}"
|
||||
database_port: "{{ (ports.localhost.database[_database_id] | d('')) if _dbtype else '' }}"
|
||||
database_env: "{{ docker_compose.directories.env }}{{ database_type }}.env"
|
||||
database_url_jdbc: "jdbc:{{ database_type if database_type == 'mariadb' else 'postgresql' }}://{{ database_host }}:{{ database_port }}/{{ database_name }}"
|
||||
database_url_full: "{{ database_type }}://{{ database_username }}:{{ database_password }}@{{ database_host }}:{{ database_port }}/{{ database_name }}"
|
||||
database_volume: "{{ _database_consumer_entity_name ~ '_' if not _database_central_enabled }}{{ database_host }}"
|
||||
database_name: "{{ _database_consumer_entity_name }}"
|
||||
database_instance: "{{ _database_central_name if _database_central_enabled else database_name }}" # This could lead to bugs at dedicated database @todo cleanup
|
||||
database_host: "{{ _database_central_name if _database_central_enabled else 'database' }}" # This could lead to bugs at dedicated database @todo cleanup
|
||||
database_username: "{{ _database_consumer_entity_name }}"
|
||||
database_password: "{{ applications | get_app_conf(_database_consumer_id, 'credentials.database_password', true) }}"
|
||||
database_port: "{{ (ports.localhost.database[_database_id] | d('')) if _dbtype else '' }}"
|
||||
database_env: "{{ docker_compose.directories.env }}{{ database_type }}.env"
|
||||
database_url_jdbc: "jdbc:{{ database_type if database_type == 'mariadb' else 'postgresql' }}://{{ database_host }}:{{ database_port }}/{{ database_name }}"
|
||||
database_url_full: "{{ database_type }}://{{ database_username }}:{{ database_password }}@{{ database_host }}:{{ database_port }}/{{ database_name }}"
|
||||
database_volume: "{{ _database_consumer_entity_name ~ '_' if not _database_central_enabled }}{{ database_host }}"
|
||||
database_image: "{{ _dbtype }}"
|
||||
database_version: "{{ applications | get_app_conf( _database_consumer_id, 'docker.services.database.version', False, _database_default_version) }}"
|
||||
|
@@ -23,6 +23,6 @@ AKAUNTING_COMPANY_NAME: "{{ applications | get_app_conf(application_
|
||||
AKAUNTING_COMPANY_EMAIL: "{{ applications | get_app_conf(application_id, 'company.email') }}"
|
||||
AKAUNTING_ADMIN_EMAIL: "{{ applications | get_app_conf(application_id, 'setup_admin_email') }}"
|
||||
AKAUNTING_ADMIN_PASSWORD: "{{ applications | get_app_conf(application_id, 'credentials.setup_admin_password') }}"
|
||||
AKAUNTING_SETUP_MARKER: "/var/lib/docker/volumes/{{ AKAUNTING_VOLUME }}/_data/.akaunting_installed"
|
||||
AKAUNTING_SETUP_MARKER: "{{ [ (AKAUNTING_VOLUME | docker_volume_path), '.akaunting_installed' ] | path_join }}"
|
||||
AKAUNTING_APP_KEY: "{{ applications | get_app_conf(application_id, 'credentials.app_key') }}"
|
||||
AKAUNTING_CACHE_DRIVER: "{{ 'redis' if applications | get_app_conf(application_id, 'docker.services.redis.enabled') else 'file' }}"
|
@@ -23,6 +23,7 @@ server:
|
||||
- https://statsigapi.net
|
||||
- https://ip.bsky.app
|
||||
- https://video.bsky.app
|
||||
- https://bsky.app
|
||||
- wss://bsky.network
|
||||
- wss://*.bsky.app
|
||||
media-src:
|
||||
|
@@ -13,6 +13,9 @@
|
||||
path: "{{ BLUESKY_SOCIAL_APP_DIR }}/src/state/geolocation.tsx"
|
||||
regexp: '^\s*const\s+BAPP_CONFIG_URL\s*=\s*.*$'
|
||||
replace: "const BAPP_CONFIG_URL = '/config'"
|
||||
notify:
|
||||
- docker compose build
|
||||
- docker compose up
|
||||
|
||||
- name: Force IPCC_URL to same-origin /ipcc
|
||||
ansible.builtin.replace:
|
||||
path: "{{ BLUESKY_SOCIAL_APP_DIR }}/src/state/geolocation.tsx"
|
||||
regexp: '^\s*const\s+IPCC_URL\s*=\s*.*$'
|
||||
replace: "const IPCC_URL = '/ipcc'"
|
||||
|
@@ -13,4 +13,17 @@ location = /config {
|
||||
proxy_hide_header Access-Control-Allow-Origin;
|
||||
add_header Access-Control-Allow-Origin $scheme://$host always;
|
||||
add_header Vary Origin always;
|
||||
}
|
||||
}
|
||||
|
||||
location = /ipcc {
|
||||
proxy_pass https://bsky.app/ipcc;
|
||||
set $up_host "bsky.app";
|
||||
proxy_set_header Host $up_host;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
proxy_ssl_server_name on;
|
||||
|
||||
proxy_hide_header Access-Control-Allow-Origin;
|
||||
add_header Access-Control-Allow-Origin $scheme://$host always;
|
||||
add_header Vary Origin always;
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ This role builds and runs Bridgy Fed as a Docker container and (optionally) star
|
||||
Upstream docs & dev notes:
|
||||
- User & developer docs: https://fed.brid.gy and https://bridgy-fed.readthedocs.io/
|
||||
- Source: https://github.com/snarfed/bridgy-fed
|
||||
- Local run (reference): `flask run -p 8080` with APPVIEW_HOST/PLC_HOST/BGS_HOST/PDS_HOST set, and Datastore emulator envs
|
||||
- Local run (reference): `flask run -p 8080` with BRIDGY_APPVIEW_HOST/BRIDGY_PLC_HOST/BRIDGY_BGS_HOST/BRIDGY_PDS_HOST set, and Datastore emulator envs
|
||||
|
||||
## Features
|
||||
- Dockerized Flask app (gunicorn)
|
||||
|
@@ -17,18 +17,13 @@ server:
|
||||
docker:
|
||||
services:
|
||||
database:
|
||||
enabled: false
|
||||
emulator:
|
||||
enabled: true
|
||||
image: 'gcr.io/google.com/cloudsdktool/google-cloud-cli:latest'
|
||||
enabled: false
|
||||
application:
|
||||
image: "python"
|
||||
version: "3.12-bookworm"
|
||||
name: "web-app-bridgy-fed"
|
||||
|
||||
image: "python"
|
||||
version: "3.12-bookworm"
|
||||
name: "web-app-bridgy-fed"
|
||||
repository: "https://github.com/snarfed/bridgy-fed.git"
|
||||
branch: "main"
|
||||
rbac:
|
||||
roles: {}
|
||||
|
||||
source:
|
||||
repo: "https://github.com/snarfed/bridgy-fed.git"
|
||||
ref: "main"
|
||||
|
||||
|
@@ -3,7 +3,7 @@ ARG PY_BASE="python:3.12-bookworm"
|
||||
FROM ${PY_BASE} AS build
|
||||
|
||||
ARG BRIDGY_REPO_URL
|
||||
ARG BRIDGY_REPO_REF
|
||||
ARG BRIDGY_REPO_BRANCH
|
||||
|
||||
# System deps: git, build tools, curl for healthchecks, and gunicorn
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
@@ -11,7 +11,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
RUN git clone --depth=1 --branch "${BRIDGY_REPO_REF}" "${BRIDGY_REPO_URL}" ./
|
||||
RUN git clone --depth=1 --branch "${BRIDGY_REPO_BRANCH}" "${BRIDGY_REPO_URL}" ./
|
||||
|
||||
# Python deps
|
||||
RUN pip install --upgrade pip && \
|
||||
@@ -35,7 +35,7 @@ PY
|
||||
FROM ${PY_BASE}
|
||||
|
||||
ARG CONTAINER_PORT
|
||||
ENV PORT=${CONTAINER_PORT:-8080}
|
||||
ENV PORT=${CONTAINER_PORT}
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=build /app /app
|
||||
|
0
roles/web-app-bridgy-fed/schema/main.yml
Normal file
0
roles/web-app-bridgy-fed/schema/main.yml
Normal file
@@ -2,20 +2,8 @@
|
||||
include_role:
|
||||
name: sys-stk-full-stateless
|
||||
|
||||
- name: "Include front proxy for {{ container_hostname }}:{{ ports.localhost.http[application_id] }}"
|
||||
- name: "Include front proxy for {{ container_hostname}}:{{ ports.localhost.http[application_id] }}"
|
||||
include_role:
|
||||
name: sys-stk-front-proxy
|
||||
vars:
|
||||
domain: "{{ container_hostname }}"
|
||||
http_port: "{{ ports.localhost.http[application_id] }}"
|
||||
|
||||
- name: "Provide Dockerfile"
|
||||
copy:
|
||||
src: "Dockerfile"
|
||||
dest: "{{ docker_compose.directories.instance }}/Dockerfile"
|
||||
notify:
|
||||
- docker compose build
|
||||
|
||||
- name: "Run once marker"
|
||||
set_fact:
|
||||
run_once_web_app_bridgy_fed: true
|
||||
- include_tasks: utils/run_once.yml
|
@@ -1,20 +0,0 @@
|
||||
# Administration
|
||||
|
||||
## Local dev shell (inside container)
|
||||
```bash
|
||||
docker compose exec application bash
|
||||
```
|
||||
|
||||
## Logs
|
||||
```bash
|
||||
docker compose logs -f application
|
||||
docker compose logs -f emulator # if enabled
|
||||
```
|
||||
|
||||
## Notes
|
||||
- Upstream dev run example:
|
||||
```bash
|
||||
export APPVIEW_HOST=api.bsky.app PLC_HOST=plc.directory BGS_HOST=bsky.network PDS_HOST=atproto.brid.gy
|
||||
flask --debug run -p 8080
|
||||
```
|
||||
(We run via gunicorn in this role.)
|
@@ -6,38 +6,15 @@
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
BRIDGY_REPO_URL: "{{ BRIDGY_REPO_URL }}"
|
||||
BRIDGY_REPO_REF: "{{ BRIDGY_REPO_REF }}"
|
||||
BRIDGY_REPO_BRANCH: "{{ BRIDGY_REPO_BRANCH }}"
|
||||
CONTAINER_PORT: "{{ container_port | string }}"
|
||||
image: "{{ BRIDGY_IMAGE }}"
|
||||
image: "{{ BRIDGY_IMAGE }}:{{ BRIDGY_VERSION }}"
|
||||
container_name: "{{ BRIDGY_CONTAINER }}"
|
||||
hostname: "{{ container_hostname }}"
|
||||
env_file:
|
||||
- "{{ docker_compose.files.env }}"
|
||||
ports:
|
||||
- "127.0.0.1:{{ ports.localhost.http[application_id] }}:{{ container_port }}"
|
||||
- "127.0.0.1:{{ http_port }}:{{ container_port }}"
|
||||
{% include 'roles/docker-container/templates/healthcheck/tcp.yml.j2' %}
|
||||
{% include 'roles/docker-container/templates/base.yml.j2' %}
|
||||
depends_on:
|
||||
{% if EMULATOR_ENABLED | bool %}
|
||||
- emulator
|
||||
{% endif %}
|
||||
{% include 'roles/docker-container/templates/networks.yml.j2' %}
|
||||
|
||||
{% if EMULATOR_ENABLED | bool %}
|
||||
emulator:
|
||||
image: "{{ EMULATOR_IMAGE }}"
|
||||
container_name: "{{ BRIDGY_CONTAINER }}_emulator"
|
||||
command: >
|
||||
gcloud emulators firestore start
|
||||
--host-port=0.0.0.0:{{ EMULATOR_PORT }}
|
||||
--database-mode=datastore-mode
|
||||
--quiet
|
||||
ports:
|
||||
- "127.0.0.1:{{ EMULATOR_PORT }}:{{ EMULATOR_PORT }}"
|
||||
environment:
|
||||
- CLOUDSDK_CORE_DISABLE_PROMPTS=1
|
||||
restart: unless-stopped
|
||||
{% include 'roles/docker-container/templates/networks.yml.j2' %}
|
||||
{% endif %}
|
||||
|
||||
{% include 'roles/docker-compose/templates/networks.yml.j2' %}
|
||||
|
@@ -1,18 +1,13 @@
|
||||
# Flask / Gunicorn basics
|
||||
FLASK_ENV="{{ ENVIRONMENT | default('production') }}"
|
||||
FLASK_ENV="{{ ENVIRONMENT }}"
|
||||
PORT="{{ container_port }}"
|
||||
BRIDGY_ADMIN_EMAIL="{{ BRIDGY_ADMIN_EMAIL }}"
|
||||
|
||||
# Bridgy Fed upstream knobs (see README @ GitHub)
|
||||
APPVIEW_HOST="{{ APPVIEW_HOST }}"
|
||||
PLC_HOST="{{ PLC_HOST }}"
|
||||
BGS_HOST="{{ BGS_HOST }}"
|
||||
PDS_HOST="{{ PDS_HOST }}"
|
||||
|
||||
# Datastore emulator (Datastore-mode Firestore). If sidecar enabled, point here.
|
||||
GOOGLE_CLOUD_PROJECT="{{ EMULATOR_PROJECT_ID }}"
|
||||
DATASTORE_EMULATOR_HOST="{{ EMULATOR_ENABLED | ternary(EMULATOR_HOST_INTERNAL, '') }}"
|
||||
# DATASTORE_DATASET not needed when GOOGLE_CLOUD_PROJECT is set
|
||||
BRIDGY_APPVIEW_HOST="{{ BRIDGY_APPVIEW_HOST }}"
|
||||
BRIDGY_PLC_HOST="{{ BRIDGY_PLC_HOST }}"
|
||||
BRIDGY_BGS_HOST="{{ BRIDGY_BGS_HOST }}"
|
||||
BRIDGY_PDS_HOST="{{ BRIDGY_PDS_HOST }}"
|
||||
|
||||
# Optional:
|
||||
# GUNICORN_CMD_ARGS="--log-level info"
|
||||
|
@@ -1,27 +1,25 @@
|
||||
# General
|
||||
application_id: "web-app-bridgy-fed"
|
||||
application_id: "web-app-bridgy-fed"
|
||||
|
||||
# Container
|
||||
container_port: 8080
|
||||
domain: "{{ container_hostname }}"
|
||||
http_port: "{{ ports.localhost.http[application_id] }}"
|
||||
container_hostname: "{{ domains | get_domain(application_id) }}"
|
||||
|
||||
# App container
|
||||
BRIDGY_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.application.name') }}"
|
||||
BRIDGY_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.application.image') }}"
|
||||
#BRIDGY_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.application.version')}}"
|
||||
container_port: 8080
|
||||
container_hostname: "{{ domains | get_domain(application_id) }}"
|
||||
BRIDGY_ADMIN_EMAIL: "{{ users.administrator.email }}"
|
||||
BRIDGY_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.application.name') }}"
|
||||
BRIDGY_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.application.image') }}"
|
||||
BRIDGY_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.application.version')}}"
|
||||
|
||||
BRIDGY_ADMIN_EMAIL: "{{ users.administrator.email }}"
|
||||
|
||||
# Source
|
||||
BRIDGY_REPO_URL: "{{ applications | get_app_conf(application_id, 'source.repo') }}"
|
||||
BRIDGY_REPO_REF: "{{ applications | get_app_conf(application_id, 'source.ref') }}"
|
||||
|
||||
# Emulator sidecar (Datastore-mode Firestore)
|
||||
EMULATOR_ENABLED: "{{ applications | get_app_conf(application_id, 'docker.services.emulator.enabled') }}"
|
||||
EMULATOR_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.emulator.image') }}"
|
||||
EMULATOR_PORT: 8089
|
||||
EMULATOR_HOST_INTERNAL: "emulator:8089"
|
||||
EMULATOR_PROJECT_ID: "bridgy-federated-local"
|
||||
BRIDGY_REPO_URL: "{{ applications | get_app_conf(application_id, 'docker.services.application.repository') }}"
|
||||
BRIDGY_REPO_BRANCH: "{{ applications | get_app_conf(application_id, 'docker.services.application.branch') }}"
|
||||
|
||||
# Runtime env defaults for Bridgy Fed (see upstream README)
|
||||
APPVIEW_HOST: "api.bsky.app"
|
||||
PLC_HOST: "plc.directory"
|
||||
BGS_HOST: "bsky.network"
|
||||
PDS_HOST: "atproto.brid.gy"
|
||||
BRIDGY_APPVIEW_HOST: "api.bsky.app"
|
||||
BRIDGY_PLC_HOST: "plc.directory"
|
||||
BRIDGY_BGS_HOST: "bsky.network"
|
||||
BRIDGY_PDS_HOST: "atproto.brid.gy"
|
||||
|
@@ -1,55 +0,0 @@
|
||||
# Administration
|
||||
|
||||
## 🗑️ Cleanup (Remove Instance & Volumes)
|
||||
```bash
|
||||
cd {{ PATH_DOCKER_COMPOSE_INSTANCES }}magento/
|
||||
docker compose down
|
||||
docker volume rm MAGENTO_VOLUME
|
||||
cd {{ PATH_DOCKER_COMPOSE_INSTANCES }} && rm -vR {{ PATH_DOCKER_COMPOSE_INSTANCES }}magento
|
||||
```
|
||||
|
||||
## 🔍 Access Container Shell
|
||||
```bash
|
||||
docker compose exec -it application /bin/bash
|
||||
```
|
||||
|
||||
## 🧰 Common Magento CLI Tasks
|
||||
```bash
|
||||
# Reindex
|
||||
docker compose exec -it application bin/magento indexer:reindex
|
||||
|
||||
# Flush caches
|
||||
docker compose exec -it application bin/magento cache:flush
|
||||
|
||||
# Enable maintenance mode
|
||||
docker compose exec -it application bin/magento maintenance:enable
|
||||
|
||||
# Disable maintenance mode
|
||||
docker compose exec -it application bin/magento maintenance:disable
|
||||
|
||||
# Recompile DI (when switching modes)
|
||||
docker compose exec -it application bin/magento setup:di:compile
|
||||
|
||||
# Deploy static content (example for English/German)
|
||||
docker compose exec -it application bin/magento setup:static-content:deploy en_US de_DE -f
|
||||
```
|
||||
|
||||
## 🚀 Performance
|
||||
```bash
|
||||
# Production mode
|
||||
docker compose exec -it application bin/magento deploy:mode:set production
|
||||
|
||||
# Developer mode
|
||||
docker compose exec -it application bin/magento deploy:mode:set developer
|
||||
```
|
||||
|
||||
## 🔐 Admin User
|
||||
```bash
|
||||
# Create another admin (example)
|
||||
docker compose exec -it application bin/magento admin:user:create \
|
||||
--admin-user="admin2" \
|
||||
--admin-password="ChangeMe_12345" \
|
||||
--admin-email="{{ users.administrator.email }}" \
|
||||
--admin-firstname="Admin" \
|
||||
--admin-lastname="User"
|
||||
```
|
@@ -1,19 +0,0 @@
|
||||
# 🔼 Upgrade
|
||||
|
||||
> Always back up the database and the `MAGENTO_VOLUME` volume before upgrades.
|
||||
|
||||
1. Update images/versions in the application config (`roles/web-app-magento/config/main.yml` or inventory overrides).
|
||||
2. Recreate containers:
|
||||
```bash
|
||||
cd {{ PATH_DOCKER_COMPOSE_INSTANCES }}magento/
|
||||
docker compose pull
|
||||
docker compose up -d --remove-orphans
|
||||
```
|
||||
3. Run upgrade routines:
|
||||
```bash
|
||||
docker compose exec -it application bin/magento maintenance:enable
|
||||
docker compose exec -it application bin/magento setup:upgrade
|
||||
docker compose exec -it application bin/magento setup:di:compile
|
||||
docker compose exec -it application bin/magento cache:flush
|
||||
docker compose exec -it application bin/magento maintenance:disable
|
||||
```
|
@@ -2,7 +2,7 @@ features:
|
||||
matomo: true
|
||||
css: true
|
||||
desktop: true
|
||||
central_database: true # Use platform DB (recommended). If false, app-local DB container is enabled.
|
||||
central_database: false # Impossible to use central database due to strict database checking
|
||||
oidc: false # Magento SSO via OIDC requires extensions; not wired by default
|
||||
logout: true
|
||||
ldap: false
|
||||
@@ -15,17 +15,23 @@ server:
|
||||
- "shop.{{ PRIMARY_DOMAIN }}"
|
||||
aliases:
|
||||
- "magento.{{ PRIMARY_DOMAIN }}"
|
||||
|
||||
docker:
|
||||
services:
|
||||
application:
|
||||
image: "ghcr.io/alexcheng1982/docker-magento2"
|
||||
version: "2.4.6-p3"
|
||||
name: "magento"
|
||||
php:
|
||||
image: "markoshust/magento-php"
|
||||
version: "8.2-fpm"
|
||||
name: "magento-php"
|
||||
backup:
|
||||
no_stop_required: true
|
||||
nginx:
|
||||
image: "markoshust/magento-nginx"
|
||||
version: "latest"
|
||||
name: "magento-nginx"
|
||||
backup:
|
||||
no_stop_required: true
|
||||
database:
|
||||
enabled: true # Central DB recommended; if disabled, app-local DB is created
|
||||
enabled: true
|
||||
version: "11.4"
|
||||
redis:
|
||||
enabled: true
|
||||
search:
|
||||
|
@@ -1 +1,7 @@
|
||||
|
||||
credentials:
|
||||
adobe_public_key:
|
||||
description: "Adobe/Magento Marketplace Public Key"
|
||||
algorithm: "plain"
|
||||
adobe_private_key:
|
||||
description: "Adobe/Magento Marketplace Private Key"
|
||||
algorithm: "plain"
|
||||
|
@@ -2,17 +2,36 @@
|
||||
include_role:
|
||||
name: sys-stk-full-stateful
|
||||
vars:
|
||||
docker_compose_flush_handlers: true
|
||||
docker_compose_flush_handlers: true
|
||||
|
||||
- name: "Bootstrap Magento 2.4.8 source (exact working variant)"
|
||||
command: >
|
||||
docker exec
|
||||
-e COMPOSER_AUTH='{"http-basic":{"repo.magento.com":{"username":"{{ MAGENTO_REPO_PUBLIC_KEY }}","password":"{{ MAGENTO_REPO_PRIVATE_KEY }}"}}}'
|
||||
-e COMPOSER_HOME=/tmp/composer
|
||||
-e COMPOSER_CACHE_DIR=/tmp/composer/cache
|
||||
--user {{ MAGENTO_USER }}
|
||||
{{ MAGENTO_PHP_CONTAINER }} bash -lc 'set -e
|
||||
mkdir -p /tmp/composer/cache
|
||||
cd /var/www/html
|
||||
composer create-project --no-interaction --no-progress --repository-url=https://repo.magento.com/ magento/project-community-edition=2.4.8 .
|
||||
mkdir -p var pub/static pub/media app/etc
|
||||
chmod -R 775 var pub/static pub/media app/etc
|
||||
'
|
||||
args:
|
||||
creates: "{{ [ (MAGENTO_VOLUME | docker_volume_path), 'bin/magento' ] | path_join }}"
|
||||
|
||||
- name: "Run Magento setup:install (in container)"
|
||||
command: >
|
||||
docker compose exec -T application bash -lc "
|
||||
docker exec --user {{ MAGENTO_USER }} {{ MAGENTO_PHP_CONTAINER }} bash -lc "
|
||||
cd /var/www/html && bin/magento setup:install \
|
||||
--base-url='{{ MAGENTO_URL }}/' \
|
||||
--db-host=\"$MYSQL_HOST\" \
|
||||
--db-name=\"$MYSQL_DATABASE\" \
|
||||
--db-user=\"$MYSQL_USER\" \
|
||||
--db-password=\"$MYSQL_PASSWORD\" \
|
||||
--skip-db-validation \
|
||||
--db-engine=mysql \
|
||||
--search-engine='opensearch' \
|
||||
--opensearch-host=\"$OPENSEARCH_HOST\" \
|
||||
--opensearch-port=\"$OPENSEARCH_PORT_NUMBER\" \
|
||||
@@ -22,11 +41,11 @@
|
||||
--admin-user=\"$MAGENTO_ADMIN_USERNAME\" \
|
||||
--admin-password=\"$MAGENTO_ADMIN_PASSWORD\""
|
||||
args:
|
||||
chdir: "{{ docker_compose.directories.instance }}"
|
||||
creates: "{{ [ (MAGENTO_VOLUME | docker_volume_path), 'app/etc/env.php' ] | path_join }}"
|
||||
register: magento_install
|
||||
changed_when: >
|
||||
(magento_install.stdout is defined and
|
||||
('Magento installation complete' in magento_install.stdout
|
||||
or 'successfully installed' in magento_install.stdout))
|
||||
|
||||
- include_tasks: utils/run_once.yml
|
||||
- include_tasks: utils/run_once.yml
|
||||
|
@@ -1,27 +1,44 @@
|
||||
{% include 'roles/docker-compose/templates/base.yml.j2' %}
|
||||
|
||||
application:
|
||||
{% set container_port = 80 %}
|
||||
{% include 'roles/docker-container/templates/base.yml.j2' %}
|
||||
image: "{{ MAGENTO_IMAGE }}:{{ MAGENTO_VERSION }}"
|
||||
container_name: "{{ MAGENTO_CONTAINER }}"
|
||||
ports:
|
||||
- "127.0.0.1:{{ ports.localhost.http[application_id] }}:{{ container_port }}"
|
||||
nginx:
|
||||
{% set container_port = 8000 %}
|
||||
image: "{{ MAGENTO_NGINX_IMAGE }}:{{ MAGENTO_NGINX_VERSION }}"
|
||||
container_name: "{{ MAGENTO_NGINX_CONTAINER }}"
|
||||
environment:
|
||||
PHP_HOST: "php"
|
||||
PHP_PORT: "9000"
|
||||
depends_on:
|
||||
- php
|
||||
- search
|
||||
volumes:
|
||||
- "data:/var/www/html"
|
||||
{% include 'roles/docker-container/templates/depends_on/dmbs_excl.yml.j2' %}
|
||||
# search:
|
||||
# condition: service_healthy
|
||||
{% include 'roles/docker-container/templates/healthcheck/tcp.yml.j2' %}
|
||||
ports:
|
||||
- "127.0.0.1:{{ ports.localhost.http[application_id] }}:{{ container_port }}"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "nginx -t >/dev/null 2>&1 && { grep -q ':1F40' /proc/net/tcp || grep -q ':1F40' /proc/net/tcp6; }"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
{% include 'roles/docker-container/templates/networks.yml.j2' %}
|
||||
|
||||
php:
|
||||
{% include 'roles/docker-container/templates/base.yml.j2' %}
|
||||
image: "{{ MAGENTO_PHP_IMAGE }}:{{ MAGENTO_PHP_VERSION }}"
|
||||
container_name: "{{ MAGENTO_PHP_CONTAINER }}"
|
||||
volumes:
|
||||
- "data:/var/www/html"
|
||||
{% include 'roles/docker-container/templates/depends_on/dmbs_incl.yml.j2' %}
|
||||
search:
|
||||
condition: service_started
|
||||
{% include 'roles/docker-container/templates/networks.yml.j2' %}
|
||||
|
||||
search:
|
||||
{% set container_port = 9200 %}
|
||||
image: "{{ MAGENTO_SEARCH_IMAGE }}:{{ MAGENTO_SEARCH_VERSION }}"
|
||||
container_name: "{{ MAGENTO_SEARCH_NAME }}"
|
||||
container_name: "{{ MAGENTO_SEARCH_CONTAINER }}"
|
||||
{% include 'roles/docker-container/templates/base.yml.j2' %}
|
||||
environment:
|
||||
- discovery.type=single-node
|
||||
- plugins.security.disabled=true
|
||||
- OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m
|
||||
{% include 'roles/docker-container/templates/healthcheck/tcp.yml.j2' %}
|
||||
{% include 'roles/docker-container/templates/networks.yml.j2' %}
|
||||
@@ -31,3 +48,4 @@
|
||||
name: {{ MAGENTO_VOLUME }}
|
||||
|
||||
{% include 'roles/docker-compose/templates/networks.yml.j2' %}
|
||||
|
||||
|
@@ -3,14 +3,30 @@ application_id: "web-app-magento"
|
||||
database_type: "mariadb"
|
||||
|
||||
# Magento (application container)
|
||||
|
||||
## Meta
|
||||
MAGENTO_VOLUME: "{{ applications | get_app_conf(application_id, 'docker.volumes.data') }}"
|
||||
MAGENTO_USER: "app"
|
||||
|
||||
## Address
|
||||
MAGENTO_DOMAIN: "{{ domains | get_domain(application_id) }}"
|
||||
MAGENTO_URL: "{{ domains | get_url(application_id, WEB_PROTOCOL) }}"
|
||||
MAGENTO_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.application.version') }}"
|
||||
MAGENTO_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.application.image') }}"
|
||||
MAGENTO_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.application.name') }}"
|
||||
MAGENTO_VOLUME: "{{ applications | get_app_conf(application_id, 'docker.volumes.data') }}"
|
||||
|
||||
# Search (OpenSearch)
|
||||
## Search (OpenSearch)
|
||||
MAGENTO_SEARCH_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.search.version') }}"
|
||||
MAGENTO_SEARCH_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.search.image') }}"
|
||||
MAGENTO_SEARCH_NAME: "{{ applications | get_app_conf(application_id, 'docker.services.search.name') }}"
|
||||
MAGENTO_SEARCH_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.search.name') }}"
|
||||
|
||||
## PHP
|
||||
MAGENTO_PHP_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.php.version') }}"
|
||||
MAGENTO_PHP_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.php.image') }}"
|
||||
MAGENTO_PHP_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.php.name') }}"
|
||||
|
||||
## NGINX
|
||||
MAGENTO_NGINX_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.nginx.version') }}"
|
||||
MAGENTO_NGINX_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.nginx.image') }}"
|
||||
MAGENTO_NGINX_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.nginx.name') }}"
|
||||
|
||||
## Credentials
|
||||
MAGENTO_REPO_PUBLIC_KEY: "{{ applications | get_app_conf(application_id, 'credentials.adobe_public_key') }}"
|
||||
MAGENTO_REPO_PRIVATE_KEY: "{{ applications | get_app_conf(application_id, 'credentials.adobe_private_key') }}"
|
||||
|
@@ -6,7 +6,13 @@
|
||||
LOCAL_DOMAIN={{ domains | get_domain(application_id) }}
|
||||
ALTERNATE_DOMAINS="{{ domains['web-app-mastodon'][1:] | join(',') }}"
|
||||
SINGLE_USER_MODE={{ applications | get_app_conf(application_id, 'single_user_mode') }}
|
||||
ALLOWED_PRIVATE_ADDRESSES={{ MASTODON_ALLOWED_PRIVATE_ADDRESSES }}
|
||||
ALLOWED_PRIVATE_ADDRESSES="{{ MASTODON_ALLOWED_PRIVATE_ADDRESSES }}"
|
||||
|
||||
# Debug
|
||||
{% if MODE_DEBUG | bool %}
|
||||
RAILS_LOG_LEVEL=debug
|
||||
DEBUG=*
|
||||
{% endif %}
|
||||
|
||||
# Credentials
|
||||
|
||||
|
@@ -28,8 +28,8 @@ class TestTreeIncludeRoleDependencies(unittest.TestCase):
|
||||
"sys-ctl-hlth-csp",
|
||||
"svc-db-postgres",
|
||||
"svc-db-mysql",
|
||||
"axb", # für a{{database_type}}b → a*b
|
||||
"ayyb", # für a{{database_type}}b → a*b
|
||||
"axb", # für a{{ database_type }}b → a*b
|
||||
"ayyb", # für a{{ database_type }}b → a*b
|
||||
"literal-role", # für reinen Literalnamen
|
||||
]
|
||||
for r in self.roles_to_create:
|
||||
@@ -46,15 +46,15 @@ class TestTreeIncludeRoleDependencies(unittest.TestCase):
|
||||
|
||||
- name: Pattern with literal + var suffix
|
||||
include_role:
|
||||
name: "svc-db-{{database_type}}"
|
||||
name: "svc-db-{{ database_type }}"
|
||||
|
||||
- name: Pattern with literal prefix/suffix around var
|
||||
include_role:
|
||||
name: "a{{database_type}}b"
|
||||
name: "a{{ database_type }}b"
|
||||
|
||||
- name: Pure variable only (should be ignored)
|
||||
include_role:
|
||||
name: "{{database_type}}"
|
||||
name: "{{ database_type }}"
|
||||
|
||||
- name: Pure literal include
|
||||
include_role:
|
||||
@@ -115,10 +115,10 @@ class TestTreeIncludeRoleDependencies(unittest.TestCase):
|
||||
expected = sorted([
|
||||
"sys-ctl-hlth-webserver", # aus loop
|
||||
"sys-ctl-hlth-csp", # aus loop
|
||||
"svc-db-postgres", # aus svc-db-{{database_type}}
|
||||
"svc-db-mysql", # aus svc-db-{{database_type}}
|
||||
"axb", # aus a{{database_type}}b
|
||||
"ayyb", # aus a{{database_type}}b
|
||||
"svc-db-postgres", # aus svc-db-{{ database_type }}
|
||||
"svc-db-mysql", # aus svc-db-{{ database_type }}
|
||||
"axb", # aus a{{ database_type }}b
|
||||
"ayyb", # aus a{{ database_type }}b
|
||||
"literal-role", # reiner Literalname
|
||||
])
|
||||
|
||||
@@ -129,8 +129,8 @@ class TestTreeIncludeRoleDependencies(unittest.TestCase):
|
||||
)
|
||||
self.assertEqual(deps, expected, "include_role dependencies mismatch")
|
||||
|
||||
# Sicherstellen, dass der pure Variable-Name "{{database_type}}" NICHT aufgenommen wurde
|
||||
self.assertNotIn("{{database_type}}", deps, "pure variable include should be ignored")
|
||||
# Sicherstellen, dass der pure Variable-Name "{{ database_type }}" NICHT aufgenommen wurde
|
||||
self.assertNotIn("{{ database_type }}", deps, "pure variable include should be ignored")
|
||||
|
||||
# Sicherstellen, dass im Original-meta der Producer-Role nichts geschrieben wurde
|
||||
original_tree_path = os.path.join(self.producer_path, "meta", "tree.json")
|
||||
|
Reference in New Issue
Block a user