commit 63aa0658ef05be08c368d75145243ef764b3f08a Author: Matteo Basile Date: Mon May 4 11:51:13 2026 +0200 feat(ansible): add semaphore docker splash demo with dagster config diff --git a/ansible-semaphore-docker-demo/README.md b/ansible-semaphore-docker-demo/README.md new file mode 100644 index 0000000..5f998af --- /dev/null +++ b/ansible-semaphore-docker-demo/README.md @@ -0,0 +1,72 @@ +# SemaphoreUI Docker Splash Demo + +Demo Ansible molto semplice, pensata per essere eseguita da SemaphoreUI: +- `test.yml`: verifica connettivita e prerequisiti +- `deploy.yml`: deploy di un container Nginx Docker con pagina HTML custom +- `undeploy.yml`: rimozione container e cleanup + +## Struttura + +```text +ansible-semaphore-docker-demo/ + ansible.cfg + inventory + requirements.yml + deploy.yml + test.yml + undeploy.yml + group_vars/ + all.yml + secrets.yml + roles/ + splash/ + tasks/main.yml + templates/index.html.j2 + templates/nginx.conf.j2 + semaphore_dagster_config.example.yml +``` + +## Prerequisiti host target + +- Linux con accesso SSH +- Privilegi sudo/root +- Debian/Ubuntu (nel playbook installo `docker.io` e `python3-docker`) + +## Uso locale rapido + +```bash +cd ansible-semaphore-docker-demo +ansible-galaxy collection install -r requirements.yml +ansible-playbook -i inventory test.yml +ansible-playbook -i inventory deploy.yml +ansible-playbook -i inventory undeploy.yml +``` + +## Accesso app + +Dopo il deploy: +- `http://:8090` +- healthcheck: `http://:8090/health` + +## Variabili principali + +In `group_vars/all.yml`: +- `app_port` +- `greeting_message` +- `container_name` +- `nginx_version` +- `accent_color` +- `secondary_color` + +In `group_vars/secrets.yml`: +- `app_secret` +- `release_id` + +Per produzione: cifra `group_vars/secrets.yml` con Ansible Vault. + +## SemaphoreUI + +Per bootstrap automatico con il tuo DAG, usa il file: +- `semaphore_dagster_config.example.yml` + +Basta aggiornare URL Semaphore, token API, project ID, repo URL e inventory content. diff --git a/ansible-semaphore-docker-demo/ansible.cfg b/ansible-semaphore-docker-demo/ansible.cfg new file mode 100644 index 0000000..bb84225 --- /dev/null +++ b/ansible-semaphore-docker-demo/ansible.cfg @@ -0,0 +1,20 @@ +[defaults] +inventory = ./inventory +host_key_checking = False +stdout_callback = default +callback_result_format = yaml +force_color = True +retry_files_enabled = False +gathering = smart +roles_path = ./roles + +[privilege_escalation] +become = True +become_method = sudo +become_user = root +become_ask_pass = False + +[ssh_connection] +timeout = 30 +pipelining = True +control_path = /tmp/ansible-ssh-%%h-%%p-%%r diff --git a/ansible-semaphore-docker-demo/deploy.yml b/ansible-semaphore-docker-demo/deploy.yml new file mode 100644 index 0000000..200a94e --- /dev/null +++ b/ansible-semaphore-docker-demo/deploy.yml @@ -0,0 +1,44 @@ +--- +- name: Deploy Docker splash app via Nginx + hosts: webservers + become: yes + + vars_files: + - group_vars/all.yml + - group_vars/secrets.yml + + pre_tasks: + - name: Installa pacchetti necessari (Debian/Ubuntu) + ansible.builtin.apt: + name: + - docker.io + - python3-docker + state: present + update_cache: yes + when: ansible_os_family == 'Debian' + + - name: Avvia e abilita Docker + ansible.builtin.service: + name: docker + state: started + enabled: yes + + roles: + - role: splash + + post_tasks: + - name: Verifica endpoint health + ansible.builtin.uri: + url: "http://localhost:{{ app_port }}/health" + status_code: 200 + register: healthcheck + retries: 10 + delay: 2 + until: healthcheck.status == 200 + + - name: Output finale + ansible.builtin.debug: + msg: + - "Deploy completato" + - "URL: http://{{ ansible_host }}:{{ app_port }}" + - "Container: {{ container_name }}" diff --git a/ansible-semaphore-docker-demo/group_vars/all.yml b/ansible-semaphore-docker-demo/group_vars/all.yml new file mode 100644 index 0000000..9358ad8 --- /dev/null +++ b/ansible-semaphore-docker-demo/group_vars/all.yml @@ -0,0 +1,17 @@ +--- +# Docker image settings +nginx_image: nginx +nginx_version: "1.27-alpine" +container_name: semaphore-splash + +# App settings +app_environment: production +app_port: 8090 +greeting_message: "Ciao dal Demo SemaphoreUI" +accent_color: "#0ea5a4" +secondary_color: "#f97316" +remove_image: false + +# Nginx tuning +nginx_worker_processes: auto +nginx_worker_connections: 1024 diff --git a/ansible-semaphore-docker-demo/group_vars/secrets.yml b/ansible-semaphore-docker-demo/group_vars/secrets.yml new file mode 100644 index 0000000..d8ec8be --- /dev/null +++ b/ansible-semaphore-docker-demo/group_vars/secrets.yml @@ -0,0 +1,5 @@ +--- +# Per demo: valori in chiaro. +# In produzione cifra questo file con ansible-vault. +app_secret: "demo-secret-change-me" +release_id: "v1" diff --git a/ansible-semaphore-docker-demo/inventory b/ansible-semaphore-docker-demo/inventory new file mode 100644 index 0000000..d316246 --- /dev/null +++ b/ansible-semaphore-docker-demo/inventory @@ -0,0 +1,11 @@ +[webservers] +# Sostituisci con il tuo host reale +server1 ansible_host=XXX.XXX.XXX.XXX ansible_user=root + +[webservers:vars] +ansible_python_interpreter=/usr/bin/python3 +# In SemaphoreUI configura la chiave SSH nella sezione Key, +# quindi normalmente non serve impostare ansible_ssh_private_key_file qui. + +[all:vars] +ansible_connection=ssh diff --git a/ansible-semaphore-docker-demo/requirements.yml b/ansible-semaphore-docker-demo/requirements.yml new file mode 100644 index 0000000..3b6b63f --- /dev/null +++ b/ansible-semaphore-docker-demo/requirements.yml @@ -0,0 +1,4 @@ +--- +collections: + - name: community.docker + version: ">=3.0.0" diff --git a/ansible-semaphore-docker-demo/roles/splash/tasks/main.yml b/ansible-semaphore-docker-demo/roles/splash/tasks/main.yml new file mode 100644 index 0000000..1b8dc22 --- /dev/null +++ b/ansible-semaphore-docker-demo/roles/splash/tasks/main.yml @@ -0,0 +1,48 @@ +--- +- name: Crea cartella app + ansible.builtin.file: + path: /opt/semaphore-splash + state: directory + mode: '0755' + +- name: Render index HTML + ansible.builtin.template: + src: index.html.j2 + dest: /opt/semaphore-splash/index.html + mode: '0644' + +- name: Render config Nginx + ansible.builtin.template: + src: nginx.conf.j2 + dest: /opt/semaphore-splash/nginx.conf + mode: '0644' + +- name: Ferma eventuale container precedente + community.docker.docker_container: + name: "{{ container_name }}" + state: absent + +- name: Scarica immagine Nginx + community.docker.docker_image: + name: "{{ nginx_image }}" + tag: "{{ nginx_version }}" + source: pull + +- name: Avvia container Nginx demo + community.docker.docker_container: + name: "{{ container_name }}" + image: "{{ nginx_image }}:{{ nginx_version }}" + state: started + restart_policy: unless-stopped + ports: + - "{{ app_port }}:80" + volumes: + - /opt/semaphore-splash/index.html:/usr/share/nginx/html/index.html:ro + - /opt/semaphore-splash/nginx.conf:/etc/nginx/nginx.conf:ro + env: + APP_ENV: "{{ app_environment }}" + GREETING_MESSAGE: "{{ greeting_message }}" + APP_SECRET: "{{ app_secret }}" + RELEASE_ID: "{{ release_id }}" + ACCENT_COLOR: "{{ accent_color }}" + SECONDARY_COLOR: "{{ secondary_color }}" diff --git a/ansible-semaphore-docker-demo/roles/splash/templates/index.html.j2 b/ansible-semaphore-docker-demo/roles/splash/templates/index.html.j2 new file mode 100644 index 0000000..a6a8645 --- /dev/null +++ b/ansible-semaphore-docker-demo/roles/splash/templates/index.html.j2 @@ -0,0 +1,161 @@ + + + + + + SemaphoreUI Docker Demo + + + +
+
+

{{ greeting_message }}

+

Demo Docker deployata con Ansible e orchestrata tramite SemaphoreUI.

+
+ +
+
+ Environment: {{ app_environment | upper }} + Release: {{ release_id }} +
+ +
+
+
Container
+
{{ container_name }}
+
+
+
Image
+
{{ nginx_image }}:{{ nginx_version }}
+
+
+
Porta esposta
+
{{ app_port }}
+
+
+
Secret hash hint
+
{{ app_secret | hash('sha1') }}
+
+
+
+ + +
+ + diff --git a/ansible-semaphore-docker-demo/roles/splash/templates/nginx.conf.j2 b/ansible-semaphore-docker-demo/roles/splash/templates/nginx.conf.j2 new file mode 100644 index 0000000..9721e61 --- /dev/null +++ b/ansible-semaphore-docker-demo/roles/splash/templates/nginx.conf.j2 @@ -0,0 +1,35 @@ +user nginx; +worker_processes {{ nginx_worker_processes }}; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections {{ nginx_worker_connections }}; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + sendfile on; + tcp_nopush on; + keepalive_timeout 65; + gzip on; + + server { + listen 80; + server_name _; + + location / { + root /usr/share/nginx/html; + index index.html; + } + + location /health { + access_log off; + return 200 "ok\n"; + add_header Content-Type text/plain; + } + } +} diff --git a/ansible-semaphore-docker-demo/semaphore_dagster_config.example.yml b/ansible-semaphore-docker-demo/semaphore_dagster_config.example.yml new file mode 100644 index 0000000..6c23cf8 --- /dev/null +++ b/ansible-semaphore-docker-demo/semaphore_dagster_config.example.yml @@ -0,0 +1,78 @@ +# Configuration for SemaphoreUI + Ansible Docker Splash Demo +# Aggiorna i campi in base al tuo ambiente + +# SemaphoreUI connection settings +semaphore_url: "https://your-semaphore-instance.com" +semaphore_token: "your-semaphore-api-token" +project_id: 1 + +# Git repository configuration +git_provider: "gitea" # github, gitlab, gitea, ... +git_base_url: "https://your-gitea-instance.com" +git_repo_url: "https://your-gitea-instance.com/your-user/ansible-semaphore-docker-demo.git" +git_branch: "main" + +# Git authentication (optional for private repos) +git_username: "your-username" +git_access_token: "your-personal-access-token" + +# Environment configuration +environment_name: "Semaphore Docker Splash Environment" +environment_variables: + nginx_image: "nginx" + nginx_version: "1.27-alpine" + container_name: "semaphore-splash" + + app_port: "8090" + app_environment: "production" + greeting_message: "Ciao dal deploy SemaphoreUI" + + accent_color: "#0ea5a4" + secondary_color: "#f97316" + + remove_image: "false" + + nginx_worker_processes: "auto" + nginx_worker_connections: "1024" + +# Optional encrypted secrets in SemaphoreUI Environment +secrets: + app_secret: "demo-secret-from-semaphore" + release_id: "v1-test" + demo_api_key: "demo-api-key-123" + demo_db_password: "demo-db-pass-123" + +# Inventory configuration +inventory_name: "Docker Splash Servers" +inventory_type: "static" +inventory_content: | + [webservers] + server1 ansible_host=XXX.XXX.XXX.XXX ansible_user=root + + [webservers:vars] + ansible_python_interpreter=/usr/bin/python3 + + [all:vars] + ansible_connection=ssh + +# Ansible Vault configuration +# Se non usi file vault, puo restare vuoto +vault_password: "" + +# Playbooks configuration +playbooks: + - name: "Test Connectivity" + description: "Check host reachability and Docker prerequisites" + playbook_filename: "test.yml" + + - name: "Deploy Splash App" + description: "Deploy Nginx container with custom splash page" + playbook_filename: "deploy.yml" + + - name: "Undeploy Splash App" + description: "Remove container and clean up resources" + playbook_filename: "undeploy.yml" + +# Optional additional settings +timeout_seconds: 30 +enable_health_check: true diff --git a/ansible-semaphore-docker-demo/test.yml b/ansible-semaphore-docker-demo/test.yml new file mode 100644 index 0000000..38a01bb --- /dev/null +++ b/ansible-semaphore-docker-demo/test.yml @@ -0,0 +1,41 @@ +--- +- name: Test host e prerequisiti Docker + hosts: webservers + become: yes + gather_facts: yes + + vars_files: + - group_vars/all.yml + + tasks: + - name: Test SSH + ansible.builtin.ping: + + - name: Mostra info host + ansible.builtin.debug: + msg: + - "Host: {{ ansible_hostname }}" + - "OS: {{ ansible_distribution }} {{ ansible_distribution_version }}" + - "Python: {{ ansible_python_version }}" + + - name: Controlla Docker CLI + ansible.builtin.command: docker --version + register: docker_version + changed_when: false + failed_when: false + + - name: Stato Docker CLI + ansible.builtin.debug: + msg: "{{ docker_version.stdout if docker_version.rc == 0 else 'Docker non trovato' }}" + + - name: Verifica porta target disponibile + ansible.builtin.wait_for: + port: "{{ app_port }}" + state: stopped + timeout: 1 + register: port_check + failed_when: false + + - name: Risultato porta + ansible.builtin.debug: + msg: "Porta {{ app_port }} {{ 'libera' if port_check is not failed else 'gia in uso' }}" diff --git a/ansible-semaphore-docker-demo/undeploy.yml b/ansible-semaphore-docker-demo/undeploy.yml new file mode 100644 index 0000000..a556379 --- /dev/null +++ b/ansible-semaphore-docker-demo/undeploy.yml @@ -0,0 +1,29 @@ +--- +- name: Undeploy demo container + hosts: webservers + become: yes + + vars_files: + - group_vars/all.yml + + tasks: + - name: Rimuovi container demo + community.docker.docker_container: + name: "{{ container_name }}" + state: absent + + - name: Rimuovi immagine (opzionale) + community.docker.docker_image: + name: "{{ nginx_image }}" + tag: "{{ nginx_version }}" + state: absent + when: remove_image | bool + + - name: Rimuovi directory applicazione + ansible.builtin.file: + path: /opt/semaphore-splash + state: absent + + - name: Conferma undeploy + ansible.builtin.debug: + msg: "Container {{ container_name }} rimosso con successo"