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
75 changes: 75 additions & 0 deletions .github/workflows/build-and-push.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Docker Build and Push

on:
push:
branches: [ "main", "master" ]
workflow_dispatch:

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

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

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx with Container Driver
uses: docker/setup-buildx-action@v3
with:
driver: docker-container

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Define image metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,format=long,prefix=
type=raw,value=latest,enable={{is_default_branch}}
type=ref,event=tag

- name: Lint Dockerfile
uses: hadolint/hadolint-action@v3.1.0

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

- name: Extract first tag
id: first_tag
run: |
FIRST_TAG=$(echo "${{ steps.meta.outputs.tags }}" | head -n 1)
echo "tag=$FIRST_TAG" >> $GITHUB_OUTPUT

- name: Run Trivy vulnerability scanner (fail only on CRITICAL)
uses: aquasecurity/trivy-action@master
continue-on-error: true
with:
image-ref: ${{ steps.meta.outputs.tags }}
format: table
exit-code: 1
vuln-type: 'os,library'
severity: 'CRITICAL'
13 changes: 13 additions & 0 deletions angular-17-client/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
node_modules
dist
.angular
.vscode
.git
.gitignore
*.md
npm-debug.log
yarn-error.log
coverage
.editorconfig
karma.conf.js
.browserslistrc
25 changes: 25 additions & 0 deletions angular-17-client/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Stage 1: Build
FROM node:18-alpine AS build

WORKDIR /app

COPY package*.json ./
# Install dependencies
RUN npm ci
# Copy application source code
COPY . .

# Build the application
RUN npm run build


# Stage 2: Runtime
FROM nginx:alpine
# Copy nginx.conf (or minimalistic nginx2.conf)
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Copy from build stage
COPY --from=build /app/dist/angular-17-crud/browser /usr/share/nginx/html

EXPOSE 8081

CMD ["nginx", "-g", "daemon off;"]
34 changes: 34 additions & 0 deletions angular-17-client/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;

gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;

location /api/ {
proxy_pass http://spring-boot-server:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}

location / {
try_files $uri $uri/ /index.html;
}

location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
57 changes: 57 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
services:
mysql:
image: mysql:8.0
container_name: mysql-db
environment:
MYSQL_ROOT_PASSWORD: 12345678
MYSQL_DATABASE: testdb
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
networks:
- app-network
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p12345678"]
interval: 10s
timeout: 5s
retries: 5

spring-boot-server:
build:
context: ./spring-boot-server
dockerfile: Dockerfile
container_name: spring-boot-app
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/testdb?useSSL=false&allowPublicKeyRetrieval=true
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: 12345678
SPRING_JPA_HIBERNATE_DDL_AUTO: update
ports:
- "8080:8080"
depends_on:
mysql:
condition: service_healthy
networks:
- app-network
restart: unless-stopped

angular-client:
build:
context: ./angular-17-client
dockerfile: Dockerfile
container_name: angular-app
ports:
- "4200:80"
depends_on:
- spring-boot-server
networks:
- app-network
restart: unless-stopped

networks:
app-network:
driver: bridge

volumes:
mysql_data:
10 changes: 10 additions & 0 deletions spring-boot-server/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
target
.mvn
mvnw
mvnw.cmd
*.md
.git
.gitignore
.vscode
.idea
*.iml
24 changes: 24 additions & 0 deletions spring-boot-server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Stage 1: Build
FROM maven:3.9-eclipse-temurin-17 AS build

WORKDIR /app

COPY pom.xml .
RUN mvn dependency:go-offline -B

COPY src ./src

RUN mvn clean package -DskipTests


# Stage 2: Run the application
FROM eclipse-temurin:17-jre-alpine

WORKDIR /app

# Copy the JAR from build stage
COPY --from=build /app/target/*.jar app.jar

EXPOSE 8080
# Run the application
ENTRYPOINT ["java", "-jar", "app.jar"]
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import com.bezkoder.spring.datajpa.model.Tutorial;
import com.bezkoder.spring.datajpa.repository.TutorialRepository;

@CrossOrigin(origins = "http://localhost:8081")
@CrossOrigin(origins = "*")
@RestController
@RequestMapping("/api")
public class TutorialController {
Expand Down