Skip to content
Open
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
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
npm-debug.log
.git
.env
125 changes: 125 additions & 0 deletions .github/workflows/ci-cd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
name: Demo API CI/CD

on:
workflow_dispatch:
pull_request:
branches: [ main, develop ]
push:
branches: [ main ]

env:
REGISTRY: justranacr.azurecr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build:
name: Build API
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
image-tag: ${{ steps.meta.outputs.tags }}
image-digest: ${{ steps.build.outputs.digest }}

steps:
- uses: actions/checkout@v4

- name: Login to ACR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: justranacr
password: ${{ secrets.ACR_PASSWORD }}

- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- uses: docker/setup-buildx-action@v3

- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=${{ github.run_number }}
type=raw,value=latest,enable={{is_default_branch}}

- name: Build & push image
id: build
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

deploy:
name: Deploy API
runs-on: ubuntu-latest
needs: build
# Deploy on push to main branch OR manual trigger
if: (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event_name == 'workflow_dispatch'

steps:
- name: Set up kubectl
uses: azure/setup-kubectl@v3
with:
version: 'v1.28.0'

- name: Set up Helm
uses: azure/setup-helm@v3
with:
version: '3.12.0'

- name: Configure kubectl
run: |
mkdir -p $HOME/.kube
echo "${{ secrets.KUBECONFIG }}" > $HOME/.kube/config
chmod 600 $HOME/.kube/config

- name: Verify cluster connection
run: |
kubectl cluster-info
kubectl get nodes

- name: Checkout Helm chart repository
uses: actions/checkout@v4
with:
repository: gbh-recruitment/ismael-ortiz-montero-ismaelortiz87-2025-5-29-senior-devops-challenge
token: ${{ secrets.PAT_TOKEN }}
path: helm-repo

- name: Deploy API with Helm
run: |
IMAGE_REPO=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
IMAGE_VERSION=${{ github.run_number }}
FULL_IMAGE=$IMAGE_REPO:$IMAGE_VERSION

echo "Deploying WebApp with image: $FULL_IMAGE"
echo "Image Repository: $IMAGE_REPO"
echo "Image Tag: $IMAGE_VERSION"

echo "Deploying API with image: $FULL_IMAGE"

# Deploy using Helm
helm upgrade --install demo-api ./helm-repo/part_2/helm/generic-web-chart \
--namespace gbh \
--values ./helm-repo/part_2/helm/generic-web-chart/values-api.yaml \
--set fullnameOverride=api \
--set image.repository="$IMAGE_REPO" \
--set image.tag="$IMAGE_VERSION" \
--set image.pullPolicy=Always \
--set env.REACT_APP_API_URL="$REACT_APP_API_URL" \
--timeout=10m \
--wait
12 changes: 12 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM node:18

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .

EXPOSE 3001

CMD ["node", "app.js"]
11 changes: 6 additions & 5 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import cors from 'cors';
import dotenv from "dotenv"
import dotenv from "dotenv";
import express from 'express';
import parser from 'body-parser';
import apiRouter from './src/routes/api.js';
Expand All @@ -19,10 +19,11 @@ app.use(parser.json());
app.use('/', apiRouter);

/* Initialize the API server */
const port = process.env.API_PORT || 3001;
const port = process.env.port || process.env.API_port || 3001;
const host = process.env.host || '0.0.0.0';

app.listen( port, () => {
console.log(`Server running on: ${port}.`)
app.listen(port, host, () => {
console.log(`Server running on: ${port}.`);
});

export default app;
export default app;