Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
- Remove middleware reference from Gitea Traefik labels (caused routing issues) - Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s) - Add explicit service reference in Traefik labels - Fix intermittent 504 timeouts by improving PostgreSQL connection handling Fixes Gitea unreachability via git.michaelschiemer.de
426 lines
19 KiB
YAML
426 lines
19 KiB
YAML
---
|
|
- name: Debug all available variables before password determination
|
|
ansible.builtin.debug:
|
|
msg: |
|
|
Available variables for registry password:
|
|
- docker_registry_password_default defined: {{ docker_registry_password_default is defined }}
|
|
- vault_docker_registry_password defined: {{ vault_docker_registry_password is defined }}
|
|
- All vault_* variable names: {{ vars.keys() | select('match', '^vault_.*') | list | join(', ') }}
|
|
delegate_to: localhost
|
|
become: no
|
|
|
|
- name: Check if docker_registry_password_default is set (safe check)
|
|
ansible.builtin.set_fact:
|
|
_docker_registry_password_default_set: "{{ 'YES' if (docker_registry_password_default is defined and docker_registry_password_default | string | trim != '') else 'NO' }}"
|
|
delegate_to: localhost
|
|
become: no
|
|
when: docker_registry_password_default is defined
|
|
|
|
- name: Check if vault_docker_registry_password is set (safe check)
|
|
ansible.builtin.set_fact:
|
|
_vault_docker_registry_password_set: "{{ 'YES' if (vault_docker_registry_password is defined and vault_docker_registry_password | string | trim != '') else 'NO' }}"
|
|
delegate_to: localhost
|
|
become: no
|
|
when: vault_docker_registry_password is defined
|
|
|
|
- name: Debug password status
|
|
ansible.builtin.debug:
|
|
msg: |
|
|
Password status:
|
|
- docker_registry_password_default: {{ _docker_registry_password_default_set | default('NOT DEFINED') }}
|
|
- vault_docker_registry_password: {{ _vault_docker_registry_password_set | default('NOT DEFINED') }}
|
|
delegate_to: localhost
|
|
become: no
|
|
|
|
- name: Determine Docker registry password from vault or defaults
|
|
ansible.builtin.set_fact:
|
|
registry_password: >-
|
|
{%- if docker_registry_password_default is defined and docker_registry_password_default | string | trim != '' -%}
|
|
{{ docker_registry_password_default }}
|
|
{%- elif vault_docker_registry_password is defined and vault_docker_registry_password | string | trim != '' -%}
|
|
{{ vault_docker_registry_password }}
|
|
{%- else -%}
|
|
{{ '' }}
|
|
{%- endif -%}
|
|
no_log: yes
|
|
|
|
- name: Debug registry password source after determination
|
|
ansible.builtin.debug:
|
|
msg: |
|
|
Registry password determination result:
|
|
- docker_registry_password_default: {{ 'SET (length: ' + (docker_registry_password_default | default('') | string | length | string) + ')' if (docker_registry_password_default | default('') | string | trim) != '' else 'NOT SET' }}
|
|
- vault_docker_registry_password defined: {{ vault_docker_registry_password is defined }}
|
|
- vault_docker_registry_password set: {{ 'YES (length: ' + (vault_docker_registry_password | default('') | string | length | string) + ')' if (vault_docker_registry_password | default('') | string | trim) != '' else 'NO' }}
|
|
- registry_password set: {{ 'YES (length: ' + (registry_password | default('') | string | length | string) + ')' if (registry_password | default('') | string | trim) != '' else 'NO' }}
|
|
delegate_to: localhost
|
|
become: no
|
|
|
|
- name: Debug vault loading
|
|
ansible.builtin.debug:
|
|
msg: |
|
|
Vault loading status:
|
|
- Vault file exists: {{ application_vault_stat.stat.exists | default(false) }}
|
|
- vault_docker_registry_password defined: {{ vault_docker_registry_password is defined }}
|
|
- vault_docker_registry_password value: {{ 'SET (length: ' + (vault_docker_registry_password | default('') | string | length | string) + ')' if (vault_docker_registry_password | default('') | string | trim) != '' else 'NOT SET or EMPTY' }}
|
|
- registry_password: {{ 'SET (length: ' + (registry_password | default('') | string | length | string) + ')' if (registry_password | default('') | string | trim) != '' else 'NOT SET or EMPTY' }}
|
|
when: true
|
|
no_log: yes
|
|
|
|
- name: Check if registry is accessible
|
|
ansible.builtin.uri:
|
|
url: "http://{{ docker_registry | default('localhost:5000') }}/v2/"
|
|
method: GET
|
|
status_code: [200, 401]
|
|
timeout: 5
|
|
register: registry_check
|
|
ignore_errors: yes
|
|
delegate_to: "{{ inventory_hostname }}"
|
|
become: no
|
|
|
|
- name: Debug registry accessibility
|
|
ansible.builtin.debug:
|
|
msg: |
|
|
Registry accessibility check:
|
|
- Registry URL: http://{{ docker_registry | default('localhost:5000') }}/v2/
|
|
- Status code: {{ registry_check.status | default('UNKNOWN') }}
|
|
- Accessible: {{ 'YES' if registry_check.status | default(0) in [200, 401] else 'NO' }}
|
|
- Note: Status 401 means registry requires authentication (expected)
|
|
delegate_to: localhost
|
|
become: no
|
|
|
|
- name: Login to Docker registry
|
|
community.docker.docker_login:
|
|
registry_url: "{{ docker_registry | default('localhost:5000') }}"
|
|
username: "{{ docker_registry_username_default | default('admin') }}"
|
|
password: "{{ registry_password }}"
|
|
when:
|
|
- registry_password | string | trim != ''
|
|
- registry_check.status | default(0) in [200, 401]
|
|
no_log: yes
|
|
ignore_errors: yes
|
|
register: docker_login_result
|
|
|
|
- name: Warn if Docker registry login failed
|
|
ansible.builtin.debug:
|
|
msg: "WARNING: Docker registry login failed or skipped. Images may not be pullable without authentication."
|
|
when:
|
|
- registry_password | string | trim != ''
|
|
- docker_login_result.failed | default(false)
|
|
|
|
- name: Debug registry authentication status
|
|
ansible.builtin.debug:
|
|
msg: |
|
|
Registry authentication status:
|
|
- Registry: {{ docker_registry | default('localhost:5000') }}
|
|
- Password set: {{ 'YES' if (registry_password | string | trim) != '' else 'NO' }}
|
|
- Login result: {{ 'SUCCESS' if (docker_login_result.failed | default(true) == false) else 'FAILED or SKIPPED' }}
|
|
- Username: {{ docker_registry_username_default | default('admin') }}
|
|
when: true
|
|
|
|
- name: Fail if registry password is not set
|
|
ansible.builtin.fail:
|
|
msg: |
|
|
Docker registry authentication required but password not set!
|
|
|
|
The registry at {{ docker_registry | default('localhost:5000') }} requires authentication.
|
|
|
|
Please set the password in one of these ways:
|
|
|
|
1. Set in vault file (recommended):
|
|
ansible-vault edit {{ vault_file | default('inventory/group_vars/production/vault.yml') }}
|
|
# Add: vault_docker_registry_password: "your-password"
|
|
|
|
2. Pass via extra vars:
|
|
-e "docker_registry_password_default=your-password"
|
|
|
|
3. Use init-secrets.sh script to generate all passwords:
|
|
cd deployment/ansible
|
|
./scripts/init-secrets.sh
|
|
|
|
Note: The registry password was likely generated when the registry stack was deployed.
|
|
Check the registry role output or the vault file for the generated password.
|
|
when:
|
|
- registry_password | string | trim == ''
|
|
- docker_registry | default('localhost:5000') == 'localhost:5000'
|
|
|
|
- name: Check registry htpasswd file to verify password
|
|
ansible.builtin.shell: |
|
|
if [ -f "{{ registry_auth_path | default('/home/deploy/deployment/stacks/registry/auth') }}/htpasswd" ]; then
|
|
cat "{{ registry_auth_path | default('/home/deploy/deployment/stacks/registry/auth') }}/htpasswd"
|
|
else
|
|
echo "htpasswd file not found"
|
|
fi
|
|
register: registry_htpasswd_check
|
|
changed_when: false
|
|
failed_when: false
|
|
delegate_to: "{{ inventory_hostname }}"
|
|
become: no
|
|
when: docker_login_result.failed | default(false)
|
|
|
|
- name: Debug registry password mismatch
|
|
ansible.builtin.debug:
|
|
msg: |
|
|
Registry authentication failed!
|
|
|
|
Registry: {{ docker_registry | default('localhost:5000') }}
|
|
Username: {{ docker_registry_username_default | default('admin') }}
|
|
|
|
Possible causes:
|
|
1. The password in vault does not match the password used during registry deployment
|
|
2. The registry was deployed with a different password (generated by registry role)
|
|
3. The username is incorrect
|
|
|
|
To fix:
|
|
1. Check the registry htpasswd file on the server:
|
|
cat {{ registry_auth_path | default('/home/deploy/deployment/stacks/registry/auth') }}/htpasswd
|
|
|
|
2. Extract the password from the registry .env file (if available):
|
|
grep REGISTRY_AUTH {{ registry_stack_path | default('/home/deploy/deployment/stacks/registry') }}/.env
|
|
|
|
3. Update the vault file with the correct password:
|
|
ansible-vault edit {{ vault_file | default('inventory/group_vars/production/vault.yml') }}
|
|
# Set: vault_docker_registry_password: "correct-password"
|
|
|
|
4. Or re-deploy the registry stack with the password from vault:
|
|
ansible-playbook -i inventory/production.yml playbooks/setup-infrastructure.yml --tags registry
|
|
|
|
Registry htpasswd file content:
|
|
{{ registry_htpasswd_check.stdout | default('NOT FOUND') }}
|
|
when:
|
|
- registry_password | string | trim != ''
|
|
- docker_login_result.failed | default(false)
|
|
|
|
- name: Fail if registry authentication failed and password was provided
|
|
ansible.builtin.fail:
|
|
msg: |
|
|
Docker registry authentication failed!
|
|
|
|
Registry: {{ docker_registry | default('localhost:5000') }}
|
|
Username: {{ docker_registry_username_default | default('admin') }}
|
|
|
|
The password in the vault file does not match the password used during registry deployment.
|
|
Please check the debug output above for instructions on how to fix this.
|
|
when:
|
|
- registry_password | string | trim != ''
|
|
- docker_login_result.failed | default(false)
|
|
|
|
- name: Force pull latest Docker images before deployment
|
|
shell: |
|
|
docker compose -f {{ application_stack_dest }}/docker-compose.base.yml -f {{ application_stack_dest }}/docker-compose.{{ application_compose_suffix }} pull --ignore-pull-failures
|
|
changed_when: false
|
|
failed_when: false
|
|
when: not ansible_check_mode
|
|
|
|
- name: Verify entrypoint script exists in Docker image (method 1 - file check)
|
|
shell: |
|
|
docker run --rm --entrypoint=/bin/sh {{ docker_registry | default('localhost:5000') }}/{{ app_name | default('framework') }}:latest -c "test -f /usr/local/bin/entrypoint.sh && ls -la /usr/local/bin/entrypoint.sh || echo 'FILE_NOT_FOUND'"
|
|
register: entrypoint_check
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: Verify entrypoint script exists in Docker image (method 2 - inspect image)
|
|
shell: |
|
|
docker image inspect {{ docker_registry | default('localhost:5000') }}/{{ app_name | default('framework') }}:latest --format '{{ "{{" }}.Config.Entrypoint{{ "}}" }}' 2>&1 || echo "INSPECT_FAILED"
|
|
register: entrypoint_inspect
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: Verify entrypoint script exists in Docker image (method 3 - extract and check)
|
|
shell: |
|
|
CONTAINER_ID=$(docker create {{ docker_registry | default('localhost:5000') }}/{{ app_name | default('framework') }}:latest 2>/dev/null) && \
|
|
docker cp $CONTAINER_ID:/usr/local/bin/entrypoint.sh /tmp/entrypoint_check.sh 2>&1 && \
|
|
if [ -f /tmp/entrypoint_check.sh ]; then \
|
|
echo "FILE_EXISTS"; \
|
|
ls -la /tmp/entrypoint_check.sh; \
|
|
head -5 /tmp/entrypoint_check.sh; \
|
|
rm -f /tmp/entrypoint_check.sh; \
|
|
else \
|
|
echo "FILE_NOT_FOUND"; \
|
|
fi && \
|
|
docker rm $CONTAINER_ID >/dev/null 2>&1 || true
|
|
register: entrypoint_extract
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: Set entrypoint verification message
|
|
set_fact:
|
|
entrypoint_verification_msg: |
|
|
==========================================
|
|
Entrypoint Script Verification
|
|
==========================================
|
|
Image: {{ docker_registry | default('localhost:5000') }}/{{ app_name | default('framework') }}:latest
|
|
|
|
Method 1 - File Check:
|
|
Return Code: {{ entrypoint_check.rc | default('unknown') }}
|
|
Output: {{ entrypoint_check.stdout | default('No output') }}
|
|
|
|
Method 2 - Image Inspect:
|
|
Entrypoint Config: {{ entrypoint_inspect.stdout | default('Not available') }}
|
|
|
|
Method 3 - Extract and Check:
|
|
{{ entrypoint_extract.stdout | default('Check not performed') }}
|
|
|
|
{% if 'FILE_NOT_FOUND' in entrypoint_check.stdout or 'FILE_NOT_FOUND' in entrypoint_extract.stdout %}
|
|
⚠️ WARNING: Entrypoint script NOT FOUND in image!
|
|
|
|
This means the Docker image was built without the entrypoint script.
|
|
Possible causes:
|
|
1. The entrypoint script was not copied during rsync to build directory
|
|
2. The Dockerfile COPY command failed silently
|
|
3. The image needs to be rebuilt with --no-cache
|
|
|
|
Next steps:
|
|
1. Rebuild the image: ansible-playbook -i inventory/production.yml playbooks/build-initial-image.yml --vault-password-file secrets/.vault_pass -e "build_no_cache=true"
|
|
2. Check if docker/entrypoint.sh exists on server: ls -la /home/deploy/michaelschiemer/docker/entrypoint.sh
|
|
3. Manually check image: docker run --rm --entrypoint=/bin/sh localhost:5000/framework:latest -c "ls -la /usr/local/bin/entrypoint.sh"
|
|
{% elif entrypoint_check.rc == 0 %}
|
|
✅ Entrypoint script found in image
|
|
File details: {{ entrypoint_check.stdout }}
|
|
{% if '\r' in entrypoint_extract.stdout %}
|
|
⚠️ CRITICAL: Entrypoint script has CRLF line endings!
|
|
The script contains \r characters which will cause "no such file or directory" errors.
|
|
The script needs to be converted to LF line endings before building the image.
|
|
{% endif %}
|
|
{% else %}
|
|
⚠️ Could not verify entrypoint script (check may have failed)
|
|
{% endif %}
|
|
==========================================
|
|
|
|
- name: Display entrypoint script verification result
|
|
debug:
|
|
var: entrypoint_verification_msg
|
|
|
|
- name: Deploy application stack
|
|
community.docker.docker_compose_v2:
|
|
project_src: "{{ application_stack_dest }}"
|
|
files:
|
|
- docker-compose.base.yml
|
|
- "docker-compose.{{ application_compose_suffix }}"
|
|
state: present
|
|
pull: always
|
|
recreate: "{{ application_compose_recreate }}"
|
|
remove_orphans: "{{ application_remove_orphans | bool }}"
|
|
register: application_compose_result
|
|
failed_when: false
|
|
|
|
- name: Show PHP container logs if deployment failed
|
|
shell: |
|
|
docker compose -f {{ application_stack_dest }}/docker-compose.base.yml -f {{ application_stack_dest }}/docker-compose.{{ application_compose_suffix }} logs --tail=50 {{ application_service_name }} 2>&1 || true
|
|
register: application_php_logs
|
|
changed_when: false
|
|
when: application_compose_result.failed | default(false)
|
|
|
|
- name: Display PHP container logs on failure
|
|
debug:
|
|
msg: |
|
|
PHP Container Logs (last 50 lines):
|
|
{{ application_php_logs.stdout | default('No logs available') }}
|
|
when: application_compose_result.failed | default(false)
|
|
|
|
- name: Fail if deployment failed
|
|
fail:
|
|
msg: "Application stack deployment failed. Check logs above for details."
|
|
when: application_compose_result.failed | default(false)
|
|
|
|
- name: Wait for application container to report Up
|
|
shell: |
|
|
docker compose -f {{ application_stack_dest }}/docker-compose.base.yml -f {{ application_stack_dest }}/docker-compose.{{ application_compose_suffix }} ps {{ application_service_name }} | grep -Eiq "Up|running"
|
|
register: application_app_running
|
|
changed_when: false
|
|
until: application_app_running.rc == 0
|
|
retries: "{{ ((application_wait_timeout | int) + (application_wait_interval | int) - 1) // (application_wait_interval | int) }}"
|
|
delay: "{{ application_wait_interval | int }}"
|
|
when: application_compose_result.changed
|
|
failed_when: false
|
|
|
|
- name: Show container status when container doesn't start
|
|
shell: |
|
|
docker compose -f {{ application_stack_dest }}/docker-compose.base.yml -f {{ application_stack_dest }}/docker-compose.{{ application_compose_suffix }} ps {{ application_service_name }}
|
|
register: application_container_status
|
|
changed_when: false
|
|
when:
|
|
- application_compose_result.changed
|
|
- application_app_running.rc != 0
|
|
|
|
- name: Show PHP container logs when container doesn't start
|
|
shell: |
|
|
docker compose -f {{ application_stack_dest }}/docker-compose.base.yml -f {{ application_stack_dest }}/docker-compose.{{ application_compose_suffix }} logs --tail=100 {{ application_service_name }} 2>&1 || true
|
|
register: application_php_logs_failed
|
|
changed_when: false
|
|
when:
|
|
- application_compose_result.changed
|
|
- application_app_running.rc != 0
|
|
|
|
- name: Display container status and logs when startup failed
|
|
debug:
|
|
msg: |
|
|
Container Status:
|
|
{{ application_container_status.stdout | default('Container not found') }}
|
|
|
|
Container Logs (last 100 lines):
|
|
{{ application_php_logs_failed.stdout | default('No logs available') }}
|
|
when:
|
|
- application_compose_result.changed
|
|
- application_app_running.rc != 0
|
|
|
|
- name: Fail if container didn't start
|
|
fail:
|
|
msg: |
|
|
Application container '{{ application_service_name }}' failed to start.
|
|
Check the logs above for details.
|
|
You can also check manually with:
|
|
docker compose -f {{ application_stack_dest }}/docker-compose.base.yml -f {{ application_stack_dest }}/docker-compose.{{ application_compose_suffix }} logs {{ application_service_name }}
|
|
when:
|
|
- application_compose_result.changed
|
|
- application_app_running.rc != 0
|
|
|
|
- name: Ensure app container is running before migrations
|
|
shell: |
|
|
docker compose -f {{ application_stack_dest }}/docker-compose.base.yml -f {{ application_stack_dest }}/docker-compose.{{ application_compose_suffix }} ps {{ application_service_name }} | grep -Eiq "Up|running"
|
|
args:
|
|
executable: /bin/bash
|
|
register: application_app_container_running
|
|
changed_when: false
|
|
failed_when: false
|
|
when: application_compose_result.changed
|
|
|
|
- name: Run database migrations
|
|
shell: |
|
|
docker compose -f {{ application_stack_dest }}/docker-compose.base.yml -f {{ application_stack_dest }}/docker-compose.{{ application_compose_suffix }} exec -T {{ application_service_name }} {{ application_migration_command }}
|
|
args:
|
|
executable: /bin/bash
|
|
register: application_migration_result
|
|
changed_when: true
|
|
failed_when: false
|
|
ignore_errors: yes
|
|
when:
|
|
- application_run_migrations
|
|
- application_compose_result.changed
|
|
- application_app_container_running.rc == 0
|
|
|
|
- name: Collect application container status
|
|
shell: docker compose -f {{ application_stack_dest }}/docker-compose.base.yml -f {{ application_stack_dest }}/docker-compose.{{ application_compose_suffix }} ps
|
|
register: application_ps
|
|
changed_when: false
|
|
ignore_errors: yes
|
|
|
|
- name: Perform application health check
|
|
uri:
|
|
url: "{{ application_healthcheck_url }}"
|
|
method: GET
|
|
validate_certs: no
|
|
status_code: [200, 404, 502, 503]
|
|
timeout: 10
|
|
register: application_healthcheck_result
|
|
ignore_errors: yes
|
|
when:
|
|
- application_healthcheck_url | length > 0
|
|
- application_compose_result.changed
|
|
|
|
- name: Set application role summary facts
|
|
set_fact:
|
|
application_stack_changed: "{{ application_compose_result.changed | default(false) }}"
|
|
application_health_output: "{{ application_ps.stdout | default('') }}"
|
|
application_healthcheck_status: "{{ application_healthcheck_result.status | default('unknown') }}"
|
|
application_migration_stdout: "{{ application_migration_result.stdout | default('') }}"
|