Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions .github/workflows/deploy-portainer-staging.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
name: Deploy to staging

run-name: Deploy Sprinter signing with Portainer to staging - ${{ github.event.inputs.image_version || 'latest' }} by @${{ github.actor }}

on:
workflow_run:
workflows: ["Publish Latest Docker Image"]
types:
- completed
workflow_dispatch:
inputs:
image_version:
description: 'Signing version. Example: v2.0.0'
required: true
default: latest
env:
PORTAINER_ENDPOINT_ID: 8
STACK_NAME: sprinter-signing-staging

jobs:
deploy:
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event.inputs.image_version }}
runs-on:
group: portainer-deployment
environment: staging

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
clean: true

- name: Check if stack exists in Portainer
id: check_stack
env:
PORTAINER_URL: ${{ secrets.PORTAINER_URL }}
PORTAINER_API_TOKEN: ${{ secrets.PORTAINER_API_TOKEN }}
run: |
RESPONSE=$(curl -s -H "X-API-Key: ${{ secrets.PORTAINER_API_TOKEN }}" "${{ secrets.PORTAINER_URL }}/api/stacks")
STACK_ID=$(echo "$RESPONSE" | jq -r --arg name "$STACK_NAME" '.[] | select(.Name == $name) | .Id')

if [ -n "$STACK_ID" ]; then
echo "Stack exists. ID: $STACK_ID"
echo "exists=true" >> $GITHUB_OUTPUT
echo "stack_id=$STACK_ID" >> $GITHUB_OUTPUT
else
echo "Stack does not exist."
echo "exists=false" >> $GITHUB_OUTPUT
fi

- name: Render docker-compose.yml with envsubst
env:
DOCKER_COMPOSE_PATH: ./deploy/docker-compose.staging.yml
# export here all secrets used in the docker-compose environment
SIGNING_IMAGE_VERSION: ${{ github.event.inputs.image_version || 'latest' }}
CONFIG_1_FULL: ${{ secrets.CONFIG_1_FULL }}
CONFIG_2_FULL: ${{ secrets.CONFIG_2_FULL }}
CONFIG_3_FULL: ${{ secrets.CONFIG_3_FULL }}
KEYSHARE_1: ${{ secrets.KEYSHARE_1 }}
KEYSHARE_2: ${{ secrets.KEYSHARE_2}}
KEYSHARE_3: ${{ secrets.KEYSHARE_3 }}
SPRINTER_SIGNING_DOMAIN: ${{ secrets.SPRINTER_SIGNING_DOMAIN }}
run: |
envsubst < ${DOCKER_COMPOSE_PATH} > docker-compose.rendered.yml
echo "Rendered docker-compose"

- name: Deploy stack (create or update)
env:
PORTAINER_URL: ${{ secrets.PORTAINER_URL }}
PORTAINER_API_TOKEN: ${{ secrets.PORTAINER_API_TOKEN }}
run: |
ESCAPED_COMPOSE=$(cat docker-compose.rendered.yml | jq -Rs .)
STACK_EXISTS="${{ steps.check_stack.outputs.exists }}"
STACK_ID="${{ steps.check_stack.outputs.stack_id }}"

if [ "$STACK_EXISTS" = "true" ]; then
echo "Updating existing stack with ID: $STACK_ID"

echo "{\"stackFileContent\": $ESCAPED_COMPOSE, \"prune\": true, \"pullImage\": true, \"env\": []}" > payload.json

curl -s -X PUT "$PORTAINER_URL/api/stacks/$STACK_ID?endpointId=$PORTAINER_ENDPOINT_ID" \
-H "X-API-Key: $PORTAINER_API_TOKEN" \
-H "Content-Type: application/json" \
-d @payload.json \
--fail
else
echo "Creating new stack: $STACK_NAME"

echo "{\"name\": \"$STACK_NAME\", \"fromAppTemplate\": false, \"stackFileContent\": $ESCAPED_COMPOSE, \"env\": []}" > payload.json
cat payload.json
curl -v -s -X POST "$PORTAINER_URL/api/stacks/create/standalone/string?endpointId=$PORTAINER_ENDPOINT_ID" \
-H "X-API-Key: $PORTAINER_API_TOKEN" \
-H "Content-Type: application/json" \
-d @payload.json \
--fail
fi

- name: Cleanup
run: rm -rf docker-compose.rendered.yml payload.json
80 changes: 80 additions & 0 deletions deploy/docker-compose.staging.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
services:
relayer1:
image: ghcr.io/sprintertech/sprinter-signing:${SIGNING_IMAGE_VERSION}
command:
- |
mkdir -p /cfg/keyshares
echo $${${no_var}CONFIG_FULL} | base64 --decode > $${${no_var}CONFIG_PATH}
echo $${${no_var}KEYSHARE} | base64 --decode > $${${no_var}KEYSHARE_PATH}
/signing run --config $${${no_var}CONFIG_PATH} --staging
entrypoint: ["/bin/sh", "-c"]
environment:
- CONFIG_FULL=${CONFIG_1_FULL}
- KEYSHARE=${KEYSHARE_1}
- CONFIG_PATH=/cfg/config_1.json
- KEYSHARE_PATH=/cfg/keyshares/0.keyshare
- VIRTUAL_HOST=${SPRINTER_SIGNING_DOMAIN}
labels:
logging: "alloy"
logging_jobname: "containerlogs"
service_name: "signing_relayer_1_staging"
ports:
- 3000:3000
expose:
- "3000"
restart: always

relayer2:
image: ghcr.io/sprintertech/sprinter-signing:${SIGNING_IMAGE_VERSION}
command:
- |
mkdir -p /cfg/keyshares
echo $${${no_var}CONFIG_FULL} | base64 --decode > $${${no_var}CONFIG_PATH}
echo $${${no_var}KEYSHARE} | base64 --decode > $${${no_var}KEYSHARE_PATH}
/signing run --config $${${no_var}CONFIG_PATH} --staging
entrypoint: ["/bin/sh", "-c"]
environment:
- CONFIG_FULL=${CONFIG_2_FULL}
- KEYSHARE=${KEYSHARE_2}
- CONFIG_PATH=/cfg/config_2.json
- KEYSHARE_PATH=/cfg/keyshares/1.keyshare
labels:
logging: "alloy"
logging_jobname: "containerlogs"
service_name: "signing_relayer_2_staging"
restart: always
ports:
- 3001:3000

relayer3:
image: ghcr.io/sprintertech/sprinter-signing:${SIGNING_IMAGE_VERSION}
command:
- |
mkdir -p /cfg/keyshares
echo $${${no_var}CONFIG_FULL} | base64 --decode > $${${no_var}CONFIG_PATH}
echo $${${no_var}KEYSHARE} | base64 --decode > $${${no_var}KEYSHARE_PATH}
/signing run --config $${${no_var}CONFIG_PATH} --staging
entrypoint: ["/bin/sh", "-c"]
environment:
- CONFIG_FULL=${CONFIG_3_FULL}
- KEYSHARE=${KEYSHARE_3}
- CONFIG_PATH=/cfg/config_3.json
- KEYSHARE_PATH=/cfg/keyshares/2.keyshare
labels:
logging: "alloy"
logging_jobname: "containerlogs"
service_name: "signing_relayer_3_staging"
ports:
- 3002:3000
restart: always

# nginx automatically proxies exposed container ports
nginx:
image: jwilder/nginx-proxy:1.7.1
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- /etc/nginx/ssl:/etc/nginx/certs
restart: unless-stopped
Loading