Skip to content
Open

Dev #41

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
135 changes: 135 additions & 0 deletions .github/workflows/deploy-gke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
name: CD - Deploy to GKE

on:
workflow_dispatch:
inputs:
source_tag:
description: 'The Git SHA or Dev tag to promote (e.g. sha-a1b2c or dev)'
required: true
default: 'dev'
target_tag:
description: 'The new version tag (e.g. v1.0.0)'
required: true
default: 'v1.0.0'
environment:
description: 'Target Environment'
required: true
type: choice
options:
- dev
- prod

permissions:
id-token: write
contents: read

env:
PROJECT_ID: "gcp-capstone-481414"
REGION: "us-central1"
REPO_NAME: "bookshelf-docker-repo"
IMAGE_NAME: "fastapi-app"
GKE_CLUSTER: "bookshelf-dev-cluster"

jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ github.event.inputs.environment }}

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

- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
service_account: ${{ secrets.WIF_SERVICE_ACCOUNT }}
project_id: ${{ env.PROJECT_ID }}

- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v2
with:
project_id: ${{ env.PROJECT_ID }}

- name: Install kubectl
run: |
gcloud components install kubectl

- name: Set Cluster Name for prod
id: set_cluster
shell: bash
run: |
# Read the environment input (dev or prod)
ENV_INPUT="${{ github.event.inputs.environment }}"

# Construct the name: bookshelf-dev-cluster or bookshelf-prod-cluster
CLUSTER_NAME="bookshelf-${ENV_INPUT}-cluster"

# Export it to the GITHUB_ENV so subsequent steps can see it
echo "GKE_CLUSTER=${CLUSTER_NAME}" >> $GITHUB_ENV

echo "Target Cluster set to: ${CLUSTER_NAME}"

- name: Get GKE Credentials
run: |
gcloud container clusters get-credentials ${{ env.GKE_CLUSTER }} --region ${{ env.REGION }}

- name: Create Namespace
run: |
kubectl create namespace my-cool-app --dry-run=client -o yaml | kubectl apply -f -

- name: Ensure Secrets Exist
env:
SECRET_USER: ${{ secrets.DB_USERNAME }}
SECRET_PASS: ${{ secrets.DB_PASSWORD }}
SECRET_NAME: ${{ secrets.DB_NAME }}
run: |
kubectl create secret generic fastapi-secret \
--from-literal=POSTGRES_USER=$SECRET_USER \
--from-literal=POSTGRES_PASSWORD=$SECRET_PASS \
--from-literal=POSTGRES_DB=$SECRET_NAME \
--namespace=my-cool-app --dry-run=client -o yaml | kubectl apply -f -

- name: Retag Image in Artifact Registry
env:
SOURCE_TAG: ${{ github.event.inputs.source_tag }}
TARGET_TAG: ${{ github.event.inputs.target_tag }}
IMAGE_URL: ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPO_NAME }}/${{ env.IMAGE_NAME }}
run: |
echo "Promoting ${IMAGE_URL}:${SOURCE_TAG} to ${IMAGE_URL}:${TARGET_TAG}..."
gcloud artifacts docker tags add \
${IMAGE_URL}:${SOURCE_TAG} \
${IMAGE_URL}:${TARGET_TAG}

- name: Create DB Init ConfigMap
run: |
kubectl create configmap db-init-script \
--from-file=server/db/init.sh \
--namespace=my-cool-app --dry-run=client -o yaml | kubectl apply -f -

- name: Deploy Application
env:
TARGET_TAG: ${{ github.event.inputs.target_tag }}
run: |
# Use sed to replace the placeholder in the YAML with the actual version
sed -i "s|__IMAGE_TAG__|${TARGET_TAG}|g" kubernetes/fastapi-app.yaml

# Apply both App and DB
kubectl apply -f kubernetes/postgres-db.yaml
kubectl apply -f kubernetes/fastapi-app.yaml

- name: Inject Database Connection String
env:
DB_USER: ${{ secrets.DB_USERNAME }}
DB_PASS: ${{ secrets.DB_PASSWORD }}
DB_NAME: ${{ secrets.DB_NAME }}
DB_HOST: "db"
DB_PORT: "5432"
run: |
DB_URL="postgresql://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}"
echo "Injecting DOCKER_DATABASE_URL into deployment..."
kubectl set env deployment/fastapi-deployment DOCKER_DATABASE_URL="${DB_URL}" -n my-cool-app

- name: Verify Deployment
run: |
kubectl rollout status deployment/fastapi-deployment -n my-cool-app
53 changes: 53 additions & 0 deletions .github/workflows/docker-build-gcp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: CI - Build & Push Docker Image

on:
push:
branches: [ "main" ]
paths:
- 'server/**'
- 'Dockerfile'
workflow_dispatch:

permissions:
id-token: write
contents: read

env:
PROJECT_ID: "gcp-capstone-481414"
REGION: "us-central1"
REPO_NAME: "bookshelf-docker-repo"
IMAGE_NAME: "fastapi-app"

jobs:
build-and-push:
runs-on: ubuntu-latest

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

- name: Authenticate to Google Cloud
id: auth
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
service_account: ${{ secrets.WIF_SERVICE_ACCOUNT }}

- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v2
with:
project_id: ${{ env.PROJECT_ID }}

- name: Configure Docker Authentication
run: gcloud auth configure-docker ${{ env.REGION }}-docker.pkg.dev

- name: Build and Push Docker Image
env:
IMAGE_URL: ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPO_NAME }}/${{ env.IMAGE_NAME }}
run: |
# Build the image
docker build -t $IMAGE_URL:dev -t $IMAGE_URL:${{ github.sha }} .

# Push both tags
docker push $IMAGE_URL:dev
docker push $IMAGE_URL:${{ github.sha }}
69 changes: 69 additions & 0 deletions .github/workflows/infra-destroy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Infrastructure Destroy

on:
workflow_dispatch:
inputs:
environment:
description: 'Select Environment to Destroy'
required: true
type: choice
options:
- dev
- prod

permissions:
id-token: write
contents: read

env:
TF_VERSION: "1.14.2"
GCP_REGION: "us-central1"

jobs:
destroy:
runs-on: ubuntu-latest
environment: ${{ github.event.inputs.environment }}

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

- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
service_account: ${{ secrets.WIF_SERVICE_ACCOUNT }}

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}

- name: Set Target Directory
id: set_dir
run: |
if [ "${{ github.event.inputs.environment }}" == "dev" ]; then
echo "target_dir=infra/envs/dev" >> $GITHUB_OUTPUT
echo "var_file=values.tfvars" >> $GITHUB_OUTPUT
else
echo "target_dir=infra/envs/prod" >> $GITHUB_OUTPUT
echo "var_file=values.tfvars" >> $GITHUB_OUTPUT
fi

# - name: Manual Approval
# if: github.event.inputs.environment == 'prod'
# uses: trstringer/manual-approval@v1
# with:
# secret: ${{ secrets.GITHUB_TOKEN }}
# approvers: nizamra
# minimum-approvals: 1

- name: Terraform Init
working-directory: ${{ steps.set_dir.outputs.target_dir }}
run: terraform init

- name: Terraform Destroy
working-directory: ${{ steps.set_dir.outputs.target_dir }}
run: |
terraform plan -destroy -var-file="${{ steps.set_dir.outputs.var_file }}"
terraform destroy -auto-approve -var-file="${{ steps.set_dir.outputs.var_file }}"
70 changes: 70 additions & 0 deletions .github/workflows/infra-pipeline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Infrastructure (GKE & Registry)

on:
push:
branches: [ "main" ]
paths:
- 'infra/**'
workflow_dispatch:

permissions:
id-token: write
contents: read

env:
TF_VERSION: "1.14.2"
GCP_REGION: "us-central1"

jobs:
deploy-infra-dev:
runs-on: ubuntu-latest

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

- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
service_account: ${{ secrets.WIF_SERVICE_ACCOUNT }}

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}

- name: Terraform Init
working-directory: infra/envs/dev
run: terraform init

- name: Terraform Apply
working-directory: infra/envs/dev
run: terraform apply -auto-approve -var-file="values.tfvars"


deploy-infra-prod:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
needs: deploy-infra-dev

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

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}

- name: Initialize Terraform
run: terraform init

- name: Plan Terraform for Prod
run: terraform plan -var-file="values.tfvars"

- name: Manual Approval
uses: hmarr/auto-approve-action@v4

- name: Apply Terraform for Prod
run: terraform apply -auto-approve -var-file="values.tfvars"
40 changes: 40 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,43 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/



# Local .terraform directories
.terraform/
.vscode/


# .tfstate files
**/.terraform/
**/*.tfstate
**/*.tfstate.*
**/.terraform.lock.hcl

# Crash log files
crash.log
crash.*.log

# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json

# Ignore transient lock info files created by terraform apply
.terraform.tfstate.lock.info

# Include override files you do wish to add to version control using negated pattern
# !example_override.tf

# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*

# Ignore CLI configuration files
.terraformrc
terraform.rc

*.private
meta.txt
Loading