Skip to content

Commit b845e06

Browse files
committed
chore: rewrite ecamp3 deployment to helmfile
That it is easier to use github action secrets and vars in the deployment. Leave dev and stage-prod in separate files that the review is somehow easier. They will be put into one workflow in the next commit.
1 parent 49995ce commit b845e06

20 files changed

+724
-588
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
name: 'Setup helmfile'
2+
description: 'Sets up helmfile in /usr/local/bin/helmfile'
3+
runs:
4+
using: "composite"
5+
steps:
6+
- name: install helmfile
7+
run: |
8+
curl -L https://github.com/helmfile/helmfile/releases/download/v1.1.3/helmfile_1.1.3_linux_amd64.tar.gz -o helmfile.tar.gz
9+
tar -xvf /tmp/helmfile.tar.gz
10+
mv helmfile /usr/local/bin
11+
chmod +x /usr/local/bin/helmfile
12+
working-directory: /tmp
13+
shell: bash

.github/workflows/deployment-devel.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ on:
55
branches:
66
- devel
77
workflow_dispatch:
8+
inputs:
9+
action:
10+
description: "Choose action"
11+
type: choice
12+
required: true
13+
default: diff
14+
options:
15+
- diff
16+
- deploy
817

918
jobs:
1019
continuous-integration:
@@ -29,4 +38,5 @@ jobs:
2938
with:
3039
name: dev
3140
env: dev
32-
secrets: inherit
41+
action: ${{ github.event.inputs.action || 'deploy' }}
42+
secrets: inherit

.github/workflows/deployment-pr.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ name: CD for feature branches
33
on:
44
pull_request_target:
55
types: [opened, reopened, labeled, synchronize]
6+
workflow_dispatch:
7+
inputs:
8+
action:
9+
description: "Choose action"
10+
type: choice
11+
required: true
12+
default: diff
13+
options:
14+
- diff
15+
- deploy
616

717
concurrency:
818
group: ${{ github.workflow}}-${{ github.event.pull_request.number }}
@@ -30,4 +40,5 @@ jobs:
3040
env: feature-branch
3141
pr-number: ${{ github.event.pull_request.number }}
3242
dropDBOnUninstall: true
43+
action: ${{ github.event.inputs.action || 'deploy' }}
3344
secrets: inherit

.github/workflows/deployment-stage-prod.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@ on:
99
- staging
1010
- prod
1111
workflow_dispatch:
12+
inputs:
13+
action:
14+
description: "Choose action"
15+
type: choice
16+
required: true
17+
default: diff
18+
options:
19+
- diff
20+
- deploy
1221

1322
jobs:
1423
build-and-push:
@@ -25,4 +34,8 @@ jobs:
2534
name: Upgrade or install deployment
2635
needs: build-and-push
2736
uses: ./.github/workflows/reusable-stage-prod-deployment.yml
37+
with:
38+
name: ${{ github.ref_name }}
39+
env: ${{ github.ref_name }}
40+
action: ${{ github.event.inputs.action || 'deploy' }}
2841
secrets: inherit

.github/workflows/reusable-dev-deployment.yml

Lines changed: 62 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1-
name: '[reusable only] Development deployment'
1+
name: '[reusable only] ecamp3 deployment'
22

33
on:
44
workflow_call:
55
inputs:
66
name:
7-
required: true
7+
description: Deployment short name for subdomain (e.g. dev, pr123).
8+
required: false
89
type: string
910
sha:
1011
required: false
1112
type: string
1213
default: ${{ github.sha }}
1314
env:
15+
description: Target environment (dev, feature-branch, staging, prod)
1416
required: true
1517
type: string
1618
pr-number:
@@ -23,9 +25,19 @@ on:
2325
restoreSourceFile:
2426
required: false
2527
type: string
28+
action:
29+
description: "Choose action of (diff|deploy)"
30+
type: string
31+
required: true
32+
default: diff
33+
34+
env:
35+
NAME: ${{ inputs.name }}
36+
IMAGE_TAG: ${{ inputs.sha }}
37+
HELM_TIMEOUT: ${{ vars.HELM_TIMEOUT }}
2638

2739
jobs:
28-
dev-deployment:
40+
deploy-ecamp3:
2941
name: Deploy to Kubernetes
3042
runs-on: ubuntu-latest
3143
environment:
@@ -36,15 +48,15 @@ jobs:
3648
id: job-url
3749
with:
3850
github_token: ${{ secrets.GITHUB_TOKEN }}
39-
job_name: Upgrade or install deployment / Deploy to Kubernetes
51+
job_name: Deploy to Kubernetes
4052

4153
- name: Create a pending GitHub deployment
4254
uses: bobheadxi/deployments@v1.5.0
4355
id: deployment
4456
with:
4557
step: start
4658
token: ${{ secrets.REPO_ACCESS_TOKEN }}
47-
env: ${{ inputs.name }}
59+
env: ${{ inputs.env }}
4860

4961
- name: Comment progress on PR
5062
uses: thollander/actions-comment-pull-request@v3
@@ -65,74 +77,51 @@ jobs:
6577
with:
6678
ref: ${{ inputs.sha }}
6779

68-
- name: Upgrade or install helm release
69-
env:
70-
never_uninstall: ${{ needs.find-prs-to-deploy.outputs.never-uninstall }}
80+
- name: Dump secrets to /tmp/secrets.json
81+
run: |
82+
cat << 'EOF' | tee /tmp/secrets.json
83+
${{ toJSON(secrets) }}
84+
EOF
85+
jq '.' /tmp/secrets.json
86+
87+
- name: Dump variables to /tmp/vars.json
88+
run: |
89+
cat << 'EOF' | tee /tmp/vars.json
90+
${{ toJSON(vars) }}
91+
EOF
92+
jq '.' /tmp/vars.json
93+
94+
- name: Merge secrets, variables, and workflow inputs to env.yaml
95+
run: |
96+
jq -n \
97+
'{
98+
NAME: "${{ inputs.name }}",
99+
IMAGE_TAG: "${{ inputs.sha }}",
100+
RESTORE_SOURCE_FILE: "${{ inputs.restoreSourceFile || '' }}",
101+
DROP_DB_ON_UNINSTALL: ${{ inputs.dropDBOnUninstall }}
102+
}') > /tmp/additions.json
103+
jq -s '.[0] + .[1] + .[2]' /tmp/secrets.json /tmp/vars.json /tmp/additions.json > .helm/ecamp3/env.yaml
104+
jq '.' .helm/ecamp3/env.yaml
105+
106+
- name: Setup kubectl authentication
107+
run: |
108+
mkdir -p ~/.kube
109+
echo '${{ secrets.KUBECONFIG }}' > ~/.kube/config
110+
chmod go-r ~/.kube/config
111+
112+
- uses: ./.github/actions/setup-helmfile
113+
114+
- name: Diff deployment
115+
run: |
116+
./.helm/ecamp3/deploy.sh diff || true
117+
118+
- name: Show values.yaml
119+
run: cat ./.helm/ecamp3/values.yaml
120+
121+
- name: Deploy
122+
if: ${{ inputs.action == 'deploy' }}
71123
run: |
72-
# Setup authentication
73-
mkdir ~/.kube && echo '${{ secrets.KUBECONFIG }}' > ~/.kube/config && chmod go-r ~/.kube/config
74-
# Switch to the helm chart directory
75-
cd .helm/ecamp3
76-
# Install dependency charts
77-
helm dependency update
78-
# Set the appVersion, workaround from https://github.com/helm/helm/issues/8194 so that we can
79-
# later find out which deployments need to be upgraded
80-
sed -i 's/^appVersion:.*$/appVersion: "${{ inputs.sha }}"/' Chart.yaml
81-
# Install or upgrade the release
82-
helm upgrade --install ecamp3-${{ inputs.name }} . \
83-
--set imageTag=${{ inputs.sha }} \
84-
--set frontend.image.repository='docker.io/${{ vars.DOCKER_HUB_USERNAME }}/ecamp3-frontend' \
85-
--set print.image.repository='docker.io/${{ vars.DOCKER_HUB_USERNAME }}/ecamp3-print' \
86-
--set api.image.repository='docker.io/${{ vars.DOCKER_HUB_USERNAME }}/ecamp3-api' \
87-
--set apiCache.image.repository='docker.io/${{ vars.DOCKER_HUB_USERNAME }}/ecamp3-varnish' \
88-
--set postgresql.dbBackupRestoreImage.repository='docker.io/${{ vars.DOCKER_HUB_USERNAME }}/ecamp3-db-backup-restore' \
89-
--set termsOfServiceLinkTemplate='https://ecamp3.ch/{lang}/tos' \
90-
--set newsLink='https://ecamp3.ch/blog' \
91-
--set helpLink='https://ecamp3.ch/faq' \
92-
--set domain=${{ inputs.name }}.${{ vars.DOMAIN }} \
93-
--set ingress.basicAuth.enabled=${{ vars.BASIC_AUTH_ENABLED || false }} \
94-
--set ingress.basicAuth.username=${{ secrets.BASIC_AUTH_USERNAME }} \
95-
--set ingress.basicAuth.password='${{ secrets.BASIC_AUTH_PASSWORD }}' \
96-
--set apiCache.enabled=${{ vars.API_CACHE_ENABLED || false }} \
97-
--set apiCache.sendXKeyHeadersDownstream=${{ vars.SEND_XKEY_HEADERS_DOWNSTREAM != null && format('''{0}''', vars.SEND_XKEY_HEADERS_DOWNSTREAM) || null }} \
98-
--set mail.dummyEnabled=true \
99-
--set postgresql.url='${{ secrets.POSTGRES_URL }}/ecamp3${{ inputs.name }}?sslmode=require' \
100-
--set postgresql.adminUrl='${{ secrets.POSTGRES_ADMIN_URL }}/ecamp3${{ inputs.name }}?sslmode=require' \
101-
--set postgresql.dropDBOnUninstall=${{ inputs.dropDBOnUninstall }} \
102-
--set postgresql.backup.schedule=${{ vars.BACKUP_SCHEDULE != null && format('''{0}''', vars.BACKUP_SCHEDULE) || null }} \
103-
--set postgresql.backup.s3.endpoint='${{ vars.BACKUP_S3_ENDPOINT }}' \
104-
--set postgresql.backup.s3.bucket='${{ vars.BACKUP_S3_BUCKET }}' \
105-
--set postgresql.backup.s3.accessKeyId='${{ secrets.BACKUP_S3_ACCESS_KEY_ID }}' \
106-
--set postgresql.backup.s3.accessKey='${{ secrets.BACKUP_S3_ACCESS_KEY }}' \
107-
--set postgresql.backup.encryptionKey=${{ secrets.BACKUP_ENCRYPTION_KEY != null && format('''{0}''', secrets.BACKUP_ENCRYPTION_KEY) || null }} \
108-
--set postgresql.restore.sourceFile=${{ inputs.restoreSourceFile != null && format('''{0}''', inputs.restoreSourceFile) || null }} \
109-
--set postgresql.restore.sourceAppName=${{ vars.RESTORE_SOURCE_APP != null && format('''{0}''', vars.RESTORE_SOURCE_APP) || null }} \
110-
--set postgresql.restore.s3.endpoint='${{ vars.RESTORE_S3_ENDPOINT }}' \
111-
--set postgresql.restore.s3.bucket='${{ vars.RESTORE_S3_BUCKET }}' \
112-
--set postgresql.restore.s3.accessKeyId='${{ secrets.RESTORE_S3_ACCESS_KEY_ID }}' \
113-
--set postgresql.restore.s3.accessKey='${{ secrets.RESTORE_S3_ACCESS_KEY }}' \
114-
--set postgresql.restore.encryptionKey=${{ secrets.RESTORE_ENCRYPTION_KEY != null && format('''{0}''', secrets.RESTORE_ENCRYPTION_KEY) || null }} \
115-
--set api.dataMigrationsDir='${{ vars.DATA_MIGRATIONS_DIR }}' \
116-
--set api.appSecret='${{ secrets.API_APP_SECRET }}' \
117-
--set api.sentryDsn='${{ secrets.API_SENTRY_DSN }}' \
118-
--set api.jwt.passphrase='${{ secrets.JWT_PASSPHRASE }}' \
119-
--set api.jwt.publicKey='${{ secrets.JWT_PUBLIC_KEY }}' \
120-
--set api.jwt.privateKey='${{ secrets.JWT_PRIVATE_KEY }}' \
121-
--set frontend.sentryDsn='${{ secrets.FRONTEND_SENTRY_DSN }}' \
122-
--set print.sentryDsn='${{ secrets.PRINT_SENTRY_DSN }}' \
123-
--set print.browserWsEndpoint='${{ secrets.BROWSER_WS_ENDPOINT }}' \
124-
--set print.ingress.readTimeoutSeconds='${{ vars.PRINT_INGRESS_READ_TIMEOUT_SECONDS }}' \
125-
--set print.renderHTMLTimeoutMs='${{ vars.PRINT_RENDER_HTML_TIMEOUT_MS }}' \
126-
--set print.renderPDFTimeoutMs='${{ vars.PRINT_RENDER_PDF_TIMEOUT_MS }}' \
127-
--set browserless.connectionTimeout=${{ vars.BROWSERLESS_CONNECTION_TIMEOUT_MS || '30000' }} \
128-
--set deploymentTime="$(date -u +%s)" \
129-
--set deployedVersion="$(git rev-parse --short '${{ inputs.sha }}')" \
130-
--set recaptcha.siteKey='${{ secrets.RECAPTCHA_SITE_KEY }}' \
131-
--set recaptcha.secret='${{ secrets.RECAPTCHA_SECRET }}' \
132-
--set frontend.loginInfoTextKey=${{ vars.LOGIN_INFO_TEXT_KEY }} \
133-
--set featureToggle.developer=true \
134-
--set featureToggle.checklist=${{ vars.FEATURE_CHECKLIST || 'false' }} \
135-
--timeout ${{ vars.HELM_TIMEOUT || '5m0s' }}
124+
./.helm/ecamp3/deploy.sh deploy
136125
137126
- name: Finish the GitHub deployment
138127
uses: bobheadxi/deployments@v1.5.0
@@ -142,7 +131,7 @@ jobs:
142131
token: ${{ secrets.REPO_ACCESS_TOKEN }}
143132
status: ${{ job.status }}
144133
deployment_id: ${{ steps.deployment.outputs.deployment_id }}
145-
env_url: https://${{ inputs.name }}.${{ vars.DOMAIN }}
134+
env_url: ${{ (inputs.env == 'staging' || inputs.env == 'prod') && format('https://{0}.{1}', vars.SUBDOMAIN, vars.DOMAIN) || format('https://{0}.{1}', inputs.name, vars.DOMAIN) }}
146135
env: ${{ steps.deployment.outputs.env }}
147136

148137
- name: Get current time

0 commit comments

Comments
 (0)