-
Notifications
You must be signed in to change notification settings - Fork 0
234 lines (208 loc) · 8.33 KB
/
ci.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
name: CI
on:
push:
branches:
- main
- prod
- feat-*
- test-*
paths:
- 'services/**'
- '.github/**'
workflow_dispatch:
jobs:
test:
name: Run Tests
timeout-minutes: 5
runs-on: ubuntu-latest
defaults:
run:
working-directory: services/server
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: |
.github
services
- name: Check Required variables and secrets
run: |
if [[ -z "${{ secrets.TEST_FIREBASE_API_KEY }}" ]]; then
echo "TEST_FIREBASE_API_KEY secret is missing";
exit 1;
fi
if [[ -z "${{ secrets.TEST_FIREBASE_SERVICE_ACCOUNT_KEY_BASE64 }}" ]]; then
echo "TEST_FIREBASE_SERVICE_ACCOUNT_KEY_BASE64 secret is missing";
exit 1;
fi
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.22.2'
- name: Install dependencies
run: go mod download
- name: Create firebase-service-account.json file
run: |
mkdir -p ./secrets
echo "${{ secrets.TEST_FIREBASE_SERVICE_ACCOUNT_KEY_BASE64 }}" | base64 -d > ./secrets/firebase-service-account.json
- name: Run tests
run: TEST_FIREBASE_API_KEY=${{ secrets.TEST_FIREBASE_API_KEY }} make test
ci:
name: Build and Push Docker Image, Deploy to Linode K8s
env:
API_VERSION: v1
timeout-minutes: 5
needs: test
defaults:
run:
working-directory: services/server
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: |
.github
services
- name: Check Required variables and secrets
run: |
if [[ -z "${{ secrets.DOCKERHUB_TOKEN }}" ]]; then
echo "DOCKERHUB_TOKEN secret is missing";
exit 1;
fi
if [[ -z "${{ secrets.FIREBASE_SERVICE_ACCOUNT_KEY_BASE64 }}" ]]; then
echo "FIREBASE_SERVICE_ACCOUNT_KEY_BASE64 secret is missing";
exit 1;
fi
if [[ -z "${{ secrets.LINODE_KUBECONFIG }}" ]]; then
echo "LINODE_KUBECONFIG secret is missing";
exit 1;
fi
if [[ -z "${{ secrets.POSTGRES_HOST }}" ]]; then
echo "POSTGRES_HOST secret is missing";
exit 1;
fi
if [[ -z "${{ secrets.POSTGRES_PASSWORD }}" ]]; then
echo "POSTGRES_PASSWORD secret is missing";
exit 1;
fi
if [[ -z "${{ vars.DOCKERHUB_REPO }}" ]]; then
echo "DOCKERHUB_REPO variable is missing";
exit 1;
fi
if [[ -z "${{ vars.DOCKERHUB_USERNAME }}" ]]; then
echo "DOCKERHUB_USERNAME variable is missing";
exit 1;
fi
if [[ -z "${{ vars.HELM_VERSION }}" ]]; then
echo "HELM_VERSION variable is missing";
exit 1;
fi
- name: Set Environment Variables
run: |
if [[ ${{ github.ref_name }} == 'prod' ]]; then
ENVIRONMENT='prod'
elif [[ ${{ github.ref_name }} == 'main' ]]; then
ENVIRONMENT='staging'
else
ENVIRONMENT='dev'
fi
IMAGE_REPO=${{ vars.DOCKERHUB_USERNAME }}/${{ vars.DOCKERHUB_REPO }}
SERVER_IMAGE_TAG="$ENVIRONMENT-server-${{ github.sha }}"
MIGRATION_IMAGE_TAG="$ENVIRONMENT-migration-${{ github.sha }}"
echo "ENVIRONMENT=$ENVIRONMENT" >> $GITHUB_ENV
echo "IMAGE_REPO=$IMAGE_REPO" >> $GITHUB_ENV
echo "SERVER_IMAGE_TAG=$SERVER_IMAGE_TAG" >> $GITHUB_ENV
echo "MIGRATION_IMAGE_TAG=$MIGRATION_IMAGE_TAG" >> $GITHUB_ENV
echo "SERVER_IMAGE=$IMAGE_REPO:$SERVER_IMAGE_TAG" >> $GITHUB_ENV
echo "MIGRATION_IMAGE=$IMAGE_REPO:$MIGRATION_IMAGE_TAG" >> $GITHUB_ENV
echo "HELM_RELEASE=server-$ENVIRONMENT" >> $GITHUB_ENV
- uses: azure/k8s-set-context@v4
with:
kubeconfig: ${{ secrets.LINODE_KUBECONFIG }} # must be the kubeconfig itself, not the path to it
- uses: azure/[email protected]
with:
version: "${{ vars.HELM_VERSION }}"
- name: Build Server Docker Image # different FIREBASE_SERVICE_ACCOUNT_KEY_BASE64 secret for prod and staging
run: |
docker build \
-f Dockerfile.prod \
-t ${{ env.SERVER_IMAGE }} \
--build-arg FIREBASE_SERVICE_ACCOUNT_KEY_BASE64=$( if [[ ${{ env.ENVIRONMENT }} == 'prod' ]]; then echo "${{ secrets.FIREBASE_SERVICE_ACCOUNT_KEY_BASE64 }}"; else echo "${{ secrets.FIREBASE_SERVICE_ACCOUNT_KEY_BASE64 }}"; fi ) \
.
- name: Build Migration Docker Image # different FIREBASE_SERVICE_ACCOUNT_KEY_BASE64 secret for prod and staging
run: |
docker build \
-f postgres/Dockerfile.migration \
-t ${{ env.MIGRATION_IMAGE }} \
.
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Push Docker Images
run: |
docker push ${{ env.SERVER_IMAGE }}
docker push ${{ env.MIGRATION_IMAGE }}
- name: Adapt app version in Helm Chart
run: |
sed -i'' \
-e "s/APP_VERSION/${{ github.sha }}/g" \
k8s/server/Chart.yaml
- name: Apply Helm Chart in Production
if: ${{ env.ENVIRONMENT == 'prod' }}
run: |
helm upgrade ${{ env.HELM_RELEASE }} k8s/server \
--install \
--set image.repository=${{ env.IMAGE_REPO }} \
--set image.tags.server=${{ env.SERVER_IMAGE_TAG }} \
--set image.tags.migration=${{ env.MIGRATION_IMAGE_TAG }} \
--set postgresql.auth.password=${{ secrets.POSTGRES_PASSWORD }} \
--set postgresql.enabled=false \
--set dbPasswordSecret.enabled=true \
--set dbHost=${{ secrets.POSTGRES_HOST }} \
--set replicaCount=1 \
--set apiVersion=${{ env.API_VERSION }} \
--set secrets.dockerHubSecret.valueBase64="$(cat ~/.docker/config.json | base64 -w 0)" \
--namespace=prod
# --wait flag -> wait for all resources to be ready before running the post hook
- name: Apply Helm Chart in non-production environments
if: ${{ env.ENVIRONMENT != 'prod' }}
run: |
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm dependency build k8s/server
helm upgrade ${{ env.HELM_RELEASE }} k8s/server \
--install \
--set image.repository=${{ env.IMAGE_REPO }} \
--set image.tags.server=${{ env.SERVER_IMAGE_TAG }} \
--set image.tags.migration=${{ env.MIGRATION_IMAGE_TAG }} \
--set replicaCount=1 \
--set apiVersion=${{ env.API_VERSION }} \
--set secrets.dockerHubSecret.valueBase64="$(cat ~/.docker/config.json | base64 -w 0)" \
--set postgresql.enabled=true \
--wait \
--namespace=${{ env.ENVIRONMENT }}
- name: Verify Deployment
if: ${{ env.ENVIRONMENT == 'prod' }}
run: |
kubectl rollout status deployment/server --namespace=${{ env.ENVIRONMENT }}
- name: Perform health check
id: health_check
if: ${{ env.ENVIRONMENT == 'prod' }}
run: |
APP_HOST=niko-heidner.com
curl http://$APP_HOST/${{ env.API_VERSION }}/health --fail
- name: Rollback if failed
if: ${{ failure() && steps.health_check.outcome == 'failure' }}
run: |
helm rollback ${{ env.HELM_RELEASE }} --namespace=${{ env.ENVIRONMENT }}
- name: Delete old Images on Docker Hub
run: |
/bin/bash bash_scripts/delete_old_images/delete_old_images.sh ${{ env.SERVER_IMAGE_REGEX }} 50 5;
/bin/bash bash_scripts/delete_old_images/delete_old_images.sh ${{ env.MIGRATION_IMAGE_REGEX }} 50 5;
env:
SERVER_IMAGE_REGEX: "${{ env.ENVIRONMENT }}-server"
MIGRATION_IMAGE_REGEX: "${{ env.ENVIRONMENT }}-migration"
DOCKERHUB_USERNAME: ${{ vars.DOCKERHUB_USERNAME }}
DOCKERHUB_REPO: ${{ vars.DOCKERHUB_REPO }}
DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }}