Skip to content

Commit a1ce255

Browse files
authored
feat: Add deployment with Portainer (#74)
* Add deployment with Portainer * Test on PR * Add virtual host and tweak commands * Add environment to workflow * Temp test * Add labels to docker compose * Substitute no switch variables * Switch to no_var * Add one more dollar * Remove deploy on pull request
1 parent 37d26f3 commit a1ce255

File tree

2 files changed

+179
-0
lines changed

2 files changed

+179
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
name: Deploy to staging
2+
3+
run-name: Deploy Sprinter signing with Portainer to staging - ${{ github.event.inputs.image_version || 'latest' }} by @${{ github.actor }}
4+
5+
on:
6+
workflow_run:
7+
workflows: ["Publish Latest Docker Image"]
8+
types:
9+
- completed
10+
workflow_dispatch:
11+
inputs:
12+
image_version:
13+
description: 'Signing version. Example: v2.0.0'
14+
required: true
15+
default: latest
16+
env:
17+
PORTAINER_ENDPOINT_ID: 8
18+
STACK_NAME: sprinter-signing-staging
19+
20+
jobs:
21+
deploy:
22+
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event.inputs.image_version }}
23+
runs-on:
24+
group: portainer-deployment
25+
environment: staging
26+
27+
steps:
28+
- name: Checkout code
29+
uses: actions/checkout@v4
30+
with:
31+
clean: true
32+
33+
- name: Check if stack exists in Portainer
34+
id: check_stack
35+
env:
36+
PORTAINER_URL: ${{ secrets.PORTAINER_URL }}
37+
PORTAINER_API_TOKEN: ${{ secrets.PORTAINER_API_TOKEN }}
38+
run: |
39+
RESPONSE=$(curl -s -H "X-API-Key: ${{ secrets.PORTAINER_API_TOKEN }}" "${{ secrets.PORTAINER_URL }}/api/stacks")
40+
STACK_ID=$(echo "$RESPONSE" | jq -r --arg name "$STACK_NAME" '.[] | select(.Name == $name) | .Id')
41+
42+
if [ -n "$STACK_ID" ]; then
43+
echo "Stack exists. ID: $STACK_ID"
44+
echo "exists=true" >> $GITHUB_OUTPUT
45+
echo "stack_id=$STACK_ID" >> $GITHUB_OUTPUT
46+
else
47+
echo "Stack does not exist."
48+
echo "exists=false" >> $GITHUB_OUTPUT
49+
fi
50+
51+
- name: Render docker-compose.yml with envsubst
52+
env:
53+
DOCKER_COMPOSE_PATH: ./deploy/docker-compose.staging.yml
54+
# export here all secrets used in the docker-compose environment
55+
SIGNING_IMAGE_VERSION: ${{ github.event.inputs.image_version || 'latest' }}
56+
CONFIG_1_FULL: ${{ secrets.CONFIG_1_FULL }}
57+
CONFIG_2_FULL: ${{ secrets.CONFIG_2_FULL }}
58+
CONFIG_3_FULL: ${{ secrets.CONFIG_3_FULL }}
59+
KEYSHARE_1: ${{ secrets.KEYSHARE_1 }}
60+
KEYSHARE_2: ${{ secrets.KEYSHARE_2}}
61+
KEYSHARE_3: ${{ secrets.KEYSHARE_3 }}
62+
SPRINTER_SIGNING_DOMAIN: ${{ secrets.SPRINTER_SIGNING_DOMAIN }}
63+
run: |
64+
envsubst < ${DOCKER_COMPOSE_PATH} > docker-compose.rendered.yml
65+
echo "Rendered docker-compose"
66+
67+
- name: Deploy stack (create or update)
68+
env:
69+
PORTAINER_URL: ${{ secrets.PORTAINER_URL }}
70+
PORTAINER_API_TOKEN: ${{ secrets.PORTAINER_API_TOKEN }}
71+
run: |
72+
ESCAPED_COMPOSE=$(cat docker-compose.rendered.yml | jq -Rs .)
73+
STACK_EXISTS="${{ steps.check_stack.outputs.exists }}"
74+
STACK_ID="${{ steps.check_stack.outputs.stack_id }}"
75+
76+
if [ "$STACK_EXISTS" = "true" ]; then
77+
echo "Updating existing stack with ID: $STACK_ID"
78+
79+
echo "{\"stackFileContent\": $ESCAPED_COMPOSE, \"prune\": true, \"pullImage\": true, \"env\": []}" > payload.json
80+
81+
curl -s -X PUT "$PORTAINER_URL/api/stacks/$STACK_ID?endpointId=$PORTAINER_ENDPOINT_ID" \
82+
-H "X-API-Key: $PORTAINER_API_TOKEN" \
83+
-H "Content-Type: application/json" \
84+
-d @payload.json \
85+
--fail
86+
else
87+
echo "Creating new stack: $STACK_NAME"
88+
89+
echo "{\"name\": \"$STACK_NAME\", \"fromAppTemplate\": false, \"stackFileContent\": $ESCAPED_COMPOSE, \"env\": []}" > payload.json
90+
cat payload.json
91+
curl -v -s -X POST "$PORTAINER_URL/api/stacks/create/standalone/string?endpointId=$PORTAINER_ENDPOINT_ID" \
92+
-H "X-API-Key: $PORTAINER_API_TOKEN" \
93+
-H "Content-Type: application/json" \
94+
-d @payload.json \
95+
--fail
96+
fi
97+
98+
- name: Cleanup
99+
run: rm -rf docker-compose.rendered.yml payload.json

deploy/docker-compose.staging.yml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
services:
2+
relayer1:
3+
image: ghcr.io/sprintertech/sprinter-signing:${SIGNING_IMAGE_VERSION}
4+
command:
5+
- |
6+
mkdir -p /cfg/keyshares
7+
echo $${${no_var}CONFIG_FULL} | base64 --decode > $${${no_var}CONFIG_PATH}
8+
echo $${${no_var}KEYSHARE} | base64 --decode > $${${no_var}KEYSHARE_PATH}
9+
/signing run --config $${${no_var}CONFIG_PATH} --staging
10+
entrypoint: ["/bin/sh", "-c"]
11+
environment:
12+
- CONFIG_FULL=${CONFIG_1_FULL}
13+
- KEYSHARE=${KEYSHARE_1}
14+
- CONFIG_PATH=/cfg/config_1.json
15+
- KEYSHARE_PATH=/cfg/keyshares/0.keyshare
16+
- VIRTUAL_HOST=${SPRINTER_SIGNING_DOMAIN}
17+
labels:
18+
logging: "alloy"
19+
logging_jobname: "containerlogs"
20+
service_name: "signing_relayer_1_staging"
21+
ports:
22+
- 3000:3000
23+
expose:
24+
- "3000"
25+
restart: always
26+
27+
relayer2:
28+
image: ghcr.io/sprintertech/sprinter-signing:${SIGNING_IMAGE_VERSION}
29+
command:
30+
- |
31+
mkdir -p /cfg/keyshares
32+
echo $${${no_var}CONFIG_FULL} | base64 --decode > $${${no_var}CONFIG_PATH}
33+
echo $${${no_var}KEYSHARE} | base64 --decode > $${${no_var}KEYSHARE_PATH}
34+
/signing run --config $${${no_var}CONFIG_PATH} --staging
35+
entrypoint: ["/bin/sh", "-c"]
36+
environment:
37+
- CONFIG_FULL=${CONFIG_2_FULL}
38+
- KEYSHARE=${KEYSHARE_2}
39+
- CONFIG_PATH=/cfg/config_2.json
40+
- KEYSHARE_PATH=/cfg/keyshares/1.keyshare
41+
labels:
42+
logging: "alloy"
43+
logging_jobname: "containerlogs"
44+
service_name: "signing_relayer_2_staging"
45+
restart: always
46+
ports:
47+
- 3001:3000
48+
49+
relayer3:
50+
image: ghcr.io/sprintertech/sprinter-signing:${SIGNING_IMAGE_VERSION}
51+
command:
52+
- |
53+
mkdir -p /cfg/keyshares
54+
echo $${${no_var}CONFIG_FULL} | base64 --decode > $${${no_var}CONFIG_PATH}
55+
echo $${${no_var}KEYSHARE} | base64 --decode > $${${no_var}KEYSHARE_PATH}
56+
/signing run --config $${${no_var}CONFIG_PATH} --staging
57+
entrypoint: ["/bin/sh", "-c"]
58+
environment:
59+
- CONFIG_FULL=${CONFIG_3_FULL}
60+
- KEYSHARE=${KEYSHARE_3}
61+
- CONFIG_PATH=/cfg/config_3.json
62+
- KEYSHARE_PATH=/cfg/keyshares/2.keyshare
63+
labels:
64+
logging: "alloy"
65+
logging_jobname: "containerlogs"
66+
service_name: "signing_relayer_3_staging"
67+
ports:
68+
- 3002:3000
69+
restart: always
70+
71+
# nginx automatically proxies exposed container ports
72+
nginx:
73+
image: jwilder/nginx-proxy:1.7.1
74+
ports:
75+
- "80:80"
76+
- "443:443"
77+
volumes:
78+
- /var/run/docker.sock:/tmp/docker.sock:ro
79+
- /etc/nginx/ssl:/etc/nginx/certs
80+
restart: unless-stopped

0 commit comments

Comments
 (0)