mirror of
https://github.com/labring/sealos.git
synced 2026-10-30 18:09:56 +08:00
feat(aiproxy): add aiproxy chart build (#6073)
* feat(aiproxy): add chart and Dockerfile for aiproxy frontend Signed-off-by: cuisongliu <cuisongliu@qq.com> * feat(aiproxy): add app configuration and update install script for suffix handling Signed-off-by: cuisongliu <cuisongliu@qq.com> * fix(aiproxy): remove space in URL construction for proper formatting Signed-off-by: cuisongliu <cuisongliu@qq.com> --------- Signed-off-by: cuisongliu <cuisongliu@qq.com>
This commit is contained in:
@@ -298,8 +298,14 @@ jobs:
|
||||
ALIYUN_CLUSTER_IMAGE: ${{ steps.prepare.outputs.aliyun_cluster_image }}
|
||||
ALIYUN_LATEST_CLUSTER_IMAGE: ${{ steps.prepare.outputs.aliyun_latest_cluster_image }}
|
||||
run: |
|
||||
sudo sed -i "s;${OLD_DOCKER_IMAGE};${NEW_DOCKER_IMAGE};" manifests/*
|
||||
|
||||
if [[ -d manifests ]]; then
|
||||
echo "Found manifests"
|
||||
sudo sed -i "s;${OLD_DOCKER_IMAGE};${NEW_DOCKER_IMAGE};" manifests/*
|
||||
fi
|
||||
if [[ -f charts/${{ env.MODULE_NAME }}/values.yaml ]]; then
|
||||
echo "Found charts charts/${{ env.MODULE_NAME }}/values.yaml"
|
||||
sed -i "s;${OLD_DOCKER_IMAGE};${NEW_DOCKER_IMAGE};" charts/${{ env.MODULE_NAME }}/values.yaml
|
||||
fi
|
||||
# Build for GHCR
|
||||
sudo sealos build -t "${CLUSTER_IMAGE}-amd64" --platform linux/amd64 -f Kubefile
|
||||
sudo sealos build -t "${LATEST_CLUSTER_IMAGE}-amd64" --platform linux/amd64 -f Kubefile
|
||||
|
||||
@@ -44,6 +44,7 @@ jobs:
|
||||
matrix:
|
||||
module:
|
||||
[
|
||||
providers/aiproxy,
|
||||
providers/license,
|
||||
providers/cronjob,
|
||||
providers/template,
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# Install dependencies only when needed
|
||||
FROM node:current-alpine AS deps
|
||||
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
||||
RUN apk add --no-cache libc6-compat && npm install -g pnpm
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies based on the preferred package manager
|
||||
COPY package.json pnpm-lock.yaml* ./
|
||||
RUN \
|
||||
[ -f pnpm-lock.yaml ] && pnpm install || \
|
||||
(echo "Lockfile not found." && exit 1)
|
||||
|
||||
# Rebuild the source code only when needed
|
||||
FROM node:current-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
# Next.js collects completely anonymous telemetry data about general usage.
|
||||
# Learn more here: https://nextjs.org/telemetry
|
||||
# Uncomment the following line in case you want to disable telemetry during the build.
|
||||
ENV NEXT_TELEMETRY_DISABLED 1
|
||||
ENV NEXT_PUBLIC_MOCK_USER ''
|
||||
|
||||
RUN npm install -g pnpm && pnpm run build
|
||||
|
||||
# Production image, copy all the files and run next
|
||||
FROM node:current-alpine AS runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV production
|
||||
# Uncomment the following line in case you want to disable telemetry during runtime.
|
||||
ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
|
||||
RUN sed -i 's/https/http/' /etc/apk/repositories
|
||||
RUN apk add curl \
|
||||
&& apk add ca-certificates \
|
||||
&& update-ca-certificates
|
||||
|
||||
# You only need to copy next.config.js if you are NOT using the default configuration
|
||||
# COPY --from=builder /app/next.config.js ./
|
||||
COPY --from=builder /app/public ./public
|
||||
COPY --from=builder /app/package.json ./package.json
|
||||
# COPY --from=builder /app/.env* .
|
||||
|
||||
# Automatically leverage output traces to reduce image size
|
||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
@@ -0,0 +1,3 @@
|
||||
FROM scratch
|
||||
COPY . .
|
||||
CMD ["bash install.sh"]
|
||||
@@ -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/
|
||||
@@ -0,0 +1,24 @@
|
||||
apiVersion: v2
|
||||
name: aiproxy-web
|
||||
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: "1.16.0"
|
||||
@@ -0,0 +1,58 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "aiproxy.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 "aiproxy.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 "aiproxy.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "aiproxy.labels" -}}
|
||||
helm.sh/chart: {{ include "aiproxy.chart" . }}
|
||||
{{ include "aiproxy.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "aiproxy.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "aiproxy.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "aiproxy.serviceAccountName" -}}
|
||||
{{- default (include "aiproxy.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,18 @@
|
||||
apiVersion: app.sealos.io/v1
|
||||
kind: App
|
||||
metadata:
|
||||
name: aiproxy
|
||||
namespace: app-system
|
||||
spec:
|
||||
data:
|
||||
desc: Sealos AI Proxy
|
||||
url: https://{{ include "aiproxy.fullname" . }}.{{.Values.cloudDomain}}{{.Values.suffix}}
|
||||
displayType: more
|
||||
i18n:
|
||||
zh:
|
||||
name: AI Proxy
|
||||
zh-Hans:
|
||||
name: AI Proxy
|
||||
icon: https://objectstorageapi.hzh.sealos.run/cyhipdvv-logos/aiproxy.svg
|
||||
name: AI Proxy
|
||||
type: iframe
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: v1
|
||||
data: {{ toYaml .Values.aiproxy | nindent 2 }}
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
namespace: {{.Release.Namespace}}
|
||||
name: {{ include "aiproxy.fullname" . }}
|
||||
labels:
|
||||
{{- include "aiproxy.labels" . | nindent 4 }}
|
||||
@@ -0,0 +1,59 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
namespace: {{ .Release.Namespace }}
|
||||
name: {{ include "aiproxy.fullname" . }}
|
||||
labels:
|
||||
{{- include "aiproxy.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{.Values.replicas}}
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxUnavailable: 0
|
||||
maxSurge: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
{{ include "aiproxy.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
{{- with .Values.podAnnotations }}
|
||||
{{ toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
|
||||
labels:
|
||||
{{ include "aiproxy.labels" . | nindent 8 }}
|
||||
{{- with .Values.podLabels }}
|
||||
{{ toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 600
|
||||
containers:
|
||||
- image: {{.Values.image}}
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: aiproxy
|
||||
resources: {{ toYaml .Values.resources | nindent 12 }}
|
||||
env:
|
||||
- name: AI_PROXY_BACKEND
|
||||
value: https://aiproxy.{{.Values.cloudDomain}}
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: {{ include "aiproxy.fullname" . }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 3000
|
||||
protocol: TCP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
namespace: {{ .Release.Namespace }}
|
||||
name: {{ include "aiproxy.fullname" . }}
|
||||
labels:
|
||||
{{- include "aiproxy.labels" . | nindent 4 }}
|
||||
spec:
|
||||
ports:
|
||||
- port: 3000
|
||||
targetPort: 3000
|
||||
selector: {{ include "aiproxy.selectorLabels" . | nindent 4 }}
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
namespace: {{.Release.Namespace}}
|
||||
name: {{ include "aiproxy.fullname" . }}
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: nginx
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: 32m
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: 'false'
|
||||
nginx.ingress.kubernetes.io/backend-protocol: HTTP
|
||||
nginx.ingress.kubernetes.io/client-body-buffer-size: 64k
|
||||
nginx.ingress.kubernetes.io/proxy-buffer-size: 64k
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: '300'
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: '300'
|
||||
nginx.ingress.kubernetes.io/server-snippet: |
|
||||
client_header_buffer_size 64k;
|
||||
large_client_header_buffers 4 128k;
|
||||
spec:
|
||||
rules:
|
||||
- host: {{ include "aiproxy.fullname" . }}.{{.Values.cloudDomain}}
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: /
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "aiproxy.fullname" . }}
|
||||
port:
|
||||
number: 3000
|
||||
tls:
|
||||
- hosts:
|
||||
- {{ include "aiproxy.fullname" . }}.{{.Values.cloudDomain}}
|
||||
secretName: wildcard-cert
|
||||
@@ -0,0 +1,28 @@
|
||||
fullnameOverride: aiproxy-web
|
||||
|
||||
replicas: 2
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 50Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
|
||||
image: ghcr.io/labring/sealos-aiproxy-frontend:latest
|
||||
|
||||
cloudDomain: 127.0.0.1.nip.io
|
||||
cloudPort: 443
|
||||
|
||||
suffix:
|
||||
|
||||
aiproxy:
|
||||
AI_PROXY_BACKEND_KEY: ""
|
||||
APP_TOKEN_JWT_KEY: ""
|
||||
AI_PROXY_BACKEND_INTERNAL: "http://aiproxy.apiproxy-system.svc:3000"
|
||||
ADMIN_NAMESPACES: "ns-admin"
|
||||
ACCOUNT_SERVER_TOKEN_JWT_KEY: ""
|
||||
CURRENCY_SYMBOL: ""
|
||||
ACCOUNT_SERVER: "http://account-service.account-system.svc:2333"
|
||||
IS_INVITATION_ACTIVE: "false"
|
||||
DOC_URL: "https://sealos.run/docs/guides/ai-proxy"
|
||||
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
timestamp() {
|
||||
date +"%Y-%m-%d %T"
|
||||
}
|
||||
print() {
|
||||
flag=$(timestamp)
|
||||
echo -e "\033[1;32m\033[1m INFO [$flag] >> $* \033[0m"
|
||||
}
|
||||
warn() {
|
||||
flag=$(timestamp)
|
||||
echo -e "\033[33m WARN [$flag] >> $* \033[0m"
|
||||
}
|
||||
info() {
|
||||
flag=$(timestamp)
|
||||
echo -e "\033[36m INFO [$flag] >> $* \033[0m"
|
||||
}
|
||||
#===========================================================================
|
||||
HELM_OPTS=${HELM_OPTS:-""}
|
||||
|
||||
NODE_COUNT=$(kubectl get nodes --no-headers | wc -l)
|
||||
REPLICA_OPTIONS=""
|
||||
if [ "$NODE_COUNT" -eq 1 ]; then
|
||||
REPLICA_OPTIONS="--set replicas=1 "
|
||||
HELM_OPTS="${HELM_OPTS} ${REPLICA_OPTIONS}"
|
||||
fi
|
||||
|
||||
|
||||
varJwtInternal=$(kubectl get configmap sealos-config -n sealos-system -o jsonpath='{.data.jwtInternal}')
|
||||
adminKey=$(kubectl get configmap aiproxy-env -n aiproxy-system -o jsonpath='{.data.ADMIN_KEY}' )
|
||||
SEALOS_CLOUD_DOMAIN=$(kubectl get configmap sealos-config -n sealos-system -o jsonpath='{.data.cloudDomain}')
|
||||
SEALOS_CLOUD_PORT=$(kubectl get configmap sealos-config -n sealos-system -o jsonpath='{.data.cloudPort}')
|
||||
CURRENCY_SYMBOL=$(kubectl get deployment -n dbprovider-frontend dbprovider-frontend -o jsonpath='{.spec.template.spec.containers[0].env[?(@.name=="CURRENCY_SYMBOL")].value}')
|
||||
if [[ "${CURRENCY_SYMBOL}" == "usd" ]]; then
|
||||
SUFFIX="/en/home"
|
||||
fi
|
||||
|
||||
helm upgrade -i aiproxy-web -n aiproxy-system charts/aiproxy ${HELM_OPTS} \
|
||||
--set aiproxy.APP_TOKEN_JWT_KEY=${varJwtInternal} --set aiproxy.AI_PROXY_BACKEND_KEY=${adminKey} \
|
||||
--set suffix=${SUFFIX} \
|
||||
--set cloudDomain=${SEALOS_CLOUD_DOMAIN} --set cloudPort=${SEALOS_CLOUD_PORT} --set aiproxy.CURRENCY_SYMBOL=${CURRENCY_SYMBOL} --create-namespace
|
||||
Reference in New Issue
Block a user