本示例描述了如何在 Kubeernetes 上持久化安装 WordPressMySQL 。在这个安装里我们将使用官方的 mysqlwordpress 镜像(WordPress 镜像包含一个 Apache 服务)。

展示的 Kubernetes 概念:

快速入门

在一个名为 password.txt 的文件中放置你期望的 MySQL 密码,结尾不要有空行。如果你的编辑器添加了一个空行,开始的 tr 命令将会删除它。

请注意:如果你的集群强制启用 selinux 特性并且你将使用 Host Path 作为存储,请遵照这个额外步骤

tr --delete '\n' <password.txt >.strippedpassword.txt && mv .strippedpassword.txt password.txt
kubectl create -f https://raw.githubusercontent.com/kubernetes/examples/master/mysql-wordpress-pd/local-volumes.yaml
kubectl create secret generic mysql-pass --from-file=password.txt
kubectl create -f https://raw.githubusercontent.com/kubernetes/examples/master/mysql-wordpress-pd/mysql-deployment.yaml
kubectl create -f https://raw.githubusercontent.com/kubernetes/examples/master/mysql-wordpress-pd/wordpress-deployment.yaml

目录

在 Kubernetes 上持久化安装 MySQL 和 WordPress

集群要求

Kubernetes本质是模块化的,可以在各种环境中运行。但并不是所有集群都相同。此处是本示例的一些要求:

查阅 Getting Started Guide,搭建一个集群并安装 kubectl 命令行工具。

决定在哪里存储你的数据

MySQL 和 WordPress 各自使用一个 Persistent Volume 来存储自己的数据。我们将使用一个 Persistent Volume Claim 来取得一个可用的持久化存储。本示例覆盖了 HostPath 和 GCEPersistentDisk 卷类型。你可以从两者中选择一个,或者查看 Persistent Volumes的类型

Host Path

Host paths 是映射到主机上目录的卷。这种类型应该只用于测试目的或者单节点集群。如果 pod 在一个新的节点上重建,数据将不会在节点之间移动。如果 pod 被删除并在一个新的节点上重建,数据将会丢失。

SELinux

在支持 selinux 的系统上,保持它为 enabled/enforcing 是最佳选择。然而,docker 容器使用 “svirt_sandbox_file_t” 标签类型挂载 host path,这和默认的 /tmp (“tmp_t”) 标签类型不兼容。在 mysql 容器试图对 /var/lib/mysql 执行 chown 时将导致权限错误。 因此,要在一个启用 selinx 的系统上使用 host path,你应该预先创建 host path 路径(/tmp/data/)并将它的 selinux 标签类型改变为 “svirt_sandbox_file_t“,就像下面一样:

## on every node:
mkdir -p /tmp/data
chmod a+rwt /tmp/data  # match /tmp permissions
chcon -Rt svirt_sandbox_file_t /tmp/data

继续进行 host path 配置,在 Kubernetes 中使用 local-volumes.yaml 创建 persistent volume 对象:

export KUBE_REPO=https://raw.githubusercontent.com/kubernetes/examples/master
kubectl create -f $KUBE_REPO/mysql-wordpress-pd/local-volumes.yaml

GCE Persistent Disk

如果在 Google Compute Engine 上运行集群,你可以使用这个存储选项。

创建两个永久磁盘。你需要在和 Kubernetes 集群相同的 GCE zone 中创建这些磁盘。默认的安装脚本将在 us-central1-b zone 中创建集群,就像你在 config-default.sh 文件中看到的。替换下面的 <zone> 为合适的 zone。wordpress-1wordpress-2 的名字必须和 gce-volumes.yaml 指定的 pdName 字段匹配。

gcloud compute disks create --size=20GB --zone=<zone> wordpress-1
gcloud compute disks create --size=20GB --zone=<zone> wordpress-2

在 Kubernetes 为这些磁盘创建 persistent volume 对象:

export KUBE_REPO=https://raw.githubusercontent.com/kubernetes/examples/master
kubectl create -f $KUBE_REPO/mysql-wordpress-pd/gce-volumes.yaml

创建 MySQL 密码 Secret

使用一个 Secret 对象存储 MySQL 密码。首先,创建一个名为 password.txt 的文件(和 wordpress 示例文件在相同的文件夹),并且将你的密码保存于其中。请确保密码文件的结尾没有空行。如果你的编辑器添加了一个,开始的 tr 命令将会删除这个空行。然后,创建这个 Secret 对象。

tr --delete '\n' <password.txt >.strippedpassword.txt && mv .strippedpassword.txt password.txt
kubectl create secret generic mysql-pass --from-file=password.txt

MySQL 和 WordPress pod 配置引用了这个 secret,所以这些 pods 就可以访问它。MySQL pod 会设置数据库密码,并且 WordPress 将使用这个密码来访问数据库。

部署 MySQL

<– Now that the persistent disks and secrets are defined, the Kubernetes pods can be launched. Start MySQL using mysql-deployment.yaml. –> 现在我们已经定义了永久磁盘和 secrets,可以启动 Kubernetes pods 了。使用 mysql-deployment.yaml 启动 MySQL。

kubectl create -f $KUBE_REPO/mysql-wordpress-pd/mysql-deployment.yaml

查看 mysql-deployment.yaml,注意到我们定义了一个挂载到 /var/lib/mysql 的卷,然后创建了一个请求 20G 卷的 Persistent Volume Claim。这个要求可以被任何符合这个要求的卷满足,在我们的例子中,可以是上面创建的卷中的一个。

再看一下 env 一节,我们引用上面创建的 mysql-pass secret 来指定密码。Secrets 可以有多组键值对。我们的只有一个键 password.txt,它是我们用来创建 secret 的文件名。MySQL镜像 使用 MYSQL_ROOT_PASSWORD 环境变量设置数据库密码。

在很短的时间内,新建的 pod 将达到 Running 状态。列出所有的 pods,查看新建的 pod 的状态。

kubectl get pods
NAME                          READY     STATUS    RESTARTS   AGE
wordpress-mysql-cqcf4-9q8lo   1/1       Running   0          1m

Kubernetes 记录每个 pod 的 stderr 和 stdout。使用 kubectl log 查看一个 pod 的日志。从 get pods 复制 pod 名字,然后:

kubectl logs <pod-name>
...
2016-02-19 16:58:05 1 [Note] InnoDB: 128 rollback segment(s) are active.
2016-02-19 16:58:05 1 [Note] InnoDB: Waiting for purge to start
2016-02-19 16:58:05 1 [Note] InnoDB: 5.6.29 started; log sequence number 1626007
2016-02-19 16:58:05 1 [Note] Server hostname (bind-address): '*'; port: 3306
2016-02-19 16:58:05 1 [Note] IPv6 is available.
2016-02-19 16:58:05 1 [Note]   - '::' resolves to '::';
2016-02-19 16:58:05 1 [Note] Server socket created on IP: '::'.
2016-02-19 16:58:05 1 [Warning] 'proxies_priv' entry '@ root@wordpress-mysql-cqcf4-9q8lo' ignored in --skip-name-resolve mode.
2016-02-19 16:58:05 1 [Note] Event Scheduler: Loaded 0 events
2016-02-19 16:58:05 1 [Note] mysqld: ready for connections.
Version: '5.6.29'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)

我们还需要在 mysql-deployment.yaml 中创建一个 service 以允许其它 pods 访问这个 mysql 示例。wordpress-mysql 名称被解析为这个 pod 的 IP。

到此为止,我们创建了一个 Deployment,一个 Pod,一个 PVC,一个 Service,一个 Endpoint,两个 PV 和一个 Secret,显示如下:

kubectl get deployment,pod,svc,endpoints,pvc -l app=wordpress -o wide && \
  kubectl get secret mysql-pass && \
  kubectl get pv
NAME                     DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deploy/wordpress-mysql   1         1         1            1           3m
NAME                                  READY     STATUS    RESTARTS   AGE       IP           NODE
po/wordpress-mysql-3040864217-40soc   1/1       Running   0          3m        172.17.0.2   127.0.0.1
NAME                  CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE       SELECTOR
svc/wordpress-mysql   None         <none>        3306/TCP   3m        app=wordpress,tier=mysql
NAME                 ENDPOINTS         AGE
ep/wordpress-mysql   172.17.0.2:3306   3m
NAME                 STATUS    VOLUME       CAPACITY   ACCESSMODES   AGE
pvc/mysql-pv-claim   Bound     local-pv-2   20Gi       RWO           3m
NAME         TYPE      DATA      AGE
mysql-pass   Opaque    1         3m
NAME         CAPACITY   ACCESSMODES   STATUS      CLAIM                    REASON    AGE
local-pv-1   20Gi       RWO           Available                                      3m
local-pv-2   20Gi       RWO           Bound       default/mysql-pv-claim             3m

部署 WordPress

接下来使用 wordpress-deployment.yaml 部署 WordPress:

kubectl create -f $KUBE_REPO/mysql-wordpress-pd/wordpress-deployment.yaml

我们在这里使用了许多相同的特性,比如对 persistent storage 的 volume claim 和 password 的 secret。

WordPress 镜像 通过环境变量 WORDPRESS_DB_HOST 接收数据库的主机名。我们将这个环境变量值设置为我们创建的 MySQL service 的名字:wordpress-mysql

WordPress service 具有 type: LoadBalancer 的设置。这将 wordpress service 置于一个外部 IP 之下。

找到你的 WordPress service 的外部 IP 地址。为这个 service 分配一个外部 IP 地址可能会耗时一分钟左右,这取决于你的集群环境。

kubectl get services wordpress
NAME        CLUSTER-IP     EXTERNAL-IP     PORT(S)   AGE
wordpress   10.0.0.5       1.2.3.4         80/TCP    19h

访问你的新 WordPress 博客

现在,我们可以访问这个运行的 WordPress 应用。请使用你上面获取的 service 的外部 IP 地址。

http://<external-ip>

你应该可以看到熟悉的 WordPress 初始页面。

WordPress init page

警告:不要在这个页面上留下你的 WordPress 设置。如果被其他用户发现,他们可能在你的实例上创建一个网站并用它来为可能有害的内容提供服务。你应该继续创建用户名密码之后的安装过程,删除你的实例,或者建立一个防火墙来限制接入。

删除并重启你的博客

建立你的 WordPress 博客并简单使用一下。然后删除它的 pods 并再次启动它们。由于使用了永久磁盘,你的博客的状态将被保留。

所有的资源都被标记为 app=wordpress,你可以使用 label selector 轻松的删除它们:

kubectl delete deployment,service -l app=wordpress
kubectl delete secret mysql-pass

稍后使用原来的命令重建资源,这将会选择包含原来的完整数据的磁盘。由于我们没有删除 PV Claims,在删除我们的 pods 后,集群中没有任何一个 pod 能够 claim 它们。保留 PV Claims 也保证了重建 Pods 不会导致 PD 切换 Pods。

如果你已经准备好了释放你的永久磁盘及其上的数据,请运行:

kubectl delete pvc -l app=wordpress

And then delete the volume objects themselves:

kubectl delete pv local-pv-1 local-pv-2

或者

kubectl delete pv wordpress-pv-1 wordpress-pv-2

接下来的步骤

Analytics