mirror of
https://github.com/chatmail/relay.git
synced 2026-05-10 16:04:37 +00:00
feat: add CI for docker
Docker and Compose support is provided through a standalone repo at https://github.com/chatmail/docker, add reusable Docker build/test CI jobs to staging workflows and a Docker docs stub pointing to the chatmail/docker repository. Requires CHATMAIL_DOCKER_DISPATCH_TOKEN secret in relay repo settings (fine-grained PAT with contents:write on chatmail/docker).
This commit is contained in:
125
.github/workflows/docker-deploy.yaml
vendored
Normal file
125
.github/workflows/docker-deploy.yaml
vendored
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
name: Docker deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
staging_host:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: 'SSH hostname (e.g. staging2.testrun.org)'
|
||||||
|
mail_domain:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: 'MAIL_DOMAIN for docker compose'
|
||||||
|
zone_file:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: 'Default zone file basename (e.g. staging.testrun.org-default.zone)'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy-docker:
|
||||||
|
name: Docker deploy on ${{ inputs.staging_host }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 20
|
||||||
|
environment:
|
||||||
|
name: ${{ inputs.staging_host }}
|
||||||
|
url: https://${{ inputs.staging_host }}/
|
||||||
|
concurrency: ${{ inputs.staging_host }}
|
||||||
|
env:
|
||||||
|
VPS: root@${{ inputs.staging_host }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- name: Setup SSH
|
||||||
|
run: |
|
||||||
|
mkdir ~/.ssh
|
||||||
|
echo "${{ secrets.STAGING_SSH_KEY }}" >> ~/.ssh/id_ed25519
|
||||||
|
chmod 600 ~/.ssh/id_ed25519
|
||||||
|
ssh-keyscan ${{ inputs.staging_host }} > ~/.ssh/known_hosts
|
||||||
|
# Reuse TCP connection for all subsequent ssh/scp calls
|
||||||
|
echo -e "Host ${{ inputs.staging_host }}\n ControlMaster auto\n ControlPath ~/.ssh/ctrl-%r@%h:%p\n ControlPersist 10m" >> ~/.ssh/config
|
||||||
|
|
||||||
|
- name: stop bare services, install Docker, prepare mounts
|
||||||
|
run: |
|
||||||
|
ssh $VPS bash -s <<'EOF'
|
||||||
|
systemctl stop postfix dovecot nginx opendkim unbound filtermail doveauth chatmail-metadata iroh-relay mtail fcgiwrap acmetool 2>/dev/null || true
|
||||||
|
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc && chmod a+r /etc/apt/keyrings/docker.asc
|
||||||
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo $VERSION_CODENAME) stable" > /etc/apt/sources.list.d/docker.list
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||||
|
mkdir -p /srv/chatmail/certs /srv/chatmail/dkim
|
||||||
|
cp -a /var/lib/acme/. /srv/chatmail/certs/ || true
|
||||||
|
cp -a /etc/dkimkeys/. /srv/chatmail/dkim/ || true
|
||||||
|
cp /etc/chatmail/chatmail.ini /srv/chatmail/chatmail.ini
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: deploy with Docker
|
||||||
|
run: |
|
||||||
|
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
|
||||||
|
GHCR_IMAGE="ghcr.io/chatmail/docker:sha-${SHORT_SHA}"
|
||||||
|
rsync -avz --exclude='.git' --exclude='venv' --exclude='__pycache__' ./ $VPS:/srv/chatmail/relay/
|
||||||
|
echo "${{ secrets.GITHUB_TOKEN }}" | ssh $VPS "docker login ghcr.io -u ${{ github.actor }} --password-stdin && \
|
||||||
|
docker pull ${GHCR_IMAGE} && \
|
||||||
|
cd /srv/chatmail/relay && CHATMAIL_IMAGE=${GHCR_IMAGE} MAIL_DOMAIN=${{ inputs.mail_domain }} docker compose -f docker/docker-compose.yaml -f docker/docker-compose.ci.yaml up -d"
|
||||||
|
|
||||||
|
- name: wait for container healthy
|
||||||
|
run: |
|
||||||
|
ssh $VPS 'docker exec chatmail journalctl -f --no-pager' &
|
||||||
|
LOG_PID=$!
|
||||||
|
trap "kill $LOG_PID 2>/dev/null || true" EXIT
|
||||||
|
for i in $(seq 1 60); do
|
||||||
|
status=$(ssh $VPS 'docker inspect --format={{.State.Health.Status}} chatmail 2>/dev/null' || echo "missing")
|
||||||
|
echo " [$i/60] status=$status"
|
||||||
|
if [ "$status" = "healthy" ]; then
|
||||||
|
echo "Container is healthy."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
if [ "$status" = "unhealthy" ]; then
|
||||||
|
echo "Container is unhealthy!"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
echo "Container did not become healthy."
|
||||||
|
kill $LOG_PID 2>/dev/null || true
|
||||||
|
ssh $VPS bash -s <<'EOF'
|
||||||
|
echo "--- failed units ---"
|
||||||
|
docker exec chatmail systemctl --failed --no-pager || true
|
||||||
|
echo "--- service logs ---"
|
||||||
|
docker exec chatmail journalctl -u dovecot -u postfix -u nginx -u unbound --no-pager -n 50 || true
|
||||||
|
echo "--- listening ports ---"
|
||||||
|
docker exec chatmail ss -tlnp || true
|
||||||
|
echo "--- chatmail.ini ---"
|
||||||
|
docker exec chatmail cat /etc/chatmail/chatmail.ini || true
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
|
||||||
|
- name: show container state
|
||||||
|
run: |
|
||||||
|
ssh $VPS bash -s <<'EOF'
|
||||||
|
echo "--- listening ports ---"
|
||||||
|
docker exec chatmail ss -tlnp
|
||||||
|
echo "--- chatmail.ini ---"
|
||||||
|
docker exec chatmail cat /etc/chatmail/chatmail.ini
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Docker integration tests
|
||||||
|
run: ssh $VPS 'docker exec chatmail cmdeploy test --slow --ssh-host @local'
|
||||||
|
|
||||||
|
- name: Docker DNS
|
||||||
|
run: |
|
||||||
|
git checkout .github/workflows/${{ inputs.zone_file }}
|
||||||
|
ssh $VPS bash -s <<'EOF'
|
||||||
|
docker exec chatmail chown opendkim:opendkim -R /etc/dkimkeys
|
||||||
|
docker exec chatmail cmdeploy dns --ssh-host @local --zonefile /opt/chatmail/staging.zone --verbose
|
||||||
|
docker cp chatmail:/opt/chatmail/staging.zone /tmp/staging.zone
|
||||||
|
EOF
|
||||||
|
scp $VPS:/tmp/staging.zone staging-generated.zone
|
||||||
|
cat staging-generated.zone >> .github/workflows/${{ inputs.zone_file }}
|
||||||
|
cat .github/workflows/${{ inputs.zone_file }}
|
||||||
|
scp .github/workflows/${{ inputs.zone_file }} root@ns.testrun.org:/etc/nsd/${{ inputs.staging_host }}.zone
|
||||||
|
ssh root@ns.testrun.org "nsd-checkzone ${{ inputs.staging_host }} /etc/nsd/${{ inputs.staging_host }}.zone && systemctl reload nsd"
|
||||||
|
|
||||||
|
- name: Docker final DNS check
|
||||||
|
run: ssh $VPS 'docker exec chatmail cmdeploy dns -v --ssh-host @local'
|
||||||
19
.github/workflows/test-and-deploy-ipv4only.yaml
vendored
19
.github/workflows/test-and-deploy-ipv4only.yaml
vendored
@@ -4,6 +4,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- j4n/docker-pr
|
||||||
pull_request:
|
pull_request:
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- 'scripts/**'
|
- 'scripts/**'
|
||||||
@@ -12,6 +13,11 @@ on:
|
|||||||
- 'LICENSE'
|
- 'LICENSE'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
trigger-docker-build:
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
uses: ./.github/workflows/trigger-docker-build.yaml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
name: deploy on staging-ipv4.testrun.org, and run tests
|
name: deploy on staging-ipv4.testrun.org, and run tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -22,6 +28,8 @@ jobs:
|
|||||||
concurrency: staging-ipv4.testrun.org
|
concurrency: staging-ipv4.testrun.org
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
|
||||||
- name: prepare SSH
|
- name: prepare SSH
|
||||||
run: |
|
run: |
|
||||||
@@ -63,7 +71,7 @@ jobs:
|
|||||||
# download acme & dkim state from ns.testrun.org
|
# download acme & dkim state from ns.testrun.org
|
||||||
rsync -e "ssh -o StrictHostKeyChecking=accept-new" -avz root@ns.testrun.org:/tmp/acme-ipv4/acme acme-restore || true
|
rsync -e "ssh -o StrictHostKeyChecking=accept-new" -avz root@ns.testrun.org:/tmp/acme-ipv4/acme acme-restore || true
|
||||||
rsync -avz root@ns.testrun.org:/tmp/dkimkeys-ipv4/dkimkeys dkimkeys-restore || true
|
rsync -avz root@ns.testrun.org:/tmp/dkimkeys-ipv4/dkimkeys dkimkeys-restore || true
|
||||||
# restore acme & dkim state to staging2.testrun.org
|
# restore acme & dkim state to staging-ipv4.testrun.org
|
||||||
rsync -avz acme-restore/acme root@staging-ipv4.testrun.org:/var/lib/ || true
|
rsync -avz acme-restore/acme root@staging-ipv4.testrun.org:/var/lib/ || true
|
||||||
rsync -avz dkimkeys-restore/dkimkeys root@staging-ipv4.testrun.org:/etc/ || true
|
rsync -avz dkimkeys-restore/dkimkeys root@staging-ipv4.testrun.org:/etc/ || true
|
||||||
ssh -o StrictHostKeyChecking=accept-new -v root@staging-ipv4.testrun.org chown root:root -R /var/lib/acme || true
|
ssh -o StrictHostKeyChecking=accept-new -v root@staging-ipv4.testrun.org chown root:root -R /var/lib/acme || true
|
||||||
@@ -102,3 +110,12 @@ jobs:
|
|||||||
- name: cmdeploy dns
|
- name: cmdeploy dns
|
||||||
run: ssh root@staging-ipv4.testrun.org "cd relay && scripts/cmdeploy dns -v --ssh-host localhost"
|
run: ssh root@staging-ipv4.testrun.org "cd relay && scripts/cmdeploy dns -v --ssh-host localhost"
|
||||||
|
|
||||||
|
deploy-docker:
|
||||||
|
needs: [deploy, trigger-docker-build]
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
uses: ./.github/workflows/docker-deploy.yaml
|
||||||
|
with:
|
||||||
|
staging_host: staging-ipv4.testrun.org
|
||||||
|
mail_domain: staging-ipv4.testrun.org
|
||||||
|
zone_file: staging-ipv4.testrun.org-default.zone
|
||||||
|
secrets: inherit
|
||||||
|
|||||||
15
.github/workflows/test-and-deploy.yaml
vendored
15
.github/workflows/test-and-deploy.yaml
vendored
@@ -4,6 +4,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- j4n/docker-pr
|
||||||
pull_request:
|
pull_request:
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- 'scripts/**'
|
- 'scripts/**'
|
||||||
@@ -12,6 +13,11 @@ on:
|
|||||||
- 'LICENSE'
|
- 'LICENSE'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
trigger-docker-build:
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
uses: ./.github/workflows/trigger-docker-build.yaml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
name: deploy on staging2.testrun.org, and run tests
|
name: deploy on staging2.testrun.org, and run tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -95,3 +101,12 @@ jobs:
|
|||||||
- name: cmdeploy dns
|
- name: cmdeploy dns
|
||||||
run: cmdeploy dns -v
|
run: cmdeploy dns -v
|
||||||
|
|
||||||
|
deploy-docker:
|
||||||
|
needs: [deploy, trigger-docker-build]
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
uses: ./.github/workflows/docker-deploy.yaml
|
||||||
|
with:
|
||||||
|
staging_host: staging2.testrun.org
|
||||||
|
mail_domain: staging2.testrun.org
|
||||||
|
zone_file: staging.testrun.org-default.zone
|
||||||
|
secrets: inherit
|
||||||
|
|||||||
24
.github/workflows/trigger-docker-build.yaml
vendored
Normal file
24
.github/workflows/trigger-docker-build.yaml
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
name: Trigger Docker image build
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
trigger-docker-build:
|
||||||
|
name: Trigger Docker image build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.CHATMAIL_DOCKER_DISPATCH_TOKEN }}
|
||||||
|
script: |
|
||||||
|
await github.rest.repos.createDispatchEvent({
|
||||||
|
owner: 'chatmail',
|
||||||
|
repo: 'docker',
|
||||||
|
event_type: 'relay-updated',
|
||||||
|
client_payload: {
|
||||||
|
relay_ref: context.ref,
|
||||||
|
relay_sha: context.sha,
|
||||||
|
relay_sha_short: context.sha.slice(0, 7)
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -98,6 +98,13 @@ steps. Please substitute it with your own domain.
|
|||||||
configure at your DNS provider (it can take some time until they are
|
configure at your DNS provider (it can take some time until they are
|
||||||
public).
|
public).
|
||||||
|
|
||||||
|
Docker installation
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
There is experimental support for running chatmail via Docker Compose.
|
||||||
|
See the `chatmail/docker README <https://github.com/chatmail/docker>`_
|
||||||
|
for full setup instructions.
|
||||||
|
|
||||||
Other helpful commands
|
Other helpful commands
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user