Skip to content

Commit a67c0f1

Browse files
authored
feat: add kubernetes CD
1 parent 18f21d3 commit a67c0f1

2 files changed

Lines changed: 530 additions & 0 deletions

File tree

.github/workflows/deploy.yml

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
name: Deploy to K3s
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
backend_image:
7+
description: "Backend image tag (full image reference)"
8+
required: false
9+
frontend_image:
10+
description: "Frontend image tag (full image reference)"
11+
required: false
12+
apply:
13+
description: "Apply changes after plan"
14+
required: false
15+
default: "true"
16+
push:
17+
branches: [ main ]
18+
workflow_run:
19+
workflows: [ "Backend Build & Push", "Frontend Build & Push" ]
20+
types: [ completed ]
21+
22+
jobs:
23+
terraform-plan:
24+
if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}
25+
runs-on: ubuntu-latest
26+
permissions:
27+
contents: read
28+
steps:
29+
- name: Checkout code
30+
uses: actions/checkout@v6
31+
with:
32+
fetch-depth: 0
33+
34+
- name: Setup Terraform
35+
uses: hashicorp/setup-terraform@v4
36+
37+
- name: Setup kubectl
38+
uses: azure/setup-kubectl@v5
39+
40+
- name: Setup Kubeconfig
41+
run: |
42+
mkdir -p ~/.kube
43+
echo "${{ secrets.KUBECONFIG_DATA }}" | base64 -d > ~/.kube/config
44+
chmod 600 ~/.kube/config
45+
46+
- name: Validate cluster access
47+
run: |
48+
kubectl cluster-info
49+
kubectl get namespace gif-mood
50+
51+
- name: Determine deployment values
52+
id: deploy-vars
53+
run: |
54+
backend_image='${{ github.event.inputs.backend_image }}'
55+
frontend_image='${{ github.event.inputs.frontend_image }}'
56+
57+
latest_backend_tag="$(git tag --list 'api-v*' --sort=-v:refname | tail -n1)"
58+
latest_frontend_tag="$(git tag --list 'app-v*' --sort=-v:refname | tail -n1)"
59+
60+
if [ -z "$latest_backend_tag" ]; then
61+
echo "No backend tag found matching api-v*" >&2
62+
exit 1
63+
fi
64+
65+
if [ -z "$latest_frontend_tag" ]; then
66+
echo "No frontend tag found matching app-v*" >&2
67+
exit 1
68+
fi
69+
70+
if [ -z "$backend_image" ]; then
71+
backend_image="ghcr.io/${{ github.repository }}/backend:$latest_backend_tag"
72+
fi
73+
if [ -z "$frontend_image" ]; then
74+
frontend_image="ghcr.io/${{ github.repository }}/frontend:$latest_frontend_tag"
75+
fi
76+
77+
echo "Resolved backend_image=$backend_image"
78+
echo "Resolved migrations_image=$migrations_image"
79+
echo "Resolved frontend_image=$frontend_image"
80+
81+
echo "backend_image=$backend_image" >> "$GITHUB_OUTPUT"
82+
echo "migrations_image=$migrations_image" >> "$GITHUB_OUTPUT"
83+
echo "frontend_image=$frontend_image" >> "$GITHUB_OUTPUT"
84+
85+
- name: Terraform Fmt -check -diff
86+
working-directory: terraform
87+
run: terraform fmt -check -diff
88+
89+
- name: Terraform Init
90+
working-directory: terraform
91+
env:
92+
AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
93+
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
94+
run: terraform init
95+
96+
- name: Terraform Validate
97+
working-directory: terraform
98+
run: terraform validate
99+
100+
- name: Terraform Plan
101+
working-directory: terraform
102+
env:
103+
AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
104+
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
105+
run: |
106+
terraform plan -out=tfplan \
107+
-var="db_user=${{ secrets.DB_USER }}" \
108+
-var="db_password=${{ secrets.DB_PASSWORD }}" \
109+
-var="db_name=${{ secrets.DB_NAME }}" \
110+
-var="security_key=${{ secrets.JWT_SECURITY_KEY }}" \
111+
-var="mailgun_api_key=${{ secrets.MAILGUN_API_KEY }}" \
112+
-var="backend_image=${{ steps.deploy-vars.outputs.backend_image }}" \
113+
-var="frontend_image=${{ steps.deploy-vars.outputs.frontend_image }}"
114+
115+
- name: Upload plan artifact
116+
uses: actions/upload-artifact@v4
117+
with:
118+
name: tfplan
119+
path: terraform/tfplan
120+
121+
terraform-apply:
122+
runs-on: ubuntu-latest
123+
needs: terraform-plan
124+
if: ${{ github.event_name == 'push' || github.event_name == 'workflow_run' || github.event.inputs.apply == 'true' }}
125+
environment:
126+
name: production
127+
permissions:
128+
contents: read
129+
steps:
130+
- name: Checkout code
131+
uses: actions/checkout@v6
132+
133+
- name: Setup Terraform
134+
uses: hashicorp/setup-terraform@v3
135+
136+
- name: Download plan artifact
137+
uses: actions/download-artifact@v4
138+
with:
139+
name: tfplan
140+
path: terraform
141+
142+
- name: Setup Kubeconfig
143+
run: |
144+
mkdir -p ~/.kube
145+
echo "${{ secrets.KUBECONFIG_DATA }}" | base64 -d > ~/.kube/config
146+
chmod 600 ~/.kube/config
147+
148+
- name: Terraform Init
149+
working-directory: terraform
150+
env:
151+
AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
152+
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
153+
run: terraform init
154+
155+
- name: Terraform Apply
156+
working-directory: terraform
157+
env:
158+
AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
159+
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
160+
run: timeout 1m terraform apply tfplan

0 commit comments

Comments
 (0)