This commit is contained in:
123
.gitea/workflows/deploy.yml
Normal file
123
.gitea/workflows/deploy.yml
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
name: Build, Push and Deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
java-version: '21'
|
||||||
|
distribution: 'temurin'
|
||||||
|
cache: 'maven'
|
||||||
|
|
||||||
|
- name: Build with Maven
|
||||||
|
run: mvn clean package -DskipTests
|
||||||
|
|
||||||
|
- name: Login to Container Registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ${{ vars.REGISTRY_URL }}
|
||||||
|
username: ${{ secrets.CI_GITEA_USER }}
|
||||||
|
password: ${{ secrets.CI_GITEA_TOKEN }}
|
||||||
|
|
||||||
|
- name: Extract metadata for Docker
|
||||||
|
id: meta
|
||||||
|
run: |
|
||||||
|
echo "image_tag=${{ vars.REGISTRY_URL }}/${{ vars.NAMESPACE }}/${{ vars.REPO_NAME }}:${{ github.sha }}" >> $GITHUB_OUTPUT
|
||||||
|
echo "image_latest=${{ vars.REGISTRY_URL }}/${{ vars.NAMESPACE }}/${{ vars.REPO_NAME }}:latest" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Build and Push Docker Image
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./docker/Dockerfile
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
${{ steps.meta.outputs.image_tag }}
|
||||||
|
${{ steps.meta.outputs.image_latest }}
|
||||||
|
|
||||||
|
- name: Deploy to Remote Server
|
||||||
|
uses: appleboy/ssh-action@v1.0.3
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.SSH_HOST }}
|
||||||
|
username: ${{ secrets.SSH_USERNAME }}
|
||||||
|
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||||
|
port: ${{ secrets.SSH_PORT }}
|
||||||
|
script: |
|
||||||
|
# Navigate to deployment directory
|
||||||
|
cd ${{ secrets.DEPLOY_PATH }}
|
||||||
|
|
||||||
|
# Create .env file with all secrets
|
||||||
|
cat > .env << 'EOF'
|
||||||
|
# Deployment
|
||||||
|
REGISTRY_URL=${{ vars.REGISTRY_URL }}
|
||||||
|
NAMESPACE=${{ vars.NAMESPACE }}
|
||||||
|
REPO_NAME=${{ vars.REPO_NAME }}
|
||||||
|
IMAGE_TAG=${{ github.sha }}
|
||||||
|
CI_GITEA_USER=${{ secrets.CI_GITEA_USER }}
|
||||||
|
CI_GITEA_TOKEN=${{ secrets.CI_GITEA_TOKEN }}
|
||||||
|
|
||||||
|
# Application
|
||||||
|
APP_PORT=${{ secrets.APP_PORT }}
|
||||||
|
SPRING_PROFILES_ACTIVE=${{ secrets.SPRING_PROFILES_ACTIVE }}
|
||||||
|
APPLICATION_NAME=${{ secrets.APPLICATION_NAME }}
|
||||||
|
CORS_ALLOWED_ORIGINS=${{ secrets.CORS_ALLOWED_ORIGINS }}
|
||||||
|
|
||||||
|
# PostgreSQL Configuration
|
||||||
|
POSTGRES_HOST=${{ secrets.POSTGRES_HOST }}
|
||||||
|
POSTGRES_PORT=${{ secrets.POSTGRES_PORT }}
|
||||||
|
POSTGRES_DB=${{ secrets.POSTGRES_DB }}
|
||||||
|
POSTGRES_USER=${{ secrets.POSTGRES_USER }}
|
||||||
|
POSTGRES_PASSWORD=${{ secrets.POSTGRES_PASSWORD }}
|
||||||
|
|
||||||
|
# Keycloak Configuration
|
||||||
|
KEYCLOAK_URL=${{ secrets.KEYCLOAK_URL }}
|
||||||
|
KEYCLOAK_REALM=${{ secrets.KEYCLOAK_REALM }}
|
||||||
|
KEYCLOAK_ISSUER_URI=${{ secrets.KEYCLOAK_ISSUER_URI }}
|
||||||
|
|
||||||
|
# MinIO (S3) Configuration
|
||||||
|
MINIO_ENDPOINT=${{ secrets.MINIO_ENDPOINT }}
|
||||||
|
MINIO_ACCESS_KEY=${{ secrets.MINIO_ACCESS_KEY }}
|
||||||
|
MINIO_SECRET_KEY=${{ secrets.MINIO_SECRET_KEY }}
|
||||||
|
|
||||||
|
# AWS S3 Configuration (if needed)
|
||||||
|
AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
|
AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
AWS_S3_BUCKET_NAME=${{ secrets.AWS_S3_BUCKET_NAME }}
|
||||||
|
AWS_S3_REGION=${{ secrets.AWS_S3_REGION }}
|
||||||
|
AWS_S3_ENDPOINT=${{ secrets.AWS_S3_ENDPOINT }}
|
||||||
|
|
||||||
|
# Hibernate Configuration
|
||||||
|
HIBERNATE_DDL_AUTO=${{ secrets.HIBERNATE_DDL_AUTO }}
|
||||||
|
|
||||||
|
# Java Options
|
||||||
|
JAVA_OPTS=${{ secrets.JAVA_OPTS }}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Set proper permissions
|
||||||
|
chmod 600 .env
|
||||||
|
|
||||||
|
# Login to Container Registry
|
||||||
|
echo "${{ secrets.CI_GITEA_TOKEN }}" | docker login ${{ vars.REGISTRY_URL }} -u ${{ secrets.CI_GITEA_USER }} --password-stdin
|
||||||
|
|
||||||
|
# Pull latest image
|
||||||
|
docker compose pull
|
||||||
|
|
||||||
|
# Restart services with new image
|
||||||
|
docker compose up -d --remove-orphans
|
||||||
|
|
||||||
|
# Clean up old images
|
||||||
|
docker image prune -af --filter "until=168h"
|
||||||
|
|
||||||
|
# Show running containers
|
||||||
|
docker compose ps
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -31,3 +31,4 @@ build/
|
|||||||
|
|
||||||
### VS Code ###
|
### VS Code ###
|
||||||
.vscode/
|
.vscode/
|
||||||
|
/docker/.env
|
||||||
|
|||||||
30
docker/.env.dist
Normal file
30
docker/.env.dist
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Deployment
|
||||||
|
REGISTRY_URL=gitea.example.com
|
||||||
|
NAMESPACE=my-organisation
|
||||||
|
REPO_NAME=my-repository
|
||||||
|
IMAGE_TAG=latest
|
||||||
|
CI_GITEA_USER=<gitea-user>
|
||||||
|
CI_GITEA_TOKEN=<gitea-token>
|
||||||
|
|
||||||
|
# Application
|
||||||
|
APP_PORT=8082
|
||||||
|
SPRING_PROFILES_ACTIVE=dev
|
||||||
|
APPLICATION_NAME=skamp-api
|
||||||
|
CORS_ALLOWED_ORIGINS=http://localhost:4200
|
||||||
|
|
||||||
|
# PostgreSQL Configuration
|
||||||
|
POSTGRES_HOST=localhost
|
||||||
|
POSTGRES_PORT=5432
|
||||||
|
POSTGRES_DB=skamp
|
||||||
|
POSTGRES_USER=dev
|
||||||
|
POSTGRES_PASSWORD=dev
|
||||||
|
|
||||||
|
# Keycloak Configuration
|
||||||
|
KEYCLOAK_URL=http://localhost:8280
|
||||||
|
KEYCLOAK_REALM=skamp
|
||||||
|
KEYCLOAK_ISSUER_URI=http://localhost:8280/realms/skamp
|
||||||
|
|
||||||
|
# MinIO (S3) Configuration
|
||||||
|
MINIO_ENDPOINT=http://localhost:9000
|
||||||
|
MINIO_ACCESS_KEY=dev
|
||||||
|
MINIO_SECRET_KEY=dev123456
|
||||||
39
docker/Dockerfile
Normal file
39
docker/Dockerfile
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# ===== Build Stage =====
|
||||||
|
FROM maven:3.9.6-eclipse-temurin-21 AS builder
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
# Copy pom.xml first for better layer caching
|
||||||
|
COPY pom.xml .
|
||||||
|
RUN mvn dependency:go-offline -B
|
||||||
|
|
||||||
|
# Copy source code
|
||||||
|
COPY src ./src
|
||||||
|
|
||||||
|
# Build the application
|
||||||
|
RUN mvn clean package -DskipTests -B
|
||||||
|
|
||||||
|
# ===== Runtime Stage =====
|
||||||
|
FROM eclipse-temurin:21-jre-jammy
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Create non-root user
|
||||||
|
RUN groupadd --system spring && \
|
||||||
|
useradd --system --gid spring --create-home spring
|
||||||
|
|
||||||
|
# Copy the JAR from build stage
|
||||||
|
COPY --from=builder --chown=spring:spring /build/target/*.jar app.jar
|
||||||
|
|
||||||
|
# Switch to non-root user
|
||||||
|
USER spring
|
||||||
|
|
||||||
|
# Expose Spring Boot default port
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \
|
||||||
|
CMD curl -f http://localhost:8080/actuator/health || exit 1
|
||||||
|
|
||||||
|
# Run the application
|
||||||
|
ENTRYPOINT ["java", "-XX:+UseContainerSupport", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]
|
||||||
91
docker/build.sh
Executable file
91
docker/build.sh
Executable file
@@ -0,0 +1,91 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Farben für Output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Script Directory
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||||
|
|
||||||
|
# Load environment variables from .env
|
||||||
|
if [ -f "${SCRIPT_DIR}/.env" ]; then
|
||||||
|
echo -e "${GREEN}Loading environment variables from .env...${NC}"
|
||||||
|
set -a
|
||||||
|
source "${SCRIPT_DIR}/.env"
|
||||||
|
set +a
|
||||||
|
else
|
||||||
|
echo -e "${RED}Error: .env file not found in ${SCRIPT_DIR}${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Variables
|
||||||
|
IMAGE_NAME="${REGISTRY_URL}/${NAMESPACE}/${REPO_NAME}"
|
||||||
|
IMAGE_FULL="${IMAGE_NAME}:${IMAGE_TAG}"
|
||||||
|
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN}Building SKAMP Application${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "Project Root: ${PROJECT_ROOT}"
|
||||||
|
echo -e "Image: ${IMAGE_FULL}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
|
||||||
|
# Change to project root
|
||||||
|
cd "${PROJECT_ROOT}"
|
||||||
|
|
||||||
|
# Step 1: Clean previous builds (optional)
|
||||||
|
echo -e "\n${YELLOW}Step 1: Cleaning previous builds...${NC}"
|
||||||
|
if command -v mvn &> /dev/null; then
|
||||||
|
mvn clean
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}Maven not found locally, will use Docker build stage${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Step 2: Build Docker image
|
||||||
|
echo -e "\n${YELLOW}Step 2: Building Docker image...${NC}"
|
||||||
|
docker build \
|
||||||
|
-f "${SCRIPT_DIR}/Dockerfile" \
|
||||||
|
-t "${IMAGE_FULL}" \
|
||||||
|
-t "${IMAGE_NAME}:latest" \
|
||||||
|
"${PROJECT_ROOT}"
|
||||||
|
|
||||||
|
# Check if build was successful
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo -e "\n${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN}Build successful!${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "Image: ${IMAGE_FULL}"
|
||||||
|
echo -e "Also tagged as: ${IMAGE_NAME}:latest"
|
||||||
|
|
||||||
|
# Show image details
|
||||||
|
echo -e "\n${YELLOW}Image details:${NC}"
|
||||||
|
docker images "${IMAGE_NAME}" | head -n 2
|
||||||
|
|
||||||
|
# Optional: Push to registry
|
||||||
|
read -p "Do you want to push the image to the registry? (y/n) " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
echo -e "\n${YELLOW}Logging in to registry...${NC}"
|
||||||
|
echo "${CI_GITEA_TOKEN}" | docker login "${REGISTRY_URL}" -u "${CI_GITEA_USER}" --password-stdin
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}Login successful!${NC}"
|
||||||
|
echo -e "\n${YELLOW}Pushing image to registry...${NC}"
|
||||||
|
docker push "${IMAGE_FULL}"
|
||||||
|
docker push "${IMAGE_NAME}:latest"
|
||||||
|
echo -e "${GREEN}Push successful!${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${RED}Login failed! Cannot push images.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "\n${RED}Build failed!${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "\n${GREEN}Done!${NC}"
|
||||||
55
docker/compose.yml
Normal file
55
docker/compose.yml
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
services:
|
||||||
|
app:
|
||||||
|
image: ${REGISTRY_URL}/${NAMESPACE}/${REPO_NAME}:${IMAGE_TAG:-latest}
|
||||||
|
container_name: skamp-app
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
ports:
|
||||||
|
- "${APP_PORT:-8080}:8080"
|
||||||
|
environment:
|
||||||
|
# Spring Boot Profile
|
||||||
|
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE-prod}
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
SPRING_DATASOURCE_URL: jdbc:postgresql://${POSTGRES_HOST:-localhost}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-skamp}
|
||||||
|
SPRING_DATASOURCE_USERNAME: ${POSTGRES_USER:-dev}
|
||||||
|
SPRING_DATASOURCE_PASSWORD: ${POSTGRES_PASSWORD:-dev}
|
||||||
|
SPRING_JPA_HIBERNATE_DDL_AUTO: ${HIBERNATE_DDL_AUTO:-update}
|
||||||
|
|
||||||
|
# OAuth2/Keycloak Configuration
|
||||||
|
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: ${KEYCLOAK_ISSUER_URI:-http://localhost:8280/realms/skamp}
|
||||||
|
#SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI: ${KEYCLOAK_JWK_SET_URI}
|
||||||
|
|
||||||
|
# CORS Configuration
|
||||||
|
CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS:-http://localhost:3000}
|
||||||
|
|
||||||
|
# S3 Configuration
|
||||||
|
S3_ACCESS_KEY: ${MINIO_ACCESS_KEY:-dev}
|
||||||
|
S3_SECRET_KEY: ${MINIO_SECRET_KEY:-dev123456}
|
||||||
|
S3_ENDPOINT: ${MINIO_ENDPOINT:-http://localhost:9000}
|
||||||
|
|
||||||
|
# Application Configuration
|
||||||
|
SERVER_PORT: 8080
|
||||||
|
JAVA_OPTS: ${JAVA_OPTS:--Xmx512m -Xms256m}
|
||||||
|
volumes:
|
||||||
|
- app_logs:/app/logs
|
||||||
|
networks:
|
||||||
|
- skamp-network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 60s
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
driver: local
|
||||||
|
app_logs:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
networks:
|
||||||
|
skamp-network:
|
||||||
|
driver: bridge
|
||||||
@@ -5,13 +5,13 @@ spring:
|
|||||||
max-file-size: 1000MB # Maximal zulässige Größe pro Datei (z.B. 10 MB)
|
max-file-size: 1000MB # Maximal zulässige Größe pro Datei (z.B. 10 MB)
|
||||||
max-request-size: 5000MB # Maximal zulässige Größe der gesamten Anfrage (z.B. 50 MB)
|
max-request-size: 5000MB # Maximal zulässige Größe der gesamten Anfrage (z.B. 50 MB)
|
||||||
profiles:
|
profiles:
|
||||||
active: dev
|
active: ${SPRING_PROFILES_ACTIVE:prod}
|
||||||
application:
|
application:
|
||||||
name: skamp-api
|
name: ${APPLICATION_NAME:skamp-api}
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:postgresql://localhost:5432/skamp
|
url: jdbc:postgresql://${POSTGRES_HOST:localhost}:${POSTGRES_PORT:5432}/${POSTGRES_DB:skamp}
|
||||||
username: dev
|
username: ${POSTGRES_USER:dev}
|
||||||
password: dev
|
password: ${POSTGRES_PASSWORD:dev}
|
||||||
driver-class-name: org.postgresql.Driver
|
driver-class-name: org.postgresql.Driver
|
||||||
jpa:
|
jpa:
|
||||||
hibernate:
|
hibernate:
|
||||||
@@ -38,7 +38,7 @@ spring:
|
|||||||
oauth2:
|
oauth2:
|
||||||
resourceserver:
|
resourceserver:
|
||||||
jwt:
|
jwt:
|
||||||
issuer-uri: http://localhost:8280/realms/skamp
|
issuer-uri: ${KEYCLOAK_ISSUER_URI:http://localhost:8280/realms/skamp}
|
||||||
jwk-set-uri: ${spring.security.oauth2.resourceserver.jwt.issuer-uri}/protocol/openid-connect/certs
|
jwk-set-uri: ${spring.security.oauth2.resourceserver.jwt.issuer-uri}/protocol/openid-connect/certs
|
||||||
|
|
||||||
logging:
|
logging:
|
||||||
@@ -52,10 +52,10 @@ logging:
|
|||||||
|
|
||||||
cors:
|
cors:
|
||||||
allowed-origins:
|
allowed-origins:
|
||||||
- http://localhost:4200
|
- ${CORS_ALLOWED_ORIGINS:http://localhost:4200}
|
||||||
allowed-headers: "*"
|
allowed-headers: "*"
|
||||||
|
|
||||||
s3:
|
s3:
|
||||||
access-key: dev
|
access-key: ${MINIO_ACCESS_KEY:dev}
|
||||||
secret-key: dev123456
|
secret-key: ${MINIO_SECRET_KEY:dev123456}
|
||||||
endpoint: http://localhost:9000
|
endpoint: ${MINIO_ENDPOINT:http://localhost:9000}
|
||||||
|
|||||||
Reference in New Issue
Block a user