Skip to content
Open
Show file tree
Hide file tree
Changes from 5 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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

All notable changes to this project will be documented in this file.

## [0.3.0] - to be released
- Support for memos version 0.30.0
- Add HTTPRoute support
- Support Deployment-Managed Configuration

## [0.2.1] - 2025-12-07

### Fixed
Expand Down
4 changes: 2 additions & 2 deletions Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ 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.2.1
version: 0.3.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: "0.25.2"
appVersion: "0.30.0"
home: https://github.com/usememos/helm
sources:
- https://github.com/usememos/memos
Expand Down
84 changes: 84 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,90 @@ when `enabled` is `false` use `emptyDir`,
1. If has created `pvc`, Please change `enabled` to `true`, and change`existPersistClaim`to your `pvc` name.
2. If `enabled` is `true` but `existPersistClaim` is empty,if will create a new `pvc` by `accessMode` `storageClass` `size`

## Database

Edit `values.yaml`

~~~yaml
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
database:
driver: postgres
existingSecret:
name: memos-cluster-app
key: fqdn-uri
~~~

[Databases](https://usememos.com/docs/configuration/database) configuration can be done with an existing secret (recommended) or by a `database.connectionString`.

## Application Configuration

Edit `values.yaml`

~~~yaml
settings:
enabled: true
general:
{
"key": "GENERAL",
"generalSetting":
{
"disallowUserRegistration": false,
"disallowPasswordAuth": false,
"additionalScript": "",
"additionalStyle": "",
"weekStartDayOffset": 1,
"disallowChangeUsername": false,
"disallowChangeNickname": false,
},
}
~~~

when `enabled` is `true` the [configuration](https://usememos.com/docs/configuration/deployment-configuration) is generated in `/etc/secrets`.

All configuration resources are supported.

~~~yaml
settings:
enabled: false
general: {}
idps: []
storage: {}
memo: {}
notification: {}
ai: {}
~~~

For OAuth2 identity provider use for example:

~~~yaml
settings:
enabled: true
idps:
- name: primary-sso
config:
{
"uid": "primary-sso",
"name": "Company SSO",
"type": "OAUTH2",
"identifierFilter": "",
"config": {
"oauth2Config": {
"clientId": "client-id",
"clientSecret": "client-secret",
"authUrl": "https://idp.example.com/oauth/authorize",
"tokenUrl": "https://idp.example.com/oauth/token",
"userInfoUrl": "https://idp.example.com/oauth/userinfo",
"scopes": ["openid", "profile", "email"],
"fieldMapping": {
"identifier": "sub",
"displayName": "name",
"email": "email",
"avatarUrl": "picture"
}
}
}
}
~~~

## Security

The chart includes secure defaults:
Expand Down
15 changes: 14 additions & 1 deletion templates/NOTES.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- if .Values.httpRoute.enabled }}
{{- if .Values.httpRoute.hostnames }}
export APP_HOSTNAME={{ .Values.httpRoute.hostnames | first }}
{{- else }}
export APP_HOSTNAME=$(kubectl get --namespace {{(first .Values.httpRoute.parentRefs).namespace | default .Release.Namespace }} gateway/{{ (first .Values.httpRoute.parentRefs).name }} -o jsonpath="{.spec.listeners[0].hostname}")
{{- end }}
{{- if and .Values.httpRoute.rules (first .Values.httpRoute.rules).matches (first (first .Values.httpRoute.rules).matches).path.value }}
echo "Visit https://$APP_HOSTNAME{{ (first (first .Values.httpRoute.rules).matches).path.value }} to use your application"

NOTE: Your HTTPRoute depends on the listener configuration of your gateway and your HTTPRoute rules.
The rules can be set for path, method, header and query parameters.
You can check the gateway configuration with 'kubectl get --namespace {{(first .Values.httpRoute.parentRefs).namespace | default .Release.Namespace }} gateway/{{ (first .Values.httpRoute.parentRefs).name }} -o yaml'
{{- end }}
Comment thread
RobSlgm marked this conversation as resolved.
{{- else if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
Expand Down
34 changes: 32 additions & 2 deletions templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ spec:
{{- include "memos.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
checksum/settings: {{ include (print $.Template.BasePath "/settings.yaml") . | sha256sum }}
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
Expand All @@ -35,7 +36,12 @@ spec:
claimName: {{ .Values.persistence.existPersistClaim | default (include "memos.fullname" .) }}
{{- else }}
emptyDir: { }
{{ end }}
{{- end }}
{{- if .Values.settings.enabled }}
- name: settings
configMap:
name: {{ include "memos.fullname" . }}
{{- end }}
containers:
- name: {{ .Chart.Name }}
securityContext:
Expand All @@ -57,10 +63,34 @@ spec:
volumeMounts:
- name: memos-data
mountPath: /var/opt/memos
{{- if .Values.settings.enabled }}
- name: settings
mountPath: /etc/secrets
readOnly: true
{{- end }}
# avoid * cannot parse 'Port' as int: strconv.ParseInt: parsing "tcp://10.233.40.219:5230": invalid syntax
env:
- name: MEMOS_PORT
value: "{{ .Values.service.port }}"
- name: MEMOS_LOG_LEVEL
value: {{ .Values.instance.logLevel | quote }}
- name: MEMOS_DRIVER
value: {{ .Values.database.driver | quote }}
{{- if .Values.database.connectionString }}
- name: MEMOS_DSN
value: {{ .Values.database.connectionString }}
{{- end }}
{{- if .Values.database.existingSecret }}
- name: MEMOS_DSN
valueFrom:
secretKeyRef:
name: {{ .Values.database.existingSecret.name }}
key: {{ .Values.database.existingSecret.key }}
{{- end }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

According to the current Kubernetes API documentation, what is the behavior when a container env list contains multiple EnvVar entries with the same name?

💡 Result:

According to the Kubernetes API documentation and established behavior, when a container's environment variable list (env) contains multiple entries with the same name, the values defined in the env list take precedence over values defined in envFrom [1][2][3]. While Kubernetes allows these duplicates to be persisted, they are generally discouraged [4][5]. The behavior associated with duplicate env entries is as follows: 1. Precedence: Values defined explicitly in the env list take precedence over those defined via envFrom [1][2][3]. 2. Patching and Updates: The presence of duplicate names in the env list can cause significant issues with kubectl apply and other patching mechanisms [4][5]. Because the env list uses the name field as a merge key, these tools often treat the key as ambiguous [5]. Consequently, attempting to update or remove one duplicate entry can result in all entries with that name being deleted or cause patch errors [4][5][6][7]. 3. Validation: Historically, Kubernetes has not strictly enforced uniqueness for the name field within the env list at the API level, allowing such configurations to be created and run [7]. However, it is strongly recommended to avoid duplicate names to prevent unexpected application behavior and operational issues with tooling [4][5]. Users are advised to maintain unique names for all environment variables within a container's configuration [4][5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate deployment.yaml and values docs =="
fd -a 'deployment.yaml|README|values\.yaml|\.yaml$' . | sed 's#^\./##' | head -200

echo
echo "== templates/deployment.yaml relevant section =="
if [ -f templates/deployment.yaml ]; then
  nl -ba templates/deployment.yaml | sed -n '60,105p'
else
  fd -a 'deployment.yaml' .
fi

echo
echo "== search MEMOS_DSN and database values doc =="
rg -n "MEMOS_DSN|database:|existingSecret|connectionString|existingSecret:" -S .

Repository: usememos/helm

Length of output: 774


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== templates/deployment.yaml relevant section =="
sed -n '60,105p' templates/deployment.yaml

echo
echo "== search MEMOS_DSN and database values doc =="
rg -n "MEMOS_DSN|database:|existingSecret|connectionString|existingSecret:" -S .

echo
echo "== values.yaml database section =="
sed -n '1,160p' values.yaml

Repository: usememos/helm

Length of output: 5939


Make MEMOS_DSN inputs mutually exclusive.

values.yaml and README.md present database.connectionString and database.existingSecret as an either-or choice. If both are set, this template emits two MEMOS_DSN env entries; the connectionString value will take precedence over the secretKeyRef, but Kubernetes still keeps both entries and can make later kubectl apply updates ambiguous. Fail when both are nonempty, or replace the second block with else if so connectionString takes precedence and document that precedence.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@templates/deployment.yaml` around lines 79 - 89, The deployment template
currently renders duplicate MEMOS_DSN entries when both
database.connectionString and database.existingSecret are configured. Make these
inputs mutually exclusive by changing the conditional flow around
database.connectionString and database.existingSecret, preferably failing
template rendering when both are nonempty; otherwise use an else-if structure
and document the connectionString precedence in the existing configuration
documentation.

{{- if .Values.instance.url }}
- name: MEMOS_INSTANCE_URL
value: {{ .Values.instance.url }}
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.nodeSelector }}
Expand Down
38 changes: 38 additions & 0 deletions templates/httproute.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{{- if .Values.httpRoute.enabled -}}
{{- $fullName := include "memos.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: {{ $fullName }}
labels:
{{- include "memos.labels" . | nindent 4 }}
{{- with .Values.httpRoute.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
parentRefs:
{{- with .Values.httpRoute.parentRefs }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.httpRoute.hostnames }}
hostnames:
{{- toYaml . | nindent 4 }}
{{- end }}
rules:
{{- range .Values.httpRoute.rules }}
{{- with .matches }}
- matches:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .filters }}
filters:
{{- toYaml . | nindent 8 }}
{{- end }}
backendRefs:
- name: {{ $fullName }}
port: {{ $svcPort }}
weight: 1
{{- end }}
Comment thread
RobSlgm marked this conversation as resolved.
{{- end }}
35 changes: 35 additions & 0 deletions templates/settings.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{{- if .Values.settings.enabled -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "memos.fullname" . }}
labels:
{{- include "memos.labels" . | nindent 4 }}
data:
{{- if .Values.settings.general }}
memos-instance-setting-general.json: >
{{- .Values.settings.general | toJson | nindent 4 }}
{{- end }}
{{- if .Values.settings.idps }}
{{- range $idp := .Values.settings.idps }}
memos-idp-{{- $idp.name -}}.json: >
{{- $idp.config | toJson | nindent 4 }}
{{- end }}
{{- end }}
{{- if .Values.settings.storage }}
memos-instance-setting-storage.json: >
{{- .Values.settings.storage | toJson | nindent 4 }}
{{- end }}
{{- if .Values.settings.memo }}
memos-instance-setting-memo-related.json: >
{{- .Values.settings.memo | toJson | nindent 4 }}
{{- end }}
{{- if .Values.settings.notification }}
memos-instance-setting-notification.json: >
{{- .Values.settings.notification | toJson | nindent 4 }}
{{- end }}
{{- if .Values.settings.ai }}
memos-instance-setting-ai.json: >
{{- .Values.settings.ai | toJson | nindent 4 }}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
{{- end }}
{{- end }}
57 changes: 56 additions & 1 deletion values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ image:
imageName: usememos/memos
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: "latest"
tag: ""

imagePullSecrets: []
nameOverride: ""
Expand All @@ -24,6 +24,30 @@ persistence:
accessMode: ReadWriteOnce
size: 10Gi

instance:
# Public instance URL, e.g. https://memos.example.com; empty enables private
url: ""
# Log verbosity (debug, info, warn, error)
logLevel: "info"

database:
# sqlite, mysql, postgres
driver: sqlite
# define database connection string or use an existing secret (recommended)
connectionString: ""
# existingSecret:
# name:
# key:

settings:
enabled: false
general: {}
idps: []
storage: {}
memo: {}
notification: {}
ai: {}

serviceAccount:
# Specifies whether a service account should be created
create: true
Expand Down Expand Up @@ -71,6 +95,37 @@ ingress:
# hosts:
# - chart-example.local

httpRoute:
enabled: false
annotations: {}
parentRefs:
- name: gateway
sectionName: http
# namespace: default
# hostnames:
# - chart-example.local
rules:
- matches:
- path:
type: PathPrefix
value: /
# filters:
# - type: RequestHeaderModifier
# requestHeaderModifier:
# set:
# - name: My-Overwrite-Header
# value: this-is-the-only-value
# remove:
# - User-Agent
# - matches:
# - path:
# type: PathPrefix
# value: /echo
# headers:
# - name: version
# value: v2


resources:
limits:
cpu: 500m
Expand Down