Kubernetes中的状态备份

因此,众所周知,最近的一次 DevOpsConfRussia2018于10月1-2日在莫斯科的“ Infraspace”举行。 对于不熟悉的人, DevOpsConf是一次有关开发,测试和操作流程集成的专业会议。


我公司也参加了这次会议。 我们是其合作伙伴,在展位上代表该公司,并举行了一次小型会议。 顺便说一句,这是我们第一次参加这种活动。 第一次会议,第一次mitap,第一次体验。


我们在说什么? Mitap的主题是“ Kubernetes中的备份”。


很可能听到这个名字,许多人会说:“为什么要备份到Kubernetes? 它不需要备份,它是无状态的。”



简介...


让我们从一些背景开始。 为什么有必要涵盖此主题以及为什么需要它。


2016年,我们熟悉了Kubernetes等技术,并开始积极将其应用于我们的项目。 当然,这些主要是具有微服务体系结构的项目,而这反过来又需要使用大量不同的软件。


在第一个使用Kubernetes的项目中,我们遇到了一个问题,即如何备份那里的有状态服务,这些服务有时由于某种原因进入k8。


我们开始研究和寻找解决该问题的现有方法。 与我们的同事和同志交流:“他们如何进行和建立这个过程?”


交谈后,我们意识到,所有这些都是通过不同的方法,手段和大量拐杖发生的。 但是,即使在一个项目的框架内 ,我们也没有遵循任何统一的方法。


为什么这这么重要? 由于我们公司为基于k8s的项目提供服务,因此我们只需要开发一种结构化的方法来解决此问题。


假设您正在使用Coober中的一个特定项目。 它包含一些状态服务,您需要备份它们的数据。 原则上,您可以在这里拐杖而忘了它。 但是,如果您已经在k8上有两个项目该怎么办? 第二个项目在工作中使用完全不同的服务。 如果已经有五个项目? 十个? 还是二十多?


当然,putting着拐杖已经是困难和不便的。 我们需要一种在古巴处理许多项目时可以同时使用的统一方法,以便工程师团队可以在几分钟内轻松,准确地对这些项目的备份进行必要的更改。


在本文的框架中,我们将仅讨论在公司内部用于解决此问题的工具和实践。


我们如何做到这一点?


Nxs备份是什么?

对于备份,我们使用我们自己的开源工具-nxs-backup。 我们不会详细介绍他可以做的事情。 可以在以下链接中找到更多详细信息。


现在让我们继续在k8s中执行备份。 我们如何以及做了什么。


什么是备份?


让我们看一下自己的Redmine的备份示例。 在其中,我们将备份MySQL数据库和用户项目文件。


我们该怎么做?


1 CronJob == 1服务

在普通服务器和硬件上的群集上,几乎所有备份工具都是通过常规cron启动的。 为此,在k8中使用CronJob,即为1个服务创建1个CronJob,我们将对其进行备份。 所有这些CronJob都与服务本身位于同一名称空间中。


让我们从MySQL数据库开始。 要备份MySQL,我们需要4个元素,就像几乎所有其他服务一样:


  • ConfigMap(nxs-backup.conf)
  • ConfigMap(nxs-backup的mysql.conf)
  • 秘密(对服务的访问存储在此处,在本例中为MySQL)。 通常,已经为服务工作定义了此元素,并且可以重复使用该元素。
  • CronJob(每个服务都有自己的服务)

让我们去吧。


nxs-backup.conf

apiVersion: v1 kind: ConfigMap metadata: name: nxs-backup-conf data: nxs-backup.conf: |- main: server_name: Nixys k8s cluster admin_mail: admins@nixys.ru client_mail: - '' mail_from: backup@nixys.ru level_message: error block_io_read: '' block_io_write: '' blkio_weight: '' general_path_to_all_tmp_dir: /var/nxs-backup cpu_shares: '' log_file: /dev/stdout jobs: !include [conf.d/*.conf] 

在这里,我们设置传递给我们工具的基本参数,这对于它的操作是必需的。 这是服务器的名称,用于通知的电子邮件,对资源消耗的限制以及其他参数。


可以以j2格式指定配置,该格式允许使用环境变量。


mysql.conf

 apiVersion: v1 kind: ConfigMap metadata: name: mysql-conf data: service.conf.j2: |- - job: mysql type: mysql tmp_dir: /var/nxs-backup/databases/mysql/dump_tmp sources: - connect: db_host: {{ db_host }} db_port: {{ db_port }} socket: '' db_user: {{ db_user }} db_password: {{ db_password }} target: - redmine_db gzip: yes is_slave: no extra_keys: '--opt --add-drop-database --routines --comments --create-options --quote-names --order-by-primary --hex-blob' storages: - storage: local enable: yes backup_dir: /var/nxs-backup/databases/mysql/dump store: days: 6 weeks: 4 month: 6 

该文件描述了相应服务的备份逻辑,在本例中为MySQL。


您可以在此处指定:


  • Job的名称是什么(字段:job)
  • 作业类型(字段:类型)
  • 收集备份所需的临时目录(字段:tmp_dir)
  • MySQL连接选项(字段:connect)
  • 要备份的数据库(字段:目标)
  • 需要在收集之前停止从站(字段:is_slave)
  • mysqldump的附加键(字段:extra_keys)
  • 存储空间,即我们将在其中存储副本(字段:存储)
  • 我们将存储副本的目录(字段:backup_dir)
  • 存储方案(字段:存储)

在我们的示例中,存储类型设置为本地,即我们在启动的pod的特定目录中本地收集和存储备份。


在这里,类似于此配置文件,如果我们的工具支持,则可以为Redis,PostgreSQL或任何其他必要的服务指定相同的配置文件。 它支持的事实可以在前面给出的链接中找到。


秘密mysql

 apiVersion: v1 kind: Secret metadata: name: app-config data: db_name: "" db_host: "" db_user: "" db_password: "" secret_token: "" smtp_address: "" smtp_domain: "" smtp_ssl: "" smtp_enable_starttls_auto: "" smtp_port: "" smtp_auth_type: "" smtp_login: "" smtp_password: "" 

我们保留秘密访问权限以连接到MySQL本身和邮件服务器。 它们既可以存储在单独的秘密中,也可以利用现有的秘密(如果有的话)。 这里没什么有趣的。 我们的秘密还包含secret_token,这对于操作Redmine来说是必需的。


CronJob MySQL

 apiVersion: batch/v1beta1 kind: CronJob metadata: name: mysql spec: schedule: "00 00 * * *" jobTemplate: spec: template: spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - nxs-node5 containers: - name: mysql-backup image: nixyslab/nxs-backup:latest env: - name: DB_HOST valueFrom: secretKeyRef: name: app-config key: db_host - name: DB_PORT value: '3306' - name: DB_USER valueFrom: secretKeyRef: name: app-config key: db_user - name: DB_PASSWORD valueFrom: secretKeyRef: name: app-config key: db_password - name: SMTP_MAILHUB_ADDR valueFrom: secretKeyRef: name: app-config key: smtp_address - name: SMTP_MAILHUB_PORT valueFrom: secretKeyRef: name: app-config key: smtp_port - name: SMTP_USE_TLS value: 'YES' - name: SMTP_AUTH_USER valueFrom: secretKeyRef: name: app-config key: smtp_login - name: SMTP_AUTH_PASS valueFrom: secretKeyRef: name: app-config key: smtp_password - name: SMTP_FROM_LINE_OVERRIDE value: 'NO' volumeMounts: - name: mysql-conf mountPath: /usr/share/nxs-backup/service.conf.j2 subPath: service.conf.j2 - name: nxs-backup-conf mountPath: /etc/nxs-backup/nxs-backup.conf subPath: nxs-backup.conf - name: backup-dir mountPath: /var/nxs-backup imagePullPolicy: Always volumes: - name: mysql-conf configMap: name: mysql-conf items: - key: service.conf.j2 path: service.conf.j2 - name: nxs-backup-conf configMap: name: nxs-backup-conf items: - key: nxs-backup.conf path: nxs-backup.conf - name: backup-dir hostPath: path: /var/backups/k8s type: Directory restartPolicy: OnFailure 

也许这个元素是最有趣的。 首先,为了编译正确的CronJob,您需要确定所收集备份的存储位置。


为此,我们有一台具有必要数量资源的单独服务器。 在该示例中,分配了一个单独的群集节点nxs-node5来收集备份。 在我们所需的节点上启动CronJob的限制由nodeAffinity指令设置。


当CronJob启动时,相应的目录通过主机系统上的hostPath连接到该目录,该目录用于存储备份副本。


接下来,将ConfigMap连接到特定的CronJob,其中包含nxs-backup的配置,即我们上面刚刚谈到的nxs-backup.conf和mysql.conf文件。


然后,设置所有必需的环境变量,这些变量直接在清单中定义或从Secret'ov中提取。


因此,变量被传输到容器,并通过docker-entrypoint.sh在ConfigMaps中的所需位置替换为必要的值。 对于MySQL,这是db_host,db_user,db_password。 在这种情况下,我们仅将端口作为CronJob清单中的值传递,因为它不携带任何有价值的信息。


好吧,对于MySQL,一切似乎都很清楚。 现在,让我们来看看备份Redmine应用程序文件所需要的。


desc_files.conf

 apiVersion: v1 kind: ConfigMap metadata: name: desc-files-conf data: service.conf.j2: |- - job: desc-files type: desc_files tmp_dir: /var/nxs-backup/files/desc/dump_tmp sources: - target: - /var/www/files gzip: yes storages: - storage: local enable: yes backup_dir: /var/nxs-backup/files/desc/dump store: days: 6 weeks: 4 month: 6 

这是一个配置文件,描述了文件的备份逻辑。 这里也没有什么不寻常的地方,除了授权数据外,所有其他参数都与MySQL相同,因为它们不是必需的。 尽管可以,但如果涉及数据传输协议:ssh,ftp,webdav,s3等。 我们稍后会考虑该选项。


CronJob desc_files

 apiVersion: batch/v1beta1 kind: CronJob metadata: name: desc-files spec: schedule: "00 00 * * *" jobTemplate: spec: template: spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - nxs-node5 containers: - name: desc-files-backup image: nixyslab/nxs-backup:latest env: - name: SMTP_MAILHUB_ADDR valueFrom: secretKeyRef: name: app-config key: smtp_address - name: SMTP_MAILHUB_PORT valueFrom: secretKeyRef: name: app-config key: smtp_port - name: SMTP_USE_TLS value: 'YES' - name: SMTP_AUTH_USER valueFrom: secretKeyRef: name: app-config key: smtp_login - name: SMTP_AUTH_PASS valueFrom: secretKeyRef: name: app-config key: smtp_password - name: SMTP_FROM_LINE_OVERRIDE value: 'NO' volumeMounts: - name: desc-files-conf mountPath: /usr/share/nxs-backup/service.conf.j2 subPath: service.conf.j2 - name: nxs-backup-conf mountPath: /etc/nxs-backup/nxs-backup.conf subPath: nxs-backup.conf - name: target-dir mountPath: /var/www/files - name: backup-dir mountPath: /var/nxs-backup imagePullPolicy: Always volumes: - name: desc-files-conf configMap: name: desc-files-conf items: - key: service.conf.j2 path: service.conf.j2 - name: nxs-backup-conf configMap: name: nxs-backup-conf items: - key: nxs-backup.conf path: nxs-backup.conf - name: backup-dir hostPath: path: /var/backups/k8s type: Directory - name: target-dir persistentVolumeClaim: claimName: redmine-app-files restartPolicy: OnFailure 

关于MySQL,也没有新内容。 但是这里安装了另外一个PV(target-dir),我们将对其备份-/ var / www / files。 否则,一切都相同,我们将副本本地存储在我们需要的节点上,并为其分配了CronJob。


总结

对于我们要备份的每个服务,我们创建一个单独的CronJob,其中包含所有必需的相关元素:ConfigMaps和Secrets。 与所考虑的示例类似,我们可以备份集群中的任何类似服务。


我认为,基于这两个示例,每个人都知道我们如何备份古巴的有状态服务。 我认为对其他服务的相同示例进行详细分析是没有意义的,因为基本上它们都是相似的,并且略有不同。


实际上,这就是我们想要实现的目标,即某种构建备份过程的统一方法 。 因此,该方法可以应用于基于k8的大量不同项目。


我们在哪里存储?


在上面讨论的所有示例中,我们将副本存储在运行容器的节点的本地目录中。 但是没有人愿意将Persistent Volume连接为可用的外部存储并在那里收集副本。 或者,您只能使用所需的协议将它们同步到远程存储,而不能在本地保存。 也就是说,有很多变化。 首先在本地收集,然后进行同步。 或仅收集和存储在远程存储器等上。 配置非常灵活。


mysql.conf + s3

以下是MySQL备份配置文件的示例,其中副本存储在本地运行CronJob的节点上,并在s3中同步。


 apiVersion: v1 kind: ConfigMap metadata: name: mysql-conf data: service.conf.j2: |- - job: mysql type: mysql tmp_dir: /var/nxs-backup/databases/mysql/dump_tmp sources: - connect: db_host: {{ db_host }} db_port: {{ db_port }} socket: '' db_user: {{ db_user }} db_password: {{ db_password }} target: - redmine_db gzip: yes is_slave: no extra_keys: ' --opt --add-drop-database --routines --comments --create-options --quote-names --order-by-primary --hex-blob' storages: - storage: local enable: yes backup_dir: /var/nxs-backup/databases/mysql/dump store: days: 6 weeks: 4 month: 6 - storage: s3 enable: yes backup_dir: /nxs-backup/databases/mysql/dump bucket_name: {{ bucket_name }} access_key_id: {{ access_key_id }} secret_access_key: {{ secret_access_key }} s3fs_opts: {{ s3fs_opts }} store: days: 2 weeks: 1 month: 6 

也就是说,如果不足以在本地存储副本,则可以使用适当的协议将它们同步到任何远程存储。 存储的存储数量可以为任意。


但是在这种情况下,您仍然需要进行一些其他更改,即:


  • 以j2格式将适当的ConfigMap与进行AWS S3授权所需的内容连接
  • 创建适当的密钥以存储授权访问
  • 设置从上述Secret中获取的必要环境变量
  • 调整docker-entrypoint.sh以替换ConfigMap中的相应变量
  • 重建Docker映像,添加用于使用AWS S3的实用程序

尽管此过程远非完美,但我们正在努力。 因此,在不久的将来,我们将向nxs-backup添加使用环境变量在配置文件中定义参数的功能,这将大大简化入口点文件的工作,并最小化增加对新服务备份的支持所花费的时间。


结论


那可能就是全部。


首先,使用刚才讨论的方法,我们可以将有状态项目服务结构化和模板化到k8。 也就是说,这是一个现成的解决方案,最重要的是,您可以在项目中应用该实践,而不会浪费时间和精力来搜索和更新现有的开源解决方案。

Source: https://habr.com/ru/post/zh-CN426543/


All Articles