This commit is contained in:
parent
6630045f67
commit
8d67d17e82
121
.woodpecker.yaml
Normal file
121
.woodpecker.yaml
Normal file
@ -0,0 +1,121 @@
|
||||
steps:
|
||||
build-frontend:
|
||||
name: Build & Push Frontend
|
||||
image: woodpeckerci/plugin-kaniko
|
||||
when:
|
||||
branch: [ master, develop ]
|
||||
event: [ push, pull_request, tag ]
|
||||
path:
|
||||
include: [ frontend/** ]
|
||||
settings:
|
||||
registry: harbor.dvirlabs.com
|
||||
repo: my-apps/${CI_REPO_NAME}-frontend
|
||||
dockerfile: frontend/Dockerfile
|
||||
context: frontend
|
||||
tags:
|
||||
- latest
|
||||
- ${CI_COMMIT_TAG:-${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:7}}
|
||||
username:
|
||||
from_secret: DOCKER_USERNAME
|
||||
password:
|
||||
from_secret: DOCKER_PASSWORD
|
||||
|
||||
build-backend:
|
||||
name: Build & Push Backend
|
||||
image: woodpeckerci/plugin-kaniko
|
||||
when:
|
||||
branch: [ master, develop ]
|
||||
event: [ push, pull_request, tag ]
|
||||
path:
|
||||
include: [ backend/** ]
|
||||
settings:
|
||||
registry: harbor-core.dev-tools.svc.cluster.local
|
||||
repo: my-apps/${CI_REPO_NAME}-backend
|
||||
dockerfile: backend/Dockerfile
|
||||
context: backend
|
||||
tags:
|
||||
- latest
|
||||
- ${CI_COMMIT_TAG:-${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:7}}
|
||||
username:
|
||||
from_secret: DOCKER_USERNAME
|
||||
password:
|
||||
from_secret: DOCKER_PASSWORD
|
||||
|
||||
update-values-frontend:
|
||||
name: Update frontend tag in values.yaml
|
||||
image: alpine:3.19
|
||||
when:
|
||||
branch: [ master, develop ]
|
||||
event: [ push ]
|
||||
path:
|
||||
include: [ frontend/** ]
|
||||
environment:
|
||||
GIT_USERNAME:
|
||||
from_secret: GIT_USERNAME
|
||||
GIT_TOKEN:
|
||||
from_secret: GIT_TOKEN
|
||||
commands:
|
||||
- apk add --no-cache git yq
|
||||
- git config --global user.name "woodpecker-bot"
|
||||
- git config --global user.email "ci@dvirlabs.com"
|
||||
- git clone "https://$${GIT_USERNAME}:$${GIT_TOKEN}@git.dvirlabs.com/dvirlabs/my-apps.git"
|
||||
- cd my-apps
|
||||
- |
|
||||
TAG="${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:7}"
|
||||
echo "💡 Setting frontend tag to: $TAG"
|
||||
yq -i ".frontend.image.tag = \"$TAG\"" manifests/${CI_REPO_NAME}/values.yaml
|
||||
git add manifests/${CI_REPO_NAME}/values.yaml
|
||||
git commit -m "frontend: update tag to $TAG" || echo "No changes"
|
||||
git push origin HEAD
|
||||
|
||||
update-values-backend:
|
||||
name: Update backend tag in values.yaml
|
||||
image: alpine:3.19
|
||||
when:
|
||||
branch: [ master, develop ]
|
||||
event: [ push ]
|
||||
path:
|
||||
include: [ backend/** ]
|
||||
environment:
|
||||
GIT_USERNAME:
|
||||
from_secret: GIT_USERNAME
|
||||
GIT_TOKEN:
|
||||
from_secret: GIT_TOKEN
|
||||
commands:
|
||||
- apk add --no-cache git yq
|
||||
- git config --global user.name "woodpecker-bot"
|
||||
- git config --global user.email "ci@dvirlabs.com"
|
||||
- |
|
||||
if [ ! -d "my-apps" ]; then
|
||||
git clone "https://$${GIT_USERNAME}:$${GIT_TOKEN}@git.dvirlabs.com/dvirlabs/my-apps.git"
|
||||
fi
|
||||
- cd my-apps
|
||||
- |
|
||||
TAG="${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA:0:7}"
|
||||
echo "💡 Setting backend tag to: $TAG"
|
||||
yq -i ".backend.image.tag = \"$TAG\"" manifests/${CI_REPO_NAME}/values.yaml
|
||||
git add manifests/${CI_REPO_NAME}/values.yaml
|
||||
git commit -m "backend: update tag to $TAG" || echo "No changes"
|
||||
git push origin HEAD
|
||||
|
||||
|
||||
trigger-gitops-via-push:
|
||||
when:
|
||||
branch: [ master, develop ]
|
||||
event: [ push ]
|
||||
name: Trigger apps-gitops via Git push
|
||||
image: alpine/git
|
||||
environment:
|
||||
GIT_USERNAME:
|
||||
from_secret: GIT_USERNAME
|
||||
GIT_TOKEN:
|
||||
from_secret: GIT_TOKEN
|
||||
commands: |
|
||||
git config --global user.name "woodpecker-bot"
|
||||
git config --global user.email "ci@dvirlabs.com"
|
||||
git clone "https://$${GIT_USERNAME}:$${GIT_TOKEN}@git.dvirlabs.com/dvirlabs/apps-gitops.git"
|
||||
cd apps-gitops
|
||||
echo "# trigger at $(date) by $${CI_REPO_NAME}" >> .trigger
|
||||
git add .trigger
|
||||
git commit -m "ci: trigger apps-gitops build" || echo "no changes"
|
||||
git push origin HEAD
|
||||
26
backend/.dockerignore
Normal file
26
backend/.dockerignore
Normal file
@ -0,0 +1,26 @@
|
||||
__pycache__
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
.Python
|
||||
*.so
|
||||
*.egg
|
||||
*.egg-info
|
||||
dist
|
||||
build
|
||||
.env
|
||||
.venv
|
||||
venv/
|
||||
ENV/
|
||||
env/
|
||||
.pytest_cache
|
||||
.coverage
|
||||
htmlcov/
|
||||
.tox/
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
*.log
|
||||
.DS_Store
|
||||
uploads/
|
||||
migrations/
|
||||
32
backend/Dockerfile
Normal file
32
backend/Dockerfile
Normal file
@ -0,0 +1,32 @@
|
||||
# Use Python 3.11 slim image as base
|
||||
FROM python:3.11-slim
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
gcc \
|
||||
postgresql-client \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy requirements file
|
||||
COPY requirements.txt .
|
||||
|
||||
# Install Python dependencies
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Copy application code
|
||||
COPY . .
|
||||
|
||||
# Create uploads directory for product images
|
||||
RUN mkdir -p /app/uploads/products
|
||||
|
||||
# Expose port 8000
|
||||
EXPOSE 8000
|
||||
|
||||
# Set environment variables
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
# Run the application
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
Binary file not shown.
Binary file not shown.
13
brand-master-chart/Chart.yaml
Normal file
13
brand-master-chart/Chart.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
apiVersion: v2
|
||||
name: brand-master
|
||||
description: A Helm chart for Brand Master - E-commerce Fashion & Shoe Store
|
||||
type: application
|
||||
version: 1.0.0
|
||||
appVersion: "1.0.0"
|
||||
keywords:
|
||||
- brand-master
|
||||
- ecommerce
|
||||
- fashion
|
||||
- shoes
|
||||
maintainers:
|
||||
- name: dvir
|
||||
158
brand-master-chart/README.md
Normal file
158
brand-master-chart/README.md
Normal file
@ -0,0 +1,158 @@
|
||||
# Brand Master Helm Chart
|
||||
|
||||
This Helm chart deploys the Brand Master e-commerce application on Kubernetes.
|
||||
|
||||
## Components
|
||||
|
||||
- **Frontend**: React-based UI served by Nginx
|
||||
- **Backend**: FastAPI application
|
||||
- **Database**: PostgreSQL 16
|
||||
- **Storage**: 15GB PVC for product images
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes 1.19+
|
||||
- Helm 3.0+
|
||||
- cert-manager (for TLS certificates)
|
||||
- Storage class configured (nfs-client by default)
|
||||
|
||||
## Installation
|
||||
|
||||
### 1. Update values.yaml
|
||||
|
||||
Edit `values.yaml` and configure:
|
||||
|
||||
- Image repositories (if using private registry)
|
||||
- Domain names for ingress
|
||||
- JWT secret key (IMPORTANT!)
|
||||
- Database credentials
|
||||
- Storage class name
|
||||
|
||||
### 2. Install the chart
|
||||
|
||||
```bash
|
||||
# Install in the my-apps namespace
|
||||
helm install brand-master ./brand-master-chart -n my-apps --create-namespace
|
||||
|
||||
# Or with custom values
|
||||
helm install brand-master ./brand-master-chart -n my-apps \
|
||||
--set backend.jwtSecretKey=your-super-secret-key \
|
||||
--set postgres.password=secure-password
|
||||
```
|
||||
|
||||
### 3. Upgrade the chart
|
||||
|
||||
```bash
|
||||
helm upgrade brand-master ./brand-master-chart -n my-apps
|
||||
```
|
||||
|
||||
### 4. Uninstall
|
||||
|
||||
```bash
|
||||
helm uninstall brand-master -n my-apps
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Key Configuration Options
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `backend.image.repository` | Backend Docker image | `harbor.dvirlabs.com/my-apps/brand-master-backend` |
|
||||
| `backend.image.tag` | Backend image tag | `latest` |
|
||||
| `backend.jwtSecretKey` | JWT secret for authentication | `your-secret-key-change-this-in-production` |
|
||||
| `backend.persistence.enabled` | Enable persistent storage for images | `true` |
|
||||
| `backend.persistence.size` | Size of uploads PVC | `15Gi` |
|
||||
| `frontend.image.repository` | Frontend Docker image | `harbor.dvirlabs.com/my-apps/brand-master-frontend` |
|
||||
| `frontend.image.tag` | Frontend image tag | `latest` |
|
||||
| `postgres.user` | PostgreSQL username | `brand_master_user` |
|
||||
| `postgres.password` | PostgreSQL password | `brand_master_password` |
|
||||
| `postgres.database` | PostgreSQL database name | `brand_master_db` |
|
||||
| `postgres.persistence.size` | Size of database PVC | `10Gi` |
|
||||
|
||||
## Building Docker Images
|
||||
|
||||
### Backend
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
docker build -t harbor.dvirlabs.com/my-apps/brand-master-backend:latest .
|
||||
docker push harbor.dvirlabs.com/my-apps/brand-master-backend:latest
|
||||
```
|
||||
|
||||
### Frontend
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
docker build -t harbor.dvirlabs.com/my-apps/brand-master-frontend:latest \
|
||||
--build-arg VITE_API_URL=https://api-brand-master.dvirlabs.com .
|
||||
docker push harbor.dvirlabs.com/my-apps/brand-master-frontend:latest
|
||||
```
|
||||
|
||||
## Storage
|
||||
|
||||
The chart creates two PVCs:
|
||||
|
||||
1. **Database PVC**: 10GB for PostgreSQL data
|
||||
2. **Uploads PVC**: 15GB for product images at `/app/uploads`
|
||||
|
||||
Both use the `nfs-client` storage class by default. Update this in `values.yaml` if needed.
|
||||
|
||||
## Ingress
|
||||
|
||||
The chart creates two ingress resources:
|
||||
|
||||
- **Frontend**: `brand-master.dvirlabs.com`
|
||||
- **Backend API**: `api-brand-master.dvirlabs.com`
|
||||
|
||||
TLS is enabled by default using Let's Encrypt via cert-manager.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Check pod status
|
||||
```bash
|
||||
kubectl get pods -n my-apps
|
||||
```
|
||||
|
||||
### View logs
|
||||
```bash
|
||||
# Backend logs
|
||||
kubectl logs -n my-apps -l app.kubernetes.io/component=backend
|
||||
|
||||
# Frontend logs
|
||||
kubectl logs -n my-apps -l app.kubernetes.io/component=frontend
|
||||
|
||||
# Database logs
|
||||
kubectl logs -n my-apps -l app.kubernetes.io/component=database
|
||||
```
|
||||
|
||||
### Access services locally
|
||||
```bash
|
||||
# Frontend
|
||||
kubectl port-forward -n my-apps svc/brand-master-frontend 8080:80
|
||||
|
||||
# Backend
|
||||
kubectl port-forward -n my-apps svc/brand-master-backend 8000:8000
|
||||
|
||||
# Database
|
||||
kubectl port-forward -n my-apps svc/brand-master-db 5432:5432
|
||||
```
|
||||
|
||||
### Check PVC status
|
||||
```bash
|
||||
kubectl get pvc -n my-apps
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
1. **Change the JWT secret** in production
|
||||
2. **Update database credentials**
|
||||
3. **Use strong passwords**
|
||||
4. **Configure proper CORS settings**
|
||||
5. **Review and adjust resource limits**
|
||||
6. **Enable network policies** if needed
|
||||
7. **Use image pull secrets** for private registries
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions, refer to the main repository documentation.
|
||||
48
brand-master-chart/templates/NOTES.txt
Normal file
48
brand-master-chart/templates/NOTES.txt
Normal file
@ -0,0 +1,48 @@
|
||||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.frontend.ingress.enabled }}
|
||||
{{- range $host := .Values.frontend.ingress.hosts }}
|
||||
{{- range .paths }}
|
||||
Frontend: http{{ if $.Values.frontend.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.backend.ingress.enabled }}
|
||||
{{- range $host := .Values.backend.ingress.hosts }}
|
||||
{{- range .paths }}
|
||||
Backend API: http{{ if $.Values.backend.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
2. Database Connection:
|
||||
Host: {{ include "brand-master.fullname" . }}-db
|
||||
Port: {{ .Values.postgres.port }}
|
||||
Database: {{ .Values.postgres.database }}
|
||||
User: {{ .Values.postgres.user }}
|
||||
|
||||
3. Product Images Storage:
|
||||
{{- if .Values.backend.persistence.enabled }}
|
||||
PVC: {{ include "brand-master.fullname" . }}-uploads-pvc
|
||||
Size: {{ .Values.backend.persistence.size }}
|
||||
Mount Path: {{ .Values.backend.persistence.mountPath }}
|
||||
{{- else }}
|
||||
Warning: Persistence is disabled. Product images will be lost on pod restart!
|
||||
{{- end }}
|
||||
|
||||
4. IMPORTANT Security Notes:
|
||||
- Change the JWT secret key in values.yaml before deploying to production
|
||||
- Update the database password in values.yaml
|
||||
- Configure your domain names in the ingress sections
|
||||
- Ensure cert-manager is installed for TLS certificates
|
||||
|
||||
5. To access the application locally without ingress:
|
||||
kubectl port-forward svc/{{ include "brand-master.fullname" . }}-frontend 8080:80
|
||||
kubectl port-forward svc/{{ include "brand-master.fullname" . }}-backend 8000:8000
|
||||
|
||||
6. To check pod status:
|
||||
kubectl get pods -l app.kubernetes.io/instance={{ .Release.Name }}
|
||||
|
||||
7. To view logs:
|
||||
kubectl logs -l app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=backend
|
||||
kubectl logs -l app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=frontend
|
||||
60
brand-master-chart/templates/_helpers.tpl
Normal file
60
brand-master-chart/templates/_helpers.tpl
Normal file
@ -0,0 +1,60 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "brand-master.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
*/}}
|
||||
{{- define "brand-master.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "brand-master.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "brand-master.labels" -}}
|
||||
helm.sh/chart: {{ include "brand-master.chart" . }}
|
||||
{{ include "brand-master.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "brand-master.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "brand-master.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "brand-master.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "brand-master.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
106
brand-master-chart/templates/backend-deployment.yaml
Normal file
106
brand-master-chart/templates/backend-deployment.yaml
Normal file
@ -0,0 +1,106 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "brand-master.fullname" . }}-backend
|
||||
labels:
|
||||
{{- include "brand-master.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: backend
|
||||
spec:
|
||||
replicas: {{ .Values.backend.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "brand-master.selectorLabels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: backend
|
||||
template:
|
||||
metadata:
|
||||
{{- with .Values.podAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "brand-master.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: backend
|
||||
spec:
|
||||
{{- with .Values.global.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "brand-master.serviceAccountName" . }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
initContainers:
|
||||
- name: wait-for-postgres
|
||||
image: busybox:1.35
|
||||
command: ['sh', '-c', 'until nc -z {{ include "brand-master.fullname" . }}-db-headless {{ .Values.postgres.port | default 5432 }}; do echo waiting for postgres; sleep 2; done;']
|
||||
containers:
|
||||
- name: backend
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.backend.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.backend.service.targetPort }}
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "brand-master.fullname" . }}-secrets
|
||||
key: database-url
|
||||
- name: SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "brand-master.fullname" . }}-secrets
|
||||
key: jwt-secret-key
|
||||
- name: ALGORITHM
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "brand-master.fullname" . }}-secrets
|
||||
key: jwt-algorithm
|
||||
- name: ACCESS_TOKEN_EXPIRE_MINUTES
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "brand-master.fullname" . }}-secrets
|
||||
key: jwt-expire-minutes
|
||||
{{- range $key, $value := .Values.backend.env }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- if .Values.backend.persistence.enabled }}
|
||||
- name: uploads
|
||||
mountPath: {{ .Values.backend.persistence.mountPath }}
|
||||
{{- end }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
resources:
|
||||
{{- toYaml .Values.backend.resources | nindent 12 }}
|
||||
volumes:
|
||||
{{- if .Values.backend.persistence.enabled }}
|
||||
- name: uploads
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "brand-master.fullname" . }}-uploads-pvc
|
||||
{{- end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
42
brand-master-chart/templates/backend-ingress.yaml
Normal file
42
brand-master-chart/templates/backend-ingress.yaml
Normal file
@ -0,0 +1,42 @@
|
||||
{{- if .Values.backend.ingress.enabled -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "brand-master.fullname" . }}-backend
|
||||
labels:
|
||||
{{- include "brand-master.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: backend
|
||||
{{- with .Values.backend.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.backend.ingress.className }}
|
||||
ingressClassName: {{ .Values.backend.ingress.className }}
|
||||
{{- end }}
|
||||
{{- if .Values.backend.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.backend.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.backend.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "brand-master.fullname" $ }}-backend
|
||||
port:
|
||||
number: {{ $.Values.backend.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
18
brand-master-chart/templates/backend-pvc.yaml
Normal file
18
brand-master-chart/templates/backend-pvc.yaml
Normal file
@ -0,0 +1,18 @@
|
||||
{{- if .Values.backend.persistence.enabled }}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ include "brand-master.fullname" . }}-uploads-pvc
|
||||
labels:
|
||||
{{- include "brand-master.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: backend
|
||||
spec:
|
||||
accessModes:
|
||||
- {{ .Values.backend.persistence.accessMode }}
|
||||
{{- if .Values.backend.persistence.storageClass }}
|
||||
storageClassName: {{ .Values.backend.persistence.storageClass }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.backend.persistence.size }}
|
||||
{{- end }}
|
||||
17
brand-master-chart/templates/backend-service.yaml
Normal file
17
brand-master-chart/templates/backend-service.yaml
Normal file
@ -0,0 +1,17 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "brand-master.fullname" . }}-backend
|
||||
labels:
|
||||
{{- include "brand-master.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: backend
|
||||
spec:
|
||||
type: {{ .Values.backend.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.backend.service.port }}
|
||||
targetPort: {{ .Values.backend.service.targetPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "brand-master.selectorLabels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: backend
|
||||
36
brand-master-chart/templates/db-service.yaml
Normal file
36
brand-master-chart/templates/db-service.yaml
Normal file
@ -0,0 +1,36 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "brand-master.fullname" . }}-db
|
||||
labels:
|
||||
{{- include "brand-master.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: database
|
||||
spec:
|
||||
type: {{ .Values.postgres.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.postgres.service.port }}
|
||||
targetPort: {{ .Values.postgres.service.targetPort }}
|
||||
protocol: TCP
|
||||
name: postgres
|
||||
selector:
|
||||
{{- include "brand-master.selectorLabels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: database
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "brand-master.fullname" . }}-db-headless
|
||||
labels:
|
||||
{{- include "brand-master.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: database
|
||||
spec:
|
||||
type: ClusterIP
|
||||
clusterIP: None
|
||||
ports:
|
||||
- port: {{ .Values.postgres.service.port }}
|
||||
targetPort: {{ .Values.postgres.service.targetPort }}
|
||||
protocol: TCP
|
||||
name: postgres
|
||||
selector:
|
||||
{{- include "brand-master.selectorLabels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: database
|
||||
124
brand-master-chart/templates/db-statefulset.yaml
Normal file
124
brand-master-chart/templates/db-statefulset.yaml
Normal file
@ -0,0 +1,124 @@
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: {{ include "brand-master.fullname" . }}-db
|
||||
labels:
|
||||
{{- include "brand-master.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: database
|
||||
spec:
|
||||
serviceName: {{ include "brand-master.fullname" . }}-db-headless
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "brand-master.selectorLabels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: database
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "brand-master.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: database
|
||||
spec:
|
||||
securityContext:
|
||||
fsGroup: 999
|
||||
initContainers:
|
||||
- name: fix-permissions
|
||||
image: busybox:latest
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
chown -R 999:999 /var/lib/postgresql/data || true
|
||||
chmod 700 /var/lib/postgresql/data || true
|
||||
volumeMounts:
|
||||
- name: postgres-data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
securityContext:
|
||||
runAsUser: 0
|
||||
containers:
|
||||
- name: postgres
|
||||
securityContext:
|
||||
runAsUser: 999
|
||||
runAsNonRoot: true
|
||||
image: "{{ .Values.postgres.image.repository }}:{{ .Values.postgres.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.postgres.image.pullPolicy }}
|
||||
ports:
|
||||
- name: postgres
|
||||
containerPort: {{ .Values.postgres.port }}
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: POSTGRES_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "brand-master.fullname" . }}-secrets
|
||||
key: postgres-user
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "brand-master.fullname" . }}-secrets
|
||||
key: postgres-password
|
||||
- name: POSTGRES_DB
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "brand-master.fullname" . }}-secrets
|
||||
key: postgres-database
|
||||
- name: PGDATA
|
||||
value: /var/lib/postgresql/data/pgdata
|
||||
volumeMounts:
|
||||
- name: postgres-data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
- name: postgres-run
|
||||
mountPath: /var/run/postgresql
|
||||
resources:
|
||||
{{- toYaml .Values.postgres.resources | nindent 12 }}
|
||||
startupProbe:
|
||||
exec:
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- pg_isready -h 127.0.0.1 -p 5432 -U "$POSTGRES_USER" -d "$POSTGRES_DB"
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 30
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- pg_isready -h 127.0.0.1 -p 5432 -U "$POSTGRES_USER" -d "$POSTGRES_DB"
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- pg_isready -h 127.0.0.1 -p 5432 -U "$POSTGRES_USER" -d "$POSTGRES_DB"
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
volumes:
|
||||
- name: postgres-run
|
||||
emptyDir: {}
|
||||
{{- if .Values.postgres.persistence.enabled }}
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: postgres-data
|
||||
labels:
|
||||
{{- include "brand-master.labels" . | nindent 8 }}
|
||||
spec:
|
||||
accessModes:
|
||||
- {{ .Values.postgres.persistence.accessMode }}
|
||||
{{- if .Values.postgres.persistence.storageClass }}
|
||||
storageClassName: {{ .Values.postgres.persistence.storageClass }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.postgres.persistence.size }}
|
||||
{{- else }}
|
||||
- name: postgres-data
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
73
brand-master-chart/templates/frontend-deployment.yaml
Normal file
73
brand-master-chart/templates/frontend-deployment.yaml
Normal file
@ -0,0 +1,73 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "brand-master.fullname" . }}-frontend
|
||||
labels:
|
||||
{{- include "brand-master.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: frontend
|
||||
spec:
|
||||
replicas: {{ .Values.frontend.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "brand-master.selectorLabels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: frontend
|
||||
template:
|
||||
metadata:
|
||||
{{- with .Values.podAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "brand-master.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: frontend
|
||||
spec:
|
||||
{{- with .Values.global.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "brand-master.serviceAccountName" . }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
containers:
|
||||
- name: frontend
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.frontend.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.frontend.service.targetPort }}
|
||||
protocol: TCP
|
||||
{{- if .Values.frontend.env }}
|
||||
env:
|
||||
{{- range $key, $value := .Values.frontend.env }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
resources:
|
||||
{{- toYaml .Values.frontend.resources | nindent 12 }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
42
brand-master-chart/templates/frontend-ingress.yaml
Normal file
42
brand-master-chart/templates/frontend-ingress.yaml
Normal file
@ -0,0 +1,42 @@
|
||||
{{- if .Values.frontend.ingress.enabled -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "brand-master.fullname" . }}-frontend
|
||||
labels:
|
||||
{{- include "brand-master.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: frontend
|
||||
{{- with .Values.frontend.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.frontend.ingress.className }}
|
||||
ingressClassName: {{ .Values.frontend.ingress.className }}
|
||||
{{- end }}
|
||||
{{- if .Values.frontend.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.frontend.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.frontend.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "brand-master.fullname" $ }}-frontend
|
||||
port:
|
||||
number: {{ $.Values.frontend.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
17
brand-master-chart/templates/frontend-service.yaml
Normal file
17
brand-master-chart/templates/frontend-service.yaml
Normal file
@ -0,0 +1,17 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "brand-master.fullname" . }}-frontend
|
||||
labels:
|
||||
{{- include "brand-master.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: frontend
|
||||
spec:
|
||||
type: {{ .Values.frontend.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.frontend.service.port }}
|
||||
targetPort: {{ .Values.frontend.service.targetPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "brand-master.selectorLabels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: frontend
|
||||
15
brand-master-chart/templates/secret.yaml
Normal file
15
brand-master-chart/templates/secret.yaml
Normal file
@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "brand-master.fullname" . }}-secrets
|
||||
labels:
|
||||
{{- include "brand-master.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
postgres-user: {{ .Values.postgres.user | quote }}
|
||||
postgres-password: {{ .Values.postgres.password | quote }}
|
||||
postgres-database: {{ .Values.postgres.database | quote }}
|
||||
database-url: "postgresql://{{ .Values.postgres.user }}:{{ .Values.postgres.password }}@{{ include "brand-master.fullname" . }}-db:{{ .Values.postgres.port }}/{{ .Values.postgres.database }}"
|
||||
jwt-secret-key: {{ .Values.backend.jwtSecretKey | quote }}
|
||||
jwt-algorithm: {{ .Values.backend.jwtAlgorithm | quote }}
|
||||
jwt-expire-minutes: {{ .Values.backend.jwtExpireMinutes | quote }}
|
||||
12
brand-master-chart/templates/serviceaccount.yaml
Normal file
12
brand-master-chart/templates/serviceaccount.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "brand-master.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "brand-master.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
165
brand-master-chart/values.yaml
Normal file
165
brand-master-chart/values.yaml
Normal file
@ -0,0 +1,165 @@
|
||||
global:
|
||||
namespace: my-apps
|
||||
imagePullSecrets: []
|
||||
|
||||
# Backend configuration
|
||||
backend:
|
||||
name: backend
|
||||
replicaCount: 1
|
||||
image:
|
||||
repository: harbor.dvirlabs.com/my-apps/brand-master-backend
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "latest"
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 8000
|
||||
targetPort: 8000
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 1Gi
|
||||
|
||||
env:
|
||||
PYTHONUNBUFFERED: "1"
|
||||
BACKEND_URL: "https://api-brand-master.dvirlabs.com"
|
||||
FRONTEND_URL: "https://brand-master.dvirlabs.com"
|
||||
|
||||
# JWT Secret Key (IMPORTANT: Change this in production!)
|
||||
jwtSecretKey: "your-secret-key-change-this-in-production"
|
||||
jwtAlgorithm: "HS256"
|
||||
jwtExpireMinutes: "30"
|
||||
|
||||
# Persistent storage for product images
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClass: "nfs-client"
|
||||
accessMode: ReadWriteOnce
|
||||
size: 15Gi
|
||||
mountPath: /app/uploads
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: "traefik"
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
hosts:
|
||||
- host: api-brand-master.dvirlabs.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: api-brand-master-tls
|
||||
hosts:
|
||||
- api-brand-master.dvirlabs.com
|
||||
|
||||
# Frontend configuration
|
||||
frontend:
|
||||
name: frontend
|
||||
replicaCount: 1
|
||||
image:
|
||||
repository: harbor.dvirlabs.com/my-apps/brand-master-frontend
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "latest"
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 80
|
||||
targetPort: 80
|
||||
|
||||
env:
|
||||
VITE_API_URL: "https://api-brand-master.dvirlabs.com"
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: "traefik"
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
hosts:
|
||||
- host: brand-master.dvirlabs.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: brand-master-tls
|
||||
hosts:
|
||||
- brand-master.dvirlabs.com
|
||||
|
||||
# PostgreSQL configuration
|
||||
postgres:
|
||||
name: db
|
||||
image:
|
||||
repository: postgres
|
||||
tag: "16-alpine"
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
user: brand_master_user
|
||||
password: brand_master_password
|
||||
database: brand_master_db
|
||||
port: 5432
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 5432
|
||||
targetPort: 5432
|
||||
|
||||
persistence:
|
||||
enabled: true
|
||||
accessMode: ReadWriteOnce
|
||||
storageClass: "nfs-client"
|
||||
size: 10Gi
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 1Gi
|
||||
|
||||
# Service Account
|
||||
serviceAccount:
|
||||
create: true
|
||||
annotations: {}
|
||||
name: ""
|
||||
|
||||
# Pod annotations
|
||||
podAnnotations: {}
|
||||
|
||||
# Pod security context
|
||||
podSecurityContext: {}
|
||||
# fsGroup: 2000
|
||||
|
||||
# Container security context
|
||||
securityContext: {}
|
||||
# capabilities:
|
||||
# drop:
|
||||
# - ALL
|
||||
# readOnlyRootFilesystem: true
|
||||
# runAsNonRoot: true
|
||||
# runAsUser: 1000
|
||||
|
||||
# Node selector
|
||||
nodeSelector: {}
|
||||
|
||||
# Tolerations
|
||||
tolerations: []
|
||||
|
||||
# Affinity
|
||||
affinity: {}
|
||||
19
frontend/.dockerignore
Normal file
19
frontend/.dockerignore
Normal file
@ -0,0 +1,19 @@
|
||||
node_modules
|
||||
dist
|
||||
.git
|
||||
.gitignore
|
||||
README.md
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.vscode
|
||||
.idea
|
||||
60
frontend/Dockerfile
Normal file
60
frontend/Dockerfile
Normal file
@ -0,0 +1,60 @@
|
||||
# Build stage
|
||||
FROM node:18-alpine AS build
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package.json package-lock.json* ./
|
||||
|
||||
# Install dependencies
|
||||
RUN npm install
|
||||
|
||||
# Copy application code
|
||||
COPY . .
|
||||
|
||||
# Build argument for API URL (can be overridden at build time)
|
||||
ARG VITE_API_URL
|
||||
ENV VITE_API_URL=${VITE_API_URL}
|
||||
|
||||
# Build the application
|
||||
RUN npm run build
|
||||
|
||||
# Production stage
|
||||
FROM nginx:alpine
|
||||
|
||||
# Remove default nginx config
|
||||
RUN rm /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Create custom nginx config
|
||||
RUN echo 'server {' > /etc/nginx/conf.d/default.conf && \
|
||||
echo ' listen 80;' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo ' server_name _;' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo ' root /usr/share/nginx/html;' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo ' index index.html;' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo '' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo ' # Enable gzip compression' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo ' gzip on;' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo ' gzip_vary on;' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo ' gzip_min_length 1024;' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo ' gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json;' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo '' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo ' location / {' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo ' try_files $uri $uri/ /index.html;' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo ' }' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo '' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo ' # Cache static assets' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo ' location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|webp)$ {' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo ' expires 1y;' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo ' add_header Cache-Control "public, immutable";' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo ' }' >> /etc/nginx/conf.d/default.conf && \
|
||||
echo '}' >> /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Copy built files from build stage
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
|
||||
# Expose port 80
|
||||
EXPOSE 80
|
||||
|
||||
# Start nginx
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
Loading…
x
Reference in New Issue
Block a user