Kubernetes: ошибка при создании StatefulSet с контейнером MySQL - PullRequest
0 голосов
/ 07 ноября 2018

Доброе утро,

Я очень новичок в Docker и Kubernetes, и я действительно не знаю, с чего начать искать помощь. Я создал контейнер базы данных с Docker, и я хочу управлять им и масштабировать с помощью Kubernetes. Я начал устанавливать minikube на своей машине и попытался сначала создать Deployment, а затем StatefulSet для контейнера базы данных. Но у меня есть проблема с StatefulSet при создании Pod с базой данных (mariadb или mysql). Когда я использую Deployment, модули загружаются и работают нормально. Однако те же модули не работают при использовании их в StatefulSet, возвращая ошибки, запрашивающие константы MYSQL. Это развертывание, и я использую команду kubectl create -f deployment.yaml:

apiVersion: apps/v1beta1
kind: Deployment
metadata:
 name: mydb-deployment
spec:
 template:
  metadata:
   labels: 
    name: mydb-pod
  spec:
   containers:
    - name: mydb
      image: ignasiet/aravomysql
      ports:
       - containerPort: 3306

А при перечислении развертываний: kubectl get Deployments:

NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
mydb-deployment    1         1         1            1           2m

И стручки: kubectl get pods:

NAME                                READY   STATUS    RESTARTS   AGE
mydb-deployment-59c867c49d-4rslh    1/1     Running   0          50s

Но так как я хочу создать постоянную базу данных, я пытаюсь создать объект statefulSet с тем же контейнером и постоянным томом. Таким образом, при создании следующего StatefulSet с kubectl create -f statefulset.yaml:

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
 name: statefulset-mydb
spec:
 serviceName: mydb-pod
 template:
  metadata:
   labels: 
    name: mydb-pod
  spec:
   containers:
    - name: aravo-database
      image: ignasiet/aravomysql
      ports:
       - containerPort: 3306
      volumeMounts:
       - name: volume-mydb
         mountPath: /var/lib/mysql
   volumes:
    - name: volume-mydb
      persistentVolumeClaim: 
       claimName: config-mydb

С услугой kubectl create -f service-db.yaml:

apiVersion: v1
kind: Service
metadata:
 name: mydb
spec:
 type: ClusterIP
 ports:
  - port: 3306
 selector:
  name: mydb-pod

И файл разрешений kubectl create -f permissions.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: config-mydb
spec:
 accessModes: 
  - ReadWriteOnce
 resources:
  requests:
   storage: 3Gi

Стручки не работают. Они дают ошибку:

NAME                    READY   STATUS             RESTARTS   AGE
statefulset-mydb-0      0/1     CrashLoopBackOff   1          37s

А при анализе логов kubectl logs statefulset-mydb-0:

`error: database is uninitialized and password option is not specified
You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD`

Как возможно, что он запрашивает эти переменные, когда контейнер уже имеет скрипт инициализации и работает отлично? И почему он спрашивает только при запуске с набором состояний, а не при запуске развертывания?

Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 07 ноября 2018

Проблема, с которой вы столкнулись, не относится к StatefulSet. Это из-за постоянного объема. Если вы используете StatefulSet без постоянного тома, вы не столкнетесь с этой проблемой. Или, если вы используете развертывание с постоянным томом, вы столкнетесь с этой проблемой.

Почему? Хорошо, позвольте мне объяснить.

Установка одной из этих переменных среды MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD или MYSQL_RANDOM_ROOT_PASSWORD обязательна для создания новой базы данных. Читайте переменные среды часть здесь .

Но, если вы инициализируете базу данных из скрипта, вам не потребуется ее предоставлять. Посмотрите на эту строку docker-entrypont.sh здесь . Он проверяет, есть ли база данных в каталоге /var/lib/mysql. Если его нет, он попытается его создать. Если вы не предоставите ни одной из указанных переменных среды, то это выдаст ошибку, которую вы получаете. Но если он обнаружил там уже одну базу данных, он не будет пытаться создать ее и не увидит ошибку.

Теперь вопрос в том, что вы уже инициализировали базу данных, почему она все еще жалуется на переменные среды?

Здесь постоянная громкость входит в игру. Поскольку вы смонтировали постоянный том в каталоге /var/lib/mysql, теперь этот каталог указывает на ваш постоянный том, который в настоящее время пуст. Таким образом, когда ваш контейнер запускает сценарий docker-entrypoint.sh, он не находит базы данных в каталоге /var/lib/mysql, поскольку теперь он указывает на постоянный том, а не на исходный каталог /var/lib/mysql вашего образа докера, который инициализировал базу данных в этом каталоге. Таким образом, он попытается создать новую базу данных и будет жаловаться, поскольку вы не указали MYSQL_ROOT_PASSWORD переменную среды.

Если вы не используете постоянный том, ваш каталог /var/lib/mysql указывает на исходный каталог, который содержит инициализированную базу данных. Таким образом, вы не видите ошибку.

Тогда как правильно инициализировать базу данных mysql?

Чтобы инициализировать MySQL из скрипта, вам просто нужно поместить скрипт в /docker-entrypoint-initdb.d. Просто используйте ванильный образ mysql, поместите скрипт инициализации в том, а затем смонтируйте том в каталог /docker-entrypoint-initdb.d. MySQL будет инициализирован.

Проверьте этот ответ для деталей о том, как инициализировать из сценария: https://stackoverflow.com/a/45682775/7695859

0 голосов
/ 07 ноября 2018

Я вытащил ваше изображение ignasiet/aravomysql, чтобы попытаться выяснить, что пошло не так. Оказывается, ваше изображение уже имеет инициализированный каталог данных MySQL по адресу /var/lib/mysql:

$ docker run -it --rm --entrypoint=sh ignasiet/aravomysql:latest
# ls -al /var/lib/mysql 
total 110616
drwxr-xr-x 1 mysql mysql      240 Nov  7 13:19 .
drwxr-xr-x 1 root  root        52 Oct 29 18:19 ..
-rw-rw---- 1 root  root     16384 Oct 29 18:18 aria_log.00000001
-rw-rw---- 1 root  root        52 Oct 29 18:18 aria_log_control
-rw-rw---- 1 root  root      1014 Oct 29 18:18 ib_buffer_pool
-rw-rw---- 1 root  root  50331648 Oct 29 18:18 ib_logfile0
-rw-rw---- 1 root  root  50331648 Oct 29 18:18 ib_logfile1
-rw-rw---- 1 root  root  12582912 Oct 29 18:18 ibdata1
-rw-rw---- 1 root  root         0 Oct 29 18:18 multi-master.info
drwx------ 1 root  root      2696 Nov  7 13:19 mysql
drwx------ 1 root  root        12 Nov  7 13:19 performance_schema
drwx------ 1 root  root        48 Nov  7 13:19 yypy

Однако при монтировании PersistentVolume или просто простого тома Docker в /var/lib/mysql он изначально пуст, и поэтому скрипт считает вашу базу данных неинициализированной. Вы можете воспроизвести эту проблему с помощью:

$ docker run -it --rm --mount type=tmpfs,destination=/var/lib/mysql ignasiet/aravomysql:latest
error: database is uninitialized and password option is not specified 
  You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD

Если у вас есть несколько сценариев, которые нужно запустить для инициализации базы данных, у вас есть два варианта:

  1. Создайте Dockerfile на основе mysql Dockerfile и добавьте сценарии оболочки или сценарии SQL в /docker-entrypoint-initdb.d. Более подробная информация доступна здесь в разделе «Инициализация нового экземпляра».
  2. Используйте свойство initContainers в PodTemplateSpec, что-то вроде:
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: statefulset-mydb
spec:
  serviceName: mydb-pod
  template:
  metadata:
    labels: 
    name: mydb-pod
  spec:
    containers:
    - name: aravo-database
      image: ignasiet/aravomysql
      ports:
        - containerPort: 3306
      volumeMounts:
        - name: volume-mydb
          mountPath: /var/lib/mysql
    initContainers:
    - name: aravo-database-init
      command:
        - /script/to/initialize/database
      image: ignasiet/aravomysql
      volumeMounts:
        - name: volume-mydb
          mountPath: /var/lib/mysql
    volumes:
    - name: volume-mydb
      persistentVolumeClaim: 
        claimName: config-mydb
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...