Docker-Kubenetes-微服务教程-全-

Docker Kubenetes 微服务教程(全)

原文:Kubernetes Microservices with Docker

协议:CC BY-NC-SA 4.0

一、使用 Docker 安装 Kubernetes

Kubernetes 是管理 Docker 容器集群的软件。Kubernetes 流程编排包括调度、分配工作负载和扩展。Kubernetes 通过引入 Pods 进一步发展了 Docker 提供的软件封装。Pod 是一个或多个 Docker 容器的集合,这些容器具有单个接口特性,例如在 Pod 级别而不是在容器级别提供网络和文件系统。Kubernetes 还引入了“标签”,服务和复制控制器(复制控制器用于扩展集群)使用这些标签来识别或选择它们管理的容器或单元。Kubernetes 是轻量级的、可移植的(适合云架构)和模块化的。

Kubernetes 几乎可以在任何平台上运行。本地机器解决方案包括基于本地 Docker 的、无虚拟机的本地集群。托管解决方案包括谷歌容器引擎。Kubernetes 支持的其他一些平台有 Fedora (Ansible 和 Manual)、Amazon Web Services、Mesos、vSphere 和 CoreOS。Kubernetes 是 Docker 容器的编排软件;推荐的安装解决方案是使用 Docker 引擎。本章我们将在 Docker 上安装 Kubernetes,Docker 运行在 Ubuntu 上。我们将使用托管 Ubuntu 的 Amazon EC2 实例作为操作系统。本章将讨论 Kubernetes 的单节点安装。Kubernetes 的多节点安装将在第十四章中讨论。本章包括以下几节。

  • 设置环境
  • 安装 Docker
  • 正在安装 kubernetes
  • 正在启动 etcd
  • 启动 kubernetes master
  • 正在启动服务代理
  • 列出非库坞站容器
  • 安装 kubectl
  • 列表服务
  • 列出节点
  • 测试 Kubernetes 安装

设置环境

本章需要以下软件。

    • Docker 引擎(最新版本)
  • -Kubernetes(1.01 版)

Linux 需要支持 64 位软件。我们使用了从 AMI Ubuntu Server 14.04 LTS (HVM)创建的 Amazon EC2 实例,SSD 卷类型- ami-d05e75b8。一个基于 Ubuntu AMI 的 Amazon EC2 实例如图 1-1 所示。

A418863_1_En_1_Fig1_HTML.gif

图 1-1。

Amazon EC2 Instance Based on Ubuntu AMI

如果满足 64 位架构的要求,可以使用不同的 Ubuntu 版本。最低内核版本要求是 3.10。内核版本可以用下面的命令来验证。

uname –r

对于不同的用户,公共 IP 将是不同的。多个 Amazon EC2 实例,因此书中使用了多个公共 IP 地址,因为每次启动 Amazon EC2 实例时都会分配不同的公共 IP。Amazon EC2 实例的私有 IP 地址在重启时是相同的。SSH 到 Amazon EC2 上的 Ubuntu 实例(在下面的命令中,公共 IP 是 52.91.80.173)。

ssh -i "docker.pem" ubuntu@52.91.80.173

Amazon EC2 实例被登录,如图 1-2 所示。命令提示符变成“ubuntu@ip-172-30-1-190 ”,而不是 root@localhost。Ip 172.30.1.190 是 Amazon EC2 实例的私有 Ip,对于不同的用户也是不同的。

A418863_1_En_1_Fig2_HTML.gif

图 1-2。

Loging into an Amazon EC2 instance

在下一节中,我们将在 Amazon EC2 实例上的 Ubuntu 上安装 Docker。

安装 Docker

Ubuntu 使用 apt 进行包管理;apt 将存储库列表存储在/etc/apt/sources.list 列表中。Docker 的 apt 存储库保存在/etc/apt/sources . list . d/docker . list 文件中。首先,使用下面的命令为 Docker 存储库添加新的存储库密钥(gpg 密钥)。

sudo apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D

添加新的 gpg 密钥,如图 1-3 所示。

A418863_1_En_1_Fig3_HTML.gif

图 1-3。

Adding a new gpg key

接下来,根据 Ubuntu 发行版更新/etc/apt/sources . list . d/Docker . list 文件中 Docker 存储库的 apt 源代码,可以使用以下命令找到它。

lsb_release –a

对于 Ubuntu Trusty,在/etc/apt/sources . list . d/docker . list 文件中添加以下行;docker.list 文件可以用 sudo VI/etc/apt/sources . list . d/docker . list 打开。

deb https://apt.dockerproject.org/repo ubuntu-trusty main

如果/etc/apt/sources . list . d/docker . list 文件不存在,则创建该文件。更新后的文件如图 1-4 所示。如果在 vi 编辑器中打开文件,用:wq 命令保存文件。

A418863_1_En_1_Fig4_HTML.gif

图 1-4。

Creating the docker.list file

如表 1-1 所列,对于不同的 Ubuntu 发行版,要添加的条目会有所不同。

表 1-1。

The docker.list file Entry Based on Ubuntu Distribution

| Ubuntu 发行版 | 进入 | | --- | --- | | Ubuntu Precise 12.04 (LTS) | deb[`https://apt.dockerproject.org/repo`](https://apt.dockerproject.org/repo)Ubuntu-精确主 | | Ubuntu trust 14.04(lt) | deb[`https://apt.dockerproject.org/repo`](https://apt.dockerproject.org/repo)Ubuntu-trusty main | | Ubuntu 生动 15.04 | deb[`https://apt.dockerproject.org/repo`](https://apt.dockerproject.org/repo)Ubuntu-生动主 |

在更新/etc/apt/sources . list . d/docker . list 文件以更新 apt 包索引后,运行以下命令。

sudo apt-get update

Apt 包索引得到更新,如图 1-5 所示。

A418863_1_En_1_Fig5_HTML.gif

图 1-5。

Updating Ubuntu Package List

使用以下命令清除旧的存储库(如果存在)。

sudo apt-get purge lxc-docker*

图 1-6 中的输出表明旧包 lxc-docker 和 lxc-docker-virtual-package 没有安装,因此没有删除。

A418863_1_En_1_Fig6_HTML.gif

图 1-6。

Purging the Old Repository

运行以下命令来验证 apt 是否正在从 Docker 的更新存储库中进行提取。

sudo apt-cache policy docker-engine

图 1-7 中的输出表明正在使用/etc/apt/sources . list . d/docker . list 中指定的新存储库 ubuntu-trusty。

A418863_1_En_1_Fig7_HTML.gif

图 1-7。

Using the Updated Repository verification

接下来,安装 Ubuntu 的必备组件,但是首先用下面的命令更新包管理器。

sudo apt-get update

包管理器得到更新,如图 1-8 所示。

A418863_1_En_1_Fig8_HTML.gif

图 1-8。

Updating the Package Manager

使用以下命令安装必备的 linux-image-extra 包。

sudo apt-get install linux-image-generic-lts-trusty

运行上述命令时,如果出现以下消息提示,请选择 Y。执行此操作后,将使用 281 MB 的额外磁盘空间。您想继续吗?【是/否】

信息提示如图 1-9 所示。

A418863_1_En_1_Fig9_HTML.gif

图 1-9。

Message Prompt to Continue

随后,在该命令完成之前,软件包配置对话框可能会提示以下消息:

The new version of /boot/grub/menu.lst is available, but the currently installed version has been modified locally. What do you want to do with menu.lst?

选择默认选项“保持当前安装的本地版本”,点击回车,如图 1-10 所示。

A418863_1_En_1_Fig10_HTML.gif

图 1-10。

Selecting the Default Package Configuration

使用以下命令重新启动系统。

sudo reboot

当 sudo reboot 命令运行时,AmazonEC2 实例退出。使用与之前相同的 ssh 命令重新连接 Amazon EC2 Ubuntu 实例。

ssh -i "docker.pem" ubuntu@52.91.80.173

主机系统重新引导后,使用以下命令再次更新软件包管理器。

sudo apt-get update

包管理器得到更新,如图 1-11 所示。

A418863_1_En_1_Fig11_HTML.gif

图 1-11。

Updating Package Manager List after Reboot

用下面的命令安装 Docker。

sudo apt-get install docker-engine

如果显示,在以下提示中选择 Y,如图 1-12 所示。

After this operation, 60.3 MB of extra disk space will be used. Do you want to continue? [Yes/No]

A418863_1_En_1_Fig12_HTML.gif

图 1-12。

Message Prompt about the additional disk space being added

对接引擎的安装如图 1-13 所示。

A418863_1_En_1_Fig13_HTML.gif

图 1-13。

Installing the Docker Engine

使用以下命令启动 Docker 服务。

sudo service docker start

要验证 Docker 服务的状态,请运行以下命令。

sudo service docker status

前述命令的输出如图 1-14 所示。docker 引擎被指示为作为进程 2697 运行。

A418863_1_En_1_Fig14_HTML.gif

图 1-14。

Starting Docker and verifying its Status

安装了 Docker 之后,接下来我们将安装 Kubernetes。

正在安装 kubernetes

Kubernetes 是一个开源的容器集群管理器。Kubernetes 的主要成分如下:

etcd   Kubernetes master   Service proxy   kubelet

etcd 是一个简单、安全、快速和可靠的分布式键值存储。

Kubernetes master 公开了 Kubernetes API,使用它在节点上运行容器来处理任务。

kubelet 是一个运行在每个节点上的代理,用于监控节点上运行的容器,如果需要保持复制级别,可以重新启动它们。

服务代理在每个节点上运行,为客户机提供 Kubernetes 服务接口。服务是对服务所代表的单元的逻辑集合的抽象,服务选择器用于选择服务所代表的单元。服务代理将客户端流量路由到匹配的 pod。标签用于将服务与 pod 相匹配。

可以选择创建一个目录(/kubernetes)来安装 kubernetes,并将其权限设置为 global (777)。

sudo mkdir /kubernetes
sudo chmod -R 777 /kubernetes

前述命令的输出如图 1-15 所示。

A418863_1_En_1_Fig15_HTML.gif

图 1-15。

Creating a Directory to install Kubernetes

将目录切换到/kubernetes 目录并启动 Docker 引擎。

cd /kubernetes
sudo service docker start

如果 Docker 引擎没有运行,它就会启动。图 1-16 显示 Docker 引擎已经运行。

A418863_1_En_1_Fig16_HTML.gif

图 1-16。

Starting Docker if not already running

作为先决条件,我们需要设置一些 Linux 内核参数,如果还没有设置的话。添加对内存和交换记帐的支持。应该在内核中打开以下配置。

CONFIG_RESOURCE_COUNTERS=y
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
CONFIG_MEMCG_SWAP_ENABLED=y
CONFIG_MEMCG_KMEM=y

当 Ubuntu 系统引导并且内核配置文件在/boot 目录中时,内核配置被启用。将目录(cd)更改为/boot 目录,并列出文件/目录。

cd /boot
ls –l

/boot 目录中的文件被列出,如图 1-17 所示。内核配置在 config-3.13.0-48-generic 文件中进行配置。对于不同的用户,内核版本可能不同;例如,内核配置文件可以是/boot/config-3.13.0-66-generic。

A418863_1_En_1_Fig17_HTML.gif

图 1-17。

Listing the Files in the /boot Directory

在 vi 编辑器中打开 config-3.13.0-48-generic 文件。

sudo vi /boot/config-3.13.0-48-generic

内核配置参数被列出,如图 1-18 所示。

A418863_1_En_1_Fig18_HTML.gif

图 1-18。

Kernel Configuration Parameter

前面列出的大多数配置已经打开,如图 1-19 所示。未设置 CONFIG_MEMCG_SWAP_ENABLED 配置。

A418863_1_En_1_Fig19_HTML.gif

图 1-19。

Most of the Required Kernel Parameters are already Set

设置 CONFIG_MEMCG_SWAP_ENABLED = y,保存内核配置文件,如图 1-20 所示。

A418863_1_En_1_Fig20_HTML.gif

图 1-20。

Setting the CONFIG_MEMCG_SWAP_ENABLED Kernel Parameter

接下来,我们需要为内核添加对内存和交换记账的支持。提供给内核的命令行参数可以用下面的命令列出。

cat /proc/cmdline

如图 1-21 所示,内存和交换记账未打开。

A418863_1_En_1_Fig21_HTML.gif

图 1-21。

Listing the Command-Line Parameters

Grub 2 是 Ubuntu 的默认引导加载程序。要打开内存和交换记帐,请在 vi 编辑器中打开/etc/default/grub 文件。GRUB_CMDLINE_LINUX 设置为空字符串,如图 1-22 所示。

A418863_1_En_1_Fig22_HTML.gif

图 1-22。

The /etc/default/grub file

如下设置 GRUB_CMDLINE_LINU,这将在启动时启用内核中的内存和交换记帐。

GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"

修改后的/etc/default/grub 文件如图 1-23 所示。用:wq 命令保存文件。

A418863_1_En_1_Fig23_HTML.gif

图 1-23。

Modified /etc/default/grub file

使用以下命令更新 grub.cfg 文件。

sudo update-grub

grub 配置文件的生成如图 1-24 所示。

A418863_1_En_1_Fig24_HTML.gif

图 1-24。

Generating an Updated Grub Configuration file

重启系统。

sudo reboot

到 Ubuntu Amazon EC2 实例的连接被关闭,如图 1-25 所示。

A418863_1_En_1_Fig25_HTML.gif

图 1-25。

Rebooting Ubuntu Instance

SSH 重新登录到 Ubuntu 实例。重新运行命令以列出命令行内核参数。

cat /proc/cmdline

cgroup _ enable = memory swap account = 1 设置的输出如图 1-26 所示。

A418863_1_En_1_Fig26_HTML.gif

图 1-26。

Updated Settings

设置好必备的内核参数后,接下来我们将启动 Kubernetes 组件 etcd、master 和服务代理。

正在启动 etcd

使用以下 docker run 命令运行 etcd。

sudo docker run --net=host -d gcr.io/google_containers/etcd:2.0.12 /usr/local/bin/etcd --
addr=127.0.0.1:4001 --bind-addr=0.0.0.0:4001 --data-dir=/var/etcd/data

docker 运行命令参数如下(表 1-2 )。

表 1-2。

The docker run Command Parameters to start etcd

| 参数 | 描述 | | --- | --- | | - net =主机 | 利用容器内部的主机容器网络将 Docker 容器连接到网络 | | -d | 在后台启动容器 | | gcr.io/google_containers/etcd:2.0.12 | 容器映像 | | /usr/local/bin/etcd --addr = 127.0.0.1:4001 --bind-addr = 0.0.0.0:4001 --data-dir=/var/etcd/date | 要运行的命令 |

前面命令的输出如图 1-27 所示。

A418863_1_En_1_Fig27_HTML.gif

图 1-27。

Starting etcd

每次启动 Kubernetes 集群管理器时,都需要运行 docker run 命令来启动 etcd。后续启动 etcd 不需要下载如图 1-28 所示的容器镜像。

A418863_1_En_1_Fig28_HTML.gif

图 1-28。

Subsequent Start of etcd does not need to download the container Image again

启动 kubernetes master

Kubernetes 主机使用 kubelet 启动,kube let 还启动其他主机组件 apiserver、调度器、控制器和暂停,这些组件在表 1-3 中讨论。

表 1-3。

The docker run Command Parameters to start etcd

| 主组件 | 描述 | | --- | --- | | appserver(伺服器) | apiserver 接受 API 请求,处理它们,如果需要的话,将结果存储在 etcd 中,并返回结果。 | | 调度程序 | 调度程序监控 API 以发现未调度的 pod,并在节点上调度它们运行,还将同样的情况通知 API。 | | 控制器 | 控制器管理单元的复制级别,在扩大事件中启动新单元,在缩小事件中停止一些单元。 | | 中止 | 暂停会保留 pod 中所有容器或 pod 网络端点的端口映射。 |

用下面的命令运行 Kubernetes master。

sudo docker run \
    --volume=/:/rootfs:ro \
    --volume=/sys:/sys:ro \
    --volume=/dev:/dev \
    --volume=/var/lib/docker/:/var/lib/docker:ro \
    --volume=/var/lib/kubelet/:/var/lib/kubelet:rw \
    --volume=/var/run:/var/run:rw \
    --net=host \
    --pid=host \
    --privileged=true \
    -d \
    gcr.io/google_containers/hyperkube:v1.0.1 \
    /hyperkube kubelet --containerized --hostname-override="127.0.0.1" --address="0.0.0.0" --api-
servers=http://localhost:8080 --config=/etc/kubernetes/manifests

表 1-4 中讨论了 docker 运行命令参数。

表 1-4。

The docker run Command Parameters to start etcd

| 参数 | 描述 | | --- | --- | | -volume =/:/rootfs:ro \-volume =/sys:/sys:ro \-volume =/dev:/dev \-volume =/var/lib/docker/ | 要使用的 Docker 卷 | | - net =主机 | 利用容器内部的主机容器网络将 Docker 容器连接到网络 | | - pid =主机 | 设置 pid 名称空间 | | -特权=真 | 在内核特性和主机访问方面,提供对主机大部分功能的访问 | | -d | 在后台启动容器 | | gcr.io/google_containers/hyperkube:v1.0.1 | 容器映像 | | hyperkube kube let-contained-hostname-override = " 127 . 0 . 0 . 1 "-address = " 0 . 0 . 0 . 0 "-API-servers =`http://localhost:8080`-config =/etc/kubernetes/manifests | 该命令运行 |

启动主机的 docker run 命令的输出如图 1-29 所示。

A418863_1_En_1_Fig29_HTML.gif

图 1-29。

The docker run Command to start Kubernetes Master

每次启动 Kubernetes 集群管理器时,都需要启动主服务器。仅在第一次运行命令时下载容器映像,在随后的运行中不下载映像,如图 1-30 所示。

A418863_1_En_1_Fig30_HTML.gif

图 1-30。

Subsequent starts of Kubernetes Master do not need to download Container image again

正在启动服务代理

要启动服务代理,它是 Kubernetes 服务的代理,使用带有标签的服务选择器提供 pod/s 接口,通过运行以下 docker run 命令启动服务代理。

sudo docker run -d --net=host --privileged gcr.io/google_containers/hyperkube:v1.0.1 /hyperkube proxy -- master=http://127.0.0.1:8080 --v=2

前面命令的命令参数在表 1-5 中讨论。

表 1-5。

The docker run Command Parameters to start service proxy

| 参数 | 描述 | | --- | --- | | -d | 在后台运行容器 | | - net =主机 | 将容器的网络设置为主机的网络 | | -特权 | 在内核特性和主机访问方面,提供对主机大部分功能的访问 | | gcr.io/google_containers/hyperkube:v1.0.1 | 容器映像 | | 超立方体代理-- master= `http://127.0.0.1:8080` --v = 2 | 要运行的命令。主 url 被设置为`http://127.0.0.1:8080`。 |

前面 docker run 命令的输出如图 1-31 所示。

A418863_1_En_1_Fig31_HTML.gif

图 1-31。

Starting the Service proxy

列出非库坞站容器

为 Kubernetes 集群管理器启动的 Docker 容器可以用下面的命令列出。

sudo docker ps

列出的 Docker 容器包括用于服务代理的容器;库伯莱的容器;用于 etcd 的容器;以及分别用于主调度器、控制器和 apiserver 的容器,并暂停如图 1-32 所示。

A418863_1_En_1_Fig32_HTML.gif

图 1-32。

Listing the Docker Containers

可以使用对接容器 id 找到对接容器信息。例如,获取运行控制器的 Docker 容器的容器 id,如图 1-33 所示。

A418863_1_En_1_Fig33_HTML.gif

图 1-33。

Obtaining the Docker Container Id

运行以下命令来查找 Docker 容器的详细信息。

sudo docker inspect 37971b53f2c1

诸如主 ip 和关于运行控制器管理器的 Docker 容器的细节得到如图 1-34 所示的输出。

A418863_1_En_1_Fig34_HTML.gif

图 1-34。

Listing Docker Container Information

安装 kubectl

kubectl 用于控制 Kubernetes 集群管理器,包括运行映像、获取 pod、获取复制控制器、将应用作为服务在指定端口公开,以及扩展集群。用下面的命令下载 Kubectl 二进制文件。

sudo wget https://storage.googleapis.com/kubernetes-release/release/v1.0.1/bin/linux/amd64/kubectl

kubectl 二进制文件被下载,如图 1-35 所示。

A418863_1_En_1_Fig35_HTML.gif

图 1-35。

Installing Kubectl

通过应用+ x 权限使 kubectl 应用可执行。

sudo chmod +x kubectl

将 kubectl 二进制文件移动到/usr/local/bin/目录。

sudo mv kubi ctel/usr/local/bin/

前述命令的输出如图 1-36 所示。

A418863_1_En_1_Fig36_HTML.gif

图 1-36。

Moving and making kubectl Binaries executable

kubectl 命令列出了如图 1-37 所示的用法。

A418863_1_En_1_Fig37_HTML.gif

图 1-37。

Kubectl Command Usage

命令参数也被列出,如图 1-38 所示。

A418863_1_En_1_Fig38_HTML.gif

图 1-38。

Command Parameters for Kubectl

列表服务

以下命令应该列出 Kubernetes 服务。

kubectl get services

kubernetes 服务被列出,如图 1-39 所示。

A418863_1_En_1_Fig39_HTML.gif

图 1-39。

Listing the Kubernetes Service

列出节点

以下命令应该列出 Kubernetes 节点。

kubectl 获取节点

集群中的单个节点被列出,如图 1-40 所示。

A418863_1_En_1_Fig40_HTML.gif

图 1-40。

Listing the Nodes

测试 Kubernetes 安装

要测试 Kubernetes 集群管理器,使用以下命令运行 nginx 应用。

kubectl -s http://localhost:8080 run nginx --image=nginx --port=80

kubectl run 命令的输出列出了复制控制器、容器、映像/sm 选择器和副本,如图 1-41 所示。

A418863_1_En_1_Fig41_HTML.gif

图 1-41。

Running he nginx Application on Kubernetes Cluster

使用 kubectl expose 命令将 nginx 应用复制控制器作为服务公开。

kubectl expose rc nginx --port=80

nginx Kubernetes 服务在端口 80 上运行,如图 1-42 所示。

A418863_1_En_1_Fig42_HTML.gif

图 1-42。

Creating a Kubernetes Service for nginx Application

用 kubectl get svc 命令列出 nginx 服务的详细信息。

kubectl get svc nginx

nginx 服务详情如图 1-43 所示。

A418863_1_En_1_Fig43_HTML.gif

图 1-43。

Listing the Kubernetes Service nginx

可以使用以下命令获取集群 IP。

kubectl get svc nginx --template={{.spec.clusterIP}}

集群 ip 被列为 10.0.0.146,如图 1-44 所示。

A418863_1_En_1_Fig44_HTML.gif

图 1-44。

Listing the Cluster IP

可以使用以下命令调用 web 服务器来利用集群 ip。

curl 10.0.0.146

文本形式的 html 输出如图 1-45 所示。

A418863_1_En_1_Fig45_HTML.gif

图 1-45。

Using curl to invoke Application

摘要

在本章中,我们使用 Docker 安装了 Kubernetes。运行 Ubuntu 的 Amazon EC2 实例用于安装 Docker 和 Kubernetes。运行 nginx 应用只是为了测试 Kubernetes 集群管理器的安装。创建应用、复制控制器和服务的 kubectl 命令将在下一章详细讨论。

二、你好,Kubernetes

Kubernetes 是 Linux 容器的集群管理器。虽然 Kubernetes 支持其他类型的容器,如 Rocket,并且还将增加对更多类型的支持,但我们将只在 Docker 容器的上下文中讨论 Kubernetes。Docker 是一个开源容器虚拟化平台,用于在容器中构建、打包和运行分布式应用,容器是底层操作系统的轻量级快照。特定于应用的 Docker 映像封装了所有需要的软件,包括应用的依赖关系,并用于创建 Docker 容器以运行容器中的应用。Docker 容器相互隔离,拥有自己的网络和文件系统,并提供容器即服务(CaaS)。Docker 类似于基于虚拟化平台(如 Oracle VirtualBox 和 VMWare Player)的虚拟机,因为它是底层操作系统上的虚拟化,但不同之处在于,虽然虚拟机使用整个操作系统,但多个 Docker 容器共享内核并在主机操作系统上独立运行。Docker 容器运行在 Docker 引擎上,Docker 引擎运行在底层操作系统内核上。

在本章中,我们将使用 Hello-World 应用介绍 Kubernetes 的概念。本章包括以下几节。

  • 概观
  • 为什么是 Kubernetes
  • 设置环境
  • 强制创建应用
  • 以声明方式创建应用
  • 将 JSON 用于资源定义

概观

Kubernetes 的概念包括 Pod、服务和复制控制器,将在以下小节中进行定义。

什么是节点?

节点是一台运行 Kubernetes 的机器(物理的或虚拟的), Pods 可以在其上进行调度。该节点可以是主节点,也可以是工作节点之一。在安装 Kubernetes 的前一章中,只使用了一个节点。在后面的章节,第十四章中,我们将讨论如何创建一个包含主节点和工作节点的多节点集群。

什么是集群?

集群是节点的集合,包括运行 Kubernetes 应用的存储等其他资源。一个集群有一个 Kubernetes 主节点和零个或多个工作节点。高可用性集群由多个主节点或主节点组成。

什么是 Pod?

Pod 是并置在一起的容器的集合,形成一个原子单元。多个应用可以在一个 Pod 内运行,尽管 Pod 内的不同容器可以用于相同的应用,但是通常不同的容器用于不同的应用。Pod 是用于管理一组具有共享卷和网络名称空间的容器的高级抽象。Pod 中的所有应用(容器)共享相同的文件系统和 IP 地址,每个应用暴露的端口是不同的。在 Pod 中运行的应用可以在“本地主机”上相互访问。调度和复制是在 Pod 级别而不是在单个容器级别执行的。例如,如果 Pod 为不同的应用定义了两个容器,并且复制级别设置为 1,则 Pod 的单个复制副本由两个容器组成,两个应用各有一个容器。Pods 促进了资源共享和通信,否则在单独运行的 Docker 容器中使用- link 将会实现这些。由多个容器组成的容器通常用于紧密耦合的应用。例如,如果一个nginx应用使用 MySQL 数据库,那么这两个应用能够通过 Kubernetes 在同一个 Pod 中为每个应用运行容器来进行交互。

什么是服务?

服务是一个或多个提供端点的 pod 的外部接口,在端点上可以调用由服务表示的应用。服务托管在单个 IP 地址,但根据服务连接的应用提供零个或多个端点。使用标签选择器将服务连接到 pod。Pod 上有标签,具有与 Pod 标签相同的选择器表达式的服务向外部客户端表示 Pod。外部客户机不知道或不需要知道服务所代表的 pod。外部客户机只需要知道服务的名称和特定应用暴露的端口。该服务基于循环方式将对应用的请求路由到使用标签选择器/选择的一个 pod。因此,服务是对应用集合的高级抽象,留下了将请求路由到哪个 Pod 的细节。服务也可以用于负载均衡。

什么是复制控制器?

复制控制器管理由复制控制器定义中的“副本”设置或命令行上的–replicas参数指定的 pod 复制级别。复制控制器确保 Pod 副本的配置级别在任何给定时间都在运行。如果复制失败或被故意停止,新的复制会自动启动。复制控制器用于扩展集群中的单元。副本是在 Pod 级别定义的,这意味着如果 Pod 由两个容器组成,则一组两个配置的容器构成一个副本。

什么是标签?

标签是标识诸如 Pod、服务或复制控制器之类的资源的键值对:最常见的是 Pod。标签用于标识任务的一组资源或资源子集,例如将它们分配给服务。服务使用标签选择器来选择它们管理的窗格。例如,如果一个 Pod 被标记为“app = helloApp ”,并且服务“选择器”被设置为“app = helloApp ”,则该 Pod 由该服务表示。服务选择器是基于标签的,而不是基于它们管理的应用的类型。例如,一个服务可以代表一个运行 hello-world 应用容器并带有特定标签的 Pod。另一个 Pod 也运行 hello-world 容器,但其标签不同于服务选择器表达式,该服务不会表示该 Pod。并且运行不是 hello-world 应用但是具有与服务选择器相同的标签的应用的第三个 Pod 也将由相同的服务表示。

什么是选择器?

选择器是使用匹配标签来标识资源的键值表达式。如前一小节所述,服务选择器表达式“app = helloApp”将选择所有标签为“app = helloApp”的 pod。虽然通常服务定义一个选择器来选择 pod,但是服务可以被定义为不包括选择器,并且被定义为抽象其他种类的后端。支持两种选择器:基于等式的和基于集合的。选择器可以由多个需求组成,这意味着可以指定由“,”分隔的多个表达式(基于等式或基于集合)。所有的要求必须由匹配的资源来满足,例如要选择的资源的 Pod。像 Pod 这样的资源可以有附加标签,但是必须为要选择的资源指定选择器中的标签。基于等式的选择器更常用,也是本书中使用的,它支持=,!=、运算符,=与同义。

什么是名字?

名称标识了一个资源。名称不同于标签。为了将资源与服务匹配,使用标签而不是名称。

什么是名称空间?

名称空间是名称之上的一个级别,用于区分项目或团队的一组资源,以防止名称冲突。不同命名空间内的资源可以具有相同的名称,但是一个命名空间内的资源具有不同的名称。

什么是卷?

卷是容器文件系统中的一个目录。卷可以用来存储数据。Kubernetes 卷从 Docker 卷演变而来。

为什么是 Kubernetes?

Docker containers 为应用引入了一个新的模块化和流动性级别,提供了对应用(包括依赖项)的打包,以及跨不同环境传输和运行应用。但是随着 Docker 容器在生产中的使用,实际问题变得很明显,例如哪个容器在哪个节点上运行(调度),如何增加/减少应用的运行容器的数量(伸缩),以及如何在容器内通信。Kubernetes 旨在克服容器集群管理的所有这些和其他实际问题。Kubernetes 实时提供动态容器集群编排。Kubernetes 作为集群管理器提供了以下好处。

  • -微服务,将应用分解成更小的、可管理的、可扩展的组件,供具有不同需求的群体使用。
  • -容错群集,其中如果一个 Pod 副本出现故障(例如,由于节点故障),另一个副本会自动启动。
  • -水平扩展,通过修改复制控制器中的“副本”设置或使用kubectl scale命令中的–replicas参数,可以运行 Pod 的更多或更少副本。
  • -更高的资源利用率和效率。
  • -关注点分离。服务开发团队不需要与集群基础设施团队交互。

设置环境

本章需要以下软件。

  • -Docker 引擎(最新版本)
  • -Kubernetes(1.01 版)
  • -Kubernetes(1.01 版)

我们使用了从 AMI Ubuntu Server 14.04 LTS (HVM)创建的 Amazon EC2 Linux 实例,SSD 卷类型- ami-d05e75b8。

SSH 登录到 Ubuntu 界面(公共 IP 地址因用户不同而不同,本章可能会用到多个 IP 地址)。

ssh -i "docker.pem" ubuntu@54.152.82.142

按照第一章所述安装 Docker,启动 Docker 引擎,并使用以下命令验证其状态。

sudo service docker start
sudo service docker status

按照第一章所述,安装 kubectl 并启动 Kubernetes 集群管理器。使用以下命令输出 Kubernetes 集群信息。

kubectl cluster-info

在图 2-1 中,Kubernetes Master 在http://localhost:8080运行。

A418863_1_En_2_Fig1_HTML.gif

图 2-1。

Getting Cluster Info

在下面几节中,我们将使用 Kubernetes 集群管理器运行一个hello-world应用。可以在命令行上使用kubectl工具强制运行应用,或者使用 Pod、复制控制器和服务的定义文件以声明方式运行应用。我们将讨论每一种方法。本章及后续章节都使用 kubectl 工具,完整的命令参考可在 https://cloud.google.com/container-engine/docs/kubectl/ 找到。

强制创建应用

当 Kubernetes 主程序在http://localhost:8080上运行时,如前一节所述,运行下面的kubectl run命令,使用映像tutum/hello-world运行一个hello-world应用。–s选项指定了 Kubernetes API 服务器主机和端口。–image命令参数指定 Docker 映像作为tutum/hello-world运行。–replicas参数指定要创建的副本数量为 1。即使没有指定–replicas参数,也会创建一个复制控制器。默认的副本数量是 1。–port参数将应用所在的容器端口指定为 80。

kubectl -s http://localhost:8080 run hello-world --image=tutum/hello-world --replicas=1 --port=80

一个名为hello-world的新应用容器被创建,如图 2-2 所示。还创建了一个名为“hello-world”的复制控制器。Pod 是隐式创建的,并且标签“run = hello-world”被添加到 Pod 中。创建的副本数量为 1。复制控制器的选择器字段也被设置为“run=hello-world”。由复制控制器管理的 pod 必须指定与在复制控制器级别指定的选择器相同的标签。默认情况下,复制控制器选择器设置为与 Pod 标签相同的表达式。

A418863_1_En_2_Fig2_HTML.gif

图 2-2。

Creating an Application including a Replication Controller and Pod Replica/s

创建的复制控制器可以用以下命令列出。

kubectl get rc

hello-world复制控制器列表如图 2-3 所示。

A418863_1_En_2_Fig3_HTML.gif

图 2-3。

Listing the Replication Controllers

使用以下命令列出创建和启动的 pod。

kubectl get pods

创建的单个 Pod 被列出,如图 2-4 所示。Pod 名称是自动分配的。会列出 Pod 状态“正在运行”,但 Pod 可能仍未就绪且不可用。“就绪”列值 0/1 表示 Pod 中的 1 个容器中有 0 个已就绪,这意味着 Pod 已创建并正在运行,但尚未就绪。Pod 可能需要几秒钟才能准备好。

A418863_1_En_2_Fig4_HTML.gif

图 2-4。

Listing the Pods

几秒钟或一分钟后再次运行相同的命令。

kubectl get pods

如图 2-5 中就绪栏的 1/1 所示,Pod 被列为就绪。“就绪”列中的值 1/1 表示 Pod 中的 1 个容器中的 1 个已经就绪。就绪列值的语法是nReady/nTotal,这意味着 Pod 中所有nTotal容器中的nReady已经就绪。例如,Kubernetes Pod k8s-master-127.0.0.1的就绪列值为 3/3,这意味着 Kubernetes Pod 中的 3 个容器中有 3 个已经就绪。

A418863_1_En_2_Fig5_HTML.gif

图 2-5。

Listing a Pod as ready with all containers in the Pod as ready

运行 Pod 和复制控制器不会隐式创建服务。在下一小节中,我们将为hello-world应用创建一个服务。

创建服务

使用kubectl expose命令创建一个 Kubernetes 服务,该命令从一个 Pod、复制控制器或另一个服务创建一个服务。因为我们创建了一个名为hello-world的复制控制器,所以使用下面的命令创建一个服务,其中公开服务的端口设置为 8080,服务类型为LoadBalancer

kubectl expose rc hello-world --port=8080 --type=LoadBalancer

一个名为hello-world的 Kubernetes 服务被创建,如图 2-6 所示。服务标签和选择器也被设置。图 2-6 中列出的服务选择器被设置为与复制控制器选择器相同的表达式run=hello-world,如图 2-3 所示,这意味着服务管理复制控制器hello-world中的 pod。

A418863_1_En_2_Fig6_HTML.gif

图 2-6。

Creating a Kubernetes Service

不同类型的服务是 ClusterIp、NodePort 和 LoadBalancer,默认为 ClusterIP,如表 2-1 中所述。

表 2-1。

Types of Services

| 通用式 | 描述 | | --- | --- | | ClusterIp(群集 Ip) | 仅使用群集内部 IP。 | | 节点端口 | 除了群集之外,IP 还在群集的每个节点上公开服务。 | | LoadBalancer(负载均衡器) | 除了在集群内部 Ip 和集群上每个节点的端口上公开服务之外,还请求云提供商为服务提供负载均衡器。负载均衡器平衡服务中各单元之间的负载。 |

用下面的命令列出所有 Kubernetes 服务。

kubectl get services

除了用于 kubernetes 集群管理器的“Kubernetes”服务之外,还创建了一个“hello-world”服务,如图 2-7 所示。

A418863_1_En_2_Fig7_HTML.gif

图 2-7。

Listing the Services

描述一个 Pod

使用从kubectl get pods命令结果中的名称列获得的 Pod 名称hello-world-syrqz,使用kubectl describe pod命令列出关于 Pod 的详细信息。

kubectl describe pod hello-world-syrqz

如图 2-8 所示,列出了包括 IP 地址在内的 Pod 的详细信息。Pod 有一个标签 run=hello-world,它与复制控制器selector相同,也与服务selector相同,这意味着复制控制器例如在扩展 Pod 的集群时管理 Pod,服务向外部客户端表示 Pod。

A418863_1_En_2_Fig8_HTML.gif

图 2-8。

Describing a Pod

接下来,我们将使用 IP 字段中列出的 IP 地址172.0.17.2调用应用。

调用 Hello-World 应用

使用图 2-8 中列出的应用 IP,通过以下curl命令,可以调用hello-world应用。

curl 172.17.0.2

应用的 HTML 输出如图 2-9 所示。

A418863_1_En_2_Fig9_HTML.gif

图 2-9。

Invoking a Application using Pod IP with curl

为了在浏览器中显示 HTML 输出,我们需要使用 URL 172.17.0.2:80从浏览器中调用应用。如果 Amazon EC2 Ubuntu 实例上没有浏览器(默认情况下没有),我们需要使用本地端口转发建立一个到应用 IP 地址的 SSH 隧道。获取 Amazon EC2 实例的公共 DNS(示例中的 ec2-52-91-200-41.compute-1.amazonaws.com ),并运行以下命令来建立从本地机器到172.17.0.2:80 host:port的 SSH 隧道。–L表示本地端口转发用于将本地端口 80 转发到172.17.0.2:80

ssh -i "docker.pem" -f -nNT -L 80:172.17.0.2:80 ubuntu@ec2-52-91-200-41.compute-1.amazonaws.com

在本地机器的浏览器中调用 URL http://localhost。来自hello-world应用的 HTML 输出显示如图 2-10 所示。主机名与图 2-5 中的 Pod 名称相同。

A418863_1_En_2_Fig10_HTML.gif

图 2-10。

Invoking the Hello-World Application in a Browser

扩展应用

当我们创建副本设置为 1 的hello-world应用时,默认情况下会创建一个复制控制器。接下来,我们将把 pod 的数量增加到 4 个。kubectl scale命令用于扩展复制控制器。运行以下命令将复制控制器hello-world扩展到 4 个。

kubectl scale rc hello-world --replicas=4

随后,使用以下命令列出 pod。

kubectl get pods

额外的窗格会被列出,但一些新窗格可能会以各种状态列出,如运行但未就绪,或映像就绪和容器创建,如图 2-11 所示。

A418863_1_En_2_Fig11_HTML.gif

图 2-11。

Scaling the Cluster of Pods with the Replication Controller

几秒钟后,再次运行相同的命令来列出 pod。

kubectl get pods

如果吊舱已经启动,所有吊舱都以状态->运行和就绪状态 1/1 列出,如图 2-12 所示。缩放到 4 个副本不会创建 4 个新的 Pod,但是 Pod 的总数会缩放到 4,并且最初创建的单个 Pod 会包含在 4 个新的缩放副本中。

A418863_1_En_2_Fig12_HTML.gif

图 2-12。

Listing all the Pods as Running and Ready

使用以下命令描述hello-world服务。

kubectl describe svc hello-world

如图 2-13 所示,列出服务名称、标签、选择器、类型、IP 和端点。可以使用各种 Pod 副本的端点来调用服务。

A418863_1_En_2_Fig13_HTML.gif

图 2-13。

Describing the Service hello-world

如前所述,为新添加的端点设置带端口转发的 SSH 隧道。下面的命令在 Amazon EC2 实例上建立一个 SSH 隧道,从localhost端口 8081 转发到172.17.0.3:80

ssh -i "docker.pem" -f -nNT -L 8081:172.17.0.3:80 ubuntu@ec2-52-91-200-41.compute-1.amazonaws.com

随后在 url 为http://localhost:8081的本地机器上的浏览器中调用hello-world应用,显示如图 2-14 所示的应用输出。

A418863_1_En_2_Fig14_HTML.gif

图 2-14。

Invoking an Application in a Local Browser

类似地,来自本地机器的以下命令建立了一个 SSH 隧道,在 Amazon EC2 实例上从localhost端口 8082 到172.17.0.4:80进行端口转发。

ssh -i "docker.pem" -f -nNT -L 8082:172.17.0.4:80 ubuntu@ec2-52-91-200-41.compute-1.amazonaws.com

随后使用 url http://localhost:8082调用hello-world应用,显示如图 2-15 所示的应用输出。

A418863_1_En_2_Fig15_HTML.gif

图 2-15。

Invoking the second Service Endpoint in a Local Browser

删除复制控制器

可以使用以下命令删除复制控制器hello-world

kubectl delete rc hello-world

复制控制器被删除,如图 2-16 所示。随后调用以下命令列出复制控制器。

A418863_1_En_2_Fig16_HTML.gif

图 2-16。

Deleting a Replication Controller

kubectl get rc

hello-world复制控制器未列出,如图 2-16 所示。

删除复制控制器会删除复制控制器以及与复制控制器相关联的 pod,但不会删除代表复制控制器的服务。kubectl get services命令仍然列出服务,如图 2-17 所示。

A418863_1_En_2_Fig17_HTML.gif

图 2-17。

Deleting a Replication Controller does not delete the Service

删除服务

要删除服务hello-world,运行以下命令。

kubectl delete svc hello-world

随后调用以下命令来列出服务。

kubectl get services

前两个命令的输出如图 2-18 所示,没有列出hello-world服务。

A418863_1_En_2_Fig18_HTML.gif

图 2-18。

Deleting the hello-world Service

以声明方式创建应用

接下来,我们将使用 Pod、服务和复制控制器的定义文件,以声明方式创建相同的 hello-world 应用。定义文件可以在 YAML 或 JSON 中配置。我们最初使用了 YAML,后来也讨论了 JSON 替代方案。

创建 Pod 定义

创建一个hello-world.yaml文件,并在文件中指定一个 Pod 的定义。对于hello-world应用,使用下面的定义,其中apiVersion映射用于 API 模式版本(v1 ), kind映射是资源并被设置为Pod。元数据映射指定 Pod 的元数据,并将名称设置为hello-world(任意)。spec映射指定了 Pod 行为。spec->-containers映射指定要运行的映像集合。hello-world.yaml为映像tutum/hello-world指定一个容器。容器名被设置为hello-world,容器ports映射是一个端口列表,8080 端口只有一个containerPort映射。

apiVersion: v1
kind: Pod
metadata:
name: hello-world
spec:
  containers:
    -
      image: tutum/hello-world
      name: hello-world
      ports:
        -containerPort: 8080

上述内容等效于以下命令。

kubectl run hello-world --image=tutum/hello-world --port=8080

hello-world.yaml中只使用了少数模式元素。完整的 Pod 模式参见 http://kubernetes.io/v1.1/docs/api-reference/v1/definitions.html#_v1_pod

接下来,使用带有以下kubectl create命令的hello-world.yaml定义文件创建hello-world应用。–validate选项验证 Pod 定义文件。YAML 皮棉验证器( http://www.yamllint.com/ )可用于验证hello-world.yaml中的 YAML 语法。语法验证不会验证定义文件是否符合 Pod 架构。

kubectl create -f hello-world.yaml --validate

名为hello-world的 Pod 被创建,如图 2-19 所示。

A418863_1_En_2_Fig19_HTML.gif

图 2-19。

Creating a Pod using a Definition File

使用以下命令列出 Pod,无论 Pod 是如何创建的,该命令都是相同的。

kubectl get pods

hello-world吊舱被列出,如图 2-20 所示。最初,Pods 可能没有准备好- > 1/1。就绪列值“0/1”意味着 Pod 中的 1 个容器中的 0 个已经就绪。

A418863_1_En_2_Fig20_HTML.gif

图 2-20。

Listing the Pods soon after creating the Pods

几秒钟后再次运行相同的命令。

kubectl get pods

hello-world箱被列为“运行中”状态,就绪状态为“1/1”,这意味着箱中 1 个容器中的 1 个已经就绪,如图 2-21 所示。

A418863_1_En_2_Fig21_HTML.gif

图 2-21。

Listing the Pod as Ready and Running

使用以下命令描述hello-world Pod。

kubectl describe pod hello-world

前面命令的输出如图 2-22 所示。

A418863_1_En_2_Fig22_HTML.gif

图 2-22。

Describing the hello-world Pod

使用 IP 172.17.0.2调用hello-world Pod 应用。

curl 172.17.0.2

来自hello-world应用的 HTML 输出如图 2-23 所示。

A418863_1_En_2_Fig23_HTML.gif

图 2-23。

Invoking the hello-world Application with curl

设置从本地机器到hello-world Pod 的 IP 地址的端口转发。

ssh -i "docker.pem" -f -nNT -L 80:172.17.0.2:80 ubuntu@ec2-52-91-200-41.compute-1.amazonaws.com

随后在本地机器的浏览器中调用 url http://localhost:80来显示应用的 HTML 输出,如图 2-24 所示。默认的超文本传输协议端口为 80,在 URL 中被省略,如图 2-24 所示。

A418863_1_En_2_Fig24_HTML.gif

图 2-24。

Invoking the hello-world Application in a Browser on a local machine

创建服务定义

我们创建了一个 Pod 定义文件并启动了一个 Pod,但是该 Pod 不与任何服务或复制控制器相关联。外部客户端必须直接访问 Pod,并且不能仅通过一个不关联的 Pod 来扩展应用。创建如下所示的服务定义文件hello-world-service.yaml。如果复制和粘贴本章和其他章节中列出的 YAML 文件,建议在应用中使用之前使用 YAML Lint ( http://www.yamllint.com/ )来格式化文件。

apiVersion: v1
kind: Service
metadata:
  labels:
    app: hello-world
  name: hello-world
spec:
  ports:
    -
      name: http
      port: 80
      targetPort: http
  selector:
    app: hello-world
  type: LoadBalancer

服务定义文件的主要映射是kindmetadataspeckind被设置为Service以指示 Kubernetes 服务。标签appname构成了元数据。spec映射包括名为http的端口 80 的ports映射。可选地,可以设置一个targetPort,默认为与端口相同的值。selectorspec中的主映射,指定了用于选择通过服务公开的 pod 的映射。app:hello-world选择器意味着所有标签为app=hello-world的 pod 被选中。定义文件可以在 vi 编辑器中创建,并用:wq命令保存,如图 2-25 所示。

A418863_1_En_2_Fig25_HTML.gif

图 2-25。

Service Definition File hello-world-service.yaml

http://kubernetes.io/v1.1/docs/api-reference/v1/definitions.html#_v1_service 可以找到 Kubernetes 服务模式的完整参考。

使用定义文件和kubectl create命令创建一个服务。

kubectl create -f hello-world-service.yaml

hello-world服务被创建,如图 2-26 所示。

A418863_1_En_2_Fig26_HTML.gif

图 2-26。

Creating the hello-world Service using the Definition File

使用以下命令列出服务。

kubectl get services

除了kubernetes服务外,还列出了hello-world服务,如图 2-27 所示。

A418863_1_En_2_Fig27_HTML.gif

图 2-27。

Listing the hello-world Service

用下面的命令描述hello-world服务。

kubectl describe svc hello-world

列出服务名、名称空间、标签、选择器、类型、Ip,如图 2-28 所示。因为使用 Pod 定义文件创建的hello-world Pod 不包含与服务选择器匹配的标签,所以它不由服务管理。由于hello-world服务没有管理任何 pod,因此没有列出端点。

A418863_1_En_2_Fig28_HTML.gif

图 2-28。

Describing the hello-world Service

创建复制控制器定义

接下来,我们将创建一个复制控制器,并将复制控制器标记为与之前创建的服务选择器相匹配。创建服务定义文件hello-rc.yaml。复制控制器的种类映射是ReplicationControllerspec映射中的replicas子映射被设置为 2,以从spec中指定的 Pod 创建两个副本。模板- >元数据- >标签中至少有一个标签必须与服务定义文件中的服务选择器相匹配,以便服务公开 Pod。因为hello-world服务中的服务选择器是app:hello-world,所以将app:hello-world标签添加到复制控制器模板中。YAML 的 app:hello-world 设置翻译成 app=hello-world。该模板可以定义一个或多个容器,这些容器将被包括在从复制控制器创建的 Pod 中。我们只为映像tutum/hello-world的一个容器包含了容器定义。下面列出了hello-rc.yaml。可以使用 YAML lint ( http://www.yamllint.com/ )来验证 YAML 语法。

apiVersion: v1
kind: ReplicationController
metadata:
  name: hello-world
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: hello-world
    spec:
      containers:
        -
          image: tutum/hello-world
          name: hello-world
          ports:
            -
              containerPort: 8080
              name: http

http://kubernetes.io/v1.1/docs/api-reference/v1/definitions.html#_v1_replicationcontroller 可以获得复制控制器的完整方案。

使用带有kubectl create命令的定义文件创建复制控制器,该命令与用于创建 Pod 和服务的命令相同。

kubectl create -f hello-rc.yaml

随后运行以下命令列出复制控制器。

kubectl get rc

一个hello-world复制控制器被创建并被列出,如图 2-29 所示。根据定义文件中的指定,副本的数量列为 2。

A418863_1_En_2_Fig29_HTML.gif

图 2-29。

Creating a Replication Controller

使用以下命令列出使用复制控制器创建的 pod。

kubectl get pods

从定义文件创建的两个 pod 被列出,如图 2-30 所示。创建了 Pod 定义文件的 Pod 也会列出,但不会与复制控制器相关联。最初,一些或所有新的吊舱可能被列为未准备好,如图 2-30 中一个吊舱的准备好列中的 0/1 值所示。

A418863_1_En_2_Fig30_HTML.gif

图 2-30。

Listing the Pods soon after creating a Replication Controller

几秒钟后再次调用相同的命令来列出窗格。

kubectl get pods

如图 2-31 所示,所有吊舱被列为就绪- > 1/1 并正在运行。

A418863_1_En_2_Fig31_HTML.gif

图 2-31。

Listing all the Pods as Running and Ready

要描述hello-world服务,请运行以下命令。

kubectl describe service hello-world

包括端点在内的服务细节如图 2-32 所示。服务选择器是 app = hello-world,服务端点是 172.17.0.3:8080 和 172.17.0.4:8080。

A418863_1_En_2_Fig32_HTML.gif

图 2-32。

Describing the Service hello-world

前面所有创建hello-world复制控制器的命令,列出了它与图 2-33 中所示的hello-world服务的关联。

A418863_1_En_2_Fig33_HTML.gif

图 2-33。

Summary of Commands to create a Replication Controller

调用 Hello-World 应用

可以使用图 2-33 中服务描述中列出的服务端点来调用与 hello-world 复制控制器和同名服务相关联的 pod。例如,用下面的curl命令调用172.17.0.3端点。

curl 172.17.0.3

Pod 的 HTML 输出得到如图 2-34 所示的输出。

A418863_1_En_2_Fig34_HTML.gif

图 2-34。

HTML Output from invoking the hello-world Application with curl

类似地,用下面的 curl 命令调用 172.17.0.4 端点。

curl 172.17.0.4

另一个 Pod 的 HTML 输出如图 2-35 所示。

A418863_1_En_2_Fig35_HTML.gif

图 2-35。

Invoking another Service Endpoint with curl

要在本地计算机上的浏览器中调用服务端点,请为服务端点配置本地端口转发。

ssh -i "docker.pem" -f -nNT -L 8081:172.17.0.3:8080 ubuntu@ec2-52-91-200-41.compute-1.amazonaws.com
ssh -i "docker.pem" -f -nNT -L 8082:172.17.0.4:8080 ubuntu@ec2-52-91-200-41.compute-1.amazonaws.com

随后在本地机器上的浏览器中调用localhost:8081 URL,如图 2-36 所示,以显示端点172.17.0.3:8080处 Pod 的 HTML 输出。

A418863_1_En_2_Fig36_HTML.gif

图 2-36。

Invoking the hello-world Application in a Local machine Browser with its Service Endpoint

类似地,在本地机器上的浏览器中调用localhost:8082 URL,如图 2-37 所示,以显示端点172.17.0.4:8080处 Pod 的 HTML 输出。

A418863_1_En_2_Fig37_HTML.gif

图 2-37。

Invoking another Service Endpoint in a Browser

扩展应用

例如,要将hello-world复制控制器扩展到 6 个副本,请运行下面的kubectl scale命令。

kubectl scale rc hello-world --replicas=6

如图 2-38 所示的“缩放”输出表示复制控制器已被缩放。

A418863_1_En_2_Fig38_HTML.gif

图 2-38。

Scaling an Application

当复制控制器扩展到 6 个时,hello-world 复制控制器的 pod 数量会增加。要列出窗格,请运行以下命令。

kubectl get pods

除了最初使用 Pod 定义文件创建的hello-world Pod 之外,还列出了六个 Pod,如图 2-39 所示。前面的命令可能需要运行多次才能列出所有状态为 Running、就绪状态为 1/1 的 pod。hello-world Pod 与hello-world复制控制器没有关联,因为它不包含与复制控制器中的选择器标签(与模板标签相同)相匹配的标签。

A418863_1_En_2_Fig39_HTML.gif

图 2-39。

Listing Pods after Scaling

在前面的例子中,我们放大了复制控制器,但是kubectl scale命令也可以用来缩小复制控制器。例如,将hello-world复制控制器缩减为 2 个副本。

kubectl scale rc hello-world --replicas=2

随后列出 POD。

kubectl get pods

除了图 2-40 所示的hello-world Pod 之外,副本的数量被列为 2。

A418863_1_En_2_Fig40_HTML.gif

图 2-40。

Scaling Down to 2 Replicas

将 JSON 用于资源定义

在前面的部分中,我们使用了 YAML 格式来创建 Pod、服务和复制控制器定义文件。定义文件可以用 JSON 格式开发。YAMLToJSON 实用程序( http://yamltojson.com/ )可用于从 YAML 转换为 JSON,JSON lint ( http://jsonlint.com/ )可用于验证 JSON。在 http://jsontoyaml.com/ 也有一个 JSON 到 YAML 的实用程序。列出了hello-world服务的 JSON 定义文件hello-world-service.json:

{
  "apiVersion": "v1",
  "kind": "Service",
  "metadata": {
    "name": "hello-world",
    "labels": {
      "app": "hello-world"
    }
  },
  "spec": {
    "ports": [
      {
        "name": "http",
        "port": 80,
        "targetPort": "http"
      }
    ],
    "selector": {
      "app": "hello-world"
    },
    "type": "LoadBalancer"
  }
}

使用 vi 编辑器创建一个hello-world-service.json文件,并将前面的清单复制并粘贴到该文件中。使用:wq 保存文件,如图 2-41 所示。

A418863_1_En_2_Fig41_HTML.gif

图 2-41。

Service Definition File in JSON Format

删除之前创建的hello-world服务和hello-world复制控制器。运行以下命令,从 JSON 格式定义文件创建服务。

kubectl create –f hello-world-service.json

hello-world服务被创建,如图 2-42 所示。

A418863_1_En_2_Fig42_HTML.gif

图 2-42。

Creating a Service from the JSON Definition File

随后列出所有的 Kubernetes 服务。

kubectl get services

hello-world服务列表如图 2-43 所示。

A418863_1_En_2_Fig43_HTML.gif

图 2-43。

Listing the Service s

复制控制器定义文件hello-rc.json,的 JSON 格式版本如下。

{
  "apiVersion": "v1",
  "kind": "ReplicationController",
  "metadata": {
    "name": "hello-world"
  },
  "spec": {
    "replicas": 2,
    "template": {
      "metadata": {
        "labels": {
          "app": "hello-world"
        }
      },
      "spec": {
        "containers": [
          {
            "image": "tutum/hello-world",
            "name": "hello-world",
            "ports": [
              {
                "containerPort": 8080,
                "name": "http"
              }
            ]
          }
        ]
      }
    }
  }
}

在 vi 编辑器中创建hello-rc.json文件,用:wq 保存,如图 2-44 所示。

A418863_1_En_2_Fig44_HTML.gif

图 2-44。

Creating the hello-rc.json File in vi Editor

删除所有以前创建的 pod 和复制控制器。运行以下命令来创建hello-world复制控制器。

kubectl create –f hello-rc.json

如图 2-45 所示创建hello-world复制控制器。随后运行以下命令列出复制控制器。

A418863_1_En_2_Fig45_HTML.gif

图 2-45。

Creating a Replication Controller from the JSON format Definition File

kubectl get rc

hello-world复制控制器列表如图 2-45 所示。使用以下命令列出复制控制器创建的 pod。

kubectl get pods

由于replicas设置为 2,两个吊舱被列出,如图 2-45 所示。

用下面的命令描述hello-world服务。

kubectl describe svc hello-world

因为hello-world复制控制器上的标签与服务选择器相匹配,所以使用复制控制器创建的两个 pod 由服务来表示,并且在服务中具有端点,如图 2-46 所示。

A418863_1_En_2_Fig46_HTML.gif

图 2-46。

Describing the hello-world Service

使用 curl 命令调用服务端点,如下所示。

curl 172.17.0.2

curl 命令的 HTML 输出如图 2-47 所示。

A418863_1_En_2_Fig47_HTML.gif

图 2-47。

Invoking the hello-world Application with curl

设置到服务端点的本地端口转发。

ssh -i "docker.pem" -f -nNT -L 80:172.17.0.2:8080 ubuntu@ec2-52-91-200-41.compute-1.amazonaws.com

随后在本地机器的浏览器中调用服务端点来显示 HTML 输出,如图 2-48 所示。

A418863_1_En_2_Fig48_HTML.gif

图 2-48。

Displaying hello-world Application HTML in a Browser

摘要

在本章中,我们介绍了 Kubernetes 的概念,如 Pod、服务、复制控制器、标签和选择器。我们还开发了一个 hello-world 应用,既可以在命令行上强制使用,也可以使用定义文件以声明方式使用。我们讨论了定义文件支持的两种不同格式:YAML 和 JSON。在下一章,我们将讨论在 Pod 定义中使用环境变量。

三、使用自定义命令和环境变量

Kubernetes 编排 Docker 容器,Docker 映像的运行指令在Dockerfile中指定。ENTRYPOINT指令指定要运行的命令,而CMD指令指定了ENTRYPOINT命令的默认参数。Kubernetes 提供了两个字段,"Command""Args",为 Pod 定义中的容器映像指定,以覆盖默认设置ENTRYPOINTCMD。我们将在本章中讨论这些字段。我们还将讨论在 Pod 定义的容器映射中使用环境变量和"env"字段映射。

本章包括以下几节。

  • 设置环境
  • 入口点和 CMD 指令
  • Pod 定义中的命令和参数字段
  • 环境变量
  • 使用 Docker 映像中的默认入口点和 CMD
  • 覆盖 Docker 映像中的入口点和 CMD
  • 在命令映射中指定可执行文件和参数
  • 指定 Args 映射中的可执行文件和参数

设置环境

本章使用了以下软件。

  • -Docker 引擎(最新版本)
  • -Kubernetes(1.01 版)
  • -Kubernetes(1.01 版)

按照第一章所述安装 Docker 引擎、Kubernetes 和 Kubectl。使用以下命令启动 Docker 引擎并验证其状态。

sudo service docker start
sudo service docker status

图 3-1 所示的输出表明 Docker 正在运行。

A418863_1_En_3_Fig1_HTML.gif

图 3-1。

Starting Docker and Verifying Its Status

入口点和 CMD 指令

Docker 映像的Dockerfile中的ENTRYPOINT指定映像运行时要运行的命令。ENTRYPOINT有两种形式,在表 3-1 中讨论。一只Dockerfile可能只有一只ENTRYPOINT。如果指定了多个ENTRYPOINT,则运行最后一个ENTRYPOINT条目。

表 3-1。

ENTRYPOINT Forms

| 形式 | 描述 | 格式 | | --- | --- | --- | | 执行表单 | 使用指定的参数运行可执行文件。如果不使用环境变量替换,exec 形式是首选形式。但是如果使用环境变量替换,就必须使用外壳形式。exec 表单不执行任何环境变量替换。 | ENTRYPOINT ["可执行"、" param1 "、" param2"] | | 外壳形式 | 在 shell 中运行命令,并防止任何 CMD 或 run 命令行参数与 ENTRYPOINT 一起使用。shell 形式使用/bin/sh -c 启动 shell,即使没有显式调用 shell。 | ENTRYPOINT 命令 param1 param2 |

CMD指令指定 exec 格式的ENTRYPOINT命令的参数。CMD有三种形式,如表 3-2 所述。一个 Dockerfile 可能只有一个CMD条目。如果指定了多个CMD,则运行最后一个CMD条目。CMD指令可以包括可执行程序。

表 3-2。

CMD Forms

| 形式 | 描述 | 格式 | | --- | --- | --- | | 执行表单 | exec 表单以 JSON 数组格式指定要调用的命令和命令参数。exec 表单不执行环境变量替换。如果要执行环境变量替换,请使用 shell 形式或在 exec 形式中显式调用 shell。在 JSONs 数组格式中,必须用双引号""将名称括起来。 | CMD [“可执行文件”、“param1”、“param2”] | | 入口点的默认参数 | 指定 ENTRYPOINT 命令的默认参数。必须指定入口点和 CMD。必须使用 JSON 数组格式指定 ENTRYPOINT 和 CMD。在 JSONs 数组格式中,必须用双引号""将名称括起来。 | CMD [“param1”,“param2”] | | 外壳形式 | 使用参数调用 shell 来调用指定的命令。该命令作为/bin/sh–c 的子命令调用。 | CMD 命令 param1 param2 |

如果向docker run命令提供命令行参数,这些参数会覆盖CMD指令中的默认参数。ENTRYPOINT指令也可以与帮助脚本结合使用。接下来,我们将讨论两个字段,“command”和“args ”,它们可以分别用于覆盖Dockerfile中的ENTRYPOINTCMD指令。

Pod 定义中的命令和参数字段

Kubernetes 可以覆盖 Dockerfile 文件中指定的ENTRYPOINT(命令)和CMD(参数)指令。Pod 定义文件中的两个字段映射可用于覆盖ENTRYPOINTCMD指令。这些字段是“Command”和“Args”,它们分别覆盖 Dockerfile 的“ENTRYPOINT”和“CMD”指令。基于指定了这些指令和字段中的哪一个,覆盖适用。表 3-3 中讨论了一些超越的例子。

表 3-3。

Examples of Overriding ENTRYPOINT and CMD with Command and Args

|   | ENTRYPOINT(入口点) | 煤矿管理局 | 命令 | 一个参数名 | 二手的 | | --- | --- | --- | --- | --- | --- | | 示例 1 | 是 | 是 | 是 | 是 | Pod 定义文件中的命令和参数字段映射会覆盖 Dockerfile 中的 ENTRYPOINT 和 CMD 指令。 | | 例 2 | 是 | 是 | 不 | 不 | 使用 Dockerfile ENTRYPOINT 命令和 CMD 参数。 | | 例 3 | 是 | 是 | 是 | 不 | 只使用命令中的命令,忽略 Dockerfile ENTRYPOINT 和 CMD 指令。 | | 例 4 | 是 | 是 | 不 | 是 | 入口点中指定的 Docker 映像命令与 Pod 定义的 args 中指定的 Args 一起使用。Dockerfile 的 CMD 中的参数被忽略。 | | 例 5 | 不 | 是 | 不 | 不 | 运行 CMD 指令中的命令和参数。 | | 例 6 | 不 | 是 | 是 | 是 | 使用 Pod 定义文件中的命令和参数字段映射。Dockerfile 中的 CMD 指令被覆盖。 | | 例 7 | 不 | 是 | 不 | 是 | 使用 Pod 定义文件中的 Args 字段映射。Dockerfile 中的 CMD 指令被覆盖。 | | 例 8 | 不 | 是 | 是 | 不 | 使用命令映射中的命令,忽略 Dockerfile CMD 指令。 |

环境变量

Pod 的模式具有指定环境变量的规定。环境变量被指定为“名称”和“值”字段映射,作为容器定义的“env”映射中的一个集合。指定环境变量的格式如下。

spec:
  containers:
    -
    image: "image name"
    name: "container name "
    env:
      -
        name: "env variable 1"
        value: " env variable 1 value"
      -
        name: "env variable 2"
        value: " env variable 2 value"

当 Docker 映像由 Kubernetes 运行时,使用–e将环境变量添加到docker run命令中。如果使用 shell 来运行 Docker image 命令,则使用环境变量替换也可以在“command”和“args”映射中使用环境变量。如果使用了以下一个或多个选项,将调用 shell:

  • -使用入口点或 CMD 的外壳形式
  • -外壳在 ENTRYPOINT 或 CMD 指令中显式调用

在接下来的部分中,我们将使用“Ubuntu”Docker 镜像来演示如何覆盖默认的ENTRYPOINT命令和默认的CMD参数。我们将从使用默认的ENTRYPOINTCMD指令开始。

使用 Docker 映像中的默认入口点和 CMD

Ubuntu 镜像的Dockerfile不提供ENTRYPOINT指令,但是CMD指令被设置为CMD ["/bin/bash"]。在本节的示例中,我们将创建一个不覆盖 Docker 映像中的ENTRYPOINTCMD指令的 Pod 定义。如下创建一个 Pod 定义文件,映像为“ubuntu ”,并设置一些环境变量。

apiVersion: v1
kind: Pod
metadata:
  name: "hello-world"
  labels:
    app: "helloApp"
spec:
  restartPolicy: Never
  containers:
    -
      image: "ubuntu"
      name: "hello"
      ports:
  containerPort: 8020
      env:
        -
          name: "MESSAGE1"
          value: "hello"
        -
          name: "MESSAGE2"
          value: "kubernetes"

可以在 vi 编辑器中创建env.yaml文件,并用:wq 命令保存,如图 3-2 所示。

A418863_1_En_3_Fig2_HTML.gif

图 3-2。

A Pod definition file env.yaml to demonstrate Environment Variables

运行以下命令,从定义文件env.yaml创建一个 Pod。

kubectl create –f env.yaml

hello-world pod 被创建,如图 3-3 所示。运行以下命令列出窗格。

A418863_1_En_3_Fig3_HTML.gif

图 3-3。

Creating and listing a Pod

kubectl get pods

hello-world pod 被创建,但创建的 Docker 容器被列为“正在创建”,如图 3-3 所示。

当 Docker 容器被创建时,STATUS列值转变为“运行中”,READY列值变为 1/1,这表示 Pod 中的 1 个容器中的 1 个准备好了,这在图 3-4 中没有示出,因为此后READY状态迅速转变为 0/1。Pod 命令/参数运行后,Pod 终止,STATUS变为ExitCode:0,如图 3-4 所示。

A418863_1_En_3_Fig4_HTML.gif

图 3-4。

After the Command/Args have run, a Pod terminates and the Pod’s Status becomes ExitCode:0

运行以下命令列出 Pod 的输出。

kubectl logs hello-world

由于“Ubuntu”Docker 镜像中的默认CMD ["/bin/bash"]只是使用/bin/bash,对 bash shell 的调用,所以不会产生任何输出,如图 3-5 所示。

A418863_1_En_3_Fig5_HTML.gif

图 3-5。

No output generated with Default CMD [“/bin/bash”] in “ubuntu” Docker Image

覆盖入口点和 CMD

在第二个例子中,我们将使用 Pod 定义文件中的CommandArgs映射来覆盖Dockerfile中的ENTRYPOINTCMD。结合使用ENTRYPOINT和 CMD 将有助于我们为映像指定默认的可执行文件,并且它还将为该可执行文件提供默认的参数。环境变量替换用于带有$(VARIABLE_NAME)语法的MESSAGE1MESSAGE2环境变量。

command: ["/bin/echo"]
args: [" $(MESSAGE1)", " $(MESSAGE2)"]

列出env.yaml Pod 定义文件:

apiVersion: v1
kind: Pod
metadata:
  name: "hello-world"
  labels:
    app: "helloApp"
spec:
  restartPolicy: Never
  containers:
    -
      image: "ubuntu"
      name: "hello"
      ports:
          -
          containerPort: 8020
      env:
        -
          name: "MESSAGE1"
          value: "hello"
        -
          name: "MESSAGE2"
          value: "kubernetes"
      command: ["/bin/echo"]
      args: [" $(MESSAGE1)", " $(MESSAGE2)"]

可以在 vi 编辑器中打开和修改env.yaml文件,并使用:wq 命令保存,如图 3-6 所示。

A418863_1_En_3_Fig6_HTML.gif

图 3-6。

Modifying env.yaml in a vi Editor

首先,我们需要用下面的命令删除第一个例子中创建的hello-world pod。

kubectl delete pod hello-world

hello-world pod 被删除,如图 3-7 所示。

A418863_1_En_3_Fig7_HTML.gif

图 3-7。

Deleting the hello-world Pod

运行kubectl create命令,从定义文件env.yaml创建一个 Pod。

kubectl create –f env.yaml

hello-world Pod 被创建,如图 3-8 所示。

A418863_1_En_3_Fig8_HTML.gif

图 3-8。

Creating the hello-world Pod from definition file env.yaml

运行kubectl get命令列出窗格。

kubectl get pods

hello-world吊舱被列出,如图 3-9 所示。如图 3-9 所示,Pod 从“运行”的STATUS快速转换到ExitCode:0

A418863_1_En_3_Fig9_HTML.gif

图 3-9。

Listing the Pods with transitioning STATUS value

运行以下命令列出 Pod 的输出。

kubectl logs hello-world

使用替换从环境变量MESSAGE1MESSAGE2创建的消息如图 3-10 所示。

A418863_1_En_3_Fig10_HTML.gif

图 3-10。

Outputting Message Generated from Environment Variables using Value Substitution

在命令映射中指定可执行文件和参数

在第三个示例中,指定可执行文件和参数都在 Pod 定义文件的命令映射中指定。环境变量替换用于MESSAGE1MESSAGE2环境变量。如果使用了环境变量语法$(VARIABLE_NAME),就不需要显式地调用/启动 shell,这正是我们所使用的。

command: ["/bin/echo", " $(MESSAGE1)", " $(MESSAGE2)"]

列出env.yaml Pod 定义文件:

apiVersion: v1
kind: Pod
metadata:
  name: "hello-world"
  labels:
    app: "helloApp"
spec:
  restartPolicy: Never
  containers:
    -
      image: "ubuntu"
      name: "hello"
      ports:
          -
          containerPort: 8020
      env:
        -
          name: "MESSAGE1"
          value: "hello"
        -
          name: "MESSAGE2"
          value: "kubernetes"
      command: ["/bin/echo", " $(MESSAGE1)", " $(MESSAGE2)"]

可以在 vi 编辑器中打开和修改env.yaml文件,并使用:wq 命令保存,如图 3-11 所示。

A418863_1_En_3_Fig11_HTML.gif

图 3-11。

The Command mapping with both the Command Executable and the Parameters

运行kubectl create命令,从定义文件env.yaml创建一个 Pod。

kubectl create –f env.yaml

hello-world pod 被创建,如图 3-12 所示。运行kubectl get命令列出 pod。

A418863_1_En_3_Fig12_HTML.gif

图 3-12。

Creating and Listing the Pod with Definition file from Figure 3-11

kubectl get pods

如图 3-12 所示,hello-world pod 被列出,尽管最初 Pod STATUS未被列为“运行中”。Pod 快速转换到 1/1 的READY值,然后是 0/1。图 3-12 中未显示 1/1 就绪值,因为它快速转换到 0/1。命令运行后,Pod 终止,STATUS变为ExitCode:0,如图 3-12 所示。

随后调用以下命令列出 Pod 生成的输出。

kubectl get logs

环境变量MESSAGE1MESSAGE2创建的消息被列出,如图 3-13 所示。

A418863_1_En_3_Fig13_HTML.gif

图 3-13。

Message output by Pod created in Figure 3-12

指定 Args 映射中的可执行文件和参数

在第四个例子中,指定可执行文件和 Pod 定义文件中的Args映射中的参数,作为覆盖Dockerfile中的CMD指令的结果。环境变量替换用于环境变量语法为$(VARIABLE_NAME)MESSAGE1MESSAGE2环境变量。

args: ["/bin/echo", " $(MESSAGE1)", " $(MESSAGE2)"]

列出env.yaml Pod 定义文件:

apiVersion: v1
kind: Pod
metadata:
  name: "hello-world"
  labels:
    app: "helloApp"
spec:
  restartPolicy: Never
  containers:
    -
      image: "ubuntu"
      name: "hello"
      ports:
          -
          containerPort: 8020
      env:
        -
          name: "MESSAGE1"
          value: "hello"
        -
          name: "MESSAGE2"
          value: "kubernetes"
      args: ["/bin/echo", " $(MESSAGE1)", " $(MESSAGE2)"]

可以在 vi 编辑器中打开和修改env.yaml文件,并使用:wq 命令保存,如图 3-14 所示。

A418863_1_En_3_Fig14_HTML.gif

图 3-14。

The args Mapping in the Pod definition file specifies both the Command Executable and the Parameters

必须删除前一示例中创建的hello-world Pod,否则在运行kubectl create命令时会产生如图 3-15 所示的错误。

A418863_1_En_3_Fig15_HTML.gif

图 3-15。

Error Generated if hello-world Pod already exists

运行kubectl create命令,从定义文件env.yaml创建一个 Pod。

kubectl create –f env.yaml

该命令的输出如图 3-16 所示。

A418863_1_En_3_Fig16_HTML.gif

图 3-16。

Creating a Pod from definition file in Figure 3-14

hello-world pod 被创建,如图 3-17 所示。运行kubectl get命令列出 pod。

A418863_1_En_3_Fig17_HTML.gif

图 3-17。

The Pod terminates and its Status transitions to ExitCode:0 after the command has run

kubectl get pods

hello-world吊舱被列出,如图 3-17 所示。Pod 快速转换到就绪值 1/1,然后是 0/1。图 3-17 中未显示 1/1 就绪值,因为它快速过渡到 0/1。命令运行后,Pod 终止,状态变为 ExitCode:0,如图 3-17 所示。

随后调用以下命令列出 Pod 生成的输出。

kubectl get logs

MESSAGE1MESSAGE2的环境变量替换创建的消息被列出,如图 3-18 所示。

A418863_1_En_3_Fig18_HTML.gif

图 3-18。

Outputting the Message Generated by Pod

摘要

在本章中,我们讨论了 Docker 映像Dockerfile中的ENTRYPOINTCMD指令:当映像在 Kubernetes Pod 中运行时,这些指令用于运行带有默认参数的默认命令。我们还讨论了 Pod 定义文件中的CommandArgs映射,它们可以用来覆盖ENTRYPOINTCMD指令。我们讨论了用 Pod 定义文件中的“command”和“args”字段映射覆盖“Ubuntu”Docker 映像的默认指令的各种例子。我们还演示了在 Pod 定义文件中使用环境变量。在下一章,我们将讨论在 Kubernetes 中使用 MySQL 数据库。

四、使用 MySQL 数据库

MySQL 数据库是最常用的开源数据库。Docker 映像“mysql”可用于创建运行 MySQL 数据库实例的 Docker 容器。为单个 MySQL 实例或多个实例单独运行 Docker 缺乏调度多个实例、伸缩和为外部客户机提供服务的功能。在本章中,我们将讨论如何使用 Kubernetes 容器集群管理器来克服所有这些缺陷。

  • 设置环境
  • 创建服务
  • 创建复制控制器
  • 列出 POD
  • 列出日志
  • 描述服务
  • 启动交互式 Shell
  • 启动 MySQL CLI
  • 创建数据库表
  • 退出 MySQL CLI 和交互式 Shell
  • 缩放副本
  • 删除复制控制器

设置环境

本章需要以下软件。

  • -Docker 引擎(最新版本)
  • -库服务器群集管理器 1.01 版
  • -Kubernetes(1.01 版)
  • -MySQL dock image(最新版本)

我们使用了从 AMI Ubuntu Server 14-04 LTS (HVM)创建的 Amazon EC2 实例,SSD 卷类型- ami-d05e75b8 来安装所需的软件。安装 Docker、Kubernetes 和 Kubectl 的过程在第一章中讨论。获取 Amazon EC2 实例的公共 IP 地址,如图 4-1 所示。

A418863_1_En_4_Fig1_HTML.gif

图 4-1。

Obtaining the Public IP Address

SSH 使用公共 IP 地址登录 Ubuntu 实例,对于不同的用户,这个地址是不同的。

sh -i "docker.pem" ubuntu@52.90.43.0

启动 Docker 引擎并验证其状态。

sudo service docker start
sudo service docker status

Docker 引擎应被列为“正在运行”,如图 4-2 所示。

A418863_1_En_4_Fig2_HTML.gif

图 4-2。

Starting Docker and Verifying Its Status

创建服务

在本节中,我们将使用一个定义文件创建一个 Kubernetes 服务。我们使用了 YAML 格式的定义文件,但是也可以使用 JSON。创建一个名为mysql-service.yaml的服务定义文件,并将下面的清单复制到该文件中。在服务的spec字段映射中,“选择器”表达式被设置为app: "mysql-app,",它被翻译为服务选择器 app=mysql-app,这意味着服务将流量路由到标签为app=mysql-app的 pod。如果selector表达式为空,则选择所有窗格。在端口列表中,公开服务的端口被设置为 3306。并且该服务有一个标签app: "mysql-app"kind field映射必须有值“服务”

apiVersion: v1
kind: Service
metadata:
-name: "mysql"
-labels:
  app: "mysql-app"
spec:
-ports:
  # the port that this service should serve on
  - port: 3306
-# label keys and values that must match in order to receive traffic for this service
-selector:
  app: "mysql-app"

服务模式在 http://kubernetes.io/v1.1/docs/api-reference/v1/definitions.html#_v1_service 可用。将 YAML 定义文件中的selector字段设置为app: "mysql-app"意味着所有具有 YAML 定义文件标签设置app: "mysql-app"的 pod 都由该服务管理。使用定义文件和kubectl create命令创建服务。

kubectl create -f mysql-service.yaml

创建了mysql服务,输出是“服务/mysql ”,如图 4-3 所示。

A418863_1_En_4_Fig3_HTML.gif

图 4-3。

Creating a Service for MySQL Database

使用以下命令列出服务。

kubectl get services

mysql服务列表如图 4-4 所示。

A418863_1_En_4_Fig4_HTML.gif

图 4-4。

Listing the mysql Service

创建复制控制器

在本节中,我们将创建一个复制控制器,该控制器由上一节中创建的服务管理。创建一个名为mysql-rc.yaml的复制控制器定义文件,并将下面/下一个清单复制到该文件中。kind字段映射必须具有值“ReplicationController”复制控制器在metadata字段映射中有一个标签app: "mysql-app"。如果标签为空,则默认为复制控制器管理的单元的标签。"spec"字段映射定义了复制控制器,并包括用于要创建的副本数量的"replicas"字段映射。在下面/下一个清单中,replicas被设置为 1。默认的副本数量也是 1。spec包括一个名为app: "mysql-app,"selector field映射,它选择所有标签为app: "mysql-app"的 pod,供复制控制器管理并计入“副本”设置。除了选择器之外,Pod 还可以有其他标签,但是必须包括要由复制控制器管理的复制控制器的选择器表达式。类似地,复制控制器可以管理不以复制控制器定义文件启动的 pod。

YAML 定义文件中的标签和选择器表达式设置并不这样使用,而是通过用“=”替换“:”来转换为标签/选择器。比如服务/复制控制器选择器设置 app:“MySQL-app”变成选择器 app = mysql-app 选择器和标签设置 app:“MySQL-app”变成标签 app = mysql-app。

如果未指定selector,模板上的标签将用于匹配 pod,并计入“副本”设置。"template"字段映射定义了由复制控制器管理的 Pod。在template字段中的spec字段映射指定了 Pod 的行为。在"spec"字段中的"containers"字段映射定义了要创建的容器的集合/列表,包括映像、环境变量(如果有的话)以及用于每个容器的端口。

我们需要为 MySQL 数据库复制控制器使用一个环境变量。Docker 映像“mysql”需要(强制)环境变量MYSQL_ROOT_PASSWORD来运行 MySQL 数据库的 Docker 容器。变量MYSQL_ROOT_PASSWORDroot用户设置密码。环境变量通过containers字段列表中的"env"映射来设置。一个env映射由一个name映射和一个value映射组成。环境变量MYSQL_ROOT_PASSWORD的设置如下所示。"ports"字段集合包括端口 3306 的containerPort映射。YAML 文件中的缩进和连字符必须格式良好,下面的列表应被复制并在 YAML Lint ( http://www.yamllint.com/ )中进行语法验证。YAML lint 只验证语法,不验证 pod 定义字段是否符合 Pod 的模式。Pod 模式在 http://kubernetes.io/v1.1/docs/api-reference/v1/definitions.html#_v1_podspec 可用。

---
apiVersion: v1
kind: ReplicationController
metadata:
  labels:
    app: "mysql-app"
spec:
  replicas: 1
  selector:
    app: "mysql-app"
  template:
    metadata:
      labels:
        app: "mysql-app"
    spec:
      containers:
      -
        env:
          -
            name: "MYSQL_ROOT_PASSWORD"
            value: "mysql"
        image: "mysql"
        name: "mysql"
        ports:
          -
            containerPort: 3306

可以在 vi 编辑器中创建mysql-rc.yaml定义文件,并用:wq 命令保存,如图 4-5 所示。

A418863_1_En_4_Fig5_HTML.gif

图 4-5。

Definition File for Replication Controller

kubectl create命令从服务定义文件创建一个复制控制器。

kubectl create -f mysql-rc.yaml

如图 4-6 中的输出所示,mysql复制控制器被创建。

A418863_1_En_4_Fig6_HTML.gif

图 4-6。

Creating a Replication Controller for MySQL Database

使用以下命令列出复制。

kubectl get rc

mysql复制控制器包括容器名、映像名、选择器表达式(app=mysql-app)和副本数量,如图 4-7 所示。

A418863_1_En_4_Fig7_HTML.gif

图 4-7。

Listing the MySQL Replication Controller

要描述mysql复制控制器,运行以下命令。

kubectl describe rc mysql

复制控制器名称、命名空间、映像、选择器、标签、副本、pod 状态和事件会被列出,如图 4-8 所示。

A418863_1_En_4_Fig8_HTML.gif

图 4-8。

Describing the MySQL Replication Controller

列出 POD

可以使用以下命令列出创建的 pod。

kubectl get pods

如图 4-9 所示,复制控制器创建的 2 个副本被列出。最初,pod 可能不会被列为就绪 1/1。几秒钟后运行前面的命令,如果需要可以多次运行,以列出所有准备就绪的单元。

A418863_1_En_4_Fig9_HTML.gif

图 4-9。

Listing the Pod/s for MySQL Database

列出日志

使用以下命令列出一个 pod 的 Pod 日志:例如,mysql-wuo7x pod。

kubectl logs mysql-wuo7x

Pod 日志列表如图 4-10 所示。

A418863_1_En_4_Fig10_HTML.gif

图 4-10。

Listing the Logs generated by the Pod for MySQL Database

如图 4-11 所示,MySQL 服务器被列为已启动并“准备连接”。

A418863_1_En_4_Fig11_HTML.gif

图 4-11。

Listing mysqld as Ready for Connections

描述服务

要描述mysql服务,请运行以下命令。

kubectl describe svc mysql

服务名称、命名空间、标签、选择器、类型、Ip、端口和端点都会列出。因为副本数量设置为 1,所以仅列出一个端点,如图 4-12 所示。

A418863_1_En_4_Fig12_HTML.gif

图 4-12。

Describing the MySQL Service

启动交互式 Shell

Bash 是随 Linux 和 GNU 操作系统(OS)发布的 Bourne shell 的免费版本。对于在Dockerfile中的FROM指令中指定的以 Linux OS 映像作为基础映像的 Docker 映像,可以使用 Bash shell 访问 Docker 容器中运行的软件。"mysql" Docker 映像基于"debian"映像,因此支持通过 bash 交互式 shell 访问 Docker 容器中运行的软件。

接下来,我们将启动一个交互式 shell 来启动 MySQL CLI。但是首先我们需要获得一个运行 MySQL 的容器的容器 id。运行以下命令列出 Docker 容器。

sudo docker ps

图 4-13 中列出了mysql映像的 Docker 容器。

A418863_1_En_4_Fig13_HTML.gif

图 4-13。

Listing the Docker Containers

使用前面命令输出中的 Docker 容器 id,启动一个交互式 shell。

sudo docker exec -it 526f5d5f6c2e bash

交互式 shell 或 tty 启动,如图 4-14 所示。

A418863_1_En_4_Fig14_HTML.gif

图 4-14。

Starting the Interactive Terminal

启动 MySQL CLI

在交互式 shell 中运行以下命令,以 root 用户身份启动 MySQL CLI。

mysql –u root –p

当提示输入密码时:将密码设置为环境变量MYSQL_ROOT_PASSWORD的值,在mysql-rc.yaml定义文件中设置为“mysql”。MySQL CLI 启动,如图 4-15 所示。

A418863_1_En_4_Fig15_HTML.gif

图 4-15。

Starting the MySQL CLI Shell

使用以下命令列出数据库。

show databases;

图 4-16 中显示的默认数据库包括"mysql"数据库,我们将用它来创建一个数据库表。其他数据库是系统数据库,不应用于用户表。

A418863_1_En_4_Fig16_HTML.gif

图 4-16。

Listing the Databases

使用以下命令将数据库“mysql”设置为当前数据库。

use mysql

如图 4-17 中的“数据库已更改”输出所示,数据库被设置为mysql

A418863_1_En_4_Fig17_HTML.gif

图 4-17。

Setting the Database

创建数据库表

接下来,用下面的 SQL 语句创建一个名为Catalog的数据库表。

CREATE TABLE Catalog(CatalogId INTEGER PRIMARY KEY,Journal VARCHAR(25),Publisher VARCHAR(25),Edition VARCHAR(25),Title VARCHAR(45),Author VARCHAR(25));

使用下面的 SQL 语句向Catalog表添加一行数据。

INSERT INTO Catalog VALUES('1','Oracle Magazine','Oracle Publishing','November December 2013','Engineering as a Service','David A. Kelly');

创建Catalog表并添加一行数据,如图 4-18 所示。

A418863_1_En_4_Fig18_HTML.gif

图 4-18。

Creating a MySQL Database Table

随后运行以下 SQL 语句来查询数据库表Catalog

SELECT * FROM Catalog;

添加的单行数据被列出,如图 4-19 所示。

A418863_1_En_4_Fig19_HTML.gif

图 4-19。

Querying the Database Table

退出 MySQL CLI 和交互式 Shell

使用“quit”命令退出 MySQL CLI。

quit

使用“退出”命令退出交互终端。

exit

前面命令的输出如图 4-20 所示。

A418863_1_En_4_Fig20_HTML.gif

图 4-20。

Exiting the MySQL CLI Shell and Docker Container Interactive Shell

缩放副本

Kubernetes 的主要优势之一是能够扩展集群中 MySQL 实例的数量。运行下面的kubectl scale命令将副本从 1 扩展到 4。

kubectl scale rc mysql --replicas=4

随后运行以下命令来列出窗格。

kubectl get pods

MySQL 数据库的 Pods 数量增加到 4 个,如图 4-21 所示。一些吊舱可能被列为就绪- > 0/1,这意味着吊舱尚未就绪。当 READY 变为 1/1 时,可以访问 Pod。0/1 值意味着箱中的 1 个 Docker 容器中的 0 个准备好了,类似地,1/1 值意味着 1 个容器中的 1 个准备好了。如果 Pod 中的所有 n 个容器都在运行,则就绪列值的一般语法是 n/n 形式。Pod 的状态必须是“正在运行”才能被视为可用。

A418863_1_En_4_Fig21_HTML.gif

图 4-21。

Scaling the Pod Replicas to Four

要描述mysql服务,运行以下命令。

kubectl describe svc mysql

服务描述与之前相同,只是端点的数量增加到了 4 个,如图 4-22 所示。

A418863_1_En_4_Fig22_HTML.gif

图 4-22。

Describing the MySQL Service After Scaling the Pod Replicas

命令“scale”还允许我们为所需的缩放操作指定一个或多个前提条件。支持以下(表 4-1 )前提条件。

表 4-1。

Preconditions for the ‘kubernetes scale’ command

| 前提 | 描述 | | --- | --- | | -当前副本 | 要执行的缩放的当前副本数。 | | -资源-版本 | 与要执行的缩放匹配的资源版本。 |

删除复制控制器

要删除复制控制器mysql,请运行以下命令。

kubectl delete rc mysql

复制控制器被删除,如图 4-23 所示。每当用于创建或删除工件(Pod、服务或复制控制器)的kubectl命令输出具有工件类型/工件名称的形式时,这意味着该命令已经成功创建/删除了 Pod/服务/复制控制器。

A418863_1_En_4_Fig23_HTML.gif

图 4-23。

Deleting the Replication Controller

随后运行以下命令来获取复制控制器。mysql rc 未列出,如图 4-24 所示。

A418863_1_En_4_Fig24_HTML.gif

图 4-24。

Describing the Service after Deleting the Replication Controllers

kubectl get rc

用下面的命令再次描述服务mysql

kubectl describe svc mysql

没有如图 4-24 所示的“端点”被列出,因为当管理它们的复制控制器被删除时,所有的 pod 也被删除。

摘要

在本章中,我们讨论了使用 Kubernetes 集群管理器编排 MySQL 数据库集群。我们创建了一个 Kubernetes 服务来代表一个基于 MySQL 的 Pod。“MySQL”Docker 映像用于创建一个 Pod。我们使用复制控制器为 MySQL base Pods 创建副本。最初,副本的数量设置为 1。我们使用一个运行 MySQL 实例的 Docker 容器来启动 MySQL CLI 并创建一个数据库表。随后,我们使用复制控制器将副本数量扩展到 4 个。缩放后,副本的数量以及 MySQL 实例的数量变为 4。复制控制器在复制失败或复制被用户关闭时维持复制级别。本章还演示了环境变量的使用。运行 Docker 映像“mysql”的容器需要使用MYSQL_ROOT_PASSWORD环境变量,我们在复制控制器的 Pod 规范中设置了MYSQL_ROOT_PASSWORD环境变量。在下一章,我们将讨论使用另一个开源数据库,PostgreSQL 数据库。

五、使用 PostgreSQL 数据库

PostgreSQL 是一个开源的对象关系数据库。PostgreSQL 在数据量和并发用户数量方面都是可伸缩的。PostgreSQL 在多个 Apache Hadoop 生态系统项目(如 Apache Sqoop)中受支持,并可用于 Apache Hive Metastore。PostgreSQL 9.5 提供了几个新特性,比如支持UPSERTBRIN索引、更快的排序,以及用于获取大型表的统计样本的TABLESAMPLE子句。在本章中,我们将讨论使用 Kubernetes 集群管理器创建 PostgreSQL 9.5 集群。我们将讨论创建和扩展 PostgreSQL 集群的命令式方法和声明式方法。本章包括以下几节。

  • 设置环境
  • 以声明方式创建 PostgreSQL 集群
  • 强制创建 PostgreSQL 集群

设置环境

我们在本章中使用了与其他章节相同类型的 Amazon EC2 实例,一个基于 Ubuntu Server 14.04 LTS (HVM),SSD 卷类型- ami-d05e75b8 AMI 的实例。本章需要以下软件。

  • -Docker 引擎(最新版本)
  • -库服务器群集管理器 1.01 版
  • -Kubernetes(1.01 版)
  • -Docker 映像“postgres”(最新版本)

安装所需软件、启动 Docker 引擎和 Kubernetes 集群管理器的过程将在第一章中讨论。要安装软件,首先我们需要登录 Amazon EC2 实例。获取 Amazon EC2 实例的公共 IP 地址,如图 5-1 所示。

A418863_1_En_5_Fig1_HTML.gif

图 5-1。

Obtaining the Public IP Address

使用公共 IP 地址 SSH 登录到 Ubuntu 实例。

ssh -i "docker.pem" ubuntu@52.91.60.182

启动 Docker 引擎并验证其状态。

sudo service docker start
sudo service docker status

如图 5-2 所示,Docker 应显示为“正在运行”。

A418863_1_En_5_Fig2_HTML.gif

图 5-2。

Starting Docker

使用以下命令列出服务。

kubectl get services

kubernetes 服务应该被列出,如图 5-3 所示。

A418863_1_En_5_Fig3_HTML.gif

图 5-3。

Listing the Kubernetes Services

以声明方式创建 PostgreSQL 集群

在下面的小节中,我们将以声明的方式创建和管理 PostgreSQL 集群,这意味着我们将使用定义文件。定义文件可以基于 YAML 格式或 JSON 格式。我们将使用 YAML 格式。建议首先创建服务,以便随后创建的任何 pod 都有一个服务来代表它们。如果首先创建 RC(复制控制器),则在创建服务之前,pod 不可用。

创建服务

创建一个服务定义文件postgres-service.yaml,并将下面的清单复制到该文件中。服务的"spec"字段映射指定了服务的行为。服务公开的端口在"ports"字段映射中定义。只有端口 5432 是公开的,因为 PostgreSQL 在端口 5432 上运行。selector表达式被设置为app: "postgres"。所有带有标签app=postgres的 pod 都由该服务管理。

apiVersion: v1
kind: Service
metadata:
  name: "postgres"
  labels:
    app: "postgres"
spec:
  ports:
    - port: 5432
  selector:
    app: "postgres"

可以使用 vi 编辑器创建postgres-service.yaml文件,并使用:wq 命令保存,如图 5-4 所示。

A418863_1_En_5_Fig4_HTML.gif

图 5-4。

Service Definition File postgres-service.yaml

使用带有postgres-service.yaml定义文件的kubectl create命令创建服务。

kubectl create -f postgres-service.yaml

随后列出服务。

kubectl get services

也列出 POD。

kubectl get pods

第一个命令的输出services/postgres表示服务已经创建。第二个命令列出了在端口 5432 运行的postgres服务,如图 5-5 所示。还列出了服务的 IP 地址。单独创建一个服务并不会单独创建一个 Pod,只会列出 Kubernetes 的 Pod。一个服务只管理或提供一个 pod 接口,该 pod 的标签与服务中的selector表达式相匹配。

A418863_1_En_5_Fig5_HTML.gif

图 5-5。

Creating a Service and listing the Service

用下面的命令描述服务postgres

kubectl describe svc postgres

服务名、名称空间、标签、选择器、类型、IP 地址、公开的端口和端点都会列出。因为没有 Pods 最初与服务相关联,所以没有列出端点,如图 5-6 所示。

A418863_1_En_5_Fig6_HTML.gif

图 5-6。

Describing the postgres Service

创建复制控制器

在本节中,我们将为复制控制器创建一个定义文件。创建一个名为postgres-rc.yaml的定义文件。定义文件具有表 5-1 中讨论的字段。

表 5-1。

Replication Controller Definition File postgres-rc.yaml

| 田 | 价值 | 描述 | | --- | --- | --- | | apiVersion(堆叠版本) | 第五颅神经的眼支 | API 版本。 | | 种类 | 复制控制器 | 将文件定义为复制控制器。 | | 元数据 |   | 复制控制器的元数据。 | | 元数据->名称 |   | 复制控制器的名称。必须指定名称或 generateName 字段。generateName 字段是在自动生成的名称中使用的前缀。 | | 投机 |   | 复制控制器的规格。 | | 规格->副本 | Two | 要创建的 Pod 副本的数量。 | | 模板 |   | 为复制控制器管理的 Pod 指定模板。 | | 模板->元数据 |   | Pod 的元数据,包括标签。标签用于选择由复制控制器管理的 Pod,并且如果服务要表示 Pod,则必须管理服务定义文件中的选择器表达式。 | | 模板->规格 |   | Pod 规格或配置。 | | 模板->规格->容器 |   | POD 里的容器。可以指定多个容器,但本章只指定了 PostgreSQL 的容器。 | | 模板->规格->容器->映像模板->规格->容器->名称 |   | 要在容器中运行的 Docker 映像。对于 PostgreSQL,映像是“postgres”名称字段指定容器名称。 |

可选地,可以指定复制控制器的selector字段映射。selector中的键:值映射必须与模板- >元数据字段映射中的标签相匹配,以便复制控制器管理模板中的 Pod。如果没有指定,selector字段映射默认为模板- >元数据- > labels字段映射。在下面的列表中,selector是斜体,不包括在使用的定义文件中。Pod 的模板- >元数据- >标签字段映射指定了一个表达式app: "postgres", which translates to Pod label app=postgres。对于管理 Pod 的服务来说,labels字段表达式必须与服务定义文件中的"selector"字段表达式相同,这在上一节中已经讨论过。

apiVersion: v1
kind: ReplicationController
metadata:
  name: "postgres"
spec:
  replicas: 2
  selector:

    - app: "postgres"

  template:
    metadata:
      labels:

        app: "postgres"

    spec:
      containers:
      -
        image: "postgres"
        name: "postgres"

将前面的清单复制到postgres-rc.yaml文件中。可以在 vi 编辑器中打开postgres-rc.yaml文件,并用:wq 保存,如图 5-7 所示。

A418863_1_En_5_Fig7_HTML.gif

图 5-7。

Replication Controller Definition File

使用定义文件postgres-rc.yaml创建一个复制控制器。

kubectl create -f postgres-rc.yaml

随后列出复制控制器。

kubectl get rc

如图 5-8 所示的第一个命令的输出replicationcontrollers/postgres表示复制控制器postgres已经创建。第二个命令列出了postgres复制控制器。如前所述,复制控制器选择器列设置为与 Pod 标签相同的值,app=postgres。

A418863_1_En_5_Fig8_HTML.gif

图 5-8。

Creating and listing the Replication Controller for PostgreSQL Database

用下面的命令描述复制控制器postgres

kubectl describe rc postgres

复制控制器的名称、命名空间、与 rc 相关联的映像、选择器(如果有)、标签、副本数量、pod 状态和事件会被列出,如图 5-9 所示。

A418863_1_En_5_Fig9_HTML.gif

图 5-9。

Describing the Replication Controller for PostgreSQL Database

拿到 POD

要获取并列出窗格,请运行以下命令。

kubectl get pods

由复制控制器创建的两个 pod 被列出,如图 5-10 所示。pod 应处于运行状态,并且就绪列值为 1/1。

A418863_1_En_5_Fig10_HTML.gif

图 5-10。

Listing the Pods for PostgreSQL Database

启动交互式命令外壳

为了能够创建 PostgreSQL 表,我们需要启动一个交互式 bash shell 来访问 Docker 容器中运行的 PostgreSQL 服务器,并为 PostgreSQL 启动 psql SQL shell。但是,首先我们需要找到运行 PostgreSQL 数据库的 Docker 容器的容器 id。运行以下命令列出 Docker 容器。

sudo docker ps

其中两个 Docker 容器基于“postgres”映像,如图 5-11 所示。从容器 id 列中复制第一个 Docker 容器的容器 ID。

A418863_1_En_5_Fig11_HTML.gif

图 5-11。

Listing the Docker Containers

使用容器 id 启动交互式 shell。

sudo docker exec -it a786960b2cb6 bash

交互外壳启动,如图 5-12 所示。

A418863_1_En_5_Fig12_HTML.gif

图 5-12。

Starting an Interactive Shell

启动 PostgreSQL SQL 终端

接下来,为 PostgreSQL 启动 psql SQL shell。将用户设置为postgres

su –l postgres

使用以下命令启动 psql 命令行 shell。

psql postgres

psql 应如图 5-13 所示启动。

A418863_1_En_5_Fig13_HTML.gif

图 5-13。

Starting the psql CLI Shell

关于psql命令的一般命令语法,请参考 http://www.postgresql.org/docs/9.5/static/app-psql.html

创建数据库表

在 psql shell 中运行以下 sql 语句,创建一个名为wlslog的数据库表,并向该表添加数据。

CREATE TABLE wlslog(time_stamp VARCHAR(255) PRIMARY KEY,category VARCHAR(255),type VARCHAR(255),servername VARCHAR(255),code VARCHAR(255),msg VARCHAR(255));
INSERT INTO wlslog(time_stamp,category,type,servername,code,msg) VALUES('Apr-8-2014-7:06:16-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to STANDBY');
INSERT INTO wlslog(time_stamp,category,type,servername,code,msg) VALUES('Apr-8-2014-7:06:17-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to STARTING');
INSERT INTO wlslog(time_stamp,category,type,servername,code,msg) VALUES('Apr-8-2014-7:06:18-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000360','Server started in RUNNING mode');

创建数据库表wlslog并添加一行数据,如图 5-14 所示。

A418863_1_En_5_Fig14_HTML.gif

图 5-14。

Creating a Database Table

运行以下 SQL 语句来查询数据库表wlslog

SELECT * FROM wlslog;

添加的 3 行数据被列出,如图 5-15 所示。

A418863_1_En_5_Fig15_HTML.gif

图 5-15。

Querying the Database Table

退出交互式命令外壳

要退出 psql shell,请运行以下命令。

\q

要退出交互式终端,请运行以下命令。

exit

psql 外壳和交互外壳退出,如图 5-16 所示。

A418863_1_En_5_Fig16_HTML.gif

图 5-16。

Exiting the psql Shell and Docker Container Interactive Shell

扩展 PostgreSQL 集群

Kubernetes 集群管理器的主要优点之一是能够根据需要扩展集群。最初,我们创建了两个副本。例如,要将 PostgreSQL 实例的数量增加到 4 个,请运行以下命令。

kubectl scale rc postgres --replicas=4

前一个命令的“scaled”输出表明集群已经被缩放,如图 5-17 所示。

A418863_1_En_5_Fig17_HTML.gif

图 5-17。

Scaling the number of Pod Replicas to 4

随后使用以下命令列出 pod。

kubectl get pods

如图 5-18 所示,列出 4 个吊舱。最初,一些容器可能被列为未“运行”和/或未处于就绪(1/1)状态。

A418863_1_En_5_Fig18_HTML.gif

图 5-18。

Listing the Pods after Scaling

几秒钟后再次运行前面的命令。

kubectl get pods

如图 5-19 所示,添加到集群中的新单元也被列为“正在运行”并处于就绪状态 1/1。

A418863_1_En_5_Fig19_HTML.gif

图 5-19。

Listing all the Pods as running and ready

再次描述一下postgres服务。

kubectl describe svc postgres

最初,当服务最初启动时,没有端点被列为与服务相关联。4 个 pod 运行时,列出 4 个端点,如图 5-20 所示。

A418863_1_En_5_Fig20_HTML.gif

图 5-20。

Describing the postgres Service

列出日志

要列出 Pod 的日志数据,例如 postgres-v0k42 Pod,请运行以下命令。

kubectl logs postgres-v0k42

图 5-21 中的输出列出了 PostgreSQL 启动。

A418863_1_En_5_Fig21_HTML.gif

图 5-21。

Listing the Logs for a Pod running PostgreSQL Database

当 PostgreSQL 数据库完全启动时,“数据库系统已准备好接受连接”的消息会输出,如图 5-22 所示。

A418863_1_En_5_Fig22_HTML.gif

图 5-22。

PostgreSQL Database listed as Started and subsequently Shutdown in the Logs

删除复制控制器

要删除复制控制器postgres并因此删除由复制控制器管理的所有 pod,请运行以下命令。

kubectl delete rc postgres

postgres复制控制器被删除,如图 5-23 中的replicationcontrollers/postgres输出所示。随后,运行以下命令列出复制控制器。

A418863_1_En_5_Fig23_HTML.gif

图 5-23。

Deleting a Replication Controller

kubectl get rc

postgres复制控制器未列出,如图 5-23 所示。删除复制控制器不会删除管理复制控制器的服务。要演示,请列出服务。

kubectl get services

postgres服务仍在列表中,如图 5-23 所示。

停止服务

要停止服务postgres,请运行以下命令。

kubectl stop service postgres

随后再次运行以下命令。

kubectl get services

postgres服务未列出,如图 5-24 所示。

A418863_1_En_5_Fig24_HTML.gif

图 5-24。

Stopping the postgres Service

强制创建 PostgreSQL 集群

对定义文件使用声明性方法可以更好地控制服务和复制控制器。但是复制控制器和服务也可以在命令行上用kubectl命令创建。在下面的小节中,我们将创建一个复制控制器和一个服务。

创建复制控制器

要为映像“postgres”创建名为postgres的复制控制器,副本数量为 2,Post as 为 5432,请运行以下命令。

kubectl run postgres --image=postgres --replicas=2 --port=5432

带有映像postgresselector表情run=postgres的 Pod 的 2 个副本的postgres复制控制器被创建,如图 5-25 所示。

A418863_1_En_5_Fig25_HTML.gif

图 5-25。

Creating a Replication Controller Imperatively

使用以下命令列出复制控制器。

kubectl get rc

postgres复制控制器列表如图 5-26 所示。

A418863_1_En_5_Fig26_HTML.gif

图 5-26。

Listing the Replication Controllers

拿到 POD

要列出由复制控制器管理的 pod,请运行以下命令。

kubectl get pods

如图 5-27 所示,两个吊舱被列出。最初,一些 pod 可能被列为未就绪,如 0/1 就绪列值所示。再次运行前面的命令,列出就绪列值为 1/1 的窗格。

A418863_1_En_5_Fig27_HTML.gif

图 5-27。

Listing the Pods

创建服务

要创建服务,我们需要运行kubectl expose命令。最初只有kubernetes服务在运行。要进行演示,请运行以下命令。

kubectl get services

如图 5-28 所示,只列出了kubernetes服务。

A418863_1_En_5_Fig28_HTML.gif

图 5-28。

Listing the “kubernetes” Service

要为复制控制器"postgres"创建服务,请运行以下命令,其中–port参数指定服务公开的端口。服务类型设置为LoadBalancer

kubectl expose rc postgres --port=5432 --type=LoadBalancer

随后列出服务。

kubectl get services

postgres 服务被列出,如图 5-29 所示。

A418863_1_En_5_Fig29_HTML.gif

图 5-29。

Creating a Service exposed at Port 5432

创建数据库表

创建数据库表的过程与前面针对声明性部分所讨论的过程相同,在本部分中只简单讨论一下。用下面的命令列出 Docker 容器。

sudo docker ps

如图 5-30 所示,其中两个 Docker 容器的映像列为postgres。从容器 id 列中复制这些列之一的容器 ID。

A418863_1_En_5_Fig30_HTML.gif

图 5-30。

Listing the Docker Containers

使用以下命令启动交互式 shell。

sudo docker exec -it af0ac629b0e7d bash

交互终端启动,如图 5-31 所示。

A418863_1_En_5_Fig31_HTML.gif

图 5-31。

Starting the TTY

将用户设置为postgres

su –l postgres

启动psql命令行外壳。

psql postgres

psql壳体如图 5-32 所示。

A418863_1_En_5_Fig32_HTML.gif

图 5-32。

Starting the psql Shell

运行以下 SQL 语句创建一个名为wlslog的数据库表,并向该表添加数据。

CREATE TABLE wlslog(time_stamp VARCHAR(255) PRIMARY KEY,category VARCHAR(255),type VARCHAR(255),servername VARCHAR(255),code VARCHAR(255),msg VARCHAR(255));

INSERT INTO wlslog(time_stamp,category,type,servername,code,msg) VALUES('Apr-8-2014-7:06:16-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to STANDBY');
INSERT INTO wlslog(time_stamp,category,type,servername,code,msg) VALUES('Apr-8-2014-7:06:17-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to STARTING');
INSERT INTO wlslog(time_stamp,category,type,servername,code,msg) VALUES('Apr-8-2014-7:06:18-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000360','Server started in RUNNING mode');

数据库表wlslog被创建,如图 5-33 所示。

A418863_1_En_5_Fig33_HTML.gif

图 5-33。

Creating a Database Table

运行以下 SQL 语句来查询wlslog表。

SELECT * FROM wlslog;

添加的三行数据被列出,如图 5-34 所示。

A418863_1_En_5_Fig34_HTML.gif

图 5-34。

Querying the wlslog Database Table

要退出运行 PostgreSQL 的 Docker 容器的psql shell 和交互式 shell,请运行以下命令。

\q

exit

psql shell 和 tty 退出,如图 5-35 所示。

A418863_1_En_5_Fig35_HTML.gif

图 5-35。

Exiting the Shells

扩展 PostgreSQL 集群

最初创建集群时,我们将副本数设置为 2。如下列出 pod。

kubectl get pods

仅列出两个吊舱,如图 5-36 所示。

A418863_1_En_5_Fig36_HTML.gif

图 5-36。

Listing the Pods

使用以下命令将集群扩展到 4 个副本。

kubectl scale rc postgres --replicas=4

如图 5-37 所示的“已缩放”输出表明该集群已被缩放。

A418863_1_En_5_Fig37_HTML.gif

图 5-37。

Scaling the Pod Replicas to 4

随后列出 POD。

kubectl get pods

如图 5-38 所示,前面的命令可能需要运行多次才能将所有的 pod 列为“运行中”并处于就绪状态 1/1。

A418863_1_En_5_Fig38_HTML.gif

图 5-38。

Listing the Pods in various states of starting

删除复制控制器

要删除复制控制器,请运行以下命令。

kubectl delete rc postgres

删除 rc 后列出 pod。

kubectl get pods

列出服务。

kubectl get services

如图 5-39 所示,postgres复制控制器被删除并且没有在后面列出。图 5-39 中也显示了postgres服务仍然被列出。

A418863_1_En_5_Fig39_HTML.gif

图 5-39。

Deleting the Replication Controller

停止服务

要停止该服务,请运行以下命令。

kubectl stop service postgres

postgres服务停止,如图 5-40 所示。随后运行以下命令。

A418863_1_En_5_Fig40_HTML.gif

图 5-40。

Stopping the Service

kubectl get services

postgres服务也没有列出,如图 5-40 所示。

摘要

在本章中,我们使用 Kubernetes 集群管理器来启动和管理 PostgreSQL 服务器集群。我们演示了在命令行上强制创建集群和使用定义文件以声明方式创建集群。我们使用复制控制器扩展集群,并使用 Kubernetes 服务公开集群的服务。在下一章中,我们将讨论创建和管理 Oracle 数据库集群。

六、使用 Oracle 数据库

Oracle 数据库是最常用的关系数据库(RDBMS)。安装和配置 Oracle 数据库通常包括下载软件、设置内核参数、安装和配置软件,所有这些都非常复杂。使用与 Kubernetes 相协调的 Docker 容器使得安装、配置和编排 Oracle 数据库集群的任务变得更加容易。由多个实例组成的 Oracle 数据库集群可以受益于 Kubernetes 容器集群管理器的可调度性、可伸缩性、分布性和故障转移特性。在本章中,我们将使用数据库的 Docker 映像来安装 Oracle 数据库。我们将使用复制控制器创建数据库 Pod 的多个副本,并将数据库作为服务公开。本章包括以下几节。

  • 设置环境
  • 强制创建 Oracle 数据库实例
  • 以声明方式创建 Oracle 数据库实例
  • 保持复制级别
  • 扩展数据库
  • 启动交互式 Shell
  • 连接到数据库
  • 创建用户
  • 创建数据库表
  • 退出交互式外壳

设置环境

本章需要以下软件。

  • -Docker 引擎(最新版本)
  • -Kubernetes(1.01 版)
  • -Kubernetes(1.01 版)
  • -Oracle 数据库的 Docker 映像(Oracle 数据库 XE 11g)

如果尚未安装,请按照第一章所述安装 Docker 引擎、Kubernetes 和 Kubectl。使用 EC2 实例的公共 IP 地址 SSH 登录 Amazon EC2 上的 Ubuntu 实例。

ssh -i "docker.pem" ubuntu@52.90.115.30

使用以下命令启动 Docker 实例并验证其状态。

sudo service docker start
sudo service docker status

图 6-1 中显示对接器正在运行。

A418863_1_En_6_Fig1_HTML.gif

图 6-1。

Starting Docker and verifying its Status

列出正在运行的服务。

kubectl get services

在图 6-2 中,只有kubernetes服务被列为正在运行。

A418863_1_En_6_Fig2_HTML.gif

图 6-2。

Listing the Kubernetes Service

强制创建 Oracle 数据库实例

在本节中,我们将在命令行上使用kubectl创建一个 Oracle 数据库集群。Oracle 数据库有几种 Docker 映像,我们将使用sath89/oracle-xe-11g映像( https://hub.docker.com/r/sath89/oracle-xe-11g/ )。运行下面的kubectl命令创建一个 Oracle 数据库集群,该集群包含 2 个副本,端口设置为 1521。

kubectl run oradb --image=sath89/oracle-xe-11g --replicas=2 --port=1521

图 6-3 中命令的输出列出了一个名为oradb的复制控制器,一个名为oradb的 Docker 容器,一个用于选择包含复制控制器副本的 pod 的选择器(run=oradb,以及副本的数量(2)。Pod 标签也被设置为run=oradb

A418863_1_En_6_Fig3_HTML.gif

图 6-3。

Creating a Replication Controller and Pod Replicas for Oracle Database

使用以下命令列出复制控制器。

kubectl get rc

图 6-4 所示的oradb复制控制器上市。

A418863_1_En_6_Fig4_HTML.gif

图 6-4。

Listing the Replication Controllers

使用以下命令列出窗格。

kubectl get pods

除了 Kubernetes Pod k8s-master-127.0.0.1之外,Oracle 数据库还列出了另外两个 Pod,如图 6-5 所示。最初,pod 可能被列为“未准备好”,如图 6-5 所示。在几秒钟后运行前面的命令,如果需要,可以多次运行,以列出两个 pod 正在运行并准备就绪(1/1)。

A418863_1_En_6_Fig5_HTML.gif

图 6-5。

Listing the Pods in various stages of running

使用以下命令获取节点。

kubectl get nodes

并使用下面的命令获得 Kubernetes 服务。

kubectl get services

只有kubernetes服务被列出,如图 6-6 所示,因为我们还没有为 Oracle 数据库创建服务。

A418863_1_En_6_Fig6_HTML.gif

图 6-6。

Creating a Replication Controller does not create a Service

列出日志

使用以下命令列出其中一个 pod 的日志。

kubectl logs oradb-ea57r

由一个已启动的 Oracle 数据库实例生成的日志得到如图 6-7 所示的输出。Oracle Net 监听程序显示为已启动。

A418863_1_En_6_Fig7_HTML.gif

图 6-7。

Listing Logs for a Pod

创建服务

接下来,在端口 1521 上公开复制控制器oradb作为 Kubernetes 服务。随后列出 Kubernetes 服务。

kubectl expose rc oradb --port=1521 --type=LoadBalancer
kubectl get services

前面两个命令中的第一个启动了oradb服务。随后,服务被列出,如图 6-8 所示。服务选择器是 run=oradb,它与复制控制器选择器相同。

A418863_1_En_6_Fig8_HTML.gif

图 6-8。

Creating a Service Imperatively

用下面的命令描述服务。

kubectl describe svc oradb

服务名称、名称空间、标签、选择器、类型、IP、端口、节点端口和端点被列出,如图 6-9 所示。

A418863_1_En_6_Fig9_HTML.gif

图 6-9。

Describing the oradb Service

扩展数据库

运行kubectl scale命令来缩放副本。例如,将副本数量减少到 1。

kubectl scale rc oradb --replicas=1

“已缩放”的输出表示复制品已被缩放,如图 6-10 所示。

A418863_1_En_6_Fig10_HTML.gif

图 6-10。

Scaling the Replicas to 1

随后列出正在运行的 pod。

kubectl get pods

仅列出一个 Oracle 数据库 Pod,因为另一个已停止,以将复制级别降至一级,如图 6-11 所示。随后,描述服务。

A418863_1_En_6_Fig11_HTML.gif

图 6-11。

Listing and Describing the Single Pod

kubectl describe svc oradb

因为集群已经缩减到一个副本,所以端点的数量也减少到一个,如图 6-11 所示。

删除复制控制器和服务

在后续部分中,我们将使用定义文件以声明方式创建一个 Oracle 数据库实例集群。因为我们将使用相同的配置参数,所以用下面的命令删除"oradb"复制控制器和"oradb"服务。

kubectl delete rc oradb
kubectl delete svc oradb

复制控制器和服务都被删除,如图 6-12 所示。

A418863_1_En_6_Fig12_HTML.gif

图 6-12。

Deleting the Replication Controller and Service

以声明方式创建 Oracle 数据库实例

在本节中,我们将使用 Pod、复制控制器和服务的定义文件以声明方式创建 Oracle 数据库集群。我们在定义文件中使用了 YAML 格式,但是也可以使用 JSON 格式。

创建 Pod

为名为oradb.yaml的 Pod 创建一个定义文件。复制下面的清单,其中定义了一个名为“oradb”的 Pod,标签设置为name: "oradb",转换为 Pod label name=oradb。容器映像设置为“sath89/oracle-xe-11g”,容器端口设置为 1521。

apiVersion: v1
kind: Pod
metadata:
  name: "oradb"
  labels:
    name: "oradb"
spec:
  containers:
    -
      image: "sath89/oracle-xe-11g"
      name: "oradb"
      ports:
        -
          containerPort: 1521
  restartPolicy: Always

可以在 vi 编辑器中创建oradb.yaml文件,并用:wq 命令保存,如图 6-13 所示。

A418863_1_En_6_Fig13_HTML.gif

图 6-13。

Pod Definition File

使用定义文件oradb.yamlkubectl create命令创建一个 Pod。

kubectl create -f oradb.yaml --validate

图 6-14 中“Pod/oradb”的输出表明oradb Pod 已经创建。

A418863_1_En_6_Fig14_HTML.gif

图 6-14。

Creating a Pod from a Definition File

随后,使用以下命令列出正在运行的 pod。

kubectl get pods

单个吊舱oradb被列出,如图 6-15 所示。最初,oradb Pod 可以在启动的不同阶段列出,例如映像“准备好,容器正在创建”或者就绪值可以是 0/1,表示 Pod 尚未准备好。当状态栏变为“正在运行”且就绪栏变为 1/1 时,Pod 启动并就绪。前面的命令可能需要运行多次才能将 Pod 列为正在运行和就绪。

A418863_1_En_6_Fig15_HTML.gif

图 6-15。

Listing the Pod/s, which could initially be not Running and not Ready

创建服务

接下来,为 Oracle 数据库集群创建一个服务。该服务不指定有多少 Oracle 数据库映像实例(副本)正在运行或应该运行。副本由复制控制器控制。该服务只定义了一个用于公开服务的端口、一个用于服务的标签和一个用于匹配由该服务管理的 pod 的选择器。选择器设置是 app:“oradb”,翻译过来就是服务选择器 app=oradb。创建一个服务定义文件oradb-service.yaml,并将下面的清单复制到定义文件中。

apiVersion: v1
kind: Service
metadata:
  name: "oradb"
  labels:
    app: "oradb"
spec:
  ports:
    -
      port: 1521
  selector:
    app: "oradb"

可以在 vi 编辑器中创建oradb-service.yaml定义文件,并用:wq 保存,如图 6-16 所示。

A418863_1_En_6_Fig16_HTML.gif

图 6-16。

Service Definition File

运行以下命令从服务定义文件创建服务。

kubectl create -f oradb-service.yaml

如图 6-17 中的“服务/oradb”输出所示,oradb服务被创建。随后列出服务。

A418863_1_En_6_Fig17_HTML.gif

图 6-17。

Creating a Service from a Service Definition File

kubectl get services

oradb服务列表如图 6-17 所示。

用下面的命令描述oradb服务。

kubectl describe svc oradb

没有列出如图 6-18 所示的服务端点,因为服务选择器与已经运行的 Pod 上的标签不匹配。服务选择器 app=oradb 必须与 Pod 标签相匹配,服务才能管理 Pod。在下一节中,我们将创建一个带有匹配标签的复制控制器。

A418863_1_En_6_Fig18_HTML.gif

图 6-18。

Describing a Service for Oracle Database

创建复制控制器

创建一个名为oradb-rc.yaml的复制控制器定义文件,并将下面定义复制控制器的清单复制到定义文件中。为了让复制控制器管理在 spec 字段中定义的 Pod,复制控制器中选择器的 key:value 表达式必须与 Pod 模板映射中的标签相匹配。oradb-rc.yaml中省略了selector,但是必须指定规格- >模板- >元数据- >标签。选择器默认为与spec->template->metadata->labels相同的设置。template->spec->containers 映射定义了 Pod 中的容器。仅定义了 Oracle 数据库容器“sath89/oracle-xe-11g”。

apiVersion: v1
kind: ReplicationController
metadata:
  name: "oradb"
  labels:
    app: "oradb"
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: "oradb"
    spec:
      containers:
        -
          image: "sath89/oracle-xe-11g"
          name: "oradb"

可以在 vi 编辑器中编辑oradb-rc.yaml文件,并用:wq 命令保存,如图 6-19 所示。

A418863_1_En_6_Fig19_HTML.gif

图 6-19。

Replication Controller Definition File

接下来,运行下面的命令,从定义文件oradb-rc.yaml创建一个复制控制器。

kubectl create -f oradb-rc.yaml

复制控制器的创建如图 6-20 所示。使用以下命令列出复制控制器。

A418863_1_En_6_Fig20_HTML.gif

图 6-20。

Creating and listing a Replication Controller from a Definition File

kubectl get rc

oradb复制控制器被创建,如图 6-20 所示。

由复制控制器创建的 pod 用以下命令列出。

kubectl get pods

如图 6-21 所示,列出了三个 Oracle 数据库单元。为什么即使复制控制器副本设置为 2,也会列出三个 pod?因为开始使用 Pod 定义文件oradb.yaml的 Pod 不包括与复制控制器中的选择器相匹配的标签。复制控制器选择器是app: "oradb",而盒上的标签是name: "oradb"。两个副本由复制控制器启动,一个 pod 由 Pod 定义文件提前启动。

A418863_1_En_6_Fig21_HTML.gif

图 6-21。

Listing the Pod Replicas

用下面的命令描述服务oradb

kubectl describe svc oradb

服务端点被列出,如图 6-22 所示。只列出了两个端点,因为服务选择器应用:“oradb”与复制控制器中的 Pod 标签匹配,有两个副本。先前创建的 Pod 不包含与选择器表达式匹配的标签。

A418863_1_En_6_Fig22_HTML.gif

图 6-22。

Describing the Service after creating the Replication Controller

保持复制级别

复制控制器的任务是维护 pod 的复制级别。因为复制控制器规范中的replicas字段映射为 2,所以在复制控制器运行时,Pod 规范中配置的 Pod 的两个副本必须一直运行。要证明复制级别保持不变,请删除一个单元。

kubectl delete pod oradb-5ntnj

随后列出正在运行的 pod。

kubectl get pods

两个副本中的一个被kubectl delete pod 命令删除,但另一个副本在图 6-23 中被列为开始。副本可能需要几秒钟才能达到复制级别。多次运行上述命令,将复制副本列为正在运行。复制品的数量回到 2。

A418863_1_En_6_Fig23_HTML.gif

图 6-23。

Maintaining the Replication Level

"oradb" Pod 与复制控制器没有关联,因此它不被算作复制控制器管理的副本之一。复制控制器不管理oradb箱,因为如前所述,oradb箱上的标签与复制控制器上的标签不匹配。为了证明oradb pod 不受复制控制器管理,请删除该 pod。

kubectl delete pod oradb

随后列出正在运行的 pod。

kubectl get pods

如图 6-24 所示,oradb Pod 被删除,替换 Pod 未启动,也未在运行 Pod 中列出。

A418863_1_En_6_Fig24_HTML.gif

图 6-24。

The oradb Pod is not managed by the Replication Controller

扩展数据库

复制控制器可用于扩展为 Oracle 数据库运行的 pod 的数量。例如,将 Pod 副本的数量从 2 个增加到 3 个。

kubectl scale rc oradb --replicas=3

“缩放”输出表示副本已被缩放。随后运行以下命令,如果需要可以多次运行,以将新的 Pod 复制副本列为正在运行和就绪。

kubectl get pods

如图 6-25 所示,列出了 Pod 的三个副本。

A418863_1_En_6_Fig25_HTML.gif

图 6-25。

Scaling the Cluster to 3 Replicas

再次描述服务。

kubectl describe svc oradb

如图 6-26 所示,列出了三个端点,而不是两个。该服务只有一个 IP 地址。

A418863_1_En_6_Fig26_HTML.gif

图 6-26。

Listing the 3 Endpoints in the Service

启动交互式 Shell

在本节中,我们将启动一个交互式 tty (shell)来连接软件,该软件是 Oracle 数据库,运行在由 Kubernetes 启动和管理的 Docker 容器中。首先,用下面的命令列出 Docker 容器。

sudo docker ps

复制sath89/oracle-xe-11g映像的一个 Docker 容器的容器 id,如图 6-27 所示。

A418863_1_En_6_Fig27_HTML.gif

图 6-27。

Copying the Container Id for a Docker Container

使用容器 id,通过以下命令启动一个交互式 shell。

sudo docker exec -it 9f74a82d4ea0 bash

交互外壳启动,如图 6-28 所示。

A418863_1_En_6_Fig28_HTML.gif

图 6-28。

Starting an Interactive Shell

连接到数据库

在交互式 tty 中,将用户改为“oracle”

su -l oracle

su oraclesu - oracle的区别在于,后者使用oracle用户的环境变量登录,并将当前目录设置为 oracle 主目录,而前者使用oracle登录,但环境变量和当前目录保持不变。

随后启动 SQL*Plus。使用/nolog选项不会建立与数据库的初始连接。

sqlplus /nolog

运行以下命令将SYS连接为SYSDBA

CONNECT SYS AS SYSDBA

出现提示时,将密码指定为“oracle”。启动 SQL*Plus 和连接SYS的上述命令的输出如图 6-29 所示。建立了一个连接。

A418863_1_En_6_Fig29_HTML.gif

图 6-29。

Starting SQL*Plus

创建用户

要创建一个名为 OE 的用户,并向该用户授予CONNECTRESOURCE角色,请运行以下命令。

CREATE USER OE QUOTA UNLIMITED ON SYSTEM IDENTIFIED BY OE;
GRANT CONNECT, RESOURCE TO OE;

用户OE被创建,角色被授予,如图 6-30 所示。

A418863_1_En_6_Fig30_HTML.gif

图 6-30。

Connecting as SYSDBA and creating a User

创建数据库表

用下面的 SQL 语句创建一个名为OE.Catalog的数据库表。

CREATE TABLE OE.Catalog(CatalogId INTEGER PRIMARY KEY,Journal VARCHAR2(25),Publisher VARCHAR2(25),Edition VARCHAR2(25),Title VARCHAR2(45),Author VARCHAR2(25));

向 OE 添加一行数据。包含以下 SQL 语句的目录表。

INSERT INTO OE.Catalog VALUES('1','Oracle Magazine','Oracle Publishing','November December 2013','Engineering as a Service','David A. Kelly');

创建OE.Catalog表并添加一行数据,如图 6-31 所示。

A418863_1_En_6_Fig31_HTML.gif

图 6-31。

Creating a Database Table

运行以下 SQL 语句来查询OE.CATALOG表。

SELECT * FROM OE.CATALOG;

添加的单行数据被列出,如图 6-32 所示。

A418863_1_En_6_Fig32_HTML.gif

图 6-32。

Querying the Database Table

退出交互式外壳

使用“退出”命令退出 SQL*Plus 命令,使用“退出”命令退出“oracle”用户,使用“退出”命令退出交互终端,也如图 6-33 所示。

A418863_1_En_6_Fig33_HTML.gif

图 6-33。

Exiting the Interactive Shell

摘要

在本章中,我们使用 Kubernetes 创建和编排了一个 Oracle 数据库集群。我们讨论了创建和管理集群的命令式和声明式方法。使用命令式方法,可以直接使用kubectl命令而无需定义文件来创建复制控制器和服务。对于 Pod 的声明性方法定义文件,必须使用复制控制器和服务。我们演示了如何扩展集群。我们还使用 Docker 容器登录到 SQL*Plus 并创建一个数据库表。在下一章中,我们将讨论在 Kubernetes 中使用 MongoDB。

七、使用 MongoDB 数据库

MongoDB 是一个灵活的模式模型 NoSQL 数据存储,最常用的 NoSQL 数据存储。MongoDB 基于 BSON(二进制 JSON)存储模型。文档存储在集合中。作为一个无模式的数据存储,就 BSON 文档中的字段而言,没有两个文档需要是相同的。在大规模集群中,可能会运行几个 MongoDB 实例,并且可能会出现几个问题。

  • -MongoDB 实例调度
  • -扩展 MongoDB 集群
  • -负载均衡
  • -提供 MongoDB 即服务

虽然 Docker 使提供容器即服务(CaaS)变得可行,但它本身并不提供前面列出的任何功能。在本章中,我们将讨论使用 Kubernetes 容器集群管理器来管理和编排运行 MongoDB 的 Docker 容器集群。本章包括以下几节。

  • 设置环境
  • 以声明方式创建 MongoDB 集群
  • 强制创建 MongoDB 集群

设置环境

本章需要以下软件。

  • -Docker 引擎(最新版本)
  • -Kubernetes(1.01 版)
  • -Kubernetes(1.01 版)
  • MongoDB 的 Docker 映像(最新版本)

在运行 Ubuntu 14 的 Amazon EC2 实例上安装所需软件;与其他章节中使用的 AMI 相同。SSH 使用公共 IP 地址登录 Ubuntu 实例,对于不同的用户,这个地址是不同的。

ssh -i "docker.pem" ubuntu@52.91.190.195

Ubuntu 实例被登录,如图 7-1 所示。

A418863_1_En_7_Fig1_HTML.gif

图 7-1。

Logging into Ubuntu Instance on Amazon EC2

第一章讨论了安装程序。要验证 Docker 是否正在运行,请运行以下命令。

sudo service docker start

Docker 应被列为运行中,如图 7-2 所示。

A418863_1_En_7_Fig2_HTML.gif

图 7-2。

Starting Docker

使用以下命令列出 pod。

kubectl get pods

并使用以下命令列出节点。

kubectl get nodes

Kubernetes Pod 被列出,节点也被列出,如图 7-3 所示。

A418863_1_En_7_Fig3_HTML.gif

图 7-3。

Listing Kubernetes Pod and the single Node

要列出服务,请运行以下命令。

kubectl get services

“kubernetes”服务被列出,如图 7-4 所示。

A418863_1_En_7_Fig4_HTML.gif

图 7-4。

Listing the Kubernetes Service

以声明方式创建 MongoDB 集群

在下面的小节中,我们将为 MongoDB 集群创建一个 Kubernetes 服务和复制控制器。我们将扩展群集,并演示使用卷和主机端口等功能。我们将创建一个 MongoDB 集合,并在 Docker 容器 tty(交互式终端或 shell)中运行的 Mongo shell 中将文档添加到集合中。

创建服务

创建服务定义文件mongo-service-yaml。在定义文件中添加以下(表 7-1 )字段映射。

表 7-1。

Service Definition File mongo-service-yaml File Fields

| 田 | 价值 | 描述 | | --- | --- | --- | | apiVersion(堆叠版本) | 第五颅神经的眼支 | API 版本。 | | 种类 | 服务 | 将定义文件指定为服务。 | | 元数据 |   | 服务元数据。 | | 元数据->标签 | 名称:mongo |   | | 元数据->名称 | 蒙戈 | 标签映射。标签可以添加多次,不会产生错误,也没有额外的意义。 | | 投机 |   | 服务规范。 | | 规格->端口 |   | 公开服务的端口。 | | 规格->端口->端口 | Twenty-seven thousand and seventeen | 托管服务的端口。 | | 规格>连接埠>目标连接埠 | Twenty-seven thousand and seventeen | 传入端口映射到的端口。targetPort 字段是可选的,默认为与 Port 字段相同的值。如果服务要在不破坏客户端设置的情况下发展,targetPort 可能是有用的。例如,targetPort 可以设置为后端 Pod 的字符串端口名称,它保持不变。并且后端 Pod 暴露的实际端口号可以变化,而不会影响客户端的设置。 | | 选择器 | 名称:mongo | 用于选择窗格的服务选择器。标签表达式与选择器相同的窗格由服务管理。 |

将下面的清单复制到mongo-service.yaml

apiVersion: v1
kind: Service
metadata:
  labels:
    name: mongo
  name: mongo
spec:
  ports:
    - port: 27017
      targetPort: 27017
  selector:
    name: mongo

vi 编辑器可用于创建mongo-service.yaml文件,并使用:wq 命令保存,如图 7-5 所示。

A418863_1_En_7_Fig5_HTML.gif

图 7-5。

Service Definition File in vi Editor

默认服务类型是ClusterIp,它仅使用集群内部 IP。如图 7-6 所示,可以将类型设置为LoadBalancer,以便在集群中的每个节点上公开服务,并请求云提供商提供负载均衡器。

A418863_1_En_7_Fig6_HTML.gif

图 7-6。

Setting the Service Type

要从定义文件创建服务,请运行以下命令。

kubectl create -f mongo-service.yaml

使用以下命令列出服务。

kubectl get services

mongo服务列表如图 7-7 所示。

A418863_1_En_7_Fig7_HTML.gif

图 7-7。

Creating the Service from the Definition File

创建复制控制器

在本节中,我们将创建一个复制控制器。创建一个定义文件mongo-rc.yaml。将以下(表 7-2 )字段映射添加到定义文件中。

表 7-2。

Replication Controller Definition File Fields

| 田 | 价值 | 描述 | | --- | --- | --- | | apiVersion(堆叠版本) | 第五颅神经的眼支 | API 版本。 | | 种类 | 复制控制器 | 指定复制控制器的定义文件。 | | 元数据 |   | 指定复制控制器的元数据。 | | 元数据->标签 | 名称:mongo | 复制控制器的标签映射。 | | 元数据->名称 | 蒙戈-rc | 复制控制器的名称。 | | 投机 |   | 复制控制器规范。 | | 规格->副本 | Two | 始终要保留的副本数量。 | | 规格->模板 |   | Pod 的模板。 | | 规格->模板->元数据 |   | Pod 的元数据。 | | 规格->模板->元数据->标签 |   | POD 标签。复制控制器和服务使用这些标签来选择要管理的 pod。复制控制器和服务中的选择器必须与用于管理 Pod 的复制控制器和服务的 Pod 标签相匹配。 | | 规格->模板->元数据->标签->名称 | 蒙戈 | 在 label 下方。 | | 规格->模板->规格 |   | Pod 的规格。 | | 规格->模板->规格->容器 |   | POD 里的容器。可以指定多个容器,但我们只配置了一个容器。 | | 规格->模板->规格->容器->映像 | 蒙戈 | “mongo”Docker 映像的容器。 | | 规格->模板->规格->容器->名称 | 蒙戈 | 容器名称。 | | 规格->模板->规格->容器->端口 |   | 要预订的容器港口。 | | 规格->模板->规格->容器->端口->名称 | 蒙戈 | 端口名称。 | | 规格->模板->规格->容器->端口->容器端口 | Twenty-seven thousand and seventeen | 容器端口号。 |

每个 Pod、服务和复制控制器都在单独的 YAML 映射文件中定义。mongo-rc.yaml已列出。

apiVersion: v1
kind: ReplicationController
metadata:
  labels:
    name: mongo
  name: mongo-rc
spec:
  replicas: 2
  template:
    metadata:
      labels:
        name: mongo
    spec:
      containers:
        -
          image: mongo
          name: mongo
          ports:
            -
              containerPort: 27017
              name: mongo

mongo-rc.yaml文件可以在 vi 编辑器中编辑,用:wq 保存,如图 7-8 所示。

A418863_1_En_7_Fig8_HTML.gif

图 7-8。

Replication Controller Definition File

若要从定义文件创建复制控制器,请运行以下命令。

kubectl create -f mongo-rc.yaml

mongo-rc复制控制器被创建,如图 7-9 所示。

A418863_1_En_7_Fig9_HTML.gif

图 7-9。

Creating the Replication Controller

运行以下命令列出复制容器。

kubectl get rc

mongo-rc复制控制器列表如图 7-10 所示。

A418863_1_En_7_Fig10_HTML.gif

图 7-10。

Creating and isting Replication Controllers

创建卷

Kubernetes 支持卷。卷是 Pod 中的目录,Pod 中的容器可以访问该目录,这些容器为卷提供卷挂载。只要包含卷的 Pod 存在,卷就会一直存在。卷可用于以下目的。

  • -跨容器崩溃保存数据。当装载卷的容器崩溃时,卷中的数据不会被删除,因为卷不在容器上,而是在 Pod 上。
  • -卷中的数据可以由装载该卷的多个容器共享。

Pod 中的体积由“规格->体积”字段指定。一个容器装载一个带有spec.containers.volumeMounts字段的卷。支持几种类型的卷,其中一些在表 7-3 中讨论。

表 7-3。

Types of Volumes

| 卷类型 | 描述 | | --- | --- | | emptyDir 先生 | Pod 中的空目录,可用于保存一个或多个容器使用的一些文件。空目录也可以用于检查点。 | | 主机路径 | 将目录从主机节点装载到 Pod 中。 | | gcePersistentDisk | 将一个谷歌计算引擎永久磁盘安装到 Pod 中。 | | awsElasticBlockStore | 将 Amazon Web Services EBS 卷装入 Pod。 | | 吉卜赛人 | 将 git repo 装载到 pod 中。 | | 弗勒加 | 将 Flocker 数据集装载到 pod 中。 | | 网络文件系统 | 将网络文件系统装入 Pod。 |

接下来,我们将把类型为emptyDir的卷添加到复制控制器定义文件mongo-rc.yaml中。一种改良版的mongo-rc.yaml上市了。

apiVersion: v1
kind: ReplicationController
metadata:
  labels:
    name: mongo
  name: mongo-rc
spec:
  replicas: 2
  template:
    metadata:
      labels:
        name: mongo
    spec:
      containers:
        -
          image: mongo
          name: mongo
          ports:
            -
              containerPort: 27017
              name: mongo
          volumeMounts:
            -
              mountPath: /mongo/data/db
              name: mongo-storage
      volumes:
        -
          emptyDir: {}
          name: mongo-storage

前面的定义文件包括类型为emptyDir的名为mongo-storage的卷的以下卷配置。

      volumes:
        -
          emptyDir: {}
          name: mongo-storage

该卷存在于 Pod 中,Pod 中的单个容器可以使用字段spec->containers->volumeMounts装载该卷。修改后的mongo-rc.yaml包括以下用于mongo容器的卷挂载。

volumeMounts:
            -
              mountPath: /mongo/data/db
              name: mongo-storage

前面的配置在容器中的挂载路径或目录路径/mongo/data/dbmongo-storage卷添加了一个卷挂载。在容器内,可以在/mongo/data/db访问卷。例如,在一个交互终端中为一个容器把目录(cd)改为/mongo/data/db目录。

cd /mongo/data/db

列出/mongo/data/db目录中的文件和目录。

ls -l

该目录是空的,因为它最初应该如图 7-11 所示。

A418863_1_En_7_Fig11_HTML.gif

图 7-11。

Empty Directory

不要将该卷与 MongoDB 服务器的数据目录混淆。默认情况下,数据目录在/data/db创建,并在运行 MongoDB 服务器实例的每个 Docker 容器中创建。/mongo/data/db是所有 Docker 容器共有的,而/data/db存在于每个 Docker 容器中。

列出日志

启动复制控制器后,使用以下命令列出 pod。

kubectl get pods

如图 7-12 所示,两个吊舱被列出。

A418863_1_En_7_Fig12_HTML.gif

图 7-12。

Listing the Pods

可以使用以下命令列出 Pod 的日志,例如,mongo-rc-4t43s Pod。

kubectl logs mongo-rc-4t43s

Pod 日志显示 MongoDB 服务器启动,如图 7-13 所示。

A418863_1_En_7_Fig13_HTML.gif

图 7-13。

Listing the Pod Logs

当 MongoDB 服务器启动时,输出消息“等待端口 27017 上的连接”,如图 7-14 所示。

A418863_1_En_7_Fig14_HTML.gif

图 7-14。

MongoDB Running on Port 27017

启动 Docker 容器的交互式外壳

在这一节中,我们将为 MongoDB 服务器启动一个交互式终端或 bash shell,为此我们需要运行 MongoDB 服务器的 Docker 容器的容器 id。列出 Docker 容器。

sudo docker ps

复制映像为“mongo”的容器的容器 id,如图 7-15 所示。

A418863_1_En_7_Fig15_HTML.gif

图 7-15。

Copying Docker Container ID

因为“mongo”Docker 映像基于 FROM 指令中指定的“debian”Docker 映像,所以我们能够启动一个 bash shell 来与基于“mongo”映像的 Docker 容器中运行的 MongoDB 服务器进行交互。使用以下命令启动交互式 bash shell。

sudo docker exec -it 00c829e0a89d bash

如图 7-16 所示,启动一个交互式外壳。

A418863_1_En_7_Fig16_HTML.jpg

图 7-16。

Starting an Interactive Shell

启动 Mongo Shell

用下面的命令启动 Mongo shell。

mongo

Mongo shell 启动如图 7-17 所示。

A418863_1_En_7_Fig17_HTML.gif

图 7-17。

Mongo Shell

创建数据库

在 Mongo shell 中使用以下命令列出数据库。

show dbs

当使用或设置数据库时,数据库被隐式地创建。比如设置数据库使用为mongodb,没有和show dbs一起列出,还不存在。

use mongodb

但是,将数据库设置为用作mongodb并不会创建数据库mongodb,直到数据库被使用。运行以下命令列出数据库。

show dbs

mongodb数据库没有被列出,如图 7-19 所示。要创建mongodb数据库,调用数据库上的一些操作,比如用下面的命令创建一个名为catalog的集合。

db.createCollection("catalog")

随后再次列出数据库。

show dbs

mongodb数据库被列出,如图 7-18 所示。要列出集合,请运行以下命令。

A418863_1_En_7_Fig18_HTML.jpg

图 7-18。

Creating and Listing a MongoDB Database

show collections

catalog系列上市。

创建收藏

在上一节中,catalog集合是使用db.createCollection方法创建的。再举一个例子,使用下面的命令创建一个名为catalog_capped的封顶集合:封顶集合是一个固定大小的集合,支持基于插入顺序添加和获取文档的高吞吐量操作。

db.createCollection("catalog_capped", {capped: true, autoIndexId: true, size: 64 * 1024, max: 1000} )

如图 7-19 所示,添加一个加盖的集合。最初,集合是空的。使用以下命令获取catalog集合中的文档。

A418863_1_En_7_Fig19_HTML.jpg

图 7-19。

Creating a Capped Collection

db.catalog.count()

文档数被列为 0,因为我们尚未添加任何文档。

添加文档

在本节中,我们将向目录集合中添加文档。为要添加的文档指定 JSON。存储在 MongoDB 中的每个文档都需要_id字段。可以像在doc2文档中一样明确地添加_id字段。如果文件 JSON 中没有提供,则自动生成_id

doc1 = {"catalogId" : "catalog1", "journal" : 'Oracle Magazine', "publisher" : 'Oracle Publishing', "edition" : 'November December 2013',"title" : 'Engineering as a Service',"author" : 'David A. Kelly'}
doc2 = {"_id": ObjectId("507f191e810c19729de860ea"), "catalogId" : "catalog1", "journal" : 'Oracle Magazine', "publisher" : 'Oracle Publishing', "edition" : 'November December 2013',"title" : 'Engineering as a Service',"author" : 'David A. Kelly'};

doc1 和 doc2 如图 7-20 所示。

A418863_1_En_7_Fig20_HTML.gif

图 7-20。

Documents doc1 and doc2

要将文档添加到catalog集合,请运行以下命令。

db.catalog.insert([doc1, doc2], { writeConcern: { w: "majority", wtimeout: 5000 }, ordered:true })

如图 7-21 中 JSON 结果的nInserted字段所示,文件被添加。

A418863_1_En_7_Fig21_HTML.jpg

图 7-21。

Adding Documents

查找文档

要查询目录,调用find()方法。要列出catalog集合中的所有文档,运行以下命令。

db.catalog.find()

添加的两个文件列表如图 7-22 所示。对于其中一个文档,会自动生成_id字段。

A418863_1_En_7_Fig22_HTML.gif

图 7-22。

Finding Documents

查找单个文档

要从catalog集合中找到一个文档,运行下面的命令来调用findOne()方法。

db.catalog.findOne()

单个文档被列出,如图 7-23 所示。

A418863_1_En_7_Fig23_HTML.gif

图 7-23。

Finding a Single Document

在单个文档中查找特定字段

例如,要仅从单个文档中获取特定字段edition, titleauthor,请运行以下命令。

db.catalog.findOne(
    { },
{ edition: 1, title: 1, author: 1 }
)

只列出单个文档中的特定字段,如图 7-24 所示。_id字段总是被列出。

A418863_1_En_7_Fig24_HTML.gif

图 7-24。

Finding Selected Fields in a Document

删除收藏

要删除catalog集合,请运行以下命令。

db.catalog.drop()

随后使用以下命令列出集合。

show collections

catalog集合没有被列出,只有catalog_capped集合被列出,如图 7-25 所示。

A418863_1_En_7_Fig25_HTML.gif

图 7-25。

Dropping the catalog Collection

退出 Mongo Shell 和交互式 Shell

要退出 Mongo shell,运行以下命令。

exit

要退出交互式终端,请运行以下命令。

exit

Mongo shell 和交互终端退出,如图 7-26 所示。

A418863_1_En_7_Fig26_HTML.gif

图 7-26。

Exiting the Shells

扩展集群

要扩展 Mongo 集群,运行kubectl scale命令。例如,以下命令将群集扩展到 4 个复制副本。

kubectl scale rc mongo --replicas=4

如图 7-27 所示的“缩放”输出将集群缩放至 4 个副本。

A418863_1_En_7_Fig27_HTML.gif

图 7-27。

Scaling a Replication Controller

缩放后列出窗格。

kubectl get pods

四个 POD 被列出。最初,一些容器可能被列为未就绪(1/1)状态。多次运行上述命令,列出所有正在运行并准备就绪的吊舱,如图 7-28 所示。

A418863_1_En_7_Fig28_HTML.gif

图 7-28。

Listing the Pods after Scaling

删除复制控制器

要删除复制控制器mongo-rc,请运行以下命令。

kubectl delete replicationcontroller mongo-rc

由复制控制器管理的所有 pod 也会被删除。随后运行以下命令来列出窗格。

kubectl get pods

mongo吊舱不会如图 7-29 所示列出。

A418863_1_En_7_Fig29_HTML.gif

图 7-29。

Deleting a Replication Controller

删除服务

要删除名为mongo的服务,运行以下命令。

kubectl delete service mongo

mongo服务未列出,如图 7-30 所示。

A418863_1_En_7_Fig30_HTML.gif

图 7-30。

Deleting the mongo Service

使用主机端口

Pod 中的容器规范有配置主机端口的规定。主机端口是映射到主机的容器端口,意味着指定的主机端口被保留给单个容器。hostPort字段应该用于单个机器容器。指定了hostPort的类型的多个容器无法启动,因为主机端口只能由一个容器保留。然而,其他没有指定hostPort字段的 pod 可以在运行具有hostPort字段映射的容器的同一台机器上运行。作为我们之前使用的复制控制器的变体,在 spec- > containers- > ports 字段中添加了一个hostPort字段。修改后的mongo-rc.yaml被列出。

---
apiVersion: v1
kind: ReplicationController
metadata:
  labels:
    name: mongo
  name: mongo-rc
spec:
  replicas: 2
  template:
    metadata:
      labels:
        name: mongo
    spec:
      containers:
        -
          image: mongo
          name: mongo
          ports:
            -
              containerPort: 27017
              hostPort: 27017
              name: mongo

运行以下命令创建复制控制器。

kubectl create -f mongo-rc.yaml

使用以下命令列出复制控制器。

kubectl get rc

mongo-rc复制控制器被创建并列出,如图 7-31 所示。

A418863_1_En_7_Fig31_HTML.gif

图 7-31。

Creating a Replication Controller from a Definition File

使用以下命令列出 pod。

kubectl get pods

两个复制副本中只有一个列为正在运行和就绪(1/1)。即使前面的命令运行多次,也只有一个副本被列为正在运行,如图 7-32 所示。

A418863_1_En_7_Fig32_HTML.gif

图 7-32。

Listing the Pods after creating a Replication Controller

使用以下命令将 MongoDB 集群扩展到 4 个副本。

kubectl scale rc mongo --replicas=4

尽管该命令的输出被“缩放”并创建了 4 个 Pod,但在任何特定时间只有一个 Pod 处于就绪(1/1)状态,如图 7-33 所示。

A418863_1_En_7_Fig33_HTML.gif

图 7-33。

Scaling the Replication Controller to 4 Replicas

即使单个运行的 Pod 停止,也只有一个新的 Pod 启动。要进行演示,请停止单个运行的 Pod。

kubectl stop pod mongo-rc-laqpl

该单元被移除,但会创建一个替换单元来保持复制级别 1,如图 7-34 所示。

A418863_1_En_7_Fig34_HTML.gif

图 7-34。

Another Pod gets created when the single running Pod is stopped

几秒钟后再次列出 Pod,只有一个 Pod 被列出,如图 7-35 所示。

A418863_1_En_7_Fig35_HTML.gif

图 7-35。

Only a single Pod is Running and Ready

不建议使用hostPort字段,除非使用单个容器机器或者只需要将单个容器映射到主机端口。

强制创建 MongoDB 集群

在接下来的小节中,我们将在命令行上使用 kubectl 为 MongoDB 集群创建一个 Kubernetes 复制控制器和服务。

创建复制控制器

要为具有 2 个副本和端口 27017 的 Docker 映像“mongo”创建复制控制器,请运行以下命令。

kubectl run mongo --image=mongo --replicas=2 --port=27017

复制控制器的创建如图 7-36 所示。

A418863_1_En_7_Fig36_HTML.gif

图 7-36。

Creating a Replication Controller Imperatively

使用以下命令列出 pod。

kubectl get rc

mongo -rc 列表如图 7-37 所示。

A418863_1_En_7_Fig37_HTML.gif

图 7-37。

Listing the Replication Controllers

列出 POD

使用以下命令列出 pod。

kubectl get pods

为 MongoDB get 启动的两个 Pods 列表如图 7-38 所示。最初,pod 可能会被列为未运行。

A418863_1_En_7_Fig38_HTML.gif

图 7-38。

Listing the Pods with some of the pods not Running yet

如图 7-39 所示,如果需要将 pod 列为正在运行,请多次运行以下程序。

A418863_1_En_7_Fig39_HTML.gif

图 7-39。

Listing all the Pods as Running

列出日志

使用以下命令列出 Pod 的日志。mongo-56850是 Pod 名称。

kubectl logs mongo-56850

Pod 日志列表如图 7-40 所示。

A418863_1_En_7_Fig40_HTML.gif

图 7-40。

Listing Pod Logs

MongoDB 被列为已启动,如图 7-41 所示。在服务器上运行的命令也会得到输出。

A418863_1_En_7_Fig41_HTML.gif

图 7-41。

Listing MongoDB Server as running and waiting for connections on port 27017

创建服务

要为mongo复制控制器创建一个服务,运行下面的命令在端口 27017 上公开一个类型为LoadBalancer的服务,这在前面已经讨论过了。

kubectl expose rc mongo --port=27017 --type=LoadBalancer

mongo服务被创建,如图 7-42 所示。

A418863_1_En_7_Fig42_HTML.gif

图 7-42。

Creating a Service Imperatively

使用以下命令列出服务。

kubectl get services

在图 7-43 中mongo服务被列为正在运行。

A418863_1_En_7_Fig43_HTML.gif

图 7-43。

Listing the Services including the mongo Service

交互式终端和 Mongo shell 可以开始创建 MongoDB 数据库和集合,以便在集合中添加和查询文档,正如在以声明方式创建 MongoDB 集群时所讨论的那样。

扩展集群

例如,要将群集扩展到 4 个副本,请运行以下命令。

kubectl scale rc mongo --replicas=4

输出“scaled”表示集群已被缩放,如图 7-44 所示。

A418863_1_En_7_Fig44_HTML.gif

图 7-44。

Scaling the Cluster created Imperatively

随后得到 POD。

kubectl get pods

列出四个吊舱,如图 7-45 所示。最初,一些 pod 可能显示为未运行或就绪。

A418863_1_En_7_Fig45_HTML.gif

图 7-45。

Listing Pods after Scaling

要描述mongo服务,请运行以下命令。

kubectl describe svc mongo

除了服务端点之外,服务描述还包括服务标签、选择器,如图 7-46 所示,四个 pod 各有一个。

A418863_1_En_7_Fig46_HTML.gif

图 7-46。

Describing the Service mongo after Scaling

删除服务和复制控制器

可以使用以下命令删除mongo服务和mongo复制控制器。

kubectl delete service mongo
kubectl delete rc mongo

“mongo”服务和“mongo”复制控制器被删除,如图 7-47 所示。删除一个不会删除另一个;复制控制器与服务的分离是一个适合于发展一个而不必修改另一个的特性。

A418863_1_En_7_Fig47_HTML.gif

图 7-47。

Deleting the Service and the Replication Controller

摘要

在本章中,我们使用 Kubernetes 集群管理器来创建和编排一个 MongoDB 集群。我们强制性地和声明性地创建了一个复制控制器和一个服务。我们还演示了如何扩展集群。我们介绍了 Kubernetes 复制控制器的另外两个特性:卷和主机端口。这一章是关于在 MongoDB 中使用 Kubernetes 的,重点不是在 MongoDB 上;但如果要更详细地探究 MongoDB,请参考 Apress 的书 Pro MongoDB Development(http://www.apress.com/9781484215999?gtmf=s)。在下一章,我们将讨论另一个 NoSQL 数据库,Apache Cassandra。

八、使用 Apache Cassandra 数据库

Apache Cassandra 是一个开源的宽列数据存储。Cassandra 是一个可伸缩的、可靠的、容错的、高度可用的 NoSQL 数据库。Cassandra 基于一种灵活的模式数据模型,在该模型中,数据存储在表的行中(也称为列族),主键标识一行。主键可以是单列或多列(复合)行键。关系数据库也在表行中存储数据,但 Cassandra 的不同之处在于表行不必遵循固定的模式。表中的每一行可能有不同的列,或者某些列可能与其他行相同。每行不必包含所有列或任何列数据。在这方面,Cassandra 提供了动态列规范。keyspace 是存储在 Cassandra 中的数据的名称空间容器。在本章中,我们将讨论在 Apache Cassandra 中使用 Kubernetes 集群管理器。本章包括以下几节。

  • 设置环境
  • 以声明方式创建 Cassandra 集群
  • 创建 Cassandra 集群势在必行

设置环境

本章需要以下软件。

  • -Docker 引擎(最新版本)
  • -Kubernetes(1.01 版)
  • -Kubernetes(1.01 版)
  • Apache Cassandra 的 Docker 映像(最新版本)

按照第一章所述,在从 Ubuntu Server 14.04 LTS (HVM)、SSD 卷类型- ami-d05e75b8 AMI 创建的 Amazon EC2 实例上安装软件。使用 Amazon EC2 实例的公共 IP 地址 SSH 登录到 Ubuntu 实例。

ssh -i "docker.pem" ubuntu@52.23.160.7

启动 Docker 引擎并验证其状态。

sudo service docker start
sudo service docker status

对接引擎应如图 8-1 所示运行。

A418863_1_En_8_Fig1_HTML.gif

图 8-1。

Starting Docker

列出服务。

kubectl

get services

应列出“kubernetes”服务,如图 8-2 所示。

A418863_1_En_8_Fig2_HTML.gif

图 8-2。

Listing the “kubernetes” Service

使用以下命令列出窗格和节点。

kubectl get pods
kubectl get nodes

最初,唯一运行的 pod 是 Kubernetes pod,如图 8-3 所示。

A418863_1_En_8_Fig3_HTML.gif

图 8-3。

Listing the Pod and Node for Kubernetes

Cassandra 集群可以通过声明和命令两种方式创建和管理,我们将讨论这两种方式。

以声明方式创建 Cassandra 集群

在下面的小节中,我们已经讨论了使用基于 YAML 格式的定义文件创建 Cassandra 集群。首先,创建一个代表 Cassandra 集群的服务。服务是 pod 集群的外部接口,在本章的上下文中称为 Apache Cassandra pods。

创建服务

创建一个名为cassandra-service.yaml的服务定义文件。添加表 8-1 中讨论的字段。

表 8-1。

Fields in the Service Definition File

| 田 | 描述 | 价值 | | --- | --- | --- | | apiVersion(堆叠版本) | API 版本。 | 第五颅神经的眼支 | | 种类 | 类似于定义文件。 | 服务 | | 元数据 | 服务的元数据。 |   | | 元数据->名称 | 服务名称。必填字段。 | 凶事预言家 | | 元数据->标签 | 服务标签。标签可以是任何键->值对。一个服务标签设置为 app:cassandra。 | 应用:卡珊德拉 | | 投机 | 服务规范。 |   | | 规格->标签 | 规格标签。标签可以是任何键->值对。服务标签设置为 app:Cassandra。 | 应用:卡珊德拉 | | 规格->选择器 | 服务选择器。用于选择要管理的窗格。标签与选择器表达式相同的窗格由服务选择或管理。选择器表达式可以是任何键:值对。或者,可以使用','指定多个需求或表达式。app:cassandra 设置转换为服务选择器 app = cassandra。 | 应用:卡珊德拉 | | 规格->端口 | 服务端口。端口字段是必需的。 |   | | 规格->端口->端口 | 一个服务端口,服务通过该端口公开,供外部客户端访问。 | Nine thousand and forty-two | | 规格->类型 | 服务类型。 | LoadBalancer(负载均衡器) |

下面列出了cassandra-service.yaml。使用 YAML Lint ( http://www.yamllint.com/ )来验证语法。

apiVersion: v1
kind: Service
metadata:
  name: cassandra
  labels:
    app: cassandra
spec:
  labels:
    app: cassandra
  selector:
    app: cassandra
  ports:
    -
      port: 9042
  type: LoadBalancer

可以在 vi 编辑器中创建cassandra-service.yaml文件,并使用:wq 命令保存,如图 8-4 所示。

A418863_1_En_8_Fig4_HTML.gif

图 8-4。

Service Definition File in vi Editor

要创建服务,请运行以下命令。

kubectl create -f cassandra-service.yaml

随后列出服务。

kubectl get services

cassandra服务列表如图 8-5 所示。

A418863_1_En_8_Fig5_HTML.gif

图 8-5。

Creating and listing a Service for Apache Cassandra

用下面的命令描述cassandra服务。

kubectl describe svc cassandra

服务名称、名称空间、标签、选择器、类型、IP、端口、节点端口和端点被列出,如图 8-6 所示。最初没有列出服务端点,因为尚未创建 Pod。

A418863_1_En_8_Fig6_HTML.gif

图 8-6。

Describing the Service for Apache Cassandra

创建复制控制器

接下来,我们将为 Cassandra 创建一个复制控制器。复制控制器定义容器的配置和它们在 Pod 中各自的 Docker 映像。创建一个定义文件cassandra-rc.yaml并添加以下(表 8-2 )字段。

表 8-2。

Fields in the Replication Controller Definition File

| 田 | 描述 | 价值 | | --- | --- | --- | | apiVersion(堆叠版本) | API 版本。 | 第五颅神经的眼支 | | 种类 | 定义文件的种类。 | 复制控制器 | | 元数据 | 复制控制器元数据。 |   | | 元数据->标签 | 复制控制器标签。key:value pair app:cassandra 被设置为复制控制器上的一个标签。 | 应用:卡珊德拉 | | 投机 | 复制控制器规范。 |   | | 规格->副本 | 副本的数量。 | one | | 规格->选择器 | 复制控制器的选择器表达式。必须与规格->模板->元数据->标签字段中的标签之一相同。必填字段,但不需要明确设置,默认为规格->模板->元数据->标签字段中的标签。如果在选择器中设置了多个要求,Pod 模板标签中的多个标签必须匹配。例如,如果`selector`是`app=cassandra,name=cassandra`,则 Pod 模板标签 spec->template->metadata->标签必须包括这两个标签。 |   | | 规格->模板 | Pod 模板。必填字段。 |   | | 规格->模板->元数据 | 模板元数据。 |   | | 规格->模板->元数据->标签 | 模板标签。关键:值对 app:cassandra 设置为 Pod 上的标签。必须在模板上设置标签。标签设置翻译成 Pod 标签 app=cassandra。 | 应用:卡珊德拉 | | 规格->模板->规格 | 容器规格。 |   | | 规格->模板->规格->容器 | POD 里的容器。 |   | | 规格->模板->规格->容器->映像 | 容器的 Docker 映像。 | 凶事预言家 | | 规格->模板->规格->容器->名称 | 容器名称。 | 凶事预言家 | | 规格->模板->规格->容器->端口 | 容器港口。 |   | | 规格->模板->规格->容器->端口->容器端口 | CQL 命令 shell 的容器端口。 | Nine thousand and forty-two | | 规格->模板->规格->容器->端口->名称 | 端口名称。 | 持续查询语言 | | 规格->模板->规格->容器->端口->容器端口 | 节俭客户的容器港口。 | Nine thousand one hundred and sixty | | 规格->模板->规格->容器->端口->名称 | 端口名称。 | 节约 |

cassandra-rc.yaml已列出。

apiVersion: v1
kind: ReplicationController
metadata:
  name: cassandra-rc
  labels:
    app: cassandra
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: cassandra
    spec:
      containers:
        -
        image: cassandra
        name: cassandra
        ports:
          -
            containerPort: 9042
            name: cql
          -
            containerPort: 9160
            name: thrift

可以在 vi 编辑器中创建cassandra-rc.yaml字段,并用:wq 命令保存,如图 8-7 所示。

A418863_1_En_8_Fig7_HTML.gif

图 8-7。

Replication Controller Definition File in vi Editor

使用以下命令创建一个复制控制器。

kubectl create -f cassandra-rc.yaml

随后列出复制控制器。

kubectl get rc

cassandra-rc复制控制器被创建并列出,如图 8-8 所示。

A418863_1_En_8_Fig8_HTML.gif

图 8-8。

Creating a Replication Controller from Definition File

列出由复制控制器创建的窗格。

kubectl get pods

当复制控制器定义文件中的副本数量设置为 1 时,会创建一个 Pod,并在图 8-9 中列出。前面的命令可能需要运行多次才能将 Pod 列为正在运行和就绪。或者,在创建复制控制器几秒钟后第一次运行该命令;到一分钟时,所有的吊舱都应该已经启动了。

A418863_1_En_8_Fig9_HTML.gif

图 8-9。

Listing Pod/s for Apache Cassandra

描述一下卡珊德拉服务。

kubectl describe svc cassandra

为 Pod 列出一个端点,如图 8-10 所示。当在创建复制控制器之前列出服务描述时,没有列出任何端点。

A418863_1_En_8_Fig10_HTML.gif

图 8-10。

Describing the Service after creating the Replication Controller

在前面的示例中,我们创建了一个复制控制器,副本数量设置为 1。复制控制器不必一开始就创建副本。为了进行演示,我们将再次创建复制控制器,但使用不同的副本设置。删除先前创建的复制控制器。

kubectl delete rc cassandra-rc

修改cassandra-rc.yaml将副本字段设置为 0,如图 8-11 所示。

A418863_1_En_8_Fig11_HTML.gif

图 8-11。

Setting Replicas to 0

使用修改后的定义文件再次创建复制控制器。

kubectl create -f cassandra-rc.yaml

随后列出副本。

kubectl get rc

cassandra-rc复制控制器被创建并列出,如图 8-12 所示。

A418863_1_En_8_Fig12_HTML.gif

图 8-12。

Creating the Replication Controller with Modified Definition File

列出 POD。

kubectl get pods

因为副本字段被设置为 0,所以副本被列为 0,如图 8-13 所示。

A418863_1_En_8_Fig13_HTML.gif

图 8-13。

With Replicas as 0 no Pod gets created

扩展数据库

从创建了 0 个副本的复制控制器开始,我们应该将群集扩展到单个副本。运行以下命令将 Pod 集群扩展到 1 个副本。

kubectl scale rc cassandra-rc --replicas=1

随后列出 POD。

kubectl get pods

前述命令的输出如图 8-14 所示。“scaled”输出表示群集已被缩放。单个 Pod 可能需要一段时间(几秒钟)才能启动并准备就绪。

A418863_1_En_8_Fig14_HTML.gif

图 8-14。

Scaling the Replication Controller to 1 Pod

再次描述一下cassandra服务。

kubectl describe svc cassandra

如图 8-15 所示,添加的 Pod 应列出一个端点。

A418863_1_En_8_Fig15_HTML.gif

图 8-15。

Describing the Service after Scaling the Cluster

描述 Pod

要描述 Pod,请运行以下命令。

kubectl describe pod cassandra-rc-tou4u

输出有关 Pod 的详细信息,如名称、名称空间、映像、节点、标签、状态、IP 地址和事件,如图 8-16 所示。Pod 标签是复制控制器定义文件中指定的app=cassandra

A418863_1_En_8_Fig16_HTML.gif

图 8-16。

Describing the single Pod

启动交互式 Shell

由于“cassandra”Docker 映像继承自“debian”Docker 映像,因此可以使用交互式 bash shell 来访问基于 Cassandra 映像的 Docker 容器。要启动一个交互式 bash shell 来访问 Docker 容器中运行的 Cassandra 服务器,我们需要获取容器 id。列出正在运行的容器。

sudo docker ps

所有正在运行的容器被列出,如图 8-17 所示。复制cassandra映像容器的容器 id。

A418863_1_En_8_Fig17_HTML.gif

图 8-17。

Listing the Docker Containers

使用容器 id 启动一个交互式 bash shell。

sudo docker exec -it e8fc5e8ddff57 bash

如图 8-18 所示,启动一个交互式外壳。

A418863_1_En_8_Fig18_HTML.gif

图 8-18。

Starting the Interactive Shell

启动 CQL Shell

Cassandra 查询语言(CQL)是 Apache Cassandra 的查询语言。在下面几节中,我们将运行 CQL 命令来创建一个键空间和一个表。使用以下命令启动 CQL Shell。

cqlsh

CQL 壳牌 5.0.1 启动如图 8-19 所示。

A418863_1_En_8_Fig19_HTML.gif

图 8-19。

Starting the cqlsh Shell

创建密钥空间

接下来,使用复制类 SimpleStrategy 和复制因子 3 创建一个名为 CatalogKeyspace 的键空间。

CREATE KEYSPACE CatalogKeyspace
            WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 3};

创建一个键空间,如图 8-20 所示。

A418863_1_En_8_Fig20_HTML.gif

图 8-20。

Creating a Keyspace

更改密钥空间

可以使用 ALTER KEYSPACE 命令更改密钥空间。运行以下命令,将密钥空间设置复制因子更改为 1。

ALTER KEYSPACE CatalogKeyspace
          WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 1};

如图 8-21 所示,键空间被改变。

A418863_1_En_8_Fig21_HTML.gif

图 8-21。

Altering a Keyspace

使用密钥空间

要使用CatalogKeyspace键区,运行以下命令。

use CatalogKeyspace;

键区CatalogKeyspace的设置如图 8-22 所示。

A418863_1_En_8_Fig22_HTML.gif

图 8-22。

Setting a Keyspace to be used

创建表格

表也称为柱族。CREATE TABLECREATE COLUMN FAMILY子句都可以用来创建一个表(列族)。使用下面的 CQL 语句创建一个名为catalog的表。

CREATE TABLE catalog(catalog_id text,journal text,publisher text,edition text,title text,author text,PRIMARY KEY (catalog_id)) WITH compaction = { 'class' : 'LeveledCompactionStrategy' };

使用以下 CQL 语句向表中添加两行数据。

INSERT INTO catalog (catalog_id, journal, publisher, edition,title,author) VALUES ('catalog1','Oracle Magazine', 'Oracle Publishing', 'November-December 2013', 'Engineering as a Service','David A. Kelly') IF NOT EXISTS;
INSERT INTO catalog (catalog_id, journal, publisher, edition,title,author) VALUES ('catalog2','Oracle Magazine', 'Oracle Publishing', 'November-December 2013', 'Quintessential and Collaborative','Tom Haunert') IF NOT EXISTS;

前述命令的输出如图 8-23 所示。创建一个 Cassandra 表并添加两行数据。

A418863_1_En_8_Fig23_HTML.gif

图 8-23。

Creating an Apache Cassandra Table

运行以下 CQL 查询语句从catalog表中选择数据。

SELECT * FROM catalog;

添加的两行数据被列出,如图 8-24 所示。

A418863_1_En_8_Fig24_HTML.gif

图 8-24。

Querying an Apache Cassandra Table

从表格中删除

要删除数据行,运行DELETE CQL 语句。主键列值不能用DELETE删除。用下面的 CQL 语句删除catalog_id为“目录”的行的其他列值。

DELETE journal, publisher, edition, title, author from catalog WHERE catalog_id='catalog1';

随后运行下面的 CQL 查询,从catalog表中选择数据。

SELECT * FROM catalog;

如图 8-25 所示,只有一行完整的数据被输出。另一行只列出了catalog_id列的值,其他所有列的值都是null

A418863_1_En_8_Fig25_HTML.gif

图 8-25。

Querying Table after deleting Data from a Row

截断表格

截断表意味着删除包括主键列值在内的所有表数据。运行下面的TRUNCATE CQL 语句删除所有行。

TRUNCATE catalog;

随后再次运行 CQL 查询语句。

SELECT * from catalog;

没有列出如图 8-26 所示的行;运行一个TRUNCATE语句后,甚至不会列出空值。

A418863_1_En_8_Fig26_HTML.gif

图 8-26。

Querying a Table after Truncating a Table

删除表和键空间

要删除一个表,请运行带有DROP TABLE子句的 CQL 语句。如果该表存在,则IF EXISTS子句删除该表,但如果该表不存在,则不返回错误。

DROP TABLE IF EXISTS catalog;

使用DROP KEYSPACE子句语句删除CatalogKeyspace键空间。如果键空间存在,则IF EXISTS子句删除该键空间,但是如果键空间不存在,则不返回错误。

DROP KEYSPACE IF EXISTS CatalogKeyspace;

要验证密钥空间CatalogKeyspace是否已被删除,请运行以下语句。

use CatalogKeyspace;

由于CatalogKeyspace键区不存在,产生如图 8-27 所示的错误。

A418863_1_En_8_Fig27_HTML.gif

图 8-27。

Dropping a Table

创建卷

在第七章中,我们介绍了卷,如何使用卷挂载将它们挂载到 Pod 中,以及如何在容器中访问它们。我们介绍了各种类型的卷,并演示了emptyDir类型的卷。在本节中,我们将使用另一种类型的卷,即hostPath卷。hostPath卷将一个目录从主机装载到 Pod 中。Pod 中的所有容器和基于使用hostPath类型卷的 Pod 模板的所有 Pod 都可以访问主机上的目录。作为对前面使用的复制控制器的修改,我们将向cassandra-rc.yaml文件添加一个类型为hostPath的卷。例如,如果主机目录/cassandra/data要安装在 Pod 中,则在 spec- >模板字段中添加以下卷。

volumes:
  -
    hostPath:
      path: /cassandra/data
    name: cassandra-storage

使用与emptyDir卷相同的字段将卷安装在 Pod 中。修改后的cassandra-rc.yaml被列出。

apiVersion: v1
kind: ReplicationController
metadata:
  name: cassandra-rc
  labels:
    app: cassandra
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: cassandra
    spec:
      containers:
        -
        image: cassandra
        name: cassandra
        ports:
          -
            containerPort: 9042
            name: cql
          -
            containerPort: 9160
            name: thrift
        volumeMounts:
          -
            mountPath: /cassandra/data
            name: cassandra-storage
      volumes:
        -
          hostPath:
            path: /cassandra/data
          name: cassandra-storage

cassandra-rc.yaml定义文件可以在 vi 编辑器中编辑,并用:wq 命令保存,如图 8-28 所示。建议在字段值中添加引号。

A418863_1_En_8_Fig28_HTML.gif

图 8-28。

Replication Controller Definition File with a Volume of type hostPath

装载到 Pod 中的主机目录必须预先存在。创建/cassandra/data目录并将其权限设置为全局(777)。

sudo mkdir –p /cassandra/data
sudo chmod –R 777 /cassandra/data

前述命令的输出如图 8-29 所示。创建了/cassandra/data目录。

A418863_1_En_8_Fig29_HTML.gif

图 8-29。

Creating the Directory for the Volume

将目录(cd)更改为主机上的/cassandra/data目录。

cd /cassandra/data

列出/cassandra/data目录中的文件和目录。

ls –l

最初/cassandra/data为空,如图 8-30 所示。使用 vi 编辑器将示例文件cassandra.txt添加到目录中。随后再次列出目录文件和目录。

A418863_1_En_8_Fig30_HTML.gif

图 8-30。

Adding a file in the hostPath Volume Directory

vi cassandra.txt
ls –l

如图 8-30 所示cassandra.txt文件被列出。hostPath卷的作用是使/cassandra/data目录对 Pod 中的所有容器可用。

按照前面对定义文件的讨论,创建一个复制控制器。应该创建一个 Pod。列出 Docker 容器。

sudo docker ps

复制映像“cassandra”的 Docker 容器的容器 id,如图 8-31 所示。

A418863_1_En_8_Fig31_HTML.gif

图 8-31。

Listing the Docker Containers

使用容器 id 启动一个交互式 shell。

sudo docker exec -it 11a4b26d9a09 bash

交互外壳启动,如图 8-32 所示。

A418863_1_En_8_Fig32_HTML.gif

图 8-32。

Starting an Interactive Shell

将目录(cd)更改为/cassandra/data目录,并列出目录中的文件。

cd /cassandra/data
ls –l

如图 8-33 所示,cassandra.txt 文件被列出。/cassandra/data 目录存在于主机上,但可以从容器中访问。

A418863_1_En_8_Fig33_HTML.gif

图 8-33。

Accessing the Volume in a Docker Container

类似地,可以创建其他类型的卷。以下是 AWS 卷的volumeMountsvolumes fields设置。volumeID字段的格式为aws://zone/volume id。

    volumeMounts:
        -
          mountPath: /aws-ebs
          name: aws-volume
  volumes:
      -
        name: aws-volume
        awsElasticBlockStore:
              volumeID: aws://us-east-ib/vol-428ba3ae
              fsType: ext4

更完整的cassandra-rc.yaml文件如图 8-34 所示。

A418863_1_En_8_Fig34_HTML.gif

图 8-34。

Volume of type awsElasticBlockStore in a Replication Controller Definition File

创建 Cassandra 集群势在必行

如果要使用大多数字段的默认设置,强制创建一个复制控制器是更好的选择。

创建复制控制器

要在命令行上创建复制控制器,请使用kubectl run命令。对于基于 Docker 映像“cassandra”的复制控制器,运行以下命令,其中复制控制器名称为“cassandra ”,端口为 9042。副本设置为 1,也是默认值。

kubectl run cassandra --image=cassandra --replicas=1 --port=9042

随后列出复制控制器。

kubectl get rc

“cassandra”复制控制器被创建并列出,如图 8-35 所示。

A418863_1_En_8_Fig35_HTML.gif

图 8-35。

Creating a Replication Controller Imperatively

要列出窗格,请运行以下命令。

kubectl get pods

创建的单个 Pod 被列出,如图 8-36 所示。

A418863_1_En_8_Fig36_HTML.gif

图 8-36。

Listing the single Pod

要描述复制控制器,请运行以下命令。

kubectl describe rc cassandra

复制控制器的名称、命名空间、映像、选择器、标签、副本、pod 状态和事件会被列出,如图 8-37 所示。对于cassandra复制控制器,选择器默认为“run=cassandra”。

A418863_1_En_8_Fig37_HTML.gif

图 8-37。

Describing the Replication Controller

创建服务

要将复制控制器cassandra作为服务公开,请运行kubectl expose命令。需要指定端口,并为该服务设置为 9042。

kubectl expose rc cassandra --port=9042 --type=LoadBalancer

cassandra服务被创建,如图 8-38 所示。

A418863_1_En_8_Fig38_HTML.gif

图 8-38。

Creating a Service for Apache Cassandra Imperatively

用下面的命令描述服务。

kubectl describe service cassandra

如图 8-39 所示,列出了服务名称、名称空间、标签、选择器、类型、IP、端口、节点端口和端点。服务选择器 run=cassandra 必须与要管理的 Pod 上的标签相同。

A418863_1_En_8_Fig39_HTML.gif

图 8-39。

Describing the Service

扩展数据库

要扩展集群,运行kubectl scale命令。扩展 Cassandra 复制控制器的一个重要原因是运行更多的 Cassandra 节点,并让它们加入集群,我们演示了如何扩展集群。但是并不总是需要扩展集群。集群也可以缩小。要将群集缩减到 0 个副本,请运行以下命令。

kubectl scale rc cassandra --replicas=0

图 8-40 中的“scaled”输出表示组合仪表已经缩小。

A418863_1_En_8_Fig40_HTML.gif

图 8-40。

Scaling Down the Database Cluster to 0 Replicas

列出 POD。

kubectl get pods

没有 pod 被列出,如图 8-41 所示。

A418863_1_En_8_Fig41_HTML.gif

图 8-41。

Listing the Pods after Scaling Down

使用以下命令列出服务。

kubectl get services

将集群扩展到 0 个副本将不会为服务留下要管理的 Pod,但服务仍在运行,如图 8-42 所示。

A418863_1_En_8_Fig42_HTML.gif

图 8-42。

Listing the Services after Scaling Down

但是该服务没有任何与之关联的端点,如图 8-43 中的kubectl describe命令所示。

A418863_1_En_8_Fig43_HTML.gif

图 8-43。

Describing the Service after Scaling Down

删除复制控制器和服务

要删除复制控制器“cassandra ”,请运行以下命令。

kubectl delete rc cassandra

随后列出复制控制器。

kubectl get rc

要删除服务“cassandra ”,请运行以下命令。

kubectl delete service cassandra

随后列出服务。

kubectl get services

前面命令的输出如图 8-44 所示。复制控制器和服务将被删除,但不会列出。

A418863_1_En_8_Fig44_HTML.gif

图 8-44。

Deleting the Replication Controller and the Service

摘要

在本章中,我们使用 Kubernetes 创建了一个 Apache Cassandra 集群。我们同时使用了声明式和命令式方法。我们在前一章中介绍了卷,在本章中,我们讨论了使用另外两种类型的卷:hostPath 和 AWS 卷。我们不仅扩大了集群,还缩小了集群。我们演示了复制控制器不需要 Pod 运行,并且可以指定 0 个副本。在下一章中,我们将讨论使用 Kubernetes 集群管理器和另一个 NoSQL 数据库 Couchbase。

九、使用 Couchbase

Couchbase 是一个基于 JSON 数据模型的分布式 NoSQL 数据库。Couchbase 比 MongoDB 和 Apache Cassandra 都快。Couchbase 提供了一些 MongoDB 和 Cassandra 中没有的特性,比如图形用户界面(GUI),Couchbase Web 控制台。Couchbase 还提供了命令行工具,比如couchbase-clicbbackupcbrestorecbtransfer。作为一个分布式数据库,Couchbase 可以从 Kubernetes 集群管理器提供的集群管理中获益,这是我们将在本章中讨论的。本章包括以下几节。

  • 设置环境
  • 以声明方式创建 Couchbase 集群
  • 强制创建 Couchbase 集群

设置环境

我们在 Amazon EC2 上使用了一个 Ubuntu 实例,它是使用其他章节中使用的相同 AMI 创建的,Ubuntu Server 14.04 LTS (HVM),SSD 卷类型- ami-d05e75b8。如果从 AMI 创建的实例已经存在,则可以使用相同的实例。本章需要以下软件。

  • -Docker 引擎(最新版本)
  • -Kubernetes(1.01 版)
  • -Kubernetes(1.01 版)
  • Couchbase 的 Docker 映像(最新版本)

首先,我们需要登录到 Ubuntu 实例。从 Amazon EC2 实例控制台获取 Ubuntu 实例的公共 IP 地址,如图 9-1 所示。

A418863_1_En_9_Fig1_HTML.gif

图 9-1。

Getting Public IP Address

使用公共 IP 地址登录 Ubuntu 实例。

ssh -i "docker.pem" ubuntu@54.172.55.212

Ubuntu 实例被登录,如图 9-2 所示。

A418863_1_En_9_Fig2_HTML.gif

图 9-2。

Logging into Ubuntu Instance on Amazon EC2

启动 Docker 引擎并验证其状态。

sudo service docker start
sudo service docker status

如图 9-3 所示,Docker 引擎应被列为正在运行。

A418863_1_En_9_Fig3_HTML.gif

图 9-3。

Starting Docker Engine

列出正在运行的服务。

kubectl get services

kubernetes 服务应被列为正在运行,如图 9-4 所示。

A418863_1_En_9_Fig4_HTML.gif

图 9-4。

Listing the “kubernetes” Service

列出节点。

kubectl get nodes

该节点应以“就绪”状态列出,如图 9-5 所示。

A418863_1_En_9_Fig5_HTML.gif

图 9-5。

Listing the Single Node

以声明方式创建 Couchbase 集群

在下面的小节中,我们将使用定义文件创建一个 Couchbase Pod、一个复制控制器和一个服务。

创建 Pod

Pod 定义文件用于创建单个 Pod。一个 Pod 可以有 0 个或多个容器配置。创建一个定义文件couchbase.yaml。将以下(表 9-1 )字段添加到定义文件中。

表 9-1。

Pod Definition File Fields

| 田 | 描述 | 价值 | | --- | --- | --- | | apiVersion(堆叠版本) |   | 第五颅神经的眼支 | | 种类 | 定义文件的种类。 | POD | | 元数据 | Pod 元数据。 |   | | 元数据->标签 | POD 标签。服务选择器利用标签来选择要管理的 pod。 | app:couch app | | 元数据->名称 | Pod 名称。 | 美洲狮号 | | 投机 | Pod 规格。 |   | | 规格->容器 | POD 里的容器。 |   | | 规格->容器->映像 | 容器映像。对于 Couchbase 服务器,映像是“couchbase” | 美洲狮号 | | 规格->容器->名称 | 容器名称。 | 美洲狮号 | | 规格->容器->端口 | 容器港口。 |   | | 规格->容器->端口->容器端口 | Couchbase 服务器的容器端口。 | Eight thousand and ninety-one |

列出couchbase.yaml定义文件。

apiVersion: v1
kind: Pod
metadata:
  labels:
    app: couchbaseApp
  name: couchbase
spec:
  containers:
    -
      image: couchbase
      name: couchbase
      ports:
        -
          containerPort: 8091

可以在 vi 编辑器中创建couchbase.yaml文件,并用:wq 命令保存,如图 9-6 所示。

A418863_1_En_9_Fig6_HTML.gif

图 9-6。

Pod Definition file couchbase.yaml in vi Editor

运行以下命令从定义文件创建一个 Pod。

kubectl create -f couchbase.yaml

如图 9-7 中的“Pod/couch base”输出所示,创建一个 Pod。

A418863_1_En_9_Fig7_HTML.gif

图 9-7。

Creating a Pod from the Definition File

随后列出 POD。

kubectl get pods

名为“couchbase”的 Pod 被列出,如图 9-7 所示。最初,状态可以不同于“正在运行”,并且就绪列可以是未就绪的;1/1 处于就绪状态,0/1 未就绪。

几秒钟后再次运行以下命令。

kubectl get pods

如图 9-8 所示couchbase吊舱被列为“运行中”和就绪- > 1/1。

A418863_1_En_9_Fig8_HTML.gif

图 9-8。

Listing the couchbase Pod

创建服务

在本节中,我们将使用服务定义文件创建一个服务。创建一个couchbase-service.yaml文件,并将以下(表 9-2 )字段添加到文件中。

表 9-2。

Service Definition File couchbase-service.yaml

| 田 | 描述 | 价值 | | --- | --- | --- | | apiVersion(堆叠版本) |   | 第五颅神经的眼支 | | 种类 | 定义文件的种类。 | 服务 | | 元数据 | 服务元数据。 |   | | 元数据->标签 | 服务标签。 | app:couch app | | 元数据->名称 | 服务名称。 | 美洲狮号 | | 投机 | 服务规范。 |   | | 规格->端口 | 服务公开的端口。 |   | | 规格->端口->端口 | 服务公开的端口。 | Eight thousand and ninety-one | | 规格>连接埠>目标连接埠 | 服务的目标端口,可以是端口号或后端端口的名称。目标端口设置增加了灵活性,因为端口号可以修改,而端口名称保持不变。 | Eight thousand and ninety-one | | 规格->选择器 | Pod 选择器,可以是一个或多个标签键:值表达式/标签。选择器中的所有 key:value 表达式必须与服务要选择的 Pod 的标签相匹配。Pod 可以有额外的标签,但必须在服务选择的选择器中包含标签。服务将流量路由到标签与选择器表达式匹配的 pod。在示例服务定义文件中仅使用了一个选择器表达式。如果选择器为空,则选择所有窗格。app: couchbaseApp 设置默认为选择器 app = couchbaseApp。 | app:couch app | | 规格->选择器->类型 | 服务类型。 | LoadBalancer(负载均衡器) |

couchbase-service.yaml已列出。

apiVersion: v1
kind: Service
metadata:
  labels:
    app: couchbaseApp
  name: couchbase
spec:
  ports:
    -
      port: 8091
      targetPort: 8091
  selector:
    app: couchbaseApp
  type: LoadBalancer

使用以下命令从定义文件创建服务。

kubectl create -f couchbase-service.yaml

随后列出正在运行的服务。

kubectl get services

如图 9-9 所示的“services/couchbase”输出表明couchbase服务已经被创建。“couchbase”服务被列出,如图 9-9 所示。

A418863_1_En_9_Fig9_HTML.gif

图 9-9。

Listing the couchbase Service

使用以下命令列出服务端点。

kubectl get endpoints

couchbase服务的服务端点如图 9-10 所示。

A418863_1_En_9_Fig10_HTML.gif

图 9-10。

Listing the Endpoints

创建复制控制器

在本节中,我们将使用一个定义文件创建一个复制控制器。创建一个couchbase-rc.yaml文件,并将以下(表 9-3 )字段添加到文件中。

表 9-3。

Definition File for Replication Controller

| 田 | 描述 | 价值 | 必填字段(包括默认设置) | | --- | --- | --- | --- | | apiVersion(堆叠版本) |   | 第五颅神经的眼支 | 是 | | 种类 | 定义文件的种类。 | 复制控制器 | 是 | | 元数据 | 复制控制器元数据。 |   | 是 | | 元数据->标签 | 复制控制器标签。 | app:couch app | 不 | | 元数据->名称 | 复制控制器的名称。 | 美洲狮号 | 是 | | 投机 | 复制控制器规范。 |   | 是 | | 规格->副本 | Pod 副本的数量。默认为 1 个副本。 | Two | 是 | | 规格->选择器 | 一个或多个 key:value 表达式,用于选择要管理的窗格。包含具有与选择器表达式相同的表达式的标签的窗格由复制控制器管理。Pod 可以包括附加标签,但必须包括由复制控制器管理的选择器中的标签。如果未指定,选择器默认为规范->模板->元数据->标签键:值表达式。app 的一个设置:couchbaseApp 翻译成选择器 app = couchbaseApp。 | app:couch app | 是 | | 规格->模板 | Pod 模板。 |   | 是 | | 规格->模板->元数据 | Pod 模板元数据。 |   | 是 | | 规格->模板->元数据->标签 | Pod 模板标签。 | app:couch app | 是 | | 规格->模板->规格 | Pod 模板规范。 |   | 是 | | 规格->模板->规格->容器 | Pod 模板的容器配置。 |   | 是 | | 规格->模板->规格->容器->映像 | Docker 的形象。 | 美洲狮号 | 是 | | 规格->模板->规格->容器->名称 | 容器名称。 | 美洲狮号 | 是 | | 规格->模板->规格->容器->端口 | 容器港口。 |   | 不 | | 规格->模板->规格->容器->端口->容器端口 | 容器港口。 | Eight thousand and ninety-one | 不 |

couchbase-rc.yaml已列出。

apiVersion: v1
kind: ReplicationController
metadata:
  labels:
    app: couchbaseApp
  name: couchbase
spec:
  replicas: 2
  selector:
    app: couchbaseApp
  template:
    metadata:
      labels:
        app: couchbaseApp
    spec:
      containers:
        -
          image: couchbase
          name: couchbase
          ports:
          -
            containerPort: 8091

可以在 vi 编辑器中创建couchbase-rc.yaml,如图 9-11 所示。

A418863_1_En_9_Fig11_HTML.gif

图 9-11。

Replication Controller Definition File couchbase-rc.yaml in vi Editor

使用以下命令创建复制控制器。

kubectl create -f couchbase-rc.yaml

随后,列出复制控制器。

kubectl get rc

如图 9-12 所示的“replication controllers/couchbase”的输出表明“couch base”复制控制器已经被创建。第二个命令列出了“couchbase”复制控制器。副本列为 2,但这并不意味着复制控制器创建了两个新副本。复制控制器基于匹配 Pod 标签的选择器表达式来管理 Pod。如果具有匹配标签的某个其他 Pod 已经在运行,它将计入副本设置。

A418863_1_En_9_Fig12_HTML.gif

图 9-12。

Creating and listing a Replication Controller from the Definition File

列出 POD

要列出窗格,请运行以下命令。

kubectl get pods

如图 9-13 所示,列出了两个 Pod,其中一个 Pod 是之前使用 Pod 定义文件创建的 Pod。Pod 定义文件中的标签是 app:“couch base app”,这也是复制控制器的选择器表达式。表达式 app:“couch base app”翻译成 app= couchbaseApp。因此,当创建副本设置为 2 的复制控制器时,仅创建一个新的 Pod。

A418863_1_En_9_Fig13_HTML.gif

图 9-13。

Listing the Pods for Couchbase Server

列出日志

要列出一个 Pod 的日志,运行kubectl logs命令。pod 名称可以从前面的 pod 列表中复制。

kubectl logs couchbase-0hglx

输出如图 9-14 所示。输出表明 WEB UI 在http://<ip>:8091可用。

A418863_1_En_9_Fig14_HTML.gif

图 9-14。

Listing Pod Logs

描述服务

要描述couchbase服务,请运行以下命令。

kubectl describe svc couchbase

服务名、名称空间、标签、选择器、类型、IP、端口、节点端口和端点被列出,如图 9-15 所示。将selector列为app=couchbaseApp

A418863_1_En_9_Fig15_HTML.gif

图 9-15。

Describing the Service for Couchbase

列出端点

再次列出端点。

kubectl get endpoints

之前列出端点时,因为只有一个 Pod 在运行,所以只列出了一个端点。两个吊舱运行时,两个端点被列出,如图 9-16 所示。

A418863_1_En_9_Fig16_HTML.gif

图 9-16。

Listing the Endpoints for Couchbase

设置端口转发

当我们列出 Couchbase Pod 的日志时,调用 web 控制台的 URL 被列为http://<ip>:8091< ip >是 Pod 的服务端点。上一节列出了两个服务端点。例如,在主机浏览器上调用http://172.17.0.2:8091将打开 web 控制台。默认情况下,Amazon EC2 Ubuntu 实例不会安装 web 浏览器。或者,我们将端口转发设置到本地机器,并从本地机器上的浏览器打开 web 控制台,这需要有一个可用的浏览器。要设置端口转发,我们需要知道运行 Kubernetes 的 Amazon EC2 实例的公共 DNS。公共 DNS 可以从亚马逊 EC2 控制台获得,如图 9-17 所示。

A418863_1_En_9_Fig17_HTML.gif

图 9-17。

Obtaining the Public DNS

本地计算机上要转发到的端口必须是打开的,并且尚未绑定。例如,使用以下命令将一个端点绑定到localhost上的端口 8093,将另一个端点绑定到localhost上的端口 8094。

ssh -i "docker.pem" -f -nNT -L 8093:172.17.0.3:8091 ubuntu@ec2-54-172-55-212.compute-1.amazonaws.com
ssh -i "docker.pem" -f -nNT -L 8094:172.17.0.2:8091 ubuntu@ec2-54-172-55-212.compute-1.amazonaws.com

从服务端点到localhost端口的端口转发如图 9-18 所示。

A418863_1_En_9_Fig18_HTML.gif

图 9-18。

Setting Port Forwarding to localhost:8093 and localhost:8094

登录 Couchbase Web 控制台

本地机器上有两个端口可用于打开 Couchbase web 控制台,8093 和 8094。这两种方法中的一种或两种都可以用来打开 Couchbase web 控制台。例如,在网络浏览器中打开 URL http://localhost:8093。如图 9-19 所示,治疗床控制台打开。点击设置来设置 Couchbase 服务器。

A418863_1_En_9_Fig19_HTML.gif

图 9-19。

Setting Up Couchbase Server

配置 Couchbase 服务器

在这一节中,我们将配置 Couchbase 服务器,这与使用 Kubernetes 没有直接关系,但为了完整起见会进行讨论。当点击设置按钮时,显示配置服务器窗口,如图 9-20 所示。

A418863_1_En_9_Fig20_HTML.gif

图 9-20。

Configuring Server Disk Storage, Hostname

保留默认设置,向下滚动选择 Start a new cluster。如果没有足够的 RAM 可用,可能必须降低 RAM 设置。点击下一步,如图 9-21 所示。

A418863_1_En_9_Fig21_HTML.gif

图 9-21。

Starting New Cluster

列出了一些样本桶,但不要求选择样本桶。点击下一步,如图 9-22 所示。

A418863_1_En_9_Fig22_HTML.gif

图 9-22。

Sample Buckets are not required to be selected

创建默认存储桶设置包括存储桶类型,它应该是 Couchbase,如图 9-23 所示。应通过“启用”复选框启用副本。

A418863_1_En_9_Fig23_HTML.gif

图 9-23。

Configuring Default Bucket

向下滚动,使用“启用”复选框启用冲洗模式。点击下一步,如图 9-24 所示。

A418863_1_En_9_Fig24_HTML.gif

图 9-24。

Enabling Flush Mode and completing Server Configuration

接下来,接受如图 9-25 所示的条款和条件,并点击下一步。

A418863_1_En_9_Fig25_HTML.gif

图 9-25。

Accepting Terms and Conditions

如图 9-26 所示,为确保服务器安全,指定一个密码,并在验证密码字段中指定相同的密码。

A418863_1_En_9_Fig26_HTML.gif

图 9-26。

Securing the Server with Username and Password

Couchbase 服务器得到配置。选择“服务器节点”页签,列出服务器节点名称,如图 9-27 所示。服务器节点名称是服务端点之一。

A418863_1_En_9_Fig27_HTML.gif

图 9-27。

Server Node Name is the same as a Service Endpoint

添加文档

接下来,我们将向 Couchbase 服务器添加一些文档。选择数据桶选项卡,如图 9-28 所示。

A418863_1_En_9_Fig28_HTML.gif

图 9-28。

Selecting Data Buckets Tab

默认存储桶被列出,如图 9-29 所示。点击文档。

A418863_1_En_9_Fig29_HTML.gif

图 9-29。

Clicking on Documents Button for the default Bucket

最初,“默认”铲斗是空的,如图 9-30 所示。

A418863_1_En_9_Fig30_HTML.gif

图 9-30。

Initially no Documents are present in the default Data Bucket

点击创建文档,添加一个文档,如图 9-31 所示。

A418863_1_En_9_Fig31_HTML.gif

图 9-31。

Clicking on Create Document

在创建文档对话框中指定一个文档 Id 并点击创建,如图 9-32 所示。

A418863_1_En_9_Fig32_HTML.gif

图 9-32。

Specifying Document ID

添加一个带有默认字段的新 JSON 文档,如图 9-33 所示。

A418863_1_En_9_Fig33_HTML.gif

图 9-33。

The catalog1 Document gets created with Default Fields

将下面的 JSON 文档复制粘贴到catalog1文档中。

{
  "journal": "Oracle Magazine",
  "publisher": "Oracle Publishing",
  "edition": "November-December 2013",
  "title": "Quintessential and Collaborative",
  "author": "Tom Haunert"
}

点击保存更新catalog1文件,如图 9-34 所示。

A418863_1_En_9_Fig34_HTML.gif

图 9-34。

Saving a JSON Document

如图 9-35 所示,当选择“默认”存储桶的文档链接时,catalog1文档被保存并被列出。

A418863_1_En_9_Fig35_HTML.gif

图 9-35。

The catalog1 Document in default Bucket

类似地,添加文档 ID 为catalog2的另一个文档,并将下面的清单复制并粘贴到该文档中。

{
"journal": “Oracle Magazine”,
"publisher": "Oracle Publishing",
"edition": "November December 2013",
"title": "Engineering as a Service",
"author": "David A. Kelly",
}

catalog2文件如图 9-36 所示。

A418863_1_En_9_Fig36_HTML.gif

图 9-36。

Adding another Document catalog2

如图 9-37 所示,“默认”存储桶的文档链接链接添加的两个文档。

A418863_1_En_9_Fig37_HTML.gif

图 9-37。

Listing the two Documents in the default Bucket

启动交互式 Shell

接下来,我们将启动一个交互式 bash shell 来从命令行访问 Couchbase 服务器。根据 Docker 映像“couchbase”获取其中一个 Docker 容器的容器 id,如图 9-38 所示。

A418863_1_En_9_Fig38_HTML.gif

图 9-38。

Obtaining the Container Id

使用容器 id,启动一个交互式 shell。

sudo docker exec -it e1b2fe2f24bd bash

如图 9-39 所示,启动一个交互式外壳。

A418863_1_En_9_Fig39_HTML.gif

图 9-39。

Starting an Interactive Shell

使用 cbtransfer 工具

从交互式外壳中,可以运行命令行工具来访问 Couchbase 服务器。例如,运行cbtransfer工具,该工具用于在集群之间和文件之间传输数据,将服务器http://172.17.0.3:8091的默认存储桶中的文档输出到stdout

cbtransfer http://172.17.0.3:8091/ stdout:

从 web 控制台添加的两个文档得到如图 9-40 所示的输出。

A418863_1_En_9_Fig40_HTML.gif

图 9-40。

Using the cbtransfer Tool

在下一节中,我们将在命令行上强制使用 Kubernetes 创建一个 Couchbase 集群。因为我们将使用相同的复制控制器名称和服务名称,所以删除复制控制器“couchbase”并删除名为“couchbase”的服务

kubectl delete rc couchbase
kubectl delete svc couchbase

强制创建 Couchbase 集群

在下面的小节中,我们将在命令行上创建一个 Couchbase 集群。

创建复制控制器

使用 Docker 映像“couchbase”创建一个名为“couchbase”的复制控制器,带有两个副本和容器端口 as 8091,使用以下命令。

kubectl run couchbase --image=couchbase --replicas=2 --port=8091

复制控制器的创建如图 9-41 所示。默认的选择器是“run=couchbase”,这意味着带有标签“run=couchbase”的 pod 应该由复制控制器来管理。Pod 标签被设置为“run=couchbase”。

A418863_1_En_9_Fig41_HTML.gif

图 9-41。

Creating a Replication Controller Imperatively

使用以下命令列出复制控制器。

kubectl get rc

couchbase复制控制器列表如图 9-42 所示。

A418863_1_En_9_Fig42_HTML.gif

图 9-42。

Listing the Replication Controllers

列出 POD

要列出窗格,请运行以下命令。

kubectl get pods

如图 9-43 所示,两个吊舱被列出。

A418863_1_En_9_Fig43_HTML.gif

图 9-43。

Listing the Pods

要描述任何特定的 Pod,运行kubectl describe pod 命令,例如,Pod couchbase-rd44o用以下命令描述。

kubectl describe pod couchbase-rd44o

吊舱细节得到如图 9-44 所示的输出。Pod 标签列为run=couchbase

A418863_1_En_9_Fig44_HTML.gif

图 9-44。

Describing a Pod

创建服务

要从在端口 8091 公开的复制控制器创建服务,请运行以下命令,该命令还指定了服务类型。

kubectl expose rc couchbase --port=8091 --type=LoadBalancer

随后列出服务。

kubectl get services

couchbase服务被创建并列出,如图 9-45 所示。

A418863_1_En_9_Fig45_HTML.gif

图 9-45。

Creating a Service for Couchbase Imperatively

要描述couchbase服务,请运行以下命令。

kubectl describe svc couchbase

服务名称、名称空间、标签、选择器、类型、Ip、端口、节点端口和端点会被列出,如图 9-46 所示。因为服务管理两个 pod,所以列出了两个端点。

A418863_1_En_9_Fig46_HTML.gif

图 9-46。

Describing a Service

扩展集群

使用 Kubernetes 集群管理器可以扩大或缩小 Couchbase 集群。例如,要将名为“couchbase”的复制控制器缩减为 1 个副本,运行下面的kubectl scale命令。

kubectl scale rc couchbase --replicas=1

“scaled”输出表示 rc 已被缩放。但是“缩放”输出并不总是意味着缩放数量的副本正在运行并准备就绪。运行以下命令列出窗格。

kubectl get pods

如图 9-47 所示,列出一个床座箱。

A418863_1_En_9_Fig47_HTML.gif

图 9-47。

Scaling Down the Couchbase Cluster to a Single Pod

运行以下命令列出复制控制器,如图 9-48 所示couchbase rc 与副本一起列为 1。

A418863_1_En_9_Fig48_HTML.gif

图 9-48。

Scaling Up the Couchbase Cluster

kubectl get rc

要将 rc 缩放回 2 个 pod,请运行以下命令。

kubectl scale rc couchbase --replicas=2

随后列出 POD。

kubectl get pods

最初,要添加的新 Pod 可能未运行或未就绪,但几秒钟后,两个 Pod 会被列为运行和就绪,如图 9-48 所示。

保持复制级别

复制控制器的主要目的是将副本的数量保持在配置的水平。在couchbase rc 中配置了 2 个副本的情况下,pod 的数量保持在 2。例如,删除其中一个窗格。

kubectl delete pod couchbase-4z3hx

一个单元被删除,但单元总数为 1,低于配置的副本数。因此,复制控制器启动一个新的副本。随后列出 POD。

kubectl get pods

最初,新的 Pod 可能没有运行和/或没有准备好,但几秒钟后,两个 Pod 正在运行并准备好,如图 9-49 所示。

A418863_1_En_9_Fig49_HTML.gif

图 9-49。

Running the kubectl get pods Command Multiple Times until all Pods are Running and Ready

描述couchbase服务。

kubectl describe svc couchbase

列出两个端点,如图 9-50 所示。

A418863_1_En_9_Fig50_HTML.gif

图 9-50。

Describing the couchbase Service

设置端口转发

将服务端点的端口转发设置为一个localhost端口,例如端口 8095,如前所述。

ssh -i "docker.pem" -f -nNT -L 8095:172.17.0.2:8091 ubuntu@ec2-52-91-80-177.compute-1.amazonaws.com

前面的命令不产生任何输出,如图 9-51 所示。

A418863_1_En_9_Fig51_HTML.gif

图 9-51。

Setting Port Forwarding

登录 Couchbase 管理控制台

使用localhost上的转发端口登录 Couchbase Web 控制台。

http://localhost:8095/index.html

Couchbase Web 控制台显示如图 9-52 所示。

A418863_1_En_9_Fig52_HTML.gif

图 9-52。

Displaying the Couchbase Console

摘要

在本章中,我们使用 Kubernetes 集群管理器创建了一个 Couchbase 集群。我们讨论了声明式和命令式方法。声明性方法利用定义文件,命令性方法利用命令行配置参数。我们演示了使用端口转发从本地主机浏览器访问 Couchbase Web 控制台。我们还在运行 Couchbase server 的 Docker 容器的交互式 shell 中使用了 cbtransfer 工具。Docker 映像“couchbase”用于创建一个 Couchbase 服务器。在下一章中,我们将讨论在 Apache Hadoop 集群中使用 Kubernetes 集群管理器。

十、使用 Apache Hadoop 生态系统

Apache Hadoop 已经发展成为处理大量数据的事实框架。Apache Hadoop 生态系统由多个项目组成,包括 Apache Hive 和 Apache HBase。Docker 映像“svds/cdh”基于最新的 cdh 版本,包括 Apache Hadoop 生态系统中的所有主要框架。Apache Hadoop、Apache Hive 和 Apache HBase 等所有框架都安装在同一个 Docker 映像中,因此有助于开发利用 Apache Hadoop 生态系统中多个框架的应用。在本章中,我们将讨论使用 Kubernetes 集群管理器来管理基于 svds/cdh 映像的 pod 集群。

  • 设置环境
  • 以声明方式创建 Apache Hadoop 集群
  • 创建 Apache Hadoop 集群势在必行

设置环境

本章需要安装以下软件,除 Docker 镜像外,其他章节使用的软件相同。

  • -Docker 引擎(最新版本)
  • -库服务器群集管理器 1.01 版
  • -Kubernetes(1.01 版)
  • -SVS/CDH 影像对接器(最新版本)

在 Amazon EC2 的 Ubuntu 实例上安装第一章中讨论的软件。SSH 登录到 Ubuntu 实例。

ssh -i "docker.pem" ubuntu@54.86.45.173

使用以下命令启动 Docker 引擎。

sudo service docker start

随后运行以下命令来验证 Docker 的状态。

sudo service docker status

如图 10-1 所示,Docker 应列为“正在运行”。

A418863_1_En_10_Fig1_HTML.gif

图 10-1。

Starting Docker

使用以下命令列出服务。

kubectl get services

kubernetes服务应该被列为正在运行,如图 10-2 所示。

A418863_1_En_10_Fig2_HTML.gif

图 10-2。

Listing the “kubernetes” Service

使用以下命令列出 pod。

kubectl get pods

使用以下命令列出节点。

kubectl get nodes

唯一列出的 Pod 是 Kubernetes,如图 10-3 所示。还会列出节点 127.0.0.1。

A418863_1_En_10_Fig3_HTML.gif

图 10-3。

Listing the Pod and Node for Kubernetes

以声明方式创建 Apache Hadoop 集群

在下面的小节中,我们将使用定义文件声明性地创建一个 Kubernetes 服务和一个 Kubernetes 复制控制器。服务是 pod 的外部接口,并将客户端请求路由到其中一个 pod。复制控制器管理 pod 的复制级别,并将副本的数量维持在定义文件中的指定值。复制控制器还用于扩展 pod 集群。

创建服务

要为 CDH pod 运行服务,请创建一个服务定义文件cdh-service.yaml并将以下(表 10-1 )字段添加到定义文件中。

表 10-1。

Service Definition File Fields

| 田 | 描述 | 价值 | 必填字段(包括默认值) | | --- | --- | --- | --- | | apiVersion(堆叠版本) |   | 第五颅神经的眼支 | 是 | | 种类 | 定义文件的种类。 | 服务 | 是 | | 元数据 | 服务元数据。 |   | 是 | | 元数据->标签 | 服务标签。 | app:HRC | 不 | | 元数据->名称 | 服务名称。 | 鼎晖投资 | 是 | | 投机 | 服务规范。 |   | 是 | | 规格->端口 | 服务公开的端口。 |   | 是 | | 规格->端口->端口 | 服务公开的端口。50010 端口用于 DataNode。 | Fifty thousand and ten |   | | 规格->端口->端口 | 服务公开的另一个端口。8020 端口是用于 NameNode 的。 | Eight thousand and twenty |   | | 规格->选择器 | 吊舱选择器。服务将流量路由到标签与选择器表达式匹配的 pod。 | app:HRC | 是 | | 规格->选择器->类型 | 服务类型。 | LoadBalancer(负载均衡器) | 不 |

服务定义文件cdh-service.yaml被列出:

apiVersion: v1
kind: Service
metadata:
labels:
    app: cdh
  name: cdh
spec:
ports:
    -
      port: 50010
    -
      port: 8020
  selector:
    app: cdh
type: LoadBalancer

可以在 vi 编辑器中创建并保存服务定义文件,如图 10-4 所示。

A418863_1_En_10_Fig4_HTML.gif

图 10-4。

Service Definition File in vi Editor

使用以下命令从定义文件创建服务。

kubectl create -f cdh-service.yaml

随后列出服务。

kubectl get services

第一个命令的输出“services/cdh”表示服务已经创建,如图 10-5 所示。第二个命令列出了名为“cdh”的服务。服务选择器在选择器列中列为 app = cdh。

A418863_1_En_10_Fig5_HTML.gif

图 10-5。

Creating a Service from a Definition File

创建复制控制器

在本节中,我们将使用一个定义文件创建一个复制控制器。创建一个 cdh-rc.yaml 文件,并将以下(表 10-2 )字段添加到该文件中。

表 10-2。

Replication Controller Definition File Fields

| 田 | 描述 | 价值 | | --- | --- | --- | | apiVersion(堆叠版本) |   | 第五颅神经的眼支 | | 种类 | 定义文件的种类。 | 复制控制器 | | 元数据 | 复制控制器元数据。 |   | | 元数据->标签 | 复制控制器标签。 | app:HRC | | 元数据->名称 | 复制控制器的名称。 | 人权委员会 | | 投机 | 复制控制器规范。 |   | | 规格->副本 | Pod 副本的数量。 | Two | | 规格->选择器 | 选择器键:用于选择要管理的窗格的值表达式。标签与选择器表达式相同的窗格由复制控制器管理。对于单个选择器表达式,选择器表达式必须与规范->模板->元数据->标签标签相同。如果没有指定,选择器默认为规范->模板->元数据->标签。 | 未设置。默认为与键相同的值:规范->模板->元数据->标签中的值对。 | | 规格->模板 | Pod 模板。 |   | | 规格->模板->元数据 | Pod 模板元数据。 |   | | 规格->模板->元数据->标签 | Pod 模板标签。 | app: cdh 名称:cdh | | 规格->模板->规格 | Pod 模板规范 |   | | 规格->模板->规格->容器 | Pod 模板的容器配置 |   | | 规格->模板->规格->容器->映像 | Docker 形象 | svds/人权中心 | | 规格->模板->规格->容器->名称 | 容器名称 | 鼎晖投资 |

列出了复制控制器的定义文件cdh-rc.yaml

apiVersion: v1
kind: ReplicationController
metadata:
  labels:
    app: cdh
  name: cdh-rc
spec:
  replicas: 2
  template:
    metadata:
      labels:
      app: cdh
      name: cdh
    spec:
      containers:
      image: svds/cdh
      name: cdh

运行以下命令,从定义文件创建复制控制器。

kubectl create -f cdh-rc.yaml

列出复制控制器。

kubectl get rc

第一个命令输出“replicationcontrollers/cdh”,这意味着已经成功创建了一个 rc。第二个命令列出了复制控制器。复制控制器“cdh”被列出,如图 10-6 所示。复制控制器文件中没有指定SELECTOR,它被列为与模板标签相同的两个键:值对app=cdh,name=cdh。由复制控制器管理的 Pod 必须包括这两个标签,并且可以包括其他标签。副本的数量设置为 2。

A418863_1_En_10_Fig6_HTML.gif

图 10-6。

Creating a Replication Controller from a Definition File

列出 POD

要列出窗格,请运行以下命令。

kubectl get pods

两个吊舱被列出,如图 10-7 所示。最初,pod 可能被列为未运行或/和未就绪。“未就绪”箱由“就绪”栏中的 0/1 值表示,这意味着箱中的 1 个容器中的 0 个已经就绪。

A418863_1_En_10_Fig7_HTML.gif

图 10-7。

Listing the Pods for CDH, created but not Ready

再次运行相同的命令以列出窗格。

kubectl get pods

如图 10-8 所示,两个 pod 应被列为状态->运行和就绪- > 1/1。

A418863_1_En_10_Fig8_HTML.gif

图 10-8。

Listing the Pods as Ready

列出日志

要列出特定 Pod 的日志,例如 cdh-612pr Pod,请运行以下命令。

kubectl logs cdh-612pr

该命令的输出列出了日志,表明 Hadoop datanode、namenode、secondarynamenode、resourcemanager 和 nodemanager 已经启动,如图 10-9 所示。

A418863_1_En_10_Fig9_HTML.gif

图 10-9。

Listing Pod Logs

HBase 等其他组件也会启动。

扩展集群

最初,CDH 群集有两个副本。要将复制副本扩展到 4,请运行以下命令。

kubectl scale rc cdh --replicas=4

随后列出集群中的单元。

kubectl get pods

向上扩展群集后,会列出 4 个 pod,而不是最初列出的 2 个。一些 pod 可能被列为未运行或未准备好。几秒钟后周期性地运行前面的命令,所有的吊舱都应该启动,如图 10-10 所示。

A418863_1_En_10_Fig10_HTML.gif

图 10-10。

Scaling the Pod Cluster

启动交互式 Shell

由于“svds/CDH”Docker 映像基于 Linux“Ubuntu”Docker 映像,因此可以启动一个交互式 bash shell 来访问基于 svds/cdh Docker 映像的 Docker 容器。为了启动 cdh 软件的交互式 bash shell,我们需要获取运行“cdh”映像的 Docker 容器的容器 id,如图 10-11 所示。

A418863_1_En_10_Fig11_HTML.gif

图 10-11。

Copying the Docker Container Id

随后使用容器 id 启动交互式 shell。

sudo docker exec -it f1efdb5937c6 bash

交互外壳启动,如图 10-12 所示。

A418863_1_En_10_Fig12_HTML.gif

图 10-12。

Starting an Interactive Shell

运行 MapReduce 应用

在本节中,我们将在交互式 shell 中运行一个示例 MapReduce 应用。hdfs命令用于运行 MapReduce 应用。在交互式 shell 中调用hdfs命令。

hdfs

命令用法应如图 10-13 所示。

A418863_1_En_10_Fig13_HTML.gif

图 10-13。

Command Usage for hdfs Command

要将用户更改为“hdfs ”,请运行以下命令。

su –l hdfs

用户变成“hdfs”,如图 10-14 所示。

A418863_1_En_10_Fig14_HTML.gif

图 10-14。

Setting User as hdfs

接下来,我们将运行一个wordcount应用。我们将从/input目录文件中获取输入,并在/output目录中输出。创建/input目录并将其权限设置为全局(777)。

hdfs dfs -mkdir /input
hdfs dfs -chmod -R 777 /input

如图 10-15 所示,/input目录被创建,其权限被设置为全局权限。

A418863_1_En_10_Fig15_HTML.gif

图 10-15。

Creating the Input Directory

在 vi 编辑器中创建一个输入文件input.1.txt

sudo vi input1.txt

将以下文本添加到 input1.txt 中。

Hello World Application for Apache Hadoop
Hello World and Hello Apache Hadoop

图 10-16 中的 vi 编辑器显示了input1.txt

A418863_1_En_10_Fig16_HTML.gif

图 10-16。

Creating an Input Text File

用下面的命令将input1.txt放到 HDFS 目录/input中,如果以root用户的身份运行,应该用sudo –u hdfs运行。如果用户已经设置为“hdfs ”,则在命令中省略“sudo–u HDFS”。

sudo -u hdfs hdfs dfs -put input1.txt /input

input1.txt文件被添加到/input目录中,命令没有产生输出,如图 10-17 所示。

A418863_1_En_10_Fig17_HTML.gif

图 10-17。

Putting the Input Text File in HDFS

类似地,创建另一个文件 input2.txt。

sudo vi input2.txt

将以下文本添加到 input2.txt。

Hello World
Hello Apache Hadoop

在 vi 编辑器中用:wq 命令保存input2.txt,如图 10-18 所示。

A418863_1_En_10_Fig18_HTML.gif

图 10-18。

Creating another Text File input2.txt

input2.txt放入/input目录。

sudo -u hdfs hdfs dfs -put input2.txt /input

input2.txt也被添加到/input目录中,如图 10-19 所示。

A418863_1_En_10_Fig19_HTML.gif

图 10-19。

Putting the input2.txt File into HDFS

可以用下面的命令列出 HDFS 中/input目录下的文件。

 hdfs dfs -ls /input

增加的两个文件input1.txtinput2.txt被列出,如图 10-20 所示。

A418863_1_En_10_Fig20_HTML.gif

图 10-20。

Listing the Files in HDFS

接下来,使用下面的命令运行wordcount示例应用,其中包含示例应用的 jar 文件由 jar 参数指定,并且/input/output目录分别被设置为输入目录和输出目录的最后两个命令参数。

sudo -u hdfs hadoop jar /usr/lib/hadoop-mapreduce/hadoop-mapreduce-examples-2.6.0-cdh5.4.7.jar wordcount /input /output

一个 MapReduce 作业开始,如图 10-21 所示。

A418863_1_En_10_Fig21_HTML.gif

图 10-21。

Starting a YARN Application for Word Count Example

MapReduce 作业完成后运行wordcount应用。图 10-22 中显示的是wordcount MapReduce 作业的输出,而不是字数统计结果。

A418863_1_En_10_Fig22_HTML.gif

图 10-22。

Output from the MapReduce Job

下面列出了 MapReduce 应用的更详细的输出:

root@cdh-6l2pr:/# sudo -u hdfs hadoop jar /usr/lib/hadoop-mapreduce/hadoop-mapreduce-examples-2.6.0-cdh5.4.7.jar wordcount /input /output
15/12/21 16:39:52 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032
15/12/21 16:39:53 INFO input.FileInputFormat: Total input paths to process : 2
15/12/21 16:39:53 INFO mapreduce.JobSubmitter: number of splits:2
15/12/21 16:39:53 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1450714825612_0002
15/12/21 16:39:53 INFO impl.YarnClientImpl: Submitted application application_1450714825612_0002
15/12/21 16:39:53 INFO mapreduce.Job: The url to track the job: http://cdh-6l2pr:8088/proxy/application_1450714825612_0002/
15/12/21 16:39:53 INFO mapreduce.Job: Running job: job_1450714825612_0002
15/12/21 16:39:59 INFO mapreduce.Job: Job job_1450714825612_0002 running in uber mode : false
15/12/21 16:39:59 INFO mapreduce.Job: map 0 % reduce 0 %
15/12/21 16:40:04 INFO mapreduce.Job: map 100 % reduce 0 %
15/12/21 16:40:10 INFO mapreduce.Job: map 100 % reduce 100 %
15/12/21 16:40:10 INFO mapreduce.Job: Job job_1450714825612_0002 completed successfully
15/12/21 16:40:10 INFO mapreduce.Job: Counters: 49
       File System Counters
           FILE: Number of bytes read=144
           FILE: Number of bytes written=332672
           FILE: Number of read operations=0
           FILE: Number of large read operations=0
           FILE: Number of write operations=0
           HDFS: Number of bytes read=317
           HDFS: Number of bytes written=60
           HDFS: Number of read operations=9
           HDFS: Number of large read operations=0
           HDFS: Number of write operations=2
       Job Counters
           Launched map tasks=2
           Launched reduce tasks=1
           Data-local map tasks=2
           Total time spent by all maps in occupied slots (ms)=4939
           Total time spent by all reduces in occupied slots (ms)=2615
           Total time spent by all map tasks (ms)=4939
           Total time spent by all reduce tasks (ms)=2615
           Total vcore-seconds taken by all map tasks=4939
           Total vcore-seconds taken by all reduce tasks=2615
           Total megabyte-seconds taken by all map tasks=5057536
           Total megabyte-seconds taken by all reduce tasks=2677760
       Map-Reduce Framework
           Map input records=5
           Map output records=17
           Map output bytes=178
           Map output materialized bytes=150
           Input split bytes=206
           Combine input records=17
           Combine output records=11
           Reduce input groups=7
           Reduce shuffle bytes=150
           Reduce input records=11
           Reduce output records=7
           Spilled Records=22
           Shuffled Maps =2
           Failed Shuffles=0
           Merged Map outputs=2
           GC time elapsed (ms)=158
           CPU time spent (ms)=2880
           Physical memory (bytes) snapshot=1148145664
           Virtual memory (bytes) snapshot=5006991360
           Total committed heap usage (bytes)=2472542208
Shuffle Errors
           BAD_ID=0
           CONNECTION=0
           IO_ERROR=0
           WRONG_LENGTH=0
           WRONG_MAP=0
           WRONG_REDUCE=0
File Input Format Counters
           Bytes Read=111
File Output Format Counters
           Bytes Written=60
root@cdh-6l2pr:/#

随后,列出/output目录中的文件。

bin/hdfs dfs -ls /output

列出两个文件:_SUCCESSpart-r-00000,如图 10-23 所示。_SUCCESS文件表示 MapReduce 命令成功完成,part-r-00000命令包含字数统计的结果。

A418863_1_En_10_Fig23_HTML.gif

图 10-23。

Listing the Files generated by the MapReduce Job

要列出 wordcount 应用的结果,请运行以下命令。

hdfs dfs -cat /output/part-r-00000

如图 10-24 所示,列出了输入中每个单词的字数。

A418863_1_En_10_Fig24_HTML.gif

图 10-24。

The Word Count for the Input Files

运行蜂箱

Apache Hive 是一个数据仓库框架,用于存储、管理和查询 HDFS 的大型数据集。如前所述,CDH 的所有/大部分组件都是在运行svds/cdh映像时安装的。在这一节中,我们将测试 Apache Hive 框架。配置单元配置目录在配置单元conf目录中,在/etc/hive目录中。将目录(cd)更改为/etc/hive目录。

cd /etc/hive

conf目录被列出,如图 10-25 所示。

A418863_1_En_10_Fig25_HTML.gif

图 10-25。

Listing the Files and Directories in the Hive Root Directory

配置单元 metastore 保存在/var/lib/hive目录中。Cd 到/var/lib/hive目录。

cd /var/lib/hive

metastore目录被列出,如图 10-26 所示。

A418863_1_En_10_Fig26_HTML.gif

图 10-26。

Listing the Hive Metastore Directory

配置单元主目录是/usr/lib/hive。Cd 到/usr/lib/hive目录。随后列出文件和目录。

cd /usr/lib/hive
ls –l

Apache Hive 的binconf,lib目录如图 10-27 所示。bin目录包含可执行文件,conf目录包含配置文件,lib目录包含 jar 文件。

A418863_1_En_10_Fig27_HTML.gif

图 10-27。

The Hive Home Directory

所有的环境变量都是预先配置的。运行以下命令启动直线 CLI。

beeline

直线版本 1.1.0-cdh5.4.7 启动,如图 10-28 所示。

A418863_1_En_10_Fig28_HTML.gif

图 10-28。

Starting Beeline CLI

最初,没有到 Apache Hive 服务器的连接。为了进行演示,运行以下命令将数据库设置为默认数据库并显示表。

use default;
show tables;

显示如图 10-29 所示的“无电流连接”信息。

A418863_1_En_10_Fig29_HTML.gif

图 10-29。

No Current Connection

使用驱动程序、用户名和密码的默认设置与 Hive2 服务器连接,如三个空""所示。

!connect jdbc:hive2://localhost:10000/default "" "" ""

Apache Hive2 服务器使用 Apache Hive JDBC 驱动程序进行连接,如图 10-30 所示。

A418863_1_En_10_Fig30_HTML.gif

图 10-30。

Connecting with Hive Server

运行命令将数据库设置为默认值并显示表格。

use default;
show tables;

连接到的数据库已经是默认的,第一个命令基本上是多余的,但是需要注意的是,前面生成的错误没有生成。第二个命令列出了表,因为默认数据库最初没有任何表,所以没有列出任何表。前面命令的输出如图 10-31 所示。

A418863_1_En_10_Fig31_HTML.gif

图 10-31。

Setting the database to Use and the listing to the Hive Tables

在创建配置单元表之前,我们需要将/user/hive/warehouse目录的权限设置为全局(777)。

sudo –u hdfs hdfs dfs –chmod –R 777 /user/hive/warehouse

配置单元仓库目录的权限设置如图 10-32 所示。

A418863_1_En_10_Fig32_HTML.gif

图 10-32。

Setting Permissions on the Hive Warehouse Directory

用下面的 HiveQL 命令创建一个名为wlslog的表。

CREATE TABLE wlslog(time_stamp STRING,category STRING,type STRING,servername STRING,code STRING,msg STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';

在默认数据库中创建wlslog表,如图 10-33 所示。

A418863_1_En_10_Fig33_HTML.gif

图 10-33。

Creating a Hive Table called wlslog

使用以下命令描述 wlslog 表。

desc wlslog;

表格列(名称和数据类型)如图 10-34 所示。

A418863_1_En_10_Fig34_HTML.gif

图 10-34。

Describing the Hive Table wlslog

wlslog表添加 7 行数据。

INSERT INTO TABLE wlslog VALUES ('Apr-8-2014-7:06:16-PM-PDT','Notice','WebLogicServer','AdminServer,BEA-000365','Server state changed to STANDBY');
INSERT INTO TABLE wlslog VALUES ('Apr-8-2014-7:06:17-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to STARTING');
INSERT INTO TABLE wlslog VALUES ('Apr-8-2014-7:06:18-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to ADMIN');
INSERT INTO TABLE wlslog VALUES ('Apr-8-2014-7:06:19-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to RESUMING');
INSERT INTO TABLE wlslog VALUES ('Apr-8-2014-7:06:20-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000331','Started WebLogic AdminServer');
INSERT INTO TABLE wlslog VALUES ('Apr-8-2014-7:06:21-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to RUNNING');
INSERT INTO TABLE wlslog VALUES ('Apr-8-2014-7:06:22-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000360','Server started in RUNNING mode');

针对每个INSERT语句运行一个 MapReduce 作业,将数据添加到配置单元表wlslog中,如图 10-35 所示。

A418863_1_En_10_Fig35_HTML.gif

图 10-35。

Adding Data to Hive Table wlslog

随后查询wlslog表。

select * from wlslog;

添加的 7 行数据被列出,如图 10-36 所示。

A418863_1_En_10_Fig36_HTML.gif

图 10-36。

Querying the Hive Table

要退出 Beeline CLI,请运行以下命令。

!q

如图 10-37 所示,蜂箱直线 CLI 退出。将显示交互式 shell 命令提示符。

A418863_1_En_10_Fig37_HTML.gif

图 10-37。

Exiting the Beeline CLI

从交互式 shell 中,可以运行 CDH 的任何框架。接下来,我们将运行 Apache HBase。

运行 HBase

Apache HBase 是 Apache Hadoop 数据库,默认情况下,它也将数据存储在 HDFS。要启动 HBase shell,请在 bash shell 中运行以下命令,用于基于 svds/cdh Docker 映像的 Docker 容器。

hbase shell

HBase shell 启动,如图 10-38 所示。

A418863_1_En_10_Fig38_HTML.gif

图 10-38。

Starting HBase Shell

使用列族“log”创建一个名为“wlslog”的表。

create 'wlslog' , 'log'

wlslog表被创建,如图 10-39 所示。

A418863_1_En_10_Fig39_HTML.gif

图 10-39。

Creating a HBase Table

将 7 行数据放入wlslog表中。

put 'wlslog', 'log1', 'log:time_stamp', 'Apr-8-2014-7:06:16-PM-PDT'
put 'wlslog', 'log1', 'log:category', 'Notice'
put 'wlslog', 'log1', 'log:type', 'WeblogicServer'
put 'wlslog', 'log1', 'log:servername', 'AdminServer'
put 'wlslog', 'log1', 'log:code', 'BEA-000365'
put 'wlslog', 'log1', 'log:msg', 'Server state changed to STANDBY'

put 'wlslog', 'log2', 'log:time_stamp', 'Apr-8-2014-7:06:17-PM-PDT'
put 'wlslog', 'log2', 'log:category', 'Notice'
put 'wlslog', 'log2', 'log:type', 'WeblogicServer'
put 'wlslog', 'log2', 'log:servername', 'AdminServer'
put 'wlslog', 'log2', 'log:code', 'BEA-000365'
put 'wlslog', 'log2', 'log:msg', 'Server state changed to STARTING'
put 'wlslog', 'log3', 'log:time_stamp', 'Apr-8-2014-7:06:18-PM-PDT'
put 'wlslog', 'log3', 'log:category', 'Notice'
put 'wlslog', 'log3', 'log:type', 'WeblogicServer'
put 'wlslog', 'log3', 'log:servername', 'AdminServer'
put 'wlslog', 'log3', 'log:code', 'BEA-000365'
put 'wlslog', 'log3', 'log:msg', 'Server state changed to ADMIN'
put 'wlslog', 'log4', 'log:time_stamp', 'Apr-8-2014-7:06:19-PM-PDT'
put 'wlslog', 'log4', 'log:category', 'Notice'
put 'wlslog', 'log4', 'log:type', 'WeblogicServer'
put 'wlslog', 'log4', 'log:servername', 'AdminServer'
put 'wlslog', 'log4', 'log:code', 'BEA-000365'
put 'wlslog', 'log4', 'log:msg', 'Server state changed to RESUMING'
put 'wlslog', 'log5', 'log:time_stamp', 'Apr-8-2014-7:06:20-PM-PDT'
put 'wlslog', 'log5', 'log:category', 'Notice'
put 'wlslog', 'log5', 'log:type', 'WeblogicServer'
put 'wlslog', 'log5', 'log:servername', 'AdminServer'
put 'wlslog', 'log5', 'log:code', 'BEA-000331'
put 'wlslog', 'log5', 'log:msg', 'Started Weblogic AdminServer'
put 'wlslog', 'log6', 'log:time_stamp', 'Apr-8-2014-7:06:21-PM-PDT'
put 'wlslog', 'log6', 'log:category', 'Notice'
put 'wlslog', 'log6', 'log:type', 'WeblogicServer'
put 'wlslog', 'log6', 'log:servername', 'AdminServer'
put 'wlslog', 'log6', 'log:code', 'BEA-000365'
put 'wlslog', 'log6', 'log:msg', 'Server state changed to RUNNING'
put 'wlslog', 'log7', 'log:time_stamp', 'Apr-8-2014-7:06:22-PM-PDT'
put 'wlslog', 'log7', 'log:category', 'Notice'
put 'wlslog', 'log7', 'log:type', 'WeblogicServer'
put 'wlslog', 'log7', 'log:servername', 'AdminServer'
put 'wlslog', 'log7', 'log:code', 'BEA-000360'
put 'wlslog', 'log7', 'log:msg', 'Server started in RUNNING mode'

put 命令的输出如图 10-40 所示。

A418863_1_En_10_Fig40_HTML.gif

图 10-40。

Putting Data into HBase Table

要列出这些表,请运行以下命令。

list

wlslog表被列出,如图 10-41 所示。

A418863_1_En_10_Fig41_HTML.gif

图 10-41。

Listing HBase Tables

要获取行关键字为“log1”的行中的数据,请运行以下命令。

get 'wlslog', 'log1'

单列数据被列出,如图 10-42 所示。

A418863_1_En_10_Fig42_HTML.gif

图 10-42。

Getting a Single Row of Data

从具有行关键字log7的行中获取单个列log.msg中的数据。使用列族:列格式指定列。

get 'wlslog', 'log7', {COLUMNS=>['log:msg']}

单列数据输出如图 10-43 所示。

A418863_1_En_10_Fig43_HTML.gif

图 10-43。

Getting a Single Column Value in a Row

scan命令扫描wlslog工作台。

scan 'wlslog'

扫描命令如图 10-44 所示。

A418863_1_En_10_Fig44_HTML.gif

图 10-44。

Scanning a HBase Table

来自wlslog表的所有数据被列出,如图 10-45 所示。

A418863_1_En_10_Fig45_HTML.gif

图 10-45。

The scan Command outputs 7 Rows of Data

删除复制控制器和服务

在下一节中,我们将在命令行上强制为svds/cdh映像创建一个集群。删除复制控制器和以声明方式创建的服务。

kubectl delete rc cdh
kubectl delete service cdh

创建 Apache Hadoop 集群势在必行

在下面的小节中,我们将从命令行上的svds/cdh Docker 映像创建一个 CDH 集群。首先,我们将创建一个复制控制器。

创建复制控制器

运行以下命令创建一个名为cdh的复制控制器,包含两个副本。

kubectl run cdh --image=svds/cdh --replicas=2

cdh控制器创建完成,如图 10-46 所示。选择器默认设置为run=cdh

A418863_1_En_10_Fig46_HTML.gif

图 10-46。

Creating a Replication Controller Imperatively

列出复制控制器。

kubectl get rc

cdh复制控制器列表如图 10-47 所示。

A418863_1_En_10_Fig47_HTML.gif

图 10-47。

Getting the Replication Controller

列出 POD

要列出集群中的 pod,请运行以下命令。

kubectl get pods

这两个 pod 会被列出。如图 10-48 所示,最初一些或所有的吊舱可能不“运行”或不处于就绪状态 1/1。

A418863_1_En_10_Fig48_HTML.gif

图 10-48。

Listing the Pods with some Pod/s not READY yet

几秒钟后再次运行前面的命令。

kubectl get pods

如图 10-49 所示,所有的吊舱应列出状态“运行”和就绪状态 1/1。

A418863_1_En_10_Fig49_HTML.gif

图 10-49。

Listing all Pods as Running and Ready

扩展集群

要将群集扩展到 4 个副本,请运行以下命令。

kubectl scale rc cdh --replicas=4

随后列出 POD。

kubectl get pods

第一个命令的输出“scaled”表示集群已被缩放。第二个命令列出了 4 个 pod,而不是最初创建的 2 个,如图 10-50 所示。第二个命令可能需要运行多次才能列出所有状态为“正在运行”和就绪状态为 1/1 的 pod。

A418863_1_En_10_Fig50_HTML.gif

图 10-50。

Scaling the CDH Cluster

创建服务

服务在服务端点公开由复制控制器管理的 pod,服务端点只是外部客户机可以调用应用的主机:端口设置。运行以下命令创建服务。

kubectl expose rc cdh --type=LoadBalancer

随后列出服务。

kubectl get services

“cdh”服务列出选择器和端口的默认设置,如图 10-51 所示。默认的服务选择器是run=cdh,它的默认格式是 run = 。默认端口是 8020。

A418863_1_En_10_Fig51_HTML.gif

图 10-51。

Creating a Service

启动交互式 Shell

交互式外壳可以像以声明方式启动的 CDH 集群一样启动。复制运行 CDH 映像的 Docker 容器的容器 id,并运行以下命令(包括容器 id)来启动交互式 bash shell。

sudo docker exec -it 42f2d8f40f17 bash

交互外壳启动,如图 10-52 所示。

A418863_1_En_10_Fig52_HTML.gif

图 10-52。

Starting an Interactive Shell

运行hdfs命令。

hdfs

hdfs命令用法得到如图 10-53 所示的输出。

A418863_1_En_10_Fig53_HTML.gif

图 10-53。

Command Usage for hdfs Command

摘要

在本章中,我们使用 Kubernetes 集群管理器根据 Docker 映像svds/cdh创建了一个 Pods 集群。我们使用声明式和命令式方法来创建集群。我们使用 kubectl scale 命令来扩展集群。我们还演示了如何使用打包在cdh映像中的一些 Apache Hadoop 框架。我们运行了一个 MapReduce wordcount示例应用。我们还运行了 Apache Hive 和 Apache HBase 工具。在下一章,我们将讨论在索引和存储框架 Apache Solr 中使用 Kubernetes。

十一、使用 Apache Solr

Apache Solr 是一个基于 Apache Lucene 的企业搜索平台,提供诸如全文搜索、近实时索引和数据库集成等功能。Apache Solr 在 servlet 容器中作为全文搜索服务器运行,缺省情况下是 Jetty,它包含在 Solr 安装中。在本章中,我们将讨论在 Apache Solr 中使用 Kubernetes 集群管理器。我们将只使用利用定义文件的声明性方法来创建和管理 Solr 集群。本章包括以下几节。

  • 设置环境
  • 创建服务
  • 列出服务端点
  • 描述服务
  • 创建复制控制器
  • 列出 POD
  • 描述一个 Pod
  • 列出日志
  • 启动交互式 Shell
  • 创建 Solr 核心
  • 添加文档
  • 使用 REST 客户端在命令行上访问 Solr
  • 设置端口转发
  • 在管理控制台中访问 Solr
  • 扩展集群

设置环境

本章需要以下软件。

  • -Docker 引擎(最新版本)
  • -Kubernetes(1.01 版)
  • -Kubernetes(1.01 版)
  • Apache Solr 的 Docker 映像(最新版本)

我们在其他章节中使用了相同的 Amazon EC2 实例 AMI。从本地机器 SSH 登录到 Ubuntu 实例。

ssh -i "docker.pem" ubuntu@54.152.82.142

按照第一章所述安装所需软件。启动 Docker 并验证其状态。

sudo service docker start
sudo service docker status

如图 11-1 所示 Docker 机应该正在运行。

A418863_1_En_11_Fig1_HTML.gif

图 11-1。

Starting Docker and Verifying Status

列出服务。

kubectl get services

如图 11-2 所示,Kubernetes 服务应该正在运行。

A418863_1_En_11_Fig2_HTML.gif

图 11-2。

Listing the “kubernetes” Service

要列出节点,请运行以下命令。

kubectl get nodes

127.0.0.1 节点被列出,如图 11-3 所示。

A418863_1_En_11_Fig3_HTML.gif

图 11-3。

Listing a Single Node

使用以下命令列出端点。

kubectl get endpoints

最初只列出了 kubernetes 的终点,如图 11-4 所示。

A418863_1_En_11_Fig4_HTML.gif

图 11-4。

Listing “kubernetes” Endpoint

创建服务

创建一个定义文件solr-service.yaml并将以下(表 11-1 )字段添加到定义文件中。

表 11-1。

Service Definition File for Apache Solr

| 田 | 描述 | 价值 | | --- | --- | --- | | apiVersion(堆叠版本) |   | 第五颅神经的眼支 | | 种类 | 定义文件的种类。 | 服务 | | 元数据 | 服务元数据。 |   | | 元数据->标签 | 服务标签。不需要。 | 应用程式:太阳能板 | | 元数据->名称 | 服务名称。必选。 | 太阳能服务 | | 投机 | 服务规范。 |   | | 规格->端口 | 服务公开的端口。 |   | | 规格->端口->端口 | 服务公开的端口。 | Eight thousand nine hundred and eighty-three | | 规格>连接埠>目标连接埠 | 目标端口。 | Eight thousand nine hundred and eighty-three | | 规格->选择器 | 吊舱选择器。服务将流量路由到标签与选择器表达式匹配的 pod。 | 应用程式:太阳能板 |

solr-service.yaml已列出。

apiVersion: v1
kind: Service
metadata:
  labels:
    app: solrApp
  name: solr-service
spec:
  ports:
    -
      port: 8983
      targetPort: 8983
  selector:
    app: solrApp

solr-service.yaml可以在 vi 编辑器中编辑,并用:wq 保存,如图 11-5 所示。

A418863_1_En_11_Fig5_HTML.gif

图 11-5。

Service Definition File in vi Editor

使用以下命令从定义文件创建服务。

kubectl create -f solr-service.yaml  

随后列出服务。

kubectl get services

如图 11-6 所示的“服务/solr-service”输出表明服务已经创建。随后solr-service被列出。服务有标签app=solrApp和选择器app=solrApp

A418863_1_En_11_Fig6_HTML.gif

图 11-6。

Creating a Service from Definition File

列出服务端点

要列出端点,请运行以下命令。

kubectl get endpoints

由于solr-service最初没有管理任何 pod,因此没有列出端点,如图 11-7 所示。

A418863_1_En_11_Fig7_HTML.gif

图 11-7。

Listing the Endpoint for the Solr Service

描述服务

要描述solr-service,运行以下命令。

kubectl describe service solr-service

服务名称、名称空间、标签、选择器、类型、IP、端口、端点和事件被列出,如图 11-8 所示。

A418863_1_En_11_Fig8_HTML.gif

图 11-8。

Describing the Apache Solr Service

创建复制控制器

为复制控制器创建一个定义文件solr-rc.yaml,并将以下(表 11-2 )字段添加到定义文件中。

表 11-2。

Replication Controller Definition File Fields

| 田 | 描述 | 价值 | | --- | --- | --- | | apiVersion(堆叠版本) |   | 第五颅神经的眼支 | | 种类 | 定义文件的种类。 | 复制控制器 | | 元数据 | 复制控制器元数据。 |   | | 元数据->标签 | 复制控制器标签。 | 应用程式:太阳能板 | | 元数据->名称 | 复制控制器的名称。 | 索尔-rc | | 投机 | 复制控制器规范。 |   | | 规格->副本 | Pod 副本的数量。 | Two | | 规格->选择器 | key:用于选择要管理的窗格的值表达式。标签与选择器表达式相同的窗格由复制控制器管理。对于单个标签/选择器表达式窗格/复制控制器组合,选择器表达式必须与规格->模板->元数据->标签表达式相同。选择器默认为规范->模板->元数据->未指定标签。app: solrApp 设置转换为 app=solrApp。 | 应用程式:太阳能板 | | 规格->模板 | Pod 模板。 |   | | 规格->模板->元数据 | Pod 模板元数据。 |   | | 规格->模板->元数据->标签 | Pod 模板标签。 | 应用程式:太阳能板 | | 规格->模板->规格 | Pod 模板规范。 |   | | 规格->模板->规格->容器 | Pod 模板的容器配置。 |   | | 规格->模板->规格->容器->映像 | Docker 的形象。 | 使用 | | 规格->模板->规格->容器->名称 | 容器名称。 | 使用 | | 规格->模板->规格->容器->端口 | 容器港口。 |   | | 规格->模板->规格->容器->端口->容器端口 | Solr 服务器的容器端口。 | Eight thousand nine hundred and eighty-three | | 规格->模板->规格->容器->端口->名称 | Solr 端口名称。 | 索拉普 |

solr-rc.yaml已列出。

apiVersion: v1
kind: ReplicationController
metadata:
  labels:
    app: solrApp
  name: solr-rc
spec:
  replicas: 2
  selector:
    app: solrApp
  template:
    metadata:
      labels:
        app: solrApp
    spec:
      containers:
        -
          image: solr
          name: solr
          ports:
            -
              containerPort: 8983
              name: solrApp

可以在 vi 编辑器中创建并保存solr-rc.yaml定义文件,如图 11-9 所示。

A418863_1_En_11_Fig9_HTML.gif

图 11-9。

Replication Controller Definition File in vi Editor

运行以下命令,从定义文件创建复制控制器。

kubectl create -f solr-rc.yaml  

solr-rc复制控制器被创建,如图 11-10 所示。随后列出复制控制器。

A418863_1_En_11_Fig10_HTML.gif

图 11-10。

Creating a Replication Controller from Definition File

kubectl get rc

solr-rc复制控制器列表如图 11-10 所示。

列出 POD

使用以下命令列出 pod。

kubectl get pods

由复制控制器创建的两个 pod 被列出,如图 11-11 所示。最初,一些 pod 可能没有运行,也没有准备好。

A418863_1_En_11_Fig11_HTML.gif

图 11-11。

Listing the Pods, all of them not yet Ready

几秒钟后再次运行相同的命令,再次列出 pod。

kubectl get pods

如图 11-12 所示,pod 应列出状态“运行”和就绪状态 1/1。

A418863_1_En_11_Fig12_HTML.gif

图 11-12。

Listing the Pods as Ready

要描述solr-service,运行以下命令。

kubectl describe svc solr-service

服务描述被列出,如图 11-13 所示。还列出了两个 pod 的服务端点。服务在其端点被访问。如前所述,在创建复制控制器之前,没有列出服务端点,如图 11-8 所示。

A418863_1_En_11_Fig13_HTML.gif

图 11-13。

Describing the Solr Service including the Service Endpoints

端点也可以单独列出。

kubectl get endpoints

端点列表如图 11-14 所示。

A418863_1_En_11_Fig14_HTML.gif

图 11-14。

Listing the Endpoints for Solr Service

描述复制控制器

要描述复制控制器solr-rc,运行以下命令。

kubectl describe rc solr-rc

复制控制器描述被列出,如图 11-15 所示。

A418863_1_En_11_Fig15_HTML.gif

图 11-15。

Describing the Replication Controller

列出日志

要列出特定命令的日志,运行kubectl logs命令。例如,使用以下命令列出了solr-rc-s82ip Pod 的日志。

kubectl logs solr-rc-s82ip

在日志输出中,Solr 服务器正在启动,如图 11-16 所示。

A418863_1_En_11_Fig16_HTML.gif

图 11-16。

Listing Logs for the Pod

服务器启动后,输出“服务器启动”得到如图 11-17 所示的输出。

A418863_1_En_11_Fig17_HTML.gif

图 11-17。

Listing the Solr Server as started

启动交互式 Shell

由于“Solr”Docker 映像继承自“Java:open JDK-8-JRE”Docker 映像,而“Java:open JDK-8-JRE”Docker 映像又继承自“buildpack-deps:jessie-curl”映像,而“jessie-curl”映像又继承自 Linux 的 Docker 映像“debian ”,因此可以启动一个交互式 bash shell 来访问基于“Solr”Docker 映像的 Docker 容器。要访问 Solr 软件,我们需要为运行 Solr 的 Docker 容器启动一个交互式 bash shell。对于运行 Solr 的 Docker 容器,使用以下命令获取容器 if。

sudo docker ps

Docker 容器如图 11-18 所示。

A418863_1_En_11_Fig18_HTML.gif

图 11-18。

Listing the Docker Container for Apache Solr

复制容器并启动一个交互式 shell。

sudo docker exec -it 2d4d7d02c05f bash

交互外壳启动,如图 11-19 所示。要列出 Solr 服务器的状态,请运行以下命令。

A418863_1_En_11_Fig19_HTML.gif

图 11-19。

Listing the Solr Status in an Interactive Shell for the Docker Container

bin/solr status

找到一个 Solr 节点,如图 11-19 所示。

Solr 5.x 引入配置集。configsets 目录由示例配置组成,可用作创建新 Solr 核心或集合的基础。configsets 将 Solr 4.x. Cd(更改目录)中的collection1示例核心配置替换为configsets目录。

cd /opt/solr/server/solr/configsets

列出configsets目录中的文件和目录。

ls –l

如图 11-20 所示,列出了三种示例配置。

A418863_1_En_11_Fig20_HTML.gif

图 11-20。

Listing the Example Configurations

当我们在本章后面创建 Solr 核心时,我们将使用 basic_configs 配置。列出//configsets/ basic_configs/conf目录中的文件。

cd conf
ls –l

basic_configs示例的配置文件被列出,包括schema.xml和 solrconfig.xml,如图 11-21 所示。

A418863_1_En_11_Fig21_HTML.gif

图 11-21。

Listing the Configuration Files in the basic_configs Example Configuration

创建 Solr 核心

也可以从命令行创建一个新的 Solr 内核。solr create命令用于创建一个新的核心或集合。例如,用solr create_core命令创建一个名为wlslog的内核。使用带有–d选项的配置集basic_configs。如果没有指定(使用–d选项),使用的默认配置集是data_driven_schema_configs。Cd 到/opt/solr目录,并运行下面的命令。

bin/solr create_core -c wlslog -d /opt/solr/server/solr/configsets/basic_configs

一个名为wlslog的 Solr 内核被创建,如图 11-22 所示。

A418863_1_En_11_Fig22_HTML.gif

图 11-22。

Creating a Solr Core called wlslog

索引文档

Apache Solr 提供了从命令行索引文档的post工具。post工具支持不同的输入文件格式,如 XML、CSV 和 JSON。我们将索引一个 XML 格式的文档,并将下面的 XML 文档保存到wlslog.xml文件中。

<add>
<doc>
<field name="id">wlslog1</field>
  <field name="time_stamp_s">Apr-8-2014-7:06:16-PM-PDT</field>
  <field name="category_s">Notice</field>
  <field name="type_s">WebLogicServer</field>
  <field name="servername_s">AdminServer</field>
  <field name="code_s">BEA-000365</field>
  <field name="msg_s">Server state changed to STANDBY</field>

</doc>

<doc>
<field name="id">wlslog2</field>

  <field name="time_stamp_s">Apr-8-2014-7:06:17-PM-PDT</field>
  <field name="category_s">Notice</field>
  <field name="type_s">WebLogicServer</field>

  <field name="servername_s">AdminServer</field>
  <field name="code">BEA-000365</field>
  <field name="msg_s">Server state changed to STARTING</field>

</doc>

<doc>
<field name="id">wlslog3</field>

  <field name="time_stamp_s">Apr-8-2014-7:06:18-PM-PDT</field>
  <field name="category_s">Notice</field>
  <field name="type_s">WebLogicServer</field>

  <field name="servername_s">AdminServer</field>
  <field name="code">BEA-000365</field>
  <field name="msg_s">Server state changed to ADMIN</field>
</doc>
<doc>
<field name="id">wlslog4</field>
  <field name="time_stamp_s">Apr-8-2014-7:06:19-PM-PDT</field>
  <field name="category_s">Notice</field>
  <field name="type_s">WebLogicServer</field>
  <field name="servername_s">AdminServer</field>
  <field name="code">BEA-000365</field>
  <field name="msg_s">Server state changed to RESUMING</field>

</doc>

<doc>
<field name="id">wlslog5</field>

  <field name="time_stamp_s">Apr-8-2014-7:06:20-PM-PDT</field>
  <field name="category_s">Notice</field>
  <field name="type_s">WebLogicServer</field>
  <field name="servername_s">AdminServer</field>
  <field name="code">BEA-000331</field>
  <field name="msg_s">Started WebLogic AdminServer</field>
</doc>
<doc>
<field name="id">wlslog6</field>

  <field name="time_stamp_s">Apr-8-2014-7:06:21-PM-PDT</field>
  <field name="category_s">Notice</field>

  <field name="type_s">WebLogicServer</field>
  <field name="servername_s">AdminServer</field>
  <field name="code">BEA-000365</field>
  <field name="msg_s">Server state changed to RUNNING</field>
</doc>
<doc>
<field name="id">wlslog7</field>
  <field name="time_stamp_s">Apr-8-2014-7:06:22-PM-PDT</field>
  <field name="category_s">Notice</field>
  <field name="type_s">WebLogicServer</field>
  <field name="servername_s">AdminServer</field>
  <field name="code">BEA-000360</field>
  <field name="msg_s">Server started in RUNNING mode</field>
</doc>
</add>

可以在 vi 编辑器中创建wlslog.xml文件,并用:wq 命令保存,如图 11-23 所示。

A418863_1_En_11_Fig23_HTML.gif

图 11-23。

The wlslog.xml File

Cd 到/opt/solr目录,并运行 post 工具将wlslog.xml文件中的文档添加到 Solr 服务器。

bin/post -c wlslog ./wlslog.xml

一个文件被编入索引,如图 11-24 所示。

A418863_1_En_11_Fig24_HTML.gif

图 11-24。

Posting the wlslog.xml File to the Solr Index

使用 REST 客户端在命令行上访问 Solr

Solr 请求处理器命令如/update/select可以使用 REST 客户端如 curl 和 wget 运行。在这一节中,我们将使用 curl 工具运行一些/select请求处理程序命令。例如,使用下面的 curl 命令查询所有文档。

curl http://localhost:8983/solr/wlslog/select?q=*%3A*&wt=json&indent=true

卷曲命令如图 11-25 所示。

A418863_1_En_11_Fig25_HTML.gif

图 11-25。

Using curl to send a Request to Solr Server with Request Handler /select

添加的 7 个文件列表如图 11-26 所示。

A418863_1_En_11_Fig26_HTML.gif

图 11-26。

Listing the Documents returned by the /select Request Handler

作为另一个例子,运行/select请求处理程序来查询 id 为wlslog7的文档。

curl http://localhost:8983/solr/wlslog/select?q=id:wlslog7&wt=json&indent=true

id 为wlslog7的文件被列出,如图 11-27 所示。

A418863_1_En_11_Fig27_HTML.gif

图 11-27。

Querying for a Single Document with id wlslog7 using /select Request Handler and curl

可用post工具删除文件。例如,使用下面的命令删除 id 为wlslog1的文档。

bin/post -c wlslog -d "<delete><id>wlslog1</id></delete>"

id 为wlslog1的文档被删除,如图 11-28 所示。

A418863_1_En_11_Fig28_HTML.gif

图 11-28。

Deleting a Document using post Tool

随后运行下面的 curl 命令,列出wlslog索引中的文档。

curl http://localhost:8983/solr/wlslog/select?q=*%3A*&wt=json&indent=true

id 为wlslog1的文件未被列出,如图 11-29 所示。

A418863_1_En_11_Fig29_HTML.gif

图 11-29。

Querying after Deleting a Document

/update请求处理程序可以用来删除文档,如下面的 curl 命令,它删除了wlslog核心中的所有文档。

curl http://localhost:8983/solr/wlslog/update --data '<delete><query>*:*</query></delete>' -H 'Content-type:text/xml; charset=utf-8'

如果尚未配置自动提交,则必须运行以下 curl 命令来提交更改。

curl http://localhost:8983/solr/wlslog/update --data '<commit/>' -H 'Content-type:text/xml; charset=utf-8'

随后运行 curl 命令来调用/select请求处理程序。

curl http://localhost:8983/solr/wlslog/select?q=*%3A*&wt=json&indent=true

如图 11-30 所示,所有文件都被删除,没有列出任何文件。

A418863_1_En_11_Fig30_HTML.gif

图 11-30。

Deleting all Documents in Solr Index with /update

设置端口转发

如果我们在本地机器上运行 Kubernetes,我们可以使用 url http://localhost:8983打开 Solr 管理控制台,但是因为我们使用的是 Amazon EC2 实例,所以我们需要在本地机器上使用 web 浏览器从 localhost:8983 到 172.17.0.2:8983 设置端口转发。从本地机器运行以下命令,从localhost端口 8983 设置端口转发。

ssh -i key-pair-file -f -nNT -L 8983:172.17.0.2:8983 ubuntu@ec2-54-152-82-142.compute-1.amazonaws.com

前面的命令将localhost:8983 URL to endpoint 172.17.0.2:8983向前,如图 11-31 所示。

A418863_1_En_11_Fig31_HTML.gif

图 11-31。

Setting Port Forwarding to localhost

在管理控制台中访问 Solr

在端口转发之后,Solr 管理控制台可以使用 url http://localhost:8983从本地机器访问,如图 11-32 所示。在型芯选择器中选择wlslog型芯,如图 11-32 所示。

A418863_1_En_11_Fig32_HTML.gif

图 11-32。

Displaying the Solr Admin Console

选择文档选项卡,将/update请求处理器的文档类型设置为 XML,如图 11-33 所示。复制并粘贴前面在文档字段中列出的 XML 文档 wlslog.xml,然后单击提交文档。

A418863_1_En_11_Fig33_HTML.jpg

图 11-33。

Adding Document to the wlslog Core

如图 11-34 所示的“成功”输出表示文档已被索引。

A418863_1_En_11_Fig34_HTML.gif

图 11-34。

Response from adding Documents

接下来,我们将查询wlslog索引。选择查询选项卡,如图 11-35 所示。

A418863_1_En_11_Fig35_HTML.gif

图 11-35。

Selecting the Query Tab

请求处理程序为/select时,查询默认为“:”,如图 11-36 所示。

A418863_1_En_11_Fig36_HTML.gif

图 11-36。

Using the Request Handler /select to Query Solr index wlslog

点击执行查询,如图 11-37 所示。

A418863_1_En_11_Fig37_HTML.gif

图 11-37。

Submitting a Query to select all Documents in the wlslog Index

因为我们没有设置自动提交,所以添加的文档还没有被索引。因此,没有文件被列出,如图 11-38 所示。

A418863_1_En_11_Fig38_HTML.gif

图 11-38。

Response from the Query

我们需要重新加载核心,以便为添加的文档建立索引。或者,我们可以重启 Solr 服务器,但是重新加载内核是一个更快的选择。选择核心管理员并点击重新加载,如图 11-39 所示。

A418863_1_En_11_Fig39_HTML.gif

图 11-39。

Reloading the Core

再次运行查询,如图 11-40 所示,添加的 7 个文档被列出。

A418863_1_En_11_Fig40_HTML.gif

图 11-40。

Query Response with 7 Documents

Solr 服务器已经自动将_version_字段添加到每个文档中,如图 11-41 所示。

A418863_1_En_11_Fig41_HTML.gif

图 11-41。

The version Field is added to each Document stored in Solr Index Automatically by the Solr Server

扩展集群

要缩放 Solr pod 集群,运行kubectl scale命令。例如,要扩展到 4 个单元,请将副本设置为 4。

kubectl scale rc solr-rc --replicas=4

输出“scaled”表示 Solr 集群已经被缩放。随后运行以下命令来列出窗格。

kubectl get pods

如图 11-42 所示,列出的吊舱数量为 4 个,而不是开始时的 2 个。一些 pod 可能没有运行或最初没有准备好。

A418863_1_En_11_Fig42_HTML.gif

图 11-42。

Scaling the Apache Solr Cluster to 4 Pods

摘要

Apache Solr 是一个索引和搜索引擎,它利用本地文件系统来存储数据。在本章中,我们使用 Docker 映像“solr”和 Kubernetes 集群管理来创建和管理 Solr 实例集群。我们演示了如何从 Docker 容器的交互式 shell 访问 Solr 实例,以及如何使用管理控制台。在下一章中,我们将使用库伯涅特斯和 ApacheKafka。

十二、使用 ApacheKafka

Apache Kafka 是一个发布-订阅、高吞吐量、分布式消息传递系统。Kafka 中的一个代理可以处理来自多个客户端的每秒 100 兆字节的读写。消息在整个集群中复制,并保存到磁盘上。Kafka 可用于流处理、网站活动跟踪、指标收集、监控和日志聚合。

Kafka 架构的主要组件是生产者、代理、主题和消费者。Kafka 在主题中保存信息的提要。生产者向主题发送(或编写)消息,消费者从主题中消费(或读取)消息。消息是数据的字节数组,可以是任何格式,最常见的是 String、JSON 和 Avro。邮件会保留指定的时间。一个动物园管理员协调 Kafka 集群。在单个生产者-消费者架构中,单个生产者向主题发送消息,单个消费者从主题中消费消息。

Kafka 类似于 Flume,因为它流式传输消息,但 Kafka 是为不同的目的而设计的。虽然 Flume 是为将消息流式传输到 HDFS 或 HBase 等接收器而设计的,但 Kafka 是为供多个应用使用的消息而设计的。

在本章中,我们将讨论使用 Kubernetes 集群管理器和 Apache Kafka。

  • 设置环境
  • 修改 Docker 映像
  • 创建服务
  • 创建复制控制器
  • 列出 POD
  • 描述一个 Pod
  • 启动交互式 Shell
  • 启动 Kafka 服务器
  • 创建主题
  • 创建 Kafka 制作人
  • 启动 Kafka 消费者
  • 生产和消费消息
  • 扩展集群
  • 删除复制控制器和服务

设置环境

我们使用了从 AMI Ubuntu Server 14.04 LTS (HVM)创建的 Amazon EC2 实例,SSD 卷类型- ami-d05e75b8。本章需要以下软件。

  • -Docker 引擎(最新版本)
  • -库服务器群集管理器 1.01 版
  • -Kubernetes(1.01 版)
  • -Docker 映像 dockerkafka/kafka(最新版本)

我们在本章中使用了 Docker 映像dockerkafka/kafkadockerkafka/kafka映像 docker 文件的默认设置不适合与 Kubernetes 进行编排。在下一节中,我们修改并重建了默认的 Docker 映像。首先,使用 Amazon EC2 实例的公共 IP 地址连接 Ubuntu 实例。

ssh -i "docker.pem" ubuntu@54.146.140.160

Ubuntu 实例如图 12-1 所示连接。

A418863_1_En_12_Fig1_HTML.gif

图 12-1。

Connecting to an Ubuntu Instance on Amazon EC2

按照第一章所述安装所需软件。启动 Docker 服务并查找其状态。

sudo service docker start
sudo service docker status

如图 12-2 所示,Docker 应被列为正在运行。

A418863_1_En_12_Fig2_HTML.gif

图 12-2。

Starting Docker

列出永恒的服务。

kubectl get services

应列出“kubernetes”服务,如图 12-3 所示。

A418863_1_En_12_Fig3_HTML.gif

图 12-3。

Listing the “kubernetes” Service

修改 Docker 映像

启动 Apache Kafka 的过程包括以下序列。

Start Zookeeper Server   Start Apache Kafka Server

Apache Kafka 服务器依赖于 Zookeeper 服务器,因此需要在 Kafka 服务器启动之前运行 Zookeeper 服务器。Kafka 服务器在启动时使用server.properties配置文件。server.properties文件中的默认设置不适合 Kafka 服务器基于运行在localhost:2181的 Zookeeper 服务器启动。我们需要在server.properties文件中修改 Zookeeper 的连接 url。

在本节中,我们将下载dockerkafka/kafka映像,修改server.properties并重建 Docker 映像。用下面的命令下载dockerkafka/kafka映像的源代码。

git clone https://github.com/DockerKafka/kafka-docker.git

dockerkafka/kafka映像的源代码被下载,如图 12-4 所示。

A418863_1_En_12_Fig4_HTML.gif

图 12-4。

Downloading the kafka-docker Docker Image Source Code

将目录(cd)更改为kafka-docker目录,并列出文件/目录。

cd kafka-docker
ls –l

Docker 镜像中的文件/目录被列出,如图 12-5 所示。

A418863_1_En_12_Fig5_HTML.gif

图 12-5。

Listing the Dockerfile and Image Directory for the kafka-source Docker Image

我们需要修改位于image/conf目录下的server.properties文件中的设置。Cd 到image/conf目录,并列出该目录的文件/目录。

cd image/conf
ls –l

server.properties文件被列出,如图 12-6 所示。

A418863_1_En_12_Fig6_HTML.gif

图 12-6。

Listing the Configuration Files for the Docker Image

在 vi 编辑器中打开server.properties文件。

sudo vi server.properties

server.properties文件如图 12-7 所示。取消带有host.name=localhost设置的行的注释。

A418863_1_En_12_Fig7_HTML.gif

图 12-7。

Uncommenting the host.name Property

如图 12-8 所示zookeeper.connect的默认设置为zookeeper:2181

A418863_1_En_12_Fig8_HTML.gif

图 12-8。

The default setting for the zookeeper.connect Property

zookeeper.connect设置修改为localhost:2181,如图 12-9 所示。用:wq 保存修改后的文件。我们需要修改设置,因为默认情况下不存在“zookeeper”这样的主机。

A418863_1_En_12_Fig9_HTML.gif

图 12-9。

Setting zookeeper.connect to localhost: 2181

随后,cd 回到 Docker 映像的根目录,即kafka-docker目录,并运行以下命令来重建 Docker 映像。

sudo docker build -t dockerkafka/kafka:v2.

该命令的输出如图 12-10 所示。

A418863_1_En_12_Fig10_HTML.gif

图 12-10。

Rebuilding the Docker Image for Kafka

Docker 映像得到重建,如图 12-11 所示。

A418863_1_En_12_Fig11_HTML.gif

图 12-11。

Completing the Rebuild of the Docker Image

我们随后将使用的 Docker 映像不是dockerkafka/kafka而是dockerkafka/kafka:v2

创建服务

创建一个名为kafka-service.yaml的服务定义文件,并将以下(表 12-1 )字段添加到该文件中。

表 12-1。

The Fields in the Service Definition File

| 田 | 描述 | 价值 | | --- | --- | --- | | apiVersion(堆叠版本) |   | 第五颅神经的眼支 | | 种类 | 定义文件的种类。 | 服务 | | 元数据 | 服务元数据。 |   | | 元数据->标签 | 服务标签。不需要。 | 应用程式:Kafka | | 元数据->名称 | 服务名称。必选。 | Kafka | | 投机 | 服务规范。 |   | | 规格->端口 | 服务公开的端口。 |   | | 规格->端口->端口 | 服务公开的端口。9092 端口用于 Kafka 服务器。 | 端口:9092 目标端口:9092 | | 规格->端口->端口 | 服务公开的另一个端口。2181 端口是给动物园管理员的。 | 端口:2181 目标端口:2181 | | 规格->选择器 | 吊舱选择器。服务将流量路由到标签与选择器表达式匹配的 pod。 | 应用程式:Kafka | | 规格->选择器->类型 | 服务类型。 | LoadBalancer(负载均衡器) |

kafka-service.yaml已列出。

apiVersion: v1
kind: Service
metadata:
  labels:
    app: kafkaApp
  name: kafka
spec:
  ports:
    -
      port: 9092
      targetPort: 9092
    -
      port: 2181
      targetPort: 2181
  selector:
    app: kafkaApp
  type: LoadBalancer

可以在 vi 编辑器中创建kafka-service.yaml并用:wq 保存,如图 12-12 所示。

A418863_1_En_12_Fig12_HTML.gif

图 12-12。

Service Definition File in vi Editor

从定义文件创建服务。

kubectl create -f kafka-service.yaml

随后列出服务。

kubectl get services

“kafka”服务被列出,如图 12-13 所示。服务选择器是 app = kafkaApp。

A418863_1_En_12_Fig13_HTML.gif

图 12-13。

Creating a Service from the Definition File

创建复制控制器

为复制控制器创建一个名为kafka-rc.yaml的定义文件,并添加以下字段(表 12-2 )。

表 12-2。

Fields in the Replication Controller Definition File

| 田 | 描述 | 价值 | | --- | --- | --- | | apiVersion(堆叠版本) |   | 第五颅神经的眼支 | | 种类 | 定义文件的种类。 | 复制控制器 | | 元数据 | 复制控制器元数据。 |   | | 元数据->标签 | 复制控制器标签。 | app:kafcapp 名称:kafca-RC | | 投机 | 复制控制器规范。 |   | | 规格->副本 | Pod 副本的数量。 | Two | | 规格->选择器 | key:用于选择要管理的窗格的值表达式。标签与选择器表达式相同的窗格由复制控制器管理。选择器表达式必须与规范->模板->元数据->标签表达式相同。如果没有指定,选择器默认为规范->模板->元数据->标签键:值表达式。 | 应用程式:Kafka | | 规格->模板 | Pod 模板。 |   | | 规格->模板->元数据 | Pod 模板元数据。 |   | | 规格->模板->元数据->标签 | Pod 模板标签。 | 应用程式:Kafka | | 规格->模板->规格 | Pod 模板规范。 |   | | 规格->模板->规格->容器 | Pod 模板的容器配置。 |   | | 规格->模板->规格->容器->命令 | 为 Docker 映像运行的命令。Dockerfile 中的默认命令是 CMD ["kafka-server-start.sh ","/opt/Kafka _ 2.10-0 . 8 . 2 . 1/config/server . properties "]。默认命令启动 Kakfa 服务器,但是我们希望 Zookeeper 服务器在 Kafka 服务器之前,因为 Kafka 服务器不会启动,除非 Zookeeper 服务器正在运行。修改后的命令只启动 Zookeeper 服务器。我们将单独启动 Kafka 服务器。 | -zookeeper-server-start . sh-/opt/Kafka _ 2.10-0 . 8 . 2 . 1/config/zookeeper . properties | | 规格->模板->规格->容器->映像 | Docker 的形象。 | dock fk/Kaka:v2 | | 规格->模板->规格->容器->名称 | 容器名称。 | 动物园管理员 | | 港口 | 指定容器端口。 | 容器港口:2181 |

kafka-rc.yaml已列出。

---
apiVersion: v1
kind: ReplicationController
metadata:
  labels:
    app: kafkaApp
  name: kafka-rc
spec:
  replicas: 1
  selector:
    app: kafkaApp
  template:
    metadata:
      labels:
        app: kafkaApp
    spec:
      containers:
        -
          command:
            - zookeeper-server-start.sh
            - /opt/kafka_2.10-0.8.2.1/config/zookeeper.properties
          image: "dockerkafka/kafka:v2"
          name: zookeeper
          ports:
            -
              containerPort: 2181

可以在 vi 编辑器中创建并保存kafka-rc.yaml文件,如图 12-14 所示。

A418863_1_En_12_Fig14_HTML.gif

图 12-14。

Replication Controller Definition File in vi Editor

从定义文件创建复制控制器。

kubectl create -f kafka-rc.yaml  

随后列出复制控制器。

kubectl get rc

复制控制器被创建并列出,如图 12-15 所示。

A418863_1_En_12_Fig15_HTML.gif

图 12-15。

Creating the Replication Controller from the Definition File

要描述kafka-rc,运行以下命令。

kubectl describe rc kafka-rc

复制控制器描述被列出,如图 12-16 所示。

A418863_1_En_12_Fig16_HTML.gif

图 12-16。

Describing the Replication Controller

列出 POD

要列出窗格,请运行以下命令。

kubectl get pods

吊舱被列出,如图 12-17 所示。

A418863_1_En_12_Fig17_HTML.gif

图 12-17。

Listing the pods for Kafka

描述一个 Pod

仅创建一个 Pod,因为定义文件kafka-rc.yaml中的“副本”设置为 1。要描述 Pod,请运行以下命令。

kubectl describe pod kafka-rc-k8as1

吊舱描述被列出,如图 12-18 所示。Pod 标签app=kafkaApp与服务选择器和复制控制器选择器相同,这使得服务和复制控制器可以管理 Pod。

A418863_1_En_12_Fig18_HTML.gif

图 12-18。

Describing a pod for Kafka

当 Pod 被创建和启动时,Zookeeper 服务器开始启动,因为用于修改的 Docker 映像的命令是启动 Zookeeper 服务器。接下来,我们将从 Docker 容器的交互式 shell 中启动 Kafka 服务器,用于修改后的 Docker 映像。

启动交互式 Shell

为了能够启动交互式 bash shell 来访问安装的 Kafka 软件,我们需要知道运行修改后的 Docker 映像的 Docker 容器的容器 id。用下面的命令列出 Docker 容器。

sudo docker ps

Docker 容器如图 12-19 所示。

A418863_1_En_12_Fig19_HTML.gif

图 12-19。

Obtaining the Docker Container Id

复制容器 id 并启动交互式 bash shell。

sudo docker exec -it 939ae2cb4f86 bash

交互外壳启动,如图 12-20 所示。

A418863_1_En_12_Fig20_HTML.gif

图 12-20。

Starting the Interactive TTY for the Docker Container

启动 Kafka 服务器

Kafka 服务器的配置属性在config/server.properties文件中设置,我们在重建 Docker 映像时修改了这个文件。因为 Zookeeper 已经在运行,所以用下面的命令启动 Kafka 服务器。

kafka-server-start.sh /opt/kafka_2.10-0.8.2.1/config/server.properties

前面的命令如图 12-21 所示。

A418863_1_En_12_Fig21_HTML.gif

图 12-21。

Starting the Kafka Server

Kafka 服务器启动,如图 12-22 所示。

A418863_1_En_12_Fig22_HTML.gif

图 12-22。

Kafka Server started at localhost:9092

创建主题

接下来,用下面的命令创建一个名为“kafka-on-kubernetes”的主题。将分区数量设置为 1,将复制因子设置为 1。动物园管理员设置为localhost:2181

kafka-topics.sh --create --topic kafka-on-kubernetes --zookeeper localhost:2181 --replication-factor 1 --partitions 1

如图 12-23 所示,kafka-on-kubernetes主题被创建。

A418863_1_En_12_Fig23_HTML.gif

图 12-23。

Creating a Kafka Topic

创建 Kafka 制作人

Kafka 生产者是用来生产信息的。启动 ZooKeeper 和 Kafka 服务器后,启动 Kafka producer。使用–topic选项将主题指定为“kafka-on-kubernetes”。--broker-list指定 Kafka 服务器为localhost:9092,这是在server.properties文件中配置的设置。

kafka-console-producer.sh --topic kafka-on-kubernetes --broker-list localhost:9092

如图 12-24 所示,Kafka 制作人开始了。

A418863_1_En_12_Fig24_HTML.gif

图 12-24。

Starting a Kafka Producer

启动 Kafka 消费者

Kafka 式的消费者消费信息。使用以下命令启动 Kafka 消费程序。使用–topic选项将主题指定为“kafka-on-kubernetes”。--zookeeper指定 Zookeeper 服务器为localhost:2181,这是在server.properties文件中配置的设置。--from-beginning选项指定从一开始就要消费消息,而不仅仅是消费者启动后消费的消息。

kafka-console-consumer.sh --topic kafka-on-kubernetes --from-beginning --zookeeper localhost:2181

如图 12-25 所示,Kafka 制作人开始了。

A418863_1_En_12_Fig25_HTML.jpg

图 12-25。

Starting a Kafka Consumer

生产和消费消息

启动了生产者和消费者之后,我们将在生产者处产生消息,在消费者处消费消息。如图 12-26 所示,在生产者处添加一条消息,例如“来自 Kafka 生产者的消息”,并点击输入按钮。信息被发送出去。

A418863_1_En_12_Fig26_HTML.jpg

图 12-26。

Producing a Message at the Kafka Producer

在消费者处,消息被消费,如图 12-27 所示。

A418863_1_En_12_Fig27_HTML.gif

图 12-27。

Consuming a Message at the Kafka Consumer

在生产者处发送更多消息,如图 12-28 所示。

A418863_1_En_12_Fig28_HTML.gif

图 12-28。

Producing More Messages at the Kafka Producer

并且消息在消费者处被消费,如图 12-29 所示。

A418863_1_En_12_Fig29_HTML.gif

图 12-29。

Consuming More Messages at the Kafka Consumer

扩展集群

要将群集从 1 个单元扩展到 4 个单元,请运行以下命令。

kubectl scale rc kafka-rc --replicas=4

随后列出 POD。

kubectl get pods

输出“scaled”表示集群已被缩放,如图 12-30 所示。随后吊舱被列出,也如图 12-30 所示。

A418863_1_En_12_Fig30_HTML.gif

图 12-30。

Scaling the Kafka Cluster

当 pod 的数量增加到 4 时,服务端点也增加到 4。描述服务kafka

kubectl describe svc kafka

如图 12-31 所示,这两个服务都列出了 4 个端点,一个用于 Zookeeper 服务器,另一个用于 Kafka 服务器。

A418863_1_En_12_Fig31_HTML.gif

图 12-31。

Describing the Kafka Service with 4 Endpoints

删除复制控制器和服务

要删除复制控制器和服务,请运行以下命令。

kubectl delete rc kafka-rc
kubectl delete service kafka

如图 12-32 所示,复制控制器和服务被删除。

A418863_1_En_12_Fig32_HTML.gif

图 12-32。

Deleting the Kafka Replication Controller and Service

摘要

Apache Kafka 是一个基于生产者和消费者的信息系统。在本章中,我们讨论了使用 Kubernetes 管理 Kafka 集群。管理 Kafka 不同于其他一些应用,因为必须启动两个服务器:Zookeeper 服务器和 Kafka 服务器。Kafka 服务器依赖于 Zookeeper 服务器,这意味着 Zookeeper 必须在 Kafka 服务器之前启动。我们需要修改 zookeeper 连接 url 的默认映像dockerkafka/kafka。在复制控制器定义文件中,我们使用一个定制命令来运行修改后的 Docker 映像,以启动 Zookeeper 服务器,Docker 映像中的默认设置是启动 Kafka 服务器。到目前为止,我们运行的所有应用都是基于单个容器 Pod 的。在下一章中,我们将开发一个多容器 Pod。

十三、创建多容器 Pod

Pod 是由 Kubernetes 管理的应用的原子单位。一个 Pod 有一个文件系统和 IP 地址;Pod 中的容器共享文件系统和网络 IP。一个 Pod 可以由一个或多个容器组成。使用 Pod 规范( http://kubernetes.io/v1.1/docs/api-reference/v1/definitions.html#_v1_podspec )在 Pod 或复制控制器的定义文件中定义 Pod。使用容器规范( http://kubernetes.io/v1.1/docs/api-reference/v1/definitions.html#_v1_container )指定 Pod 中的单个容器。在前面章节中讨论的所有应用中,使用了单个容器箱。在本章中,我们将开发一个多容器 Pod。我们已经为多容器 Pod 使用了tutum/hello-worldpostgres Docker 映像。在前面的章节中,这些映像中的每一个都在单个容器窗格中使用过。本章将涵盖以下主题。

  • 如何找到一个箱中的容器数量?
  • 使用多容器箱的应用类型
  • 设置环境
  • 创建服务
  • 描述服务
  • 创建复制容器
  • 列出 POD
  • 列出 Docker 容器
  • 创建复制控制器后描述服务
  • 在命令行上调用 Hello World 应用
  • 启动交互式 Shell
  • 正在启动 PostgreSQL Shell
  • 设置端口转发
  • 在浏览器中打开 Hello World 应用
  • 扩展集群
  • 描述扩展后的服务
  • 描述一个 Pod
  • 设置端口转发
  • 在浏览器中打开 Hello World 应用
  • 从命令行调用 Hello World 应用
  • 删除复制控制器
  • 删除服务

如何找到一个箱中的容器数量?

如前所述,可以使用以下命令列出 pod。

kubectl get pods

Kubernetes Pod k8s-master-127.0.0.1 Pod 有 3/3 在就绪列中,如图 13-1 所示。3/3 表示 Pod 有 3 个容器,并且这三个容器都准备好了。任何箱的就绪栏中的 n/n 表示容器总数中就绪的容器数。所有容器都运行在一个节点上,如后面的节点列表所示。

A418863_1_En_13_Fig1_HTML.gif

图 13-1。

Listing the Pods and the Number of Containers in the Pods

使用多容器 Pod 的应用类型

各种类型的应用可以利用多容器 Pod。一些例子如下:

  • Apache Sqoop 应用利用 CDH Docker 基于映像的容器和 MySQL 数据库 Docker 基于映像的容器将数据从 MySQL 数据库批量传输到 HDFS。
  • Apache Flume 应用利用基于 CDH Docker 映像的容器和基于 Kafka 的容器将数据从 Kafka 源传输到 HDFS。
  • Apache Solr 应用利用基于 Oracle 数据库的容器和 Solr 容器将数据从 Oracle 数据库导入 Solr。
  • -一个 Apache Hive 应用使用一个 CDH 容器和一个 MongoDB 容器,通过 MongoDB 存储处理程序创建一个 Hive 表。
  • -需要一个 Apache Solr 容器和一个 CDH 容器来将 Solr 数据存储在 HDFS,而不是本地文件系统。

设置环境

我们已经使用了从 AMI Ubuntu Server 14.04 LTS (HVM),SSD 卷类型- ami-d05e75b8 创建的 Amazon EC2 实例来安装以下所需的软件。

  • -Docker 引擎(最新版本)
  • -Kubernetes(1.01 版)
  • -Kubernetes(1.01 版)
  • -Docker image tutum/hello-world(最新版本)
  • -Docker 映像 postgres(最新版本)

按照第一章所述安装 Docker、Kubernetes 和 Kubectl。要登录 Ubuntu 实例,可以从亚马逊 EC2 控制台获取公共 IP 地址,如图 13-2 所示。

A418863_1_En_13_Fig2_HTML.gif

图 13-2。

Obtaining the Public IP Address

SSH 登录到 Ubuntu 实例。

ssh -i "docker.pem" ubuntu@52.90.62.35

安装 Docker 后,启动 Docker 并验证其状态。

sudo service docker start
sudo service docker status

如图 13-3 所示,Docker 应被列为“正在运行”。

A418863_1_En_13_Fig3_HTML.gif

图 13-3。

Starting Docker

创建服务

创建一个服务定义文件hello-postgres-service.yaml来配置服务端口。我们将配置两个服务端口,一个用于hello-world应用,另一个用于postgres应用。服务定义文件中的字段在表 13-1 中讨论。

表 13-1。

Fields in the Service Definition File

| 田 | 描述 | 价值 | | --- | --- | --- | | apiVersion(堆叠版本) |   | 第五颅神经的眼支 | | 种类 | 定义文件的种类。 | 服务 | | 元数据 | 服务元数据。 |   | | 元数据->标签 | 服务标签。该设置转换为标签 app = MultiContainerApp | app:多容器面板 | | 元数据->名称 | 服务名称。 | 你好-波斯特格里斯 | | 投机 | 服务规范。 |   | | 规格->端口 | 服务公开的端口。公开了两个端口,一个用于 hello-world 应用,另一个用于 postgres 应用。 | 名称:hello-world 端口:8080 名称:postgres 端口:5432 | | 规格->选择器 | 吊舱选择器。服务将流量路由到标签与选择器表达式匹配的 pod。该设置转换为选择器 app = MultiContainerApp | app:多容器面板 | | 规格->选择器->类型 | 服务类型。 | LoadBalancer(负载均衡器) |

列出了hello-postgres-service.yaml:

apiVersion: v1
kind: Service
metadata:
  labels:
    app: MultiContainerApp
  name: hello-postgres
spec:
  ports:
    -
      name: hello-world
      port: 8080
    -
      name: postgres
      port: 5432
  selector:
    app: MultiContainerApp
  type: LoadBalancer

从定义文件创建服务。

kubectl create -f hello-postgres-service.yaml

随后列出服务。

kubectl get services

hello-postgres服务被创建并列出,如图 13-4 所示。

A418863_1_En_13_Fig4_HTML.gif

图 13-4。

Creating a Service from the Definition File

描述服务

可以用下面的命令描述hello-postgres服务。

kubectl describe service hello-postgres

服务描述包括名称、命名空间、标签、选择器、类型、IP、端口和端点,如图 13-5 所示。最初,该服务不管理任何 pod,因此没有列出任何端点。

A418863_1_En_13_Fig5_HTML.gif

图 13-5。

Describing the Service

创建复制容器

为复制控制器创建一个定义文件hello-postgres-rc.yaml。将以下(表 13-2 )字段添加到定义文件中。

表 13-2。

Fields in the Replication Controller Definition File

| 田 | 描述 | 价值 | | --- | --- | --- | | apiVersion(堆叠版本) |   | 第五颅神经的眼支 | | 种类 | 定义文件的种类。 | 复制控制器 | | 元数据 | 复制控制器元数据。 |   | | 元数据->标签 | 复制控制器标签。 | app:“多容器” | | 元数据->名称 | 复制控制器的名称。 | “你好-波斯特格里斯” | | 投机 | 复制控制器规范。 |   | | 规格->副本 | Pod 副本的数量。 | one | | 规格->选择器 | key:用于选择要管理的窗格的值表达式。标签与选择器表达式相同的窗格由复制控制器管理。选择器表达式必须与规范->模板->元数据->标签表达式相同。如果没有指定,选择器默认为规范->模板->元数据->标签键:值表达式。 | app:“多容器” | | 规格->模板 | Pod 模板。 |   | | 规格->模板->元数据 | Pod 模板元数据。 |   | | 规格->模板->元数据->标签 | Pod 模板标签。如果未指定选择器,则默认为该设置。服务选择器必须与代表 Pod 的服务的 Pod 模板标签相同。服务选择器没有默认为与标签相同的值,我们已经将服务选择器设置为 app: MultiContainerApp。 | app:“多容器” | | 规格->模板->规格 | Pod 模板规范。 |   | | 规格->模板->规格->容器 | Pod 模板的容器配置。 |   | | 规格->模板->规格->容器->映像 | hello-world 容器的 Docker 映像。 | tutum/hello-world | | 规格->模板->规格->容器->名称 | hello-world 容器的容器名。 | hello-world | | 港口 | 指定 hello-world 容器的容器端口。 | 容器港口:8080 | | 规格->模板->规格->容器->映像 | postgres 容器的 Docker 映像。 | 数据库 | | 规格->模板->规格->容器->名称 | postgres 容器的容器名称。 | 数据库 | | 港口 | 邮政容器的容器港口。 | 容器港口:5432 |

列出了hello-postgres-rc.yaml:

apiVersion: v1
kind: ReplicationController
metadata:
  labels:
    app: "MultiContainerApp"
  name: "hello-postgres"
spec:
  replicas: 1
  selector:
    app: "MultiContainerApp"
  template:
    metadata:
      labels:
        app: "MultiContainerApp"
    spec:
      containers:
        -
          image: "tutum/hello-world"
          name: "hello-world"
          ports:
            -
              containerPort: 8080
        -
          image: "postgres"
          name: "postgres"
          ports:
            -
              containerPort: 5432

从定义文件创建一个复制控制器。

kubectl create -f hello-postgres-rc.yaml

随后列出复制控制器。

kubectl get rc

如图 13-6 所示,hello-postgres复制控制器被创建并列出。

A418863_1_En_13_Fig6_HTML.gif

图 13-6。

Creating a Replication Controller from the Definition File

列出 POD

要列出窗格,请运行以下命令。

kubectl get pods

当复制控制器中的replicas字段被设置为 1 时,只有一个 Pod 被创建,如图 13-7 所示。“就绪”列列出了 0/2,这表示 pod 中的两个容器都没有就绪。最初,容器可能被列为未运行和正在创建。几秒钟后运行前面的命令,Pod 状态应该是“正在运行”,就绪状态应该是 2/2,这意味着两个容器中有两个正在运行。

A418863_1_En_13_Fig7_HTML.gif

图 13-7。

Listing the Pods

列出 Docker 容器

要列出已启动的 Docker 容器,请运行以下命令。

sudo docker ps

列出的两个容器,基于postgres映像的容器和基于tutum/hello-world映像的容器,如图 13-8 所示,由复制控制器hello-postgres启动。

A418863_1_En_13_Fig8_HTML.gif

图 13-8。

Listing the Docker Containers

创建复制控制器后描述服务

在我们创建复制控制器之前,服务hello-postgres没有与任何端点相关联。创建复制控制器和 Pod 后,再次运行以下命令来描述服务。

kubectl describe service hello-postgres

为服务公开的每个端口列出一个端点,如图 13-9 所示。

A418863_1_En_13_Fig9_HTML.gif

图 13-9。

Describing the Service

在命令行上调用 Hello World 应用

使用 curl 调用服务端点172.17.0.2,如下所示。

curl 172.17.0.2

应用生成的 HTML 得到如图 13-10 所示的输出。

A418863_1_En_13_Fig10_HTML.gif

图 13-10。

Invoking an Endpoint for the Service

启动交互式 Shell

要为安装的软件启动一个交互式外壳,可使用多容器盒的任何一个 Docker 容器,如前面图 13-8 中所列。两个容器访问相同的文件系统和 IP。使用以下命令启动交互式 shell。

sudo docker exec -it 2e351a609b5b bash

如图 13-11 所示,启动一个交互式外壳。

A418863_1_En_13_Fig11_HTML.gif

图 13-11。

Starting an Interactive Shell

正在启动 PostgreSQL Shell

要启动名为psql的 PostgreSQL 命令 shell,请在交互式 shell 中运行以下命令。

psql postgres

启动psql并显示postgres命令提示符,如图 13-12 所示。

A418863_1_En_13_Fig12_HTML.gif

图 13-12。

Starting psql Shell

第五章讨论了带有 Kubernetes 的 PostgreSQL。

设置端口转发

我们之前调用了服务端点来输出在命令行上使用 curl 生成的 HTML,但是 HTML 最好在浏览器中显示。由于 Amazon EC2 实例在默认情况下不提供浏览器,我们需要设置本地机器的端口转发,以便能够在浏览器中访问服务端点。使用以下命令将172.17.0.2:80的端口转发设置为localhost:80

ssh -i "docker.pem" -f -nNT -L 80:172.17.0.2:80 ubuntu@ec2-52-90-62-35.compute-1.amazonaws.com

转发到localhost的端口设置如图 13-13 所示。

A418863_1_En_13_Fig13_HTML.gif

图 13-13。

Setting Port Forwarding

Amazon EC2 实例的公共 DNS 可以从 Amazon EC2 控制台获得,如图 13-14 所示。

A418863_1_En_13_Fig14_HTML.gif

图 13-14。

Obtaining Public DNS

在浏览器中打开 Hello World 应用

设置端口转发后,可以在 url 为http://localhost的本地机器上的浏览器中打开应用,如图 13-15 所示。除了主机名之外,HELLO_POSTGRES监听的两个端口也被列出。

A418863_1_En_13_Fig15_HTML.gif

图 13-15。

Invoking the Service Endpoint in a Browser

扩展集群

要将群集扩展到 3 个副本或单元,请运行以下命令。

kubectl scale rc hello-postgres --replicas=3

随后列出 POD。

kubectl get pods

三个吊舱被列出,如图 13-16 所示。一些 pod 可能没有运行或最初没有准备好。几秒钟后再次运行前面的命令,列出所有状态为“正在运行”且就绪状态为 2/2 的 pod。

A418863_1_En_13_Fig16_HTML.gif

图 13-16。

Scaling the Cluster to 3 Replicas

可使用kubectl describe pod 命令描述一个 Pod。例如,用下面的命令描述hello-postgres-jliem pod。

kubectl describe pod hello-postgres-jliem

如图 13-17 所示,Pod 描述被列出。

A418863_1_En_13_Fig17_HTML.gif

图 13-17。

Describing a Pod

列出 Docker 容器

由于每个单元由两个容器组成,将集群扩展到 3 个单元或副本会启动 4 个新容器,两个新单元各有 2 个容器。在扩展集群后,运行以下命令,使用默认输出格式再次列出正在运行的 Docker 容器。

sudo docker ps

总共列出了 3 个基于postgres映像的容器和 3 个基于tutum/hello-world映像的容器,如图 13-18 所示。

A418863_1_En_13_Fig18_HTML.gif

图 13-18。

Listing the Docker Containers

描述扩展后的服务

在扩展集群后再次描述服务。

kubectl describe service hello-postgres

服务公开的每个端口都与三个端点相关联,因为有 3 个 Pods 正在运行,如图 13-19 所示。

A418863_1_En_13_Fig19_HTML.gif

图 13-19。

Describing the Service including the Service Endpoints

设置端口转发

为了能够在浏览器中打开应用,我们需要将端口转发设置为 locahost。将端口转发设置为先前未绑定的端口。在之前创建的单个 Pod 的端口转发中,localhost:80 beind 地址已经用完。要为两个新的 pod 设置端口转发,请使用本地主机上的端口 81 和 82。

ssh -i "docker.pem" -f -nNT -L 81:172.17.0.3:80 ubuntu@ec2-52-90-62-35.compute-1.amazonaws.com
ssh -i "docker.pem" -f -nNT -L 82:172.17.0.4:80 ubuntu@ec2-52-90-62-35.compute-1.amazonaws.com

前面的命令不产生任何输出,但是端口被转发到localhost,如图 13-20 所示。

A418863_1_En_13_Fig20_HTML.gif

图 13-20。

Setting Port Forwarding

在浏览器中打开 Hello World 应用

该应用可以在每个转发端口的浏览器中打开;比如在http://localhost:81打开一个浏览器。应用 HTML 显示如图 13-21 所示。HELLO_POSTGRES服务正在监听两个端口 8020 和 5432。

A418863_1_En_13_Fig21_HTML.gif

图 13-21。

Invoking a Service Endpoint in a Browser

类似地,用 url http://localhost:82在浏览器中打开另一个服务端点。监听同一端口的不同主机名被转发到localhost上的不同端口。服务端点 HTML 得到如图 13-22 所示的输出。

A418863_1_En_13_Fig22_HTML.gif

图 13-22。

Invoking another Service Endpoint in a Browser

从命令行调用 Hello World 应用

对于单个容器 Pod,可以在命令行上调用两个新服务端点中的每一个。例如,用下面的 curl 命令调用172.17.0.3端点。

curl 172.17.0.3

服务端点的 HTML 得到如图 13-23 所示的输出。

A418863_1_En_13_Fig23_HTML.gif

图 13-23。

Invoking a Service Endpoint with curl

用下面的 curl 命令调用172.17.0.4端点。

 curl 172.17.0.4

服务端点的 HTML 得到如图 13-24 所示的输出。

A418863_1_En_13_Fig24_HTML.gif

图 13-24。

Invoking another Service Endpoint with curl

删除复制控制器

要删除hello-postgres复制控制器,请运行以下命令。

kubectl delete rc hello-postgres

随后使用以下命令列出 pod。

kubectl get pods

图 13-25 中没有列出hello-postgres复制控制器的吊舱。

A418863_1_En_13_Fig25_HTML.gif

图 13-25。

Deleting the Replication Controller

删除服务

要删除服务hello-postgres,运行以下命令。

kubectl delete service hello-postgres

随后运行以下命令列出服务。

kubectl get services

未列出hello-postgres服务,如图 13-26 所示。

A418863_1_En_13_Fig26_HTML.gif

图 13-26。

Deleting the Service

摘要

在本章中,我们讨论了在一个 Pod 中使用多个容器。我们讨论了多容器 Pod 的用例,并使用tutum/hello-worldpostgres Docker 映像来创建多容器 Pod。多容器 pod 为每个 Pod 启动多个 Docker 容器,即使 Pod 是原子单位。Pod 中的多个容器共享相同的 IP 地址和文件系统。缩放多容器单元时,将为每个新单元启动多个容器。在下一章,我们将讨论在多节点集群上安装 Kubernetes。

十四、在多节点集群上安装 Kubernetes

在本书前面的所有章节中,我们都使用了单节点集群。对于大多数小型应用,单节点集群应该足够了。但是,对于相对较大规模的分布式应用,多节点集群是更合适的选择。在本章中,我们将在多节点(2 节点)集群上安装 Kubernetes。本章包括以下几节。

  • 多节点集群的组件
  • 设置环境
  • 安装主节点
  • 设置 flannels 和 etcd
  • 在主节点上启动 Kubernetes
  • 运行服务代理
  • 测试主节点
  • 添加工作节点
  • 导出主 IP
  • 设置 flannels 和 etcd
  • 在工作节点上启动 Kubernetes
  • 运行服务代理
  • 测试 Kubernetes 集群
  • 在群集上运行应用
  • 将应用公开为服务
  • 在浏览器中测试应用
  • 扩展应用

多节点集群的组件

多节点集群由以下主要和辅助组件组成。

  • Kubernetes 特大师节点 Kubernetes 大师节点 Kubernetes 大师节点 Kubernetes 大师节点 Kubernetes 大师节点 Kubernetes 大师节点 Kubernetes 大师节点 Kubernetes 大师节点 Kubernetes 大师节点
  • -Kubernetes 工作节点
  • -还有 cd
  • 法兰绒
  • -服务代理
  • -库柏

第一章讨论了 etcd、kubernetes 主服务器和服务代理。在第一章中介绍的 etcd 是一个分布式的键值存储,由 Kubernetes 集群管理器使用。我们将 etcd 安装在 Kubernetes 主节点所在的节点上,但是在生产环境中,etcd 通常会作为单独的集群安装在 Kubernetes 主节点以外的节点上。对 etcd 集群的提交基于对大多数(法定)可用节点的复制,并为一个或多个节点的故障做好准备。1 节点群集的多数是 1,3 节点群集的多数是 2,4 节点群集的多数是 3,5 节点群集的多数是 3。一个 etcd 集群通常具有奇数个(> 2)具有容错能力的节点。例如,一个 5 节点 etcd 集群可能会失去多达 2 个节点,从而导致一个 3 节点集群,其中大多数节点仍然是可确定的。一个 3 节点集群具有多一个节点的容错能力。2 节点 etcd 集群没有任何容错能力,2 节点集群的大部分被认为是 2。生产中建议的 etcd 集群大小为 3、5 或 7。

法兰绒是一种用于容器的网状织物。法兰绒为运行时容器使用的每个主机提供一个子网。实际上,法兰绒在每个分配子网的主机上运行一个名为 flanneld 的代理。法兰绒建立并管理网络,该网络将 Kubernetes 创建的所有 Docker 容器相互连接。法兰绒由 etcd 支持,使用 etcd 存储网络配置、分配的子网和辅助数据,如主机的 IP 地址。

设置环境

本章我们使用了从 Ubuntu Server 14-04 LTS (HVM)创建的 Amazon EC2 实例,SSD 卷类型- ami-d05e75b8 AMI。本章要求安装以下软件。

  • -Docker 引擎(最新版本)
  • -主节点上的库帐户(1.01 版)
  • -工作节点上的 Kubernetes(版本 1.01)
  • -Kubernetes(1.01 版)

因为我们正在创建一个多节点集群,所以我们需要创建多个 Amazon EC2 实例。对于双节点集群,创建两个 Amazon EC2 实例——KubernetesMaster 和 KubernetesWorker——如图 14-1 所示。

A418863_1_En_14_Fig1_HTML.gif

图 14-1。

Creating two Ubuntu Instances for Kubernetes Master and Worker Nodes

SSH 分别登录到每个节点。主节点的公共 IP 地址可以从 Amazon EC2 控制台获得,如图 14-2 所示。

A418863_1_En_14_Fig2_HTML.gif

图 14-2。

Obtaining the Public IP Address for a Ubuntu Instance

登录到主节点的 Ubuntu 实例。

ssh -i "docker.pem" ubuntu@52.91.243.99

类似地,获取工作者节点的 Ubuntu 实例的公共 IP 地址,并登录工作者节点的 Ubuntu 实例。

ssh -i "docker.pem" ubuntu@52.23.236.15

按照第一章所述,在每个节点上安装 Docker 和 Kubectl。不要像第一章那样安装 Kubernetes,因为 Kubernetes 的多节点配置不同于单节点配置。

启动 Docker 引擎并验证其状态。

sudo service docker start
sudo service docker status

如图 14-3 所示,Docker 引擎应被列为“正在运行”。

A418863_1_En_14_Fig3_HTML.gif

图 14-3。

Starting Docker

安装主节点

主节点托管 API 服务器并将工作分配给工作节点。我们需要运行两个 Docker 守护进程,一个主 Docker 实例和一个引导 Docker 实例。主 Docker 实例由 Kubernetes 使用,引导 Docker 实例由一个 etcd 使用。法兰绒守护进程建立并管理网络,该网络将 Kubernetes 创建的所有 Docker 容器相互连接起来。

设置 flannels 和 etcd

设置 Flanneld 和 etcd 包括为 Docker 设置一个 bootstrap 实例,为法兰绒和 API 服务器启动 etcd,以及在主节点上设置法兰绒。

设置 Docker 的引导实例

法兰绒,它在 Docker 容器之间建立网络;和 etcd 都是在 Docker 容器内部运行的。使用单独的引导 Docker 是因为法兰绒用于 Kubernetes 创建的 Docker 容器之间的联网;在同一个 Docker 引擎中运行法兰绒和 Kubernetes 可能会有问题,不推荐这样做。为法兰绒和 etcd 创建一个单独的 Docker 引导实例。

sudo sh -c 'docker daemon -H unix:///var/run/docker-bootstrap.sock -p /var/run/docker-bootstrap.pid --iptables=false --ip-masq=false --bridge=none --graph=/var/lib/docker-bootstrap 2> /var/log/docker-bootstrap.log 1> /dev/null &'

启动 bootstrap Docker 守护进程,前面命令的输出如图 14-4 所示。

A418863_1_En_14_Fig4_HTML.gif

图 14-4。

Starting the Bootstrap Daemon on the Master Node

“–d”选项在 Docker 1.10 中被完全删除,代之以“daemon”。如果使用 Docker 1.10 之前的 Docker 版本,例如 Docker 1.9.1,请将前面命令中的' daemon '替换为'-d ',以运行命令,如下所示:

sudo sh -c 'docker -d -H unix:///var/run/docker-bootstrap.sock -p /var/run/docker-bootstrap.pid --iptables=false --ip-masq=false --bridge=none --graph=/var/lib/docker-bootstrap 2> /var/log/docker-bootstrap . log 1>/dev/null&

设置 etcd

使用以下命令为法兰绒和 API 服务器设置 etcd。

sudo docker -H unix:///var/run/docker-bootstrap.sock run --net=host -d gcr.io/google_containers/etcd:2.0.12 /usr/local/bin/etcd --addr=127.0.0.1:4001 --bind-addr=0.0.0.0:4001 --data-dir=/var/etcd/data

下载 etcd 的容器并安装 etcd,如图 14-5 所示。

A418863_1_En_14_Fig5_HTML.gif

图 14-5。

Setting up etcd on the Master Node

设置无类域间路由(CIDR ),这是一种 IP 寻址方案,可以减少路由表的大小,并提供更多的可用地址。

sudo docker -H unix:///var/run/docker-bootstrap.sock run --net=host gcr.io/google_containers/etcd:2.0.12 etcdctl set /coreos.com/network/config '{ "Network": "10.1.0.0/16" }'

前面的命令不产生任何输出,如图 14-6 所示。

A418863_1_En_14_Fig6_HTML.gif

图 14-6。

Setting Up CIDR on the Master Node

设置法兰绒

默认情况下,Docker 确实提供了容器和 pod 之间的网络,但法兰绒提供的网络要简单得多。我们将使用法兰绒进行交流。首先,我们需要阻止 Docker。

sudo service docker stop

如图 14-7 所示,

A418863_1_En_14_Fig7_HTML.gif

图 14-7。

Stopping Docker Temporarily

用下面的命令运行法兰绒。

sudo docker -H unix:///var/run/docker-bootstrap.sock run -d --net=host --privileged -v /dev/net:/dev/net quay.io/coreos/flannel:0.5.0

法兰绒的安装如图 14-8 所示。

A418863_1_En_14_Fig8_HTML.gif

图 14-8。

Installing Flannel

法兰绒生成哈希如图 14-9 所示。复制哈希。

A418863_1_En_14_Fig9_HTML.gif

图 14-9。

Obtaining the Hash Generated by Flannel

将哈希复制并粘贴到以下命令中,然后运行该命令以获取子网设置。

sudo docker -H unix:///var/run/docker-bootstrap.sock exec <really-long-hash-from-above-here> cat /run/flannel/subnet.env

列出子网设置,如图 14-10 所示。

A418863_1_En_14_Fig10_HTML.gif

图 14-10。

Listing the Subnet Settings

记下FLANNEL_SUBNETFLANNEL_MTU的值,因为我们将需要它们来编辑 Docker 配置。在 vi 编辑器中打开 Docker 配置文件。

sudo vi /etc/default/docker

docker 配置文件中的默认设置如图 14-11 所示。

A418863_1_En_14_Fig11_HTML.gif

图 14-11。

Docker Configuration File Default Settings

DOCKER_OPTS设置添加以下参数,其值从图 14-10 的输出中获得。

--bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}

修改后的 docker 配置文件如图 14-12 所示。

A418863_1_En_14_Fig12_HTML.gif

图 14-12。

Modified Docker Configuration File

如前所述,Docker 通过一个名为docker0的 Docker 桥提供了自己的网络。因为我们不会使用默认的 Docker 桥,所以请删除默认的 Docker 桥。对于 brctl 二进制文件,首先安装 bridge-utils 包。

sudo /sbin/ifconfig docker0 down
sudo apt-get install bridge-utils
sudo brctl delbr docker0

安装 bridge-utils 包和移除 docker0 桥的输出如图 14-13 所示。

A418863_1_En_14_Fig13_HTML.gif

图 14-13。

Removing docker0 bridge

重启 Docker。

sudo service docker start

Docker 重新启动,如图 14-14 所示。

A418863_1_En_14_Fig14_HTML.gif

图 14-14。

Restarting Docker

启动 Kubernetes Master

设置法兰绒网络是设置单节点集群和多节点集群的主要区别。使用与单节点集群相同的命令启动 Kubernetes 主服务器。

sudo docker run \
  --volume=/:/rootfs:ro \
  --volume=/sys:/sys:ro \
  --volume=/dev:/dev \
  --volume=/var/lib/docker/:/var/lib/docker:rw \
  --volume=/var/lib/kubelet/:/var/lib/kubelet:rw \
  --volume=/var/run:/var/run:rw \
  --net=host \
  --privileged=true \
  --pid=host \
  -d \
  gcr.io/google_containers/hyperkube:v1.0.1 /hyperkube kubelet --api-servers=http://localhost:8080 --v=2 --address=0.0.0.0 --enable-server --hostname-override=127.0.0.1 --config=/etc/kubernetes/manifests-multi --cluster-dns=10.0.0.10 --cluster-domain=cluster.local

前面的命令从主节点运行,如图 14-15 所示。

A418863_1_En_14_Fig15_HTML.gif

图 14-15。

Starting Kubernetes on the Master Node

Kubernetes 安装在主节点上,如图 14-16 所示。

A418863_1_En_14_Fig16_HTML.gif

图 14-16。

Kubernetes Started on Master Node

运行服务代理

使用与单节点集群相同的命令运行服务代理。

sudo docker run -d --net=host --privileged gcr.io/google_containers/hyperkube:v1.0.1 /hyperkube proxy --master=http://127.0.0.1:8080 --v=2

服务代理的安装如图 14-17 所示。

A418863_1_En_14_Fig17_HTML.gif

图 14-17。

Starting Service proxy on Master Node

测试单节点集群

要测试主节点,请运行以下命令,该命令列出了群集中的节点。

kubectl get nodes

单个节点被列出,如图 14-18 所示。

A418863_1_En_14_Fig18_HTML.gif

图 14-18。

Listing the Nodes, only the Master Node to start with

添加工作节点

设置工作节点与设置主节点非常相似。接下来,我们将设置一个工作节点。工作者节点的 Ubuntu 实例的 SSH 登录。

导出主 IP

首先,我们需要设置环境变量MASTER_IP。获取运行主节点的 Ubuntu 实例的公共 IP 地址,如图 14-19 所示。

A418863_1_En_14_Fig19_HTML.gif

图 14-19。

Obtaining the Master Node’s IP Address

使用公共 IP 地址导出环境变量MASTER_IP

export MASTER_IP=52.91.243.99

回显MASTER_IP环境变量。

echo $MASTER_IP

前面命令的输出如图 14-20 所示。

A418863_1_En_14_Fig20_HTML.gif

图 14-20。

Exporting the MASTER_IP Environment Variable on a Worker Node

设置法兰绒

启动一个 bootstrap Docker 守护进程,只是为了法兰绒网络。

sudo sh -c 'docker daemon -H unix:///var/run/docker-bootstrap.sock -p /var/run/docker-bootstrap.pid --iptables=false --ip-masq=false --bridge=none --graph=/var/lib/docker-bootstrap 2> /var/log/docker-bootstrap.log 1> /dev/null &'

自举对接器的设置如图 14-21 所示。

A418863_1_En_14_Fig21_HTML.gif

图 14-21。

Starting Bootstrap Docker on the Worker Node

“–d”选项在 Docker 1.10 中被完全删除,代之以“daemon”。如果使用 Docker 1.10 之前的 Docker 版本,例如 Docker 1.9.1,请将前面命令中的' daemon '替换为'-d ',以运行命令,如下所示:

sudo sh -c 'docker -d -H unix:///var/run/docker-bootstrap.sock -p /var/run/docker-bootstrap.pid --iptables=false --ip-masq=false --bridge=none --graph=/var/lib/docker-bootstrap 2> /var/log/docker-bootstrap . log 1>/dev/null&

要安装法兰绒,首先我们需要停止 Docker 引擎。

sudo service docker stop

对接发动机停止,如图 14-22 所示。

A418863_1_En_14_Fig22_HTML.gif

图 14-22。

Stopping Docker Temporarily on the Worker Node

接下来,在 worker 节点上安装法兰绒。主节点上运行的相同 etcd 用于工作节点上的 flanneld。etcd 实例使用MASTER_IP环境变量包含主服务器的 Ip。

sudo docker -H unix:///var/run/docker-bootstrap.sock run -d --net=host --privileged -v /dev/net:/dev/net quay.io/coreos/flannel:0.5.0 /opt/bin/flanneld --etcd-endpoints=http://${MASTER_IP}:4001

法兰绒被设置在工人节点上,如图 14-23 所示。

A418863_1_En_14_Fig23_HTML.gif

图 14-23。

Installing Flannel on the Worker Node

复制前面命令生成的哈希,如图 14-24 所示。

A418863_1_En_14_Fig24_HTML.gif

图 14-24。

Obtaining the Hash geenrated by Flannel

使用以下命令中的哈希值从法兰绒获取子网设置。

sudo docker -H unix:///var/run/docker-bootstrap.sock exec <really-long-hash-from-above-here> cat /run/flannel/subnet.env

子网设置得到如图 14-25 所示的输出。

A418863_1_En_14_Fig25_HTML.gif

图 14-25。

Listing the Subnet Settings on the Worker Node

使用子网设置,我们需要编辑 Docker 配置文件。在 vi 编辑器中打开 Docker 配置文件。

sudo /etc/default/docker

将以下参数添加到DOCKER_OPTS设置中。将从图 14-25 中获得的值代入FLANNEL_SUBNETFLANNEL_MTU中。

--bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}

修改后的 Docker 配置文件如图 14-26 所示。

A418863_1_En_14_Fig26_HTML.gif

图 14-26。

Modified Docker Configuration File

关闭并移除现有的 Docker 网桥docker0,Docker 默认使用该网桥在容器和 pod 之间进行联网。需要安装 bridge-utils 包,因为它在 Amazon EC2 上的 Ubuntu 实例上默认不可用。

sudo /sbin/ifconfig docker0 down
sudo apt-get install bridge-utils
sudo brctl delbr docker0

重启 Docker。

sudo service docker start

对接引擎启动,如图 14-27 所示。

A418863_1_En_14_Fig27_HTML.gif

图 14-27。

Restarting Docker

在工作节点上启动 Kubernetes

使用与主节点相同的命令在 worker 节点上启动 Kubernetes,不同之处在于,不是将--api-servers设置为http://localhost:8080,而是将- api-servers 设置为http://${MASTER_IP}:8080

sudo docker run \
  --volume=/:/rootfs:ro \
  --volume=/sys:/sys:ro \
  --volume=/dev:/dev \
  --volume=/var/lib/docker/:/var/lib/docker:rw \
  --volume=/var/lib/kubelet/:/var/lib/kubelet:rw \
  --volume=/var/run:/var/run:rw \
  --net=host \
  --privileged=true \
  --pid=host \
  -d \
  gcr.io/google_containers/hyperkube:v1.0.1 /hyperkube kubelet --api-servers=http://${MASTER_IP}:8080 --v=2 --address=0.0.0.0 --enable-server --hostname-override=$(hostname -i) --cluster-dns=10.0.0.10 --cluster-domain=cluster.local

前面的命令将在 worker 节点上运行,如图 14-28 所示。

A418863_1_En_14_Fig28_HTML.gif

图 14-28。

Starting Kubernetes on the Worker Node

运行服务代理

工作节点上的服务代理也使用与主节点相同的命令运行,只是主节点的 Ip 参数-- master= http://127.0.0.1:8080应该替换为--master=http://${MASTER_IP}:8080

sudo docker run -d --net=host --privileged gcr.io/google_containers/hyperkube:v1.0.1 /hyperkube proxy --master=http://${MASTER_IP}:8080 --v=2

服务代理启动,如图 14-29 所示。

A418863_1_En_14_Fig29_HTML.gif

图 14-29。

Starting Service Proxy on the Worker Node

测试 Kubernetes 集群

从主节点,而不是前面命令中配置的工作节点,列出集群中的节点。

kubectl get nodes

列出两个节点,如图 14-30 所示:主节点和工作节点。

A418863_1_En_14_Fig30_HTML.gif

图 14-30。

Listing a Two-Node Cluster

使用本节添加工作节点中讨论的相同过程,根据需要添加更多节点。

在群集上运行应用

要测试集群,请使用 kubectl 在命令行上运行应用。例如,用下面的命令运行 Docker 映像“nginx”。

kubectl -s http://localhost:8080 run nginx --image=nginx --port=80

随后列出 POD。

kubectl get pods

如图 14-31 所示,nginx 应用容器被创建,nginx 复制控制器被创建,默认为 1 个副本。一个吊舱被列出,也如图 14-31 所示。最初,Pod 可以被列为待定状态。几秒钟后运行前面的命令,将 Pod 列为正在运行和就绪。要查找 Pod 正在群集中的哪个实例(节点)上运行,请运行命令。

A418863_1_En_14_Fig31_HTML.gif

图 14-31。

Installing an Application on the Cluster

kubectl get pods -o wide.

将应用公开为服务

要将复制控制器 nginx 作为服务公开,请运行以下命令。

kubectl expose rc nginx --port=80

nginx 服务被创建,如图 14-32 所示。

A418863_1_En_14_Fig32_HTML.gif

图 14-32。

Creating a Service

使用以下命令列出服务。

kubectl get services

为了能够调用服务,使用以下命令获取第一个集群 Ip,如图 14-33 所示。

A418863_1_En_14_Fig33_HTML.gif

图 14-33。

Invoking a Web Server with Curl

kubectl get svc nginx --template={{.spec.clusterIP}}

使用返回的集群 Ip 10 . 0 . 0 . 99 调用 web 服务器。

curl 10.0.0.99

nginx 应用返回的 HTML 输出如图 14-34 所示。

A418863_1_En_14_Fig34_HTML.gif

图 14-34。

The HTML generated by the Application

在浏览器中测试应用

要在浏览器中调用服务端点,设置从10.0.0.99:80端点到localhost:80的端口转发。

ssh -i docker.pem -f -nNT -L 80:10.0.0.99:80 ubuntu@ec2-52-91-243-99.compute-1.amazonaws.com

端口转发的设置如图 14-35 所示。

A418863_1_En_14_Fig35_HTML.gif

图 14-35。

Setting Port Forwarding

在本地浏览器中使用 url http://localhost调用 nginx 应用,如图 14-36 所示。

A418863_1_En_14_Fig36_HTML.gif

图 14-36。

Invoking a Service Endpoint in a Browser

扩展应用

缩放是复制控制器的一种常见使用模式。nginx 复制控制器可以使用kubectl scale命令进行缩放。例如,扩展到 3 个副本。

kubectl scale rc nginx --replicas=3

随后列出 POD。

kubectl get pods

输出“scaled”表示复制控制器已被扩展。三个吊舱被列出,如图 14-37 所示。

A418863_1_En_14_Fig37_HTML.gif

图 14-37。

Listing the Pods

用下面的命令描述服务。

kubectl describe svc nginx

列出三个服务端点,如图 14-38 所示。

A418863_1_En_14_Fig38_HTML.gif

图 14-38。

Describing the Service

为了能够在本地机器上的浏览器中调用每个服务端点,请设置端口转发。

ssh -i docker.pem -f -nNT -L 8081:10.1.34.2:80 ubuntu@ec2-52-91-243-99.compute-1.amazonaws.com
ssh -i docker.pem -f -nNT -L 8082:10.1.35.2:80 ubuntu@ec2-52-91-243-99.compute-1.amazonaws.com
ssh -i docker.pem -f -nNT -L 8083:10.1.35.3:80 ubuntu@ec2-52-91-243-99.compute-1.amazonaws.com

端口转发的设置如图 14-39 所示。

A418863_1_En_14_Fig39_HTML.gif

图 14-39。

Setting port Forwarding for the additional Service Endpoints

可以在本地浏览器中调用服务端点。例如,url http://localhost:8081调用一个服务端点,如图 14-40 所示。

A418863_1_En_14_Fig40_HTML.gif

图 14-40。

Invoking a Service Endpoint in a Browser

类似地,url http://localhost:8082调用另一个服务端点,如图 14-41 所示。

A418863_1_En_14_Fig41_HTML.gif

图 14-41。

Invoking another Service Endpoint in a Browser

类似地,url http://localhost:8083调用第三个服务端点,如图 14-42 所示。

A418863_1_En_14_Fig42_HTML.gif

图 14-42。

Invoking a Third Service Endpoint in a Browser

摘要

在本章中,我们在多节点集群上安装了 Kubernetes。多节点配置利用法兰绒进行联网,而不是 Docker 提供的默认联网。首先,我们在主节点上安装了 Kubernetes。使用主节点的 Ip 地址,我们在一个工作节点上安装了 Kubernetes,结果创建了一个双节点集群。可以使用相同的过程添加所需数量的工作节点。我们使用 nginx Docker 映像创建了一个应用,并使用 curl 在命令行上调用该应用,使用端口转发在本地浏览器中调用该应用。我们还扩展了应用。在单节点集群中,应用在主节点上运行。在多节点集群中,应用同时在工作节点和主节点上运行。本章总结了 Docker 关于 Kubernetes 微服务的书。

第一部分:开始

第二部分:关系数据库

第三部分:NoSQL 数据库

第四部分:Apache Hadoop 生态系统

第五部分:多容器和节点

posted @ 2024-08-12 11:18  绝不原创的飞龙  阅读(3)  评论(0编辑  收藏  举报