Skip to content

Commit 60e25e3

Browse files
committed
*: support juicefs #745
1 parent 41b6f3c commit 60e25e3

24 files changed

+926
-11
lines changed

Dockerfile.sidecar

+10-3
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,20 @@ RUN set -ex; \
4343
ARG XTRABACKUP_PKG=percona-xtrabackup-24
4444
RUN set -ex; \
4545
apt-get update; \
46-
apt-get install -y --no-install-recommends gnupg2 wget lsb-release curl bc; \
46+
apt-get install -y --no-install-recommends gnupg2 wget lsb-release curl bc fuse jq openssh-server; \
4747
wget -P /tmp --no-check-certificate https://repo.percona.com/apt/percona-release_latest.$(lsb_release -sc)_all.deb; \
4848
dpkg -i /tmp/percona-release_latest.$(lsb_release -sc)_all.deb; \
4949
apt-get update; \
5050
apt-get install -y --no-install-recommends ${XTRABACKUP_PKG}; \
5151
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
52-
52+
#ADD http://mirrors.woqutech.com/download/qfusion/files/bin/juicefs-1.0.0-rc1-linux-amd64 /usr/local/bin/juicefs
53+
# COPY juicefs/juicefs /usr/local/bin/juicefs
54+
RUN wget --no-check-certificate "https://d.juicefs.com/juicefs/releases/download/v1.0.2/juicefs-1.0.2-linux-amd64.tar.gz" && tar -zxf "juicefs-1.0.2-linux-amd64.tar.gz" ;\
55+
mv juicefs /usr/local/bin/juicefs; \
56+
chmod +x /usr/local/bin/juicefs ; mkdir -p /run/sshd; \
57+
mkdir -p /root/.ssh; \
58+
chmod 700 /root/.ssh
5359
WORKDIR /
5460
COPY --from=builder /workspace/bin/sidecar /usr/local/bin/sidecar
55-
ENTRYPOINT ["sidecar"]
61+
COPY script/*.sh /
62+
CMD [ "sidecar" ]

api/v1alpha1/backup_types.go

+11
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ import (
2121
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2222
)
2323

24+
type JuiceOpt struct {
25+
// sqlite or redis
26+
JuiceMeta string `json:"juiceMeta"`
27+
// backupSecrete name for S3
28+
BackupSecretName string `json:"backupSecretName"`
29+
JuiceName string `json:"juiceName"`
30+
}
31+
2432
// This is the backup Job CRD.
2533
// BackupSpec defines the desired state of Backup
2634
type BackupSpec struct {
@@ -40,6 +48,9 @@ type BackupSpec struct {
4048
// +optional
4149
NFSServerAddress string `json:"nfsServerAddress,omitempty"`
4250

51+
// Represents the juicefs parameters which need.
52+
// +optional
53+
JuiceOpt *JuiceOpt `json:"juiceOpt,omitempty"`
4354
// ClusterName represents the cluster name to backup
4455
ClusterName string `json:"clusterName"`
4556

api/v1alpha1/zz_generated.deepcopy.go

+20-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backup/syncer/job.go

+90
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@ limitations under the License.
1717
package syncer
1818

1919
import (
20+
"context"
2021
"fmt"
22+
"strings"
2123

2224
"github.com/presslabs/controller-util/pkg/syncer"
2325
batchv1 "k8s.io/api/batch/v1"
2426
corev1 "k8s.io/api/core/v1"
2527
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2628
"k8s.io/apimachinery/pkg/runtime"
29+
"k8s.io/apimachinery/pkg/types"
2730
"sigs.k8s.io/controller-runtime/pkg/client"
2831

2932
v1alpha1 "github.com/radondb/radondb-mysql-kubernetes/api/v1alpha1"
@@ -33,6 +36,7 @@ import (
3336
)
3437

3538
type jobSyncer struct {
39+
client client.Client
3640
job *batchv1.Job
3741
backup *backup.Backup
3842
}
@@ -50,6 +54,7 @@ func NewJobSyncer(c client.Client, backup *backup.Backup) syncer.Interface {
5054
}
5155

5256
sync := &jobSyncer{
57+
client: c,
5358
job: obj,
5459
backup: backup,
5560
}
@@ -174,6 +179,10 @@ func (s *jobSyncer) ensurePodSpec(in corev1.PodSpec) corev1.PodSpec {
174179
MountPath: utils.XtrabckupLocal,
175180
},
176181
}
182+
} else if s.backup.Spec.JuiceOpt != nil {
183+
// Deal it for juiceOpt
184+
s.buildJuicefsBackPod(&in)
185+
177186
} else {
178187
// in.Containers[0].ImagePullPolicy = s.opt.ImagePullPolicy
179188
in.Containers[0].Args = []string{
@@ -238,3 +247,84 @@ func (s *jobSyncer) ensurePodSpec(in corev1.PodSpec) corev1.PodSpec {
238247
}
239248
return in
240249
}
250+
251+
func (s *jobSyncer) buildJuicefsBackPod(in *corev1.PodSpec) error {
252+
// add volumn about pvc
253+
var defMode int32 = 0600
254+
var err error
255+
var cmdstr string
256+
in.Volumes = []corev1.Volume{
257+
{
258+
Name: utils.SShVolumnName,
259+
VolumeSource: corev1.VolumeSource{
260+
Secret: &corev1.SecretVolumeSource{
261+
SecretName: fmt.Sprintf("%s-ssh-key", s.backup.Spec.ClusterName),
262+
DefaultMode: &defMode,
263+
},
264+
},
265+
},
266+
}
267+
268+
in.Containers[0].VolumeMounts = []corev1.VolumeMount{
269+
{
270+
Name: utils.SShVolumnName,
271+
MountPath: utils.SshVolumnPath,
272+
},
273+
}
274+
275+
// PodName.clusterName-mysql.Namespace
276+
// sample-mysql-0.sample-mysql.default
277+
hostname := fmt.Sprintf("%s.%s-mysql.%s", s.backup.Spec.HostName, s.backup.Spec.ClusterName, s.backup.Namespace)
278+
if cmdstr, err = s.buildJuicefsCmd(s.backup.Spec.JuiceOpt.BackupSecretName); err != nil {
279+
return err
280+
}
281+
282+
in.Containers[0].Command = []string{"bash", "-c", "--", `cp /etc/secret-ssh/* /root/.ssh
283+
chmod 600 /root/.ssh/authorized_keys ;` +
284+
strings.Join([]string{
285+
"ssh", "-o", "UserKnownHostsFile=/dev/null", "-o", "StrictHostKeyChecking=no", hostname, cmdstr,
286+
}, " ")}
287+
288+
return nil
289+
}
290+
291+
func (s *jobSyncer) buildJuicefsCmd(secName string) (string, error) {
292+
juiceopt := s.backup.Spec.JuiceOpt
293+
secret := &corev1.Secret{
294+
TypeMeta: metav1.TypeMeta{
295+
APIVersion: "v1",
296+
Kind: "Secret",
297+
},
298+
ObjectMeta: metav1.ObjectMeta{
299+
Name: secName,
300+
Namespace: s.backup.Namespace,
301+
},
302+
}
303+
err := s.client.Get(context.TODO(),
304+
types.NamespacedName{Namespace: s.backup.Namespace,
305+
Name: secName}, secret)
306+
307+
if err != nil {
308+
return "", err
309+
}
310+
url, bucket := secret.Data["s3-endpoint"], secret.Data["s3-bucket"]
311+
accesskey, secretkey := secret.Data["s3-access-key"], secret.Data["s3-secret-key"]
312+
juicebucket := utils.InstallBucket(string(url), string(bucket))
313+
cmdstr := fmt.Sprintf(`<<EOF
314+
export CLUSTER_NAME=%s
315+
juicefs format --storage s3 \
316+
--bucket %s \
317+
--access-key %s \
318+
--secret-key %s \
319+
%s \
320+
%s`, s.backup.Spec.ClusterName, juicebucket, accesskey, secretkey, juiceopt.JuiceMeta, juiceopt.JuiceName)
321+
cmdstr += fmt.Sprintf(`
322+
juicefs mount -d %s /%s/
323+
`, juiceopt.JuiceMeta, juiceopt.JuiceName)
324+
cmdstr += fmt.Sprintf(`
325+
source /backup.sh
326+
backup
327+
juicefs umount /%s/
328+
EOF`, juiceopt.JuiceName)
329+
return cmdstr, nil
330+
}

charts/mysql-operator/crds/mysql.radondb.com_backups.yaml

+16
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,22 @@ spec:
7070
default: radondb/mysql57-sidecar:v2.3.0
7171
description: To specify the image that will be used for sidecar container.
7272
type: string
73+
juiceOpt:
74+
description: Represents the juicefs parameters which need.
75+
properties:
76+
backupSecretName:
77+
description: backupSecrete name for S3
78+
type: string
79+
juiceMeta:
80+
description: sqlite or redis
81+
type: string
82+
juiceName:
83+
type: string
84+
required:
85+
- backupSecretName
86+
- juiceMeta
87+
- juiceName
88+
type: object
7389
nfsServerAddress:
7490
description: Represents the ip address of the nfs server.
7591
type: string

config/crd/bases/mysql.radondb.com_backups.yaml

+16
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,22 @@ spec:
7070
default: radondb/mysql57-sidecar:v2.3.0
7171
description: To specify the image that will be used for sidecar container.
7272
type: string
73+
juiceOpt:
74+
description: Represents the juicefs parameters which need.
75+
properties:
76+
backupSecretName:
77+
description: backupSecrete name for S3
78+
type: string
79+
juiceMeta:
80+
description: sqlite or redis
81+
type: string
82+
juiceName:
83+
type: string
84+
required:
85+
- backupSecretName
86+
- juiceMeta
87+
- juiceName
88+
type: object
7389
nfsServerAddress:
7490
description: Represents the ip address of the nfs server.
7591
type: string

controllers/mysqlcluster_controller.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ import (
2424
"github.com/presslabs/controller-util/pkg/syncer"
2525
appsv1 "k8s.io/api/apps/v1"
2626
corev1 "k8s.io/api/core/v1"
27-
policyv1beta1 "k8s.io/api/policy/v1beta1"
27+
28+
// policyv1beta1 "k8s.io/api/policy/v1beta1"
29+
policyv1beta1 "k8s.io/api/policy/v1"
2830
rbacv1 "k8s.io/api/rbac/v1"
2931
"k8s.io/apimachinery/pkg/api/errors"
3032
"k8s.io/apimachinery/pkg/labels"
@@ -125,6 +127,11 @@ func (r *MysqlClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request
125127
return ctrl.Result{}, err
126128
}
127129

130+
secretSShSyncer := clustersyncer.NewSShKeySyncer(r.Client, instance)
131+
if err = syncer.Sync(ctx, secretSShSyncer, r.Recorder); err != nil {
132+
return ctrl.Result{}, err
133+
}
134+
128135
// Todo: modify mysql cm will trigger rolling update but it will not be applied.
129136
cmRev := mysqlCMSyncer.Object().(*corev1.ConfigMap).ResourceVersion
130137
sctRev := secretSyncer.Object().(*corev1.Secret).ResourceVersion

mysqlcluster/container/backup.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func (c *backupSidecar) getImage() string {
3838
}
3939

4040
func (c *backupSidecar) getCommand() []string {
41-
return []string{"sidecar", "http"}
41+
return []string{"sh", "-c", "/sshd.sh ; sidecar http"}
4242
}
4343

4444
func (c *backupSidecar) getEnvVars() []corev1.EnvVar {
@@ -147,5 +147,13 @@ func (c *backupSidecar) getVolumeMounts() []corev1.VolumeMount {
147147
Name: utils.SysLocalTimeZone,
148148
MountPath: utils.SysLocalTimeZoneMountPath,
149149
},
150+
{
151+
Name: utils.SysFuseVolume,
152+
MountPath: utils.SysFuseVolumnMountPath,
153+
},
154+
{
155+
Name: utils.SShVolumnName,
156+
MountPath: utils.SshVolumnPath,
157+
},
150158
}
151159
}

mysqlcluster/container/container.go

+10
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ func getStartupProbe(name string) *corev1.Probe {
6363
// EnsureContainer ensure a container by the giving name.
6464
func EnsureContainer(name string, c *mysqlcluster.MysqlCluster) corev1.Container {
6565
var ctr container
66+
var security *corev1.SecurityContext = nil
6667
switch name {
6768
case utils.ContainerInitSidecarName:
6869
ctr = &initSidecar{c, name}
@@ -80,6 +81,14 @@ func EnsureContainer(name string, c *mysqlcluster.MysqlCluster) corev1.Container
8081
ctr = &auditLog{c, name}
8182
case utils.ContainerBackupName:
8283
ctr = &backupSidecar{c, name}
84+
needAdmin := true
85+
security = &corev1.SecurityContext{
86+
Privileged: &needAdmin,
87+
Capabilities: &corev1.Capabilities{
88+
Add: []corev1.Capability{"CAP_SYS_ADMIN",
89+
"DAC_READ_SEARCH",
90+
},
91+
}}
8392
}
8493

8594
return corev1.Container{
@@ -95,5 +104,6 @@ func EnsureContainer(name string, c *mysqlcluster.MysqlCluster) corev1.Container
95104
ReadinessProbe: ctr.getReadinessProbe(),
96105
StartupProbe: getStartupProbe(name),
97106
VolumeMounts: ctr.getVolumeMounts(),
107+
SecurityContext: security,
98108
}
99109
}

mysqlcluster/mysqlcluster.go

+22-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ func (c *MysqlCluster) EnsureVolumes() []corev1.Volume {
180180
},
181181
)
182182
}
183-
183+
var defMode int32 = 0600
184184
volumes = append(volumes,
185185
corev1.Volume{
186186
Name: utils.MysqlConfVolumeName,
@@ -246,6 +246,23 @@ func (c *MysqlCluster) EnsureVolumes() []corev1.Volume {
246246
},
247247
},
248248
},
249+
corev1.Volume{
250+
Name: utils.SysFuseVolume,
251+
VolumeSource: corev1.VolumeSource{
252+
HostPath: &corev1.HostPathVolumeSource{
253+
Path: "/dev/fuse",
254+
},
255+
},
256+
},
257+
corev1.Volume{
258+
Name: utils.SShVolumnName,
259+
VolumeSource: corev1.VolumeSource{
260+
Secret: &corev1.SecretVolumeSource{
261+
SecretName: c.GetNameForResource(utils.SShKey),
262+
DefaultMode: &defMode,
263+
},
264+
},
265+
},
249266
)
250267
// add the nfs volumn mount
251268
if len(c.Spec.NFSServerAddress) != 0 {
@@ -328,8 +345,12 @@ func (c *MysqlCluster) GetNameForResource(name utils.ResourceName) string {
328345
return fmt.Sprintf("%s-metrics", c.Name)
329346
case utils.Secret:
330347
return fmt.Sprintf("%s-secret", c.Name)
348+
case utils.SShKey:
349+
return fmt.Sprintf("%s-ssh-key", c.Name)
331350
case utils.XenonMetaData:
332351
return fmt.Sprintf("%s-xenon", c.Name)
352+
case utils.RestoreCMN:
353+
return fmt.Sprintf("%s-restore", c.Name)
333354
case utils.ConfigMap:
334355
if template := c.Spec.MysqlOpts.MysqlConfTemplate; template != "" {
335356
return template

0 commit comments

Comments
 (0)