Skip to content

Commit 3b385c5

Browse files
egeguneshors
andauthored
K8SPSMDB-733: Automate volume scaling (#1487)
* K8SPSMDB-733: Automate volume scaling * add test * address review comments * fix tests --------- Co-authored-by: Viacheslav Sarzhan <slava.sarzhan@percona.com>
1 parent 04dc2f3 commit 3b385c5

File tree

8 files changed

+537
-43
lines changed

8 files changed

+537
-43
lines changed
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
apiVersion: apps/v1
2+
kind: StatefulSet
3+
metadata:
4+
annotations: {}
5+
generation: 1
6+
labels:
7+
app.kubernetes.io/component: mongod
8+
app.kubernetes.io/instance: some-name
9+
app.kubernetes.io/managed-by: percona-server-mongodb-operator
10+
app.kubernetes.io/name: percona-server-mongodb
11+
app.kubernetes.io/part-of: percona-server-mongodb
12+
app.kubernetes.io/replset: rs0
13+
name: some-name-rs0
14+
ownerReferences:
15+
- controller: true
16+
kind: PerconaServerMongoDB
17+
name: some-name
18+
spec:
19+
podManagementPolicy: OrderedReady
20+
replicas: 3
21+
revisionHistoryLimit: 10
22+
selector:
23+
matchLabels:
24+
app.kubernetes.io/component: mongod
25+
app.kubernetes.io/instance: some-name
26+
app.kubernetes.io/managed-by: percona-server-mongodb-operator
27+
app.kubernetes.io/name: percona-server-mongodb
28+
app.kubernetes.io/part-of: percona-server-mongodb
29+
app.kubernetes.io/replset: rs0
30+
serviceName: some-name-rs0
31+
template:
32+
metadata:
33+
annotations: {}
34+
labels:
35+
app.kubernetes.io/component: mongod
36+
app.kubernetes.io/instance: some-name
37+
app.kubernetes.io/managed-by: percona-server-mongodb-operator
38+
app.kubernetes.io/name: percona-server-mongodb
39+
app.kubernetes.io/part-of: percona-server-mongodb
40+
app.kubernetes.io/replset: rs0
41+
spec:
42+
containers:
43+
- args:
44+
- --bind_ip_all
45+
- --auth
46+
- --dbpath=/data/db
47+
- --port=27017
48+
- --replSet=rs0
49+
- --storageEngine=wiredTiger
50+
- --relaxPermChecks
51+
- --sslAllowInvalidCertificates
52+
- --clusterAuthMode=x509
53+
- --enableEncryption
54+
- --encryptionKeyFile=/etc/mongodb-encryption/encryption-key
55+
- --wiredTigerCacheSizeGB=0.25
56+
- --wiredTigerIndexPrefixCompression=true
57+
- --config=/etc/mongodb-config/mongod.conf
58+
- --quiet
59+
command:
60+
- /opt/percona/ps-entry.sh
61+
env:
62+
- name: SERVICE_NAME
63+
value: some-name
64+
- name: MONGODB_PORT
65+
value: "27017"
66+
- name: MONGODB_REPLSET
67+
value: rs0
68+
envFrom:
69+
- secretRef:
70+
name: internal-some-name-users
71+
optional: false
72+
imagePullPolicy: Always
73+
livenessProbe:
74+
exec:
75+
command:
76+
- /opt/percona/mongodb-healthcheck
77+
- k8s
78+
- liveness
79+
- --ssl
80+
- --sslInsecure
81+
- --sslCAFile
82+
- /etc/mongodb-ssl/ca.crt
83+
- --sslPEMKeyFile
84+
- /tmp/tls.pem
85+
- --startupDelaySeconds
86+
- "7200"
87+
failureThreshold: 4
88+
initialDelaySeconds: 60
89+
periodSeconds: 30
90+
successThreshold: 1
91+
timeoutSeconds: 10
92+
name: mongod
93+
ports:
94+
- containerPort: 27017
95+
name: mongodb
96+
protocol: TCP
97+
readinessProbe:
98+
exec:
99+
command:
100+
- /opt/percona/mongodb-healthcheck
101+
- k8s
102+
- readiness
103+
- --component
104+
- mongod
105+
failureThreshold: 8
106+
initialDelaySeconds: 10
107+
periodSeconds: 3
108+
successThreshold: 1
109+
timeoutSeconds: 2
110+
resources:
111+
limits:
112+
cpu: 500m
113+
memory: 500M
114+
requests:
115+
cpu: 100m
116+
memory: 100M
117+
securityContext:
118+
runAsNonRoot: true
119+
runAsUser: 1001
120+
terminationMessagePath: /dev/termination-log
121+
terminationMessagePolicy: File
122+
volumeMounts:
123+
- mountPath: /data/db
124+
name: mongod-data
125+
- mountPath: /etc/mongodb-secrets
126+
name: some-name-mongodb-keyfile
127+
readOnly: true
128+
- mountPath: /etc/mongodb-ssl
129+
name: ssl
130+
readOnly: true
131+
- mountPath: /etc/mongodb-ssl-internal
132+
name: ssl-internal
133+
readOnly: true
134+
- mountPath: /etc/mongodb-config
135+
name: config
136+
- mountPath: /opt/percona
137+
name: bin
138+
- mountPath: /etc/mongodb-encryption
139+
name: some-name-mongodb-encryption-key
140+
readOnly: true
141+
- mountPath: /etc/users-secret
142+
name: users-secret-file
143+
workingDir: /data/db
144+
dnsPolicy: ClusterFirst
145+
initContainers:
146+
- command:
147+
- /init-entrypoint.sh
148+
imagePullPolicy: Always
149+
name: mongo-init
150+
resources:
151+
limits:
152+
cpu: 500m
153+
memory: 500M
154+
requests:
155+
cpu: 100m
156+
memory: 100M
157+
terminationMessagePath: /dev/termination-log
158+
terminationMessagePolicy: File
159+
volumeMounts:
160+
- mountPath: /data/db
161+
name: mongod-data
162+
- mountPath: /opt/percona
163+
name: bin
164+
restartPolicy: Always
165+
schedulerName: default-scheduler
166+
securityContext:
167+
fsGroup: 1001
168+
serviceAccount: default
169+
serviceAccountName: default
170+
terminationGracePeriodSeconds: 60
171+
volumes:
172+
- name: some-name-mongodb-keyfile
173+
secret:
174+
defaultMode: 288
175+
optional: false
176+
secretName: some-name-mongodb-keyfile
177+
- emptyDir: {}
178+
name: bin
179+
- configMap:
180+
defaultMode: 420
181+
name: some-name-rs0-mongod
182+
optional: true
183+
name: config
184+
- name: some-name-mongodb-encryption-key
185+
secret:
186+
defaultMode: 288
187+
optional: false
188+
secretName: some-name-mongodb-encryption-key
189+
- name: ssl
190+
secret:
191+
defaultMode: 288
192+
optional: false
193+
secretName: some-name-ssl
194+
- name: ssl-internal
195+
secret:
196+
defaultMode: 288
197+
optional: true
198+
secretName: some-name-ssl-internal
199+
- name: users-secret-file
200+
secret:
201+
defaultMode: 420
202+
secretName: internal-some-name-users
203+
updateStrategy:
204+
rollingUpdate:
205+
partition: 0
206+
type: RollingUpdate
207+
volumeClaimTemplates:
208+
- metadata:
209+
name: mongod-data
210+
spec:
211+
accessModes:
212+
- ReadWriteOnce
213+
resources:
214+
requests:
215+
storage: 1Gi
216+
status:
217+
phase: Pending

e2e-tests/pvc-resize/run

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/bin/bash
2+
3+
set -o errexit
4+
5+
test_dir=$(realpath $(dirname $0))
6+
. ${test_dir}/../functions
7+
8+
set_debug
9+
10+
if [[ $EKS == 1 ]]; then
11+
echo "Skip the test. We don't run it for EKS."
12+
exit 0
13+
fi
14+
15+
create_infra ${namespace}
16+
17+
desc 'create secrets and psmdb client'
18+
kubectl_bin apply \
19+
-f $conf_dir/secrets.yml \
20+
-f $conf_dir/client.yml
21+
22+
desc 'create PSMDB cluster'
23+
cluster="some-name"
24+
spinup_psmdb "${cluster}-rs0" "$conf_dir/$cluster-rs0.yml"
25+
26+
kubectl_bin patch psmdb ${cluster} --type=json -p='[{"op": "replace", "path": "/spec/replsets/0/volumeSpec/persistentVolumeClaim/resources/requests/storage", "value":"5Gi"}]'
27+
wait_cluster_consistency "$cluster" 3 2
28+
29+
for pvc in $(kubectl_bin get pvc -l app.kubernetes.io/component=mongod -o name); do
30+
retry=0
31+
until [[ $(kubectl_bin get ${pvc} -o jsonpath={.status.capacity.storage}) == "5Gi" ]]; do
32+
if [[ $retry -ge 60 ]]; then
33+
echo "PVC ${pvc} was not resized, max retries exceeded"
34+
exit 1
35+
fi
36+
37+
echo "Waiting for PVC ${pvc} to be resized"
38+
sleep 5
39+
40+
retry=$((retry + 1))
41+
done
42+
echo "PVC ${pvc} was resized"
43+
done
44+
45+
destroy "${namespace}"
46+
desc "test passed"

e2e-tests/run-pr.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ operator-self-healing-chaos
2727
pitr
2828
pitr-sharded
2929
pitr-physical
30+
pvc-resize
3031
recover-no-primary
3132
rs-shard-migration
3233
scaling

e2e-tests/run-release.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ operator-self-healing-chaos
2828
pitr
2929
pitr-sharded
3030
pitr-physical
31+
pvc-resize
3132
recover-no-primary
3233
rs-shard-migration
3334
scaling

pkg/apis/psmdb/v1/psmdb_types.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1136,4 +1136,12 @@ func (cr *PerconaServerMongoDB) GetOrderedFinalizers() []string {
11361136
return orderedFinalizers
11371137
}
11381138

1139-
const AnnotationResyncPBM = "percona.com/resync-pbm"
1139+
const (
1140+
AnnotationResyncPBM = "percona.com/resync-pbm"
1141+
AnnotationPVCResizeInProgress = "percona.com/pvc-resize-in-progress"
1142+
)
1143+
1144+
func (cr *PerconaServerMongoDB) PVCResizeInProgress() bool {
1145+
_, ok := cr.Annotations[AnnotationPVCResizeInProgress]
1146+
return ok
1147+
}

pkg/controller/perconaservermongodb/statefulset.go

Lines changed: 4 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,9 @@ import (
55

66
api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1"
77
"github.com/percona/percona-server-mongodb-operator/pkg/psmdb"
8-
"github.com/percona/percona-server-mongodb-operator/pkg/util"
98
"github.com/pkg/errors"
109
appsv1 "k8s.io/api/apps/v1"
1110
corev1 "k8s.io/api/core/v1"
12-
"k8s.io/apimachinery/pkg/labels"
1311
"k8s.io/apimachinery/pkg/types"
1412
"sigs.k8s.io/controller-runtime/pkg/client"
1513
logf "sigs.k8s.io/controller-runtime/pkg/log"
@@ -49,6 +47,10 @@ func (r *ReconcilePerconaServerMongoDB) reconcileStatefulSet(ctx context.Context
4947
return sfs, nil
5048
}
5149

50+
if err := r.reconcilePVCs(ctx, cr, sfs, ls, volumeSpec.PersistentVolumeClaim); err != nil {
51+
return nil, errors.Wrapf(err, "reconcile PVCs for %s", sfs.Name)
52+
}
53+
5254
err = r.createOrUpdate(ctx, sfs)
5355
if err != nil {
5456
return nil, errors.Wrapf(err, "update StatefulSet %s", sfs.Name)
@@ -59,10 +61,6 @@ func (r *ReconcilePerconaServerMongoDB) reconcileStatefulSet(ctx context.Context
5961
return nil, errors.Wrapf(err, "PodDisruptionBudget for %s", sfs.Name)
6062
}
6163

62-
if err := r.reconcilePVCs(ctx, sfs, ls, volumeSpec.PersistentVolumeClaim); err != nil {
63-
return nil, errors.Wrapf(err, "reconcile PVCs for %s", sfs.Name)
64-
}
65-
6664
if err := r.smartUpdate(ctx, cr, sfs, rs); err != nil {
6765
return nil, errors.Wrap(err, "failed to run smartUpdate")
6866
}
@@ -126,39 +124,3 @@ func (r *ReconcilePerconaServerMongoDB) getStatefulsetFromReplset(ctx context.Co
126124

127125
return sfs, nil
128126
}
129-
130-
func (r *ReconcilePerconaServerMongoDB) reconcilePVCs(ctx context.Context, sts *appsv1.StatefulSet, ls map[string]string, pvcSpec api.PVCSpec) error {
131-
pvcList := &corev1.PersistentVolumeClaimList{}
132-
err := r.client.List(ctx, pvcList, &client.ListOptions{
133-
Namespace: sts.Namespace,
134-
LabelSelector: labels.SelectorFromSet(ls),
135-
})
136-
if err != nil {
137-
return errors.Wrap(err, "list PVCs")
138-
}
139-
140-
for _, pvc := range pvcList.Items {
141-
orig := pvc.DeepCopy()
142-
143-
for k, v := range pvcSpec.Labels {
144-
pvc.Labels[k] = v
145-
}
146-
for k, v := range sts.Labels {
147-
pvc.Labels[k] = v
148-
}
149-
for k, v := range pvcSpec.Annotations {
150-
pvc.Annotations[k] = v
151-
}
152-
153-
if util.MapEqual(orig.Labels, pvc.Labels) && util.MapEqual(orig.Annotations, pvc.Annotations) {
154-
continue
155-
}
156-
patch := client.MergeFrom(orig)
157-
158-
if err := r.client.Patch(ctx, &pvc, patch); err != nil {
159-
logf.FromContext(ctx).Error(err, "patch PVC", "PVC", pvc.Name)
160-
}
161-
}
162-
163-
return nil
164-
}

0 commit comments

Comments
 (0)