早上好
我是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时询问?
谢谢。
答案 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
如果有一堆脚本需要运行以初始化数据库,则有两个选择:
mysql
Dockerfile创建一个Dockerfile,并将外壳程序脚本或SQL脚本添加到/docker-entrypoint-initdb.d
。 here下的“初始化新实例”下有更多详细信息。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_PASSWORD
,MYSQL_ALLOW_EMPTY_PASSWORD
或MYSQL_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