Kubernetes:使用MySQL容器创建StatefulSet时出错

时间:2018-11-07 12:27:52

标签: mysql docker kubernetes minikube

早上好

我是Docker和Kubernetes的新手,我真的不知道从哪里开始寻求帮助。我用Docker创建了一个数据库容器,我想对其进行管理并通过Kubernetes进行扩展。我开始在计算机上安装minikube,并尝试首先创建一个Deployment,然后为数据库容器创建一个StatefulSet。但是在使用数据库(mariadb或mysql)创建Pod时,StatefulSet出现问题。使用Deployment时,将加载Pod并正常工作。但是,当在StatefulSet中使用它们时,相同的Pod无法正常工作,并返回错误,要求提供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对象。 因此,在使用kubectl create -f statefulset.yaml创建以下StatefulSet时:

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日志会显示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`

当容器已经具有初始化脚本并且可以完美运行时,它怎么可能会问这些变量?为什么只在以statefulSet启动时而不是在启动Deployment时询问?

谢谢。

2 个答案:

答案 0 :(得分:4)

我拉了您的图片ignasiet/aravomysql,以试图找出问题所在。事实证明,您的映像已经在/var/lib/mysql上具有初始化的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. 基于mysql Dockerfile创建一个Dockerfile,并将外壳程序脚本或SQL脚本添加到/docker-entrypoint-initdb.dhere下的“初始化新实例”下有更多详细信息。
  2. 使用PodTemplateSpec中的initContainers属性,例如:
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

答案 1 :(得分:1)

您面临的问题并非特定于StatefulSet。这是因为持续的数量。如果使用不带持久卷的StatefulSet,则不会遇到此问题。或者,如果您将“部署”与持久卷一起使用,则会遇到此问题。

为什么?好,让我解释一下。

设置这些环境变量MYSQL_ROOT_PASSWORDMYSQL_ALLOW_EMPTY_PASSWORDMYSQL_RANDOM_ROOT_PASSWORD之一对于创建新数据库是必需的。阅读环境变量第here部分。

但是,如果您通过脚本初始化数据库,则无需提供它。请看docker-entrypont.sh here的这一行。它检查/var/lib/mysql目录中是否已经有一个数据库。如果没有,它将尝试创建一个。如果您不提供任何指定的环境变量,那么它将给出您得到的错误。但是,如果它已经在那里找到一个数据库,它将不会尝试创建一个数据库,并且您将不会看到错误。

现在,问题是,您已经初始化了数据库,那么为什么它仍然抱怨环境变量?

在这里,持续的音量发挥了作用。在/var/lib/mysql目录中安装了持久卷之后,现在该目录指向您当前为空的持久卷。因此,当您的容器运行docker-entrypoint.sh脚本时,它在/var/lib/mysql目录中未找到任何数据库,因为它现在指向的是持久卷,而不是您的docker镜像的原始/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