mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-09 20:26:33 +00:00
fix(swarm): reach gitea, shopware and fider from inside their containers
In swarm, `docker stack deploy` drops the host IP of a short port mapping, so a `127.0.0.1:<ports.local>` publish lands on the ingress routing mesh on every node. The provisioning of these three roles only worked because the mesh answered on the host: - web-app-gitea waited for `DOCKER_REACH_HOST:<ports.local.http>` with wait_for and polled `/api/v1/version` there with uri_retry. - web-app-shopware waited for `DOCKER_REACH_HOST:<ports.local.http>`. - web-app-fider bootstrapped its first tenant in swarm by POSTing to `127.0.0.1:<ports.local.http>` on the hosting node. As long as these calls depend on the mesh, container_ports cannot stop publishing loopback ports in swarm. The probes now run inside the service's own container through the resolved `<PREFIX>_LOCAL_CID` on `<PREFIX>_HOST_NODE`, against the internal port: - Gitea uses the curl it ships. The first wait accepts any HTTP answer, as wait_for did. The post-migration wait still requires 200. - Shopware runs the wget probe its compose healthcheck already uses. - Fider ships no HTTP client, so bash writes the tenant POST to /dev/tcp. The body comes in on stdin and the status line is checked for 200/201. Fider's compose path is unchanged. The compose render of all three roles is unchanged. The host-side ingress guard from svc-swarm-node stays in place until the remaining host-side consumers are moved. Refs #1089 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e8cb250c51
commit
c59e2838d6
5 files changed
+44
-28
No files matched your search
@@ -45,15 +45,21 @@
|
||||
- DEPLOYMENT_MODE == 'compose'
|
||||
- (fider_tenant_count.rows[0][0] | int) == 0
|
||||
|
||||
- name: "🥾 Fider | Bootstrap initial tenant via API (swarm, routing-mesh port)"
|
||||
uri_retry:
|
||||
url: "http://127.0.0.1:{{ lookup('config', application_id, 'services.fider.ports.local.http') }}/_api/tenants"
|
||||
method: POST
|
||||
body_format: json
|
||||
body: "{{ FIDER_TENANT_BOOTSTRAP_BODY }}"
|
||||
status_code: [200, 201]
|
||||
- name: "🥾 Fider | Bootstrap initial tenant via API (swarm in-container)"
|
||||
ansible.builtin.shell:
|
||||
cmd: >- # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
|
||||
container exec -i {{ FIDER_LOCAL_CID | quote }} bash -c
|
||||
'set -e; body=$(cat); length=$(printf %s "$body" | wc -c);
|
||||
exec 3<>"/dev/tcp/127.0.0.1/$1";
|
||||
printf "POST /_api/tenants HTTP/1.0\r\nContent-Type: application/json\r\nContent-Length: %d\r\n\r\n%s" "$length" "$body" >&3;
|
||||
head -n1 <&3 | cut -d" " -f2' _ {{ FIDER_INTERNAL_PORT | quote }}
|
||||
stdin: "{{ FIDER_TENANT_BOOTSTRAP_BODY | to_json }}"
|
||||
register: fider_tenant_bootstrap
|
||||
changed_when: true
|
||||
failed_when: (fider_tenant_bootstrap.stdout | trim) not in ['200', '201']
|
||||
retries: 30
|
||||
delay: 2
|
||||
until: fider_tenant_bootstrap.rc == 0
|
||||
delegate_to: "{{ FIDER_HOST_NODE }}"
|
||||
when:
|
||||
- DEPLOYMENT_MODE == 'swarm'
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
application_id: "web-app-fider"
|
||||
|
||||
FIDER_CONTAINER: "{{ lookup('config', application_id, 'services.fider.name') }}"
|
||||
FIDER_INTERNAL_PORT: "{{ lookup('config', application_id, 'services.fider.ports.internal.http') }}"
|
||||
|
||||
FIDER_OIDC_ENABLED: "{{ lookup('config', application_id, 'services.sso.enabled') }}"
|
||||
|
||||
@@ -20,7 +21,7 @@ FIDER_MCP_PORT: "{{ lookup('config', application_id, 'services.fidermcp.ports.in
|
||||
FIDER_MCP_BEARER: "{{ lookup('config', application_id, 'secrets.credentials.mcp_bearer') }}"
|
||||
FIDER_MCP_INSTANCE_DIR: "{{ [lookup('container', application_id, 'directories.instance'), 'mcp'] | path_join }}"
|
||||
FIDER_MCP_UPSTREAM_HOST: "{{ lookup('config', application_id, 'services.fider.name') }}"
|
||||
FIDER_MCP_UPSTREAM_PORT: "{{ lookup('config', application_id, 'services.fider.ports.internal.http') }}"
|
||||
FIDER_MCP_UPSTREAM_PORT: "{{ FIDER_INTERNAL_PORT }}"
|
||||
FIDER_MCP_UPSTREAM_URL: "http://{{ FIDER_MCP_UPSTREAM_HOST }}:{{ FIDER_MCP_UPSTREAM_PORT }}"
|
||||
FIDER_MCP_CONTRACT:
|
||||
provider: "{{ application_id }}"
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
---
|
||||
- name: ⏳ Wait for Gitea HTTP endpoint
|
||||
wait_for:
|
||||
host: "{{ DOCKER_REACH_HOST }}"
|
||||
port: "{{ lookup('config', application_id, 'services.gitea.ports.local.http') }}"
|
||||
delay: 5
|
||||
timeout: "{{ lookup('timeout', 300) | int }}"
|
||||
|
||||
- name: "🔍 Resolve {{ application_id }} hosting node + container id"
|
||||
ansible.builtin.include_tasks: "{{ lookup('path_absolute', 'roles/sys-svc-compose/tasks/utils/swarm/resolve_host_cid.yml') }}"
|
||||
vars:
|
||||
@@ -13,6 +6,17 @@
|
||||
resolve_output_prefix: GITEA
|
||||
resolve_compose_cid: "{{ GITEA_CONTAINER_ADDRESS }}"
|
||||
|
||||
- name: ⏳ Wait for Gitea HTTP endpoint
|
||||
ansible.builtin.shell: >- # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
|
||||
container exec {{ GITEA_LOCAL_CID | quote }}
|
||||
{{ 10 | curl(retries=0) }} -S -o /dev/null {{ GITEA_LOOPBACK_VERSION_URL | quote }}
|
||||
delegate_to: "{{ GITEA_HOST_NODE }}"
|
||||
register: gitea_http_ready
|
||||
changed_when: false
|
||||
retries: 60
|
||||
delay: 5
|
||||
until: gitea_http_ready.rc == 0
|
||||
|
||||
- name: "⏳ Wait for Gitea app.ini to be present after redeploy"
|
||||
shell: | # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
|
||||
container exec -i --user {{ GITEA_USER }} {{ GITEA_LOCAL_CID | quote }} \
|
||||
@@ -48,13 +52,13 @@
|
||||
failed_when: create_admin.rc != 0 and 'user already exists' not in create_admin.stderr
|
||||
|
||||
- name: "⏳ Wait until Gitea setup and migrations are ready"
|
||||
uri_retry:
|
||||
url: "http://{{ DOCKER_REACH_HOST }}:{{ lookup('config', application_id, 'services.gitea.ports.local.http') }}/api/v1/version"
|
||||
method: GET
|
||||
status_code: 200
|
||||
return_content: false
|
||||
ansible.builtin.shell: >- # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
|
||||
container exec {{ GITEA_LOCAL_CID | quote }}
|
||||
{{ 10 | curl(retries=0) }} -fS -o /dev/null {{ GITEA_LOOPBACK_VERSION_URL | quote }}
|
||||
delegate_to: "{{ GITEA_HOST_NODE }}"
|
||||
register: gitea_ready
|
||||
until: gitea_ready.status == 200
|
||||
changed_when: false
|
||||
until: gitea_ready.rc == 0
|
||||
retries: 20
|
||||
delay: 5
|
||||
when: (GITEA_OIDC_ENABLED | bool) or (GITEA_LDAP_ENABLED | bool)
|
||||
|
||||
@@ -22,6 +22,7 @@ GITEA_CONTAINER: "{{ lookup('config', application_id, 'services.gitea.name') }}"
|
||||
GITEA_CONTAINER_ADDRESS: "{{ lookup('container_address', application_id, entity_name) }}"
|
||||
GITEA_USER: "git"
|
||||
GITEA_CONFIG: "/data/gitea/conf/app.ini"
|
||||
GITEA_LOOPBACK_VERSION_URL: "http://127.0.0.1:{{ lookup('config', application_id, 'services.gitea.ports.internal.http') }}/api/v1/version"
|
||||
|
||||
GITEA_REDIS_ENABLED: "{{ lookup('config', application_id, 'services.redis.enabled') }}"
|
||||
GITEA_REDIS_ADDRESS: "{{ lookup('engine', 'redis', application_id, 'host') }}:{{ lookup('engine', 'redis', application_id, 'port') }}"
|
||||
|
||||
@@ -37,13 +37,6 @@
|
||||
- name: "🚿 Flush compose handlers"
|
||||
meta: flush_handlers
|
||||
|
||||
- name: ⏳ Wait for Shopware HTTP endpoint
|
||||
wait_for:
|
||||
host: "{{ DOCKER_REACH_HOST }}"
|
||||
port: "{{ lookup('config', application_id, 'services.shopware.ports.local.http') }}"
|
||||
delay: 5
|
||||
timeout: "{{ lookup('timeout', 300) | int }}"
|
||||
|
||||
- name: "🔍 Resolve Shopware web hosting node + container id"
|
||||
ansible.builtin.include_tasks: "{{ lookup('path_absolute', 'roles/sys-svc-compose/tasks/utils/swarm/resolve_host_cid.yml') }}"
|
||||
vars:
|
||||
@@ -53,6 +46,17 @@
|
||||
resolve_converge_retries: 120
|
||||
resolve_converge_delay: 5
|
||||
|
||||
- name: ⏳ Wait for Shopware HTTP endpoint
|
||||
ansible.builtin.shell: >- # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
|
||||
container exec {{ SHOPWARE_WEB_LOCAL_CID | quote }}
|
||||
sh -c 'wget -q --spider "$1/robots.txt" || wget -q --spider "$1/"' _ {{ SHOPWARE_API_BASE | quote }}
|
||||
delegate_to: "{{ SHOPWARE_WEB_HOST_NODE }}"
|
||||
register: shopware_http_ready
|
||||
changed_when: false
|
||||
retries: 60
|
||||
delay: 5
|
||||
until: shopware_http_ready.rc == 0
|
||||
|
||||
- name: "✅ Ensure admin user exists with correct password"
|
||||
ansible.builtin.include_tasks:
|
||||
file: 01_admin.yml
|
||||
|
||||
Reference in new issue
Block a user