Docker-高级教程-全-
Docker 高级教程(全)
原文:Pro Docker
一、你好,Docker
Docker 是一个开发、打包和运行可移植分布式应用的开放标准平台。使用 Docker,开发人员和系统管理员可以在任何平台(如 PC、云、数据中心或虚拟机)上构建、发布和运行应用。在开发和运行应用时,获取软件应用所需的所有依赖项(包括代码、运行时库以及系统工具和库)通常是一项挑战。Docker 通过将应用所需的所有软件(包括依赖项)打包到一个称为 Docker 镜像的软件单元中,简化了应用的开发和执行,该镜像可以在任何平台和环境上运行。
Docker 映像与虚拟设备(也是软件映像(虚拟机映像))的不同之处在于,虽然每个虚拟机映像运行在单独的客户操作系统上,但 Docker 映像运行在同一个操作系统内核中。Docker 软件运行在一个被称为 Docker 容器的隔离环境中,它包含自己的文件系统和环境变量。Docker 容器相互隔离,并与底层操作系统隔离。
软件应用的 Docker 容器包括运行软件所需的所有内容,并且如果需要,文件可以从主机 OS 复制到 Docker 容器。由于应用可能需要其他软件来开发链接的应用,所以 Docker 容器可以被链接,这使得来自另一个 Docker 容器的环境变量和软件对 Docker 容器可用。
Docker 利用 docker 文件来构建映像。Dockerfile 由所有指令组成,例如下载什么软件、运行什么命令、暴露哪些网络端口、将哪些文件和目录添加到文件系统以及设置哪些环境变量。通过提供入口点,可以使停靠映像成为可执行的。可以通过提供 Docker 文件来构建 Docker 映像,或者可以从 Docker Hub ( https://hub.docker.com/ )下载预构建的 Docker 映像。Dockerfile 支持的完整指令集可以在docs.docker.com/engine/reference/builder/找到。
在这一章中,我们将在 Linux 上安装 Docker 引擎,下载 Hello World Docker 镜像,并为 Hello World 应用运行 Docker 容器。我们使用 Linux 是因为我们使用的其他一些软件,比如 Apache Hadoop,只在 Linux 上受支持(包括开发和生产)。我们使用了两个常用的 Linux 发行版,Red Hat 7 和 Ubuntu 14,但是任何支持的安装( https://docs.docker.com/v1.8/installation/ )都可以使用。
- 设置环境
- 在 Red Hat 7 上安装 Docker
- 卸载 Docker
- 安装特定的 Docker 版本
- 在 Ubuntu 上安装坞站
- 启动 Docker 服务
- 查找 Docker 服务状态
- 运行 Docker Hello World 应用
- 下载 Docker 映像
- 在 Docker 容器中运行应用
- 列出正在运行的 Docker 容器
- 在命令行上访问应用输出
- 在浏览器中访问应用输出
- 停止 Docker 容器
- 移除 Docker 容器
- 移除 Docker 映像
- 停止 Docker 服务
设置环境
我们将使用基于 Linux 的 Amazon EC2 实例来部署 Docker 和 Docker 映像。Linux 需要支持 64 位软件。我们使用了两种不同的 64 位(必需的)Amazon 机器映像(AMIs):
Ubuntu Server 14.04 LTS (HVM), SSD Volume Type - ami-d05e75b8 64 bit Red Hat Enterprise Linux version 7.1 (HVM), EBS General Purpose (SSD) Volume Type (ami-12663b7a) 64 bit
一个基于 Ubuntu AMI 的 Amazon EC2 实例如图 1-1 所示。

图 1-1。
Amazon EC2 Instance Based on Ubuntu AMI
为了连接到 Amazon EC2 实例,使用公共 IP 地址。公共 IP 地址可以从 EC2 控制台获取,如图 1-2 所示。

图 1-2。
Obtaining the Public IP Address
使用 SSH 和公共 IP 地址连接到 Amazon EC2 Ubuntu 实例,使用下面的命令,其中docker.pem是私钥格式。pem)由亚马逊 EC2 生成。
ssh -i "docker.pem" ubuntu@54.86.12.113
Ubuntu 实例的连接如图 1-3 所示。

图 1-3。
Connecting to Ubuntu Instance on Amazon EC2 from Local Host
如果使用 Red Hat AMI,连接 Amazon EC2 实例的命令会略有不同。使用“ec2-user”用户代替用户“ubuntu”。例如,使用下面的命令连接到 Linux 实例,其中docker.pem是私钥格式(。pem)由亚马逊 EC2 生成。
ssh -i "docker.pem" ec2-user@54.175.182.96
RHEL 7.1 实例的连接如图 1-4 所示。

图 1-4。
Connecting to RHEL Instance
运行以下命令,查看 Linux 体系结构是否支持 64 位软件。
uname -r
图 1-5 输出中的 x86_64 表示支持 64 位。

图 1-5。
Finding Architecture Support
在 Red Hat 7 上安装 Docker
在 Red Hat 上安装 Docker 有两种不同的方法:用 yum 安装或用脚本安装。使用 yum 安装需要用户添加 yum repo,这可能比脚本选项更复杂。我们已经使用了 Docker 安装脚本来安装 Docker。
作为拥有sudo或 root 权限的用户,使用以下命令更新本地存储库包。
sudo yum update
运行 Docker 安装脚本来安装 Docker 引擎。
curl -sSLhttps://get.docker.com/
对接发动机安装如图 1-6 所示。

图 1-6。
Installing Docker Engine
在启动 Docker 服务之前,应该修改docker.service文件来禁用 Docker 启动超时。docker.service文件在/usr/lib/systemd/system目录中,该目录设置了权限。运行 sudo 命令或将文件复制到没有权限集的目录中。例如,用下面的命令将docker.service复制到root目录。
cp /usr/lib/systemd/system/docker.service .
在 vi 编辑器中打开docker.service文件。
vi docker.service
或者以 sudo 的身份打开docker.service文件。
sudo vi /usr/lib/systemd/system/docker.service
在[Service]标题的docker.service中添加以下一行。
TimeoutStartSec=0
更新后的docker.service如图 1-7 所示。

图 1-7。
Updated docker.service
如果docker.service被复制到另一个目录,用下面的命令将文件复制回/usr/lib/systemd/system目录。
sudo cp docker.service /usr/lib/systemd/system/docker.service
刷新更改以加载新配置。
sudo systemctl daemon-reload
在红帽上安装 Docker 的所有选项都在docs . Docker . com/engine/installation/rhel/讨论。
卸载 Docker
如果在本章和后面的章节中要用到 Docker,可以跳过这一节。要卸载 Docker,请运行以下命令来列出已安装的 Docker 引擎。
yum list installed | grep docker
使用以下命令删除 Docker 引擎和 Docker 目录。
sudo yum -y remove docker-engine.x86_64
rm -rf /var/lib/docker
安装特定的 Docker 版本
要安装 Docker 的特定版本,请下载并安装该版本的 rpm。比如安装 Docker 1.7.0 如下。
curl -O -sSLhttps://get.docker.com/rpm/1.7.0/centos-6/RPMS/x86_64/docker-engine-1.7.0-1.el6.x86_64.rpm
sudo yum localinstall --nogpgcheck docker-engine-1.7.0-1.el6.x86_64.rpm
在 Ubuntu 上安装坞站
以下版本的 Ubuntu 支持 docker:Ubuntu Wily 15.10、Ubuntu Vivid 15.04、Ubuntu Trusty 14.04 (LTS)和 Ubuntu Precise 12.04 (LTS)。无论版本如何,Docker 都需要 64 位操作系统,最低 Linux 内核版本为 3.10。要找到内核版本,请在 Ubuntu 终端中运行以下命令。
uname –r
内核版本输出为 3.13,如图 1-8 ,安装 Docker 没问题。

图 1-8。
Outputting Kernel Version
在 Ubuntu 上安装 Docker 引擎之前,从以下命令开始更新 apt 源代码。
sudo apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
在“更新你的 apt 源”( http://docs.docker.com/engine/installation/ubuntulinux/ )第六节。需要你基于 Ubuntu 版本更新/etc/apt/sources.list.d/docker.list。使用以下命令可以找到 Ubuntu 发行版。
lsb_release –a
对于 Ubuntu Trusty,下面一行被添加到/etc/apt/sources.list.d/docker.list文件中。
debhttps://apt.dockerproject.org/repo
更新/etc/apt/sources.list.d/docker.list文件后运行以下命令。
sudo apt-get update
sudo apt-get purge lxc-docker*
sudo apt-cache policy docker-engine
使用以下命令安装 Ubuntu 的先决条件。
sudo apt-get update
sudo apt-get install linux-image-generic-lts-trusty
重启系统。
sudo reboot
主机系统重新启动后,使用以下命令安装 Docker。
sudo apt-get update
sudo apt-get install docker-engine
启动 Docker 服务
不管 Linux 发行版是什么,用下面的命令启动 Docker 服务。
sudo service docker start
Docker 通过 systemctl 启动,如图 1-9 中 OK 消息所示。

图 1-9。
Starting Docker Service
查找 Docker 服务状态
要验证 Docker 服务的状态,请运行以下命令。
sudo service docker status
如果 Docker 服务正在运行,则应输出如图 1-10 所示的消息 Active: active (running)。

图 1-10。
Finding Docker Service Status
运行 Docker Hello World 应用
要测试 Docker,使用下面的docker run命令运行 Hello World 应用。
sudo docker run hello-world
docker run命令将在后面的章节中介绍。如果hello-world应用运行良好,应该会生成图 1-11 中的输出,该输出是在 Red Hat 7 上生成的。

图 1-11。
Running hello-world Application
在 Ubuntu 上,对hello-world运行相同的命令。
sudo docker run hello-world
如图 1-12 所示,输出“你好,来自 Docker”消息。

图 1-12。
Running hello-world on Ubuntu
下载 Docker 映像
当我们使用docker run命令运行hello-world应用时,Docker 映像hello-world被下载,用于HelloWorld应用的 Docker 容器启动。当用于 Docker 映像的 Docker 容器启动时,可以自动下载 Docker 映像,或者可以单独下载 Docker 映像。docker pull命令用于下载 Docker 镜像。例如,运行以下命令下载 Docker 映像tutum/hello-world,这是打包成 Docker 映像的另一个HelloWorld应用。
sudo docker pull tutum/hello-world
Docker 映像是预先构建的,不需要构建。Docker 图片tutum/hello-world:latest被下载,如图 1-13 所示。后缀:latest是 Docker 映像的标签,指定了映像版本,默认情况下会下载最新版本。

图 1-13。
Downloading tutum:hello-world:latest
使用以下命令列出下载的 Docker 映像。
sudo docker images
除了之前可能已经安装的其他映像之外,tutum/hello-world Docker 映像被列出,如图 1-14 所示。

图 1-14。
Listing Docker Images
在 Docker 容器中运行应用
docker run命令用于在一个单独的容器中运行一个进程,这是应用的另一个术语。docker run命令的语法如下。
docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]
唯一需要的命令参数是 Docker 映像。Docker 容器可以在分离模式(或后台)或前台模式下启动。在分离模式下,进程的 stdin、stdout 和 stderr 流与运行docker run命令的命令行分离。要在分离模式下启动容器,设置–d=true或仅设置–d。默认模式是前台模式,在这种模式下,容器在前台启动,stdin、stdout 和 stderr 流连接到主机命令行控制台。–name选项可用于指定 Docker 容器的名称。–p选项用于为容器中运行的进程指定一个端口。例如,使用–d参数在分离模式下为tutum/hello-world映像启动一个 Docker 容器,使用–p参数将容器名设为helloapp,将应用运行的端口设为 80。
sudo docker run -d -p 80 --name helloapp tutum/hello-world
Docker 容器启动,如图 1-15 所示。

图 1-15。
Running an Application in a Docker Container
可以启动交互式外壳或终端(tty)来运行应用于在容器中运行的进程的命令。交互终端启动时,–i和–t命令参数一起使用或组合为–it。关于docker run命令的完整语法,参见 http://docs.docker.com/engine/reference/run/ 。
列出正在运行的 Docker 容器
要列出正在运行的 Docker 容器,请运行以下命令。
sudo docker ps
helloapp容器被列出,如图 1-16 所示。容器 id 也被分配给容器。在所有 docker 命令中,如docker stop、docker start,可以使用容器名或容器 id。

图 1-16。
Listing only the Docker Containers that are Running
在 PORTS 列中,分配给容器中端口 80 上运行的进程的外部端口被列为 32768。当从容器外部访问helloapp应用时,必须使用 32768 端口(不是端口 80)。也可以使用docker port命令列出外部端口。
sudo docker port 82171f7ade46
端口 32768 被列出,如图 1-17 所示。0.0.0.0 主机 IP 地址意味着本地机器上的所有 IP 地址。

图 1-17。
Listing Port
要列出所有正在运行或已退出的 Docker 容器,请运行以下命令。
sudo docker ps –a
在命令行上访问应用输出
curl 工具可用于连接运行helloapp的主机和端口。运行以下命令来访问外部端口 32768 上的应用。
curl http://localhost:32768
helloapp生成的 HTML 在主机中得到输出,如图 1-18 所示。

图 1-18。
Output from helloapp Application
在浏览器中访问应用输出
然而,使用 curl 工具访问生成 HTML 输出的应用并不总是最好的方法。在本节中,我们将在浏览器中访问helloapp。如果浏览器与运行 Docker 容器的主机在同一台机器上,url http://localhost:32768可以用来显示应用输出。但是如果浏览器在不同的主机上,就像本章中的例子一样,Amazon EC2 实例的公共 DNS 必须用来访问应用。公共 DNS 可以从亚马逊 EC2 控制台获得,如图 1-19 所示。

图 1-19。
Finding Public DNS
使用公共 DNS,通过 URL http://ec2-54-86-12-113.compute-1.amazonaws.com:32768/ 在远程浏览器中访问helloapp,该浏览器可以运行在 Windows 操作系统上。Docker 容器helloapp中运行的应用生成的输出显示在浏览器中,如图 1-20 所示。

图 1-20。
Displaying Output from helloapp in a Browser
停止 Docker 容器
Docker 容器可以用docker stop命令停止。例如,用下面的命令停止helloapp容器。
sudo docker stop helloapp
Docker 容器被停止。随后运行docker ps命令列出正在运行的容器。如图 1-21 所示helloapp容器未列出。

图 1-21。
Stopping a Container
移除 Docker 容器
Docker 容器可通过docker rm命令移除。例如,用下面的命令删除helloapp容器。
sudo docker rm helloapp
在移除容器之前,必须停止 Docker 容器。
移除 Docker 映像
要删除 Docker 映像,请运行 docker rmi 命令。例如,运行以下命令删除 Docker 映像 tutum/hello-world。
sudo docker rmi tutum/hello-world
在删除 Docker 映像之前,必须停止并删除所有访问 Docker 映像的容器。有时,一些未完全下载的 Docker 映像可以用docker images命令列出。此类 Docker 映像没有指定名称,而是被列为<>。所有这样的悬挂映像都可以用下面的命令删除。
sudo docker rmi $(sudo docker images -f "dangling=true" -q)
如图 1-22 中的输出所示,多个 Docker 映像被移除。

图 1-22。
Removing Dangling Docker Images
停止 Docker 服务
要停止 Docker 服务,请运行以下命令。
sudo service docker stop
可以使用以下命令再次启动 Docker 服务。
sudo service docker start
或者,可以使用以下命令重新启动正在运行的 Docker 服务。
sudo service docker restart
摘要
在本章中,我们介绍了 Docker 引擎。我们在两个 Linux 发行版上安装了 Docker:Red Hat 7 和 Ubuntu,但 Docker 也可能安装在其他 Linux 发行版上。对于支持的 Docker 安装操作系统,请参考docs.docker.com/v1.8/installation/。我们讨论了下载 Docker 映像、使用 Docker 映像运行 Docker 容器、从远程浏览器访问 Docker 容器应用,以及停止和删除 Docker 容器和 Docker 映像。在下一章,我们将在 Docker 容器中运行 Linux。
二、安装 Linux
安装 Linux 是大多数开发人员和所有 Linux 管理员都熟悉的任务。有几种 Linux 发行版,包括 Red Hat Linux、Ubuntu、openSuse 和 Oracle Linux。安装 Linux 的一些选项包括使用 Amazon Linux AMIs、ISO 映像和虚拟机映像。Linux 也可以使用 Docker 镜像来安装。Docker 公共存储库( https://hub.docker.com/ )提供了几个用于 Linux 发行版的 Docker 映像。在本章中,我们将使用 Docker 映像安装 Oracle Linux。
- 设置环境
- 下载 Docker 映像
- 列出 Docker 映像
- 以分离模式运行容器
- 在前台运行容器
- 列出 Docker 容器
- 查找 Oracle Linux 容器信息
- 列出容器进程
- 启动交互式 Shell
- 创建容器
- 停止容器
- 移除容器
设置环境
本章需要以下软件:
- -Docker(使用 1.8.x 版本)
- -适用于 Oracle Linux 的 docker image
- -主机 Linux 操作系统(使用 Amazon EC2 AMI)
对于主机操作系统,我们在 Amazon EC2 上使用了 Red Hat Enterprise Linux 7.1 (HVM),SSD 卷类型- ami-12663b7a。使用以下命令登录 Amazon EC2 实例;不同用户的 IP 地址(54.165.251.73)会有所不同,可以按照附录 a 中的说明获取
ssh -i "docker.pem" ec2-user@54.165.251.73
按照第一章中的说明安装 Docker。用下面的命令启动 Docker。
sudo service docker start
一条 OK 消息表明 Docker 已经启动。要确认 Docker 已经开始运行以下命令。
sudo service docker status
如果 Active:标签具有如图 2-1 所示的活动(运行)值,则 Docker 已经启动并准备在 Docker 容器中部署应用。

图 2-1。
Finding Docker Status
下载 Docker 映像
我们使用了 Docker Hub 存储库中的 Docker 映像oraclelinux(Hub . Docker . com/_/Oracle Linux/)。使用以下命令下载最新版本的oraclelinux Docker 映像。
sudo docker pull oraclelinux
Docker 映像被标记到映像名称,以区分映像的变体(或版本)。例如,要下载oraclelinux 6.6 版本,运行以下命令。
sudo docker pull oraclelinux:6.6
要下载oraclelinux 7 版本,运行以下命令。
sudo docker pull oraclelinux:7
如图 2-2 中的输出所示,下载oraclelinux 6.6 和 7 版本的 Docker 映像。

图 2-2。
Downloading Docker Images
列出 Docker 映像
可以使用以下命令列出下载并可用于运行应用的 Docker 映像。
sudo docker images
两张oraclelinux图片;版本 6.6 和 7 如图 2-3 所示。标签列列出了映像的版本(或变体)。

图 2-3。
Listing Docker Images
以分离模式运行容器
docker run命令用于运行容器中的进程。docker run命令可以在分离模式或连接模式下运行。在分离模式下,容器与命令行分离,I/O 通过网络和共享卷完成。下面的命令语法将以分离模式运行 Docker 容器,如–d选项所示。–name选项设置容器的名称。
sudo docker run –d --name <container-name> <image-name>
如果使用–d 选项指定–I–t 选项,则不会启动交互式终端或 shell。例如,运行以下命令,使用标签为 6.6 的oraclelinux Docker 映像以分离模式启动名为oraclelinux的容器。
sudo docker run –i –t –d --name oraclelinux6 oraclelinux:6.6
即使指定了–i和–t选项,容器还是以分离模式运行,如图 2-4 所示。

图 2-4。
Starting Docker Container in Detached Mode
在分离模式下,Docker 容器与 STDIN、STDOUT 和 STDERR 流分离。–RM 选项不能在分离模式下使用。关于docker run命令语法的详细信息,请参考docs . docker . com/engine/reference/run/。
在前台运行容器
要在附加模式下运行 Docker 容器,省略–d选项。
sudo docker run <image-name>
在附加模式下,启动一个容器进程并将其附加到所有标准流(STDIN、STDOUT 和 STDERR)。–name选项也可在附加模式下用于指定容器名称。要启动一个交互式终端,使用–i和–t选项,这将为容器进程分配一个 tty。如果指定了–RM 选项,则会在容器退出后清理容器资源,包括分配给容器的文件系统。运行以下命令,使用oraclelinux:7.0 Docker 映像运行容器进程;–name选项为容器指定一个名称,–i –t选项启动一个交互终端(tty),–rm选项在容器退出后清理容器。
sudo docker run –i –t –rm –name oraclelinux7 oraclelinux:7.0
使用oracleinux映像的 Docker 容器进程启动并连接到一个交互式 shell 或 tty,如图 2-5 所示。

图 2-5。
Starting Docker Container in Attached Mode
容器名称必须唯一。如果启动了与正在运行的容器同名的容器,则会产生如图 2-6 所示的错误。

图 2-6。
Container Name must be Unique
列出 Docker 容器
Docker 容器可以运行,也可以不运行。运行以下命令列出正在运行的 Docker 容器。
sudo docker ps
唯一运行的容器oraclelinux:6.6和oraclelinux:7.0如图 2-7 所示。“状态”列指示容器是“启动”并正在运行还是“已退出”。容器 ID 列列出了容器 ID。

图 2-7。
Listing Running Docker Containers
要列出所有正在运行或已退出的容器,请运行以下命令。
sudo docker ps –a
已经退出的容器也会被列出,如图 2-8 所示。

图 2-8。
Listing All Docker Containers
查找 Oracle Linux 容器信息
可以用docker inspect命令列出一个容器的信息。运行以下命令列出有关容器 oraclelinux7 的信息。
sudo docker inspect oraclelinux7
容器细节以 JSON 格式列出,如图 2-9 所示。

图 2-9。
Output from docker inspect
列出容器进程
用docker top命令列出容器正在运行的进程。下面的命令列出了由oraclelinux6容器运行的进程。
sudo docker top oraclelinux6
如图 2-10 所示,UID 和 PID 在为进程列出的列中。

图 2-10。
Listing Container Processes
启动交互式 Shell
当使用附加模式和–i –t选项使用docker run命令启动容器进程时,可以启动交互式 shell 或 tty,以指示交互式终端。
sudo docker run –i –t --rm <image-name>
运行以下命令来运行 oraclelinux:7.0 映像的容器并启动 tty 终端。
sudo docker run –i –t --rm –name oraclelinux7 oraclelinux:7.0
如图 2-11 所示,一个交互式 shell 启动,容器进程连接到终端。

图 2-11。
The interactive shell gets started when a Docker container is started in Attached Mode
如果已经使用–d选项在分离模式下启动了容器进程,可以使用以下命令语法启动交互式终端。
docker exec -i -t <container> bash
–i和–t选项可以合并成–it。运行下面的命令为oraclelinux6容器启动一个 tty。
sudo docker exec –it oraclelinux6 bash
交互式 tty 启动,如图 2-12 所示。

图 2-12。
Starting an Interactive Terminal for a Docker Docker Container running in Detached Mode
无论 tty 是在使用–rm、-it选项启动容器进程时启动,还是随后使用前面的命令启动,容器命令都可以在交互式 shell 中运行。在交互式外壳中运行的命令指向在容器中运行的软件或应用。例如,如果 Docker 容器运行 Oracle Linux,则 tty 命令适用于 Oracle Linux 平台。例如,使用以下命令输出 Oracle 版本。
cat /etc/oracle-release
Oracle Linux Server 版如图 2-13 所示。

图 2-13。
Outputting Oracle Release
运行其他一些 Linux 命令来创建一个目录,设置该目录的权限,并列出文件和目录。
mkdir /orcl
chmod 777 /orcl
ls -l
/orcl目录被创建并被列出,如图 2-14 所示。

图 2-14。
Listing Files and Directories
运行exit命令退出交互 shell,如图 2-15 所示。

图 2-15。
Running the exit Command
创建容器
docker create命令用于创建一个容器。运行以下命令为oraclelinux:6.6映像创建一个名为orcl6的容器。即使指定了–i –t选项,交互式 shell 也不会启动。
docker create -i -t --name orcl6 oraclelinux:6.6 /bin/bash
要启动 Docker 容器orcl6和用于orcl6容器的交互式 shell,运行docker start命令。-a和-i选项将当前 shell 的标准输入、标准输出和标准错误流附加到容器中。所有信号都被转发到容器。
sudo docker start –a –i orcl6
Docker 容器 orcl6 和一个交互 shell 开始如图 2-16 所示。

图 2-16。
Starting an Interactive Shell with docker start
停止容器
要停止正在运行的容器,运行docker stop命令。运行以下命令来停止orcl6容器。
sudo docker stop orcl6
orcl6 容器停止,如图 2-17 所示。

图 2-17。
Stopping a Docker Container
随后,docker ps –a命令会将orcl6容器列为“已退出”,如图 2-18 所示。

图 2-18。
Listing an Exited Container
移除容器
要移除容器,运行docker rm命令。移除前必须先停止容器,否则docker rm命令不会移除容器。运行以下命令删除orcl6容器。
sudo docker rm orcl6
orcl6 容器被移除,如图 2-19 所示。

图 2-19。
Removing A Docker Container
摘要
在本章中,我们在 Docker 容器中安装了 Oracle Linux。我们讨论了如何下载 Docker 映像并运行容器进程。我们还讨论了使用不同的映像标签、启动交互式 shell、运行容器的不同模式,以及启动、停止和删除容器。在下一章,我们将讨论在 Docker 容器中运行 Oracle 数据库。
三、使用 Oracle 数据库
Oracle 数据库是最常用的关系数据库。关系数据库基于固定的模式,存储的基本单位是表。Docker Hub 在公共存储库中有几个针对 Oracle 数据库的 Docker 映像。在本章中,我们将使用 Oracle 数据库的 Docker 映像在 Linux 上安装和使用数据库。本章包括以下几节。
- 设置环境
- 启动 Oracle 数据库
- 列出容器日志
- 正在启动 SQL* Plus
- 创建用户
- 创建数据库表
- 正在删除 Oracle 数据库
设置环境
本章需要以下软件。
- -Docker 引擎(使用 1.8 版)
- oracle 数据库的 docker image
我们使用了一个 Amazon EC2 实例,使用 Red Hat Linux 7 作为操作系统。首先,SSH 登录到 Amazon EC2 实例。对于不同的用户,IP 地址是不同的。
ssh -i "docker.pem" ec2-user@54.175.172.33
查找 Docker 引擎的状态。
sudo service docker status
如果 Docker 引擎没有运行,请启动 Docker 服务。
sudo service docker start
下载sath89/oracle-xe-11g Docker 映像。
sudo docker pull sath89/oracle-xe-11g
下载sath89/oracle-xe-11g的最新映像,如图 3-1 所示。

图 3-1。
Downloading Docker Image for Oracle Database
列出 Docker 映像。
sudo docker images
sath89/oracle-xe-11g 映像被列出,如图 3-2 所示。

图 3-2。
Listing Docker Images
启动 Oracle 数据库
接下来,用docker run命令在 Docker 容器中启动一个 Oracle 数据库实例。为 Oracle Application Express 管理控制台指定 8080 端口,为 Oracle 数据库监听程序指定 1521 端口。用–name选项指定容器名称。
docker run --name orcldb -d -p 8080:8080 -p 1521:1521 sath89/oracle-xe-11g
Oracle 数据库在 Docker 容器中启动,如图 3-3 所示。

图 3-3。
Starting Oracle Database in a Docker Container
用下面的命令列出 Docker 容器。
sudo docker ps
orcldb容器被列出,如图 3-4 所示。

图 3-4。
Listing Docker Containers that are Running
Oracle 数据库的主机名、端口、SID、用户名和口令如下。
hostname: localhost
port: 1521
sid: xe
username: system
password: oracle
列出容器日志
要列出容器日志,运行docker logs命令。
sudo docker logs -f c0fa107a43d2
容器日志列表如图 3-5 所示。Oracle 数据库日志包括数据库初始化和配置。

图 3-5。
Listing Docker Container Log
更详细的 Docker 容器日志如下。
[ec2-user@ip-172-30-1-192 ∼]$ sudo docker logs -f c0fa107a43d2
Database not initialized. Initializing database.
Setting up:
processes=500
sessions=555
transactions=610
If you want to use different parameters set processes, sessions, transactions env variables and consider this formula:
processes=x
sessions=x*1.1+5
transactions=sessions*1.1
Oracle Database 11g Express Edition Configuration
-------------------------------------------------
This will configure on-boot properties of Oracle Database 11g Express
Edition. The following questions will determine whether the database should
be starting upon system boot, the ports it will use, and the passwords that
will be used for database accounts. Press <Enter> to accept the defaults.
Ctrl-C will abort.
Specify the HTTP port that will be used for Oracle Application Express [8080]:
Specify a port that will be used for the database listener [1521]:
Specify a password to be used for database accounts. Note that the same
password will be used for SYS and SYSTEM. Oracle recommends the use of
different passwords for each database account. This can be done after
initial configuration:
Confirm the password:
Do you want Oracle Database 11g Express Edition to be started on boot (y/n) [y]:
Starting Oracle Net Listener...Done
Configuring database...Done
Starting Oracle Database 11g Express Edition instance...Done
Installation completed successfully.
Database initialized. Please visit http://#containeer:8080/apex to proceed with configuration
Oracle Database 11g Express Edition instance is already started
Database ready to use. Enjoy! ;)
[ec2-user@ip-172-30-1-192 ∼]$
正在启动 SQL* Plus
使用以下命令启动交互式 shell。容器 ID 很可能不同。
sudo docker exec -it c0fa107a43d2 bash
关于 bash 的更多细节请参考 http://www.gnu.org/software/bash/manual/bash.html#Bash-Startup-Files 。在 tty 中运行以下命令。术语“tty”、“交互式外壳”和“交互式终端”可以互换使用。
sqlplus
当提示输入如图 3-6 所示的用户名时,指定“系统”。

图 3-6。
Starting SQL*Plus
当提示输入密码时,请指定“oracle”。与 Oracle Database 11g Express 建立连接。SQL*Plus 启动,显示 SQL >提示符,如图 3-7 所示。

图 3-7。
SQL*Plus Shell Prompt
我们使用容器 id 来启动交互式 tty 终端。或者,容器名称可以如下使用。
sudo docker exec -it orcldb bash
创建用户
要创建一个名为OE的用户,在SYSTEM表空间上拥有无限配额,密码为“OE ”,运行以下命令。
SQL> CREATE USER OE QUOTA UNLIMITED ON SYSTEM IDENTIFIED BY OE;
Grant the CONNECT and RESOURCE roles to the OE user.
GRANT CONNECT, RESOURCE TO OE;
创建用户“OE”并授予角色,如图 3-8 所示。

图 3-8。
Creating User OE
创建数据库表
使用以下 SQL 语句在“OE”模式中创建一个名为“Catalog”的数据库。
SQL> CREATE TABLE OE.Catalog(CatalogId INTEGER PRIMARY KEY,Journal VARCHAR2(25),Publisher VARCHAR2(25),Edition VARCHAR2(25),Title VARCHAR2(45),Author VARCHAR2(25));
表格“目录”被创建,如图 3-9 所示。

图 3-9。
Creating Oracle Database Table OE.Catalog
使用下面的INSERT SQL 语句将数据添加到目录表中。
SQL> INSERT INTO OE.Catalog VALUES('1','Oracle Magazine','Oracle Publishing','November December 2013','Engineering as a Service','David A. Kelly');
增加一行数据,如图 3-10 所示。

图 3-10。
Adding Data to OE.Catalog Table
使用下面的SELECT语句运行 SQL 查询。
SQL> SELECT * FROM OE.CATALOG;
添加的一行数据被列出,如图 3-11 所示。

图 3-11。
Running a SQL Query
要退出 SQL*Plus,指定退出命令,如图 3-12 所示。

图 3-12。
Exiting SQL*Plus
正在删除 Oracle 数据库
要删除运行 Oracle 数据库实例的容器,运行下面的docker rm命令。
sudo docker rm c0fa107a43d2
要删除 Docker 映像 sath89/oracle-xe-11g,请运行以下命令。
sudo docker rmi sath89/oracle-xe-11g
Docker 容器和映像被移除,如图 3-13 所示。

图 3-13。
Removing Docker Image
摘要
在本章中,我们使用 Docker 映像在 Amazon EC2 实例上安装 Oracle Database 11g XE。我们登录到 SQL*Plus 并创建了一个数据库表来演示 Docker 容器中运行的 Oracle 数据库的使用。在下一章,我们将在 Docker 容器中运行 MySQL 数据库。
四、使用 MySQL 数据库
MySQL 是最常用的开源关系数据库。MySQL 在某些方面类似于 Oracle 数据库,例如数据库将用户保存在授权表中。但是 MySQL 在某些方面也不同于 Oracle 数据库:
MySQL does not have roles and privileges have to be granted individually to users. Database and table names are case-insensitive in Oracle but are case sensitive if the underlying OS is case-sensitive. MySQL provides a default value for columns that do not allow a NULL value and a value is not provided explicitly in the INSERT statement, if the strict mode is not enabled. Oracle database does not generate a default value for columns with the NOT NULL constraint. MySQL database supports AUTO_INCREMENT for a column while a Sequence is used in Oracle Database. Some of the data types in MySQL are different. For example, MySQL does not support the VARCHAR2 data type.
在本章中,我们将在 Docker 容器中运行 MySQL 数据库。本章包括以下几节。
- 设置环境
- 启动 MySQL CLI Shell
- 设置要使用的数据库
- 创建数据库表
- 添加表格数据
- 查询表
- 列出数据库和表格
- 离开 TTY 终点站
- 启动另一个 MySQL 服务器实例
- 列出 Docker 容器日志
设置环境
本章需要以下软件。
- -Docker 引擎(使用 1.8 版)
- MySQL 数据库的 Docker 映像
使用 Amazon EC2 实例的公共 IP 地址登录到该实例。
ssh -i "docker.pem" ec2-user@52.91.169.69
启动 Docker 服务。
sudo service docker start
验证 Docker 服务正在运行。
sudo service docker status
如图 4-1 所示,来自docker start命令的输出应该正常,并且来自docker status命令的输出对于活动字段应该是活动的(运行中)。

图 4-1。
Starting Docker Service and verifying Status
Docker Hub 提供了一个官方的 Docker 映像。使用以下命令下载 Docker 映像。
sudo docker pull mysql
最新的 Docker 映像mysql:latest被下载,如图 4-2 所示。

图 4-2。
Downloading Docker Image for MySQL Database
使用以下命令列出 Docker 映像。
sudo docker images
mysql映像被列出,如图 4-3 所示。

图 4-3。
Listing Docker Image for MySQL Database
启动 MySQL 服务器
在这一节中,我们将在 Docker 容器中运行 MySQL 数据库。MySQL 数据库默认使用/var/lib/mysql目录存储数据,但是也可以使用另一个目录。我们将使用/mysql/data目录来存储 MySQL 数据。创建/mysql/data目录,并将其权限设置为全局(777)。
sudo mkdir -p /mysql/data
sudo chmod -R 777 /mysql/data
/mysql/data目录被创建,如图 4-4 所示。

图 4-4。
Creating the Data Directory
当运行docker run命令在 Docker 容器中启动 MySQL 时,可能会指定某些环境变量,如下表所述。
除了MYSQL_ROOT_PASSWORD环境变量,所有其他变量都是可选的,但是我们将使用所有环境变量运行一个 MySQL 实例容器。我们将使用以下命令参数运行docker run命令。
环境变量用–e指定。运行下面的docker run命令在 Docker 容器中启动一个 MySQL 实例。
sudo docker run -v /mysql/data:/var/lib/mysql --name mysqldb -e MYSQL_DATABASE='mysqldb' -e MYSQL_USER='mysql' -e MYSQL_PASSWORD='mysql' -e MYSQL_ALLOW_EMPTY_PASSWORD='yes' -e MYSQL_ROOT_PASSWORD='' -d mysql
docker run命令的输出如图 4-5 所示。

图 4-5。
Running MySQL Database in a Docker Container
运行以下命令,列出正在运行的 Docker 容器。
sudo docker ps
运行 MySQL 数据库实例的 Docker 容器mysqldb如图 4-6 所示。

图 4-6。
Listing Docker Containers
启动 MySQL CLI Shell
接下来,我们将登录 MySQL CLI shell。但是首先我们需要启动一个交互式终端来运行mysql命令来启动 MySQL CLI。使用以下命令启动交互式终端或 shell。
sudo docker exec -it mysqldb bash
在交互式终端中运行以下命令。
mysql
MySQL CLI 启动,如图 4-7 所示。

图 4-7。
Starting MySQL CLI
也可以使用容器 id 而不是容器名称来启动交互式终端。
sudo docker exec -it 969088c84a4f bash
设置要使用的数据库
使用“use”命令设置数据库。默认情况下,Docker 容器中启动的 MySQL 数据库不提供“测试”数据库。如果运行“use test”命令,将输出以下错误消息。
mysql> use test
ERROR 1049 (42000): Unknown database 'test'
当我们用docker run命令启动 MySQL 数据库的 Docker 容器时,我们创建了一个名为“mysqldb”的数据库。使用以下命令将数据库设置为“mysqldb”。
mysql> use mysqldb
前面命令的输出如下。数据库被设置为“mysqldb”,如图 4-8 所示。

图 4-8。
Setting Database to mysqldb
创建数据库表
接下来,创建一个名为“Catalog”的数据库表,其中包含列 CatalogId、Journal、Publisher、Edition、Title 和 Author。运行以下 SQL 语句。
mysql> CREATE TABLE Catalog(CatalogId INTEGER PRIMARY KEY,Journal VARCHAR(25),Publisher VARCHAR(25),Edition VARCHAR(25),Title VARCHAR(45),Author VARCHAR(25));
Catalog表被创建,如图 4-9 所示。

图 4-9。
Creating a MySQL Database Table
添加表格数据
使用以下 INSERT 语句将数据添加到目录表中。
mysql> INSERT INTO Catalog VALUES('1','Oracle Magazine','Oracle Publishing','November December 2013','Engineering as a Service','David A. Kelly');
一行数据被添加到目录表中,如图 4-10 所示。

图 4-10。
Adding a Row of Data to MySQL Table
查询表
接下来,用 SQL 查询查询目录表。以下 SELECT 语句选择目录表中的所有数据。
mysql> SELECT * FROM Catalog;
添加的一行数据被列出,如图 4-11 所示。

图 4-11。
Running a SQL Query
在本章使用的操作系统(RHEL 7.1 操作系统)上,MySQL 表名区分大小写。如果使用了表名Catalog的变体,就会产生错误。例如,在 SQL 查询中使用表名CATALOG,会产生如图 4-12 所示的错误。

图 4-12。
The table name is Case-sensitive in MySQL
列出数据库和表格
可以在 MySQL CLI 中使用以下命令列出 MySQL 服务器实例中的数据库。
mysql> show databases;
数据库被列出,包括新创建的数据库“mysqldb”,如图 4-13 所示。

图 4-13。
Listing MySQL Databases
离开 TTY 终点站
使用“Exit”命令退出 MySQL CLI。
mysql> exit
Bye
使用“Exit”命令退出交互式 shell 或 tty。
root@969088c84a4f:/# exit
exit
前面命令的输出如图 4-14 所示。

图 4-14。
Exiting MySQL CLI
停止 Docker 容器
用docker stop命令停止 Docker 容器。
[ec2-user@ip-172-30-1-192 ∼]$ sudo docker stop 969088c84a4f
969088c84a4f
随后,用docker ps命令列出正在运行的 Docker 容器。mysqldb容器没有被列出。
sudo docker ps
[ec2-user@ip-172-30-1-192 ∼]$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
在下一节中,我们将创建另一个 MySQL 服务器实例,就像我们在本章前面创建 MySQL 服务器实例一样。但是我们不能使用与现有容器相同的容器名。如果 Docker 容器名称不同,则可以启动运行 MySQL 数据库或任何其他软件的另一个 Docker 容器。如果我们创建一个 Docker 容器来运行另一个名为“mysqldb”的 MySQL 服务器,就会产生一个错误。例如,运行下面的docker run命令创建另一个名为“mysqldb”的容器。
sudo docker run --name mysqldb -e MYSQL_ROOT_PASSWORD=mysql -d mysql
下面的错误会得到输出。
Error response from daemon: Conflict. The name "mysqldb" is already in use by container 969088c84a4f. You have to delete (or rename) that container to be able to reuse that name.
要创建一个名为“mysqldb”的新 Docker 容器,首先删除已经用docker rm命令创建的“mysqldb”容器。容器 id 或容器名称可用于容器的 docker 命令,如stop、start和rm。
sudo docker rm 969088c84a4f
启动另一个 MySQL 服务器实例
删除“mysqldb”容器后,用docker run命令再次创建容器。我们将以不同的方式创建新的“mysqldb”容器。为第二次运行docker run命令指定不同的环境变量。仅指定所需的环境变量MYSQL_ROOT_PASSWORD,并将其值设置为“mysql”。
sudo docker run --name mysqldb -e MYSQL_ROOT_PASSWORD=mysql -d mysql
随后,使用以下命令启动交互式 shell。
sudo docker exec -it 113458c31ce5 bash
在交互式 shell 中使用以下命令登录 MySQL CLI。
mysql –u root –p mysql
指定“root”用户的密码,即mysql。MySQL CLI 启动如图 4-15 所示。

图 4-15。
Using a Password to Start MySQL CLI
也可以发出如下的mysql命令。
mysql –u root –p
指定“mysql”用户的密码。MySQL CLI 启动如图 4-16 所示。

图 4-16。
Alternative mysql Login command
下面的mysql命令不会启动 MySQL CLI。
root@113458c31ce5:/# mysql -u root
将生成以下错误。
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
用show databases命令列出数据库。默认数据库包括“mysql”数据库,如图 4-17 所示。之前,“mysqldb”数据库也与show databases命令一起列出,因为“mysqldb”数据库是在运行docker run命令时创建的。

图 4-17。
Listing the Default Databases
使用“使用 mysql”命令将数据库设置为“mysql”数据库,如图 4-18 所示。

图 4-18。
Using the mysql Database
用show tables命令列出mysql数据库中的数据库表,如图 4-19 所示。

图 4-19。
Listing Tables
列出 Docker 容器日志
接下来,用docker logs命令列出mysqldb容器的日志。
sudo docker logs -f mysqldb
mysqldb容器的日志列表如图 4-20 所示。

图 4-20。
Listing Docker Container Log
摘要
在这一章中,我们使用 Docker 镜像在 Docker 容器中运行 MySQL 服务器。我们运行了两种不同的docker run命令;一个包括所有可能为“mysql”映像设置的环境变量,另一个只包括必需的环境变量。在下一章中,我们将讨论在 Docker 上运行 MongoDB。
五、使用 MongoDB
MongoDB 是最常用的 NoSQL 数据库。MongoDB 基于文档存储数据模型,将数据存储为 BSON(二进制 JSON)文档。MongoDB 提供了一种灵活的无模式存储格式,其中不同的记录可以有不同的字段,这意味着没有应用固定的数据结构。字段值没有关联的数据类型,不同的字段可能具有不同的数据类型。有了 JSON 格式,数据结构的层次变得可行,一个字段可以使用一个数组存储多个值。在本章中,我们将使用 Docker 映像在 Docker 容器中运行 MongoDB。本章包括以下几节。
- 设置环境
- 正在启动 MongoDB
- 启动交互式终端
- 启动 Mongo Shell
- 创建数据库
- 创建收藏
- 创建文档
- 查找文档
- 添加另一个文档
- 删除收藏
- 添加一批文档
- 更新文档
- 查询单个文档
- 查询所有文档
- 制作数据备份
- 停止和重新启动 MongoDB 数据库
- 删除文档
- 退出 Mongo Shell
设置环境
本章需要以下软件:
- -Docker 引擎(版本 1.8)
- -蒙戈布坞站映像
我们使用了一个 Amazon EC2 实例(Amazon Machine Image Red Hat Enterprise Linux 7.1(HVM),SSD 卷类型- ami-12663b7a)来安装 Docker 映像,并在 Docker 容器中运行 MongoDB。到 Amazon EC2 实例的 SSH 登录。
ssh -i "docker.pem" ec2-user@54.174.254.96
启动 Docker 服务。
sudo service docker start
验证 Docker 服务状态。
sudo service docker status
Docker 服务应该是活动的(正在运行),如图 5-1 所示。

图 5-1。
Starting Docker Service and verifying Status
下载 MongoDB 数据库的官方 Docker 映像。
sudo docker pull mongo:latest
列出 Docker 映像。
sudo docker images
名为“mongo”的 Docker 映像被列出,如图 5-2 所示。

图 5-2。
Downloading Docker Image mongo
正在启动 MongoDB
接下来,在 Docker 容器中启动 MongoDB。MongoDB 默认将数据存储在 Docker 容器的/data/db目录中。一个目录可以从底层主机系统挂载到运行 MongoDB 数据库的容器。例如,在主机上创建一个目录/data。
sudo mkdir -p /data
在 mongo 映像上使用docker run命令启动 Docker 容器,将容器中的/data目录挂载为主机上的/data目录。将容器名称指定为“mongodb”。
sudo docker run -t -i -v /data:/data --name mongodb -d mongo
Docker 容器和容器中的 MongoDB 服务器如图 5-3 所示启动。

图 5-3。
Starting Docker Container for MongoDB
列出正在运行的 Docker 容器。
sudo docker ps
如图 5-4 所示,mongodb容器被列为在端口 27017 上运行。

图 5-4。
Listing Docker Container for MongoDB
MongoDB 端口也可以使用–p选项显式指定。
docker run -t -i -v /data:/data -p 27017:27017 --name mongodb -d mongo
可以使用docker logs命令列出容器日志。
sudo docker logs mongodb
启动交互式终端
使用以下命令启动交互式终端(tty)。
sudo docker exec -it mongodb bash
启动 Mongo Shell
要启动 MongoDB shell,请运行以下命令。
mongo
MongoDB shell 启动,并显示>提示符,如图 5-5 所示。

图 5-5。
Starting MongoDB Shell from TTY
MongoDB shell 也可以在特定的主机和端口上启动,如下所示。
mongo –host localhost –port 27017
MongoDB shell 在主机localhost,端口 27017 上启动,如图 5-6 所示。“测试”数据库实例被连接到。

图 5-6。
Starting MongoDB Shell using Host and Port
或者,可以只指定主机或端口中的一个来启动 MongoDB shell。
mongo –port 27017
MongoDB shell 在127.0.0.1:27071/test启动并连接到 MongoDB 服务器,如图 5-7 所示。

图 5-7。
Starting MongoDB Shell using only the Port
指定主机和端口的另一种形式是host:port。例如,用下面的命令启动 MongoDB shell 并连接到localhost:27017。
mongo localhost:27017
MongoDB Shell 连接到localhost:27017/test数据库,如图 5-8 所示。

图 5-8。
Starting MongoDB Shell using host:port Format
创建数据库
使用下面的命令帮助方法(也称为命令助手)从 MongoDB shell 中列出数据库。
show dbs
当数据库名称设置为要创建的数据库时,会隐式创建一个新数据库。例如,用下面的命令将数据库设置为“mongodb”。
use mongodb
show dbs 命令帮助方法在使用数据库之前不会列出mongodb数据库。使用db.createCollection()方法创建一个名为“catalog”的集合。随后,再次运行show dbs命令。
show dbs
db.createCollection("catalog")
show dbs
show dbs命令在创建“catalog”集合之前不列出“mongodb”数据库,但是在创建集合之后列出“mongodb”数据库,如图 5-9 所示。

图 5-9。
Creating a Database
用下面的命令列出mongodb数据库中的集合。
show collections
除了系统集合system.indexes之外,“目录”集合也被列出,如图 5-10 所示。

图 5-10。
Listing Collections
创建收藏
在上一节中,我们使用db.createCollection命令创建了一个名为“catalog”的集合。接下来,通过将capped选项字段设置为true,创建一个加盖的集合“catalog_capped”。capped 集合是一个固定大小的集合,它在添加和获取文档时跟踪插入顺序,因此提供了高吞吐量。
db.createCollection("catalog_capped", {capped: true, autoIndexId: true, size: 64 * 1024, max: 1000} )
如图 5-11 所示,创建了一个名为“catalog_capped”的加盖集合。

图 5-11。
Creating a Capped Collection
也可以使用db.runCommand命令创建一个集合。使用db.runCommand命令创建另一个名为“catalog_capped_2”的 capped 集合。
db.runCommand( { create: "catalog_capped_2", capped: true, size: 64 * 1024, max: 1000 } )
Capped 集合 catalog_capped_2 被创建,如图 5-12 所示。

图 5-12。
Creating a Capped Collection using db.runCommand()
创建文档
接下来,我们将向 MongoDB 集合添加文档。最初,catalog集合是空的。运行 mongo shell 方法db.<collection>.count()对catalog集合中的文档进行计数。将<collection>替换为收藏名称“catalog”。
db.catalog.count()
catalog集合中的文档数被列为 0,如图 5-13 所示。

图 5-13。
Finding Document Count
接下来,我们将向catalog集合添加一个文档。创建一个 JSON 文档结构,包含字段catalogId、journal、publisher、edition、title和author。
doc1 = {"catalogId" : "catalog1", "journal" : 'Oracle Magazine', "publisher" : 'Oracle Publishing', "edition" : 'November December 2013',"title" : 'Engineering as a Service',"author" : 'David A. Kelly'}
使用db.<collection>.insert()方法将文档添加到catalog集合中。
db.catalog.insert(doc1)
随后再次输出文档计数。
db.catalog.count()
来自db.catalog.insert()方法的输出,如图 5-14 所示,是一个类型为WriteResult的对象,其中nInserted为 1,这意味着增加了一个文档。文档计数被列为 1。

图 5-14。
Adding a Document
查找文档
db.collection.find(query, projection)方法用于查找文档。document类型的query参数使用查询操作符指定选择标准。类型为document的projection参数指定了要返回的字段。这两个参数都是可选的。要选择所有文档,请不要指定任何参数或指定空文档{}。例如,查找catalog集合中的所有文档。
db.catalog.find()
先前添加的一个文档被列为 JSON 文档,如图 5-15 所示。如果没有明确指定,_id字段会自动添加到文档中。

图 5-15。
Running a Query using find() Method
添加另一个文档
类似地,为另一个文档创建 JSON 结构。如果_id是唯一的,可以再次添加相同的文档。在 JSON 中包含_id字段作为显式字段/属性。_id字段值必须是类型为ObjectId的对象,而不是字符串文字。
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'};
使用db.<collection>.insert()方法添加文档。
db.catalog.insert(doc2)
如图 5-16 中的nInserted值 1 所示,另一个文档被添加到catalog集合中。

图 5-16。
Adding Another Document
随后使用db.<collection>.find()方法查询catalog集合。
db.catalog.find()
添加到catalog集合中的两个文档被列出,如图 5-17 所示。这两个文档在 JSON 中都有相同的名称/值对,除了_id字段,它有一个惟一的值。

图 5-17。
Running the find() Method
查询单个文档
db.<collection>.findOne()方法用于查找单个文档。从catalog集合中查找单个文档。
db.catalog.findOne()
其中一个文档通过查询得到输出,如图 5-18 所示。

图 5-18。
Using the findOne() Method
db.collection.findOne(query, projection)方法也接受两个类型都是document的参数,并且都是可选的。query参数指定查询选择标准,而projection参数指定要选择的字段。例如,选择edition、title和author字段,并将查询文档指定为{}。
db.catalog.findOne(
{ },
{ edition: 1, title: 1, author: 1 }
)
列出edition、title和author字段。_id字段总是由查询输出,如图 5-19 所示。

图 5-19。
Using a Query Projection
删除收藏
方法删除一个集合。例如,删除catalog集合。
db.catalog.drop()
随后,show collections方法不列出catalog集合,如图 5-20 所示。

图 5-20。
Dropping a Collection
添加一批文档
以前,我们一次添加一个文档。接下来,我们将添加一批文档。如果在前面的部分中还没有删除,则删除catalog集合。
db.catalog.drop()
使用db.catalog.insert()方法调用添加一个文档数组,其中doc1和doc2与前面相同。writeConcern选项指定了 MongoDB 提供的保证,值“majority”意味着insert()方法直到写入被传播到大多数节点后才返回。将ordered选项设置为true会按指定的顺序添加文件。
db.catalog.insert([doc1, doc2], { writeConcern: { w: "majority", wtimeout: 5000 }, ordered:true })
在前面的方法调用中使用了insert方法的完整语法,如下所示。
db.collection.insert(
<document or array of documents>,
{
writeConcern: <document>,
ordered: <boolean>
}
)
第一个参数是单个文档或文档数组。第二个参数是一个带有字段writeConcern和 ordered 的文档。writeConcern指定了写问题或 MongoDB 在插入成功时提供的保证。ordered参数设置为true,这意味着按照指定的顺序添加文档,如果其中一个文档出现错误,则不添加任何文档。如图 5-21 所示,增加的两个文件,输出中的nInserted为 2。

图 5-21。
Adding a Batch of Documents
运行db.catalog.find()方法查询catalog集合中的文档,如图 5-22 所示。

图 5-22。
Running the find() Method to list Documents added in a Batch
更新文档
db.collection.save()方法具有以下语法,如果文档已经存在,则更新文档,如果文档不存在,则发布新文档。
db.collection.save(
<document>,
{
writeConcern: <document>
}
)
文档由类型ObjectId的唯一_id标识。接下来,我们将把_id更新为ObjectId("507f191e810c19729de860ea")。创建一个更新的 JSON 文档,修改一些字段值。
doc1 = {"_id": ObjectId("507f191e810c19729de860ea"), "catalogId" : 'catalog1', "journal" : 'Oracle Magazine', "publisher" : 'Oracle Publishing', "edition" : '11-12-2013',"title" : 'Engineering as a Service',"author" : 'Kelly, David A.'}
使用catalog集合中的db.collection.save()方法保存文档。
db.catalog.save(doc1,{ writeConcern: { w: "majority", wtimeout: 5000 } })
通过更新现有文档来保存文档。返回的WriteResult对象中nMatched为 1、nUpserted为 0、nModified为 1,如图 5-23 所示。nUpserted字段指的是相对于修改现有文档而言添加的新文档的数量。

图 5-23。
Using the save() Method to Update a Document
使用find()方法查询catalog集合。
db.catalog.find()
更新后的文档被列为图 5-24 所示的文档之一。

图 5-24。
Querying Updated Document
将文档输出为 JSON
db.collection.find(query, projection)方法返回查询选择的文档上的光标。调用游标上的forEach(printjson)方法,以 JSON 格式输出文档。
db.catalog.find().forEach(printjson)
文件以 JSON 的形式输出,如图 5-25 所示。

图 5-25。
Outputting JSON
制作数据备份
mongodump实用程序用于创建数据库中数据的二进制导出。mongorestore实用程序与mongodump结合使用,从备份中恢复数据库。mongorestore实用程序要么创建一个新的数据库实例,要么添加到一个现有的数据库中。
运行下面的mongodump命令,将测试数据库导出到/data/backup目录。
mongodump --db test --out /data/backup
测试数据库被导出到/data/backup目录,如图 5-26 所示。

图 5-26。
Exporting the test Database
列出/data/backup目录中的目录。test数据库目录被列出,如图 5-27 所示。

图 5-27。
Listing the test Database
运行下面的mongorestore命令,将从/data/backup/test导出的数据恢复到testrestore数据库。
mongorestore --db testrestore /data/backup/test
/data/backup/test目录数据被恢复到testrestore数据库中,如图 5-28 所示。

图 5-28。
Restoring a Database
使用以下命令连接到 MongoDB shell。
mongo localhost:27017/testrestore
MongoDB shell 的启动如图 5-29 所示。

图 5-29。
Connecting to the Restored Database
使用以下命令列出数据库。
show dbs
当我们将备份恢复到testrestore数据库时,之前导出的mongodb数据库会被列出,如图 5-30 所示。

图 5-30。
Listing the Restored Database
将数据库名称设置为mongodb。
use mongodb
列出收藏。
show collections
查询catalog集合中的文档。
db.catalog.find()
前述命令的输出如图 5-31 所示。

图 5-31。
Listing and Querying the Restored Collection
删除文档
db.collection.remove方法用于删除文档,其语法如下。
db.collection.remove(
<query>,
<justOne>
)
例如,删除带有ObjectId("561ff033380a18f6587b0aa5")的文档。
db.catalog.remove({ _id: ObjectId("561ff033380a18f6587b0aa5") })
WriteResult中的nRemoved为 1,表示有一个文档被移除。在db.catalog.remove()方法调用前后运行db.catalog.find()方法。在调用db.catalog.remove()方法之前,先列出两个文档,之后只列出一个文档,如图 5-32 所示。

图 5-32。
Removing a Single Document
要删除所有文档,向db.catalog.remove()方法调用提供一个空文档{}。
db.catalog.remove({})
如图 5-33 所示nRemoved值为 2 表示多个文件被移除。

图 5-33。
Removing All Documents
必须为db.catalog.remove()方法调用提供一个空的查询文档。如果没有提供空文档{},则会产生一个错误,指示需要进行查询,如图 5-34 所示。

图 5-34。
An empty document must be provided to the remove() method to remove all documents
停止和重新启动 MongoDB 数据库
运行 MongoDB 实例的 Docker 容器可以用docker stop命令停止。
sudo docker stop mongo
用下面的命令列出正在运行的 Docker 容器。
sudo docker ps
用docker start命令再次启动 Docker 容器。
sudo docker start mongo
再次运行以下命令以列出正在运行的容器。
sudo docker ps
前述命令的输出如图 5-35 所示。停靠容器mongodb再次被列为正在运行。

图 5-35。
Listing a Docker Container after Restarting the Container
使用以下命令启动交互式终端,其中使用容器 ID 而不是容器名称。
sudo docker exec -it 68fe88ca79fe bash
在交互 shell 中用mongo命令启动 MongoDB shell,如图 5-36 所示。

图 5-36。
Starting the MongoDB Shell
将数据库设置为local并用show collections命令列出集合。随后将数据库设置为mongodb,并列出收藏。db.catalog.find()方法不列出任何文件,如图 5-37 所示。

图 5-37。
Listing Documents in the catalog Collection in local Database
退出 Mongo Shell
要退出交互终端,使用“exit”命令,并使用“exit”命令退出 MongoDB shell,也如图 5-38 所示。

图 5-38。
Exiting MongoDB Shell and TTY
摘要
在本章中,我们使用 MongoDB 的 Docker 映像在 Docker 容器中运行 MongoDB 实例。我们创建了一个数据库,将集合添加到数据库中,并将文档添加到集合中。我们还查询了 MongoDB 中的文档。我们演示了停止和启动 Docker 容器。我们还备份了一个 MongoDB 数据库,并随后从备份中恢复了数据库。在下一章,我们将讨论在 Docker 容器中运行另一个 NoSQL 数据库 Apache Cassandra。
六、使用 Apache Cassandra
Apache Cassandra 是一个宽列、开源的 NoSQL 数据库,也是同类中最常用的 NoSQL 数据库。在 Apache Cassandra 中,数据容器相当于关系数据库中的数据库模式,是一个键空间。存储的基本单元是列族(也称为表),表中的每条记录存储在一行中,数据存储在列中。一个列有一个名称、一个值和一个与之相关联的时间戳。存储值不需要列,该列可以是空的。Apache Cassandra 基于灵活的模式(或无模式或动态模式)数据模型,其中不同的行可以有不同的列,并且不需要在表定义中预先指定列。Apache Cassandra 支持列名(称为比较器)和列值(称为验证器)的数据类型,但不要求指定数据类型(验证器和比较器)。定义表(列族)后,可以添加或修改验证器和比较器。Apache Cassandra 为表上的 CRUD(添加、获取、更新、删除)操作提供了一种 Cassandra 查询语言(CQL)。Apache Cassandra 安装包括一个cqlsh实用程序,这是一个交互式 shell,可以从其中运行 CQL 命令。Apache Cassandra 的官方 Docker 映像是可用的,在本章中,我们将在 Docker 容器中运行 Apache Cassandra。
- 设置环境
- 启动 Apache Cassandra
- 启动 TTY
- 连接到 CQL Shell
- 创建密钥空间
- 更改密钥空间
- 使用密钥空间
- 创建表格
- 添加表格数据
- 查询表
- 从表格中删除
- 截断表格
- 放下一张桌子
- 删除一个键空间
- 退出 CQLSh
- 阻止 Apache 卡桑德拉
- 启动 Apache Cassandra 的多个实例
设置环境
本章需要以下软件。
- -Docker(版本 1.8)
- apache cassandra 的 docker image
我们在其他章节中使用了 Amazon EC2 AMI 来安装 Docker 和 Docker 映像。首先,SSH 到 Amazon EC2 实例。
ssh -i "docker.pem" ec2-user@54.86.243.122
安装 Docker 在第一章中讨论。启动 Docker 服务。以下命令应该输出一条 OK 消息。
sudo service docker start
验证 Docker 服务是否已启动。以下命令应该在 active 字段中输出 Active(正在运行)。
sudo service docker status
前述命令的输出如图 6-1 所示。

图 6-1。
Starting Docker Service and verifying Status
接下来,下载最新的cassandra Docker 图片。
sudo docker pull cassandra:latest
列出下载的 Docker 映像。
sudo docker images
cassandra映像应被列出,如图 6-2 所示。

图 6-2。
Listing Docker Image cassandra
启动 Apache Cassandra
使用以下命令在 Docker 容器中启动 Apache Cassandra 服务器进程,其中节点间 Apache Cassandra 集群通信端口指定为 7000,Apache Cassandra 存储数据的目录为/cassandra/data。用–name选项指定容器名为cassandradb。以分离模式启动 Cassandra 实例的语法如下。
docker run --name some-cassandra -d cassandra:tag
–d参数以分离模式启动容器,这意味着即使指定了–t –i选项,交互式 shell 也不会连接到 docker run 命令。
sudo docker run -t -i -v /cassandra/data:/var/lib/cassandra/data --name cassandradb -d -p 7000:7000 cassandra
运行 Apache Cassandra 服务器进程的 Docker 容器启动,如图 6-3 所示。

图 6-3。
Starting Docker Container for Apache Cassandra
用下面的命令列出正在运行的 Docker 容器。
sudo docker ps
运行 Apache Cassandra 服务器实例的cassandradb容器被列出。还列出了容器 id。默认情况下,端口 9042 是 Apache Cassandra 监听客户端连接的客户端端口。端口 9160 是节俭 API,如图 6-4 所示。

图 6-4。
Listing Docker Containers that are Running
启动 TTY
使用以下命令启动交互式终端(tty)。
sudo docker exec -it cassandradb bash
tty 被连接,命令提示符被设置为user@containerid。如果用户是 root,容器 id 是dfade56f871,命令提示符变成root@dfade56f871,如图 6-5 所示。

图 6-5。
Starting the TTY
连接到 CQL Shell
cqlsh 终端用于连接 Apache Cassandra 实例并运行 CQL 命令。使用以下命令启动 cqlsh 终端。
cqlsh
在127.0.0.1:9042建立到测试集群的连接。Apache Cassandra 版本的输出为 2.2.2,CQL 规范版本的输出为 3.3.1。显示cqlsh>命令提示符,如图 6-6 所示。

图 6-6。
Connecting the CQL Shell
我们使用容器名启动了交互式终端,但是 tty 也可以使用容器 id 启动。无论 tty 是如何启动的,cqlsh shell 都是用cqlsh命令启动的。
sudo docker exec –it dfade56f871 bash
cqlsh
cqlsh>命令提示符显示如前,如图 6-7 所示。

图 6-7。
Connecting to CQL Shell using the Container ID
创建密钥空间
键空间是应用数据的容器,用于对列族进行分组。复制是基于每个键空间设置的。创建密钥空间的 DDL 命令如下。
CREATE KEYSPACE (IF NOT EXISTS)? <identifier> WITH <properties>
默认情况下,密钥空间名称不区分大小写,可以只包含字母数字字符,最大长度为 32。要使密钥空间名称区分大小写,请添加引号。创建顶级键空间的CREATE KEYSPACE语句支持的属性是 replication,用于指定复制策略和选项,而durable_writes用于指定提交日志是否用于键空间上的更新,replication 属性是强制的。例如,创建一个名为CatalogKeyspace的键空间,复制策略类为SimpleStrategy,复制因子为 3。
CREATE KEYSPACE CatalogKeyspace
WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 3};
CatalogKeyspace keyspace被创建,如图 6-8 所示。

图 6-8。
Creating a Keyspace
更改密钥空间
ALTER KEYSPACE语句用于改变密钥空间,其语法如下,支持的属性与CREATE KEYSPACE语句相同。
ALTER KEYSPACE <identifier> WITH <properties>
例如,改变CatalogKeyspace键空间,使复制因子为 1。
ALTER KEYSPACE CatalogKeyspace
WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 1};
复制因子被设置为 1,如图 6-9 所示。

图 6-9。
Altering a Keyspace
使用密钥空间
USE 语句用于设置当前密钥空间,其语法如下。
USE <identifier>
所有后续命令都在用USE语句设置的密钥空间的上下文中运行。例如,将当前密钥空间设置为CatalogKeyspace。
use CatalogKeyspace;
cqlsh>命令提示符变为cqlsh:catalogkeyspace>,如图 6-10 所示。

图 6-10。
Using a Keyspace
创建表格
表也称为COLUMN FAMILY,CREATE TABLE或CREATE COLUMN FAMILY语句用于创建表(列族)。
CREATE ( TABLE | COLUMNFAMILY ) ( IF NOT EXISTS )? <tablename>
'(' <column-definition> ( ',' <column-definition> )* ')'
( WITH <option> ( AND <option>)* )?
关于CREATE TABLE语句的完整语法,请参考 cassandra。Apache。org/ doc/ cql3/ CQL。html#createTableStmt 。例如,创建一个名为“catalog”的表,其中包含类型为 text 的列catalog_id、journal、publisher、edition、title和author。指定主键为catalog_id,设置压缩类为LeveledCompactionStrategy。
CREATE TABLE catalog(catalog_id text,journal text,publisher text,edition text,title text,author text,PRIMARY KEY (catalog_id)) WITH compaction = { 'class' : 'LeveledCompactionStrategy' };
catalog表被创建,如图 6-11 所示。

图 6-11。
Creating a Table
添加表格数据
INSERT DML 语句用于向表中添加数据,其语法如下。
INSERT INTO <tablename>
'(' <identifier> ( ',' <identifier> )* ')'
VALUES '(' <term-or-literal> ( ',' <term-or-literal> )* ')'
( IF NOT EXISTS )?
( USING <option> ( AND <option> )* )?
关于INSERT语句的完整语法,请参考 https://cassandra.apache.org/doc/cql3/CQL.html#insertStmt 。例如,向目录表中添加两行数据,并包含IF NOT EXISTS子句,以便在主键标识的行不存在时添加一行。
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;
如[applied] True输出所示,两行数据相加,如图 6-12 所示。

图 6-12。
Adding Table Data
查询表
具有以下语法的SELECT语句用于查询一个表。
SELECT <select-clause>
FROM <tablename>
( WHERE <where-clause> )?
( ORDER BY <order-by> )?
( LIMIT <integer> )?
( ALLOW FILTERING )?
关于SELECT语句的完整语法,请参考 cassandra。Apache。org/ doc/ cql3/ CQL。html#selectStmt 。例如,从catalog表中选择所有列。
SELECT * FROM catalog;
先前添加的两行数据被列出,如图 6-13 所示。

图 6-13。
Querying Table
从表格中删除
DELETE语句用于删除列和行,其语法如下。
DELETE ( <selection> ( ',' <selection> )* )?
FROM <tablename>
( USING TIMESTAMP <integer>)?
WHERE <where-clause>
( IF ( EXISTS | ( <condition> ( AND <condition> )*) ) )?
关于DELETE语句的完整语法,请参考 cassandra。Apache。org/ doc/ cql3/ CQL。html # deletes mt。例如,从带有catalog_id作为catalog1的行中删除所有列。
DELETE catalog_id, journal, publisher, edition, title, author from catalog WHERE catalog_id='catalog1';
随后,用SELECT语句查询catalog表。
SELECT * FROM catalog;
带有作为catalog1的catalog_id的行的列值被删除,但是包括主键列值的行本身没有被删除,即使主键catalog_id被列为要删除的列之一。后续查询列出了主键列值,但将其他列的列值列为空,如图 6-14 所示。

图 6-14。
Deleting Table Data
截断表格
TRUNCATE语句从表中删除所有数据,其语法如下。
TRUNCATE <tablename>
例如,截断catalog表。随后,使用SELECT语句运行查询。
TRUNCATE catalog;
SELECT * from catalog;
如查询输出所示,没有列出任何数据,因为TRUNCATE语句已经删除了所有数据,如图 6-15 所示。

图 6-15。
Truncating a Table
放下一张桌子
DROP TABLE或DROP COLUMN FAMILY语句用于删除表,其语法如下。
DROP TABLE ( IF EXISTS )? <tablename>
例如,删除catalog表。
DROP TABLE IF EXISTS catalog;
如果没有指定IF EXISTS子句,并且该表不存在,则会生成一个错误。但是有了IF EXISTS子句,如图 6-16 中包含的 IF EXISTS子句的两个连续运行的DROP TABLE语句所示,不会产生错误。

图 6-16。
Dropping a Table
删除一个键空间
具有以下语法的DROP KEYSPACE语句删除指定的键空间,包括键空间中的列族和列族中的数据,并且键空间在被删除之前不必为空。
DROP KEYSPACE ( IF EXISTS )? <identifier>
例如,删除CatalogKeyspace键空间。
DROP KEYSPACE IF EXISTS CatalogKeyspace;
如果没有指定IF EXISTS子句,并且密钥空间不存在,则会生成一个错误。但是有了IF EXISTS子句,如图 6-17 所示,包含IF EXISTS子句的两个连续运行的DROP KEYSPACE语句所指示的错误不会产生。

图 6-17。
Dropping a Keyspace
退出 CQL 壳牌
要退出 cqlsh shell,指定退出命令,如图 6-18 所示。随后也用exit命令退出 tty。

图 6-18。
Exiting CQL Shell
阻止 Apache 卡桑德拉
要停止 Apache Cassandra,请停止运行 Apache Cassandra 服务器的 Docker 容器。
sudo docker stop cassandradb
随后,运行以下命令列出正在运行的容器。
sudo docker ps
如图 6-19 所示,cassndradb容器未被列为运行中。

图 6-19。
Stopping Cassandra DB Docker Container
启动 Apache Cassandra 的多个实例
可以启动多个运行 Apache Cassandra 实例的 Docker 容器,但是容器名必须是唯一的。例如,启动一个新的 Docker 容器,也称为cassandradb来运行 Apache Cassandra 数据库的另一个实例。
sudo docker run -t -i -v /cassandra/data:/var/lib/cassandra/data --name cassandradb -d -p 7000:7000 cassandra
因为之前已经创建了一个同名(cassandradb)的 Docker 容器,所以即使容器已经停止,也会产生错误,如图 6-20 所示。必须用docker rm命令删除一个容器,才能创建一个同名的新容器。

图 6-20。
Duplicate Docker Container name error
例如,可以启动另一个具有不同名称cassandradb2的容器。
sudo docker run -t -i -v /cassandra/data:/var/lib/cassandra/data --name cassandradb2 -d -p 7000:7000 cassandra
启动第三个容器,并指定用于运行集群中多个节点的 IP 地址的CASSANDRA_SEEDS环境变量(如果需要)。
sudo docker run -t -i -v /cassandra/data:/var/lib/cassandra/data --name cassandradb3 -d -p 7000:7000 -e CASSANDRA_SEEDS=52.91.214.50,54.86.243.122,54.86.205.95 cassandra
随后,运行以下命令列出正在运行的容器。
sudo docker ps
cassandradb2和cassandradb3容器被列为运行中,如图 6-21 所示。

图 6-21。
Running Multiple Docker Containers for Instances of Apache Cassandra
摘要
在本章中,我们使用 Apache Cassandra 的 Docker 映像在 Docker 容器中运行 Apache Cassandra。我们在 cqlsh shell 中使用不同的 CQL 语句来创建一个键空间,在键空间中创建一个表,并向表中添加数据。我们还运行了 CQL 语句来查询表、删除表中的数据、截断表、删除表和删除键空间。我们还演示了如何创建多个 Docker 容器来运行 Apache Cassandra 的多个实例。在下一章,我们将在 Docker 中运行 Couchbase 服务器。
七、使用 Couchbase 服务器
Couchbase 服务器是一个分布式 NoSQL 数据库。Couchbase 是一个基于 JSON (JavaScript Object Notation)的文档库。像其他 NoSQL 数据存储一样,Couchbase 没有固定的数据存储模式。Couchbase 与 MongoDB 的不同之处在于,MongoDB 基于 BSON(二进制 JSON)文档数据模型。Couchbase 提供了一个 Web 控制台,用于从图形用户界面(GUI)访问 Couchbase 服务器。Couchbase 还提供了一个命令行界面(CLI ),包括几个在 CLI 中运行的工具。在本章中,我们将在 Docker 容器中运行 Couchbase 服务器。
- 设置环境
- 启动 Couchbase
- 访问 Couchbase Web 控制台
- 配置 Couchbase 服务器
- 添加文档
- 启动交互式终端
- 运行 Couchbase CLI 工具
- 停止 Couchbase 服务器
设置环境
本章需要以下软件。
- -Docker(版本 1.8)
- Couchbase 的 Docker 映像(最新版本)
我们在本章中使用了图 7-1 所示的 Ubuntu 服务器 AMI 来运行软件。附录 a 中讨论了 Amazon EC2 实例的安装和配置。

图 7-1。
Ubuntu Server AMI
使用用户“Ubuntu”和 Amazon EC2 实例的公共 IP 地址 SSH 登录到 Ubuntu Amazon EC2 实例。对于不同的用户,公共 IP 地址会有所不同(根据所讨论的示例的多次运行,本章还使用了多个公共 IP 地址)。
ssh -i "docker.pem" ubuntu@54.152.90.139
我们需要修改主机 IP 地址文件/etc/hosts中localhost的 IP 地址设置。将 IP 地址设置为 Amazon EC2 实例的公共 IP 地址。获取 Amazon EC2 实例的公共 IP 地址在附录 a 中讨论。在 vi 编辑器中打开/etc/hosts文件。
sudo vi /etc/hosts
将“127.0.0.1”替换为公有 IP 地址;替换以下行:
127.0.0.1 localhost
与:
54.152.90.139 localhost
按照第一章中的讨论在 Ubuntu 上安装 Docker。运行hello-world Docker 映像来测试 Docker 安装。
sudo docker run hello-world
hello-world应用的输出如图 7-2 所示。

图 7-2。
Output from hello-world
下载名为“Couchbase”的官方 Couchbase Docker 图片。
sudo docker pull couchbase
下载最新的 Docker 映像,如图 7-3 所示。

图 7-3。
Downloading Docker Image couchbase
启动 Couchbase
接下来,运行 Docker 映像“couchbase”的 Docker 容器,这将在 Docker 容器中启动一个 Couchbase 服务器进程。运行以下 docker 命令,其中 Couchbase Web 控制台连接到 Couchbase 服务器的端口被指定为 8091。容器名被指定为“couchbasedb”。
sudo docker run --name couchbasedb -d -p 8091:8091 couchbase
Couchbase 服务器可能需要非默认的 ulimit 设置。
| Ulimit 设置 | 价值 | 描述 | | --- | --- | --- | | mmit -n | Forty thousand nine hundred and sixty | nofile:打开文件的最大数量 | | 乌利米特-c | One hundred million | 核心:最大核心文件大小。100000000 设置相当于“无限制”,不直接支持。 | | 尤利姆-l | One hundred million | memlock:最大锁定内存地址空间。100000000 设置相当于“无限制”,不直接支持。 |Docker 容器将所有持久数据存储在/opt/couchbase/var目录中,可以使用–v命令参数从主机挂载这些数据。–ulimit命令参数用于设置docker run命令。运行以下命令来运行 Docker 容器以运行 Couchbase 服务器,如图 7-4 所示。
sudo docker run --name couchbasedb -v ∼/couchbase/data:/opt/couchbase/var -d --ulimit nofile=40960:40960 --ulimit core=100000000:100000000 --ulimit memlock=100000000:100000000 -p 8091:8091 couchbase
随后,列出正在运行的 Docker 容器。
sudo docker ps
couchbasedb 容器被列出,如图 7-4 所示。

图 7-4。
Running Docker Container for Couchbase
用docker logs命令输出容器的日志。
sudo docker logs couchbasedb
显示如图 7-5 所示的信息。

图 7-5。
Listing Docker Container Log
访问 Couchbase Web 控制台
接下来,我们将从logs: http://<ip>:8091中指示的 URL 访问 Couchbase Web 控制台。使用的<ip>地址会因 Web 控制台访问的主机系统而异。如果在运行 Docker 容器的主机上,使用主机 Amazon EC2 实例的公共 IP 地址。如果在我们访问的远程主机系统上,使用 Amazon EC2 实例的公共 DNS。获取公共 IP 地址和公共 DNS 在附录 a 中讨论。如果公共 DNS 是ec2-54-152-90-139.compute-1.amazonaws.com,,则访问 Couchbase WebConsole 的 URL 变为如下。
http://ec2-54-152-90-139.compute-1.amazonaws.com:8091
在前面的 URL 打开浏览器。床座控制台显示如图 7-6 所示。在下一节中,我们将设置一个 Couchbase 服务器集群。

图 7-6。
Accessing Couchbase Admin Console
如果已经配置了 Couchbase 集群,Couchbase 控制台 URL 将显示如图 7-7 所示的登录页面。

图 7-7。
Login Page
指定用户名(管理员)和密码,点击登录,如图 7-8 所示。

图 7-8。
Specifying Username and Password
配置 Couchbase 服务器群集
在本节中,我们将配置 Couchbase 服务器集群。如前所述访问 Couchbase Web 控制台,如图 7-6 所示,URL 为 http://ec2-54-152-90-139.compute-1.amazonaws.com:8091 。单击 Web 控制台中的设置;只有首次访问 Web 控制台时,才会显示“设置”页面。随后,配置完集群后,将显示登录页面,如前一节所述。
使用配置磁盘存储部分的默认设置。在 Configure Server Hostname 中,将主机名指定为 Amazon EC2 实例的公共 IP 地址,这对于不同的用户是不同的,如图 7-9 所示。主机名字段不接受短名称,主机名中至少需要一个点。

图 7-9。
Configuring Server
“加入集群/启动新集群”部分提供了两个选项。由于我们正在配置一个新的集群,选择启动一个新的集群,如图 7-10 所示。选择默认设置或修改设置,同时考虑每台服务器可配置的总 RAM。点击下一步。

图 7-10。
Starting a New Cluster
Couchbase 服务器将数据存储在数据桶中。样本桶部分列出了样本桶。不需要选择样本桶。点击下一步。在创建默认存储桶屏幕中,存储桶名称被预先指定为“默认”。选择铲斗类型为“Couchbase”。选择默认的内存大小和副本设置。还要选择默认的磁盘 I/O 优化设置。

图 7-11。
Configuring the Default Cluster
在 Flush 中选择 Enable 并点击 Next,如图 7-12 所示。为了能够从存储桶中刷新(删除)数据,必须启用“刷新”。

图 7-12。
Enabling Flush
在通知中,选择默认设置和“我同意…”复选框,然后单击下一步,如图 7-13 所示。

图 7-13。
Configuring Notifications
在 Secure this Server 屏幕中,将用户名指定为 Administrator(默认设置),如图 7-14 所示。在密码字段中指定密码,并在验证密码字段中指定相同的密码。点击下一步。

图 7-14。
Specifying Username and Password
点击集群概述选项卡,显示集群摘要,包括分配和使用的 RAM,以及分配和使用的磁盘存储,如图 7-15 所示。

图 7-15。
Displaying Cluster Summary
在图 7-16 中,一个存储桶显示为活动的,一个服务器显示为活动的。

图 7-16。
Displaying Servers Summary
单击服务器节点以列出服务器节点。运行在 IP 地址172.17.0.1的服务器列表如图 7-17 所示。

图 7-17。
Listing Server IP Address
单击“数据桶”选项卡。“默认”铲斗被列出,如图 7-18 所示。

图 7-18。
Listing the Default Buckets
添加文档
在这一节中,我们将从 Couchbase 控制台向 Couchbase 服务器添加文档。点击默认桶的文档按钮,如图 7-19 所示。

图 7-19。
Clicking on the Documents button
在默认的➤文档中,一开始没有列出任何文档。点击创建文件按钮,如图 7-20 所示。

图 7-20。
Clicking on ‘Create Document’
在创建文档对话框中指定一个文档 ID,例如目录 1,然后点击创建,如图 7-21 所示。

图 7-21。
Creating a Document
Id 为catalog1的 JSON 文档被添加到默认桶中,如图 7-22 所示。新文档有一些默认字段,可能需要修改。

图 7-22。
New Document with ID as catalog1
用下面的 JSON 文档替换示例 JSON 文档。
{
"journal": "Oracle Magazine",
"publisher": "Oracle Publishing",
"edition": "November-December 2013",
"title": "Quintessential and Collaborative",
"author": "Tom Haunert"
}
点击【保存】,保存修改后的 JSON 文档,如图 7-23 所示。

图 7-23。
Saving a Couchbase Document
JSON 文档在 Couchbase 控制台中保存并格式化,如图 7-24 所示。

图 7-24。
Formatted JSON Document
在 Couchbase 存储桶中,“默认”存储桶的项目计数被列为 1,如图 7-25 所示。单击“文档”按钮,在默认存储桶中显示文档。

图 7-25。
Item Count for default Bucket
catalog1文件列表如图 7-26 所示。如果需要,单击编辑文档按钮显示文档 JSON。

图 7-26。
Listing Documents in the default Bucket
类似地,添加文档 id 为 catalog2 的另一个文档。catalog2文档的 JSON 如下。
{
"journal": "Oracle Magazine",
"publisher": "Oracle Publishing",
"edition": "November December 2013",
"title": "Engineering as a Service",
"author": "David A. Kelly",
}
像我们为 catalog1 文档所做的那样,为catalog2的样本文档添加 JSON,并点击保存,如图 7-27 所示。

图 7-27。
Adding another JSON Document
两个文件catalog1和catalog2被列出,如图 7-28 所示。

图 7-28。
Listing the Two Documents Added
启动交互式终端
要从命令行访问 Couchbase 服务器,请启动交互式终端(tty)。
sudo docker exec -it couchbasedb bash
交互外壳启动,如图 7-29 所示。

图 7-29。
Starting the Interactive Shell
也可以使用容器 id 而不是容器名称来启动交互式终端。
sudo docker exec -it bff916e55a52 bash
运行 Couchbase CLI 工具
Couchbase Server 提供了几个命令行界面工具(CLI)来监控和管理 Couchbase 服务器桶、节点和集群。
这些 CLI 工具包括用于整个集群操作的couchbase-cli工具、用于创建备份的cbbackup工具、用于加载 JSON 文档的cbdocloader工具以及用于在集群和主机上的数据文件之间传输数据的cbtransfer工具。
例如,使用下面的命令从 tty 运行,运行cbtransfer工具将数据从 Couchbase 服务器传输到 stdout。
cbtransferhttp://ec2-54-152-90-139.compute-1.amazonaws.com:8091/
之前从 Couchbase 控制台添加到 Couchbase 集群的两个 JSON 文档获得了 stdout 输出,如图 7-30 所示。

图 7-30。
Running cbtransfer
停止 Couchbase 服务器和容器
要停止 Couchbase 服务器和容器,使用exit命令退出交互终端,如图 7-31 所示。

图 7-31。
Stopping Couchbase Server
在主机系统中,运行docker stop命令来停止 Docker 容器。
sudo docker stop couchbasedb
随后,列出正在运行的 Docker 容器。
sudo docker ps
couchbasedb容器未列出,如图 7-32 所示。

图 7-32。
The Docker Container for couchbasedb does not get listed
摘要
在本章中,我们使用 Couchbase Server 的官方 Docker 映像在 Docker 容器中运行一个 Couchbase Server 实例。我们从 Couchbase 控制台访问 Couchbase 服务器,并添加了一些 JSON 文档。随后,我们使用cbtransfer CLI 工具将存储的文档输出到 stdout。在下一章,我们将讨论如何使用 Apache Hadoop。
八、使用 Apache Hadoop
Apache Hadoop 是处理大型数据集的事实上的框架。Apache Hadoop 是一个分布式软件应用,运行在一个集群中的几个(多达成百上千个)节点上。Apache Hadoop 由两个主要组件组成:Hadoop 分布式文件系统(HDFS)和 MapReduce。HDFS 用于存储大型数据集,MapReduce 用于处理大型数据集。Hadoop 可以线性扩展而不会降低性能,并且利用商用硬件而不是任何专用硬件。Hadoop 旨在容错,并通过将计算转移到数据而不是将数据转移到计算来利用数据局部性。MapReduce 框架有两个版本 MapReduce1 (MR1)和 MapReduce2 (MR2)(也叫 YARN)。MR1 是 Hadoop 早期版本(Hadoop 1.x)的默认 MapReduce 框架,YARN 是 Hadoop 后期版本(Hadoop 2.x)的默认 MapReduce 框架。
- 设置环境
- 启动 Hadoop
- 启动交互式 Shell
- 为 MapReduce 字数统计应用创建输入文件
- 运行 MapReduce 字数统计应用
- 停止 Hadoop Docker 容器
- 使用 CDH 坞站映像
设置环境
本章使用了以下软件。
- -Docker(版本 1.8)
- Apache Hadoop 坞站映像
- -Cloudera Hadoop (CDH)坞站映像
在其他章节中,我们使用了一个基于 Red Hat Enterprise Linux 7.1 (HVM)、SSD 卷类型 ami-12663b7a 的 Amazon EC2 实例来安装软件。到 Amazon EC2 实例的 SSH 登录。
ssh -i "docker.pem" ec2-user@52.23.207.240
按照第一章所述安装 Docker。启动 Docker 服务。
sudo service docker start
OK 消息表明 Docker 服务已经启动,如图 8-1 所示。

图 8-1。
Starting the Docker Service
添加一个名为“hadoop”的组和一个名为“hadoop”的用户。
groupadd hadoop
useradd -g hadoop hadoop
Apache Hadoop 有几个 Docker 映像。我们使用了 Docker Hub 上的sequenceiq/hadoop-docker Docker 映像。下载标签为 2.7.0 的 Docker 映像或最新的标签映像(如果不同)。
sudo dock pull sequence IQ/Hadoop dock:2 . 7 . 0
docker pull命令如图 8-2 所示。

图 8-2。
Running the docker pull Command
Docker 映像sequenceiq/hadoop-docker被下载,如图 8-3 所示。

图 8-3。
Downloading Docker Image sequenceiq/hadoop-docker
启动 Hadoop
接下来,启动 Hadoop 组件 HDFS 和 MapReduce。Docker 映像sequenceiq/hadoop-docker默认配置为启动 YARN 或 MR2 框架。运行下面的docker run命令,以分离模式启动 Docker 容器,启动 HDFS (NameNode 和 DataNode)和 YARN (ResourceManager 和 NodeManager)。
sudo docker run -d --name hadoop sequenceiq/hadoop-docker:2.7.0
随后,列出正在运行的 Docker 容器。
sudo docker ps
前面两个命令的输出如图 8-4 所示,包括基于sequenceiq/hadoop-docker映像的 Apache Hadoop 的运行 Docker 容器。Docker 容器名为“hadoop”,容器 id 为“27436aa7c645”。

图 8-4。
Running Docker Container for Apache Hadoop
启动交互式 Shell
使用以下命令启动交互式 shell 或终端(tty)。
sudo docker exec -it hadoop bash
显示如图 8-5 所示的交互终端提示。

图 8-5。
Starting Interactive Terminal
也可以使用容器 id 而不是容器名称来启动交互式外壳。
sudo docker exec -it 27436aa7c645 bash
如果docker run命令中省略了–d命令参数,并且使用以下命令提供了–it参数(与–i和–t一起提供), Docker 容器将以前台模式启动。
sudo docker run -it --name hadoop sequenceiq/hadoop-docker:2.7.0 /etc/bootstrap.sh –bash
Hadoop 组件启动并将控制台连接到 Hadoop 标准输入、标准输出和标准错误流,如图 8-6 所示。对于每个启动的 Hadoop 组件,控制台都会输出一条消息。–it参数启动交互终端(tty)。

图 8-6。
Starting Docker Container in Foreground
为 MapReduce 字数统计应用创建输入文件
在本节中,我们将为 MapReduce Word Count 应用创建输入文件,该应用包含在 Hadoop 发行版打包的示例中。要创建输入文件,请将目录(cd)更改为$HADOOP_PREFIX目录。
bash-4.1# cd $HADOOP_PREFIX
如图 8-7 所示,前面的命令将从交互终端(tty)运行。

图 8-7。
Setting Current Directory to $HADOOP_PREFIX Directory
在 HDFS 中为输入文件创建一个名为/input的目录。随后,将目录权限设置为全局(777)。
bash-4.1# bin/hdfs dfs -mkdir /input
bash-4.1# bin/hdfs dfs -chmod -R 777 /input
前面的命令也从交互终端运行,如图 8-8 所示。

图 8-8。
Creating Input Directory
向/input目录添加两个文本文件(input1.txt和input2.txt)和一些示例文本。要创建一个文本文件input1.txt,在 tty 中运行下面的 vi 编辑器命令。
vi input1.txt
在input1.txt中添加以下两行文本。
Hello World Application for Apache Hadoop
Hello World and Hello Apache Hadoop
使用: wq命令保存input1.txt文件,如图 8-9 所示。

图 8-9。
The input1.txt File
用下面的命令将 input1.txt 文件放到 HDFS 目录/input中,也如图 8-10 所示。
bin/hdfs dfs -put input1.txt /input
input1.txt文件被添加到 HDFS 的/input目录中。

图 8-10。
Putting the input1.txt in the HDFS
类似地,用下面的 vi 命令打开另一个新的文本文件input2.txt。
vi input2.txt
在input2.txt文件中添加以下两行文本。
Hello World
Hello Apache Hadoop
使用:wq命令保存input2.txt文件,如图 8-11 所示。

图 8-11。
The input2.txt File
将input2.txt文件放到 HDFS 目录/input中。
bin/hdfs dfs -put input2.txt /input
随后,运行以下命令来运行/input目录中的文件。
bin/hdfs –ls /input
添加到 HDFS 的两个文件被列出,如图 8-12 所示。

图 8-12。
Listing the Input Files in the HDFS
运行 MapReduce 字数统计应用
在本节中,我们将运行一个 MapReduce 应用进行字数统计;应用打包在hadoop-mapreduce-examples-2.7.0.jar文件中,可以用参数“wordcount”调用。wordcount应用要求提供输入和输出目录。输入目录是我们之前创建的 HDFS 中的/input目录,输出目录是/output,它在运行 hadoop 命令之前必须不存在。从交互式 shell 中运行下面的hadoop命令。
bin/hadoop jar $HADOOP_PREFIX/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.0.jar wordcount /input /output
MapReduce 作业使用 YARN 框架开始,如图 8-13 所示。

图 8-13。
Starting MapReduce Application with YARN Framework
纱线作业完成,如图 8-14 所示,字数统计应用输出到 HDFS 的/output目录。

图 8-14。
Output from the MapReduce Application
hadoop命令的完整输出如下。
<mapreduce/hadoop-mapreduce-examples-2.7.0.jar wordcount /input /output
15/10/18 15:46:17 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032
15/10/18 15:46:19 INFO input.FileInputFormat: Total input paths to process : 2
15/10/18 15:46:19 INFO mapreduce.JobSubmitter: number of splits:2
15/10/18 15:46:20 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1445197241840_0001
15/10/18 15:46:21 INFO impl.YarnClientImpl: Submitted application application_1445197241840_0001
15/10/18 15:46:21 INFO mapreduce.Job: The url to track the job: http://fb25c4cabc55:8088/proxy/application_1445197241840_0001/
15/10/18 15:46:21 INFO mapreduce.Job: Running job: job_1445197241840_0001
15/10/18 15:46:40 INFO mapreduce.Job: Job job_1445197241840_0001 running in uber mode : false
15/10/18 15:46:40 INFO mapreduce.Job: map 0% reduce 0%
15/10/18 15:47:03 INFO mapreduce.Job: map 100% reduce 0%
15/10/18 15:47:17 INFO mapreduce.Job: map 100% reduce 100%
15/10/18 15:47:18 INFO mapreduce.Job: Job job_1445197241840_0001 completed successfully
15/10/18 15:47:18 INFO mapreduce.Job: Counters: 49
File System Counters
FILE: Number of bytes read=144
FILE: Number of bytes written=345668
FILE: Number of read operations=0
FILE: Number of large read operations=0
FILE: Number of write operations=0
HDFS: Number of bytes read=324
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)=41338
Total time spent by all reduces in occupied slots (ms)=11578
Total time spent by all map tasks (ms)=41338
Total time spent by all reduce tasks (ms)=11578
Total vcore-seconds taken by all map tasks=41338
Total vcore-seconds taken by all reduce tasks=11578
Total megabyte-seconds taken by all map tasks=42330112
Total megabyte-seconds taken by all reduce tasks=11855872
Map-Reduce Framework
Map input records=6
Map output records=17
Map output bytes=178
Map output materialized bytes=150
Input split bytes=212
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)=834
CPU time spent (ms)=2760
Physical memory (bytes) snapshot=540696576
Virtual memory (bytes) snapshot=2084392960
Total committed heap usage (bytes)=372310016
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=112
File Output Format Counters
Bytes Written=60
bash-4.1#
用下面的命令列出 HDFS 目录中的输出文件。
bin/hdfs dfs -ls /output
列出两个文件:_SUCCESS,表示纱线作业成功完成,part-r-00000,是wordcount应用的输出,如图 8-15 所示。

图 8-15。
Files Output by the YARN Application
使用以下命令列出wordcount应用的输出。
hdfs dfs -cat /output/part-r-00000
输入文件input1.txt和input2.txt中每个不同单词的字数得到输出,如图 8-16 所示。

图 8-16。
Listing the Word Count
停止 Hadoop Docker 容器
可以使用docker stop命令停止运行 Hadoop 进程的 Docker 容器。
sudo docker stop hadoop
随后运行docker ps命令,没有容器被列为运行中,如图 8-17 所示。

图 8-17。
Listing Running Docker Containers after stopping Apache Hadoop Container
使用 CDH 坞站映像
如前所述,Apache Hadoop 有几个 Docker 映像可用。另一个 Docker 映像是svds/cdh Docker 映像,我们也将在随后的章节中使用,它基于由名为 CDH 的 Cloudera Hadoop 发行版打包的 Apache Hadoop 生态系统。svds/cdh映像不仅包括 Apache Hadoop,还包括 Apache Hadoop 生态系统中的几个框架,其中一些将在后面的章节中讨论。用下面的命令下载svds/cdh镜像。
sudo docker pull svds/cdh
启动一个运行 CDH 框架的 Docker 容器。
sudo docker run -d --name cdh svds/cdh
启动交互式终端来运行 CDH 框架的命令。
sudo docker exec -it cdh bash
在 tty 中,Hadoop 框架应用无需进一步配置即可运行。例如,在命令行上运行带有“hdfs”的 HDFS 命令。hdfs命令的用法如下。
hdfs
HDFS 命令用法得到如图 8-18 所示的输出。

图 8-18。
hdfs Command Usage
配置文件在/etc/hadoop/conf符号链接中,如图 8-19 所示。

图 8-19。
Listing the Symlink for the Configuration Directory
图 8-20 列出了conf符号链接指向的/etc/alternatives/hadoop-conf目录下的配置文件如下。

图 8-20。
Listing the Configuration Files
可使用docker stop命令停止 cdh 容器。
sudo docker stop cdh
摘要
在本章中,我们在 Docker 容器中运行了 Apache Hadoop 组件。我们创建了一些文件,并把这些文件放在 HDFS。随后,我们运行了一个与 Hadoop 发行版中的示例打包在一起的 MapReduce wordcount应用。我们还介绍了基于 Cloudera Hadoop 发行版(CDH)的 Docker 映像,我们还将在基于 Apache Hadoop 生态系统框架的后续章节中使用它。
九、使用 Apache Hive
Apache Hive 是用于存储、管理和查询大型数据集的数据仓库框架。HiveQL 是一种类似 SQL 的语言。默认情况下,Hive 将数据存储在 HDFS 中,并且可以使用 Hive 表来定义数据的结构。Hive 支持两种表:托管表和外部表。托管表由 Hive 框架管理,而外部表则不是。删除托管表时,元数据和表数据也会被删除。当删除配置单元外部表时,仅删除元数据,而不删除表数据,因为表数据不由配置单元框架管理。Hive 利用 metastore 来存储有关 Hive 表的元数据。配置单元 metastore 数据库用于 metastore,默认情况下是 Derby 数据库。metastore 数据库可以在嵌入式模式或远程模式下运行;默认为嵌入式模式。在本章中,我们将使用一个 Docker 映像来运行 Docker 容器中的 Apache Hive。
- 设置环境
- 正在启动 Apache Hive
- 连接到直线 CLI 外壳
- 连接到 HiveServer2
- 创建配置单元表
- 将数据加载到配置单元表中
- 查询配置单元表
- 停止 Apache 蜂房
设置环境
本章需要以下软件。
- -Docker(使用 1.8 版)
- apache hive 的 docker image
我们使用 Amazon EC2 实例来安装软件。按照第一章所述安装 Docker。SSH 连接到 Amazon EC2 实例。
ssh -i "docker.pem" ec2-user@52.23.241.186
启动 Docker 服务并验证 Docker 服务的状态。
sudo service docker start
sudo service docker status
下载svds/cdh Docker 镜像,它与 Apache HBase、Apache Sqoop 和 Apache Spark 上的一些其他 Apache Hadoop 生态系统章节中使用的镜像相同。
sudo docker pull svds/cdh
正在启动 Apache Hive
要启动 Apache Hive,请启动一个运行cdh进程或组件的 Docker 容器。运行下面的docker run命令,该命令以分离模式启动 Docker 容器,并将名称“cdh”分配给容器。
sudo docker run -d --name cdh svds/cdh
列出正在运行的 Docker 容器;应该会列出“cdh”容器。
sudo docker ps
启动一个交互式终端来运行 Apache Hive shell 命令。
sudo docker exec -it cdh bash
连接到直线 CLI 外壳
Apache Hive 提供了 Hive CLI 来从命令行界面访问 HiveServer1。在 Hive 的较新版本中,HiveServer1 已被弃用,并被替换为 HiveServer2,Hive CLI 已被弃用,并被替换为 Beeline CLI。Hive CLI 是一个基于 Apache Thrift 的客户端,而 Beeline 是一个基于 SQLLine CLI 的 JDBC 客户端。对于 Beeline,仍然使用 Thrift API,但不是直接从客户端使用;JDBC 驱动程序使用 Thrift API 与 HiveServer2 通信。
在使用 Hive CLI 或 Beeline CLI 之前,我们需要修改 Hive 存储其数据的 HDFS 目录的权限,这个目录就是/user/hive/warehouse目录。在/user/hive/warehouse目录上设置全局权限(777)。
hdfs dfs –chmod –R 777 /user/hive/warehouse
前面的命令在交互终端中运行,如图 9-1 所示。

图 9-1。
Setting Permissions on the Hive Warehouse Directory
如果要使用 Hive CLI,请在交互式终端中运行以下命令。
hive
配置单元 CLI 已启动。如图 9-2 所示,还会输出一条警告消息,指出 Hive CLI 已被否决,建议迁移到 Beeline。

图 9-2。
Message about Migration to Beeline
我们将在本章中使用直线 CLI。使用exit或quit命令退出 Hive CLI。使用以下命令启动直线 CLI。
beeline
直线版本 1.1.0 CDH 5.4.3 开始如图 9-3 所示。

图 9-3。
Starting Beeline
连接到 HiveServer2
我们在上一节中启动了 Beeline CLI,但是我们还没有连接到 HiveServer2。要进行演示,请运行以下命令。
use default;
show tables;
输出“无电流连接”信息,如图 9-4 所示。

图 9-4。
Message “No Current Connection”
要连接到 HiveServer2,我们需要运行!connect命令。!connect命令用途可通过以下命令输出。
!connect
!connect命令用法得到如图 9-5 所示的输出。

图 9-5。
Command Usage for !connect
HiveServer2 可以以两种模式之一连接:嵌入式或远程。如果 Beeline CLI 在安装了 Hive 的同一台计算机上运行,则可以使用嵌入式模式。如果 Beeline CLI 在配置单元的远程机器上,则必须使用远程模式。我们将使用嵌入式模式。连接 url 的语法如下,其中dbName是 Hive 数据库,<host>和<port>是 HiveServer2 的主机名和端口号。
jdbc:hive2://<host>:<port>/dbName
运行下面的直线命令!connect,其中首先指定到 HiveServer2 的连接 url,然后是用户名、密码和 Hive JDBC 驱动程序。对于默认用户名、密码和配置单元 JDBC 驱动程序,请指定空字符串“”。默认的 Hive JDBS 驱动程序是org.apache.hive.jdbc.HiveDriver。
!connect jdbc:hive2://localhost:10000/default "" "" ""
如图 9-6 所示,建立了到 Apache Hive 1.1.0 的连接。Apache Hive 1.1.0 版本是重新命名的 Hive 0.15.0 版本。

图 9-6。
Connecting with Hive2 Server
以前不运行的直线命令在连接到 HiveServer2 后会运行。再次运行以下命令,将数据库设置为“默认”并列出配置单元表。
use default
show tables
数据库被设置为默认值,并列出配置单元表。该数据库已经是连接 url 中指定的“默认”数据库,并且运行use default命令来演示该命令的运行。没有列出任何表格,因为还没有创建任何表格,如图 9-7 所示。我们将在下一部分创建一个表。

图 9-7。
Listing Tables
创建配置单元表
在本节中,我们将创建一个名为“wlslog”的配置单元表,其中包含列time_stamp、category、type、servername、code和msg,,所有列的类型都是string。Hive 使用序列化器/反序列化器,也称为 Serde。可以使用自定义 Serde,也可以使用本地 Serde。如果没有指定ROW FORMAT,则使用本地 Serde。如果为带分隔符的数据文件指定了ROW FORMAT DELIMITED,也将使用本地 Serde。要用','分隔字段,请指定FIELDS TERMINATED BY','并用换行符结束一行数据,请指定LINES TERMINATED BY '\n'。
运行下面的CREATE TABLE命令来创建一个配置单元管理的表;配置单元外部表的命令是CREATE EXTERNAL TABLE。
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的配置单元表被创建,如图 9-8 所示。我们还没有使用wlslog表中的PRIMARY KEY字段。

图 9-8。
Creating Hive Table
运行以下命令来描述wlslog表。
desc wlslog;
由列名和数据类型组成的表结构如图 9-9 所示。

图 9-9。
Describing Table Structure
将数据加载到配置单元表中
接下来,我们将数据加载到 Hive 表中。运行下面的INSERT HiveQL 语句将一行数据添加到wlslog表中。
INSERT INTO TABLE wlslog VALUES ('Apr-8-2014-7:06:16-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to STANDBY');
MapReduce 作业开始将数据加载到 Hive 表中,如图 9-10 所示。

图 9-10。
Running the INSERT Command
MapReduce 作业由 1 个映射器和 0 个缩减器组成。数据被加载到default.wlslog表中,如图 9-11 所示。

图 9-11。
Loading Data into Hive Table
如果没有指定PRIMARY KEY,配置单元表中的数据不会被约束为具有唯一的列值,我们没有指定。可以添加具有相同数据的行,而不在表定义中添加PRIMARY KEY。运行下面的INSERT语句,再添加 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');
查询配置单元表
创建了一个 Hive 表并将数据加载到该表中后,我们将使用一个SELECT HiveQL 语句查询该表。在直线 CLI 中运行以下查询。
select * from wlslog;
8 行数据被列出,如图 9-12 所示。

图 9-12。
Running a SELECT HiveQL Statement
停止 Apache 蜂房
要停止 Apache Hive 进程,运行docker stop命令来停止运行 cdh 框架的 Docker 容器。
sudo docker stop cdh
摘要
在本章中,我们使用了一个 Docker 映像来运行 CDH 框架,包括 Docker 容器中的 Apache Hive 框架。我们启动了一个直线 CLI,它取代了 Hive CLI,并从直线 CLI 连接到 HiveServer2。我们创建了一个配置单元管理表,并将数据加载到配置单元表中。随后,我们从 Beeline CLI 查询了 Hive 表。在下一章中,我们将使用 Docker 容器中的 Apache HBase 数据库。
十、使用 Apache HBase
Apache HBase 是 Apache Hadoop 数据库。Apache HBase 基于宽列数据存储模型,以表作为存储单位。一个表由一个或多个柱族组成。Apache HBase 是一个无模式的 NoSQL 数据库。默认情况下,HBase 将数据存储在 HDFS 中。在本章中,我们将使用 Docker 映像在 Docker 容器中运行 Apache HBase。我们将使用我们在第八章中介绍的 svds/cdh Docker 镜像。
- 设置环境
- 从 CDH 开始
- 启动交互式外壳
- 启动 HBase Shell
- 创建 HBase 表
- 列出 HBase 表
- 获取单个表格行
- 获取单行列
- 扫描表格
- 阻止 CDH
设置环境
本章需要以下软件。
- -Docker(使用 1.8 版)
- cdh 的坞站映像
在其他章节中,我们已经在 Amazon EC2 实例上安装了软件。到 Amazon EC2 实例的 SSH 登录。
ssh -i "docker.pem" ec2-user@54.209.254.175
启动 Docker 服务。
sudo service docker start
验证 Docker 是否已启动。
sudo service docker status
下载 svds/cdh Docker 映像(如果尚未下载前一章的映像)。
sudo docker pull svds/cdh
下载svds/cdh:latest Docker 镜像,如图 10-1 所示。

图 10-1。
Downloading the svds/cdh Docker Image
列出 Docker 映像以验证 svds/cdh 映像是否已下载。
sudo docker images
从 CDH 开始
启动 Docker 容器来运行 Apache Hadoop 生态系统框架,其中包括 Apache HBase。运行带有–d选项的docker run命令,以分离模式启动容器。Docker 容器名是“cdh ”,用–name选项指定。
sudo docker run -d --name cdh svds/cdh
Docker 容器启动如图 10-2 所示。

图 10-2。
Starting Docker Container
列出正在运行的 Docker 容器。
sudo docker ps
“cdh”容器被列为正在运行,如图 10-3 所示。还列出了容器 id。

图 10-3。
Listing the Running Docker Containers
启动交互式外壳
接下来,启动一个交互式终端(tty)来运行 HBase shell。
sudo docker exec -it cdh bash
交互终端启动,命令提示符变为root@86f0cf0a5c8d,如图 10-4 所示。

图 10-4。
Starting the Interactive Shell
也可以使用容器 id 而不是容器名称来启动交互式外壳。
sudo docker exec -it 86f0cfoa5c8d bash
启动 HBase Shell
接下来,在交互式终端中运行以下命令,启动 HBase shell。
bin/hbase shell
HBase shell 启动,如图 10-5 所示。

图 10-5。
Starting the HBase Shell
创建 HBase 表
使用“创建”命令创建一个 HBase 表。除了表名之外,还要提供一个或多个列族以及每个列族的规范字典。或者,提供一个表配置字典。例如,创建一个名为“wlslog”的表,其中包含一个名为“log”的列族。
create 'wlslog', 'log'
HBase 表' wlslog '被创建,如图 10-6 所示。

图 10-6。
Creating an HBase Table
使用put命令在表格/行/列坐标处添加单元格值。用下面的put命令添加 7 行数据。Apache HBase 和其他 Apache Hadoop 生态系统软件是为大量数据而设计的,这些数据可能有数百万行,但我们只添加了一个数据示例来演示 Apache HBase 的使用。
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'
数据被添加到“wlslog”表中,如图 10-7 所示。

图 10-7。
Adding Data to HBase Table
列出 HBase 表
使用在 HBase shell 中运行的以下命令列出这些表。
list
一个表格,即“wlslog”表格,如图 10-8 所示。

图 10-8。
Listing HBase Tables
获取单个表格行
get命令用于获取行或列单元格中的数据。运行下面的get命令获取表‘WLS log’中‘log 7’行的数据。
get 'wlslog', 'log7'
单列数据被列出,如图 10-9 所示。

图 10-9。
Getting a Single Table Row
获取单行列
可选地,列的字典可以被提供给get命令。例如,从log.msg列中的“log5”行获取wlslog表中的列数据。
get 'wlslog', 'log5', {COLUMNS=>['log:msg']}
表‘WLS log’中‘log5’行的log.msg列数据得到如图 10-10 所示的输出。

图 10-10。
Getting a Single Row Column Value
扫描表格
scan命令用于扫描一个表,以获取表中的所有数据。可选地,可以提供扫描仪规范的字典,这在下面的命令中省略了。
scan 'wlslog'
每行的行➤列数据得到输出,如图 10-11 所示。

图 10-11。
Scanning a HBase Table
7 行数据得到如图 10-12 所示的输出。

图 10-12。
Output from the scan Command
阻止 CDH
要停止 Docker 容器,请对“cdh”容器运行docker stop命令。
sudo docker stop cdh
或者,可以指定容器 id。
sudo docker stop 86f0cfoa5c8d
摘要
在这一章中,我们使用了一个 Docker 镜像来运行 Docker 容器中的 CDH 框架。我们启动了一个交互式终端,并在 tty 中启动了一个 HBase shell。在 HBase shell 中,我们使用了create命令来创建一个表。我们使用put命令将数据放入表中。随后,我们使用get命令来添加数据。我们还运行了scan命令来扫描整个表并列出表中的所有数据。在下一章,我们将在 Docker 容器中运行 Apache Sqoop。
十一、使用 Apache Sqoop
Apache Sqoop 是一个 Hadoop 生态系统框架,用于将批量数据从关系数据库(RDBMS)传输到 Hadoop 分布式文件系统(HDFS)、Apache HBase 和 Apache Hive。Sqoop 还支持从 HDFS 到 RDBMS 的批量数据传输。Sqoop 支持的直接数据传输路径如图 11-1 所示。Sqoop 支持 HSQLDB(版本 1.8.0 以上)、MySQL(版本 5.0 以上)、Oracle(版本 10.2.0)和 PostgreSQL(版本 8.3 以上),也可以用于其他关系数据库,如 IBM DB2 数据库和版本。Sqoop 使用 JDBC 进行数据传输,并且要求安装 Java,JDBC 驱动程序 jar 位于运行时类路径中。

图 11-1。
Direct Transfer Paths supported by Sqoop
在本章中,我们将使用 Apache Sqoop 从 MySQL 数据库导入数据到 HDFS。我们还将从 HDFS 导出数据回 MySQL 数据库表。
- 设置环境
- 启动 Docker 容器
- 启动交互式终端
- 创建 MySQL 表
- 将 MySQL JDBC Jar 添加到 Sqoop 类路径
- 配置 Apache Hadoop
- 用 Sqoop 将 MySQL 表数据导入 HDFS
- 导入 HDFS 的列表数据
- 用 Sqoop 从 HDFS 导出到 MySQL
- 查询导出的数据
- 停止和移除 Docker 容器
设置环境
本章需要以下软件。
- -Docker 引擎(版本 1.8)
- MySQL 数据库的 Docker 映像
- cdh 的坞站映像
SSH 连接到 Amazon EC2 实例。
ssh -i "docker.pem" ec2-user@54.175.13.99
如果尚未安装 Docker,则按照第一章所述安装 Docker。启动 Docker 服务,并验证 Docker 是否已经启动。
sudo service docker start
sudo service docker status
从下载jdk-8u65-linux-x64.gz。甲骨文。com/tech network/Java/javase/downloads/JDK 8-downloads-2133151。html 。由于 JDK 下载需要 BSD 许可才能被接受,使用wget或类似软件下载文件会使下载命令成为非标准命令。使用浏览器下载jdk-8u65-linux-x64.gz,并使用如下的scp命令复制到 EC2 实例。
scp -i "docker.pem" /jdk-8u65-linux-x64.gz ec2-user@54.175.13.99:/
我们需要为本章下载两个 Docker 映像,因为 CDH 的 Docker 映像包括 Apache Sqoop,但不包括 MySQL Server。使用 docker pull 命令下载mysql Docker 映像。
sudo docker pull mysql
下载 svds/cdh 坞站映像。
sudo docker pull svds/cdh
用docker images命令列出 Docker 映像。
sudo docker images
mysql和svds/cdh Docker 映像都应该被列出,如图 11-2 所示。

图 11-2。
Listing Docker Images Required for Apache Sqoop with MySQL Database
启动 Docker 容器
mysql 和 svds/cdh Docker 映像已经在前面的章节中分别讨论过,并用于启动 Docker 容器。但是,使用两个 Docker 映像略有不同,需要链接两个 Docker 容器。在本节中,我们将启动两个独立的 Docker 容器:cdh用于cdh Docker 映像,而mysqldb用于mysql Docker 映像。对于mysqldb容器,为 MySQL 存储的数据创建一个目录,并将其权限设置为 global (777)。
sudo mkdir -p /mysql/data
sudo chmod -R 777 /mysql/data
前面的命令将在连接到 Amazon EC2 实例时运行,如图 11-3 所示。

图 11-3。
Creating Directory for MySQL Data
下表讨论了docker run命令中使用的环境变量,表 11-1 。
表 11-1。
Environment Variables for a Docker container based on mysql Docker Image
| 环境变量 | 描述 | 价值 | | --- | --- | --- | | MYSQL _ 数据库 | 要创建的 MySQL 数据库实例。 | mysqldb | | MYSQL_USER | 创建的数据库的用户名。 | 关系型数据库 | | MYSQL_PASSWORD | 创建的数据库的密码。 | 关系型数据库 | | MYSQL _ ALLOW _ EMPTY _ 密码 | 是否允许空密码。 | 不 | | MYSQL _ ROOT _ 密码 | “root”用户的密码。 | 关系型数据库 |运行下面的docker run命令来启动 MySQL 数据库的 Docker 容器。环境变量只在docker run命令中设置,而不在 bash shell 中设置。
sudo docker run -v /mysql/data:/var/lib/mysql --name mysqldb -e MYSQL_DATABASE='mysqldb' -e MYSQL_USER='mysql' -e MYSQL_PASSWORD='mysql' -e MYSQL_ALLOW_EMPTY_PASSWORD='no' -e MYSQL_ROOT_PASSWORD='mysql' -d mysql
运行下面的docker run命令来启动 svds/cdh 映像软件的 Docker 容器,它包括 Apache Sqoop,并使用--link命令参数将该容器与运行 MySQL 数据库的mysqldb容器链接起来。
sudo docker run -d --name cdh --link mysqldb svds/cdh
列出正在运行的 Docker 容器。
sudo docker ps
前面命令的输出如图 11-4 所示。cdh 和 mysqldb 容器都被列为已启动。

图 11-4。
Starting Docker Containers for CDH and MySQL
启动交互式终端
启动 Docker 容器后,为每个 Docker 容器启动交互终端(tty)。使用以下命令启动 mysqldb 容器的交互式 shell。
sudo docker exec -it mysqldb bash
使用以下命令启动 cdh 容器的交互式 shell。
sudo docker exec -it cdh bash
创建 MySQL 表
在本节中,我们将登录 MySQL CLI 并创建一个数据库表,该表将通过 Apache Sqoop 导入 HDFS。运行以下命令登录 MySQL CLI。
mysql –u mysql –p
出现如图 11-5 所示的mysql>提示。

图 11-5。
Starting the MySQL CLI Shell
将数据库设置为“mysqldb”。
use mysqldb
使用GRANT选项将mysqldb数据库上的所有权限授予mysql用户。
GRANT ALL PRIVILEGES ON mysqldb.* TO 'mysql'@'%' IDENTIFIED BY 'mysql' WITH GRANT OPTION;
在mysqldb数据库上设置权限,如图 11-6 所示。

图 11-6。
Setting Privileges on mysqldb Database
接下来,创建一个名为wlslog的数据库表,其中包含列time_stamp、category、type、servername、code和msg。PRIMARY KEY栏需要包含在sqoop import工具中,以便将数据导入 HDFS。在 MySQL CLI 中运行以下 SQL 命令。
CREATE TABLE wlslog(time_stamp VARCHAR(255) PRIMARY KEY,category VARCHAR(255),type VARCHAR(255),servername VARCHAR(255), code VARCHAR(255),msg VARCHAR(255));
名为wlslog的数据库表被创建,如图 11-7 所示。

图 11-7。
Creating a MySQL Database Table
向wlslog表添加数据。运行下面的INSERT SQL 语句将数据添加到wlslog表中。
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-000365','Server state changed to ADMIN');
INSERT INTO wlslog(time_stamp,category,type,servername,code,msg) VALUES('Apr-8-2014-7:06:19-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to RESUMING');
INSERT INTO wlslog(time_stamp,category,type,servername,code,msg) VALUES('Apr-8-2014-7:06:20-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000361','Started WebLogic AdminServer');
INSERT INTO wlslog(time_stamp,category,type,servername,code,msg) VALUES('Apr-8-2014-7:06:21-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to RUNNING');
前面 SQL 语句的输出如图 11-8 所示。

图 11-8。
Running INSERT SQL Statements
运行以下 SQL 查询来列出添加的数据。
SELECT * FROM wlslog;
如图 11-9 所示,列出 6 行数据。

图 11-9。
Running a SQL Query
我们需要为sqoop export工具创建另一个数据库表,将数据从 HDFS 导出到 MySQL 数据库。因为wlslog表已经有数据,所以创建另一个名为WLSLOG_COPY的表,它与wlslog表有相同的表定义。在 MySQL CLI 中运行以下 SQL 脚本。
CREATE TABLE WLSLOG_COPY(time_stamp VARCHAR(255) PRIMARY KEY,category VARCHAR(255),type VARCHAR(255),servername VARCHAR(255), code VARCHAR(255),msg VARCHAR(255));
WLSLOG_COPY表被创建,如图 11-10 所示。

图 11-10。
Creating MySQL Table WLSLOG_COPY
将 MySQL JDBC Jar 添加到 Sqoop 类路径
我们需要将 MySQL JDBC jar 添加到 Apache Sqoop 类路径中。启动 cdh 容器的交互式终端(如果尚未启动)。
sudo docker exec -it cdh bash
在交互式 shell 中,下载 MySQL-connector-Java-5 . 1 . 37 . jar,并将 jar 复制到/usr/lib/sqoop/lib 目录。
wgethttp://central.maven.org/maven2/mysql/mysql-connector-java/5.1.37/mysql-connector-java-5.1.37.jar
cp mysql-connector-java-5.1.37.jar /usr/lib/sqoop/lib
前面命令的输出如图 11-11 所示。

图 11-11。
Adding MySQL JDBC Jar to Sqoop Classpath
设置 JAVA_HOME 环境变量
为了运行 Apache Sqoop,我们需要设置JAVA_HOME环境变量。但是,首先我们需要将 jdk-8u65-linux-x64.gz 文件复制到运行包括 Apache Sqoop 在内的 CDH 框架的 Docker 容器中。我们之前下载了 jdk-8u65-linux-x64.gz。使用以下命令将 jdk-8u65-linux-x64.gz 文件复制到 Docker 容器,其中容器 id 从图 11-12 中的docker ps命令的输出中获得。
sudo docker cp jdk-8u65-linux-x64.gz 49d774f8f1fe:/jdk-8u65-linux-x64.gz
jdk-8u65-linux-x64.gz 文件被复制到 Docker 容器“cdh”中,如图 11-12 所示。

图 11-12。
Copying the JDK gz File to Docker Container
前面的命令将从 Amazon EC2 实例中运行。启动 cdh 容器的交互式 shell。
sudo docker exec -it cdh bash
使用以下命令列出 Docker 容器根目录中的文件。
ls –l
jdk-8u65-linux-x64.gz 文件被列出,如图 11-13 所示。

图 11-13。
Listing the files in Docker Container’s root Directory
提取 jdk-8u65-linux-x64.gz 文件。
tar -xv jdk-8u65-linux-x64.gz
那个。gz 文件被提取,如图 11-14 所示。

图 11-14。
Extracting the JDK .gz File
我们需要在hadoop-env.sh文件中设置JAVA_HOME环境变量。要找到hadoop-env.sh文件的目录,运行以下命令。
find –name hadoop-env.sh
包含hadoop-env.sh文件的不同目录被列出,如图 11-15 所示。

图 11-15。
Finding the hadoop-env.sh File
在 vi 编辑器中打开./etc/hadoop/conf.psuedo/hadoop-env.sh文件,并添加下面的export语句。
export JAVA_HOME=./jdk1.8.0_65
hadoop-env.sh文件中的前述语句如图 11-16 所示。用:wq命令保存文件。

图 11-16。
Setting the JAVA_HOME Environment Variable
配置 Apache Hadoop
Apache Hadoop MapReduce 框架可以在三种模式下启动:local、classic和yarn。在“本地”模式下,MapReduce 在 Java 进程中运行。在经典模式下,MapReduce 使用 MapReduce1 框架运行。在 yarn 模式下,MapReduce 使用 MapReduce2 框架(也称为 YARN)运行。要使用的 MapReduce 框架是在mapred-site.xml配置文件的mapreduce.framework.name设置中设置的,该文件与hadoop-env.sh、./etc/hadoop/conf.psuedo目录在同一个目录下。因为 yarn 和 classic 框架需要比本地更多的内存,所以将mapreduce.framework.name设置为本地。
<property>
<name>mapreduce.framework.name</name>
<value>local</value>
</property>
mapreduce.framework.name设置如图 11.17 所示。

图 11-17。
Setting the MapReduce Framework to local
同时在hdfs-site.xml配置文件中设置以下(表 11-2 )配置属性。
表 11-2。
Configuration Properties for hdfs-site.xml
| 配置属性 | 描述 | 价值 | | --- | --- | --- | | dfs.permissions .超级用户组 | 设置超级用户组 | 大数据 | | dfs . namenode . name . dir | 设置 NameNode 存储目录 | file:///data/1/dfs/nn | | dfs.replication | 设置复制级别 | one | | dfs .权限 | 是否要检查权限 | 错误的 |下面列出了hdfs-site.xml配置设置。
<configuration>
<property>
<name>dfs.permissions.superusergroup</name>
<value>hadoop</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>file:///data/1/dfs/nn</value>
</property>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<name>dfs.permissions</name>
<value>false</value>
</property>
</configuration>
hdfs-site.xml配置文件如图 11-18 所示。

图 11-18。
The hdfs-site.xml Configuration File
我们需要在dfs.namenode.name.dir属性中创建 NameNode 存储目录集。创建/data/1/dfs/nn目录并将其权限设置为全局(777)。
sudo mkdir -p /data/1/dfs/nn
sudo chmod -R 777 /data/1/dfs/nn
创建用户组hadoop和用户hadoop。
groupadd hadoop
useradd hadoop
我们需要在core-site.xml文件中设置以下(表 11-3 )配置属性。
表 11-3。
Configuration Properties for core-site.xml
| 配置属性 | 描述 | 价值 | | --- | --- | --- | | fs.defaultfs(默认设置) | URI 这个名字 | hdfs://localhost:8020 | | hadoop.tmp.dir | Hadoop 临时目录 | file:///var/lib/Hadoop-0.20/cache |列出了core-site.xml配置设置:
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://10.0.2.15:8020</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>file:///var/lib/hadoop-0.20/cache</value>
</property>
</configuration>
core-site.xml文件如图 11-19 所示。用:wq保存文件。

图 11-19。
The core-site.xml Configuration File
在hadoop.tmp.dir目录中创建目录集,并将其权限设置为全局(777)。
mkdir -p /var/lib/hadoop-0.20/cache
chmod -R 777 /var/lib/hadoop-0.20/cache
我们还需要使用下面的命令将 HDFS 的/目录的权限设置为 global (777)。
sudo -u hdfs hdfs dfs -chmod 777 /
用 Sqoop 将 MySQL 表数据导入 HDFS
在本节中,我们将使用sqoop import命令将 MySQL 数据库表数据导入到 HDFS。通过从 cdh 容器的交互 shell 中运行sqoop help命令,可以列出 sqoop 工具支持的不同命令,如图 11-20 所示。import命令用于将一个表从关系数据库导入到 HDFS。

图 11-20。
Running the sqoop help Command
运行sqoop import命令需要生成访问关系数据库的代码。代码可以在运行sqoop import命令时直接生成,也可以在使用sqoop codegen命令运行sqoop import命令之前生成。运行下面的sqoop codegen命令来生成与数据库记录交互的代码。
sudo -u hdfs sqoop codegen --connect "jdbc:mysql://e414f8c41d0b:3306/mysqldb" --password "mysql" --username "mysql" --table "wlslog"
–u hdfs 将用户指定为hdfs。命令参数在表 11-4 中讨论。
表 11-4。
Command Parameters for the hdfs Command
| 参数 | 描述 | 价值 | | --- | --- | --- | | -连接 | 连接到 MySQL 数据库的连接 url。主机名是运行 MySQL 的容器 id。 | " JDBC:MySQL://e 414 F8 c41 d0s had:3306/mysqldb " | | -密码 | 连接 MySQL 的密码。建议使用非 root 用户。 | " mysql " | | -用户名 | 连接到 MySQL 的用户名。 | " mysql " | | -桌子 | 要从中导入的 MySQL 表 | " wlslog " |与数据库交互所需的代码在wlslog.jar文件中生成,如图 11-21 所示。

图 11-21。
Output from the codegen Command
接下来,以用户hdfs的身份运行sqoop import命令。用–libjars选项在类路径中添加wlslog.jar文件。
sudo -u hdfs sqoop import -libjars /tmp/sqoop-hdfs/compile/6348ef9539c8ad2bee9ba1875a62c923/wlslog.jar --connect "jdbc:mysql://e414f8c41d0b:3306/mysqldb" --password "mysql" --username "mysql" --table "wlslog" --columns "time_stamp,category,type,servername,code,msg" --target-dir "/mysql/import" –verbose
其他命令参数在表 11-5 中讨论。
表 11-5。
Command Parameters for sqoop import
| 参数 | 描述 | 价值 | | --- | --- | --- | | -连接 | 连接到 MySQL 数据库的连接 url。主机名是运行 MySQL 的容器 id。 | " JDBC:MySQL://e 414 F8 c41 d0s had:3306/mysqldb " | | -密码 | 连接 MySQL 的密码。建议使用非 root 用户。 | " mysql " | | -用户名 | 连接到 MySQL 的用户名。 | " mysql " | | -列 | 要导入的列 | 时间戳,类别,类型,服务器名,代码,消息 | | -桌子 | 要从中导入的 MySQL 表 | " wlslog " | | -目标方向 | 要导入的 HDFS 目录 | "/mysql/import " |sqoop import命令的输出如图 11-22 所示。

图 11-22。
Output from sqoop import
sqoop import命令的详细输出如下:
root@08b338cb2a90:/# sudo -u hdfs sqoop import -libjars /tmp/sqoop-hdfs/compile/6348ef9539c8ad2bee9ba1875a62c923/wlslog.jar --connect "jdbc:mysql://e414f8c41d0b:3306/mysqldb" --password "mysql" --username "mysql" --table "wlslog" --columns "time_stamp,category,type,servername,code,msg" --target-dir "/mysql/import" -verbose
15/10/22 00:07:07 INFO sqoop.Sqoop: Running Sqoop version: 1.4.5-cdh5.4.3
ConnManager
15/10/22 00:07:10 INFO tool.CodeGenTool: Beginning code generation
15/10/22 00:07:10 DEBUG manager.SqlManager: Execute getColumnInfoRawQuery : SELECT t.* FROM wlslog AS t LIMIT 1
15/10/22 00:07:10 DEBUG manager.SqlManager: No connection paramenters specified. Using regular API for making connection.
15/10/22 00:07:11 DEBUG manager.SqlManager: Using fetchSize for next query: -2147483648
15/10/22 00:07:11 INFO manager.SqlManager: Executing SQL statement: SELECT t.* FROM wlslog AS t LIMIT 1
15/10/22 00:07:11 DEBUG manager.SqlManager: Found column time_stamp of type [12, 255, 0]
15/10/22 00:07:11 DEBUG manager.SqlManager: Found column category of type [12, 255, 0]
15/10/22 00:07:11 DEBUG manager.SqlManager: Found column type of type [12, 255, 0]
15/10/22 00:07:11 DEBUG manager.SqlManager: Found column servername of type [12, 255, 0]
15/10/22 00:07:11 DEBUG manager.SqlManager: Found column code of type [12, 255, 0]
15/10/22 00:07:11 DEBUG manager.SqlManager: Found column msg of type [12, 255, 0]
15/10/22 00:07:11 DEBUG orm.ClassWriter: selected columns:
15/10/22 00:07:11 DEBUG orm.ClassWriter: time_stamp
15/10/22 00:07:11 DEBUG orm.ClassWriter: category
15/10/22 00:07:11 DEBUG orm.ClassWriter: type
15/10/22 00:07:11 DEBUG orm.ClassWriter: servername
15/10/22 00:07:11 DEBUG orm.ClassWriter: code
15/10/22 00:07:11 DEBUG orm.ClassWriter: msg
15/10/22 00:07:11 DEBUG manager.SqlManager: Using fetchSize for next query: -2147483648
15/10/22 00:07:11 INFO manager.SqlManager: Executing SQL statement: SELECT t.* FROM wlslog AS t LIMIT 1
15/10/22 00:07:11 DEBUG manager.SqlManager: Found column time_stamp of type VARCHAR
15/10/22 00:07:11 DEBUG manager.SqlManager: Found column category of type VARCHAR
15/10/22 00:07:11 DEBUG manager.SqlManager: Found column type of type VARCHAR
15/10/22 00:07:11 DEBUG manager.SqlManager: Found column servername of type VARCHAR
15/10/22 00:07:11 DEBUG manager.SqlManager: Found column code of type VARCHAR
15/10/22 00:07:11 DEBUG manager.SqlManager: Found column msg of type VARCHAR
15/10/22 00:07:11 DEBUG orm.ClassWriter: Writing source file: /tmp/sqoop-hdfs/compile/3c3425a2eecf819af8fe8f4eabd40468/wlslog.java
15/10/22 00:07:11 DEBUG orm.ClassWriter: Table name: wlslog
15/10/22 00:07:11 DEBUG orm.ClassWriter: Columns: time_stamp:12, category:12, type:12, servername:12, code:12, msg:12,
15/10/22 00:07:11 DEBUG orm.ClassWriter: sourceFilename is wlslog.java
15/10/22 00:07:11 DEBUG orm.CompilationManager: Found existing /tmp/sqoop-hdfs/compile/3c3425a2eecf819af8fe8f4eabd40468/
15/10/22 00:07:11 INFO orm.CompilationManager: HADOOP_MAPRED_HOME is /usr/lib/hadoop-mapreduce
15/10/22 00:07:11 DEBUG orm.CompilationManager: Returning jar file path /usr/lib/hadoop-mapreduce/hadoop-mapreduce-client-core.jar:/usr/lib/hadoop-mapreduce/hadoop-mapreduce-client-core-2.6.0-cdh5.4.3.jar
15/10/22 00:07:17 DEBUG orm.CompilationManager: Could not rename /tmp/sqoop-hdfs/compile/3c3425a2eecf819af8fe8f4eabd40468/wlslog.java to /./wlslog.java
15/10/22 00:07:17 INFO orm.CompilationManager: Writing jar file: /tmp/sqoop-hdfs/compile/3c3425a2eecf819af8fe8f4eabd40468/wlslog.jar
15/10/22 00:07:17 DEBUG orm.CompilationManager: Scanning for .class files in directory: /tmp/sqoop-hdfs/compile/3c3425a2eecf819af8fe8f4eabd40468
15/10/22 00:07:17 DEBUG orm.CompilationManager: Got classfile: /tmp/sqoop-hdfs/compile/3c3425a2eecf819af8fe8f4eabd40468/wlslog.class -> wlslog.class
15/10/22 00:07:17 DEBUG orm.CompilationManager: Finished writing jar file /tmp/sqoop-hdfs/compile/3c3425a2eecf819af8fe8f4eabd40468/wlslog.jar
15/10/22 00:07:17 WARN manager.MySQLManager: It looks like you are importing from mysql.
15/10/22 00:07:17 WARN manager.MySQLManager: This transfer can be faster! Use the --direct
15/10/22 00:07:17 WARN manager.MySQLManager: option to exercise a MySQL-specific fast path.
15/10/22 00:07:17 INFO manager.MySQLManager: Setting zero DATETIME behavior to convertToNull (mysql)
15/10/22 00:07:17 DEBUG manager.MySQLManager: Rewriting connect string to jdbc:mysql://e414f8c41d0b:3306/mysqldb?zeroDateTimeBehavior=convertToNull
15/10/22 00:07:17 DEBUG manager.CatalogQueryManager: Retrieving primary key for table 'wlslog' with query SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = (SELECT SCHEMA()) AND TABLE_NAME = 'wlslog' AND COLUMN_KEY = 'PRI'
15/10/22 00:07:17 DEBUG manager.CatalogQueryManager: Retrieving primary key for table 'wlslog' with query SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = (SELECT SCHEMA()) AND TABLE_NAME = 'wlslog' AND COLUMN_KEY = 'PRI'
15/10/22 00:07:17 INFO mapreduce.ImportJobBase: Beginning import of wlslog
15/10/22 00:07:17 INFO Configuration.deprecation: mapred.job.tracker is deprecated. Instead, use mapreduce.jobtracker.address
15/10/22 00:07:17 INFO Configuration.deprecation: mapred.jar is deprecated. Instead, use mapreduce.job.jar
15/10/22 00:07:17 DEBUG db.DBConfiguration: Securing password into job credentials store
15/10/22 00:07:17 DEBUG mapreduce.DataDrivenImportJob: Using table class: wlslog
15/10/22 00:07:17 DEBUG mapreduce.DataDrivenImportJob: Using InputFormat: class com.cloudera.sqoop.mapreduce.db.DataDrivenDBInputFormat
15/10/22 00:07:18 INFO Configuration.deprecation: mapred.map.tasks is deprecated. Instead, use mapreduce.job.maps
15/10/22 00:07:19 INFO jvm.JvmMetrics: Initializing JVM Metrics with processName=JobTracker, sessionId=
15/10/22 00:07:20 DEBUG db.DBConfiguration: Fetching password from job credentials store
15/10/22 00:07:20 INFO db.DBInputFormat: Using read commited transaction isolation
15/10/22 00:07:20 DEBUG db.DataDrivenDBInputFormat: Creating input split with lower bound '1=1' and upper bound '1=1'
15/10/22 00:07:20 INFO mapreduce.JobSubmitter: number of splits:1
15/10/22 00:07:21 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_local2065078437_0001
15/10/22 00:07:25 INFO mapreduce.Job: The url to track the job: http://localhost:8080/
15/10/22 00:07:25 INFO mapreduce.Job: Running job: job_local2065078437_0001
15/10/22 00:07:25 INFO mapred.LocalJobRunner: OutputCommitter set in config null
15/10/22 00:07:25 INFO output.FileOutputCommitter: File Output Committer Algorithm version is 1
15/10/22 00:07:25 INFO mapred.LocalJobRunner: OutputCommitter is org.apache.hadoop.mapreduce.lib.output.FileOutputCommitter
15/10/22 00:07:26 INFO mapred.LocalJobRunner: Waiting for map tasks
15/10/22 00:07:26 INFO mapred.LocalJobRunner: Starting task: attempt_local2065078437_0001_m_000000_0
15/10/22 00:07:26 INFO output.FileOutputCommitter: File Output Committer Algorithm version is 1
15/10/22 00:07:26 INFO mapred.Task: Using ResourceCalculatorProcessTree : [ ]
15/10/22 00:07:26 DEBUG db.DBConfiguration: Fetching password from job credentials store
15/10/22 00:07:26 INFO db.DBInputFormat: Using read commited transaction isolation
15/10/22 00:07:26 INFO mapred.MapTask: Processing split: 1=1 AND 1=1
15/10/22 00:07:26 DEBUG db.DataDrivenDBInputFormat: Creating db record reader for db product: MYSQL
15/10/22 00:07:26 INFO mapreduce.Job: Job job_local2065078437_0001 running in uber mode : false
15/10/22 00:07:26 INFO mapreduce.Job: map 0% reduce 0%
15/10/22 00:07:27 INFO db.DBRecordReader: Working on split: 1=1 AND 1=1
15/10/22 00:07:27 DEBUG db.DataDrivenDBRecordReader: Using query: SELECT time_stamp, category, type, servername, code, msgFROMwlslogASwlslog WHERE ( 1=1 ) AND ( 1=1 )
15/10/22 00:07:27 DEBUG db.DBRecordReader: Using fetchSize for next query: -2147483648
15/10/22 00:07:27 INFO db.DBRecordReader: Executing query: SELECT time_stamp, category, type, servername, code, msgFROMwlslogASwlslog WHERE ( 1=1 ) AND ( 1=1 )
15/10/22 00:07:27 DEBUG mapreduce.AutoProgressMapper: Instructing auto-progress thread to quit.
15/10/22 00:07:27 DEBUG mapreduce.AutoProgressMapper: Waiting for progress thread shutdown…
15/10/22 00:07:27 INFO mapreduce.AutoProgressMapper: Auto-progress thread is finished. keepGoing=false
15/10/22 00:07:27 DEBUG mapreduce.AutoProgressMapper: Progress thread shutdown detected.
15/10/22 00:07:27 INFO mapred.LocalJobRunner:
15/10/22 00:07:27 INFO mapred.Task: Task:attempt_local2065078437_0001_m_000000_0 is done. And is in the process of committing
15/10/22 00:07:27 INFO mapred.LocalJobRunner:
15/10/22 00:07:27 INFO mapred.Task: Task attempt_local2065078437_0001_m_000000_0 is allowed to commit now
15/10/22 00:07:27 INFO output.FileOutputCommitter: Saved output of task 'attempt_local2065078437_0001_m_000000_0' to hdfs://localhost:8020/mysql/import/_temporary/0/task_local2065078437_0001_m_000000
15/10/22 00:07:27 INFO mapred.LocalJobRunner: map
15/10/22 00:07:27 INFO mapred.Task: Task 'attempt_local2065078437_0001_m_000000_0' done.
15/10/22 00:07:27 INFO mapred.LocalJobRunner: Finishing task: attempt_local2065078437_0001_m_000000_0
15/10/22 00:07:27 INFO mapred.LocalJobRunner: map task executor complete.
15/10/22 00:07:28 INFO mapreduce.Job: map 100% reduce 0%
15/10/22 00:07:28 INFO mapreduce.Job: Job job_local2065078437_0001 completed successfully
15/10/22 00:07:28 INFO mapreduce.Job: Counters: 23
File System Counters
FILE: Number of bytes read=17796154
FILE: Number of bytes written=18238016
FILE: Number of read operations=0
FILE: Number of large read operations=0
FILE: Number of write operations=0
HDFS: Number of bytes read=0
HDFS: Number of bytes written=615
HDFS: Number of read operations=4
HDFS: Number of large read operations=0
HDFS: Number of write operations=3
Map-Reduce Framework
Map input records=6
Map output records=6
Input split bytes=87
Spilled Records=0
Failed Shuffles=0
Merged Map outputs=0
GC time elapsed (ms)=306
CPU time spent (ms)=0
Physical memory (bytes) snapshot=0
Virtual memory (bytes) snapshot=0
Total committed heap usage (bytes)=138571776
File Input Format Counters
Bytes Read=0
File Output Format Counters
Bytes Written=615
15/10/22 00:07:28 INFO mapreduce.ImportJobBase: Transferred 615 bytes in 9.6688 seconds (63.6064 bytes/sec)
15/10/22 00:07:28 INFO mapreduce.ImportJobBase: Retrieved 6 records.
root@08b338cb2a90:/#
导入 HDFS 的列表数据
要在/mysql/import目录中列出用sqoop import工具生成的文件,运行以下命令。
sudo -u hdfs hdfs dfs -ls /mysql/import
列出两个文件:_SUCCESS,表示sqoop import命令成功完成,part-m-00000,导入数据如图 11-23 所示。

图 11-23。
Listing Files Generated by sqoop import
用以下命令列出数据文件part-m-00000中的数据。
sudo -u hdfs hdfs dfs -cat /mysql/import/part-m-00000
用sqoop import工具导入的数据如图 11-24 所示。

图 11-24。
Listing Data imported by Sqoop
用 Sqoop 从 HDFS 导出到 MySQL
接下来,我们将把导入 HDFS 的数据导出回 MySQL 数据库。一般来说,sqoop export工具将一组文件从 HDFS 导出回 RDBMS,其中目标表已经存在于数据库中,输入文件将被读取并根据“用户指定”值中指定的分隔符解析成一组记录。
与数据库交互所需的代码可在sqoop export命令期间或在sqoop export命令之前生成。我们将在使用sqoop codegen命令运行sqoop export命令之前生成代码,如下所示。
sudo -u hdfs sqoop codegen --connect "jdbc:mysql://e414f8c41d0b:3306/mysqldb" --password "mysql" --username "mysql" --table "WLSLOG_COPY"
命令参数与在sqoop import命令之前运行的sqoop codegen命令相同,除了表名是WLSLOG_COPY而不是wlslog。sqoop export命令所需的代码在WLSLOG_COPY.jar文件中生成,如图 11-25 所示。

图 11-25。
Running the sqoop codegen Command
接下来,运行sqoop export命令,用–libjars选项将WLSLOG_COPY.jar添加到类路径中。除了–table为“WLSLOG_COPY”和用--export-dir选项代替--target-dir外,其他命令参数与sqoop import命令相同。--export-dir选项中的目录应与sqoop import命令的--data-dir选项中的目录相同。
sudo -u hdfs sqoop export -libjars /tmp/sqoop-hdfs/compile/047d0687acbb2298370a7b461cdfdd2e/WLSLOG_COPY.jar --connect "jdbc:mysql://e414f8c41d0b:3306/mysqldb" --password "mysql" --username "mysql" --export-dir "/mysql/import" --table "WLSLOG_COPY" --verbose
sqoop export命令的输出如图 11-26 所示。

图 11-26。
Output from the sqoop export command
sqoop export命令的详细输出如下:
root@08b338cb2a90:/# sudo -u hdfs sqoop export -libjars /tmp/sqoop-hdfs/compile/047d0687acbb2298370a7b461cdfdd2e/WLSLOG_COPY.jar --connect "jdbc:mysql://e414f8c41d0b:3306/mysqldb" --password "mysql" --username "mysql" --export-dir "/mysql/import" --table "WLSLOG_COPY" --verbose
15/10/22 00:13:52 INFO sqoop.Sqoop: Running Sqoop version: 1.4.5-cdh5.4.3
15/10/22 00:13:54 INFO tool.CodeGenTool: Beginning code generation
15/10/22 00:13:54 DEBUG manager.SqlManager: Execute getColumnInfoRawQuery : SELECT t.* FROM WLSLOG_COPY AS t LIMIT 1
15/10/22 00:13:54 DEBUG manager.SqlManager: No connection paramenters specified. Using regular API for making connection.
15/10/22 00:13:55 DEBUG manager.SqlManager: Using fetchSize for next query: -2147483648
15/10/22 00:13:55 INFO manager.SqlManager: Executing SQL statement: SELECT t.* FROM WLSLOG_COPY AS t LIMIT 1
15/10/22 00:13:55 DEBUG manager.SqlManager: Found column time_stamp of type [12, 255, 0]
15/10/22 00:13:55 DEBUG manager.SqlManager: Found column category of type [12, 255, 0]
15/10/22 00:13:55 DEBUG manager.SqlManager: Found column type of type [12, 255, 0]
15/10/22 00:13:55 DEBUG manager.SqlManager: Found column servername of type [12, 255, 0]
15/10/22 00:13:55 DEBUG manager.SqlManager: Found column code of type [12, 255, 0]
15/10/22 00:13:55 DEBUG manager.SqlManager: Found column msg of type [12, 255, 0]
15/10/22 00:13:55 DEBUG orm.ClassWriter: selected columns:
15/10/22 00:13:55 DEBUG orm.ClassWriter: time_stamp
15/10/22 00:13:55 DEBUG orm.ClassWriter: category
15/10/22 00:13:55 DEBUG orm.ClassWriter: type
15/10/22 00:13:55 DEBUG orm.ClassWriter: servername
15/10/22 00:13:55 DEBUG orm.ClassWriter: code
15/10/22 00:13:55 DEBUG orm.ClassWriter: msg
15/10/22 00:13:55 DEBUG manager.SqlManager: Using fetchSize for next query: -2147483648
15/10/22 00:13:55 INFO manager.SqlManager: Executing SQL statement: SELECT t.* FROM WLSLOG_COPY AS t LIMIT 1
15/10/22 00:13:55 DEBUG manager.SqlManager: Found column time_stamp of type VARCHAR
15/10/22 00:13:55 DEBUG manager.SqlManager: Found column category of type VARCHAR
15/10/22 00:13:55 DEBUG manager.SqlManager: Found column type of type VARCHAR
15/10/22 00:13:55 DEBUG manager.SqlManager: Found column servername of type VARCHAR
15/10/22 00:13:55 DEBUG manager.SqlManager: Found column code of type VARCHAR
15/10/22 00:13:55 DEBUG manager.SqlManager: Found column msg of type VARCHAR
15/10/22 00:13:55 DEBUG orm.ClassWriter: Writing source file: /tmp/sqoop-hdfs/compile/715ce1218221b63dfffd800222f863f0/WLSLOG_COPY.java
15/10/22 00:13:55 DEBUG orm.ClassWriter: Table name: WLSLOG_COPY
15/10/22 00:13:55 DEBUG orm.ClassWriter: Columns: time_stamp:12, category:12, type:12, servername:12, code:12, msg:12,
15/10/22 00:13:55 DEBUG orm.ClassWriter: sourceFilename is WLSLOG_COPY.java
15/10/22 00:13:55 DEBUG orm.CompilationManager: Found existing /tmp/sqoop-hdfs/compile/715ce1218221b63dfffd800222f863f0/
15/10/22 00:13:55 INFO orm.CompilationManager: HADOOP_MAPRED_HOME is /usr/lib/hadoop-mapreduce
15/10/22 00:13:55 DEBUG orm.CompilationManager: Returning jar file path /usr/lib/hadoop-mapreduce/hadoop-mapreduce-client-core.jar:/usr/lib/hadoop-mapreduce/hadoop-mapreduce-client-core-2.6.0-cdh5.4.3.jar
15/10/22 00:14:02 INFO mapreduce.ExportJobBase: Beginning export of WLSLOG_COPY
15/10/22 00:14:02 INFO Configuration.deprecation: mapred.job.tracker is deprecated. Instead, use mapreduce.jobtracker.address
15/10/22 00:14:02 INFO Configuration.deprecation: mapred.jar is deprecated. Instead, use mapreduce.job.jar
15/10/22 00:14:04 DEBUG mapreduce.JobBase: Using InputFormat: class org.apache.sqoop.mapreduce.ExportInputFormat
15/10/22 00:14:04 DEBUG db.DBConfiguration: Securing password into job credentials store
15/10/22 00:14:04 INFO jvm.JvmMetrics: Initializing JVM Metrics with processName=JobTracker, sessionId=
15/10/22 00:14:06 INFO input.FileInputFormat: Total input paths to process : 1
15/10/22 00:14:06 DEBUG mapreduce.ExportInputFormat: Target numMapTasks=4
15/10/22 00:14:06 DEBUG mapreduce.ExportInputFormat: Total input bytes=615
15/10/22 00:14:06 DEBUG mapreduce.ExportInputFormat: maxSplitSize=153
15/10/22 00:14:06 INFO input.FileInputFormat: Total input paths to process : 1
15/10/22 00:14:06 DEBUG mapreduce.ExportInputFormat: Generated splits:
15/10/22 00:14:06 DEBUG mapreduce.ExportInputFormat: Paths:/mysql/import/part-m-00000:0+153 Locations:08b338cb2a90:;
15/10/22 00:14:06 DEBUG mapreduce.ExportInputFormat: Paths:/mysql/import/part-m-00000:153+153 Locations:08b338cb2a90:;
15/10/22 00:14:06 DEBUG mapreduce.ExportInputFormat: Paths:/mysql/import/part-m-00000:306+153 Locations:08b338cb2a90:;
15/10/22 00:14:06 DEBUG mapreduce.ExportInputFormat: Paths:/mysql/import/part-m-00000:459+78,/mysql/import/part-m-00000:537+78 Locations:08b338cb2a90:;
15/10/22 00:14:06 INFO mapreduce.JobSubmitter: number of splits:4
15/10/22 00:14:06 INFO Configuration.deprecation: mapred.map.tasks.speculative.execution is deprecated. Instead, use mapreduce.map.speculative
15/10/22 00:14:06 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_local1198888838_0001
15/10/22 00:14:11 INFO mapreduce.Job: The url to track the job: http://localhost:8080/
15/10/22 00:14:11 INFO mapreduce.Job: Running job: job_local1198888838_0001
15/10/22 00:14:11 INFO mapred.LocalJobRunner: OutputCommitter set in config null
15/10/22 00:14:11 INFO mapred.LocalJobRunner: OutputCommitter is org.apache.sqoop.mapreduce.NullOutputCommitter
15/10/22 00:14:11 INFO mapred.LocalJobRunner: Waiting for map tasks
15/10/22 00:14:11 INFO mapred.LocalJobRunner: Starting task: attempt_local1198888838_0001_m_000000_0
15/10/22 00:14:11 DEBUG mapreduce.CombineShimRecordReader: ChildSplit operates on: hdfs://localhost:8020/mysql/import/part-m-00000
15/10/22 00:14:11 DEBUG db.DBConfiguration: Fetching password from job credentials store
15/10/22 00:14:12 DEBUG mapreduce.CombineShimRecordReader: ChildSplit operates on: hdfs://localhost:8020/mysql/import/part-m-00000
15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Instructing auto-progress thread to quit.
15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Waiting for progress thread shutdown...
15/10/22 00:14:12 INFO mapreduce.AutoProgressMapper: Auto-progress thread is finished. keepGoing=false
15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Progress thread shutdown detected.
15/10/22 00:14:12 INFO mapred.LocalJobRunner:
15/10/22 00:14:12 DEBUG mapreduce.AsyncSqlOutputFormat: Committing transaction of 1 statements
15/10/22 00:14:12 INFO mapred.Task: Task:attempt_local1198888838_0001_m_000000_0 is done. And is in the process of committing
15/10/22 00:14:12 INFO mapred.LocalJobRunner: map
15/10/22 00:14:12 INFO mapred.Task: Task 'attempt_local1198888838_0001_m_000000_0' done.
15/10/22 00:14:12 INFO mapred.LocalJobRunner: Finishing task: attempt_local1198888838_0001_m_000000_0
15/10/22 00:14:12 INFO mapred.LocalJobRunner: Starting task: attempt_local1198888838_0001_m_000001_0
15/10/22 00:14:12 INFO mapred.Task: Using ResourceCalculatorProcessTree : [ ]
15/10/22 00:14:12 INFO mapred.MapTask: Processing split: Paths:/mysql/import/part-m-00000:0+153
15/10/22 00:14:12 DEBUG mapreduce.CombineShimRecordReader: ChildSplit operates on: hdfs://localhost:8020/mysql/import/part-m-00000
15/10/22 00:14:12 DEBUG db.DBConfiguration: Fetching password from job credentials store
15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Instructing auto-progress thread to quit.
15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Waiting for progress thread shutdown...
15/10/22 00:14:12 INFO mapreduce.AutoProgressMapper: Auto-progress thread is finished. keepGoing=false
15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Progress thread shutdown detected.
15/10/22 00:14:12 INFO mapred.LocalJobRunner:
15/10/22 00:14:12 DEBUG mapreduce.AsyncSqlOutputFormat: Committing transaction of 1 statements
15/10/22 00:14:12 INFO mapred.Task: Task:attempt_local1198888838_0001_m_000001_0 is done. And is in the process of committing
15/10/22 00:14:12 INFO mapred.LocalJobRunner: map
15/10/22 00:14:12 INFO mapred.Task: Task 'attempt_local1198888838_0001_m_000001_0' done.
15/10/22 00:14:12 INFO mapred.LocalJobRunner: Finishing task: attempt_local1198888838_0001_m_000001_0
15/10/22 00:14:12 INFO mapred.LocalJobRunner: Starting task: attempt_local1198888838_0001_m_000002_0
15/10/22 00:14:12 INFO mapreduce.Job: Job job_local1198888838_0001 running in uber mode : false
15/10/22 00:14:12 INFO mapred.Task: Using ResourceCalculatorProcessTree : [ ]
15/10/22 00:14:12 INFO mapred.MapTask: Processing split: Paths:/mysql/import/part-m-00000:153+153
15/10/22 00:14:12 DEBUG mapreduce.CombineShimRecordReader: ChildSplit operates on: hdfs://localhost:8020/mysql/import/part-m-00000
15/10/22 00:14:12 INFO mapreduce.Job: map 100% reduce 0%
15/10/22 00:14:12 DEBUG db.DBConfiguration: Fetching password from job credentials store
15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Instructing auto-progress thread to quit.
15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Waiting for progress thread shutdown...
15/10/22 00:14:12 INFO mapreduce.AutoProgressMapper: Auto-progress thread is finished. keepGoing=false
15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Progress thread shutdown detected.
15/10/22 00:14:12 INFO mapred.LocalJobRunner:
15/10/22 00:14:12 DEBUG mapreduce.AsyncSqlOutputFormat: Committing transaction of 1 statements
15/10/22 00:14:12 INFO mapred.Task: Task:attempt_local1198888838_0001_m_000002_0 is done. And is in the process of committing
15/10/22 00:14:12 INFO mapred.LocalJobRunner: map
15/10/22 00:14:12 INFO mapred.Task: Task 'attempt_local1198888838_0001_m_000002_0' done.
15/10/22 00:14:12 INFO mapred.LocalJobRunner: Finishing task: attempt_local1198888838_0001_m_000002_0
15/10/22 00:14:12 INFO mapred.LocalJobRunner: Starting task: attempt_local1198888838_0001_m_000003_0
15/10/22 00:14:12 INFO mapred.Task: Using ResourceCalculatorProcessTree : [ ]
15/10/22 00:14:12 INFO mapred.MapTask: Processing split: Paths:/mysql/import/part-m-00000:306+153
15/10/22 00:14:12 DEBUG mapreduce.CombineShimRecordReader: ChildSplit operates on: hdfs://localhost:8020/mysql/import/part-m-00000
15/10/22 00:14:12 DEBUG db.DBConfiguration: Fetching password from job credentials store
15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Instructing auto-progress thread to quit.
15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Waiting for progress thread shutdown...
15/10/22 00:14:12 INFO mapreduce.AutoProgressMapper: Auto-progress thread is finished. keepGoing=false
15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Progress thread shutdown detected.
15/10/22 00:14:12 INFO mapred.LocalJobRunner:
15/10/22 00:14:12 DEBUG mapreduce.AsyncSqlOutputFormat: Committing transaction of 1 statements
15/10/22 00:14:12 INFO mapred.Task: Task:attempt_local1198888838_0001_m_000003_0 is done. And is in the process of committing
15/10/22 00:14:12 INFO mapred.LocalJobRunner: map
15/10/22 00:14:12 INFO mapred.Task: Task 'attempt_local1198888838_0001_m_000003_0' done.
15/10/22 00:14:12 INFO mapred.LocalJobRunner: Finishing task: attempt_local1198888838_0001_m_000003_0
15/10/22 00:14:12 INFO mapred.LocalJobRunner: map task executor complete.
15/10/22 00:14:13 INFO mapreduce.Job: Job job_local1198888838_0001 completed successfully
15/10/22 00:14:13 INFO mapreduce.Job: Counters: 23
File System Counters
FILE: Number of bytes read=71190614
FILE: Number of bytes written=72948608
FILE: Number of read operations=0
FILE: Number of large read operations=0
FILE: Number of write operations=0
HDFS: Number of bytes read=4068
HDFS: Number of bytes written=0
HDFS: Number of read operations=86
HDFS: Number of large read operations=0
HDFS: Number of write operations=0
Map-Reduce Framework
Map input records=6
Map output records=6
Input split bytes=576
Spilled Records=0
Failed Shuffles=0
Merged Map outputs=0
GC time elapsed (ms)=0
CPU time spent (ms)=0
Physical memory (bytes) snapshot=0
Virtual memory (bytes) snapshot=0
Total committed heap usage (bytes)=576782336
File Input Format Counters
Bytes Read=0
File Output Format Counters
Bytes Written=0
15/10/22 00:14:13 INFO mapreduce.ExportJobBase: Transferred 3.9727 KB in 8.722 seconds (466.4067 bytes/sec)
15/10/22 00:14:13 INFO mapreduce.ExportJobBase: Exported 6 records.
root@08b338cb2a90:/#
查询导出的数据
从 HDFS 导出到 MySQL 后,在 MySQL CLI 中使用下面的SELECT语句查询导出的数据。
select * from WLSLOG_COPY;
导出的六行数据列表如图 11-27 所示。

图 11-27。
Querying Exported Data in WLSLOG_COPY
停止和移除 Docker 容器
要移除mysqldb和cdh容器,必须首先停止容器。用docker stop命令停止mysqldb容器。
sudo docker stop mysqldb
用docker rm命令移除mysqldb容器。
sudo docker rm mysqldb
mysqldb容器停止移动,如图 11-28 所示。

图 11-28。
Stopping and Removing Docker Container for MySQL Database
同样,停止并移除cdh容器。
sudo docker stop cdh
sudo docker rm cdh
cdh容器停止移动,如图 11-29 所示。

图 11-29。
Stopping and Removing Docker Container for CDH
摘要
在这一章中,我们使用 CDH 和 MySQL 数据库的 Docker 镜像来运行两个独立但链接的 Docker 容器。我们在 Docker 容器中创建了一个 MySQL 数据库,并在 CDH 容器中运行了sqoop import工具,将数据从 MySQL 导入到 HDFS。随后,我们运行sqoop export工具从 HDFS 导出到 MySQL 数据库。在下一章,我们将讨论 ApacheKafka。
十二、使用 ApacheKafka
Apache Kafka 是一个基于发布-订阅模型的消息传递系统。Kafka 集群由一个或多个称为代理的服务器组成。Kafka 将信息按“主题”分类。生产者产生消息并将消息发布到主题。消费者订阅特定的主题并消费发布到该主题的消息的提要。发布到主题的消息不必在产生时就消费,而是在主题中存储可配置的持续时间。消费者可以选择从一开始就消费主题中的消息。Apache ZooKeeper 服务器用于协调 Kafka 集群。Kafka 式的建筑如图 12-1 所示。

图 12-1。
Apache Kafka Architecture
Apache Kafka 不直接基于 Apache Hadoop,也不使用 Apache Hadoop。但是 Kafka 可以被用作 Apache 水槽的源头、渠道或水槽。在本章中,我们将利用 Docker 映像在 Docker 容器中运行 Apache Kafka。本章包括以下几节。
- 设置环境
- 为 Apache Kafka 启动 Docker 容器
- 查找 IP 地址
- 列出 Kafka 的日志
- 创造一个 Kafka 主题
- 启动 Kafka 制作人
- 启动 Kafka 消费者
- 生产和消费消息
- 停止和移除 Docker 容器
设置环境
本章需要以下软件。
- -Docker(版本 1.8)
- Apache ZooKeeper 的 Docker 映像(最新版本)
- Apache Kafka 的 Docker 映像(最新版本)
连接到将要安装软件的 Amazon EC2 实例;公共 IP 地址对于不同的用户是不同的。
ssh -i "docker.pem" ec2-user@52.91.168.33
安装 Docker 并启动 Docker 服务。
sudo service docker start
OK 信息表示对接器已经启动,如图 12-2 所示。

图 12-2。
Starting Docker Service
下载 Apache ZooKeeper 的 Docker 图片dockerkafka/zookeeper。
sudo docker pull dockerkafka/zookeeper
Docker 镜像被下载,如图 12-3 所示。

图 12-3。
Downloading dockerkafka/zookeeper Docker Image
选择下载dockerkafka/zookeeper映像是因为相应的 dockerkafka/kafka 映像也是可用的。也下载 Docker 映像dockerkafka/kafka。
sudo docker pull dockerkafka/kafka
Docker 映像dockerkafka/kafka被下载,如图 12-4 所示。

图 12-4。
Downloading the dockerkafka/kafka Docker Image
为 Apache Kafka 启动 Docker 容器
我们需要启动 Apache ZooKeeper 和 Apache Kafka 容器,因为 Kafka 集群需要这两个容器。首先,使用下面的docker run命令启动 Apache ZooKeeper 的 Docker 容器,其中 ZooKeeper 的端口设置为 2181。Docker 容器使用–d选项在分离模式下启动。
sudo docker run -d --name zookeeper -p 2181:2181 dockerkafka/zookeeper
接下来,使用dockerkafka/kafka映像启动 Kafka 服务器的 Docker 容器。将 Kafka 服务器的端口指定为 9092,并使用–link参数将 Kafka 容器与运行 ZooKeeper 的容器链接起来。
sudo docker run --name kafka -p 9092:9092 --link zookeeper:zookeeper dockerkafka/kafka
用docker ps命令列出正在运行的容器。
sudo docker ps
两个容器,一个用于 Apache ZooKeeper,另一个用于 Apache Kafka,如图 12-5 所示。

图 12-5。
Listing Running Docker Containers
查找 IP 地址
要运行 Kakfa 生产者和消费者,我们需要找到运行 ZooKeeper 的 Docker 容器的 IP 地址和运行 Kafka 服务器的 Docker 容器的 IP 地址。运行以下两个命令来导出ZK_IP和KAFKA_IP环境变量。
export ZK_IP=$(sudo docker inspect --format '{{ .NetworkSettings.IPAddress }}' zookeeper)
export KAFKA_IP=$(sudo docker inspect --format '{{ .NetworkSettings.IPAddress }}' kafka)
随后,回显ZK_IP和KAFKA_IP变量。ZK_IP输出为172.17.0.1,KAFKA_IP输出为 172.17.0.2,如图 12-6 所示。我们将在后续章节中使用这些 IP 地址。

图 12-6。
Finding IP Addresses for Zookeeper and Kafka Servers
列出 Kafka 的日志
用docker logs命令输出 Docker 容器“kafka”的日志。
sudo docker logs -f kafka
输出表明 Kafka 服务器已经启动,如图 12-7 所示。

图 12-7。
Listing Kafka Logs
在随后的部分中,我们将创建一个 Kafka 主题,启动一个 Kafka 生产者,启动一个 Kafka 消费者,并在 Kafka 生产者处产生要在 Kafka 主题处发布的消息,并在 Kafka 消费者处消费这些消息。
创造一个 Kafka 主题
首先,我们需要创建一个 Kafka 主题来发布消息。使用以下命令启动交互式终端。
sudo docker exec -it kafka bash
用kafka-topics. sh –create命令在交互终端创建一个 Kafka 主题。用–topic选项指定要创建的主题为“测试”。将 ZooKeeper 地址指定为之前获取的 ZooKeeper 的 IP 地址,并在环境变量ZK_IP中设置。将 ZooKeeper 端口指定为 2181。使用--partitions选项将分区数量设置为 1,使用--replication-factor选项将复制因子设置为 1。
kafka-topics.sh --create --topic test --zookeeper 172.17.0.1:2181 --replication-factor 1 --partitions 1
该命令的输出被创建为“测试”主题,如图 12-8 所示。

图 12-8。
Creating a Kafka topic
启动 Kafka 制作人
接下来,从运行 kafka 服务器的“Kafka”容器的交互终端使用以下命令启动 Kafka 生成器。代理列表被指定为172.17.0.2:9092,其中 IP 地址是之前导出的环境变量KAFKA_IP。Kafka 服务器监听的端口是 9092。通过–topic选项将消息发布的主题设置为“测试”。
kafka-console-producer.sh --topic test --broker-list 172.17.0.2:9092
Kafka producer 控制台启动,如图 12-9 所示。

图 12-9。
Starting the Kafka Producer
启动 Kafka 消费者
对于 kafka 消费者控制台,我们需要为“Kafka”容器启动另一个交互式终端。
sudo docker exec -it kafka bash
运行以下命令来启动 Kafka 消费者控制台,以使用通过–topic选项指定的发布到“test”主题的消息。ZooKeeper host:port用–zookeeper选项设置为172.17.0.1:2181,其中 IP 地址为环境变量ZK_IP,端口为 2181。--from-beginning选项意味着从一开始就要使用消息。
kafka-console-consumer.sh --topic test --from-beginning --zookeeper 172.17.0.1:2181
Kafka 消费者控制台启动,如图 12-10 所示。

图 12-10。
Starting the Kafka Consumer
生产和消费消息
在本节中,我们将把消息从 Kafka 生产者发布到在我们启动生产者时配置的 Kafka 主题“test ”,并在也订阅了“test”主题的 Kafka 消费者处消费这些消息。
如图 12-11 所示,在制作人控制台发布一条消息“Docker 的 Kafka 你好”。单击 Enter 导航到控制台中的下一行。

图 12-11。
Producing a Message at the Kafka Producer
发布到“测试”主题的消息在 Kafka 消费者处被消费,并在消费者控制台中被输出,如图 12-12 所示。

图 12-12。
Consuming Messages at the Consumer
类似地,从 Kafka 生产者发布更多消息到“测试”主题,如图 12-13 所示。

图 12-13。
Producing More Messages at the Producer
消息在 Kafka 消费者控制台得到输出,如图 12-14 所示。

图 12-14。
Consumming Messages
停止和移除 Docker 容器
要停止 Docker 容器,运行docker stop命令。按如下方式停止“kafka”容器。
sudo docker stop kafka
“kafka”容器可以用docker rm命令删除。
sudo docker rm kafka
同样,停止并删除 Docker 容器“zookeeper”。
sudo docker stop zookeeper
sudo docker rm zookeeper
摘要
在本章中,我们使用了 Apache ZooKeeper 和 Apache Kafka 的 Docker 容器来运行链接到 Apache ZooKeeper 进程的 Kafka 服务器进程。我们创建了一个 Kafka 主题,启动了一个 Kafka 生产者,启动了一个 Kafka 消费者,从 Kafka 生产者向主题发布消息,并在消费者处消费这些消息。在下一章,我们将讨论使用 Apache Solr 和 Docker。
十三、使用 Apache Solr
Apache Solr 是一个基于 Apache Lucene(一个文本搜索引擎库)的开源搜索平台。Apache Solr 是可伸缩的和可靠的,并提供索引和查询服务。Cloudera 搜索基于 Apache Solr。在本章中,我们将使用 Apache Solr 的官方 Docker 映像在 Docker 容器中运行 Apache Solr。本章包括以下几节。
- 设置环境
- 启动 Apache Solr 服务器的 Docker 容器
- 启动交互式外壳
- 登录 Solr 管理控制台
- 创建核心管理索引
- 加载样本数据
- 在 Solr 管理控制台中查询 Apache Solr
- 使用 REST API 客户端查询 Apache Solr
- 删除数据
- 列出日志
- 停止 Apache Solr 服务器
设置环境
本章需要以下软件。
- -Docker 引擎(版本 1.8)
- apache solr 的 docker image
我们将使用一个基于 Ubuntu Server 14.04 LTS (HVM)的 Amazon EC2 实例,SSD 卷类型- ami-d05e75b8。使用用户名“ubuntu”和 Amazon EC2 实例的公共 IP 地址登录 Amazon EC2 实例。
ssh -i "docker.pem" ubuntu@54.208.53.110
Amazon EC2 上的 Ubuntu 实例被登录,如图 13-1 所示。

图 13-1。
Logging in to Ubuntu on AmazonEC2
按照第一章所述,在 Ubuntu 上安装 Docker。启动 Docker 服务。如果 Docker 已经启动,则输出一条消息“start:Job is has running:Docker”。
sudo service docker start
Docker 服务状态可以通过以下命令输出。
sudo service docker status
如图 13-2 所示,输出一条指示 docker 进程正在运行的消息。

图 13-2。
Starting and Finding Docker Service Status
接下来,用docker pull命令下载 Apache Solr 的官方 Docker 映像。
sudo docker pull solr
如图 13-3 所示下载 Docker 镜像。

图 13-3。
Downloading Docker Image solr
启动 Apache Solr 服务器的 Docker 容器
要启动 Apache Solr 服务器,请运行docker run命令,并将端口用–p指定为 8983。用–name选项指定容器名为“solr_on_docker”,这是任意的。–d命令参数使 Docker 容器以分离模式运行。
sudo docker run -p 8983:8983 -d --name solr_on_docker solr
用docker ps命令列出正在运行的 Docker 容器。
sudo docker ps
运行 Apache Solr 的 Docker 容器被列出,包括分配给容器的容器 id,如图 13-4 所示。

图 13-4。
Starting Docker Container for Apache Solr
运行docker logs命令来输出 Docker 容器的日志。docker 命令中可以使用容器名或容器 id。
sudo docker logs -f 8061f79d1f16
容器日志表明 Apache Solr 服务器已经启动,如图 13-5 所示。

图 13-5。
Listing Docker Container Log
启动交互式 Shell
以用户“solr”的身份启动 Docker 容器的交互式 shell。
sudo docker exec -it –user=solr solr_on_docker bash
交互式 shell(或 tty)启动,如图 13-6 所示。

图 13-6。
Starting TTY
Apache Solr 命令可以在交互终端中运行。
登录 Solr 管理控制台
如果运行 Apache Solr 服务器的 Docker 容器运行在不同于管理控制台的主机上,则使用运行 Docker 引擎和 Docker 容器的 Amazon EC2 实例的公共 DNS 名称。从 Amazon EC2 管理控制台获取公共 DNS。公共 DNS 为ec2-54-208-53-110.compute-1.amazonaws.com,如图 13-7 所示。

图 13-7。
Finding the Public DNS
使用 URL http://ec2-54-208-53-110.compute-1.amazonaws.com:8983/ 访问 Apache Solr 管理控制台。仪表板如图 13-8 所示。

图 13-8。
Logging in to Solr Admin Console
创建核心索引
接下来,创建一个核心,这是要存储在 Apache Solr 中的数据的索引。从 tty 运行bin/solr create_core命令来创建一个名为gettingstarted的内核。
bin/solr create_core -c gettingstarted
一个名为“gettingstarted”的新内核被创建,如图 13-9 所示。

图 13-9。
Creating a Core called “gettingstarted”
在 Solr 管理控制台中,选择核心管理,如图 13-10 所示。

图 13-10。
Selecting Core Admin
在型芯选择器中选择gettingstarted型芯,如图 13-11 所示。

图 13-11。
Selecting the gettingstarted Core
如图 13-12 所示,在空白处选择概览选项卡。会列出索引统计信息,如版本、文档数、最大文档数和已删除数。

图 13-12。
Displaying the Overview of the gettingstarted Core
加载样本数据
Apache Solr 支持 XML、JSON 和 CSV 格式的文档索引。我们将使用 XML 格式进行索引。根元素必须是<add/>,并且每个文档必须包含在<doc/>元素中。id字段是必填的。我们将索引下面的 XML 格式文档。将文件存储为solr.xml。
<add>
<doc>
<field name="id">SOLR1000</field>
<field name="name">Solr, the Enterprise Search Server</field>
<field name="manu">Apache Software Foundation</field>
<field name="cat">software</field>
<field name="cat">search</field>
<field name="features">Advanced Full-Text Search Capabilities using Lucene</field>
<field name="features">Optimized for High Volume Web Traffic</field>
<field name="features">Standards Based Open Interfaces - XML and HTTP</field>
<field name="features">Comprehensive HTML Administration Interfaces</field>
<field name="features">Scalability - Efficient Replication to other Solr Search Servers</field>
<field name="features">Flexible and Adaptable with XML configuration and Schema</field>
<field name="features">Good unicode support: héllo (hello with an accent over the e)</field>
<field name="price">0</field>
<field name="popularity">10</field>
<field name="inStock">true</field>
<field name="incubationdate_dt">2006-01-17T00:00:00.000Z</field>
</doc>
</add>
将 solr.xml 复制到 Docker 容器中的/opt/solr目录。从 Ubuntu 主机而不是 Docker 容器运行下面的docker cp命令,将solr.xml文档复制到 id 为8061f79d1f16的 Docker 容器,该容器运行 Apache Solr 服务器。容器 id 可以从docker ps命令的输出中获得。
sudo docker cp solr.xml 8061f79d1f16:/opt/solr/solr.xml
solr.xml文档被复制到 Docker 容器中的/opt/solr目录,如图 13-13 所示。

图 13-13。
Copying solr.xml to DockerContainer
使用以下命令启动交互式终端(tty)。
sudo docker exec -it –user=solr solr_on_docker bash
从/opt/solr目录运行以下命令,列出目录中的文件和目录。solr.xml应被列出,如图 13-14 所示。

图 13-14。
Listing the solr.xml File in Docker Container
运行以下命令将 solr.xml 发布到gettingstarted索引。
bin/post -c gettingstarted ./solr.xml
solr.xml文件被索引,如图 13-15 所示。

图 13-15。
indexing solr.xml
在 Solr 管理控制台中查询 Apache Solr
可以从 Solr 管理控制台查询索引文档。选择查询页签,如图 13-16 所示。

图 13-16。
Selecting the Query tab
请求处理程序(qt)应该设置为/select,查询应该设置为。选择索引中的所有文件,如图 13-17 所示。起始索引设置为 0,要选择的行数设置为 10。将wt(响应编写器)设置为json,以 JSON 格式返回查询到的文档。其他支持的格式有 XML 和 CSV。

图 13-17。
The /select Request Handler
点击执行查询,如图 13-18 所示。

图 13-18。
Clicking on Execute Query
查询结果返回为 JSON,如图 13-19 所示。

图 13-19。
JSON Response from Query
版本字段被添加到返回的 JSON 文档中,如图 13-20 所示。

图 13-20。
The version field added automatically
使用 REST API 客户端查询 Apache Solr
Apache Solr 索引的文档也可以使用 REST 客户端访问,比如curl。例如,从“solr”容器的交互终端运行下面的curl命令,查询gettingstarted索引中的所有文档。
curl http://ec2-54-208-53-110.compute-1.amazonaws.com:8983/solr/gettingstarted/select?q=*%3A*&wt=json&indent=true
在gettingstarted索引中被索引的所有文档得到如图 13-21 所示的输出。

图 13-21。
Running a REST Client Query
再比如,查询文档中带有“Lucene”的所有文档。
curl "``http://ec2-54-208-53-110.compute-1.amazonaws.com:8983/solr/gettingstarted/select?wt=json&indent=true&q=Lucene
由于被索引的单个文档中包含“Lucene ”,因此该文档将被返回,如图 13-22 所示。

图 13-22。
Running a REST Client Query using term ‘Lucene’
要查询具有特定字段文本的文档,请使用q参数中的field=text格式。例如,搜索“名称”字段中带有“Lucene”的所有文档。
curl "``http://ec2-54-208-53-110.compute-1.amazonaws.com:8983/solr/gettingstarted/select?wt=json&indent=true&q=name:Lucene
由于索引中的单个文档的名称字段不包含“Lucene ”,因此没有返回任何文档,如图 13-23 所示。

图 13-23。
Running a REST Client Query with “Lucene” in “name” Field
还可以使用 REST 客户端执行短语搜索。例如,搜索短语“企业搜索”。
curl "``http://ec2-54-208-53-110.compute-1.amazonaws.com:8983/solr/gettingstarted/select?wt=json&indent=true&q=\"Enterprise+Search
由于单个文档中包含“企业搜索”,因此该文档将返回,如图 13-24 所示。

图 13-24。
Running a REST Query using a Phrase
删除数据
要删除文档,请运行与发布文档相同的工具,即发布工具。使用 XML <delete><id></id></delete>指定要删除的文档 id。要删除的索引由–c选项指定。
bin/post -c gettingstarted -d "<delete><id>SOLR1000</id></delete>"
如图 13-25 所示,id 为SOLR1000,的被索引的单个文档被删除。

图 13-25。
Deleting a Single Document
随后,运行与之前相同的 curl 命令来搜索所有文档。
curl http://ec2-54-208-53-110.compute-1.amazonaws.com:8983/solr/gettingstarted/select?q=*%3A*&wt=json&indent=true
没有找到如图 13-26 所示的文件,因为唯一索引的文件已被删除。

图 13-26。
REST Query does not list any Document after deleting the only document
删除唯一的索引文档后,在 Solr 管理控制台中运行一个查询,没有返回任何文档,如返回的 JSON 文档中的字段值 0 所示,如图 13-27 所示。

图 13-27。
Query in Sole Admin Console does not list any document after Deleting the only Document
列出日志
Apache Solr 服务器上运行的所有命令的 Docker 容器日志可以使用docker logs命令输出。
sudo docker logs -f solr_on_docker
Docker 容器日志的输出如图 13-28 所示。

图 13-28。
Listing Docker Container Logs
停止 Apache Solr 服务器
可以用docker ps命令列出正在运行的 Docker 容器。solr_on_docker容器列为运行中,如图 13-29 所示。

图 13-29。
Listing Running Docker Containers
要停止solr_on_docker容器,运行docker stop命令,如图 13-30 所示。
sudo docker stop solr_on_docker
运行docker ps命令再次列出正在运行的 Docker 容器。solr_on_docker容器没有被列出。

图 13-30。
Stopping Docker Container for Apache Solr
Docker 映像仍然会用docker images命令列出,如图 13-31 所示。

图 13-31。
Listing Docker Image for a stopped Docker Container
如果要删除 Docker 映像,首先必须在停止后删除 Docker 容器solr_on_docker。
sudo docker rm solr_on_docker
sudo docker rm solr
摘要
在本章中,我们使用 Apache Solr 的官方 Docker 映像在 Docker 容器中运行 Apache Solr 服务器。我们创建了一个核心索引,并向该索引发布了一个文档。随后,我们从 Solr 管理控制台和 REST 客户端工具 curl 查询文档。在下一章,我们将和 Docker 讨论 Apache Spark。
十四、使用 Apache Spark
Apache Spark 是一个用于大型数据集的数据处理引擎。Apache Spark 比 Apache Hadoop MapReduce 快得多(内存快 100 倍)。在集群模式下,Spark 应用作为独立的进程运行,由主程序驱动程序中的SparkContext对象协调。SparkContext可以连接到几种类型的集群管理器,为 Spark 应用分配资源。支持的集群管理器包括独立的集群管理器、Mesos 和 YARN。Apache Spark 旨在访问来自各种数据源的数据,包括 HDFS、Apache HBase 和 NoSQL 数据库,如 Apache Cassandra 和 MongoDB。在这一章中,我们将使用我们用于几个 Apache Hadoop 框架(包括 Apache Hive 和 Apache HBase)的相同的 CDH Docker 映像。我们将使用 Docker 容器中的 YARN cluster manager 在集群模式下运行 Apache Spark Master。
- 设置环境
- 运行 CDH 的 Docker 容器
- 以纱线集群模式运行 Apache Spark 作业
- 在 yarn-client 模式下运行 Apache Spark 作业
- 运行 Apache Spark Shell
设置环境
本章需要以下软件。
- -Docker 引擎(版本 1.8)
- apache spark 的 docker image
使用 Amazon EC2 实例的公共 IP 地址连接到该实例。公共 IP 地址可以从 Amazon EC2 控制台找到,如附录 a 中所述。
ssh -i "docker.pem" ec2-user@54.208.146.254
启动 Docker 服务并验证状态是否为已启动。
sudo service docker start
sudo service docker status
下载 CDH 的 Docker 镜像,svds/cdh 镜像(如果之前章节没有下载的话)。
sudo docker pull svds/cdh
Docker 镜像 svds/cdh 被下载,如图 14-1 所示。

图 14-1。
Downloading svds/cdh Docker Image
运行 CDH 的 Docker 容器
使用 Apache Spark 主端口 as 8088 为 CDH 框架启动一个 Docker 容器。
sudo docker run -p 8088 -d --name cdh svds/cdh
列出正在运行的 Docker 容器。
sudo docker ps
包括 Apache Spark 在内的 cdh 进程启动,容器 CDH 被列为正在运行,如图 14-2 所示。

图 14-2。
Starting Docker Container for CDH including Apache Spark
为 cdh 容器启动一个交互式终端。
sudo docker exec -it cdh bash
交互终端启动,如图 14-3 所示。

图 14-3。
Starting the TTY
在 YARN 模式中,Spark 应用可以提交给 yarn-cluster 模式或 yarn-client 模式中的集群。在 yarn-cluster 模式下,Apache Spark 驱动程序运行在一个由 yarn 管理的应用主机中。在纱线客户端模式下。Spark 驱动程序在 YARN 之外的客户端进程中运行,而应用主机仅用于向 YARN 请求资源。根据提交申请的方式,--master参数为yarn-cluster或yarn-client。在 yarn-client 模式下,Spark 驱动程序登录到控制台。
我们将使用每种应用提交模式运行 Spark 应用。我们将使用示例应用org.apache.spark.examples.SparkPi。
以纱线集群模式运行 Apache Spark 作业
要使用 1000 次迭代在纱线簇模式下提交 Spark 应用SparkPi,运行下面的spark-submit命令,将--master参数作为纱线簇。
spark-submit --master yarn-cluster --class org.apache.spark.examples.SparkPi /usr/lib/spark/examples/lib/spark-examples-1.3.0-cdh5.4.7-hadoop2.6.0-cdh5.4.7.jar 1000
前面的命令从交互终端运行,如图 14-4 所示。

图 14-4。
Submitting the Spark Application in yarn-cluster Mode
火花应用的输出如图 14-5 所示。

图 14-5。
Output from Spark Job in yarn-cluster Mode
下面列出了来自spark-submit命令的更详细的输出:
spark-submit --master yarn-cluster --class org.apache.spark.examples.SparkPi /usr/lib/spark/examples/lib/spark-examples-1.3.0-cdh5.4.7-hadoop2.6.0-cdh5.4.7.jar 1000
15/10/23 19:12:52 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
15/10/23 19:12:54 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032
15/10/23 19:12:56 INFO yarn.Client: Requesting a new application from cluster with 1 NodeManagers
15/10/23 19:12:56 INFO yarn.Client: Verifying our application has not requested more than the maximum memory capability of the cluster (8192 MB per container)
15/10/23 19:12:56 INFO yarn.Client: Will allocate AM container, with 896 MB memory including 384 MB overhead
15/10/23 19:12:56 INFO yarn.Client: Setting up container launch context for our AM
15/10/23 19:12:56 INFO yarn.Client: Preparing resources for our AM container
15/10/23 19:12:59 WARN shortcircuit.DomainSocketFactory: The short-circuit local reads feature cannot be used because libhadoop cannot be loaded.
15/10/23 19:12:59 INFO yarn.Client: Uploading resource file:/usr/lib/spark/lib/spark-assembly-1.3.0-cdh5.4.7-hadoop2.6.0-cdh5.4.7.jar -> hdfs://localhost:8020/user/root/.sparkStaging/application_1445627521793_0001/spark-assembly-1.3.0-cdh5.4.7-hadoop2.6.0-cdh5.4.7.jar
15/10/23 19:13:05 INFO yarn.Client: Uploading resource file:/usr/lib/spark/examples/lib/spark-examples-1.3.0-cdh5.4.7-hadoop2.6.0-cdh5.4.7.jar -> hdfs://localhost:8020/user/root/.sparkStaging/application_1445627521793_0001/spark-examples-1.3.0-cdh5.4.7-hadoop2.6.0-cdh5.4.7.jar
15/10/23 19:13:06 INFO yarn.Client: Setting up the launch environment for our AM container
15/10/23 19:13:07 INFO spark.SecurityManager: Changing view acls to: root
15/10/23 19:13:07 INFO spark.SecurityManager: Changing modify acls to: root
15/10/23 19:13:07 INFO spark.SecurityManager: SecurityManager: authentication disabled; ui acls disabled; users with view permissions: Set(root); users with modify permissions: Set(root)
15/10/23 19:13:07 INFO yarn.Client: Submitting application 1 to ResourceManager
15/10/23 19:13:08 INFO impl.YarnClientImpl: Submitted application application_1445627521793_0001
15/10/23 19:13:09 INFO yarn.Client: Application report for application_1445627521793_0001 (state: ACCEPTED)
15/10/23 19:13:09 INFO yarn.Client:
client token: N/A
diagnostics: N/A
ApplicationMaster host: N/A
ApplicationMaster RPC port: -1
queue: root.root
start time: 1445627587658
final status: UNDEFINED
tracking URL: http://4b4780802318:8088/proxy/application_1445627521793_0001/
user: root
15/10/23 19:13:10 INFO yarn.Client: Application report for application_1445627521793_0001 (state: ACCEPTED)
15/10/23 19:13:11 INFO yarn.Client: Application report for application_1445627521793_0001 (state: ACCEPTED)
15/10/23 19:13:24 INFO yarn.Client: Application report for application_1445627521793_0001 (state: RUNNING)
15/10/23 19:13:24 INFO yarn.Client:
client token: N/A
diagnostics: N/A
ApplicationMaster host: 4b4780802318
ApplicationMaster RPC port: 0
queue: root.root
start time: 1445627587658
final status: UNDEFINED
tracking URL: http://4b4780802318:8088/proxy/application_1445627521793_0001/
user: root
15/10/23 19:13:25 INFO yarn.Client: Application report for application_1445627521793_0001 (state: RUNNING)
15/10/23 19:13:26 INFO yarn.Client: Application report for
15/10/23 19:13:51 INFO yarn.Client: Application report for application_1445627521793_0001 (state: FINISHED)
15/10/23 19:13:51 INFO yarn.Client:
client token: N/A
diagnostics: N/A
ApplicationMaster host: 4b4780802318
ApplicationMaster RPC port: 0
queue: root.root
start time: 1445627587658
final status: SUCCEEDED
tracking URL: http://4b4780802318:8088/proxy/application_1445627521793_0001/A
user: root
在纱线聚类模式下,Spark 应用结果不会输出到控制台,如果最终状态为SUCCEEDED,则必须使用浏览器中的跟踪 URL http://4b4780802318:8088/proxy/application_1445627521793_0001/A从ResourceManager访问纱线容器日志。
在 yarn-client 模式下运行 Apache Spark 作业
要在 yarn-client 模式下提交使用 1000 次迭代的 Spark 应用SparkPi,运行下面的spark-submit命令,将--master参数作为 yarn-client。
spark-submit
--master yarn-client
--class org.apache.spark.examples.SparkPi
/usr/lib/spark/examples/lib/spark-examples-1.3.0-cdh5.4.7-hadoop2.6.0-cdh5.4.7.jar
1000
火花提交命令的输出如图 14-6 所示。

图 14-6。
Submitting Spark Application in yarn-client Mode
来自 Apache Spark 应用的更详细的输出如下所示,其中包括近似计算的 Pi 值。
spark-submit --master yarn-client --class org.apache.spark.examples.SparkPi /usr/lib/spark/examples/lib/spark-examples-1.3.0-cdh5.4.7-hadoop2.6.0-cdh5.4.7.jar 1000
15/10/23 19:15:19 INFO spark.SparkContext: Running Spark version 1.3.0
15/10/23 19:15:43 INFO cluster.YarnScheduler: Adding task set 0.0 with 1000 tasks
15/10/23 19:15:43 INFO scheduler.TaskSetManager: Starting task 0.0 in stage 0.0 (TID 0, 4b4780802318, PROCESS_LOCAL, 1353 bytes)
15/10/23 19:15:43 INFO scheduler.TaskSetManager: Starting task 1.0 in stage 0.0 (TID 1, 4b4780802318, PROCESS_LOCAL, 1353 bytes)
15/10/23 19:15:57 INFO scheduler.TaskSetManager: Finished task 999.0 in stage 0.0 (TID 999) in 22 ms on 4b4780802318 (999/1000)
15/10/23 19:15:57 INFO scheduler.TaskSetManager: Finished task 998.0 in stage 0.0 (TID 998) in 28 ms on 4b4780802318 (1000/1000)
15/10/23 19:15:57 INFO cluster.YarnScheduler: Removed TaskSet 0.0, whose tasks have all completed, from pool
15/10/23 19:15:57 INFO scheduler.DAGScheduler: Stage 0 (reduce at SparkPi.scala:35) finished in 14.758 s
15/10/23 19:15:57 INFO scheduler.DAGScheduler: Job 0 finished: reduce at SparkPi.scala:35, took 15.221643 s
Pi is roughly 3.14152984
运行 Apache Spark Shell
Apache Spark shell 在 yarn-client 模式下启动,如下所示。
spark-shell --master yarn-client
显示如图 14-7 所示的scala>命令提示符。Spark 上下文被创建并作为“sc”可用。SQL 上下文也可以作为“SQL context”使用。

图 14-7。
The scala> Command Prompt
spark-shell命令更详细的输出如下。
root@4b4780802318:/# spark-shell --master yarn-client
15/10/23 19:17:16 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
15/10/23 19:17:16 INFO spark.SecurityManager: Changing view acls to: root
15/10/23 19:17:16 INFO spark.SecurityManager: Changing modify acls to: root
15/10/23 19:17:16 INFO spark.SecurityManager: SecurityManager: authentication disabled; ui acls disabled; users with view permissions: Set(root); users with modify permissions: Set(root)
15/10/23 19:17:16 INFO spark.HttpServer: Starting HTTP Server
15/10/23 19:17:16 INFO server.Server: jetty-8.y.z-SNAPSHOT
15/10/23 19:17:16 INFO server.AbstractConnector: Started SocketConnector@0.0.0.0:56899
15/10/23 19:17:16 INFO util.Utils: Successfully started service 'HTTP class server' on port 56899.
Welcome to
____ __
/ __/__ ___ _____/ /__
_\ \/ _ \/ _ / __/ '_/`
/___/ .__/\_,_/_/ /_/\_\ version 1.3.0
/_/
Using Scala version 2.10.4 (OpenJDK 64-Bit Server VM, Java 1.7.0_79)
Type in expressions to have them evaluated.
Type :help for more information.
15/10/23 19:17:22 INFO spark.SparkContext: Running Spark version 1.3.0
15/10/23 19:17:45 INFO repl.SparkILoop: Created spark context..
Spark context available as sc.
15/10/23 19:17:45 INFO repl.SparkILoop: Created sql context (with Hive support)..
SQL context available as sqlContext.
15/10/23 19:17:45 INFO storage.BlockManagerMasterActor: Registering block manager 4b4780802318:48279 with 530.3 MB RAM, BlockManagerId(2, 4b4780802318, 48279)
scala>
运行下面的 Scala 脚本,它由一个 Hello World 程序的 Spark shell 中的HelloWorld模块组成。
object HelloWorld {
def main(args: Array[String]) {
println("Hello, world!")
}
}
HelloWorld.main(null)
Scala 脚本的输出如图 14-8 所示。

图 14-8。
Output from Scala Script
摘要
在本章中,我们使用 spark-submit 命令在 Docker 容器中的 YARN 集群上运行了 Apache Spark 应用。我们以 yarn-cluster 和 yarn-client 模式提交了示例应用。我们还在 Spark shell 中运行了一个HelloWorld Scala 脚本。
这一章结束了关于 Docker 的书。除了在 Docker 上运行一些常用的软件,我们还讨论了主要的 Docker 管理任务,例如安装 Docker、下载 Docker 映像、创建和运行 Docker 容器、启动交互式 shell、在交互式 shell 中运行命令、列出 Docker 容器、列出 Docker 容器日志、停止 Docker 容器以及删除 Docker 容器和 Docker 映像。在本书的范围内,只有一些软件应用可以被讨论。在 https://hub.docker.com/ 的 Docker hub 上还有更多 Docker 图片。
十五、使用亚马逊 EC2
亚马逊网络服务(AWS)提供各种服务,亚马逊弹性计算云(Amazon EC2)就是其中之一。Amazon EC2 可用于创建虚拟主机服务器。Amazon EC2 在创建虚拟服务器时提供了大量实例 ami(Amazon 机器映像)供选择。在本附录中,我们将讨论创建和配置 Amazon EC2 实例以安装 Docker 和 Docker 映像。Amazon EC2 实例不是运行 Docker 软件的必要条件,可以使用本地或远程的替代平台。
- 创建 Amazon EC2 实例
- 创建密钥对
- 启动 Amazon EC2 实例
- 连接到 Amazon EC2 实例
- 查找公共 IP 地址
- 查找公共 DNS
- 添加默认安全组
- 停止 Amazon EC2 实例
- 更改实例类型
创建 Amazon EC2 实例
我们已经使用基于 Linux 的 Amazon EC2 实例来部署 Docker 和 Docker 映像。Amazon EC2 不是必需的,可以使用本地 Linux 安装等替代方法。Linux 平台需要支持 64 位软件。我们使用了两种不同的 64 位(必需的)ami:
Ubuntu Server 14.04 LTS (HVM), SSD Volume Type - ami-d05e75b8 64 bit Red Hat Enterprise Linux version 7.1 (HVM), EBS General Purpose (SSD) Volume Type (ami-12663b7a) 64 bit
要创建一个 Amazon EC2 实例,需要一个 Amazon Web Services 帐户,可以在 https://aws.amazon.com/getting-started/?nc2=h_l2_cc 创建。要创建一个 Amazon EC2 实例,请导航到 https://aws.amazon.com/ec2/ 并点击登录控制台。从列出的 Amazon Web Services 中选择 EC2。点击实例➤实例,列出账户中已经创建的 Amazon EC2 实例。单击 Launch Instance 创建一个新的 Amazon EC2 实例,如图 A-1 所示。

图 A-1。
Launching an Amazon EC2 Instance
选择要从中创建虚拟服务器的 AMI。一些非盟驻苏特派团有资格获得免费等级。比如选择 Ubuntu AMI,如图 A-2 所示。

图 A-2。
Selecting an AMI
在选择实例类型时,根据支持的容量和虚拟 CPU(vcpu)等功能的不同,可以使用不同的类型。选择一种实例类型,例如通用➤ t2.micro,然后单击查看并启动,如图 A-3 所示。

图 A-3。
Review and Launch
在审核实例启动中点击启动,如图 A-4 所示。

图 A-4。
Launch
将显示一个对话框,用于创建或选择现有的密钥对。授权需要密钥对。要创建新的密钥对,选择“创建新的密钥对”选项,如图 A-5 所示。

图 A-5。
Selecting “Create a new key pair”
指定密钥对名称并点击下载密钥对,如图 A-6 所示。密钥对被创建和下载。连接到实例时需要在创建实例时为 Amazon EC2 实例选择的密钥对,这将在本附录的后面讨论。

图 A-6。
Download Key Pair
或者,选择“选择一个现有的密钥对”选项,并点击如图 A-7 所示的启动实例。

图 A-7。
Choose an existing Key Pair
将显示启动状态。点击实例 id,显示如图 A-8 所示的实例。

图 A-8。
Launch Status
该实例被列出,并且最初处于“挂起”状态,如图 A-9 所示。

图 A-9。
Amazon EC2 Instance in Pending State
当一个实例完全启动后,实例状态变为“正在运行”,如图 A-10 所示。

图 A-10。
Running Instance
创建密钥对
如前所述,连接 Amazon EC2 实例需要一个密钥对。密钥对可以在创建实例时创建,也可以单独创建。要创建密钥对,请分别选择网络和安全➤密钥对,如图 A-11 所示。

图 A-11。
Network & Security ➤ Key Pairs
列出已经创建的密钥对。可以通过选择密钥对并点击删除来删除密钥对。在如图 A-12 所示的对话框中点击是。

图 A-12。
Delete Key Pair
要创建新的密钥对,点击创建密钥对,如图 A-13 所示。

图 A-13。
Create Key Pair
指定一个密钥对名称并点击创建按钮,如图 A-14 所示。

图 A-14。
Create Button
如图 A-15 所示,创建一个新的密钥对。

图 A-15。
New Key Pair
启动 Amazon EC2 实例
当创建一个新的 Amazon EC2 实例并选择 Launch 时,该实例就会启动。可以通过选中实例旁边的复选框并选择操作➤实例状态➤启动来启动已停止的实例,如图 A-16 所示。

图 A-16。
Actions ➤ Instance State ➤ Start
在启动实例对话框中点击是,启动如图 A-17 所示。

图 A-17。
Starting an instance
连接到 Amazon EC2 实例
已经启动的实例可以从本地机器(例如本地 Linux 实例)连接到,而没有与所连接的实例一样多的 RAM 和不同的 Linux 发行版。如图 A-18 所示,可以通过点击 connect 来获得用于连接正在运行的实例的 ssh 命令。

图 A-18。
Connect
在“连接到实例”对话框中,将显示 ssh 命令。“docker.pem”是用于创建实例的密钥对,也下载到 Amazon EC2 实例要连接的本地实例。ubuntu 实例的用户名是“Ubuntu”,如图 A-19 所示,而 Red Hat 实例的用户名是“ec2-user”。

图 A-19。
Connect To Your Instance dialog
ssh 命令中显示的 IP 地址是 Amazon EC2 实例的公共 IP 地址。
查找公共 IP 地址
公共 IP 地址也可以从 EC2 控制台获得,如图 A-20 所示。

图 A-20。
Public IP Address
查找公共 DNS
要从远程浏览器连接到 Amazon EC2 实例流程,比如第一章中的HelloWorld应用,需要公共 DNS。公共 DNS 也可以从 EC2 管理控制台获得,如图 A-21 所示。

图 A-21。
Public DNS
公共 DNS 最初可能不会显示。要显示公共 DNS,在 EC2 管理控制台中选择服务➤ VPC,如图 A-22 所示。VPC 是分配给用户的虚拟私有云。

图 A-22。
Services ➤ VPC
在 VPC 仪表板中,选择您的 VPC,如图 A-23 所示。

图 A-23。
Your VPCs
选择如图 A-24 所示的 VPC 列表。

图 A-24。
Selecting the VPC
从操作中,选择编辑 DNS 主机名,如图 A-25 所示。

图 A-25。
Edit DNS Hostnames
在编辑 DNS 主机名对话框中,为 DNS 主机名选择是,并点击保存,如图 A-26 所示。

图 A-26。
Edit DNS Hostnames Dialog
添加默认安全组
为了能够从远程浏览器进行连接,需要设置入站和出站规则,以允许来自任何来源、在 0-65535 范围内的所有端口上使用任何协议的所有流量。“默认”安全组默认配置为允许所有流量。我们需要将“默认”安全组分配给运行 Docker 的 Amazon EC2 实例。选择实例,然后选择操作➤网络➤更改安全组,如图 A-27 所示。

图 A-27。
Actions ➤ Networking ➤ Change Security Groups
在更改安全组面板中,可能没有选择“默认”组,如图 A-28 所示。

图 A-28。
The “default” group not selected
选择“默认”安全组的复选框,并点击分配安全组,如图 A-29 所示。

图 A-29。
Assign Security Groups
默认的安全组被分配给 Amazon EC2 实例。要查找可用的安全组及其入站/出站规则,请单击网络与安全➤安全组,如图 A-30 所示。

图 A-30。
Network & Security ➤ Security Groups
应该列出“默认”安全组。选择“默认”组。选择入站选项卡。类型应该列为“所有流量”,协议应该列为“所有”,端口范围应该列为“所有”,源应该列为 0.0.0.0。要编辑入站规则,点击入站➤编辑,如图 A-31 所示。

图 A-31。
Inbound ➤ Edit
入站规则将显示出来,并应保持默认设置,如图 A-32 所示。点击保存。

图 A-32。
Edit inbound rules dialog
同样,选择出站选项卡。类型应列为“所有流量”,协议应列为“所有”,端口范围应列为“所有”,目的地应列为 0.0.0.0。点击编辑,如图 A-33 所示。

图 A-33。
Outbound ➤ Edit
将显示出站规则的默认设置,并应保持默认设置,如图 A-34 所示。点击保存。

图 A-34。
Edit outbound rules dialog
分配给实例的安全组列在安全组列中,如图 A-35 所示。

图 A-35。
Security Groups column
停止 Amazon EC2 实例
要停止一个 Amazon EC2 实例,请选择该实例,然后选择 Actions ➤实例状态➤停止,如图 A-36 所示。

图 A-36。
Actions ➤ Instance State ➤ Stop
可以选择多个实例并一起停止,如图 A-37 所示。

图 A-37。
Stopping Multiple Instances
在停止实例对话框中,点击是,停止如图 A-38 所示。

图 38。
Stop Instance dialog
实例被停止。
更改实例类型
要增加或减少实例的容量,可能需要更改实例类型,例如从微型实例更改为中型实例。在更改实例类型之前,必须首先停止实例,然后在修改类型之后重新启动实例。要更改实例类型,请选择实例并选择操作➤实例设置➤更改实例类型,如图 A-39 所示。

图 39。
Actions ➤ Instance Settings ➤ Change Instance Type
在 Change Instance Type 对话框中,选择要应用的实例类型,例如 m3.medium,如图 A-40 所示。

图 A-40。
Change Instance Type dialog
点击应用,如图 A-41 所示。

图 A-41。
Applying a new Instance Type
实例类型升级到 m3.medium,如图 A-42 所示。请记住,升级实例类型可能会使该实例不符合空闲层的条件。

图 A-42。
Upgraded Instance Type
摘要
在附录 A 中,我们讨论了基于 AMI 创建 Amazon EC2 实例、启动实例、连接实例、查找公共 IP 地址、查找公共 DNS、更改实例类型和停止实例。


浙公网安备 33010602011771号