fix: more details deployment

This commit is contained in:
Benno Tielen 2026-04-16 13:22:17 +02:00
parent c4060dad0c
commit 2efcb5f672
6 changed files with 185 additions and 35 deletions

View file

@ -169,42 +169,38 @@ docker restart postgres
## Deploy via Ansible (without CI/CD) ## Deploy via Ansible (without CI/CD)
Use the `deploy.yml` playbook to deploy from your local machine — no Forgejo runner or CI/CD pipeline needed. This is useful for hotfixes, CI outages, or production servers without Forgejo. Use these playbooks to deploy from your local machine — no Forgejo runner needed.
```bash ```bash
cd infra/ansible cd infra/ansible
# Deploy to test/staging VPS # Deploy both environments (git pull once, then build+deploy each sequentially)
ansible-playbook playbooks/deploy.yml -i inventory/test.yml --ask-vault-pass ansible-playbook playbooks/deploy.yml --ask-vault-pass
# Deploy to production # Deploy staging only
ansible-playbook playbooks/deploy.yml -i inventory/production.yml --ask-vault-pass ansible-playbook playbooks/deploy-staging.yml --ask-vault-pass
# Deploy test only
ansible-playbook playbooks/deploy-test.yml --ask-vault-pass
``` ```
**What it does:** **Steps executed per environment:**
1. Pulls the latest code from the configured branch (`repo_branch` in inventory) 1. Pull latest code from the configured branch (`staging`)
2. Runs `deploy.sh` for each environment (sequentially to save RAM), which: 2. Build app Docker image (bakes in `NEXT_PUBLIC_SERVER_URL` and `NEXT_PUBLIC_SITE_ID`)
- Builds the Docker app image with build-time env vars 3. Build migration image and run `npx payload migrate`
- Builds a migration image and runs `npx payload migrate` 4. Stop and remove the old container
- Stops the old container, starts the new one 5. Start the new container
- Prunes old Docker images 6. Fix upload volume permissions
7. Prune old Docker images
**Deploy a specific branch:** **Deploy a specific branch:**
```bash ```bash
ansible-playbook playbooks/deploy.yml -i inventory/test.yml --ask-vault-pass \ ansible-playbook playbooks/deploy.yml --ask-vault-pass -e repo_branch=feature/my-branch
-e repo_branch=feature/my-branch
``` ```
**Deploy only one environment** (e.g., just staging): > **Note:** The server must already be provisioned with `setup.yml` before deploying. The deploy playbooks only pull code and rebuild containers — they do not install Docker, Caddy, or PostgreSQL.
```bash
ansible-playbook playbooks/deploy.yml -i inventory/test.yml --ask-vault-pass \
-e '{"app_environments": [{"name": "staging", "port": 3001}]}'
```
> **Note:** The server must already be provisioned with `setup.yml` before using `deploy.yml`. The deploy playbook only pulls code and rebuilds containers — it does not install Docker, Caddy, or PostgreSQL.
--- ---

View file

@ -0,0 +1,20 @@
---
- name: Deploy staging environment
hosts: all
become: true
tasks:
- name: Pull {{ repo_branch }} branch
ansible.builtin.git:
repo: "{{ repo_url }}"
dest: "{{ repo_dir }}"
version: "{{ repo_branch }}"
force: true
accept_hostkey: true
- name: Build and deploy staging
ansible.builtin.include_role:
name: app
tasks_from: deploy_env
vars:
env: "{{ app_environments | selectattr('name', 'equalto', 'staging') | first }}"

View file

@ -0,0 +1,20 @@
---
- name: Deploy test environment
hosts: all
become: true
tasks:
- name: Pull {{ repo_branch }} branch
ansible.builtin.git:
repo: "{{ repo_url }}"
dest: "{{ repo_dir }}"
version: "{{ repo_branch }}"
force: true
accept_hostkey: true
- name: Build and deploy test
ansible.builtin.include_role:
name: app
tasks_from: deploy_env
vars:
env: "{{ app_environments | selectattr('name', 'equalto', 'test') | first }}"

View file

@ -1,19 +1,37 @@
--- ---
- name: Deploy app (rebuild + restart) - name: Pull latest code (shared for both environments)
hosts: all hosts: all
become: true become: true
tasks: tasks:
- name: Pull latest code - name: Pull {{ repo_branch }} branch
ansible.builtin.git: ansible.builtin.git:
repo: "{{ repo_url }}" repo: "{{ repo_url }}"
dest: "{{ repo_dir }}" dest: "{{ repo_dir }}"
version: "{{ repo_branch }}" version: "{{ repo_branch }}"
force: true force: true
accept_hostkey: true
- name: Deploy each environment - name: Deploy staging environment
ansible.builtin.shell: | hosts: all
{{ scripts_dir }}/deploy.sh {{ item.name }} {{ item.port }} become: true
loop: "{{ app_environments }}"
loop_control: tasks:
label: "{{ item.name }}" - name: Build and deploy staging
ansible.builtin.include_role:
name: app
tasks_from: deploy_env
vars:
env: "{{ app_environments | selectattr('name', 'equalto', 'staging') | first }}"
- name: Deploy test environment
hosts: all
become: true
tasks:
- name: Build and deploy test
ansible.builtin.include_role:
name: app
tasks_from: deploy_env
vars:
env: "{{ app_environments | selectattr('name', 'equalto', 'test') | first }}"

View file

@ -1,9 +1,7 @@
--- ---
- name: Deploy each environment (sequentially to save RAM) - name: Deploy each environment (sequentially to save RAM)
ansible.builtin.shell: | ansible.builtin.include_tasks: deploy_env.yml
{{ scripts_dir }}/deploy.sh {{ item.name }} {{ item.port }}
loop: "{{ app_environments }}" loop: "{{ app_environments }}"
loop_control: loop_control:
label: "{{ item.name }}" loop_var: env
register: deploy_result label: "{{ env.name }}"
changed_when: true

View file

@ -0,0 +1,98 @@
---
- name: "{{ env.name }} | Build app image"
ansible.builtin.command:
argv:
- docker
- build
- --build-arg
- "NEXT_PUBLIC_SERVER_URL=https://{{ env.domain }}"
- --build-arg
- "NEXT_PUBLIC_SITE_ID={{ env.site_id }}"
- -t
- "church-website:{{ env.name }}"
- "{{ repo_dir }}"
changed_when: true
- name: "{{ env.name }} | Build migration image"
ansible.builtin.command:
argv:
- docker
- build
- --target
- builder
- --build-arg
- "NEXT_PUBLIC_SERVER_URL=https://{{ env.domain }}"
- --build-arg
- "NEXT_PUBLIC_SITE_ID={{ env.site_id }}"
- -t
- "church-website-migrate:{{ env.name }}"
- "{{ repo_dir }}"
changed_when: true
- name: "{{ env.name }} | Run database migrations"
ansible.builtin.command:
argv:
- docker
- run
- --rm
- --network
- "{{ docker_network }}"
- --env-file
- "{{ envs_dir }}/{{ env.name }}/.env"
- "church-website-migrate:{{ env.name }}"
- npx
- payload
- migrate
changed_when: true
- name: "{{ env.name }} | Stop old container"
ansible.builtin.command: "docker stop app-{{ env.name }}"
failed_when: false
changed_when: true
- name: "{{ env.name }} | Remove old container"
ansible.builtin.command: "docker rm app-{{ env.name }}"
failed_when: false
changed_when: true
- name: "{{ env.name }} | Start new container"
ansible.builtin.command:
argv:
- docker
- run
- -d
- --name
- "app-{{ env.name }}"
- --restart
- unless-stopped
- --network
- "{{ docker_network }}"
- --env-file
- "{{ envs_dir }}/{{ env.name }}/.env"
- -v
- "uploads-{{ env.name }}-media:/app/media"
- -v
- "uploads-{{ env.name }}-documents:/app/documents"
- -p
- "127.0.0.1:{{ env.port }}:3000"
- "church-website:{{ env.name }}"
changed_when: true
- name: "{{ env.name }} | Fix upload volume permissions"
ansible.builtin.command:
argv:
- docker
- exec
- -u
- "0"
- "app-{{ env.name }}"
- chown
- -R
- 1001:1001
- /app/media
- /app/documents
changed_when: true
- name: "{{ env.name }} | Prune old Docker images"
ansible.builtin.command: docker image prune -f
changed_when: true