init Commit

This commit is contained in:
Andreas Martin
2026-01-19 12:27:03 +01:00
commit 4bbffd8a3d
6 changed files with 317 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
build/*
files/image_digests.yml
.vault-pass

140
ansible.cfg Normal file
View File

@@ -0,0 +1,140 @@
[defaults]
#inventory = /etc/ansible/hosts
inventory = inventory.yaml
#library = ~/.ansible/plugins/modules:/usr/share/ansible/plugins/modules
#module_utils = ~/.ansible/plugins/module_utils:/usr/share/ansible/plugins/module_utils
#remote_tmp = ~/.ansible/tmp
#local_tmp = ~/.ansible/tmp
#forks = 5
#poll_interval = 0.001
#ask_pass = False
#transport = smart
host_key_checking = False
remote_user = root
# private_key_file = ssh/ssh_deploy_private
vault_password_file = .vault-pass
[inventory]
# List of enabled inventory plugins and the order in which they are used.
#enable_plugins = host_list, script, auto, yaml, ini, toml
# Ignore these extensions when parsing a directory as inventory source
#ignore_extensions = .pyc, .pyo, .swp, .bak, ~, .rpm, .md, .txt, ~, .orig, .ini, .cfg, .retry
# ignore files matching these patterns when parsing a directory as inventory source
#ignore_patterns=
# If 'True' unparsed inventory sources become fatal errors, otherwise they are warnings.
#unparsed_is_failed = False
[privilege_escalation]
#become = False
#become_method = sudo
#become_ask_pass = False
## Connection Plugins ##
# Settings for each connection plugin go under a section titled '[[plugin_name]_connection]'
# To view available connection plugins, run ansible-doc -t connection -l
# To view available options for a connection plugin, run ansible-doc -t connection [plugin_name]
# https://docs.ansible.com/ansible/latest/plugins/connection.html
[paramiko_connection]
#record_host_keys=False
#pty = False
#look_for_keys = False
#host_key_auto_add = True
[ssh_connection]
#ssh_args = -F ssh/config
#ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s
#control_path_dir = ~/.ansible/cp
#control_path =
#pipelining = False
#scp_if_ssh = smart
#transfer_method = smart
#sftp_batch_mode = False
#usetty = True
#retries = 3
[persistent_connection]
#connect_timeout = 30
#command_timeout = 30
[sudo_become_plugin]
#flags = -H -S -n
#user = root
[selinux]
# file systems that require special treatment when dealing with security context
# the default behaviour that copies the existing context or uses the user default
# needs to be changed to use the file system dependent context.
#special_context_filesystems=fuse,nfs,vboxsf,ramfs,9p,vfat
# Set this to True to allow libvirt_lxc connections to work without SELinux.
#libvirt_lxc_noseclabel = False
[colors]
#highlight = white
#verbose = blue
#warn = bright purple
#error = red
#debug = dark gray
#deprecate = purple
#skip = cyan
#unreachable = red
#ok = green
#changed = yellow
#diff_add = green
#diff_remove = red
#diff_lines = cyan
[diff]
# Always print diff when running ( same as always running with -D/--diff )
#always = False
# Set how many context lines to show in diff
#context = 3
[galaxy]
# Controls whether the display wheel is shown or not
#display_progress=
# Validate TLS certificates for Galaxy server
#ignore_certs = False
# Role or collection skeleton directory to use as a template for
# the init action in ansible-galaxy command
#role_skeleton=
# Patterns of files to ignore inside a Galaxy role or collection
# skeleton directory
#role_skeleton_ignore="^.git$", "^.*/.git_keep$"
# Galaxy Server URL
#server=https://galaxy.ansible.com
# A list of Galaxy servers to use when installing a collection.
#server_list=automation_hub, release_galaxy
# Server specific details which are mentioned in server_list
#[galaxy_server.automation_hub]
#url=https://cloud.redhat.com/api/automation-hub/
#auth_url=https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token
#token=my_ah_token
#
#[galaxy_server.release_galaxy]
#url=https://galaxy.ansible.com/
#token=my_token

122
build.yml Normal file
View File

@@ -0,0 +1,122 @@
---
- name: Lese Docker-Compose Images und erstelle Digest-Datei
hosts: localhost
gather_facts: false
vars:
compose_file: "files/docker-compose.yml"
digest_file: "files/image_digests.yml"
target_arch: "amd64"
tasks:
- name: Prüfe, ob docker-compose.yml existiert
ansible.builtin.stat:
path: "{{ compose_file }}"
register: compose_stat
failed_when: not compose_stat.stat.exists
- name: Lese docker-compose.yml
ansible.builtin.include_vars:
file: "{{ compose_file }}"
name: compose_data
- name: Extrahiere Service-Namen und Images
ansible.builtin.set_fact:
service_images: "{{ compose_data.services | dict2items }}"
- name: Zeige gefundene Services und Images
ansible.builtin.debug:
msg: "Service: {{ item.key }} → Image: {{ item.value.image }}"
loop: "{{ service_images }}"
when: item.value.image is defined
- name: Hole Manifest-Liste für jedes Image
ansible.builtin.command: >
skopeo inspect docker://{{ item.value.image }} --raw
register: manifests
loop: "{{ service_images }}"
when: item.value.image is defined
changed_when: false
failed_when: false
- name: Extrahiere amd64-Digest für jedes Image
ansible.builtin.set_fact:
service_digests: "{{ service_digests | default({}) | combine({item.item.key: digest_info}) }}"
loop: "{{ manifests.results }}"
when:
- item.item.value.image is defined
- item.rc == 0
- digest != 'N/A'
vars:
manifest_json: "{{ item.stdout | from_json }}"
image_name: "{{ item.item.value.image.split(':')[0] }}"
digest: >-
{%- if manifest_json.manifests is defined -%}
{%- set ns = namespace(found='') -%}
{%- for m in manifest_json.manifests -%}
{%- if m.platform.architecture == target_arch and m.platform.os == 'linux' -%}
{%- set ns.found = m.digest -%}
{%- endif -%}
{%- endfor -%}
{{ ns.found if ns.found else 'N/A' }}
{%- elif manifest_json.config is defined and manifest_json.config.digest is defined -%}
{{ manifest_json.config.digest }}
{%- else -%}
N/A
{%- endif -%}
digest_info:
image: "{{ image_name }}@{{ digest }}"
- name: Zeige Service-Digest-Mapping
ansible.builtin.debug:
msg: "Service: {{ item.key }} → Image mit Digest: {{ item.value.image }}"
loop: "{{ service_digests | dict2items }}"
when: service_digests is defined
- name: Erstelle image_digests.yml
ansible.builtin.copy:
content: |
# Automatisch generiert von Ansible
# Verwendung: docker-compose -f docker-compose.yml -f image_digests.yml up -d
services:
{% for service_name, service_config in service_digests.items() %}
{{ service_name }}:
image: {{ service_config.image }}
{% endfor %}
dest: "{{ digest_file }}"
when: service_digests is defined and service_digests | length > 0
- name: Zeige Erfolgsmeldung
ansible.builtin.debug:
msg: |
✅ Digest-Datei wurde erstellt: {{ digest_file }}
Verwendung:
docker-compose -f {{ compose_file }} -f {{ digest_file }} up -d
Services mit Digests:
{% for service_name, service_config in service_digests.items() %}
- {{ service_name }}: {{ service_config.image }}
{% endfor %}
when: service_digests is defined and service_digests | length > 0
- name: Warnung, falls keine Digests gefunden wurden
ansible.builtin.debug:
msg: "⚠️ Keine gültigen Digests für {{ target_arch }} gefunden!"
when: service_digests is not defined or service_digests | length == 0
# create compose config
- name: Erstelle Docker Compose Konfigurationsdatei
ansible.builtin.shell: |
test -d build || mkdir build &&
docker compose -f files/docker-compose.yml -f files/image_digests.yml config
register: compose_config
- name: Speichere Docker Compose Konfigurationsdatei
ansible.builtin.copy:
content: "{{ compose_config.stdout }}"
dest: build/docker-compose.yml
backup: true
mode: '0644'
...

12
deploy.yml Normal file
View File

@@ -0,0 +1,12 @@
---
- name: deploy Docker-Compose
hosts: localhost
gather_facts: no
tasks:
- name: Docker compose up
community.docker.docker_compose_v2:
project_src: build
state: present
...

36
files/docker-compose.yml Normal file
View File

@@ -0,0 +1,36 @@
# compose.yml
services:
traefik:
image: traefik:v3.6.4
container_name: traefik
command:
# API und Dashboard aktivieren
- "--api.insecure=true"
- "--api.dashboard=true"
# Docker Provider aktivieren
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
# Entrypoints definieren
- "--entrypoints.web.address=:80"
ports:
- "80:80" # HTTP
- "8080:8080" # Traefik Dashboard
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- traefik-net
whoami:
image: traefik/whoami
container_name: whoami
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"
- "traefik.http.routers.whoami.entrypoints=web"
networks:
- traefik-net
networks:
traefik-net:
name: traefik-net

4
inventory.yaml Normal file
View File

@@ -0,0 +1,4 @@
all:
hosts:
localhost:
ansible_connection: local