Docker-Kubenetes-微服务教程-全-
Docker Kubenetes 微服务教程(全)
一、使用 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 所示。
图 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,对于不同的用户也是不同的。
图 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 所示。
图 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 命令保存文件。
图 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 所示。
图 1-5。
Updating Ubuntu Package List
使用以下命令清除旧的存储库(如果存在)。
sudo apt-get purge lxc-docker*
图 1-6 中的输出表明旧包 lxc-docker 和 lxc-docker-virtual-package 没有安装,因此没有删除。
图 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。
图 1-7。
Using the Updated Repository verification
接下来,安装 Ubuntu 的必备组件,但是首先用下面的命令更新包管理器。
sudo apt-get update
包管理器得到更新,如图 1-8 所示。
图 1-8。
Updating the Package Manager
使用以下命令安装必备的 linux-image-extra 包。
sudo apt-get install linux-image-generic-lts-trusty
运行上述命令时,如果出现以下消息提示,请选择 Y。执行此操作后,将使用 281 MB 的额外磁盘空间。您想继续吗?【是/否】
信息提示如图 1-9 所示。
图 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 所示。
图 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 所示。
图 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]
图 1-12。
Message Prompt about the additional disk space being added
对接引擎的安装如图 1-13 所示。
图 1-13。
Installing the Docker Engine
使用以下命令启动 Docker 服务。
sudo service docker start
要验证 Docker 服务的状态,请运行以下命令。
sudo service docker status
前述命令的输出如图 1-14 所示。docker 引擎被指示为作为进程 2697 运行。
图 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 所示。
图 1-15。
Creating a Directory to install Kubernetes
将目录切换到/kubernetes 目录并启动 Docker 引擎。
cd /kubernetes
sudo service docker start
如果 Docker 引擎没有运行,它就会启动。图 1-16 显示 Docker 引擎已经运行。
图 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。
图 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 所示。
图 1-18。
Kernel Configuration Parameter
前面列出的大多数配置已经打开,如图 1-19 所示。未设置 CONFIG_MEMCG_SWAP_ENABLED 配置。
图 1-19。
Most of the Required Kernel Parameters are already Set
设置 CONFIG_MEMCG_SWAP_ENABLED = y,保存内核配置文件,如图 1-20 所示。
图 1-20。
Setting the CONFIG_MEMCG_SWAP_ENABLED Kernel Parameter
接下来,我们需要为内核添加对内存和交换记账的支持。提供给内核的命令行参数可以用下面的命令列出。
cat /proc/cmdline
如图 1-21 所示,内存和交换记账未打开。
图 1-21。
Listing the Command-Line Parameters
Grub 2 是 Ubuntu 的默认引导加载程序。要打开内存和交换记帐,请在 vi 编辑器中打开/etc/default/grub 文件。GRUB_CMDLINE_LINUX 设置为空字符串,如图 1-22 所示。
图 1-22。
The /etc/default/grub file
如下设置 GRUB_CMDLINE_LINU,这将在启动时启用内核中的内存和交换记帐。
GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"
修改后的/etc/default/grub 文件如图 1-23 所示。用:wq 命令保存文件。
图 1-23。
Modified /etc/default/grub file
使用以下命令更新 grub.cfg 文件。
sudo update-grub
grub 配置文件的生成如图 1-24 所示。
图 1-24。
Generating an Updated Grub Configuration file
重启系统。
sudo reboot
到 Ubuntu Amazon EC2 实例的连接被关闭,如图 1-25 所示。
图 1-25。
Rebooting Ubuntu Instance
SSH 重新登录到 Ubuntu 实例。重新运行命令以列出命令行内核参数。
cat /proc/cmdline
cgroup _ enable = memory swap account = 1 设置的输出如图 1-26 所示。
图 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 所示。
图 1-27。
Starting etcd
每次启动 Kubernetes 集群管理器时,都需要运行 docker run 命令来启动 etcd。后续启动 etcd 不需要下载如图 1-28 所示的容器镜像。
图 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 所示。
图 1-29。
The docker run Command to start Kubernetes Master
每次启动 Kubernetes 集群管理器时,都需要启动主服务器。仅在第一次运行命令时下载容器映像,在随后的运行中不下载映像,如图 1-30 所示。
图 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 所示。
图 1-31。
Starting the Service proxy
列出非库坞站容器
为 Kubernetes 集群管理器启动的 Docker 容器可以用下面的命令列出。
sudo docker ps
列出的 Docker 容器包括用于服务代理的容器;库伯莱的容器;用于 etcd 的容器;以及分别用于主调度器、控制器和 apiserver 的容器,并暂停如图 1-32 所示。
图 1-32。
Listing the Docker Containers
可以使用对接容器 id 找到对接容器信息。例如,获取运行控制器的 Docker 容器的容器 id,如图 1-33 所示。
图 1-33。
Obtaining the Docker Container Id
运行以下命令来查找 Docker 容器的详细信息。
sudo docker inspect 37971b53f2c1
诸如主 ip 和关于运行控制器管理器的 Docker 容器的细节得到如图 1-34 所示的输出。
图 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 所示。
图 1-35。
Installing Kubectl
通过应用+ x 权限使 kubectl 应用可执行。
sudo chmod +x kubectl
将 kubectl 二进制文件移动到/usr/local/bin/目录。
sudo mv kubi ctel/usr/local/bin/
前述命令的输出如图 1-36 所示。
图 1-36。
Moving and making kubectl Binaries executable
kubectl 命令列出了如图 1-37 所示的用法。
图 1-37。
Kubectl Command Usage
命令参数也被列出,如图 1-38 所示。
图 1-38。
Command Parameters for Kubectl
列表服务
以下命令应该列出 Kubernetes 服务。
kubectl get services
kubernetes 服务被列出,如图 1-39 所示。
图 1-39。
Listing the Kubernetes Service
列出节点
以下命令应该列出 Kubernetes 节点。
kubectl 获取节点
集群中的单个节点被列出,如图 1-40 所示。
图 1-40。
Listing the Nodes
测试 Kubernetes 安装
要测试 Kubernetes 集群管理器,使用以下命令运行 nginx 应用。
kubectl -s http://localhost:8080 run nginx --image=nginx --port=80
kubectl run 命令的输出列出了复制控制器、容器、映像/sm 选择器和副本,如图 1-41 所示。
图 1-41。
Running he nginx Application on Kubernetes Cluster
使用 kubectl expose 命令将 nginx 应用复制控制器作为服务公开。
kubectl expose rc nginx --port=80
nginx Kubernetes 服务在端口 80 上运行,如图 1-42 所示。
图 1-42。
Creating a Kubernetes Service for nginx Application
用 kubectl get svc 命令列出 nginx 服务的详细信息。
kubectl get svc nginx
nginx 服务详情如图 1-43 所示。
图 1-43。
Listing the Kubernetes Service nginx
可以使用以下命令获取集群 IP。
kubectl get svc nginx --template={{.spec.clusterIP}}
集群 ip 被列为 10.0.0.146,如图 1-44 所示。
图 1-44。
Listing the Cluster IP
可以使用以下命令调用 web 服务器来利用集群 ip。
curl 10.0.0.146
文本形式的 html 输出如图 1-45 所示。
图 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
运行。
图 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 标签相同的表达式。
图 2-2。
Creating an Application including a Replication Controller and Pod Replica/s
创建的复制控制器可以用以下命令列出。
kubectl get rc
hello-world
复制控制器列表如图 2-3 所示。
图 2-3。
Listing the Replication Controllers
使用以下命令列出创建和启动的 pod。
kubectl get pods
创建的单个 Pod 被列出,如图 2-4 所示。Pod 名称是自动分配的。会列出 Pod 状态“正在运行”,但 Pod 可能仍未就绪且不可用。“就绪”列值 0/1 表示 Pod 中的 1 个容器中有 0 个已就绪,这意味着 Pod 已创建并正在运行,但尚未就绪。Pod 可能需要几秒钟才能准备好。
图 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 个已经就绪。
图 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。
图 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 所示。
图 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。
图 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 所示。
图 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 名称相同。
图 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 所示。
图 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 个新的缩放副本中。
图 2-12。
Listing all the Pods as Running and Ready
使用以下命令描述hello-world
服务。
kubectl describe svc hello-world
如图 2-13 所示,列出服务名称、标签、选择器、类型、IP 和端点。可以使用各种 Pod 副本的端点来调用服务。
图 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 所示的应用输出。
图 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 所示的应用输出。
图 2-15。
Invoking the second Service Endpoint in a Local Browser
删除复制控制器
可以使用以下命令删除复制控制器hello-world
。
kubectl delete rc hello-world
复制控制器被删除,如图 2-16 所示。随后调用以下命令列出复制控制器。
图 2-16。
Deleting a Replication Controller
kubectl get rc
hello-world
复制控制器未列出,如图 2-16 所示。
删除复制控制器会删除复制控制器以及与复制控制器相关联的 pod,但不会删除代表复制控制器的服务。kubectl get services
命令仍然列出服务,如图 2-17 所示。
图 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
服务。
图 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 所示。
图 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 个已经就绪。
图 2-20。
Listing the Pods soon after creating the Pods
几秒钟后再次运行相同的命令。
kubectl get pods
hello-world
箱被列为“运行中”状态,就绪状态为“1/1”,这意味着箱中 1 个容器中的 1 个已经就绪,如图 2-21 所示。
图 2-21。
Listing the Pod as Ready and Running
使用以下命令描述hello-world
Pod。
kubectl describe pod hello-world
前面命令的输出如图 2-22 所示。
图 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 所示。
图 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 所示。
图 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
服务定义文件的主要映射是kind
、metadata
和spec
。kind
被设置为Service
以指示 Kubernetes 服务。标签app
和name
构成了元数据。spec
映射包括名为http
的端口 80 的ports
映射。可选地,可以设置一个targetPort
,默认为与端口相同的值。selector
是spec
中的主映射,指定了用于选择通过服务公开的 pod 的映射。app:hello-world
选择器意味着所有标签为app=hello-world
的 pod 被选中。定义文件可以在 vi 编辑器中创建,并用:wq
命令保存,如图 2-25 所示。
图 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 所示。
图 2-26。
Creating the hello-world Service using the Definition File
使用以下命令列出服务。
kubectl get services
除了kubernetes
服务外,还列出了hello-world
服务,如图 2-27 所示。
图 2-27。
Listing the hello-world Service
用下面的命令描述hello-world
服务。
kubectl describe svc hello-world
列出服务名、名称空间、标签、选择器、类型、Ip,如图 2-28 所示。因为使用 Pod 定义文件创建的hello-world
Pod 不包含与服务选择器匹配的标签,所以它不由服务管理。由于hello-world
服务没有管理任何 pod,因此没有列出端点。
图 2-28。
Describing the hello-world Service
创建复制控制器定义
接下来,我们将创建一个复制控制器,并将复制控制器标记为与之前创建的服务选择器相匹配。创建服务定义文件hello-rc.yaml
。复制控制器的种类映射是ReplicationController
。spec
映射中的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。
图 2-29。
Creating a Replication Controller
使用以下命令列出使用复制控制器创建的 pod。
kubectl get pods
从定义文件创建的两个 pod 被列出,如图 2-30 所示。创建了 Pod 定义文件的 Pod 也会列出,但不会与复制控制器相关联。最初,一些或所有新的吊舱可能被列为未准备好,如图 2-30 中一个吊舱的准备好列中的 0/1 值所示。
图 2-30。
Listing the Pods soon after creating a Replication Controller
几秒钟后再次调用相同的命令来列出窗格。
kubectl get pods
如图 2-31 所示,所有吊舱被列为就绪- > 1/1 并正在运行。
图 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。
图 2-32。
Describing the Service hello-world
前面所有创建hello-world
复制控制器的命令,列出了它与图 2-33 中所示的hello-world
服务的关联。
图 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 所示的输出。
图 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 所示。
图 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 输出。
图 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 输出。
图 2-37。
Invoking another Service Endpoint in a Browser
扩展应用
例如,要将hello-world
复制控制器扩展到 6 个副本,请运行下面的kubectl scale
命令。
kubectl scale rc hello-world --replicas=6
如图 2-38 所示的“缩放”输出表示复制控制器已被缩放。
图 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
复制控制器没有关联,因为它不包含与复制控制器中的选择器标签(与模板标签相同)相匹配的标签。
图 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。
图 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 所示。
图 2-41。
Service Definition File in JSON Format
删除之前创建的hello-world
服务和hello-world
复制控制器。运行以下命令,从 JSON 格式定义文件创建服务。
kubectl create –f hello-world-service.json
hello-world
服务被创建,如图 2-42 所示。
图 2-42。
Creating a Service from the JSON Definition File
随后列出所有的 Kubernetes 服务。
kubectl get services
hello-world
服务列表如图 2-43 所示。
图 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 所示。
图 2-44。
Creating the hello-rc.json File in vi Editor
删除所有以前创建的 pod 和复制控制器。运行以下命令来创建hello-world
复制控制器。
kubectl create –f hello-rc.json
如图 2-45 所示创建hello-world
复制控制器。随后运行以下命令列出复制控制器。
图 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 所示。
图 2-46。
Describing the hello-world Service
使用 curl 命令调用服务端点,如下所示。
curl 172.17.0.2
curl 命令的 HTML 输出如图 2-47 所示。
图 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 所示。
图 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 定义中的容器映像指定,以覆盖默认设置ENTRYPOINT
和CMD
。我们将在本章中讨论这些字段。我们还将讨论在 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 正在运行。
图 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
中的ENTRYPOINT
和CMD
指令。
Pod 定义中的命令和参数字段
Kubernetes 可以覆盖 Dockerfile 文件中指定的ENTRYPOINT
(命令)和CMD
(参数)指令。Pod 定义文件中的两个字段映射可用于覆盖ENTRYPOINT
和CMD
指令。这些字段是“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
参数。我们将从使用默认的ENTRYPOINT
和CMD
指令开始。
使用 Docker 映像中的默认入口点和 CMD
Ubuntu 镜像的Dockerfile
不提供ENTRYPOINT
指令,但是CMD
指令被设置为CMD ["/bin/bash"]
。在本节的示例中,我们将创建一个不覆盖 Docker 映像中的ENTRYPOINT
或CMD
指令的 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 所示。
图 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 所示。运行以下命令列出窗格。
图 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 所示。
图 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 所示。
图 3-5。
No output generated with Default CMD [“/bin/bash”] in “ubuntu” Docker Image
覆盖入口点和 CMD
在第二个例子中,我们将使用 Pod 定义文件中的Command
和Args
映射来覆盖Dockerfile
中的ENTRYPOINT
和CMD
。结合使用ENTRYPOINT
和 CMD 将有助于我们为映像指定默认的可执行文件,并且它还将为该可执行文件提供默认的参数。环境变量替换用于带有$(VARIABLE_NAME)
语法的MESSAGE1
和MESSAGE2
环境变量。
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 所示。
图 3-6。
Modifying env.yaml in a vi Editor
首先,我们需要用下面的命令删除第一个例子中创建的hello-world
pod。
kubectl delete pod hello-world
hello-world
pod 被删除,如图 3-7 所示。
图 3-7。
Deleting the hello-world Pod
运行kubectl create
命令,从定义文件env.yaml
创建一个 Pod。
kubectl create –f env.yaml
hello-world
Pod 被创建,如图 3-8 所示。
图 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
。
图 3-9。
Listing the Pods with transitioning STATUS value
运行以下命令列出 Pod 的输出。
kubectl logs hello-world
使用替换从环境变量MESSAGE1
和MESSAGE2
创建的消息如图 3-10 所示。
图 3-10。
Outputting Message Generated from Environment Variables using Value Substitution
在命令映射中指定可执行文件和参数
在第三个示例中,指定可执行文件和参数都在 Pod 定义文件的命令映射中指定。环境变量替换用于MESSAGE1
和MESSAGE2
环境变量。如果使用了环境变量语法$(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 所示。
图 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。
图 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
环境变量MESSAGE1
和MESSAGE2
创建的消息被列出,如图 3-13 所示。
图 3-13。
Message output by Pod created in Figure 3-12
指定 Args 映射中的可执行文件和参数
在第四个例子中,指定可执行文件和 Pod 定义文件中的Args
映射中的参数,作为覆盖Dockerfile
中的CMD
指令的结果。环境变量替换用于环境变量语法为$(VARIABLE_NAME)
的MESSAGE1
和MESSAGE2
环境变量。
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 所示。
图 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 所示的错误。
图 3-15。
Error Generated if hello-world Pod already exists
运行kubectl create
命令,从定义文件env.yaml
创建一个 Pod。
kubectl create –f env.yaml
该命令的输出如图 3-16 所示。
图 3-16。
Creating a Pod from definition file in Figure 3-14
hello-world
pod 被创建,如图 3-17 所示。运行kubectl get
命令列出 pod。
图 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
用MESSAGE1
和MESSAGE2
的环境变量替换创建的消息被列出,如图 3-18 所示。
图 3-18。
Outputting the Message Generated by Pod
摘要
在本章中,我们讨论了 Docker 映像Dockerfile
中的ENTRYPOINT
和CMD
指令:当映像在 Kubernetes Pod 中运行时,这些指令用于运行带有默认参数的默认命令。我们还讨论了 Pod 定义文件中的Command
和Args
映射,它们可以用来覆盖ENTRYPOINT
和CMD
指令。我们讨论了用 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 所示。
图 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 所示。
图 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 所示。
图 4-3。
Creating a Service for MySQL Database
使用以下命令列出服务。
kubectl get services
mysql
服务列表如图 4-4 所示。
图 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_PASSWORD
为root
用户设置密码。环境变量通过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 所示。
图 4-5。
Definition File for Replication Controller
用kubectl create
命令从服务定义文件创建一个复制控制器。
kubectl create -f mysql-rc.yaml
如图 4-6 中的输出所示,mysql
复制控制器被创建。
图 4-6。
Creating a Replication Controller for MySQL Database
使用以下命令列出复制。
kubectl get rc
mysql
复制控制器包括容器名、映像名、选择器表达式(app=mysql-app)和副本数量,如图 4-7 所示。
图 4-7。
Listing the MySQL Replication Controller
要描述mysql
复制控制器,运行以下命令。
kubectl describe rc mysql
复制控制器名称、命名空间、映像、选择器、标签、副本、pod 状态和事件会被列出,如图 4-8 所示。
图 4-8。
Describing the MySQL Replication Controller
列出 POD
可以使用以下命令列出创建的 pod。
kubectl get pods
如图 4-9 所示,复制控制器创建的 2 个副本被列出。最初,pod 可能不会被列为就绪 1/1。几秒钟后运行前面的命令,如果需要可以多次运行,以列出所有准备就绪的单元。
图 4-9。
Listing the Pod/s for MySQL Database
列出日志
使用以下命令列出一个 pod 的 Pod 日志:例如,mysql-wuo7x
pod。
kubectl logs mysql-wuo7x
Pod 日志列表如图 4-10 所示。
图 4-10。
Listing the Logs generated by the Pod for MySQL Database
如图 4-11 所示,MySQL 服务器被列为已启动并“准备连接”。
图 4-11。
Listing mysqld as Ready for Connections
描述服务
要描述mysql
服务,请运行以下命令。
kubectl describe svc mysql
服务名称、命名空间、标签、选择器、类型、Ip、端口和端点都会列出。因为副本数量设置为 1,所以仅列出一个端点,如图 4-12 所示。
图 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 容器。
图 4-13。
Listing the Docker Containers
使用前面命令输出中的 Docker 容器 id,启动一个交互式 shell。
sudo docker exec -it 526f5d5f6c2e bash
交互式 shell 或 tty 启动,如图 4-14 所示。
图 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 所示。
图 4-15。
Starting the MySQL CLI Shell
使用以下命令列出数据库。
show databases;
图 4-16 中显示的默认数据库包括"mysql"
数据库,我们将用它来创建一个数据库表。其他数据库是系统数据库,不应用于用户表。
图 4-16。
Listing the Databases
使用以下命令将数据库“mysql”设置为当前数据库。
use mysql
如图 4-17 中的“数据库已更改”输出所示,数据库被设置为mysql
。
图 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 所示。
图 4-18。
Creating a MySQL Database Table
随后运行以下 SQL 语句来查询数据库表Catalog
。
SELECT * FROM Catalog;
添加的单行数据被列出,如图 4-19 所示。
图 4-19。
Querying the Database Table
退出 MySQL CLI 和交互式 Shell
使用“quit”命令退出 MySQL CLI。
quit
使用“退出”命令退出交互终端。
exit
前面命令的输出如图 4-20 所示。
图 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 的状态必须是“正在运行”才能被视为可用。
图 4-21。
Scaling the Pod Replicas to Four
要描述mysql
服务,运行以下命令。
kubectl describe svc mysql
服务描述与之前相同,只是端点的数量增加到了 4 个,如图 4-22 所示。
图 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/服务/复制控制器。
图 4-23。
Deleting the Replication Controller
随后运行以下命令来获取复制控制器。mysql
rc 未列出,如图 4-24 所示。
图 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 提供了几个新特性,比如支持UPSERT
、BRIN
索引、更快的排序,以及用于获取大型表的统计样本的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 所示。
图 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 应显示为“正在运行”。
图 5-2。
Starting Docker
使用以下命令列出服务。
kubectl get services
kubernetes 服务应该被列出,如图 5-3 所示。
图 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 所示。
图 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
表达式相匹配。
图 5-5。
Creating a Service and listing the Service
用下面的命令描述服务postgres
。
kubectl describe svc postgres
服务名、名称空间、标签、选择器、类型、IP 地址、公开的端口和端点都会列出。因为没有 Pods 最初与服务相关联,所以没有列出端点,如图 5-6 所示。
图 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 所示。
图 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。
图 5-8。
Creating and listing the Replication Controller for PostgreSQL Database
用下面的命令描述复制控制器postgres
。
kubectl describe rc postgres
复制控制器的名称、命名空间、与 rc 相关联的映像、选择器(如果有)、标签、副本数量、pod 状态和事件会被列出,如图 5-9 所示。
图 5-9。
Describing the Replication Controller for PostgreSQL Database
拿到 POD
要获取并列出窗格,请运行以下命令。
kubectl get pods
由复制控制器创建的两个 pod 被列出,如图 5-10 所示。pod 应处于运行状态,并且就绪列值为 1/1。
图 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。
图 5-11。
Listing the Docker Containers
使用容器 id 启动交互式 shell。
sudo docker exec -it a786960b2cb6 bash
交互外壳启动,如图 5-12 所示。
图 5-12。
Starting an Interactive Shell
启动 PostgreSQL SQL 终端
接下来,为 PostgreSQL 启动 psql SQL shell。将用户设置为postgres
。
su –l postgres
使用以下命令启动 psql 命令行 shell。
psql postgres
psql 应如图 5-13 所示启动。
图 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 所示。
图 5-14。
Creating a Database Table
运行以下 SQL 语句来查询数据库表wlslog
。
SELECT * FROM wlslog;
添加的 3 行数据被列出,如图 5-15 所示。
图 5-15。
Querying the Database Table
退出交互式命令外壳
要退出 psql shell,请运行以下命令。
\q
要退出交互式终端,请运行以下命令。
exit
psql 外壳和交互外壳退出,如图 5-16 所示。
图 5-16。
Exiting the psql Shell and Docker Container Interactive Shell
扩展 PostgreSQL 集群
Kubernetes 集群管理器的主要优点之一是能够根据需要扩展集群。最初,我们创建了两个副本。例如,要将 PostgreSQL 实例的数量增加到 4 个,请运行以下命令。
kubectl scale rc postgres --replicas=4
前一个命令的“scaled”输出表明集群已经被缩放,如图 5-17 所示。
图 5-17。
Scaling the number of Pod Replicas to 4
随后使用以下命令列出 pod。
kubectl get pods
如图 5-18 所示,列出 4 个吊舱。最初,一些容器可能被列为未“运行”和/或未处于就绪(1/1)状态。
图 5-18。
Listing the Pods after Scaling
几秒钟后再次运行前面的命令。
kubectl get pods
如图 5-19 所示,添加到集群中的新单元也被列为“正在运行”并处于就绪状态 1/1。
图 5-19。
Listing all the Pods as running and ready
再次描述一下postgres
服务。
kubectl describe svc postgres
最初,当服务最初启动时,没有端点被列为与服务相关联。4 个 pod 运行时,列出 4 个端点,如图 5-20 所示。
图 5-20。
Describing the postgres Service
列出日志
要列出 Pod 的日志数据,例如 postgres-v0k42 Pod,请运行以下命令。
kubectl logs postgres-v0k42
图 5-21 中的输出列出了 PostgreSQL 启动。
图 5-21。
Listing the Logs for a Pod running PostgreSQL Database
当 PostgreSQL 数据库完全启动时,“数据库系统已准备好接受连接”的消息会输出,如图 5-22 所示。
图 5-22。
PostgreSQL Database listed as Started and subsequently Shutdown in the Logs
删除复制控制器
要删除复制控制器postgres
并因此删除由复制控制器管理的所有 pod,请运行以下命令。
kubectl delete rc postgres
postgres
复制控制器被删除,如图 5-23 中的replicationcontrollers/postgres
输出所示。随后,运行以下命令列出复制控制器。
图 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 所示。
图 5-24。
Stopping the postgres Service
强制创建 PostgreSQL 集群
对定义文件使用声明性方法可以更好地控制服务和复制控制器。但是复制控制器和服务也可以在命令行上用kubectl
命令创建。在下面的小节中,我们将创建一个复制控制器和一个服务。
创建复制控制器
要为映像“postgres”创建名为postgres
的复制控制器,副本数量为 2,Post as 为 5432,请运行以下命令。
kubectl run postgres --image=postgres --replicas=2 --port=5432
带有映像postgres
和selector
表情run=postgres
的 Pod 的 2 个副本的postgres
复制控制器被创建,如图 5-25 所示。
图 5-25。
Creating a Replication Controller Imperatively
使用以下命令列出复制控制器。
kubectl get rc
postgres
复制控制器列表如图 5-26 所示。
图 5-26。
Listing the Replication Controllers
拿到 POD
要列出由复制控制器管理的 pod,请运行以下命令。
kubectl get pods
如图 5-27 所示,两个吊舱被列出。最初,一些 pod 可能被列为未就绪,如 0/1 就绪列值所示。再次运行前面的命令,列出就绪列值为 1/1 的窗格。
图 5-27。
Listing the Pods
创建服务
要创建服务,我们需要运行kubectl expose
命令。最初只有kubernetes
服务在运行。要进行演示,请运行以下命令。
kubectl get services
如图 5-28 所示,只列出了kubernetes
服务。
图 5-28。
Listing the “kubernetes” Service
要为复制控制器"postgres"
创建服务,请运行以下命令,其中–port
参数指定服务公开的端口。服务类型设置为LoadBalancer
。
kubectl expose rc postgres --port=5432 --type=LoadBalancer
随后列出服务。
kubectl get services
postgres 服务被列出,如图 5-29 所示。
图 5-29。
Creating a Service exposed at Port 5432
创建数据库表
创建数据库表的过程与前面针对声明性部分所讨论的过程相同,在本部分中只简单讨论一下。用下面的命令列出 Docker 容器。
sudo docker ps
如图 5-30 所示,其中两个 Docker 容器的映像列为postgres
。从容器 id 列中复制这些列之一的容器 ID。
图 5-30。
Listing the Docker Containers
使用以下命令启动交互式 shell。
sudo docker exec -it af0ac629b0e7d bash
交互终端启动,如图 5-31 所示。
图 5-31。
Starting the TTY
将用户设置为postgres
。
su –l postgres
启动psql
命令行外壳。
psql postgres
psql
壳体如图 5-32 所示。
图 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 所示。
图 5-33。
Creating a Database Table
运行以下 SQL 语句来查询wlslog
表。
SELECT * FROM wlslog;
添加的三行数据被列出,如图 5-34 所示。
图 5-34。
Querying the wlslog Database Table
要退出运行 PostgreSQL 的 Docker 容器的psql
shell 和交互式 shell,请运行以下命令。
\q
exit
psql shell 和 tty 退出,如图 5-35 所示。
图 5-35。
Exiting the Shells
扩展 PostgreSQL 集群
最初创建集群时,我们将副本数设置为 2。如下列出 pod。
kubectl get pods
仅列出两个吊舱,如图 5-36 所示。
图 5-36。
Listing the Pods
使用以下命令将集群扩展到 4 个副本。
kubectl scale rc postgres --replicas=4
如图 5-37 所示的“已缩放”输出表明该集群已被缩放。
图 5-37。
Scaling the Pod Replicas to 4
随后列出 POD。
kubectl get pods
如图 5-38 所示,前面的命令可能需要运行多次才能将所有的 pod 列为“运行中”并处于就绪状态 1/1。
图 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
服务仍然被列出。
图 5-39。
Deleting the Replication Controller
停止服务
要停止该服务,请运行以下命令。
kubectl stop service postgres
postgres
服务停止,如图 5-40 所示。随后运行以下命令。
图 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 中显示对接器正在运行。
图 6-1。
Starting Docker and verifying its Status
列出正在运行的服务。
kubectl get services
在图 6-2 中,只有kubernetes
服务被列为正在运行。
图 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
。
图 6-3。
Creating a Replication Controller and Pod Replicas for Oracle Database
使用以下命令列出复制控制器。
kubectl get rc
图 6-4 所示的oradb
复制控制器上市。
图 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)。
图 6-5。
Listing the Pods in various stages of running
使用以下命令获取节点。
kubectl get nodes
并使用下面的命令获得 Kubernetes 服务。
kubectl get services
只有kubernetes
服务被列出,如图 6-6 所示,因为我们还没有为 Oracle 数据库创建服务。
图 6-6。
Creating a Replication Controller does not create a Service
列出日志
使用以下命令列出其中一个 pod 的日志。
kubectl logs oradb-ea57r
由一个已启动的 Oracle 数据库实例生成的日志得到如图 6-7 所示的输出。Oracle Net 监听程序显示为已启动。
图 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,它与复制控制器选择器相同。
图 6-8。
Creating a Service Imperatively
用下面的命令描述服务。
kubectl describe svc oradb
服务名称、名称空间、标签、选择器、类型、IP、端口、节点端口和端点被列出,如图 6-9 所示。
图 6-9。
Describing the oradb Service
扩展数据库
运行kubectl scale
命令来缩放副本。例如,将副本数量减少到 1。
kubectl scale rc oradb --replicas=1
“已缩放”的输出表示复制品已被缩放,如图 6-10 所示。
图 6-10。
Scaling the Replicas to 1
随后列出正在运行的 pod。
kubectl get pods
仅列出一个 Oracle 数据库 Pod,因为另一个已停止,以将复制级别降至一级,如图 6-11 所示。随后,描述服务。
图 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 所示。
图 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 所示。
图 6-13。
Pod Definition File
使用定义文件oradb.yaml
和kubectl create
命令创建一个 Pod。
kubectl create -f oradb.yaml --validate
图 6-14 中“Pod/oradb”的输出表明oradb
Pod 已经创建。
图 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 列为正在运行和就绪。
图 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 所示。
图 6-16。
Service Definition File
运行以下命令从服务定义文件创建服务。
kubectl create -f oradb-service.yaml
如图 6-17 中的“服务/oradb”输出所示,oradb
服务被创建。随后列出服务。
图 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。在下一节中,我们将创建一个带有匹配标签的复制控制器。
图 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 所示。
图 6-19。
Replication Controller Definition File
接下来,运行下面的命令,从定义文件oradb-rc.yaml
创建一个复制控制器。
kubectl create -f oradb-rc.yaml
复制控制器的创建如图 6-20 所示。使用以下命令列出复制控制器。
图 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 定义文件提前启动。
图 6-21。
Listing the Pod Replicas
用下面的命令描述服务oradb
。
kubectl describe svc oradb
服务端点被列出,如图 6-22 所示。只列出了两个端点,因为服务选择器应用:“oradb”与复制控制器中的 Pod 标签匹配,有两个副本。先前创建的 Pod 不包含与选择器表达式匹配的标签。
图 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。
图 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 中列出。
图 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 的三个副本。
图 6-25。
Scaling the Cluster to 3 Replicas
再次描述服务。
kubectl describe svc oradb
如图 6-26 所示,列出了三个端点,而不是两个。该服务只有一个 IP 地址。
图 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 所示。
图 6-27。
Copying the Container Id for a Docker Container
使用容器 id,通过以下命令启动一个交互式 shell。
sudo docker exec -it 9f74a82d4ea0 bash
交互外壳启动,如图 6-28 所示。
图 6-28。
Starting an Interactive Shell
连接到数据库
在交互式 tty 中,将用户改为“oracle”
su -l oracle
su oracle
和su - oracle
的区别在于,后者使用oracle
用户的环境变量登录,并将当前目录设置为 oracle 主目录,而前者使用oracle
登录,但环境变量和当前目录保持不变。
随后启动 SQL*Plus。使用/nolog
选项不会建立与数据库的初始连接。
sqlplus /nolog
运行以下命令将SYS
连接为SYSDBA
。
CONNECT SYS AS SYSDBA
出现提示时,将密码指定为“oracle”。启动 SQL*Plus 和连接SYS
的上述命令的输出如图 6-29 所示。建立了一个连接。
图 6-29。
Starting SQL*Plus
创建用户
要创建一个名为 OE 的用户,并向该用户授予CONNECT
和RESOURCE
角色,请运行以下命令。
CREATE USER OE QUOTA UNLIMITED ON SYSTEM IDENTIFIED BY OE;
GRANT CONNECT, RESOURCE TO OE;
用户OE
被创建,角色被授予,如图 6-30 所示。
图 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 所示。
图 6-31。
Creating a Database Table
运行以下 SQL 语句来查询OE.CATALOG
表。
SELECT * FROM OE.CATALOG;
添加的单行数据被列出,如图 6-32 所示。
图 6-32。
Querying the Database Table
退出交互式外壳
使用“退出”命令退出 SQL*Plus 命令,使用“退出”命令退出“oracle”用户,使用“退出”命令退出交互终端,也如图 6-33 所示。
图 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 所示。
图 7-1。
Logging into Ubuntu Instance on Amazon EC2
第一章讨论了安装程序。要验证 Docker 是否正在运行,请运行以下命令。
sudo service docker start
Docker 应被列为运行中,如图 7-2 所示。
图 7-2。
Starting Docker
使用以下命令列出 pod。
kubectl get pods
并使用以下命令列出节点。
kubectl get nodes
Kubernetes Pod 被列出,节点也被列出,如图 7-3 所示。
图 7-3。
Listing Kubernetes Pod and the single Node
要列出服务,请运行以下命令。
kubectl get services
“kubernetes”服务被列出,如图 7-4 所示。
图 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 所示。
图 7-5。
Service Definition File in vi Editor
默认服务类型是ClusterIp
,它仅使用集群内部 IP。如图 7-6 所示,可以将类型设置为LoadBalancer
,以便在集群中的每个节点上公开服务,并请求云提供商提供负载均衡器。
图 7-6。
Setting the Service Type
要从定义文件创建服务,请运行以下命令。
kubectl create -f mongo-service.yaml
使用以下命令列出服务。
kubectl get services
mongo
服务列表如图 7-7 所示。
图 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 所示。
图 7-8。
Replication Controller Definition File
若要从定义文件创建复制控制器,请运行以下命令。
kubectl create -f mongo-rc.yaml
mongo-rc
复制控制器被创建,如图 7-9 所示。
图 7-9。
Creating the Replication Controller
运行以下命令列出复制容器。
kubectl get rc
mongo-rc
复制控制器列表如图 7-10 所示。
图 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/db
为mongo-storage
卷添加了一个卷挂载。在容器内,可以在/mongo/data/db
访问卷。例如,在一个交互终端中为一个容器把目录(cd)改为/mongo/data/db
目录。
cd /mongo/data/db
列出/mongo/data/db
目录中的文件和目录。
ls -l
该目录是空的,因为它最初应该如图 7-11 所示。
图 7-11。
Empty Directory
不要将该卷与 MongoDB 服务器的数据目录混淆。默认情况下,数据目录在/data/db
创建,并在运行 MongoDB 服务器实例的每个 Docker 容器中创建。/mongo/data/db
是所有 Docker 容器共有的,而/data/db
存在于每个 Docker 容器中。
列出日志
启动复制控制器后,使用以下命令列出 pod。
kubectl get pods
如图 7-12 所示,两个吊舱被列出。
图 7-12。
Listing the Pods
可以使用以下命令列出 Pod 的日志,例如,mongo-rc-4t43s
Pod。
kubectl logs mongo-rc-4t43s
Pod 日志显示 MongoDB 服务器启动,如图 7-13 所示。
图 7-13。
Listing the Pod Logs
当 MongoDB 服务器启动时,输出消息“等待端口 27017 上的连接”,如图 7-14 所示。
图 7-14。
MongoDB Running on Port 27017
启动 Docker 容器的交互式外壳
在这一节中,我们将为 MongoDB 服务器启动一个交互式终端或 bash shell,为此我们需要运行 MongoDB 服务器的 Docker 容器的容器 id。列出 Docker 容器。
sudo docker ps
复制映像为“mongo”的容器的容器 id,如图 7-15 所示。
图 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 所示,启动一个交互式外壳。
图 7-16。
Starting an Interactive Shell
启动 Mongo Shell
用下面的命令启动 Mongo shell。
mongo
Mongo shell 启动如图 7-17 所示。
图 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 所示。要列出集合,请运行以下命令。
图 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
集合中的文档。
图 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 所示。
图 7-20。
Documents doc1 and doc2
要将文档添加到catalog
集合,请运行以下命令。
db.catalog.insert([doc1, doc2], { writeConcern: { w: "majority", wtimeout: 5000 }, ordered:true })
如图 7-21 中 JSON 结果的nInserted
字段所示,文件被添加。
图 7-21。
Adding Documents
查找文档
要查询目录,调用find()
方法。要列出catalog
集合中的所有文档,运行以下命令。
db.catalog.find()
添加的两个文件列表如图 7-22 所示。对于其中一个文档,会自动生成_id
字段。
图 7-22。
Finding Documents
查找单个文档
要从catalog
集合中找到一个文档,运行下面的命令来调用findOne()
方法。
db.catalog.findOne()
单个文档被列出,如图 7-23 所示。
图 7-23。
Finding a Single Document
在单个文档中查找特定字段
例如,要仅从单个文档中获取特定字段edition, title
和author
,请运行以下命令。
db.catalog.findOne(
{ },
{ edition: 1, title: 1, author: 1 }
)
只列出单个文档中的特定字段,如图 7-24 所示。_id
字段总是被列出。
图 7-24。
Finding Selected Fields in a Document
删除收藏
要删除catalog
集合,请运行以下命令。
db.catalog.drop()
随后使用以下命令列出集合。
show collections
catalog
集合没有被列出,只有catalog_capped
集合被列出,如图 7-25 所示。
图 7-25。
Dropping the catalog Collection
退出 Mongo Shell 和交互式 Shell
要退出 Mongo shell,运行以下命令。
exit
要退出交互式终端,请运行以下命令。
exit
Mongo shell 和交互终端退出,如图 7-26 所示。
图 7-26。
Exiting the Shells
扩展集群
要扩展 Mongo 集群,运行kubectl scale
命令。例如,以下命令将群集扩展到 4 个复制副本。
kubectl scale rc mongo --replicas=4
如图 7-27 所示的“缩放”输出将集群缩放至 4 个副本。
图 7-27。
Scaling a Replication Controller
缩放后列出窗格。
kubectl get pods
四个 POD 被列出。最初,一些容器可能被列为未就绪(1/1)状态。多次运行上述命令,列出所有正在运行并准备就绪的吊舱,如图 7-28 所示。
图 7-28。
Listing the Pods after Scaling
删除复制控制器
要删除复制控制器mongo-rc
,请运行以下命令。
kubectl delete replicationcontroller mongo-rc
由复制控制器管理的所有 pod 也会被删除。随后运行以下命令来列出窗格。
kubectl get pods
mongo
吊舱不会如图 7-29 所示列出。
图 7-29。
Deleting a Replication Controller
删除服务
要删除名为mongo
的服务,运行以下命令。
kubectl delete service mongo
mongo
服务未列出,如图 7-30 所示。
图 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 所示。
图 7-31。
Creating a Replication Controller from a Definition File
使用以下命令列出 pod。
kubectl get pods
两个复制副本中只有一个列为正在运行和就绪(1/1)。即使前面的命令运行多次,也只有一个副本被列为正在运行,如图 7-32 所示。
图 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 所示。
图 7-33。
Scaling the Replication Controller to 4 Replicas
即使单个运行的 Pod 停止,也只有一个新的 Pod 启动。要进行演示,请停止单个运行的 Pod。
kubectl stop pod mongo-rc-laqpl
该单元被移除,但会创建一个替换单元来保持复制级别 1,如图 7-34 所示。
图 7-34。
Another Pod gets created when the single running Pod is stopped
几秒钟后再次列出 Pod,只有一个 Pod 被列出,如图 7-35 所示。
图 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 所示。
图 7-36。
Creating a Replication Controller Imperatively
使用以下命令列出 pod。
kubectl get rc
mongo
-rc 列表如图 7-37 所示。
图 7-37。
Listing the Replication Controllers
列出 POD
使用以下命令列出 pod。
kubectl get pods
为 MongoDB get 启动的两个 Pods 列表如图 7-38 所示。最初,pod 可能会被列为未运行。
图 7-38。
Listing the Pods with some of the pods not Running yet
如图 7-39 所示,如果需要将 pod 列为正在运行,请多次运行以下程序。
图 7-39。
Listing all the Pods as Running
列出日志
使用以下命令列出 Pod 的日志。mongo-56850
是 Pod 名称。
kubectl logs mongo-56850
Pod 日志列表如图 7-40 所示。
图 7-40。
Listing Pod Logs
MongoDB 被列为已启动,如图 7-41 所示。在服务器上运行的命令也会得到输出。
图 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 所示。
图 7-42。
Creating a Service Imperatively
使用以下命令列出服务。
kubectl get services
在图 7-43 中mongo
服务被列为正在运行。
图 7-43。
Listing the Services including the mongo Service
交互式终端和 Mongo shell 可以开始创建 MongoDB 数据库和集合,以便在集合中添加和查询文档,正如在以声明方式创建 MongoDB 集群时所讨论的那样。
扩展集群
例如,要将群集扩展到 4 个副本,请运行以下命令。
kubectl scale rc mongo --replicas=4
输出“scaled”表示集群已被缩放,如图 7-44 所示。
图 7-44。
Scaling the Cluster created Imperatively
随后得到 POD。
kubectl get pods
列出四个吊舱,如图 7-45 所示。最初,一些 pod 可能显示为未运行或就绪。
图 7-45。
Listing Pods after Scaling
要描述mongo
服务,请运行以下命令。
kubectl describe svc mongo
除了服务端点之外,服务描述还包括服务标签、选择器,如图 7-46 所示,四个 pod 各有一个。
图 7-46。
Describing the Service mongo after Scaling
删除服务和复制控制器
可以使用以下命令删除mongo
服务和mongo
复制控制器。
kubectl delete service mongo
kubectl delete rc mongo
“mongo”服务和“mongo”复制控制器被删除,如图 7-47 所示。删除一个不会删除另一个;复制控制器与服务的分离是一个适合于发展一个而不必修改另一个的特性。
图 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 所示运行。
图 8-1。
Starting Docker
列出服务。
kubectl
get services
应列出“kubernetes”服务,如图 8-2 所示。
图 8-2。
Listing the “kubernetes” Service
使用以下命令列出窗格和节点。
kubectl get pods
kubectl get nodes
最初,唯一运行的 pod 是 Kubernetes pod,如图 8-3 所示。
图 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 所示。
图 8-4。
Service Definition File in vi Editor
要创建服务,请运行以下命令。
kubectl create -f cassandra-service.yaml
随后列出服务。
kubectl get services
cassandra
服务列表如图 8-5 所示。
图 8-5。
Creating and listing a Service for Apache Cassandra
用下面的命令描述cassandra
服务。
kubectl describe svc cassandra
服务名称、名称空间、标签、选择器、类型、IP、端口、节点端口和端点被列出,如图 8-6 所示。最初没有列出服务端点,因为尚未创建 Pod。
图 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 所示。
图 8-7。
Replication Controller Definition File in vi Editor
使用以下命令创建一个复制控制器。
kubectl create -f cassandra-rc.yaml
随后列出复制控制器。
kubectl get rc
cassandra-rc
复制控制器被创建并列出,如图 8-8 所示。
图 8-8。
Creating a Replication Controller from Definition File
列出由复制控制器创建的窗格。
kubectl get pods
当复制控制器定义文件中的副本数量设置为 1 时,会创建一个 Pod,并在图 8-9 中列出。前面的命令可能需要运行多次才能将 Pod 列为正在运行和就绪。或者,在创建复制控制器几秒钟后第一次运行该命令;到一分钟时,所有的吊舱都应该已经启动了。
图 8-9。
Listing Pod/s for Apache Cassandra
描述一下卡珊德拉服务。
kubectl describe svc cassandra
为 Pod 列出一个端点,如图 8-10 所示。当在创建复制控制器之前列出服务描述时,没有列出任何端点。
图 8-10。
Describing the Service after creating the Replication Controller
在前面的示例中,我们创建了一个复制控制器,副本数量设置为 1。复制控制器不必一开始就创建副本。为了进行演示,我们将再次创建复制控制器,但使用不同的副本设置。删除先前创建的复制控制器。
kubectl delete rc cassandra-rc
修改cassandra-rc.yaml
将副本字段设置为 0,如图 8-11 所示。
图 8-11。
Setting Replicas to 0
使用修改后的定义文件再次创建复制控制器。
kubectl create -f cassandra-rc.yaml
随后列出副本。
kubectl get rc
cassandra-rc
复制控制器被创建并列出,如图 8-12 所示。
图 8-12。
Creating the Replication Controller with Modified Definition File
列出 POD。
kubectl get pods
因为副本字段被设置为 0,所以副本被列为 0,如图 8-13 所示。
图 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 可能需要一段时间(几秒钟)才能启动并准备就绪。
图 8-14。
Scaling the Replication Controller to 1 Pod
再次描述一下cassandra
服务。
kubectl describe svc cassandra
如图 8-15 所示,添加的 Pod 应列出一个端点。
图 8-15。
Describing the Service after Scaling the Cluster
描述 Pod
要描述 Pod,请运行以下命令。
kubectl describe pod cassandra-rc-tou4u
输出有关 Pod 的详细信息,如名称、名称空间、映像、节点、标签、状态、IP 地址和事件,如图 8-16 所示。Pod 标签是复制控制器定义文件中指定的app=cassandra
。
图 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。
图 8-17。
Listing the Docker Containers
使用容器 id 启动一个交互式 bash shell。
sudo docker exec -it e8fc5e8ddff57 bash
如图 8-18 所示,启动一个交互式外壳。
图 8-18。
Starting the Interactive Shell
启动 CQL Shell
Cassandra 查询语言(CQL)是 Apache Cassandra 的查询语言。在下面几节中,我们将运行 CQL 命令来创建一个键空间和一个表。使用以下命令启动 CQL Shell。
cqlsh
CQL 壳牌 5.0.1 启动如图 8-19 所示。
图 8-19。
Starting the cqlsh Shell
创建密钥空间
接下来,使用复制类 SimpleStrategy 和复制因子 3 创建一个名为 CatalogKeyspace 的键空间。
CREATE KEYSPACE CatalogKeyspace
WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 3};
创建一个键空间,如图 8-20 所示。
图 8-20。
Creating a Keyspace
更改密钥空间
可以使用 ALTER KEYSPACE 命令更改密钥空间。运行以下命令,将密钥空间设置复制因子更改为 1。
ALTER KEYSPACE CatalogKeyspace
WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 1};
如图 8-21 所示,键空间被改变。
图 8-21。
Altering a Keyspace
使用密钥空间
要使用CatalogKeyspace
键区,运行以下命令。
use CatalogKeyspace;
键区CatalogKeyspace
的设置如图 8-22 所示。
图 8-22。
Setting a Keyspace to be used
创建表格
表也称为柱族。CREATE TABLE
和CREATE 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 表并添加两行数据。
图 8-23。
Creating an Apache Cassandra Table
运行以下 CQL 查询语句从catalog
表中选择数据。
SELECT * FROM catalog;
添加的两行数据被列出,如图 8-24 所示。
图 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
。
图 8-25。
Querying Table after deleting Data from a Row
截断表格
截断表意味着删除包括主键列值在内的所有表数据。运行下面的TRUNCATE
CQL 语句删除所有行。
TRUNCATE catalog;
随后再次运行 CQL 查询语句。
SELECT * from catalog;
没有列出如图 8-26 所示的行;运行一个TRUNCATE
语句后,甚至不会列出空值。
图 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 所示的错误。
图 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 所示。建议在字段值中添加引号。
图 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
目录。
图 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
添加到目录中。随后再次列出目录文件和目录。
图 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 所示。
图 8-31。
Listing the Docker Containers
使用容器 id 启动一个交互式 shell。
sudo docker exec -it 11a4b26d9a09 bash
交互外壳启动,如图 8-32 所示。
图 8-32。
Starting an Interactive Shell
将目录(cd)更改为/cassandra/data
目录,并列出目录中的文件。
cd /cassandra/data
ls –l
如图 8-33 所示,cassandra.txt 文件被列出。/cassandra/data 目录存在于主机上,但可以从容器中访问。
图 8-33。
Accessing the Volume in a Docker Container
类似地,可以创建其他类型的卷。以下是 AWS 卷的volumeMounts
和volumes 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 所示。
图 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 所示。
图 8-35。
Creating a Replication Controller Imperatively
要列出窗格,请运行以下命令。
kubectl get pods
创建的单个 Pod 被列出,如图 8-36 所示。
图 8-36。
Listing the single Pod
要描述复制控制器,请运行以下命令。
kubectl describe rc cassandra
复制控制器的名称、命名空间、映像、选择器、标签、副本、pod 状态和事件会被列出,如图 8-37 所示。对于cassandra
复制控制器,选择器默认为“run=cassandra”。
图 8-37。
Describing the Replication Controller
创建服务
要将复制控制器cassandra
作为服务公开,请运行kubectl expose
命令。需要指定端口,并为该服务设置为 9042。
kubectl expose rc cassandra --port=9042 --type=LoadBalancer
cassandra
服务被创建,如图 8-38 所示。
图 8-38。
Creating a Service for Apache Cassandra Imperatively
用下面的命令描述服务。
kubectl describe service cassandra
如图 8-39 所示,列出了服务名称、名称空间、标签、选择器、类型、IP、端口、节点端口和端点。服务选择器 run=cassandra 必须与要管理的 Pod 上的标签相同。
图 8-39。
Describing the Service
扩展数据库
要扩展集群,运行kubectl scale
命令。扩展 Cassandra 复制控制器的一个重要原因是运行更多的 Cassandra 节点,并让它们加入集群,我们演示了如何扩展集群。但是并不总是需要扩展集群。集群也可以缩小。要将群集缩减到 0 个副本,请运行以下命令。
kubectl scale rc cassandra --replicas=0
图 8-40 中的“scaled”输出表示组合仪表已经缩小。
图 8-40。
Scaling Down the Database Cluster to 0 Replicas
列出 POD。
kubectl get pods
没有 pod 被列出,如图 8-41 所示。
图 8-41。
Listing the Pods after Scaling Down
使用以下命令列出服务。
kubectl get services
将集群扩展到 0 个副本将不会为服务留下要管理的 Pod,但服务仍在运行,如图 8-42 所示。
图 8-42。
Listing the Services after Scaling Down
但是该服务没有任何与之关联的端点,如图 8-43 中的kubectl describe
命令所示。
图 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 所示。复制控制器和服务将被删除,但不会列出。
图 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-cli
、cbbackup
、cbrestore
和cbtransfer
。作为一个分布式数据库,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 所示。
图 9-1。
Getting Public IP Address
使用公共 IP 地址登录 Ubuntu 实例。
ssh -i "docker.pem" ubuntu@54.172.55.212
Ubuntu 实例被登录,如图 9-2 所示。
图 9-2。
Logging into Ubuntu Instance on Amazon EC2
启动 Docker 引擎并验证其状态。
sudo service docker start
sudo service docker status
如图 9-3 所示,Docker 引擎应被列为正在运行。
图 9-3。
Starting Docker Engine
列出正在运行的服务。
kubectl get services
kubernetes 服务应被列为正在运行,如图 9-4 所示。
图 9-4。
Listing the “kubernetes” Service
列出节点。
kubectl get nodes
该节点应以“就绪”状态列出,如图 9-5 所示。
图 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 所示。
图 9-6。
Pod Definition file couchbase.yaml in vi Editor
运行以下命令从定义文件创建一个 Pod。
kubectl create -f couchbase.yaml
如图 9-7 中的“Pod/couch base”输出所示,创建一个 Pod。
图 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。
图 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 所示。
图 9-9。
Listing the couchbase Service
使用以下命令列出服务端点。
kubectl get endpoints
couchbase
服务的服务端点如图 9-10 所示。
图 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 所示。
图 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 已经在运行,它将计入副本设置。
图 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。
图 9-13。
Listing the Pods for Couchbase Server
列出日志
要列出一个 Pod 的日志,运行kubectl logs
命令。pod 名称可以从前面的 pod 列表中复制。
kubectl logs couchbase-0hglx
输出如图 9-14 所示。输出表明 WEB UI 在http://<ip>:8091
可用。
图 9-14。
Listing Pod Logs
描述服务
要描述couchbase
服务,请运行以下命令。
kubectl describe svc couchbase
服务名、名称空间、标签、选择器、类型、IP、端口、节点端口和端点被列出,如图 9-15 所示。将selector
列为app=couchbaseApp
。
图 9-15。
Describing the Service for Couchbase
列出端点
再次列出端点。
kubectl get endpoints
之前列出端点时,因为只有一个 Pod 在运行,所以只列出了一个端点。两个吊舱运行时,两个端点被列出,如图 9-16 所示。
图 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 所示。
图 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 所示。
图 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 服务器。
图 9-19。
Setting Up Couchbase Server
配置 Couchbase 服务器
在这一节中,我们将配置 Couchbase 服务器,这与使用 Kubernetes 没有直接关系,但为了完整起见会进行讨论。当点击设置按钮时,显示配置服务器窗口,如图 9-20 所示。
图 9-20。
Configuring Server Disk Storage, Hostname
保留默认设置,向下滚动选择 Start a new cluster。如果没有足够的 RAM 可用,可能必须降低 RAM 设置。点击下一步,如图 9-21 所示。
图 9-21。
Starting New Cluster
列出了一些样本桶,但不要求选择样本桶。点击下一步,如图 9-22 所示。
图 9-22。
Sample Buckets are not required to be selected
创建默认存储桶设置包括存储桶类型,它应该是 Couchbase,如图 9-23 所示。应通过“启用”复选框启用副本。
图 9-23。
Configuring Default Bucket
向下滚动,使用“启用”复选框启用冲洗模式。点击下一步,如图 9-24 所示。
图 9-24。
Enabling Flush Mode and completing Server Configuration
接下来,接受如图 9-25 所示的条款和条件,并点击下一步。
图 9-25。
Accepting Terms and Conditions
如图 9-26 所示,为确保服务器安全,指定一个密码,并在验证密码字段中指定相同的密码。
图 9-26。
Securing the Server with Username and Password
Couchbase 服务器得到配置。选择“服务器节点”页签,列出服务器节点名称,如图 9-27 所示。服务器节点名称是服务端点之一。
图 9-27。
Server Node Name is the same as a Service Endpoint
添加文档
接下来,我们将向 Couchbase 服务器添加一些文档。选择数据桶选项卡,如图 9-28 所示。
图 9-28。
Selecting Data Buckets Tab
默认存储桶被列出,如图 9-29 所示。点击文档。
图 9-29。
Clicking on Documents Button for the default Bucket
最初,“默认”铲斗是空的,如图 9-30 所示。
图 9-30。
Initially no Documents are present in the default Data Bucket
点击创建文档,添加一个文档,如图 9-31 所示。
图 9-31。
Clicking on Create Document
在创建文档对话框中指定一个文档 Id 并点击创建,如图 9-32 所示。
图 9-32。
Specifying Document ID
添加一个带有默认字段的新 JSON 文档,如图 9-33 所示。
图 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 所示。
图 9-34。
Saving a JSON Document
如图 9-35 所示,当选择“默认”存储桶的文档链接时,catalog1
文档被保存并被列出。
图 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 所示。
图 9-36。
Adding another Document catalog2
如图 9-37 所示,“默认”存储桶的文档链接链接添加的两个文档。
图 9-37。
Listing the two Documents in the default Bucket
启动交互式 Shell
接下来,我们将启动一个交互式 bash shell 来从命令行访问 Couchbase 服务器。根据 Docker 映像“couchbase”获取其中一个 Docker 容器的容器 id,如图 9-38 所示。
图 9-38。
Obtaining the Container Id
使用容器 id,启动一个交互式 shell。
sudo docker exec -it e1b2fe2f24bd bash
如图 9-39 所示,启动一个交互式外壳。
图 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 所示的输出。
图 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”。
图 9-41。
Creating a Replication Controller Imperatively
使用以下命令列出复制控制器。
kubectl get rc
couchbase
复制控制器列表如图 9-42 所示。
图 9-42。
Listing the Replication Controllers
列出 POD
要列出窗格,请运行以下命令。
kubectl get pods
如图 9-43 所示,两个吊舱被列出。
图 9-43。
Listing the Pods
要描述任何特定的 Pod,运行kubectl describe
pod 命令,例如,Pod couchbase-rd44o
用以下命令描述。
kubectl describe pod couchbase-rd44o
吊舱细节得到如图 9-44 所示的输出。Pod 标签列为run=couchbase
。
图 9-44。
Describing a Pod
创建服务
要从在端口 8091 公开的复制控制器创建服务,请运行以下命令,该命令还指定了服务类型。
kubectl expose rc couchbase --port=8091 --type=LoadBalancer
随后列出服务。
kubectl get services
couchbase
服务被创建并列出,如图 9-45 所示。
图 9-45。
Creating a Service for Couchbase Imperatively
要描述couchbase
服务,请运行以下命令。
kubectl describe svc couchbase
服务名称、名称空间、标签、选择器、类型、Ip、端口、节点端口和端点会被列出,如图 9-46 所示。因为服务管理两个 pod,所以列出了两个端点。
图 9-46。
Describing a Service
扩展集群
使用 Kubernetes 集群管理器可以扩大或缩小 Couchbase 集群。例如,要将名为“couchbase”的复制控制器缩减为 1 个副本,运行下面的kubectl scale
命令。
kubectl scale rc couchbase --replicas=1
“scaled”输出表示 rc 已被缩放。但是“缩放”输出并不总是意味着缩放数量的副本正在运行并准备就绪。运行以下命令列出窗格。
kubectl get pods
如图 9-47 所示,列出一个床座箱。
图 9-47。
Scaling Down the Couchbase Cluster to a Single Pod
运行以下命令列出复制控制器,如图 9-48 所示couchbase
rc 与副本一起列为 1。
图 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 所示。
图 9-49。
Running the kubectl get pods Command Multiple Times until all Pods are Running and Ready
描述couchbase
服务。
kubectl describe svc couchbase
列出两个端点,如图 9-50 所示。
图 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 所示。
图 9-51。
Setting Port Forwarding
登录 Couchbase 管理控制台
使用localhost
上的转发端口登录 Couchbase Web 控制台。
http://localhost:8095/index.html
Couchbase Web 控制台显示如图 9-52 所示。
图 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 应列为“正在运行”。
图 10-1。
Starting Docker
使用以下命令列出服务。
kubectl get services
kubernetes
服务应该被列为正在运行,如图 10-2 所示。
图 10-2。
Listing the “kubernetes” Service
使用以下命令列出 pod。
kubectl get pods
使用以下命令列出节点。
kubectl get nodes
唯一列出的 Pod 是 Kubernetes,如图 10-3 所示。还会列出节点 127.0.0.1。
图 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 所示。
图 10-4。
Service Definition File in vi Editor
使用以下命令从定义文件创建服务。
kubectl create -f cdh-service.yaml
随后列出服务。
kubectl get services
第一个命令的输出“services/cdh”表示服务已经创建,如图 10-5 所示。第二个命令列出了名为“cdh”的服务。服务选择器在选择器列中列为 app = cdh。
图 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。
图 10-6。
Creating a Replication Controller from a Definition File
列出 POD
要列出窗格,请运行以下命令。
kubectl get pods
两个吊舱被列出,如图 10-7 所示。最初,pod 可能被列为未运行或/和未就绪。“未就绪”箱由“就绪”栏中的 0/1 值表示,这意味着箱中的 1 个容器中的 0 个已经就绪。
图 10-7。
Listing the Pods for CDH, created but not Ready
再次运行相同的命令以列出窗格。
kubectl get pods
如图 10-8 所示,两个 pod 应被列为状态->运行和就绪- > 1/1。
图 10-8。
Listing the Pods as Ready
列出日志
要列出特定 Pod 的日志,例如 cdh-612pr Pod,请运行以下命令。
kubectl logs cdh-612pr
该命令的输出列出了日志,表明 Hadoop datanode、namenode、secondarynamenode、resourcemanager 和 nodemanager 已经启动,如图 10-9 所示。
图 10-9。
Listing Pod Logs
HBase 等其他组件也会启动。
扩展集群
最初,CDH 群集有两个副本。要将复制副本扩展到 4,请运行以下命令。
kubectl scale rc cdh --replicas=4
随后列出集群中的单元。
kubectl get pods
向上扩展群集后,会列出 4 个 pod,而不是最初列出的 2 个。一些 pod 可能被列为未运行或未准备好。几秒钟后周期性地运行前面的命令,所有的吊舱都应该启动,如图 10-10 所示。
图 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 所示。
图 10-11。
Copying the Docker Container Id
随后使用容器 id 启动交互式 shell。
sudo docker exec -it f1efdb5937c6 bash
交互外壳启动,如图 10-12 所示。
图 10-12。
Starting an Interactive Shell
运行 MapReduce 应用
在本节中,我们将在交互式 shell 中运行一个示例 MapReduce 应用。hdfs
命令用于运行 MapReduce 应用。在交互式 shell 中调用hdfs
命令。
hdfs
命令用法应如图 10-13 所示。
图 10-13。
Command Usage for hdfs Command
要将用户更改为“hdfs ”,请运行以下命令。
su –l hdfs
用户变成“hdfs”,如图 10-14 所示。
图 10-14。
Setting User as hdfs
接下来,我们将运行一个wordcount
应用。我们将从/input
目录文件中获取输入,并在/output
目录中输出。创建/input
目录并将其权限设置为全局(777)。
hdfs dfs -mkdir /input
hdfs dfs -chmod -R 777 /input
如图 10-15 所示,/input
目录被创建,其权限被设置为全局权限。
图 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
。
图 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 所示。
图 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 所示。
图 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 所示。
图 10-19。
Putting the input2.txt File into HDFS
可以用下面的命令列出 HDFS 中/input
目录下的文件。
hdfs dfs -ls /input
增加的两个文件input1.txt
和input2.txt
被列出,如图 10-20 所示。
图 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 所示。
图 10-21。
Starting a YARN Application for Word Count Example
MapReduce 作业完成后运行wordcount
应用。图 10-22 中显示的是wordcount
MapReduce 作业的输出,而不是字数统计结果。
图 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
列出两个文件:_SUCCESS
和part-r-00000
,如图 10-23 所示。_SUCCESS
文件表示 MapReduce 命令成功完成,part-r-00000
命令包含字数统计的结果。
图 10-23。
Listing the Files generated by the MapReduce Job
要列出 wordcount 应用的结果,请运行以下命令。
hdfs dfs -cat /output/part-r-00000
如图 10-24 所示,列出了输入中每个单词的字数。
图 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 所示。
图 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 所示。
图 10-26。
Listing the Hive Metastore Directory
配置单元主目录是/usr/lib/hive
。Cd 到/usr/lib/hive
目录。随后列出文件和目录。
cd /usr/lib/hive
ls –l
Apache Hive 的bin
、conf,
和lib
目录如图 10-27 所示。bin
目录包含可执行文件,conf
目录包含配置文件,lib
目录包含 jar 文件。
图 10-27。
The Hive Home Directory
所有的环境变量都是预先配置的。运行以下命令启动直线 CLI。
beeline
直线版本 1.1.0-cdh5.4.7 启动,如图 10-28 所示。
图 10-28。
Starting Beeline CLI
最初,没有到 Apache Hive 服务器的连接。为了进行演示,运行以下命令将数据库设置为默认数据库并显示表。
use default;
show tables;
显示如图 10-29 所示的“无电流连接”信息。
图 10-29。
No Current Connection
使用驱动程序、用户名和密码的默认设置与 Hive2 服务器连接,如三个空""所示。
!connect jdbc:hive2://localhost:10000/default "" "" ""
Apache Hive2 服务器使用 Apache Hive JDBC 驱动程序进行连接,如图 10-30 所示。
图 10-30。
Connecting with Hive Server
运行命令将数据库设置为默认值并显示表格。
use default;
show tables;
连接到的数据库已经是默认的,第一个命令基本上是多余的,但是需要注意的是,前面生成的错误没有生成。第二个命令列出了表,因为默认数据库最初没有任何表,所以没有列出任何表。前面命令的输出如图 10-31 所示。
图 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 所示。
图 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 所示。
图 10-33。
Creating a Hive Table called wlslog
使用以下命令描述 wlslog 表。
desc wlslog;
表格列(名称和数据类型)如图 10-34 所示。
图 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 所示。
图 10-35。
Adding Data to Hive Table wlslog
随后查询wlslog
表。
select * from wlslog;
添加的 7 行数据被列出,如图 10-36 所示。
图 10-36。
Querying the Hive Table
要退出 Beeline CLI,请运行以下命令。
!q
如图 10-37 所示,蜂箱直线 CLI 退出。将显示交互式 shell 命令提示符。
图 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 所示。
图 10-38。
Starting HBase Shell
使用列族“log”创建一个名为“wlslog”的表。
create 'wlslog' , 'log'
wlslog
表被创建,如图 10-39 所示。
图 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 所示。
图 10-40。
Putting Data into HBase Table
要列出这些表,请运行以下命令。
list
wlslog
表被列出,如图 10-41 所示。
图 10-41。
Listing HBase Tables
要获取行关键字为“log1”的行中的数据,请运行以下命令。
get 'wlslog', 'log1'
单列数据被列出,如图 10-42 所示。
图 10-42。
Getting a Single Row of Data
从具有行关键字log7
的行中获取单个列log.msg
中的数据。使用列族:列格式指定列。
get 'wlslog', 'log7', {COLUMNS=>['log:msg']}
单列数据输出如图 10-43 所示。
图 10-43。
Getting a Single Column Value in a Row
用scan
命令扫描wlslog
工作台。
scan 'wlslog'
扫描命令如图 10-44 所示。
图 10-44。
Scanning a HBase Table
来自wlslog
表的所有数据被列出,如图 10-45 所示。
图 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
。
图 10-46。
Creating a Replication Controller Imperatively
列出复制控制器。
kubectl get rc
cdh
复制控制器列表如图 10-47 所示。
图 10-47。
Getting the Replication Controller
列出 POD
要列出集群中的 pod,请运行以下命令。
kubectl get pods
这两个 pod 会被列出。如图 10-48 所示,最初一些或所有的吊舱可能不“运行”或不处于就绪状态 1/1。
图 10-48。
Listing the Pods with some Pod/s not READY yet
几秒钟后再次运行前面的命令。
kubectl get pods
如图 10-49 所示,所有的吊舱应列出状态“运行”和就绪状态 1/1。
图 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。
图 10-50。
Scaling the CDH Cluster
创建服务
服务在服务端点公开由复制控制器管理的 pod,服务端点只是外部客户机可以调用应用的主机:端口设置。运行以下命令创建服务。
kubectl expose rc cdh --type=LoadBalancer
随后列出服务。
kubectl get services
“cdh”服务列出选择器和端口的默认设置,如图 10-51 所示。默认的服务选择器是run=cdh
,它的默认格式是 run =
图 10-51。
Creating a Service
启动交互式 Shell
交互式外壳可以像以声明方式启动的 CDH 集群一样启动。复制运行 CDH 映像的 Docker 容器的容器 id,并运行以下命令(包括容器 id)来启动交互式 bash shell。
sudo docker exec -it 42f2d8f40f17 bash
交互外壳启动,如图 10-52 所示。
图 10-52。
Starting an Interactive Shell
运行hdfs
命令。
hdfs
hdfs
命令用法得到如图 10-53 所示的输出。
图 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 机应该正在运行。
图 11-1。
Starting Docker and Verifying Status
列出服务。
kubectl get services
如图 11-2 所示,Kubernetes 服务应该正在运行。
图 11-2。
Listing the “kubernetes” Service
要列出节点,请运行以下命令。
kubectl get nodes
127.0.0.1 节点被列出,如图 11-3 所示。
图 11-3。
Listing a Single Node
使用以下命令列出端点。
kubectl get endpoints
最初只列出了 kubernetes 的终点,如图 11-4 所示。
图 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 所示。
图 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
。
图 11-6。
Creating a Service from Definition File
列出服务端点
要列出端点,请运行以下命令。
kubectl get endpoints
由于solr-service
最初没有管理任何 pod,因此没有列出端点,如图 11-7 所示。
图 11-7。
Listing the Endpoint for the Solr Service
描述服务
要描述solr-service
,运行以下命令。
kubectl describe service solr-service
服务名称、名称空间、标签、选择器、类型、IP、端口、端点和事件被列出,如图 11-8 所示。
图 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 所示。
图 11-9。
Replication Controller Definition File in vi Editor
运行以下命令,从定义文件创建复制控制器。
kubectl create -f solr-rc.yaml
solr-rc
复制控制器被创建,如图 11-10 所示。随后列出复制控制器。
图 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 可能没有运行,也没有准备好。
图 11-11。
Listing the Pods, all of them not yet Ready
几秒钟后再次运行相同的命令,再次列出 pod。
kubectl get pods
如图 11-12 所示,pod 应列出状态“运行”和就绪状态 1/1。
图 11-12。
Listing the Pods as Ready
要描述solr-service
,运行以下命令。
kubectl describe svc solr-service
服务描述被列出,如图 11-13 所示。还列出了两个 pod 的服务端点。服务在其端点被访问。如前所述,在创建复制控制器之前,没有列出服务端点,如图 11-8 所示。
图 11-13。
Describing the Solr Service including the Service Endpoints
端点也可以单独列出。
kubectl get endpoints
端点列表如图 11-14 所示。
图 11-14。
Listing the Endpoints for Solr Service
描述复制控制器
要描述复制控制器solr-rc
,运行以下命令。
kubectl describe rc solr-rc
复制控制器描述被列出,如图 11-15 所示。
图 11-15。
Describing the Replication Controller
列出日志
要列出特定命令的日志,运行kubectl logs
命令。例如,使用以下命令列出了solr-rc-s82ip
Pod 的日志。
kubectl logs solr-rc-s82ip
在日志输出中,Solr 服务器正在启动,如图 11-16 所示。
图 11-16。
Listing Logs for the Pod
服务器启动后,输出“服务器启动”得到如图 11-17 所示的输出。
图 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 所示。
图 11-18。
Listing the Docker Container for Apache Solr
复制容器并启动一个交互式 shell。
sudo docker exec -it 2d4d7d02c05f bash
交互外壳启动,如图 11-19 所示。要列出 Solr 服务器的状态,请运行以下命令。
图 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 所示,列出了三种示例配置。
图 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 所示。
图 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 所示。
图 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 所示。
图 11-23。
The wlslog.xml File
Cd 到/opt/solr
目录,并运行 post 工具将wlslog.xml
文件中的文档添加到 Solr 服务器。
bin/post -c wlslog ./wlslog.xml
一个文件被编入索引,如图 11-24 所示。
图 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 所示。
图 11-25。
Using curl to send a Request to Solr Server with Request Handler /select
添加的 7 个文件列表如图 11-26 所示。
图 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 所示。
图 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 所示。
图 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 所示。
图 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 所示,所有文件都被删除,没有列出任何文件。
图 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 所示。
图 11-31。
Setting Port Forwarding to localhost
在管理控制台中访问 Solr
在端口转发之后,Solr 管理控制台可以使用 url http://localhost:8983
从本地机器访问,如图 11-32 所示。在型芯选择器中选择wlslog
型芯,如图 11-32 所示。
图 11-32。
Displaying the Solr Admin Console
选择文档选项卡,将/update
请求处理器的文档类型设置为 XML,如图 11-33 所示。复制并粘贴前面在文档字段中列出的 XML 文档 wlslog.xml,然后单击提交文档。
图 11-33。
Adding Document to the wlslog Core
如图 11-34 所示的“成功”输出表示文档已被索引。
图 11-34。
Response from adding Documents
接下来,我们将查询wlslog
索引。选择查询选项卡,如图 11-35 所示。
图 11-35。
Selecting the Query Tab
请求处理程序为/select
时,查询默认为“:”,如图 11-36 所示。
图 11-36。
Using the Request Handler /select to Query Solr index wlslog
点击执行查询,如图 11-37 所示。
图 11-37。
Submitting a Query to select all Documents in the wlslog Index
因为我们没有设置自动提交,所以添加的文档还没有被索引。因此,没有文件被列出,如图 11-38 所示。
图 11-38。
Response from the Query
我们需要重新加载核心,以便为添加的文档建立索引。或者,我们可以重启 Solr 服务器,但是重新加载内核是一个更快的选择。选择核心管理员并点击重新加载,如图 11-39 所示。
图 11-39。
Reloading the Core
再次运行查询,如图 11-40 所示,添加的 7 个文档被列出。
图 11-40。
Query Response with 7 Documents
Solr 服务器已经自动将_version_
字段添加到每个文档中,如图 11-41 所示。
图 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 可能没有运行或最初没有准备好。
图 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/kafka
。dockerkafka/kafka
映像 docker 文件的默认设置不适合与 Kubernetes 进行编排。在下一节中,我们修改并重建了默认的 Docker 映像。首先,使用 Amazon EC2 实例的公共 IP 地址连接 Ubuntu 实例。
ssh -i "docker.pem" ubuntu@54.146.140.160
Ubuntu 实例如图 12-1 所示连接。
图 12-1。
Connecting to an Ubuntu Instance on Amazon EC2
按照第一章所述安装所需软件。启动 Docker 服务并查找其状态。
sudo service docker start
sudo service docker status
如图 12-2 所示,Docker 应被列为正在运行。
图 12-2。
Starting Docker
列出永恒的服务。
kubectl get services
应列出“kubernetes”服务,如图 12-3 所示。
图 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 所示。
图 12-4。
Downloading the kafka-docker Docker Image Source Code
将目录(cd)更改为kafka-docker
目录,并列出文件/目录。
cd kafka-docker
ls –l
Docker 镜像中的文件/目录被列出,如图 12-5 所示。
图 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 所示。
图 12-6。
Listing the Configuration Files for the Docker Image
在 vi 编辑器中打开server.properties
文件。
sudo vi server.properties
server.properties
文件如图 12-7 所示。取消带有host.name=localhost
设置的行的注释。
图 12-7。
Uncommenting the host.name Property
如图 12-8 所示zookeeper.connect
的默认设置为zookeeper:2181
。
图 12-8。
The default setting for the zookeeper.connect Property
将zookeeper.connect
设置修改为localhost:2181
,如图 12-9 所示。用:wq 保存修改后的文件。我们需要修改设置,因为默认情况下不存在“zookeeper”这样的主机。
图 12-9。
Setting zookeeper.connect to localhost: 2181
随后,cd 回到 Docker 映像的根目录,即kafka-docker
目录,并运行以下命令来重建 Docker 映像。
sudo docker build -t dockerkafka/kafka:v2.
该命令的输出如图 12-10 所示。
图 12-10。
Rebuilding the Docker Image for Kafka
Docker 映像得到重建,如图 12-11 所示。
图 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 所示。
图 12-12。
Service Definition File in vi Editor
从定义文件创建服务。
kubectl create -f kafka-service.yaml
随后列出服务。
kubectl get services
“kafka”服务被列出,如图 12-13 所示。服务选择器是 app = kafkaApp。
图 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 所示。
图 12-14。
Replication Controller Definition File in vi Editor
从定义文件创建复制控制器。
kubectl create -f kafka-rc.yaml
随后列出复制控制器。
kubectl get rc
复制控制器被创建并列出,如图 12-15 所示。
图 12-15。
Creating the Replication Controller from the Definition File
要描述kafka-rc
,运行以下命令。
kubectl describe rc kafka-rc
复制控制器描述被列出,如图 12-16 所示。
图 12-16。
Describing the Replication Controller
列出 POD
要列出窗格,请运行以下命令。
kubectl get pods
吊舱被列出,如图 12-17 所示。
图 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。
图 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 所示。
图 12-19。
Obtaining the Docker Container Id
复制容器 id 并启动交互式 bash shell。
sudo docker exec -it 939ae2cb4f86 bash
交互外壳启动,如图 12-20 所示。
图 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 所示。
图 12-21。
Starting the Kafka Server
Kafka 服务器启动,如图 12-22 所示。
图 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
主题被创建。
图 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 制作人开始了。
图 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 制作人开始了。
图 12-25。
Starting a Kafka Consumer
生产和消费消息
启动了生产者和消费者之后,我们将在生产者处产生消息,在消费者处消费消息。如图 12-26 所示,在生产者处添加一条消息,例如“来自 Kafka 生产者的消息”,并点击输入按钮。信息被发送出去。
图 12-26。
Producing a Message at the Kafka Producer
在消费者处,消息被消费,如图 12-27 所示。
图 12-27。
Consuming a Message at the Kafka Consumer
在生产者处发送更多消息,如图 12-28 所示。
图 12-28。
Producing More Messages at the Kafka Producer
并且消息在消费者处被消费,如图 12-29 所示。
图 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 所示。
图 12-30。
Scaling the Kafka Cluster
当 pod 的数量增加到 4 时,服务端点也增加到 4。描述服务kafka
。
kubectl describe svc kafka
如图 12-31 所示,这两个服务都列出了 4 个端点,一个用于 Zookeeper 服务器,另一个用于 Kafka 服务器。
图 12-31。
Describing the Kafka Service with 4 Endpoints
删除复制控制器和服务
要删除复制控制器和服务,请运行以下命令。
kubectl delete rc kafka-rc
kubectl delete service kafka
如图 12-32 所示,复制控制器和服务被删除。
图 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-world
和postgres
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 表示容器总数中就绪的容器数。所有容器都运行在一个节点上,如后面的节点列表所示。
图 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 所示。
图 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 应被列为“正在运行”。
图 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 所示。
图 13-4。
Creating a Service from the Definition File
描述服务
可以用下面的命令描述hello-postgres
服务。
kubectl describe service hello-postgres
服务描述包括名称、命名空间、标签、选择器、类型、IP、端口和端点,如图 13-5 所示。最初,该服务不管理任何 pod,因此没有列出任何端点。
图 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
复制控制器被创建并列出。
图 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,这意味着两个容器中有两个正在运行。
图 13-7。
Listing the Pods
列出 Docker 容器
要列出已启动的 Docker 容器,请运行以下命令。
sudo docker ps
列出的两个容器,基于postgres
映像的容器和基于tutum/hello-world
映像的容器,如图 13-8 所示,由复制控制器hello-postgres
启动。
图 13-8。
Listing the Docker Containers
创建复制控制器后描述服务
在我们创建复制控制器之前,服务hello-postgres
没有与任何端点相关联。创建复制控制器和 Pod 后,再次运行以下命令来描述服务。
kubectl describe service hello-postgres
为服务公开的每个端口列出一个端点,如图 13-9 所示。
图 13-9。
Describing the Service
在命令行上调用 Hello World 应用
使用 curl 调用服务端点172.17.0.2
,如下所示。
curl 172.17.0.2
应用生成的 HTML 得到如图 13-10 所示的输出。
图 13-10。
Invoking an Endpoint for the Service
启动交互式 Shell
要为安装的软件启动一个交互式外壳,可使用多容器盒的任何一个 Docker 容器,如前面图 13-8 中所列。两个容器访问相同的文件系统和 IP。使用以下命令启动交互式 shell。
sudo docker exec -it 2e351a609b5b bash
如图 13-11 所示,启动一个交互式外壳。
图 13-11。
Starting an Interactive Shell
正在启动 PostgreSQL Shell
要启动名为psql
的 PostgreSQL 命令 shell,请在交互式 shell 中运行以下命令。
psql postgres
启动psql
并显示postgres
命令提示符,如图 13-12 所示。
图 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 所示。
图 13-13。
Setting Port Forwarding
Amazon EC2 实例的公共 DNS 可以从 Amazon EC2 控制台获得,如图 13-14 所示。
图 13-14。
Obtaining Public DNS
在浏览器中打开 Hello World 应用
设置端口转发后,可以在 url 为http://localhost
的本地机器上的浏览器中打开应用,如图 13-15 所示。除了主机名之外,HELLO_POSTGRES
监听的两个端口也被列出。
图 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。
图 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 描述被列出。
图 13-17。
Describing a Pod
列出 Docker 容器
由于每个单元由两个容器组成,将集群扩展到 3 个单元或副本会启动 4 个新容器,两个新单元各有 2 个容器。在扩展集群后,运行以下命令,使用默认输出格式再次列出正在运行的 Docker 容器。
sudo docker ps
总共列出了 3 个基于postgres
映像的容器和 3 个基于tutum/hello-world
映像的容器,如图 13-18 所示。
图 13-18。
Listing the Docker Containers
描述扩展后的服务
在扩展集群后再次描述服务。
kubectl describe service hello-postgres
服务公开的每个端口都与三个端点相关联,因为有 3 个 Pods 正在运行,如图 13-19 所示。
图 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 所示。
图 13-20。
Setting Port Forwarding
在浏览器中打开 Hello World 应用
该应用可以在每个转发端口的浏览器中打开;比如在http://localhost:81
打开一个浏览器。应用 HTML 显示如图 13-21 所示。HELLO_POSTGRES
服务正在监听两个端口 8020 和 5432。
图 13-21。
Invoking a Service Endpoint in a Browser
类似地,用 url http://localhost:82
在浏览器中打开另一个服务端点。监听同一端口的不同主机名被转发到localhost
上的不同端口。服务端点 HTML 得到如图 13-22 所示的输出。
图 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 所示的输出。
图 13-23。
Invoking a Service Endpoint with curl
用下面的 curl 命令调用172.17.0.4
端点。
curl 172.17.0.4
服务端点的 HTML 得到如图 13-24 所示的输出。
图 13-24。
Invoking another Service Endpoint with curl
删除复制控制器
要删除hello-postgres
复制控制器,请运行以下命令。
kubectl delete rc hello-postgres
随后使用以下命令列出 pod。
kubectl get pods
图 13-25 中没有列出hello-postgres
复制控制器的吊舱。
图 13-25。
Deleting the Replication Controller
删除服务
要删除服务hello-postgres
,运行以下命令。
kubectl delete service hello-postgres
随后运行以下命令列出服务。
kubectl get services
未列出hello-postgres
服务,如图 13-26 所示。
图 13-26。
Deleting the Service
摘要
在本章中,我们讨论了在一个 Pod 中使用多个容器。我们讨论了多容器 Pod 的用例,并使用tutum/hello-world
和postgres
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 所示。
图 14-1。
Creating two Ubuntu Instances for Kubernetes Master and Worker Nodes
SSH 分别登录到每个节点。主节点的公共 IP 地址可以从 Amazon EC2 控制台获得,如图 14-2 所示。
图 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 引擎应被列为“正在运行”。
图 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 所示。
图 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 所示。
图 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 所示。
图 14-6。
Setting Up CIDR on the Master Node
设置法兰绒
默认情况下,Docker 确实提供了容器和 pod 之间的网络,但法兰绒提供的网络要简单得多。我们将使用法兰绒进行交流。首先,我们需要阻止 Docker。
sudo service docker stop
如图 14-7 所示,
图 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 所示。
图 14-8。
Installing Flannel
法兰绒生成哈希如图 14-9 所示。复制哈希。
图 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 所示。
图 14-10。
Listing the Subnet Settings
记下FLANNEL_SUBNET
和FLANNEL_MTU
的值,因为我们将需要它们来编辑 Docker 配置。在 vi 编辑器中打开 Docker 配置文件。
sudo vi /etc/default/docker
docker 配置文件中的默认设置如图 14-11 所示。
图 14-11。
Docker Configuration File Default Settings
向DOCKER_OPTS
设置添加以下参数,其值从图 14-10 的输出中获得。
--bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}
修改后的 docker 配置文件如图 14-12 所示。
图 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 所示。
图 14-13。
Removing docker0 bridge
重启 Docker。
sudo service docker start
Docker 重新启动,如图 14-14 所示。
图 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 所示。
图 14-15。
Starting Kubernetes on the Master Node
Kubernetes 安装在主节点上,如图 14-16 所示。
图 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 所示。
图 14-17。
Starting Service proxy on Master Node
测试单节点集群
要测试主节点,请运行以下命令,该命令列出了群集中的节点。
kubectl get nodes
单个节点被列出,如图 14-18 所示。
图 14-18。
Listing the Nodes, only the Master Node to start with
添加工作节点
设置工作节点与设置主节点非常相似。接下来,我们将设置一个工作节点。工作者节点的 Ubuntu 实例的 SSH 登录。
导出主 IP
首先,我们需要设置环境变量MASTER_IP
。获取运行主节点的 Ubuntu 实例的公共 IP 地址,如图 14-19 所示。
图 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 所示。
图 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 所示。
图 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 所示。
图 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 所示。
图 14-23。
Installing Flannel on the Worker Node
复制前面命令生成的哈希,如图 14-24 所示。
图 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 所示的输出。
图 14-25。
Listing the Subnet Settings on the Worker Node
使用子网设置,我们需要编辑 Docker 配置文件。在 vi 编辑器中打开 Docker 配置文件。
sudo /etc/default/docker
将以下参数添加到DOCKER_OPTS
设置中。将从图 14-25 中获得的值代入FLANNEL_SUBNET
和FLANNEL_MTU
中。
--bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}
修改后的 Docker 配置文件如图 14-26 所示。
图 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 所示。
图 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 所示。
图 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 所示。
图 14-29。
Starting Service Proxy on the Worker Node
测试 Kubernetes 集群
从主节点,而不是前面命令中配置的工作节点,列出集群中的节点。
kubectl get nodes
列出两个节点,如图 14-30 所示:主节点和工作节点。
图 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 正在群集中的哪个实例(节点)上运行,请运行命令。
图 14-31。
Installing an Application on the Cluster
kubectl get pods -o wide.
将应用公开为服务
要将复制控制器 nginx 作为服务公开,请运行以下命令。
kubectl expose rc nginx --port=80
nginx 服务被创建,如图 14-32 所示。
图 14-32。
Creating a Service
使用以下命令列出服务。
kubectl get services
为了能够调用服务,使用以下命令获取第一个集群 Ip,如图 14-33 所示。
图 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 所示。
图 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 所示。
图 14-35。
Setting Port Forwarding
在本地浏览器中使用 url http://localhost
调用 nginx 应用,如图 14-36 所示。
图 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 所示。
图 14-37。
Listing the Pods
用下面的命令描述服务。
kubectl describe svc nginx
列出三个服务端点,如图 14-38 所示。
图 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 所示。
图 14-39。
Setting port Forwarding for the additional Service Endpoints
可以在本地浏览器中调用服务端点。例如,url http://localhost:8081
调用一个服务端点,如图 14-40 所示。
图 14-40。
Invoking a Service Endpoint in a Browser
类似地,url http://localhost:8082
调用另一个服务端点,如图 14-41 所示。
图 14-41。
Invoking another Service Endpoint in a Browser
类似地,url http://localhost:8083
调用第三个服务端点,如图 14-42 所示。
图 14-42。
Invoking a Third Service Endpoint in a Browser
摘要
在本章中,我们在多节点集群上安装了 Kubernetes。多节点配置利用法兰绒进行联网,而不是 Docker 提供的默认联网。首先,我们在主节点上安装了 Kubernetes。使用主节点的 Ip 地址,我们在一个工作节点上安装了 Kubernetes,结果创建了一个双节点集群。可以使用相同的过程添加所需数量的工作节点。我们使用 nginx Docker 映像创建了一个应用,并使用 curl 在命令行上调用该应用,使用端口转发在本地浏览器中调用该应用。我们还扩展了应用。在单节点集群中,应用在主节点上运行。在多节点集群中,应用同时在工作节点和主节点上运行。本章总结了 Docker 关于 Kubernetes 微服务的书。