Kubernetes:使用 MySQL 容器创建 StatefulSet 时出错
Kubernetes: Error when creating a StatefulSet with a MySQL container
早上好,
我是 Docker 和 Kubernetes 的新手,我真的不知道从哪里开始寻求帮助。我使用 Docker 创建了一个数据库容器,我想管理它并使用 Kubernetes 进行扩展。我开始在我的机器上安装 minikube,并尝试先创建一个部署,然后为数据库容器创建一个 StatefulSet。但是在使用数据库(mariadb 或 mysql)创建 Pod 时,StatefulSet 出现问题。当我使用 Deployment 时,Pods 被加载并且工作正常。但是,在 StatefulSet 中使用它们时,相同的 Pods 不起作用,返回请求 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
和pods: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
pods 不起作用。他们给出一个错误:
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`
当容器已经有初始化脚本并且运行良好时,它怎么可能会请求这些变量?为什么它只在作为 statefulSet 启动时询问,而不是在启动 Deployment 时询问?
提前致谢。
我提取了您的图像 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
如果你有一堆脚本需要运行初始化数据库,你有两个选择:
- 根据
mysql
Docker文件创建一个Docker文件,并将shell脚本或SQL脚本添加到/docker-entrypoint-initdb.d
。 "Initializing a fresh instance". 下提供了更多详细信息 here
- 使用 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
您遇到的问题不是 StatefulSet 特有的。这是因为持久卷。如果你在没有持久卷的情况下使用 StatefulSet,你将不会遇到这个问题。或者,如果您使用 Deployment with persistent volume,您将面临这个问题。
为什么?好的,我来解释一下。
设置这些环境变量之一 MYSQL_ROOT_PASSWORD
、MYSQL_ALLOW_EMPTY_PASSWORD
或 MYSQL_RANDOM_ROOT_PASSWORD
是创建新数据库所必需的。读取环境变量部分 here.
但是,如果您从脚本初始化数据库,则不需要提供它。看看这一行docker-entrypont.sh
here。它检查 /var/lib/mysql
目录中是否已有数据库。如果有 none,它会尝试创建一个。如果您不提供任何指定的环境变量,那么它将给出您遇到的错误。但是,如果它发现那里已经有一个数据库,它就不会尝试创建一个,您也不会看到错误。
现在,问题是,你已经初始化了数据库,为什么它仍然抱怨环境变量?
在这里,持久卷发挥作用。由于您已将持久卷安装在 /var/lib/mysql
目录中,现在该目录指向当前为空的持久卷。因此,当您的容器 运行 docker-entrypoint.sh
脚本时,它没有在 /var/lib/mysql
目录中找到任何数据库,因为它现在指向持久卷而不是您的原始 /var/lib/mysql
目录docker 已在此目录上初始化数据库的图像。因此,它会尝试创建一个新数据库,并会抱怨你没有提供 MYSQL_ROOT_PASSWORD
环境变量。
当您不使用任何持久卷时,您的 /var/lib/mysql
目录指向包含初始化数据库的原始目录。所以,你不会看到错误。
那么,如何正确初始化mysql数据库呢?
为了从脚本初始化MySQL,您只需将脚本放入/docker-entrypoint-initdb.d
。只需使用 vanilla mysql 映像,将初始化脚本放入卷中,然后将卷安装在 /docker-entrypoint-initdb.d
目录中。 MySQL 将被初始化。
查看此答案以了解有关如何从脚本初始化的详细信息:
早上好,
我是 Docker 和 Kubernetes 的新手,我真的不知道从哪里开始寻求帮助。我使用 Docker 创建了一个数据库容器,我想管理它并使用 Kubernetes 进行扩展。我开始在我的机器上安装 minikube,并尝试先创建一个部署,然后为数据库容器创建一个 StatefulSet。但是在使用数据库(mariadb 或 mysql)创建 Pod 时,StatefulSet 出现问题。当我使用 Deployment 时,Pods 被加载并且工作正常。但是,在 StatefulSet 中使用它们时,相同的 Pods 不起作用,返回请求 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
和pods: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
pods 不起作用。他们给出一个错误:
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`
当容器已经有初始化脚本并且运行良好时,它怎么可能会请求这些变量?为什么它只在作为 statefulSet 启动时询问,而不是在启动 Deployment 时询问?
提前致谢。
我提取了您的图像 ignasiet/aravomysql
以试图找出问题所在。事实证明,您的图像已经在 /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
如果你有一堆脚本需要运行初始化数据库,你有两个选择:
- 根据
mysql
Docker文件创建一个Docker文件,并将shell脚本或SQL脚本添加到/docker-entrypoint-initdb.d
。 "Initializing a fresh instance". 下提供了更多详细信息 here
- 使用 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
您遇到的问题不是 StatefulSet 特有的。这是因为持久卷。如果你在没有持久卷的情况下使用 StatefulSet,你将不会遇到这个问题。或者,如果您使用 Deployment with persistent volume,您将面临这个问题。
为什么?好的,我来解释一下。
设置这些环境变量之一 MYSQL_ROOT_PASSWORD
、MYSQL_ALLOW_EMPTY_PASSWORD
或 MYSQL_RANDOM_ROOT_PASSWORD
是创建新数据库所必需的。读取环境变量部分 here.
但是,如果您从脚本初始化数据库,则不需要提供它。看看这一行docker-entrypont.sh
here。它检查 /var/lib/mysql
目录中是否已有数据库。如果有 none,它会尝试创建一个。如果您不提供任何指定的环境变量,那么它将给出您遇到的错误。但是,如果它发现那里已经有一个数据库,它就不会尝试创建一个,您也不会看到错误。
现在,问题是,你已经初始化了数据库,为什么它仍然抱怨环境变量?
在这里,持久卷发挥作用。由于您已将持久卷安装在 /var/lib/mysql
目录中,现在该目录指向当前为空的持久卷。因此,当您的容器 运行 docker-entrypoint.sh
脚本时,它没有在 /var/lib/mysql
目录中找到任何数据库,因为它现在指向持久卷而不是您的原始 /var/lib/mysql
目录docker 已在此目录上初始化数据库的图像。因此,它会尝试创建一个新数据库,并会抱怨你没有提供 MYSQL_ROOT_PASSWORD
环境变量。
当您不使用任何持久卷时,您的 /var/lib/mysql
目录指向包含初始化数据库的原始目录。所以,你不会看到错误。
那么,如何正确初始化mysql数据库呢?
为了从脚本初始化MySQL,您只需将脚本放入/docker-entrypoint-initdb.d
。只需使用 vanilla mysql 映像,将初始化脚本放入卷中,然后将卷安装在 /docker-entrypoint-initdb.d
目录中。 MySQL 将被初始化。
查看此答案以了解有关如何从脚本初始化的详细信息: