Skip to content

Commit

Permalink
Add some examples and a GitHub integration test (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
joecorall authored Jan 25, 2025
1 parent 0739526 commit a585ae0
Show file tree
Hide file tree
Showing 13 changed files with 291 additions and 3 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
*.json
*.json5
*.md
examples
61 changes: 61 additions & 0 deletions .github/workflows/github-integration-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: github-integration-test
on:
push:

permissions:
contents: read

jobs:
rollout:
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
id-token: write
steps:
- uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # v4

# if you're copying this into your repo
# you would just need the run step
# the build/start/cleanup are just used so we can run smoke tests in this repo
- name: build
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6
with:
context: .
tags: |
rollout:latest
- name: start
run: |
docker run \
-d \
-p 8080:8080 \
--rm \
--name=rollout \
-v ./examples/github/rollout.sh:/rollout.sh \
--env JWKS_URI="https://token.actions.githubusercontent.com/.well-known/jwks" \
--env JWT_AUD=https://github.com/lehigh-university-libraries \
rollout:latest
for i in {1..5}; do
if curl -s http://localhost:8080/healthcheck | grep "ok"; then
echo "container ready"
exit 0
fi
echo "Waiting for container to be ready..."
sleep 2
done
echo "🚨 Container did not start in time" && exit 1
- name: run
env:
# TODO - replace with your rollout URL
# and not the docker service we're running here in GitHub Action
ROLLOUT_URL: http://localhost:8080/
run: ./examples/github/trigger-rollout.sh

- name: cleanup
if: ${{ always() }}
run: |
docker logs rollout
docker stop rollout
2 changes: 1 addition & 1 deletion .github/workflows/validate-renovate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ jobs:
with:
node-version: 20

- run: npx -p renovate renovate-config-validator renovate.json5
- run: npx -p renovate renovate-config-validator renovate.json5
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,5 @@ JWT_AUD=aud-string-you-set-in-your-job

## TODO

- [ ] Add a full example for GitLab
- [ ] Add a full example for GitHub
- [ ] Install instructions using binary
- [ ] Tag/push versions to dockerhub
11 changes: 11 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Example CI/CD

In this directory is [a docker-compose template](./docker-compose.yml) that would be deployed into your environment(s) to allow the CI/CD system to send requests to the rollout service.

## GitHub

In the [github](../.github/workflows/github-integration-test.yml) you will find a sample GitHub Action you could add to your GitHub repo to trigger deployments.

## GitLab

In the [gitlab](./gitlab) directory, you will find a sample `.gitlab-ci.yml` you could add to your GitLab repo to trigger deployments from self-hosted or gitlab.com
56 changes: 56 additions & 0 deletions examples/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
networks:
default:
services:
# use traefik as a reverse proxy for rollout
# swap it with your favorite (i.e. haproxy/nginx/etc)
traefik:
command: >-
--api.insecure=true
--api.dashboard=true
--api.debug=true
--ping=true
--entryPoints.http.address=:80
--entryPoints.https.address=:443
--entryPoints.http.forwardedHeaders.trustedIPs=${FRONTEND_IP_1},${FRONTEND_IP_2},${FRONTEND_IP_3}
--entryPoints.https.forwardedHeaders.trustedIPs=${FRONTEND_IP_1},${FRONTEND_IP_2},${FRONTEND_IP_3}
--entryPoints.https.transport.respondingTimeouts.readTimeout=3600
--providers.file.filename=/etc/traefik/tls.yml
--providers.docker=true
--providers.docker.network=default
--providers.docker.exposedByDefault=false
labels:
traefik.enable: false
volumes:
- ./certs:/etc/ssl/traefik:Z,ro
- ./tls.yml:/etc/traefik/tls.yml:Z,ro
- /var/run/docker.sock:/var/run/docker.sock:z
healthcheck:
test: traefik healthcheck --ping
rollout:
image: lehighlts/rollout:main
labels:
traefik.enable: true
traefik.http.routers.rollout.entrypoints: https
traefik.http.routers.rollout.rule: PathPrefix(`/path/to/rollout`)
traefik.http.routers.rollout.tls.certresolver: *traefik-certresolver
traefik.http.routers.rollout.tls: true
traefik.http.services.rollout.loadbalancer.server.port: 8080
traefik.http.routers.rollout.middlewares: rollout-ip
# add all your trusted domains
traefik.http.middlewares.rollout-ip.ipwhitelist.sourcerange: 172.16.0.0/12, 192.168.0.0/16, 127.0.0.1/32
# would increment to 1 if traefik (which is proxying this service)
# was also behind a reverse proxy
traefik.http.middlewares.rollout-ip.ipwhitelist.ipstrategy.depth: 0
volumes:
- /optionally/your/code/base:/code
- /optionally/other/files/to/help/with/git/docker/etc/auth:/some/other/path
- ./rollout.sh:/rollout.sh
# if you need to run docker commands in rollout.sh
- /var/run/docker.sock:/var/run/docker.sock
environment:
JWKS_URI: ${JWKS_URI}
JWT_AUD: $HOST
CUSTOM_CLAIMS: ${CUSTOM_CLAIMS}
GIT_BRANCH: ${GIT_BRANCH}
ROLLOUT_LOCK_FILE: /tmp/rollout.lock
5 changes: 5 additions & 0 deletions examples/github/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# GitHub rollout example

In this example, you can see the GitHub Action YML in [.github/workflows/github-integration-test.yml](../.github/workflows/github-integration-test.yml) that you could add to your GitHub repo to trigger deployments.

The GitHub YML creates an OIDC token and uses that to authenticate to the rollout service.
6 changes: 6 additions & 0 deletions examples/github/rollout.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash

set -eou pipefail

echo "Rolling out $GIT_BRANCH"
echo "I might git pull or docker compose up -d here."
39 changes: 39 additions & 0 deletions examples/github/trigger-rollout.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env bash

set -eou pipefail

echo "Fetching GitHub OIDC token"
TOKEN=$(curl -s \
-H "Accept: application/json; api-version=2.0" \
-H "Content-Type: application/json" -d "{}" \
-H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL" | jq -er '.value')

# add some buffer to avoid iat issues
sleep 5

echo "Triggering rollout via $ROLLOUT_URL"
echo "${TOKEN}" | jq -rR 'split(".") | .[1] | @base64d | fromjson | .aud'

for i in {1..3}; do
STATUS=$(curl -s \
--max-time 900 \
-w '%{http_code}' \
-o /dev/null \
-d '{"git-branch": "'"${GITHUB_REF_NAME}"'"}' \
-H "Authorization: Bearer ${TOKEN}" \
"${ROLLOUT_URL}")

echo "Received $STATUS"
if [ "${STATUS}" = 200 ]; then
echo "Rollout complete"
exit 0
fi

SLEEP_INTERVAL=$(( 60 * i ))
echo "trying again in ${SLEEP_INTERVAL}s"
sleep "${SLEEP_INTERVAL}"
done

echo "Rollout failed. Check logs"
exit 1
68 changes: 68 additions & 0 deletions examples/gitlab/.gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
workflow:
auto_cancel:
on_new_commit: interruptible

stages:
- build-lint-test-push
- deploy

build-lint-test-push:
interruptible: true
stage: build-lint-test
id_tokens:
ID_TOKEN_1:
aud: your-dev-server-claim
variables:
ROLLOUT_URL: https://dev.example.com/proxied/path/to/rollout
script:
- YOUR LINT/BUILD SCRIPT(s)
- ./trigger-rollout.sh # deploy to dev
- YOUR TEST SCRIPT(S)
- YOUR PUSH SCRIPT(s)
tags:
- your
- runner
- tags
- dev
- maybe they're all the same

deploy_stage:
stage: deploy
dependencies:
- push
id_tokens:
ID_TOKEN_1:
aud: your-stage-server-claim
variables:
ROLLOUT_URL: https://stage.example.com/proxied/path/to/rollout
script:
- ./trigger-rollout.sh
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
tags:
- your
- runner
- tags
- stage
- maybe they're all the same

deploy_prod:
stage: deploy
dependencies:
- deploy_stage
id_tokens:
ID_TOKEN_1:
aud: your-prod-server-claim
variables:
ROLLOUT_URL: https://prod.example.com/proxied/path/to/rollout
script:
- ./trigger-rollout.sh
when: manual
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
tags:
- your
- runner
- tags
- prod
- maybe they're all the same
7 changes: 7 additions & 0 deletions examples/gitlab/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# GitLab rollout example

In this example, you can find the [.gitlab-ci.yml](./.gitlab-ci.yml) you could add to your repo, along with [a bash script](./trigger-rollout.sh) that calls the rollout service deployed in your environment(s).

The GitLab CI deploys to a dev/stage/prod environment, and has exponential backoff on the deploy.

See https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html for more information on the `id_tokens` YML spec.
29 changes: 29 additions & 0 deletions examples/gitlab/trigger-rollout.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash

set -eou pipefail

echo "Triggering rollout via $ROLLOUT_URL"
echo "${ID_TOKEN_1}" | jq -rR 'split(".") | .[1] | @base64d | fromjson | .project_path + " " + .user_email + " " + .aud'

for i in {1..3}; do
STATUS=$(curl -s \
--max-time 900 \
-w '%{http_code}' \
-o /dev/null \
-d '{"git-branch": "'"${CI_COMMIT_BRANCH}"'"}' \
-H "Authorization: bearer ${ID_TOKEN_1}" \
"${ROLLOUT_URL}")

echo "Received $STATUS"
if [ "${STATUS}" = 200 ]; then
echo "Rollout complete"
exit 0
fi

SLEEP_INTERVAL=$(( 60 * i ))
echo "trying again in ${SLEEP_INTERVAL}s"
sleep "${SLEEP_INTERVAL}"
done

echo "Rollout failed. Check logs"
exit 1
7 changes: 7 additions & 0 deletions examples/tls.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# traefik TLS config
tls:
stores:
default:
defaultCertificate:
certFile: /etc/ssl/traefik/cert.pem
keyFile: /etc/ssl/traefik/privkey.pem

0 comments on commit a585ae0

Please sign in to comment.