Optimized images and version configuration for dockerfiles

This commit is contained in:
Kevin Veen-Birkenbach 2025-05-26 13:06:21 +02:00
parent 9e19a050a6
commit b599a528b8
No known key found for this signature in database
GPG Key ID: 44D8F11FD62F878E
35 changed files with 210 additions and 45 deletions

View File

@ -6,7 +6,7 @@ services:
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
image: {{ applications[application_id].images.application }}
image: "{{ applications[application_id].images.akaunting }}"
build:
context: .
ports:

View File

@ -1,5 +1,5 @@
images:
application: "docker.io/akaunting/akaunting:latest"
akaunting: "docker.io/akaunting/akaunting:latest"
company_name: "{{primary_domain}}"
company_email: "{{users.administrator.email}}"
setup_admin_email: "{{users.administrator.email}}"

View File

@ -6,7 +6,7 @@ services:
application:
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
image: "{{ applications[application_id].images.application }}"
image: "{{ applications[application_id].images.baserow }}"
container_name: baserow-application
volumes:
- data:/baserow/data

View File

@ -1,5 +1,5 @@
images:
application: "baserow/baserow:latest"
baserow: "baserow/baserow:latest"
features:
matomo: true
css: true

View File

@ -1,9 +1,13 @@
- name: "Create (optional) '{{ docker_compose.files.dockerfile }}'"
template:
src: "{{ playbook_dir }}/roles/{{ role_name }}/templates/{{ template_name }}"
src: "{{ playbook_dir }}/roles/{{ role_name }}/templates/Dockerfile"
dest: "{{ docker_compose.files.dockerfile }}"
notify: docker compose project build and setup
ignore_errors: true
ignore_errors: false
register: create_dockerfile_result
failed_when:
- create_dockerfile_result is failed
- "'Could not find or access' not in create_dockerfile_result.msg"
- name: "Create (optional) '{{ docker_compose.files.env }}'"
template:
@ -13,7 +17,10 @@
force: yes
notify: docker compose project setup
register: env_template
ignore_errors: true
ignore_errors: false
failed_when:
- env_template is failed
- "'Could not find or access' not in env_template.msg"
- name: "Create (obligatoric) '{{ docker_compose.files.docker_compose }}'"
template:

View File

@ -3,7 +3,7 @@ services:
{% include 'roles/docker-central-database/templates/services/' + database_type + '.yml.j2' %}
web:
image: espocrm/espocrm:{{ applications[application_id].version }}
image: "{{ applications[application_id].images.espocrm }}"
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]
@ -15,7 +15,7 @@ services:
- data:/var/www/html
daemon:
image: espocrm/espocrm:{{ applications[application_id].version }}
image: "{{ applications[application_id].images.espocrm }}"
restart: {{docker_restart_policy}}
logging:
driver: journald
@ -25,7 +25,7 @@ services:
- data:/var/www/html
websocket:
image: espocrm/espocrm:{{ applications[application_id].version }}
image: "{{ applications[application_id].images.espocrm }}"
restart: {{docker_restart_policy}}
logging:
driver: journald

View File

@ -1,4 +1,5 @@
version: "latest"
images:
espocrm: "espocrm/espocrm:latest"
users:
administrator:
username: "{{ users.administrator.username }}"

View File

@ -3,7 +3,7 @@ services:
{% include 'roles/docker-central-database/templates/services/' + database_type + '.yml.j2' %}
application:
image: "friendica:{{applications.friendica.version}}"
image: "{{ applications[application_id].images.friendica }}"
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
volumes:
- html:/var/www/html

View File

@ -1,4 +1,5 @@
version: "latest"
images:
friendica: "friendica:latest"
features:
matomo: true
css: true

View File

@ -14,7 +14,7 @@ services:
# flag:
# celery -A funkwhale_api.taskapp worker -l INFO --concurrency=4
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
image: funkwhale/api:{{applications.funkwhale.version}}
image: "{{ applications[application_id].images.api }}"
command: celery -A funkwhale_api.taskapp worker -l INFO --concurrency={{celeryd_concurrency}}
environment:
- C_FORCE_ROOT=true
@ -26,14 +26,14 @@ services:
celerybeat:
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
image: funkwhale/api:{{applications.funkwhale.version}}
image: "{{ applications[application_id].images.api }}"
command: celery -A funkwhale_api.taskapp beat --pidfile= -l INFO
{% include 'templates/docker/container/depends-on-database-redis.yml.j2' %}
{% include 'templates/docker/container/networks.yml.j2' %}
api:
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
image: funkwhale/api:{{applications.funkwhale.version}}
image: "{{ applications[application_id].images.api }}"
volumes:
- "music:{{music_directory_path}}:ro"
- "data:{{media_root}}"
@ -45,7 +45,7 @@ services:
front:
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
image: funkwhale/front:{{applications.funkwhale.version}}
image: "{{ applications[application_id].images.front }}"
depends_on:
- api
environment:
@ -60,7 +60,7 @@ services:
typesense:
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
image: typesense/typesense:0.24.0
image: "{{ applications[application_id].images.typesense }}"
volumes:
- ./typesense/data:/data
command: --data-dir /data --enable-cors

View File

@ -1,4 +1,7 @@
version: "1.4.0"
images:
api: "funkwhale/api:1.4.0"
front: "funkwhale/front:1.4.0"
typesense: "typesense/typesense"
features:
matomo: true
css: true

View File

@ -1,4 +1,4 @@
# FusionDirectory
# FusionDirectory (DRAFT)
# Warning
This application isn't implemented yet

View File

@ -4,7 +4,7 @@ services:
application:
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
image: "gitea/gitea:{{applications.gitea.version}}"
image: "{{ applications[application_id].images.gitea }}"
ports:
- "127.0.0.1:{{ports.localhost.http[application_id]}}:3000"
- "{{ports.public.ssh[application_id]}}:22"

View File

@ -1,4 +1,5 @@
version: "latest" # Use latest docker image
images:
gitea: "gitea/gitea:latest"
configuration:
repository:
enable_push_create_user: True # Allow users to push local repositories to Gitea and have them automatically created for a user.

View File

@ -5,7 +5,7 @@ services:
{% include 'roles/docker-central-database/templates/services/' + database_type + '.yml.j2' %}
web:
image: "gitlab/gitlab-ee:{{applications.gitlab.version}}"
image: "{{ applications[application_id].images.gitlab }}"
hostname: '{{domains | get_domain(application_id)}}'
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
ports:

View File

@ -1,4 +1,5 @@
version: "latest"
images:
gitlab: "gitlab/gitlab-ee:latest"
features:
matomo: true
css: true

View File

@ -3,7 +3,7 @@ services:
{% include 'roles/docker-central-database/templates/services/' + database_type + '.yml.j2' %}
application:
image: "joomla:{{applications.joomla.version}}"
image: "{{ applications[application_id].images.joomla }}"
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
volumes:
- data:/var/www/html

View File

@ -1,4 +1,5 @@
version: "latest"
images:
joomla: "joomla:latest"
features:
matomo: true
css: true

View File

@ -3,7 +3,7 @@ services:
{% include 'roles/docker-central-database/templates/services/' + database_type + '.yml.j2' %}
application:
image: quay.io/keycloak/keycloak:{{applications.keycloak.version}}
image: "{{ applications[application_id].images.keycloak }}"
container_name: {{container_name}}
command: start {% if applications[application_id].import_realm | bool %}--import-realm{% endif %}
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}

View File

@ -1,4 +1,5 @@
version: "latest"
images:
keycloak: "quay.io/keycloak/keycloak:latest"
users:
administrator:
username: "{{users.administrator.username}}" # Administrator Username for Keycloak

View File

@ -4,7 +4,7 @@ services:
application:
container_name: {{ application_id }}
image: ghcr.io/ldapaccountmanager/lam:{{applications[application_id].version}}
image: "{{ applications[application_id].images.lam }}"
ports:
- 127.0.0.1:{{ports.localhost.http[application_id]}}:80
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}

View File

@ -1,4 +1,5 @@
version: "latest"
images:
lam: "ghcr.io/ldapaccountmanager/lam:latest"
oauth2_proxy:
application: application
port: 80

View File

@ -3,7 +3,7 @@ services:
{% include 'roles/docker-oauth2-proxy/templates/container.yml.j2' %}
application:
image: bitnami/openldap:{{ applications[application_id].version }}
image: "{{ applications[application_id].images.openldap }}"
container_name: {{ applications[application_id].hostname }}
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
{% if applications[application_id].network.public | bool or applications[application_id].network.local | bool %}

View File

@ -1,4 +1,5 @@
version: "latest"
images:
openldap: "bitnami/openldap:latest"
network:
local: True # Activates local network. Necessary for LDIF import routines
docker: True # Activates docker network to allow other docker containers to connect

View File

@ -4,7 +4,7 @@ services:
application:
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
image: listmonk/listmonk:{{applications.listmonk.version}}
image: "{{ applications[application_id].images.listmonk }}"
ports:
- "127.0.0.1:{{ports.localhost.http[application_id]}}:9000"
volumes:

View File

@ -1,3 +1,5 @@
images:
listmonk: "listmonk/listmonk:latest"
users:
administrator:
username: "{{users.administrator.username}}" # Listmonk administrator account username

View File

@ -5,7 +5,7 @@ services:
{% include 'roles/docker-central-database/templates/services/' + database_type + '.yml.j2' %}
web:
image: ghcr.io/mastodon/mastodon:{{applications.mastodon.version}}
image: "{{ applications[application_id].images.mastodon }}"
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
healthcheck:
@ -18,7 +18,7 @@ services:
{% include 'templates/docker/container/networks.yml.j2' %}
streaming:
image: ghcr.io/mastodon/mastodon-streaming:{{applications.mastodon.version}}
image: "{{ applications[application_id].images.streaming }}"
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
command: node ./streaming
healthcheck:
@ -29,7 +29,7 @@ services:
{% include 'templates/docker/container/networks.yml.j2' %}
sidekiq:
image: ghcr.io/mastodon/mastodon:{{applications.mastodon.version}}
image: "{{ applications[application_id].images.mastodon }}"
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
command: bundle exec sidekiq
{% include 'templates/docker/container/depends-on-database-redis.yml.j2' %}

View File

@ -1,4 +1,6 @@
version: "latest"
images:
mastodon: "ghcr.io/mastodon/mastodon:latest"
streaming: "ghcr.io/mastodon/mastodon-streaming:latest"
single_user_mode: false # Set true for initial setup
setup: false # Set true in inventory file to execute the setup and initializing procedures
credentials:

View File

@ -4,7 +4,7 @@ services:
application:
{% include 'roles/docker-compose/templates/services/base.yml.j2' %}
image: matomo:{{applications.matomo.version}}
image: "{{ applications[application_id].images.matomo }}"
ports:
- "127.0.0.1:{{ports.localhost.http.matomo}}:80"
volumes:

View File

@ -1,4 +1,5 @@
version: "latest"
images:
matomo: "matomo:latest"
features:
matomo: true
css: false

View File

@ -3,7 +3,7 @@ services:
{% include 'roles/docker-central-database/templates/services/' + database_type + '.yml.j2' %}
synapse:
image: matrixdotorg/synapse:{{applications[application_id].synapse.version}}
image: "{{ applications[application_id].images.synapse }}"
container_name: matrix-synapse
restart: {{docker_restart_policy}}
logging:
@ -36,7 +36,7 @@ services:
{% endif %}
{% include 'templates/docker/container/networks.yml.j2' %}
element:
image: vectorim/element-web:{{applications[application_id].element.version}}
image: "{{ applications[application_id].images.element }}"
container_name: matrix-element
restart: {{docker_restart_policy}}
volumes:

View File

@ -1,4 +1,7 @@
images:
synapse: "matrixdotorg/synapse:latest"
element: "vectorim/element-web:latest"
# Set bridges
users:
administrator:
username: "{{users.administrator.username}}" # Accountname of the matrix admin

View File

@ -0,0 +1,2 @@
# Todo
- Integrate OIDC as soon as possible

View File

@ -0,0 +1,49 @@
import unittest
from pathlib import Path
import yaml
class TestDeprecatedVersionKey(unittest.TestCase):
def test_version_key_deprecation(self):
"""
Checks all roles/docker-*/vars/configuration.yml for deprecated use of 'version'.
Warns if 'version' is set but 'images' is missing.
Prints warnings but does NOT fail the test.
"""
repo_root = Path(__file__).resolve().parent.parent.parent
roles_dir = repo_root / "roles"
warnings = []
for role_path in roles_dir.iterdir():
if not (role_path.is_dir() and role_path.name.startswith("docker-")):
continue
cfg_file = role_path / "vars" / "configuration.yml"
if not cfg_file.exists():
continue
try:
config = yaml.safe_load(cfg_file.read_text("utf-8")) or {}
except yaml.YAMLError as e:
print(f"YAML parse error in {cfg_file}: {e}")
continue
uses_version = 'version' in config
uses_images = 'images' in config
if uses_version and not uses_images:
warnings.append(
f"[DEPRECATION WARNING] {role_path.name}/vars/configuration.yml: "
f"'version:' is set, but 'images:' is missing. "
f"'version' is deprecated and must only be set if 'images' is present."
)
if warnings:
print("\n".join(warnings))
else:
print("No deprecated 'version:' keys found in docker roles without 'images:'.")
# Never fail, just warn
self.assertTrue(True)
if __name__ == "__main__":
unittest.main()

View File

@ -0,0 +1,88 @@
import unittest
import yaml
from pathlib import Path
import re
class TestDockerRoleImagesConfiguration(unittest.TestCase):
def test_images_keys_and_templates(self):
"""
For each docker-* role, check that:
- roles/docker-*/vars/configuration.yml contains 'images' as a dict with keys/values
- Each image key is referenced as:
image: "{{ applications[application_id].images.<key> }}"
in either roles/docker-*/templates/docker-compose.yml.j2 or env.j2
"""
repo_root = Path(__file__).resolve().parent.parent.parent
roles_dir = repo_root / "roles"
errors = []
warnings = []
for role_path in roles_dir.iterdir():
if not (role_path.is_dir() and role_path.name.startswith("docker-")):
continue
cfg_file = role_path / "vars" / "configuration.yml"
if not cfg_file.exists():
continue # No configuration to check
try:
config = yaml.safe_load(cfg_file.read_text("utf-8")) or {}
except yaml.YAMLError as e:
errors.append(f"{role_path.name}: YAML parse error: {e}")
continue
images = config.get("images")
if not images:
warnings.append(f"[WARNING] {role_path.name}: No 'images' key in configuration.yml")
continue
if not isinstance(images, dict):
errors.append(f"{role_path.name}: 'images' must be a dict in configuration.yml")
continue
for key, value in images.items():
if not key or not value or not isinstance(key, str) or not isinstance(value, str):
errors.append(f"{role_path.name}: images['{key}'] is invalid (must be non-empty string key and value)")
continue
# Improved regex: matches both ' and " and allows whitespace
pattern = (
r'image:\s*["\']\{\{\s*applications\[application_id\]\.images\.' + re.escape(key) + r'\s*\}\}["\']'
)
found = False
for tmpl_file in [
role_path / "templates" / "docker-compose.yml.j2",
role_path / "templates" / "env.j2"
]:
if tmpl_file.exists():
content = tmpl_file.read_text("utf-8")
if re.search(pattern, content):
found = True
break
if not found:
errors.append(
f"{role_path.name}: image key '{key}' is not referenced as "
f'image: \"{{{{ applications[application_id].images.{key} }}}}\" in docker-compose.yml.j2 or env.j2'
)
# OPTIONAL: Check if the image is available locally via docker images
# from shutil import which
# import subprocess
# if which("docker"):
# try:
# out = subprocess.check_output(
# ["docker", "images", "--format", "{{.Repository}}:{{.Tag}}"]
# ).decode()
# if value not in out:
# errors.append(f"{role_path.name}: Image '{value}' not found locally (optional check)")
# except Exception as e:
# errors.append(f"{role_path.name}: Error running 'docker images' (optional): {e}")
if warnings:
print("\nWarnings in docker role images configuration:\n" + "\n".join(warnings))
if errors:
self.fail("Errors in docker role images configuration:\n" + "\n".join(errors))
if __name__ == "__main__":
unittest.main()