📝 feat: Update README with feature list and deployment instructions

refactor: Remove old Helm chart files and templates

feat: Add new Helm chart structure for neo-blog deployment

chore: Add .helmignore and initial Chart.yaml for Helm chart

feat: Implement backend and frontend deployment templates in Helm chart

feat: Create services and ingress configurations for backend and frontend

chore: Define resource limits and requests for backend and frontend in values.yaml

feat: Enable autoscaling configuration for backend and frontend deployments

chore: Clean up unused files and configurations from previous setup
This commit is contained in:
2025-07-29 08:15:20 +08:00
parent 6b391422b8
commit 1b29d50ba4
12 changed files with 15 additions and 1 deletions

23
helm/.helmignore Normal file
View File

@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

24
helm/Chart.yaml Normal file
View File

@ -0,0 +1,24 @@
apiVersion: v2
name: neo-blog
description: A Helm chart for Kubernetes
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "latest"

View File

@ -0,0 +1,77 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "neo-blog.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "neo-blog.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 "neo-blog.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "neo-blog.labels" -}}
helm.sh/chart: {{ include "neo-blog.chart" . }}
{{ include "neo-blog.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "neo-blog.selectorLabels" -}}
app.kubernetes.io/name: {{ include "neo-blog.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Selector labels for Frontend
*/}}
{{- define "neo-blog.frontend.selectorLabels" -}}
{{- include "neo-blog.selectorLabels" . }}
app.kubernetes.io/component: frontend
{{- end }}
{{/*
Selector labels for Backend
*/}}
{{- define "neo-blog.backend.selectorLabels" -}}
{{- include "neo-blog.selectorLabels" . }}
app.kubernetes.io/component: backend
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "neo-blog.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "neo-blog.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,83 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "neo-blog.fullname" . }}-backend
labels:
{{- include "neo-blog.backend.selectorLabels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "neo-blog.backend.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "neo-blog.backend.selectorLabels" . | nindent 8 }}
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "neo-blog.serviceAccountName" . }}
{{- with .Values.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ .Chart.Name }}-backend
{{- with .Values.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
image: "{{ .Values.image.registry }}/{{ .Values.image.backend }}:{{ .Values.image.backendTag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
env:
{{- range $key, $val := .Values.backend.env }}
- name: {{ $key | quote }}
value: {{ $val | quote }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.service.port }}
protocol: TCP
livenessProbe:
httpGet:
path: /api/v1/post/list
port: http
readinessProbe:
httpGet:
path: /api/v1/post/list
port: http
{{- with .Values.resources.backend }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.volumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- 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 }}

View File

@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "neo-blog.fullname" . }}-backend
labels:
{{- include "neo-blog.backend.selectorLabels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "neo-blog.backend.selectorLabels" . | nindent 4 }}

View File

@ -0,0 +1,86 @@
{{- if .Values.frontend.enabled -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "neo-blog.fullname" . }}-frontend
labels:
{{- include "neo-blog.frontend.selectorLabels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "neo-blog.frontend.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "neo-blog.frontend.selectorLabels" . | nindent 8 }}
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "neo-blog.serviceAccountName" . }}
{{- with .Values.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ .Chart.Name }}-frontend
{{- with .Values.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
image: "{{ .Values.image.registry }}/{{ .Values.image.frontend }}:{{ .Values.image.frontendTag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.port }}
protocol: TCP
env:
- name: BACKEND_URL
value: "http://{{(include "neo-blog.fullname" .)}}-backend:{{ .Values.service.port }}"
- name: PORT
value: "{{ .Values.service.port }}"
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
{{- with .Values.resources.frontend }}
resources:
{{- toYaml . | nindent 12}}
{{- end }}
{{- with .Values.volumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- 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 }}
{{- end -}}

View File

@ -0,0 +1,17 @@
{{- if .Values.frontend.enabled -}}
apiVersion: v1
kind: Service
metadata:
name: {{ include "neo-blog.fullname" . }}-frontend
labels:
{{- include "neo-blog.frontend.selectorLabels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "neo-blog.frontend.selectorLabels" . | nindent 4 }}
{{- end -}}

65
helm/templates/hpa.yaml Normal file
View File

@ -0,0 +1,65 @@
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "neo-blog.fullname" . }}-backend
labels:
{{- include "neo-blog.backend.selectorLabels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "neo-blog.fullname" . }}-backend
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- if .Values.frontend.enabled -}}
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "neo-blog.fullname" . }}-frontend
labels:
{{- include "neo-blog.frontend.selectorLabels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "neo-blog.fullname" . }}-frontend
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- end -}}
{{- end }}

View File

@ -0,0 +1,61 @@
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "neo-blog.fullname" . }}-frontend
labels:
{{- include "neo-blog.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.ingress.className }}
ingressClassName: {{ . }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts.frontend }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
{{- with .pathType }}
pathType: {{ . }}
{{- end }}
backend:
service:
name: {{ include "neo-blog.fullname" $ }}-frontend
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- if .Values.backend.expose -}}
{{- range .Values.ingress.hosts.backend }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
{{- with .pathType }}
pathType: {{ . }}
{{- end }}
backend:
service:
name: {{ include "neo-blog.fullname" $ }}-backend
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,13 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "neo-blog.serviceAccountName" . }}
labels:
{{- include "neo-blog.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automount }}
{{- end }}

174
helm/values.yaml Normal file
View File

@ -0,0 +1,174 @@
# 初始副本数
replicaCount: 1
# 镜像设置
image:
registry: docker.io
backend: snowykami/neo-blog-backend
backendTag: latest
frontend: snowykami/neo-blog-frontend
frontendTag: latest
pullPolicy: IfNotPresent
# 是否启用前端
frontend:
enabled: true
backend:
# 是否暴露后端
expose: false
# 后端环境变量
env:
# Captcha settings 机器人挑战配置
# 开发模式下的直接通过验证码
CAPTCHA_DEV_PASSCODE: "114514"
# captcha类型支持turnstile recaptcha hcaptchadisable为禁用验证码
CAPTCHA_TYPE: turnstile
# captcha设置
CAPTCHA_SITE_SECRET: 89dh29djha28dh
CAPTCHA_SECRET_KEY: 89dh28912dh1289dh128d9d
# Database settings 数据库配置
# 数据库驱动支持sqlite postgres
DB_DRIVER: sqlite
DB_NAME: blog
DB_PATH: ./data/data.db
DB_HOST: postgres
DB_PORT: 5432
DB_USER: blog
DB_PASSWORD: blog
# postgres数据库SSL模式
DB_SSLMODE: disable
# Email settings 邮件配置
EMAIL_ENABLED: false
EMAIL_USERNAME: xxx@bbb.com
EMAIL_PASSWORD: xxx
EMAIL_ADDRESS: xxx@bbb.com
EMAIL_HOST: smtp.xxx.com
EMAIL_PORT: "465"
EMAIL_SSL: true
# App settings 应用程序配置
LOG_LEVEL: debug
BASE_URL: https://blog.shenyu.moe
MAX_REQUEST_BODY_SIZE: "1000000"
MODE: prod
# 后端端口,无需替换
PORT: "80"
PASSWORD_SALT: "1234567890"
JWT_SECRET: "1234567890"
TOKEN_DURATION: "3600"
REFRESH_TOKEN_DURATION: "604800"
## 镜像拉取密钥
imagePullSecrets: []
# 覆盖ChartName
nameOverride: ""
fullnameOverride: ""
# 服务账号
serviceAccount:
# 是否创建
create: true
# 是否自动挂载
automount: true
# 自定义声明
annotations: {}
# 服务账号名
# 若未设置将自动生成
name: ""
# This is for setting Kubernetes Annotations to a Pod.
# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
podAnnotations: {}
# This is for setting Kubernetes Labels to a Pod.
# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
podLabels: {}
podSecurityContext: {}
# fsGroup: 2000
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
# 服务配置
service:
type: ClusterIP
# 服务端口,非必要无需更改
port: 80
# ingress 配置
ingress:
enabled: true
className: "nginx"
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
frontend:
- host: neo-blog.local
paths:
- path: /
pathType: ImplementationSpecific
backend:
- host: api.neo-blog.local
paths:
- path: /
pathType: ImplementationSpecific
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
# 资源配置
resources:
backend:
limits:
cpu: 2
memory: 2Gi
requests:
cpu: 2
memory: 2Gi
frontend:
limits:
cpu: 64
memory: 64Gi
requests:
cpu: 64
memory: 64Gi
# 自动扩缩容
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
targetMemoryUtilizationPercentage: 80
# 存储卷
volumes: []
# - name: foo
# secret:
# secretName: mysecret
# optional: false
volumeMounts: []
# - name: foo
# mountPath: "/etc/foo"
# readOnly: true
nodeSelector: {}
tolerations: []
affinity: {}