Автор статьи: Рустем Галиев
IBM Senior DevOps Engineer & Integration Architect. Официальный DevOps ментор и коуч в IBM
Привет, Хабр! Сегодня мы узнаем, как запустить надежный одноэлементный инстанс базы данных MySQL в качестве пода в Kubernetes и как предоставить этот под другим приложениям в кластере. Для этого мы создадим три основных объекта:
Persistent Volume для управления сроком службы дискового хранилища независимо от срока службы работающего приложения MySQL.
Под MySQL, который будет запускать приложение MySQL.
Сервис, который будет предоставлять этот под другим контейнерам в кластере.
Создаем persistent volume
Мы определяем IP-адрес кластера службы, которая предоставляет под, чтобы позже ссылаться на него при монтировании службы NFS в PersistentVolume
:kubectl get service nfs-service -n storage -o jsonpath='{.spec.clusterIP}'
Для начала создадим PV для нашей базы данных MySQL.
apiVersion: v1
kind: PersistentVolume
metadata:
name: database
labels:
volume: my-volume
spec:
accessModes:
- ReadWriteMany
capacity:
storage: 1Gi
nfs:
server: <добавьте-свой-nfs-service-cluster-ip-здесь>
path: "/nfs-direct"
Это определяет объект NFS PersistentVolume
с 1 ГБ дискового пространства.
Создаемkubectl apply -f nfs-volume.yaml
Создадим PersistentVolumeClaim
Теперь, когда у нас есть PV, нам нужно залкэймить PV для нашего пода. Мы делаем это с помощью объекта PersistentVolumeClaim
:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: database
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
selector:
matchLabels:
volume: my-volume
Поле селектора использует метки для поиска соответствующего тома, который мы определили ранее.
Создаем объект с помощью следующей команды:kubectl apply -f nfs-volume-claim.yaml
Создание набора реплик MySQL
Теперь, когда заклэймили PV, мы можем использовать ReplicaSet
для создания нашего пода. Может показаться странным, что мы используем ReplicaSet
для управления одним подом, но это необходимо для надежности. Если нода перестает работать, то любые поды, которые находятся на этой ноде и не управляются контроллером более высокого уровня, таким как ReplicaSet
, исчезают вместе с нодой и не переназначаются другой ноде. Следовательно, чтобы убедиться, что наш под базы данных перепланируется при наличии сбоев ноды, мы используем контроллер ReplicaSet
более высокого уровня с количеством реплик, равным единице, для управления нашей базой данных.
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: mysql
labels:
app: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: database
image: mysql
resources:
requests:
cpu: 1
memory: 2Gi
env:
- name: MYSQL_ROOT_PASSWORD
value: root
livenessProbe:
tcpSocket:
port: 3306
ports:
- containerPort: 3306
volumeMounts:
- name: database
mountPath: "/var/lib/mysql"
volumes:
- name: database
persistentVolumeClaim:
claimName: database
Создаем kubectl apply -f mysql-replicaset.yaml
ReplicaSet
создает один под с парой «ключ-значение» метки app=label. Вы можете запросить его с помощью следующей команды:
kubectl get pods -l app=mysql
После запуска пода, управляемого набором реплик, и перехода в статус «Running», вы сможете проверить содержимое пути монтирования тома. Следующая команда предполагает, что имя Pod — mysql-XXXX(тут должны быть ваши цифры).
kubectl exec -it mysql-xxxx -- ls /var/lib/mysql
Предоставление MySQL как службы
Как только мы создадим ReplicaSet
, он, в свою очередь, создаст под с MySQL, используя изначально созданный персистент диск. Последний шаг — представить это как сервис Kubernetes.
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
protocol: TCP
selector:
app: mysql
Создаемkubectl apply -f mysql-service.yaml
Теперь у нас есть надежный одноэлементный экземпляр MySQL, работающий в нашем кластере и представленный как служба с именем mysql, к которой мы можем получить доступ по полному доменному имени mysql.svc.default.cluster.local
.
Мы создали persistent volume
для использования базой данных MySQL. В этом примере для максимальной переносимости использовалась NFS, но Kubernetes поддерживает множество различных типов persistent volume. Например, существуют persistent volume drivers томов для всех основных клауд провайдеров. Чтобы использовать эти решения, просто замените nfs на соответствующий тип тома облачного провайдера (например, azure, awsElasticBlockStore или gcePersistentDisk). Во всех случаях это изменение — все, что вам нужно. Kubernetes знает, как создать соответствующий диск для хранения в соответствующем клауд провайдере.
В завершение хочу порекомендовать бесплатный урок от моих коллег из OTUS, в рамках которого будет рассмотрено как устроен мониторинг кластера, его компоненты и приложения в кластере. Вы изучите различные подходы мониторинга, подходы к мониторингу как приложения, так и компонентов кластера, основные метрики Kubernetes.
stitrace
Я бы убрал на вашем месте слово «надежный» из описания, т.к. в процессе эксплуатации этого решения, вы неизбежно получите повреждение базы данных. Первая и самая серьезная опасность, это поднятие двух независимых инстансов mysql на одной и той же папке с данными БД, которая произойдет при первом же обновлении конфигурации деплоя, в том виде, в котором он описан у вас. Ну и, конечно, если у вас контрол плэйн потеряет ноду с подом, он заскедулит реплику рода на любую из доступных, но это вовсе не гарантирует, что нода умерла и на ней не продолжает работать инстанс mysql и даже, то что в данный момент, в него не пишет ПО. Короче говоря, не делайте так.
ggo
да ну что вы, право боже.
Базы данных внутри кубера - это же надежно, все так делают ;)
vasyakrg
Делают и ничего в этом такого нет. Другой вопрос, что надо использовать csi, умеющие размещать данные на этих же нодах, чтоб рядом, без задержек и в нескольких репликах: longhorn, linstor, etc.
А вот nfs - действительно не очень хорошая идея