Skip to content

Commit

Permalink
Add continuous deployment
Browse files Browse the repository at this point in the history
  • Loading branch information
matthijsln committed Sep 11, 2023
1 parent f984ea9 commit 4edaf75
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 0 deletions.
83 changes: 83 additions & 0 deletions .github/workflows/test-and-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,86 @@ jobs:
with:
name: Event File
path: ${{ github.event_path }}

build:
name: 'Build and deploy'
runs-on: ubuntu-22.04
if: vars.DEPLOY == 'true'
env:
VERSION: snapshot
COMPOSE_PROJECT_NAME: ${{ vars.DEPLOY_PROJECT_NAME }}-snapshot
COMPOSE_FILE: docker-compose.yml:docker-compose.traefik.yml
BASE_HREF: /
HOST: ${{ vars.DEPLOY_HOSTNAME }}
ADMIN_HASHED_PASSWORD: ${{ vars.ADMIN_HASHED_PASSWORD }}
BUILDX_NO_DEFAULT_ATTESTATIONS: 1
needs: [ lint, test ]
steps:
- uses: actions/checkout@v4
with:
# If tags aren't fetched the bin/prebuild.js script will leave fields in generated/version.json empty
# https://github.com/actions/checkout/issues/701
fetch-depth: 0
- name: 'GitHub Slug Action'
uses: rlespinasse/github-slug-action@v4

- name: 'Find Current Pull Request'
uses: jwalton/gh-find-current-pr@v1
id: find-pr

- name: 'Set variables for PR'
# When running on a PR, build and tag the Docker image for a deployment with a different base-href and a static-only deployment on
# a path prefix, with the frontend using the /api URL from the main branch deployment.
if: ${{ success() && steps.find-pr.outputs.number }}
env:
PR: ${{ steps.find-pr.outputs.number }}
run: |
echo "VERSION=pr-${PR}" >> $GITHUB_ENV
echo "COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME}-pr-${PR}" >> $GITHUB_ENV
echo "COMPOSE_FILE=docker-compose.yml:docker-compose.traefik.yml:ci/docker-compose.pr.yml" >> $GITHUB_ENV
echo "BASE_HREF=/pull-request/${PR}/${GITHUB_REF_NAME_SLUG_URL}/" >> $GITHUB_ENV
- name: 'Build image'
# Always uses the 'snapshot' tag of the tailormap-api base image by setting the API_VERSION build arg
run: docker build --progress plain --build-arg VERSION=${VERSION} --build-arg API_VERSION=snapshot --tag ${{ vars.DEPLOY_IMAGE_TAG }}:${VERSION} --output type=local,dest=image.tar .

- name: 'Set Docker context for deployment'
uses: arwynfr/actions-docker-context@v2
with:
docker_host: ${{ secrets.DEPLOY_DOCKER_HOST }}
context_name: 'dev-server'
ssh_cert: ${{ secrets.DEPLOY_DOCKER_HOST_SSH_CERT }}
ssh_key: ${{ secrets.DEPLOY_DOCKER_HOST_SSH_KEY }}
use_context: true

- name: 'Add known hosts'
run: |
ssh-keyscan -H ${{ secrets.DOCKER_HOSTNAME }} > $HOME/.ssh/known_hosts
- name: 'Load Docker image'
run: |
docker load --input image.tar
- uses: actions/checkout@v4
with:
repository: B3Partners/tailormap-viewer
path: tailormap-viewer
sparse-checkout: |
docker-compose*.yml
sparse-checkout-cone-mode: false

- name: 'Update deployment using Docker Compose'
run: |
cd tailormap-viewer
docker compose up -d
- name: 'Create GitHub deployment'
if: success()
uses: chrnorm/deployment-action@v2
with:
token: "${{ secrets.GITHUB_TOKEN }}"
environment-url: "https://${{ secrets.DEPLOY_HOST }}${{ env.BASE_HREF}}"
description: "Deployment for ${{ env.VERSION }}"
environment: ${{ env.VERSION }}
initial-status: success
ref: "${{ env.GITHUB_HEAD_REF }}"
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,38 @@ version matches the NPM packages you use in this Angular app.
You can run your customized Tailormap container separately or using the Docker (Compose) configuration in tailormap-viewer. For Docker
Compose, specify your custom image and tag in the `TAILORMAP_IMAGE` and `VERSION` variables in an environment file (see the README of
tailormap-viewer and its `.env.template` for details).

# Setting up continuous deployment

To add continuous deployment, you need a server with Docker and Traefik configured with `--providers.docker` and a Let's Encrypt certificate
resolver named `letsencrypt`. Generate an SSH keypair and add the public key to the `~/.ssh/authorized_keys` file for an account that has
Docker access. Assign a hostname for the deployments to this server.

You can use different SSH keypairs for different deployments. Just add more public keys to the `authorized_keys` file.

Add these repository variables in GitHub to enable deployment.

Like the continuous deployment in `tailormap-viewer`, the Tailormap API backend will only be deployed for the `main` branch and pull request
deployments will only serve the static Angular frontend on a different base path which will use the API for the main deployment on the `/api`
path.

- `DEPLOY`: set to `true`
- `DEPLOY_HOSTNAME`: set to hostname for the server
- `DEPLOY_PROJECT_NAME`: Name of your customized project, used for docker image and container name (a-z)
- `ADMIN_HASHED_PASSWORD`: Hashed password of the tm-admin account, created when the Tailormap configuration database is empty (only the
first deployment unless you remove the volume manually). Generate with Spring CLI: ` docker run --rm rocko/spring-boot-cli-docker spring encodepassword "[your password]"`.
- `DEPLOY_IMAGE_TAG`: Tag for Docker image (without version), for example `ghcr.io/b3partners/tailormap-viewer`. The image is built in a GitHub Actions worker and uploaded to the server -- it is not pushed to
a registry. The version used is `snapshot` for deployments for the main `branch` and `pr-nn` for pull request deployments.

Add the following as GitHub secrets:

- `DEPLOY_DOCKER_HOST`: something like ssh://github-[email protected]
- `DEPLOY_DOCKER_HOST_SSH_CERT`: the public part of the SSH key as added to `authorized_keys`, something like `ssh-rsa AAAAB3NzaC1yc2EAA(...)ei3Uv4zj9/8M= user@host`
- `DEPLOY_DOCKER_HOST_SSH_KEY`: the private part of the SSH key, without passphrase, something like:

```
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAA...
...
-----END OPENSSH PRIVATE KEY-----
```
37 changes: 37 additions & 0 deletions ci/docker-compose.pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Docker Compose overrides for continuous deployment of a PR with a different BASE_HREF, serving only the static frontend without the
# backend API controllers. Traefik labels configure Tailormap to run on a path prefix. The Angular frontend uses `/api/` (absolute URL) to
# the backend, not a relative URL so the backend of Tailormap for the main branch is used.

# Usage (see also the GitHub Actions workflows in .github):
# cat << EOF > env-pr
# VERSION=pr-xxx
# BASE_HREF=/pr-xxx/
# HOST=tailormap.example.com
# COMPOSE_FILE=docker-compose.yml:docker-compose.traefik.yml:ci/docker-compose.pr.yml
# COMPOSE_PROJECT_NAME=tailormap-${VERSION}
# EOF
# docker compose --env-file env-pr build
# docker compose --env-file env-pr up -d
# docker compose --env-file env-pr down -v

services:
tailormap:
environment:
- SPRING_PROFILES_ACTIVE=static-only
healthcheck:
# With the static-only profile the management port 8081 is disabled so the default HEALTHCHECK won't succeed
test: [NONE]
labels:
- "traefik.http.routers.${COMPOSE_PROJECT_NAME:-tailormap}.rule=Host(`${HOST:-localhost}`) && PathPrefix(`${BASE_HREF}`)"
- "traefik.http.routers.${COMPOSE_PROJECT_NAME:-tailormap}.tls=true"
- "traefik.http.routers.${COMPOSE_PROJECT_NAME:-tailormap}.tls.certresolver=letsencrypt"
- "traefik.http.routers.${COMPOSE_PROJECT_NAME:-tailormap}.middlewares=${COMPOSE_PROJECT_NAME:-tailormap}-stripprefix"
- "traefik.http.services.${COMPOSE_PROJECT_NAME:-tailormap}.loadbalancer.server.port=8080"
- "traefik.http.middlewares.${COMPOSE_PROJECT_NAME:-tailormap}-stripprefix.stripprefix.prefixes=${BASE_HREF}"
restart: unless-stopped

db:
image: rwgrim/docker-noop
healthcheck:
disable: true
restart: no

0 comments on commit 4edaf75

Please sign in to comment.