Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#171 - Allow setting up read only replicas #174

Merged
merged 24 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
329ec14
split LDAP_EXTRA_SCHEMAS from main configmap
davidfrickert Jun 20, 2024
e31a2a0
support creating a read only replica statefulset
davidfrickert Jun 20, 2024
a790f75
separate values for read only services from normal service
davidfrickert Jun 21, 2024
389e1cf
splitenable ldap port values
davidfrickert Jun 21, 2024
95f06a7
WIP: Write test that verifies readonly replica
davidfrickert Jun 24, 2024
d0dc984
Code review fixes
davidfrickert Jun 24, 2024
44c8ae9
ci - call readonly job
davidfrickert Jun 25, 2024
26156ba
need to load custom ldif for test to work as expected
davidfrickert Jun 25, 2024
2a410cd
use 0 read only replicas as the default
davidfrickert Jun 25, 2024
9740e50
add kind ports for read only ldap tests
davidfrickert Jun 25, 2024
4fe875e
changes in replication to support readonly replica
davidfrickert Jun 26, 2024
685cba1
CI readonly test fix
davidfrickert Jun 26, 2024
a8f0e11
save current readlonly strategy
jp-gouin Jul 18, 2024
b3c79d4
commit some changes that were uncommitted for readonly functionality
davidfrickert Sep 3, 2024
d1c380c
add read-only replica
jp-gouin Sep 27, 2024
f3fa7ea
add read-only replica
jp-gouin Sep 27, 2024
0ba2528
merge helper
jp-gouin Sep 27, 2024
baee6c9
merge helper
jp-gouin Sep 27, 2024
8567aaf
fix ci
jp-gouin Sep 27, 2024
7bb4a28
fix load of schema
jp-gouin Oct 1, 2024
cff4c66
fix mount custom schema
jp-gouin Oct 2, 2024
ae47cb4
allow read only to load custom schema during startup
jp-gouin Oct 3, 2024
02187ad
resolve conflicts
jp-gouin Oct 9, 2024
3f666e5
Merge branch 'master' into feat/add-readonly-replicas
jp-gouin Oct 9, 2024
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
30 changes: 30 additions & 0 deletions .bin/readonly.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
persistence:
accessModes:
- ReadWriteOnce
enabled: true
size: 1Gi
ltb-passwd:
enabled : false
phpldapadmin:
enabled: false
replicaCount: 3
readOnlyReplicaCount: 1
replication:
clusterName: cluster.local
enabled: true
interval: "00:00:00:10"
retry: 60
starttls: critical
timeout: 1
tls_reqcert: never
initTLSSecret:
tls_enabled: true
secret: "custom-cert"
service:
ldapPortNodePort: 30389
sslLdapPortNodePort: 30636
type: NodePort
serviceReadOnly:
ldapPortNodePort: 31389
Copy link
Owner

Choose a reason for hiding this comment

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

You need to update .bin/kind-conf.yml to include the 2 new ports :

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
  kubeadmConfigPatches:
  - |
    kind: JoinConfiguration
    nodeRegistration:
      kubeletExtraArgs:
        node-labels: "ingress-ready=true"
  extraPortMappings:
  - containerPort: 80
    hostPort: 8080
    protocol: TCP
  - containerPort: 443
    hostPort: 8444
    protocol: TCP
  - containerPort: 30636
    hostPort: 30636
  - containerPort: 30389
    hostPort: 30389
  - containerPort: 31389
    hostPort: 31389
  - containerPort: 31636
    hostPort: 31636
- role: worker
- role: worker

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ah, thanks for the tip

sslLdapPortNodePort: 31636
type: NodePort
58 changes: 58 additions & 0 deletions .github/workflows/ci-readonly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# WIP!
name: Test readonly replica
on:
workflow_call:
jobs:
qualif:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v1
- name: Run custom action
# Use the location in the repository (without action.yml)
uses: ./.github/actions/setup
with:
install-chaos: false
- name: setup certs
shell: bash
run: |
openssl req -x509 -newkey rsa:4096 -nodes -subj '/CN=example.com' -keyout tls.key -out tls.crt -days 365
cp tls.crt ca.crt
kubectl create secret generic custom-cert --from-file=./tls.crt --from-file=./tls.key --from-file=./ca.crt
- name: deploy openldap-stack-ha
shell: bash
run: |
cd "$GITHUB_WORKSPACE"
helm install openldap-stack-ha -f .bin/readonly.yaml .
kubectl rollout status sts openldap-stack-ha
- name: verify deployment
shell: bash
run: |
echo "test access to openldap database"
sleep 10
LDAPTLS_REQCERT=never ldapsearch -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:30636 -b 'dc=example,dc=org'
- name: verify certs
shell: bash
run: |
echo "verify certificate"
echo | openssl s_client -showcerts -servername example.com -connect localhost:30636 2>/dev/null | openssl x509 -inform pem -noout -text > /tmp/test-cert.txt
if ! grep -q "CN = example.com" /tmp/test-cert.txt; then echo exit 1; fi
- name: test write on main cluster
shell: bash
run: |
echo "Write test to openldap database"
LDAPTLS_REQCERT=never ldapadd -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:30636 -f .bin/user.ldif
LDAPTLS_REQCERT=never ldapsearch -o nettimeout=20 -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:30636 -b 'dc=example,dc=org' > /tmp/test-write.txt
if ! grep "Einstein" /tmp/test-write.txt; then echo 'no Einstein entry found' ; fi
if ! grep "objectClass: ownCloud" /tmp/test-write.txt; then echo 'no ownCloud entry found'; fi
- name: test memberOf on main cluster
shell: bash
run: |
echo "MemberOf test to openldap database"
LDAPTLS_REQCERT=never ldapsearch -o nettimeout=20 -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:30636 -b 'dc=example,dc=org' "(memberOf=cn=testgroup,ou=Group,dc=example,dc=org)" > /tmp/test-write.txt
if [ $(grep "numResponses" /tmp/test-write.txt | cut -d ":" -f 2 | tr -d ' ') -ne 2 ]; then exit 1 ; fi
if ! grep -q "uid=test1,ou=People,dc=example,dc=org" /tmp/test-write.txt; then echo exit 1; fi
- name: test write on readonly replica
run: |
echo "Write test to openldap readonly replica"
LDAPTLS_REQCERT=never ldapadd -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:31636 -f .bin/user.ldif
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ jobs:
call-ci-other:
uses: ./.github/workflows/ci-other.yml
call-ci-ha:
uses: ./.github/workflows/ci-ha.yml
uses: ./.github/workflows/ci-ha.yml
call-ci-readonly:
uses: ./.github/workflows/ci-readonly.yml
28 changes: 28 additions & 0 deletions templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ Generate olcServerID list
{{- $index1 := $index0 | add1 }}
olcServerID: {{ $index1 }} ldap://{{ $name }}-{{ $index0 }}.{{ $name }}-headless.{{ $namespace }}.svc.{{ $cluster }}:1389
{{- end -}}
{{- $readonlyNodeCount := .Values.readOnlyReplicaCount | int }}
{{- range $index0 := until $readonlyNodeCount }}
{{- $index1 := $index0 | add $nodeCount | add 1 }}
olcServerID: {{ $index1 }} ldap://{{ $name }}-readonly-{{ $index0 }}.{{ $name }}-headless-readonly.{{ $namespace }}.svc.{{ $cluster }}:1389
{{- end -}}
{{- end -}}

{{/*
Expand All @@ -81,6 +86,11 @@ Generate olcSyncRepl list
{{- $index1 := $index0 | add1 }}
olcSyncRepl: rid=00{{ $index1 }} provider=ldap://{{ $name }}-{{ $index0 }}.{{ $name }}-headless.{{ $namespace }}.svc.{{ $cluster }}:1389 binddn="cn={{ $bindDNUser }},cn=config" bindmethod=simple credentials={{ $configPassword }} searchbase="cn=config" type=refreshAndPersist retry="{{ $retry }} +" timeout={{ $timeout }} starttls={{ $starttls }} tls_reqcert={{ $tls_reqcert }}
{{- end -}}
{{- $readonlyNodeCount := .Values.readOnlyReplicaCount | int }}
{{- range $index0 := until $readonlyNodeCount }}
{{- $index1 := $index0 | add $nodeCount | add 1 }}
olcSyncRepl: rid=00{{ $index1 }} provider=ldap://{{ $name }}-readonly-{{ $index0 }}.{{ $name }}-headless-readonly.{{ $namespace }}.svc.{{ $cluster }}:1389 binddn="cn={{ $bindDNUser }},cn=config" bindmethod=simple credentials={{ $configPassword }} searchbase="cn=config" type=refreshAndPersist retry="{{ $retry }} +" timeout={{ $timeout }} starttls={{ $starttls }} tls_reqcert={{ $tls_reqcert }}
{{- end -}}
{{- end -}}

{{/*
Expand All @@ -99,6 +109,7 @@ Generate olcSyncRepl list
{{- $tls_reqcert := .Values.replication.tls_reqcert }}
{{- $interval := .Values.replication.interval }}
{{- $nodeCount := .Values.replicaCount | int }}
{{- $readonlyNodeCount := .Values.readOnlyReplicaCount | int }}
{{- range $index0 := until $nodeCount }}
{{- $index1 := $index0 | add1 }}
olcSyncrepl:
Expand All @@ -116,6 +127,23 @@ Generate olcSyncRepl list
starttls={{ $starttls }}
tls_reqcert={{ $tls_reqcert }}
{{- end -}}
{{- range $index0 := until $readonlyNodeCount }}
{{- $index1 := $index0 | add $nodeCount | add 1 }}
olcSyncrepl:
rid=10{{ $index1 }}
provider=ldap://{{ $name }}-readonly-{{ $index0 }}.{{ $name }}-headless-readonly.{{ $namespace }}.svc.{{ $cluster }}:1389
binddn={{ printf "cn=%s,%s" $bindDNUser $domain }}
bindmethod=simple
credentials={{ $adminPassword }}
searchbase={{ $domain }}
type=refreshAndPersist
interval={{ $interval }}
network-timeout=0
retry="{{ $retry }} +"
timeout={{ $timeout }}
starttls={{ $starttls }}
tls_reqcert={{ $tls_reqcert }}
{{- end -}}
{{- end -}}

{{/*
Expand Down
1 change: 0 additions & 1 deletion templates/configmap-env.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ metadata:
{{- end }}
data:
LDAP_ROOT: {{ include "global.baseDomain" . }}
LDAP_EXTRA_SCHEMAS: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" .) }}
{{- if .Values.users }}
LDAP_USERS: {{ .Values.users }}
{{- end }}
Expand Down
19 changes: 19 additions & 0 deletions templates/configmap-readonly.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{{- if (gt (.Values.readOnlyReplicaCount | int) 0) }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "openldap.fullname" . }}-readonly
labels:
app: {{ template "openldap.name" . }}
chart: {{ template "openldap.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
{{- if .Values.extraLabels }}
{{ toYaml .Values.extraLabels | indent 4 }}
{{- end }}
data:
# replication
readonly.ldif: |
dn: olcDatabase={2}mdb,cn=config
olcReadonly: TRUE
{{- end }}
57 changes: 57 additions & 0 deletions templates/service-readonly.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{{- if (gt (.Values.readOnlyReplicaCount | int) 0) }}
apiVersion: v1
kind: Service
metadata:
{{- if .Values.serviceReadOnly.annotations }}
annotations:
{{ toYaml .Values.serviceReadOnly.annotations | indent 4 }}
{{- end }}
name: {{ template "openldap.fullname" . }}-readonly
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/component: {{ template "openldap.fullname" . }}
chart: {{ template "openldap.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
{{- if .Values.extraLabels }}
{{ toYaml .Values.extraLabels | indent 4 }}
{{- end }}
spec:
type: {{ .Values.serviceReadOnly.type }}
{{- if and (eq .Values.serviceReadOnly.type "LoadBalancer") .Values.serviceReadOnly.loadBalancerIP }}
loadBalancerIP: {{ .Values.serviceReadOnly.loadBalancerIP }}
{{- end }}
{{- if and (eq .Values.serviceReadOnly.type "LoadBalancer") .Values.serviceReadOnly.loadBalancerSourceRanges }}
loadBalancerSourceRanges: {{ toYaml .Values.serviceReadOnly.loadBalancerSourceRanges | nindent 4 }}
{{- end }}
{{- if and (eq .Values.serviceReadOnly.type "ClusterIP") .Values.serviceReadOnly.clusterIP }}
clusterIP: {{ .Values.serviceReadOnly.clusterIP }}
{{- end }}
ports:
{{- if .Values.serviceReadOnly.enableLdapPort }}
- name: ldap-port
protocol: TCP
port: {{ .Values.global.ldapPort }}
targetPort: ldap-port
{{- if and (or (eq .Values.serviceReadOnly.type "NodePort") (eq .Values.serviceReadOnly.type "LoadBalancer")) (not (empty .Values.serviceReadOnly.ldapPortNodePort)) }}
nodePort: {{ .Values.serviceReadOnly.ldapPortNodePort }}
{{- else if eq .Values.serviceReadOnly.type "ClusterIP" }}
nodePort: null
{{- end }}
{{- end }}
{{- if .Values.serviceReadOnly.enableSslLdapPort }}
- name: ssl-ldap-port
protocol: TCP
port: {{ .Values.global.sslLdapPort }}
targetPort: ssl-ldap-port
{{- if and (or (eq .Values.serviceReadOnly.type "NodePort") (eq .Values.serviceReadOnly.type "LoadBalancer")) (not (empty .Values.serviceReadOnly.sslLdapPortNodePort)) }}
nodePort: {{ .Values.serviceReadOnly.sslLdapPortNodePort }}
{{- else if eq .Values.serviceReadOnly.type "ClusterIP" }}
nodePort: null
{{- end }}
{{- end }}
sessionAffinity: {{ .Values.service.sessionAffinity }}
selector:
app.kubernetes.io/component: {{ template "openldap.fullname" . }}-readonly
release: {{ .Release.Name }}
{{- end }}
Loading
Loading