Docker-高级教程-全-

Docker 高级教程(全)

原文:Pro Docker

协议:CC BY-NC-SA 4.0

一、你好,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 所示。

A978-1-4842-1830-3_1_Fig1_HTML.jpg

图 1-1。

Amazon EC2 Instance Based on Ubuntu AMI

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

A978-1-4842-1830-3_1_Fig2_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_1_Fig3_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_1_Fig4_HTML.jpg

图 1-4。

Connecting to RHEL Instance

运行以下命令,查看 Linux 体系结构是否支持 64 位软件。

uname -r

图 1-5 输出中的 x86_64 表示支持 64 位。

A978-1-4842-1830-3_1_Fig5_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_1_Fig6_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_1_Fig7_HTML.jpg

图 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 没问题。

A978-1-4842-1830-3_1_Fig8_HTML.jpg

图 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 消息所示。

A978-1-4842-1830-3_1_Fig9_HTML.jpg

图 1-9。

Starting Docker Service

查找 Docker 服务状态

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

sudo service docker status

如果 Docker 服务正在运行,则应输出如图 1-10 所示的消息 Active: active (running)。

A978-1-4842-1830-3_1_Fig10_HTML.jpg

图 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 上生成的。

A978-1-4842-1830-3_1_Fig11_HTML.jpg

图 1-11。

Running hello-world Application

在 Ubuntu 上,对hello-world运行相同的命令。

sudo docker run hello-world

如图 1-12 所示,输出“你好,来自 Docker”消息。

A978-1-4842-1830-3_1_Fig12_HTML.jpg

图 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 映像的标签,指定了映像版本,默认情况下会下载最新版本。

A978-1-4842-1830-3_1_Fig13_HTML.jpg

图 1-13。

Downloading tutum:hello-world:latest

使用以下命令列出下载的 Docker 映像。

sudo docker images

除了之前可能已经安装的其他映像之外,tutum/hello-world Docker 映像被列出,如图 1-14 所示。

A978-1-4842-1830-3_1_Fig14_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_1_Fig15_HTML.jpg

图 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 stopdocker start,可以使用容器名或容器 id。

A978-1-4842-1830-3_1_Fig16_HTML.jpg

图 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 地址。

A978-1-4842-1830-3_1_Fig17_HTML.jpg

图 1-17。

Listing Port

要列出所有正在运行或已退出的 Docker 容器,请运行以下命令。

sudo docker ps –a

在命令行上访问应用输出

curl 工具可用于连接运行helloapp的主机和端口。运行以下命令来访问外部端口 32768 上的应用。

curl http://localhost:32768

helloapp生成的 HTML 在主机中得到输出,如图 1-18 所示。

A978-1-4842-1830-3_1_Fig18_HTML.jpg

图 1-18。

Output from helloapp Application

在浏览器中访问应用输出

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

A978-1-4842-1830-3_1_Fig19_HTML.jpg

图 1-19。

Finding Public DNS

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

A978-1-4842-1830-3_1_Fig20_HTML.jpg

图 1-20。

Displaying Output from helloapp in a Browser

停止 Docker 容器

Docker 容器可以用docker stop命令停止。例如,用下面的命令停止helloapp容器。

sudo docker stop helloapp

Docker 容器被停止。随后运行docker ps命令列出正在运行的容器。如图 1-21 所示helloapp容器未列出。

A978-1-4842-1830-3_1_Fig21_HTML.jpg

图 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 映像被移除。

A978-1-4842-1830-3_1_Fig22_HTML.jpg

图 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 容器中部署应用。

A978-1-4842-1830-3_2_Fig1_HTML.jpg

图 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 映像。

A978-1-4842-1830-3_2_Fig2_HTML.jpg

图 2-2。

Downloading Docker Images

列出 Docker 映像

可以使用以下命令列出下载并可用于运行应用的 Docker 映像。

sudo docker images

两张oraclelinux图片;版本 6.6 和 7 如图 2-3 所示。标签列列出了映像的版本(或变体)。

A978-1-4842-1830-3_2_Fig3_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_2_Fig4_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_2_Fig5_HTML.jpg

图 2-5。

Starting Docker Container in Attached Mode

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

A978-1-4842-1830-3_2_Fig6_HTML.jpg

图 2-6。

Container Name must be Unique

列出 Docker 容器

Docker 容器可以运行,也可以不运行。运行以下命令列出正在运行的 Docker 容器。

sudo docker ps

唯一运行的容器oraclelinux:6.6oraclelinux:7.0如图 2-7 所示。“状态”列指示容器是“启动”并正在运行还是“已退出”。容器 ID 列列出了容器 ID。

A978-1-4842-1830-3_2_Fig7_HTML.jpg

图 2-7。

Listing Running Docker Containers

要列出所有正在运行或已退出的容器,请运行以下命令。

sudo docker ps –a

已经退出的容器也会被列出,如图 2-8 所示。

A978-1-4842-1830-3_2_Fig8_HTML.jpg

图 2-8。

Listing All Docker Containers

查找 Oracle Linux 容器信息

可以用docker inspect命令列出一个容器的信息。运行以下命令列出有关容器 oraclelinux7 的信息。

sudo docker  inspect oraclelinux7

容器细节以 JSON 格式列出,如图 2-9 所示。

A978-1-4842-1830-3_2_Fig9_HTML.jpg

图 2-9。

Output from docker inspect

列出容器进程

docker top命令列出容器正在运行的进程。下面的命令列出了由oraclelinux6容器运行的进程。

sudo docker top oraclelinux6

如图 2-10 所示,UID 和 PID 在为进程列出的列中。

A978-1-4842-1830-3_2_Fig10_HTML.jpg

图 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 启动,容器进程连接到终端。

A978-1-4842-1830-3_2_Fig11_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_2_Fig12_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_2_Fig13_HTML.jpg

图 2-13。

Outputting Oracle Release

运行其他一些 Linux 命令来创建一个目录,设置该目录的权限,并列出文件和目录。

mkdir /orcl

chmod 777 /orcl

ls -l

/orcl目录被创建并被列出,如图 2-14 所示。

A978-1-4842-1830-3_2_Fig14_HTML.jpg

图 2-14。

Listing Files and Directories

运行exit命令退出交互 shell,如图 2-15 所示。

A978-1-4842-1830-3_2_Fig15_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_2_Fig16_HTML.jpg

图 2-16。

Starting an Interactive Shell with docker start

停止容器

要停止正在运行的容器,运行docker stop命令。运行以下命令来停止orcl6容器。

sudo docker stop orcl6

orcl6 容器停止,如图 2-17 所示。

A978-1-4842-1830-3_2_Fig17_HTML.jpg

图 2-17。

Stopping a Docker Container

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

A978-1-4842-1830-3_2_Fig18_HTML.jpg

图 2-18。

Listing an Exited Container

移除容器

要移除容器,运行docker rm命令。移除前必须先停止容器,否则docker rm命令不会移除容器。运行以下命令删除orcl6容器。

sudo docker rm orcl6

orcl6 容器被移除,如图 2-19 所示。

A978-1-4842-1830-3_2_Fig19_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_3_Fig1_HTML.jpg

图 3-1。

Downloading Docker Image for Oracle Database

列出 Docker 映像。

sudo docker images

sath89/oracle-xe-11g 映像被列出,如图 3-2 所示。

A978-1-4842-1830-3_3_Fig2_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_3_Fig3_HTML.jpg

图 3-3。

Starting Oracle Database in a Docker Container

用下面的命令列出 Docker 容器。

sudo docker ps

orcldb容器被列出,如图 3-4 所示。

A978-1-4842-1830-3_3_Fig4_HTML.jpg

图 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 数据库日志包括数据库初始化和配置。

A978-1-4842-1830-3_3_Fig5_HTML.jpg

图 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 所示的用户名时,指定“系统”。

A978-1-4842-1830-3_3_Fig6_HTML.jpg

图 3-6。

Starting SQL*Plus

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

A978-1-4842-1830-3_3_Fig7_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_3_Fig8_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_3_Fig9_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_3_Fig10_HTML.jpg

图 3-10。

Adding Data to OE.Catalog Table

使用下面的SELECT语句运行 SQL 查询。

SQL> SELECT * FROM OE.CATALOG;

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

A978-1-4842-1830-3_3_Fig11_HTML.jpg

图 3-11。

Running a SQL Query

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

A978-1-4842-1830-3_3_Fig12_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_3_Fig13_HTML.jpg

图 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命令的输出对于活动字段应该是活动的(运行中)。

A978-1-4842-1830-3_4_Fig1_HTML.jpg

图 4-1。

Starting Docker Service and verifying Status

Docker Hub 提供了一个官方的 Docker 映像。使用以下命令下载 Docker 映像。

sudo docker pull mysql

最新的 Docker 映像mysql:latest被下载,如图 4-2 所示。

A978-1-4842-1830-3_4_Fig2_HTML.jpg

图 4-2。

Downloading Docker Image for MySQL Database

使用以下命令列出 Docker 映像。

sudo docker images

mysql映像被列出,如图 4-3 所示。

A978-1-4842-1830-3_4_Fig3_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_4_Fig4_HTML.jpg

图 4-4。

Creating the Data Directory

当运行docker run命令在 Docker 容器中启动 MySQL 时,可能会指定某些环境变量,如下表所述。

| 环境变量 | 描述 | 需要 | | --- | --- | --- | | MYSQL _ ROOT _ 密码 | “root”用户的密码。 | 是 | | MYSQL _ 数据库 | 创建数据库 | 不 | | MYSQL _ 用户,MYSQL _ 密码 | 指定用户名和密码以创建新用户。用户被授予对 MYSQL_DATABASE 变量中指定的数据库的超级用户权限。如果设置了用户名和密码,则必须同时设置这两者。 | 不 | | MYSQL _ ALLOW _ EMPTY _ 密码 | 指定是否允许“root”用户拥有空密码。 | 不 |

除了MYSQL_ROOT_PASSWORD环境变量,所有其他变量都是可选的,但是我们将使用所有环境变量运行一个 MySQL 实例容器。我们将使用以下命令参数运行docker run命令。

| 命令参数 | 价值 | | --- | --- | | MYSQL _ ROOT _ 密码 | '' | | MYSQL _ 数据库 | mysqldb | | MYSQL _ 用户,MYSQL _ 密码 | mysql,mysql | | MYSQL _ ALLOW _ EMPTY _ 密码 | 是 | | -v | /mysql/data:/var/lib/mysql | | 名字 | mysqldb | | -d |   |

环境变量用–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 所示。

A978-1-4842-1830-3_4_Fig5_HTML.jpg

图 4-5。

Running MySQL Database in a Docker Container

运行以下命令,列出正在运行的 Docker 容器。

sudo docker ps

运行 MySQL 数据库实例的 Docker 容器mysqldb如图 4-6 所示。

A978-1-4842-1830-3_4_Fig6_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_4_Fig7_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_4_Fig8_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_4_Fig9_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_4_Fig10_HTML.jpg

图 4-10。

Adding a Row of Data to MySQL Table

查询表

接下来,用 SQL 查询查询目录表。以下 SELECT 语句选择目录表中的所有数据。

mysql> SELECT * FROM Catalog;

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

A978-1-4842-1830-3_4_Fig11_HTML.jpg

图 4-11。

Running a SQL Query

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

A978-1-4842-1830-3_4_Fig12_HTML.jpg

图 4-12。

The table name is Case-sensitive in MySQL

列出数据库和表格

可以在 MySQL CLI 中使用以下命令列出 MySQL 服务器实例中的数据库。

mysql> show databases;

数据库被列出,包括新创建的数据库“mysqldb”,如图 4-13 所示。

A978-1-4842-1830-3_4_Fig13_HTML.jpg

图 4-13。

Listing MySQL Databases

离开 TTY 终点站

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

mysql> exit

Bye

使用“Exit”命令退出交互式 shell 或 tty。

root@969088c84a4f:/# exit

exit

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

A978-1-4842-1830-3_4_Fig14_HTML.jpg

图 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 命令,如stopstartrm

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 所示。

A978-1-4842-1830-3_4_Fig15_HTML.jpg

图 4-15。

Using a Password to Start MySQL CLI

也可以发出如下的mysql命令。

mysql –u root –p

指定“mysql”用户的密码。MySQL CLI 启动如图 4-16 所示。

A978-1-4842-1830-3_4_Fig16_HTML.jpg

图 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命令时创建的。

A978-1-4842-1830-3_4_Fig17_HTML.jpg

图 4-17。

Listing the Default Databases

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

A978-1-4842-1830-3_4_Fig18_HTML.jpg

图 4-18。

Using the mysql Database

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

A978-1-4842-1830-3_4_Fig19_HTML.jpg

图 4-19。

Listing Tables

列出 Docker 容器日志

接下来,用docker logs命令列出mysqldb容器的日志。

sudo docker logs -f mysqldb

mysqldb容器的日志列表如图 4-20 所示。

A978-1-4842-1830-3_4_Fig20_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_5_Fig1_HTML.jpg

图 5-1。

Starting Docker Service and verifying Status

下载 MongoDB 数据库的官方 Docker 映像。

sudo docker pull mongo:latest

列出 Docker 映像。

sudo docker images

名为“mongo”的 Docker 映像被列出,如图 5-2 所示。

A978-1-4842-1830-3_5_Fig2_HTML.jpg

图 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 所示启动。

A978-1-4842-1830-3_5_Fig3_HTML.jpg

图 5-3。

Starting Docker Container for MongoDB

列出正在运行的 Docker 容器。

sudo docker ps

如图 5-4 所示,mongodb容器被列为在端口 27017 上运行。

A978-1-4842-1830-3_5_Fig4_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_5_Fig5_HTML.jpg

图 5-5。

Starting MongoDB Shell from TTY

MongoDB shell 也可以在特定的主机和端口上启动,如下所示。

mongo –host localhost –port 27017

MongoDB shell 在主机localhost,端口 27017 上启动,如图 5-6 所示。“测试”数据库实例被连接到。

A978-1-4842-1830-3_5_Fig6_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_5_Fig7_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_5_Fig8_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_5_Fig9_HTML.jpg

图 5-9。

Creating a Database

用下面的命令列出mongodb数据库中的集合。

show collections

除了系统集合system.indexes之外,“目录”集合也被列出,如图 5-10 所示。

A978-1-4842-1830-3_5_Fig10_HTML.jpg

图 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”的加盖集合。

A978-1-4842-1830-3_5_Fig11_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_5_Fig12_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_5_Fig13_HTML.jpg

图 5-13。

Finding Document Count

接下来,我们将向catalog集合添加一个文档。创建一个 JSON 文档结构,包含字段catalogIdjournalpublishereditiontitleauthor

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。

A978-1-4842-1830-3_5_Fig14_HTML.jpg

图 5-14。

Adding a Document

查找文档

db.collection.find(query, projection)方法用于查找文档。document类型的query参数使用查询操作符指定选择标准。类型为documentprojection参数指定了要返回的字段。这两个参数都是可选的。要选择所有文档,请不要指定任何参数或指定空文档{}。例如,查找catalog集合中的所有文档。

db.catalog.find()

先前添加的一个文档被列为 JSON 文档,如图 5-15 所示。如果没有明确指定,_id字段会自动添加到文档中。

A978-1-4842-1830-3_5_Fig15_HTML.jpg

图 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集合中。

A978-1-4842-1830-3_5_Fig16_HTML.jpg

图 5-16。

Adding Another Document

随后使用db.<collection>.find()方法查询catalog集合。

db.catalog.find()

添加到catalog集合中的两个文档被列出,如图 5-17 所示。这两个文档在 JSON 中都有相同的名称/值对,除了_id字段,它有一个惟一的值。

A978-1-4842-1830-3_5_Fig17_HTML.jpg

图 5-17。

Running the find() Method

查询单个文档

db.<collection>.findOne()方法用于查找单个文档。从catalog集合中查找单个文档。

db.catalog.findOne()

其中一个文档通过查询得到输出,如图 5-18 所示。

A978-1-4842-1830-3_5_Fig18_HTML.jpg

图 5-18。

Using the findOne() Method

db.collection.findOne(query, projection)方法也接受两个类型都是document的参数,并且都是可选的。query参数指定查询选择标准,而projection参数指定要选择的字段。例如,选择editiontitleauthor字段,并将查询文档指定为{}。

db.catalog.findOne(

{  },

{ edition: 1, title: 1, author: 1 }

)

列出editiontitleauthor字段。_id字段总是由查询输出,如图 5-19 所示。

A978-1-4842-1830-3_5_Fig19_HTML.jpg

图 5-19。

Using a Query Projection

删除收藏

方法删除一个集合。例如,删除catalog集合。

db.catalog.drop()

随后,show collections方法不列出catalog集合,如图 5-20 所示。

A978-1-4842-1830-3_5_Fig20_HTML.jpg

图 5-20。

Dropping a Collection

添加一批文档

以前,我们一次添加一个文档。接下来,我们将添加一批文档。如果在前面的部分中还没有删除,则删除catalog集合。

db.catalog.drop()

使用db.catalog.insert()方法调用添加一个文档数组,其中doc1doc2与前面相同。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。

A978-1-4842-1830-3_5_Fig21_HTML.jpg

图 5-21。

Adding a Batch of Documents

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

A978-1-4842-1830-3_5_Fig22_HTML.jpg

图 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字段指的是相对于修改现有文档而言添加的新文档的数量。

A978-1-4842-1830-3_5_Fig23_HTML.jpg

图 5-23。

Using the save() Method to Update a Document

使用find()方法查询catalog集合。

db.catalog.find()

更新后的文档被列为图 5-24 所示的文档之一。

A978-1-4842-1830-3_5_Fig24_HTML.jpg

图 5-24。

Querying Updated Document

将文档输出为 JSON

db.collection.find(query, projection)方法返回查询选择的文档上的光标。调用游标上的forEach(printjson)方法,以 JSON 格式输出文档。

db.catalog.find().forEach(printjson)

文件以 JSON 的形式输出,如图 5-25 所示。

A978-1-4842-1830-3_5_Fig25_HTML.jpg

图 5-25。

Outputting JSON

制作数据备份

mongodump实用程序用于创建数据库中数据的二进制导出。mongorestore实用程序与mongodump结合使用,从备份中恢复数据库。mongorestore实用程序要么创建一个新的数据库实例,要么添加到一个现有的数据库中。

运行下面的mongodump命令,将测试数据库导出到/data/backup目录。

mongodump --db test --out /data/backup

测试数据库被导出到/data/backup目录,如图 5-26 所示。

A978-1-4842-1830-3_5_Fig26_HTML.jpg

图 5-26。

Exporting the test Database

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

A978-1-4842-1830-3_5_Fig27_HTML.jpg

图 5-27。

Listing the test Database

运行下面的mongorestore命令,将从/data/backup/test导出的数据恢复到testrestore数据库。

mongorestore --db testrestore /data/backup/test

/data/backup/test目录数据被恢复到testrestore数据库中,如图 5-28 所示。

A978-1-4842-1830-3_5_Fig28_HTML.jpg

图 5-28。

Restoring a Database

使用以下命令连接到 MongoDB shell。

mongo localhost:27017/testrestore

MongoDB shell 的启动如图 5-29 所示。

A978-1-4842-1830-3_5_Fig29_HTML.jpg

图 5-29。

Connecting to the Restored Database

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

show dbs

当我们将备份恢复到testrestore数据库时,之前导出的mongodb数据库会被列出,如图 5-30 所示。

A978-1-4842-1830-3_5_Fig30_HTML.jpg

图 5-30。

Listing the Restored Database

将数据库名称设置为mongodb

use mongodb

列出收藏。

show collections

查询catalog集合中的文档。

db.catalog.find()

前述命令的输出如图 5-31 所示。

A978-1-4842-1830-3_5_Fig31_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_5_Fig32_HTML.jpg

图 5-32。

Removing a Single Document

要删除所有文档,向db.catalog.remove()方法调用提供一个空文档{}

db.catalog.remove({})

如图 5-33 所示nRemoved值为 2 表示多个文件被移除。

A978-1-4842-1830-3_5_Fig33_HTML.jpg

图 5-33。

Removing All Documents

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

A978-1-4842-1830-3_5_Fig34_HTML.jpg

图 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再次被列为正在运行。

A978-1-4842-1830-3_5_Fig35_HTML.jpg

图 5-35。

Listing a Docker Container after Restarting the Container

使用以下命令启动交互式终端,其中使用容器 ID 而不是容器名称。

sudo docker exec -it 68fe88ca79fe bash

在交互 shell 中用mongo命令启动 MongoDB shell,如图 5-36 所示。

A978-1-4842-1830-3_5_Fig36_HTML.jpg

图 5-36。

Starting the MongoDB Shell

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

A978-1-4842-1830-3_5_Fig37_HTML.jpg

图 5-37。

Listing Documents in the catalog Collection in local Database

退出 Mongo Shell

要退出交互终端,使用“exit”命令,并使用“exit”命令退出 MongoDB shell,也如图 5-38 所示。

A978-1-4842-1830-3_5_Fig38_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_6_Fig1_HTML.jpg

图 6-1。

Starting Docker Service and verifying Status

接下来,下载最新的cassandra Docker 图片。

sudo docker pull cassandra:latest

列出下载的 Docker 映像。

sudo docker images

cassandra映像应被列出,如图 6-2 所示。

A978-1-4842-1830-3_6_Fig2_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_6_Fig3_HTML.jpg

图 6-3。

Starting Docker Container for Apache Cassandra

用下面的命令列出正在运行的 Docker 容器。

sudo docker ps

运行 Apache Cassandra 服务器实例的cassandradb容器被列出。还列出了容器 id。默认情况下,端口 9042 是 Apache Cassandra 监听客户端连接的客户端端口。端口 9160 是节俭 API,如图 6-4 所示。

A978-1-4842-1830-3_6_Fig4_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_6_Fig5_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_6_Fig6_HTML.jpg

图 6-6。

Connecting the CQL Shell

我们使用容器名启动了交互式终端,但是 tty 也可以使用容器 id 启动。无论 tty 是如何启动的,cqlsh shell 都是用cqlsh命令启动的。

sudo docker exec –it dfade56f871 bash

cqlsh

cqlsh>命令提示符显示如前,如图 6-7 所示。

A978-1-4842-1830-3_6_Fig7_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_6_Fig8_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_6_Fig9_HTML.jpg

图 6-9。

Altering a Keyspace

使用密钥空间

USE 语句用于设置当前密钥空间,其语法如下。

USE <identifier>

所有后续命令都在用USE语句设置的密钥空间的上下文中运行。例如,将当前密钥空间设置为CatalogKeyspace

use CatalogKeyspace;

cqlsh>命令提示符变为cqlsh:catalogkeyspace>,如图 6-10 所示。

A978-1-4842-1830-3_6_Fig10_HTML.jpg

图 6-10。

Using a Keyspace

创建表格

表也称为COLUMN FAMILYCREATE TABLECREATE 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_idjournalpublishereditiontitleauthor。指定主键为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 所示。

A978-1-4842-1830-3_6_Fig11_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_6_Fig12_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_6_Fig13_HTML.jpg

图 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;

带有作为catalog1catalog_id的行的列值被删除,但是包括主键列值的行本身没有被删除,即使主键catalog_id被列为要删除的列之一。后续查询列出了主键列值,但将其他列的列值列为空,如图 6-14 所示。

A978-1-4842-1830-3_6_Fig14_HTML.jpg

图 6-14。

Deleting Table Data

截断表格

TRUNCATE语句从表中删除所有数据,其语法如下。

TRUNCATE <tablename>

例如,截断catalog表。随后,使用SELECT语句运行查询。

TRUNCATE catalog;

SELECT * from catalog;

如查询输出所示,没有列出任何数据,因为TRUNCATE语句已经删除了所有数据,如图 6-15 所示。

A978-1-4842-1830-3_6_Fig15_HTML.jpg

图 6-15。

Truncating a Table

放下一张桌子

DROP TABLEDROP COLUMN FAMILY语句用于删除表,其语法如下。

DROP TABLE ( IF EXISTS )? <tablename>

例如,删除catalog表。

DROP TABLE IF EXISTS catalog;

如果没有指定IF EXISTS子句,并且该表不存在,则会生成一个错误。但是有了IF EXISTS子句,如图 6-16 中包含的 IF EXISTS子句的两个连续运行的DROP TABLE语句所示,不会产生错误。

A978-1-4842-1830-3_6_Fig16_HTML.jpg

图 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语句所指示的错误不会产生。

A978-1-4842-1830-3_6_Fig17_HTML.jpg

图 6-17。

Dropping a Keyspace

退出 CQL 壳牌

要退出 cqlsh shell,指定退出命令,如图 6-18 所示。随后也用exit命令退出 tty。

A978-1-4842-1830-3_6_Fig18_HTML.jpg

图 6-18。

Exiting CQL Shell

阻止 Apache 卡桑德拉

要停止 Apache Cassandra,请停止运行 Apache Cassandra 服务器的 Docker 容器。

sudo docker stop cassandradb

随后,运行以下命令列出正在运行的容器。

sudo docker ps

如图 6-19 所示,cassndradb容器未被列为运行中。

A978-1-4842-1830-3_6_Fig19_HTML.jpg

图 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命令删除一个容器,才能创建一个同名的新容器。

A978-1-4842-1830-3_6_Fig20_HTML.jpg

图 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

cassandradb2cassandradb3容器被列为运行中,如图 6-21 所示。

A978-1-4842-1830-3_6_Fig21_HTML.jpg

图 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 实例的安装和配置。

A978-1-4842-1830-3_7_Fig1_HTML.jpg

图 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/hostslocalhost的 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 所示。

A978-1-4842-1830-3_7_Fig2_HTML.jpg

图 7-2。

Output from hello-world

下载名为“Couchbase”的官方 Couchbase Docker 图片。

sudo docker pull couchbase

下载最新的 Docker 映像,如图 7-3 所示。

A978-1-4842-1830-3_7_Fig3_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_7_Fig4_HTML.jpg

图 7-4。

Running Docker Container for Couchbase

docker logs命令输出容器的日志。

sudo docker logs couchbasedb

显示如图 7-5 所示的信息。

A978-1-4842-1830-3_7_Fig5_HTML.jpg

图 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 服务器集群。

A978-1-4842-1830-3_7_Fig6_HTML.jpg

图 7-6。

Accessing Couchbase Admin Console

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

A978-1-4842-1830-3_7_Fig7_HTML.jpg

图 7-7。

Login Page

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

A978-1-4842-1830-3_7_Fig8_HTML.jpg

图 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 所示。主机名字段不接受短名称,主机名中至少需要一个点。

A978-1-4842-1830-3_7_Fig9_HTML.jpg

图 7-9。

Configuring Server

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

A978-1-4842-1830-3_7_Fig10_HTML.jpg

图 7-10。

Starting a New Cluster

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

A978-1-4842-1830-3_7_Fig11_HTML.jpg

图 7-11。

Configuring the Default Cluster

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

A978-1-4842-1830-3_7_Fig12_HTML.jpg

图 7-12。

Enabling Flush

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

A978-1-4842-1830-3_7_Fig13_HTML.jpg

图 7-13。

Configuring Notifications

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

A978-1-4842-1830-3_7_Fig14_HTML.jpg

图 7-14。

Specifying Username and Password

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

A978-1-4842-1830-3_7_Fig15_HTML.jpg

图 7-15。

Displaying Cluster Summary

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

A978-1-4842-1830-3_7_Fig16_HTML.jpg

图 7-16。

Displaying Servers Summary

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

A978-1-4842-1830-3_7_Fig17_HTML.jpg

图 7-17。

Listing Server IP Address

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

A978-1-4842-1830-3_7_Fig18_HTML.jpg

图 7-18。

Listing the Default Buckets

添加文档

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

A978-1-4842-1830-3_7_Fig19_HTML.jpg

图 7-19。

Clicking on the Documents button

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

A978-1-4842-1830-3_7_Fig20_HTML.jpg

图 7-20。

Clicking on ‘Create Document’

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

A978-1-4842-1830-3_7_Fig21_HTML.jpg

图 7-21。

Creating a Document

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

A978-1-4842-1830-3_7_Fig22_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_7_Fig23_HTML.jpg

图 7-23。

Saving a Couchbase Document

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

A978-1-4842-1830-3_7_Fig24_HTML.jpg

图 7-24。

Formatted JSON Document

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

A978-1-4842-1830-3_7_Fig25_HTML.jpg

图 7-25。

Item Count for default Bucket

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

A978-1-4842-1830-3_7_Fig26_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_7_Fig27_HTML.jpg

图 7-27。

Adding another JSON Document

两个文件catalog1catalog2被列出,如图 7-28 所示。

A978-1-4842-1830-3_7_Fig28_HTML.jpg

图 7-28。

Listing the Two Documents Added

启动交互式终端

要从命令行访问 Couchbase 服务器,请启动交互式终端(tty)。

sudo docker exec -it couchbasedb bash

交互外壳启动,如图 7-29 所示。

A978-1-4842-1830-3_7_Fig29_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_7_Fig30_HTML.jpg

图 7-30。

Running cbtransfer

停止 Couchbase 服务器和容器

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

A978-1-4842-1830-3_7_Fig31_HTML.jpg

图 7-31。

Stopping Couchbase Server

在主机系统中,运行docker stop命令来停止 Docker 容器。

sudo docker stop couchbasedb

随后,列出正在运行的 Docker 容器。

sudo docker ps

couchbasedb容器未列出,如图 7-32 所示。

A978-1-4842-1830-3_7_Fig32_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_8_Fig1_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_8_Fig2_HTML.jpg

图 8-2。

Running the docker pull Command

Docker 映像sequenceiq/hadoop-docker被下载,如图 8-3 所示。

A978-1-4842-1830-3_8_Fig3_HTML.jpg

图 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”。

A978-1-4842-1830-3_8_Fig4_HTML.jpg

图 8-4。

Running Docker Container for Apache Hadoop

启动交互式 Shell

使用以下命令启动交互式 shell 或终端(tty)。

sudo docker exec -it hadoop bash

显示如图 8-5 所示的交互终端提示。

A978-1-4842-1830-3_8_Fig5_HTML.jpg

图 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)。

A978-1-4842-1830-3_8_Fig6_HTML.jpg

图 8-6。

Starting Docker Container in Foreground

为 MapReduce 字数统计应用创建输入文件

在本节中,我们将为 MapReduce Word Count 应用创建输入文件,该应用包含在 Hadoop 发行版打包的示例中。要创建输入文件,请将目录(cd)更改为$HADOOP_PREFIX目录。

bash-4.1# cd $HADOOP_PREFIX

如图 8-7 所示,前面的命令将从交互终端(tty)运行。

A978-1-4842-1830-3_8_Fig7_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_8_Fig8_HTML.jpg

图 8-8。

Creating Input Directory

/input目录添加两个文本文件(input1.txtinput2.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 所示。

A978-1-4842-1830-3_8_Fig9_HTML.jpg

图 8-9。

The input1.txt File

用下面的命令将 input1.txt 文件放到 HDFS 目录/input中,也如图 8-10 所示。

bin/hdfs dfs -put input1.txt /input

input1.txt文件被添加到 HDFS 的/input目录中。

A978-1-4842-1830-3_8_Fig10_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_8_Fig11_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_8_Fig12_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_8_Fig13_HTML.jpg

图 8-13。

Starting MapReduce Application with YARN Framework

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

A978-1-4842-1830-3_8_Fig14_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_8_Fig15_HTML.jpg

图 8-15。

Files Output by the YARN Application

使用以下命令列出wordcount应用的输出。

hdfs dfs -cat /output/part-r-00000

输入文件input1.txtinput2.txt中每个不同单词的字数得到输出,如图 8-16 所示。

A978-1-4842-1830-3_8_Fig16_HTML.jpg

图 8-16。

Listing the Word Count

停止 Hadoop Docker 容器

可以使用docker stop命令停止运行 Hadoop 进程的 Docker 容器。

sudo docker stop hadoop

随后运行docker ps命令,没有容器被列为运行中,如图 8-17 所示。

A978-1-4842-1830-3_8_Fig17_HTML.jpg

图 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 所示的输出。

A978-1-4842-1830-3_8_Fig18_HTML.jpg

图 8-18。

hdfs Command Usage

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

A978-1-4842-1830-3_8_Fig19_HTML.jpg

图 8-19。

Listing the Symlink for the Configuration Directory

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

A978-1-4842-1830-3_8_Fig20_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_9_Fig1_HTML.jpg

图 9-1。

Setting Permissions on the Hive Warehouse Directory

如果要使用 Hive CLI,请在交互式终端中运行以下命令。

hive

配置单元 CLI 已启动。如图 9-2 所示,还会输出一条警告消息,指出 Hive CLI 已被否决,建议迁移到 Beeline。

A978-1-4842-1830-3_9_Fig2_HTML.jpg

图 9-2。

Message about Migration to Beeline

我们将在本章中使用直线 CLI。使用exitquit命令退出 Hive CLI。使用以下命令启动直线 CLI。

beeline

直线版本 1.1.0 CDH 5.4.3 开始如图 9-3 所示。

A978-1-4842-1830-3_9_Fig3_HTML.jpg

图 9-3。

Starting Beeline

连接到 HiveServer2

我们在上一节中启动了 Beeline CLI,但是我们还没有连接到 HiveServer2。要进行演示,请运行以下命令。

use default;

show tables;

输出“无电流连接”信息,如图 9-4 所示。

A978-1-4842-1830-3_9_Fig4_HTML.jpg

图 9-4。

Message “No Current Connection”

要连接到 HiveServer2,我们需要运行!connect命令。!connect命令用途可通过以下命令输出。

!connect

!connect命令用法得到如图 9-5 所示的输出。

A978-1-4842-1830-3_9_Fig5_HTML.jpg

图 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 版本。

A978-1-4842-1830-3_9_Fig6_HTML.jpg

图 9-6。

Connecting with Hive2 Server

以前不运行的直线命令在连接到 HiveServer2 后会运行。再次运行以下命令,将数据库设置为“默认”并列出配置单元表。

use default

show tables

数据库被设置为默认值,并列出配置单元表。该数据库已经是连接 url 中指定的“默认”数据库,并且运行use default命令来演示该命令的运行。没有列出任何表格,因为还没有创建任何表格,如图 9-7 所示。我们将在下一部分创建一个表。

A978-1-4842-1830-3_9_Fig7_HTML.jpg

图 9-7。

Listing Tables

创建配置单元表

在本节中,我们将创建一个名为“wlslog”的配置单元表,其中包含列time_stampcategorytypeservernamecodemsg,,所有列的类型都是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字段。

A978-1-4842-1830-3_9_Fig8_HTML.jpg

图 9-8。

Creating Hive Table

运行以下命令来描述wlslog表。

desc wlslog;

由列名和数据类型组成的表结构如图 9-9 所示。

A978-1-4842-1830-3_9_Fig9_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_9_Fig10_HTML.jpg

图 9-10。

Running the INSERT Command

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

A978-1-4842-1830-3_9_Fig11_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_9_Fig12_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_10_Fig1_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_10_Fig2_HTML.jpg

图 10-2。

Starting Docker Container

列出正在运行的 Docker 容器。

sudo docker ps

“cdh”容器被列为正在运行,如图 10-3 所示。还列出了容器 id。

A978-1-4842-1830-3_10_Fig3_HTML.jpg

图 10-3。

Listing the Running Docker Containers

启动交互式外壳

接下来,启动一个交互式终端(tty)来运行 HBase shell。

sudo docker exec -it cdh bash

交互终端启动,命令提示符变为root@86f0cf0a5c8d,如图 10-4 所示。

A978-1-4842-1830-3_10_Fig4_HTML.jpg

图 10-4。

Starting the Interactive Shell

也可以使用容器 id 而不是容器名称来启动交互式外壳。

sudo docker exec -it 86f0cfoa5c8d bash

启动 HBase Shell

接下来,在交互式终端中运行以下命令,启动 HBase shell。

bin/hbase shell

HBase shell 启动,如图 10-5 所示。

A978-1-4842-1830-3_10_Fig5_HTML.jpg

图 10-5。

Starting the HBase Shell

创建 HBase 表

使用“创建”命令创建一个 HBase 表。除了表名之外,还要提供一个或多个列族以及每个列族的规范字典。或者,提供一个表配置字典。例如,创建一个名为“wlslog”的表,其中包含一个名为“log”的列族。

create 'wlslog', 'log'

HBase 表' wlslog '被创建,如图 10-6 所示。

A978-1-4842-1830-3_10_Fig6_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_10_Fig7_HTML.jpg

图 10-7。

Adding Data to HBase Table

列出 HBase 表

使用在 HBase shell 中运行的以下命令列出这些表。

list

一个表格,即“wlslog”表格,如图 10-8 所示。

A978-1-4842-1830-3_10_Fig8_HTML.jpg

图 10-8。

Listing HBase Tables

获取单个表格行

get命令用于获取行或列单元格中的数据。运行下面的get命令获取表‘WLS log’中‘log 7’行的数据。

get 'wlslog', 'log7'

单列数据被列出,如图 10-9 所示。

A978-1-4842-1830-3_10_Fig9_HTML.jpg

图 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 所示的输出。

A978-1-4842-1830-3_10_Fig10_HTML.jpg

图 10-10。

Getting a Single Row Column Value

扫描表格

scan命令用于扫描一个表,以获取表中的所有数据。可选地,可以提供扫描仪规范的字典,这在下面的命令中省略了。

scan 'wlslog'

每行的行➤列数据得到输出,如图 10-11 所示。

A978-1-4842-1830-3_10_Fig11_HTML.jpg

图 10-11。

Scanning a HBase Table

7 行数据得到如图 10-12 所示的输出。

A978-1-4842-1830-3_10_Fig12_HTML.jpg

图 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 位于运行时类路径中。

A978-1-4842-1830-3_11_Fig1_HTML.jpg

图 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

mysqlsvds/cdh Docker 映像都应该被列出,如图 11-2 所示。

A978-1-4842-1830-3_11_Fig2_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_11_Fig3_HTML.jpg

图 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 容器都被列为已启动。

A978-1-4842-1830-3_11_Fig4_HTML.jpg

图 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>提示。

A978-1-4842-1830-3_11_Fig5_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_11_Fig6_HTML.jpg

图 11-6。

Setting Privileges on mysqldb Database

接下来,创建一个名为wlslog的数据库表,其中包含列time_stampcategorytypeservernamecodemsgPRIMARY 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 所示。

A978-1-4842-1830-3_11_Fig7_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_11_Fig8_HTML.jpg

图 11-8。

Running INSERT SQL Statements

运行以下 SQL 查询来列出添加的数据。

SELECT * FROM wlslog;

如图 11-9 所示,列出 6 行数据。

A978-1-4842-1830-3_11_Fig9_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_11_Fig10_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_11_Fig11_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_11_Fig12_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_11_Fig13_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_11_Fig14_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_11_Fig15_HTML.jpg

图 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命令保存文件。

A978-1-4842-1830-3_11_Fig16_HTML.jpg

图 11-16。

Setting the JAVA_HOME Environment Variable

配置 Apache Hadoop

Apache Hadoop MapReduce 框架可以在三种模式下启动:localclassicyarn。在“本地”模式下,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 所示。

A978-1-4842-1830-3_11_Fig17_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_11_Fig18_HTML.jpg

图 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保存文件。

A978-1-4842-1830-3_11_Fig19_HTML.jpg

图 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。

A978-1-4842-1830-3_11_Fig20_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_11_Fig21_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_11_Fig22_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_11_Fig23_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_11_Fig24_HTML.jpg

图 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而不是wlslogsqoop export命令所需的代码在WLSLOG_COPY.jar文件中生成,如图 11-25 所示。

A978-1-4842-1830-3_11_Fig25_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_11_Fig26_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_11_Fig27_HTML.jpg

图 11-27。

Querying Exported Data in WLSLOG_COPY

停止和移除 Docker 容器

要移除mysqldbcdh容器,必须首先停止容器。用docker stop命令停止mysqldb容器。

sudo docker stop mysqldb

docker rm命令移除mysqldb容器。

sudo docker rm mysqldb

mysqldb容器停止移动,如图 11-28 所示。

A978-1-4842-1830-3_11_Fig28_HTML.jpg

图 11-28。

Stopping and Removing Docker Container for MySQL Database

同样,停止并移除cdh容器。

sudo docker stop cdh

sudo docker rm cdh

cdh容器停止移动,如图 11-29 所示。

A978-1-4842-1830-3_11_Fig29_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_12_Fig1_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_12_Fig2_HTML.jpg

图 12-2。

Starting Docker Service

下载 Apache ZooKeeper 的 Docker 图片dockerkafka/zookeeper

sudo docker pull dockerkafka/zookeeper

Docker 镜像被下载,如图 12-3 所示。

A978-1-4842-1830-3_12_Fig3_HTML.jpg

图 12-3。

Downloading dockerkafka/zookeeper Docker Image

选择下载dockerkafka/zookeeper映像是因为相应的 dockerkafka/kafka 映像也是可用的。也下载 Docker 映像dockerkafka/kafka

sudo  docker pull dockerkafka/kafka

Docker 映像dockerkafka/kafka被下载,如图 12-4 所示。

A978-1-4842-1830-3_12_Fig4_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_12_Fig5_HTML.jpg

图 12-5。

Listing Running Docker Containers

查找 IP 地址

要运行 Kakfa 生产者和消费者,我们需要找到运行 ZooKeeper 的 Docker 容器的 IP 地址和运行 Kafka 服务器的 Docker 容器的 IP 地址。运行以下两个命令来导出ZK_IPKAFKA_IP环境变量。

export ZK_IP=$(sudo docker inspect --format '{{ .NetworkSettings.IPAddress }}' zookeeper)

export KAFKA_IP=$(sudo docker inspect --format '{{ .NetworkSettings.IPAddress }}' kafka)

随后,回显ZK_IPKAFKA_IP变量。ZK_IP输出为172.17.0.1KAFKA_IP输出为 172.17.0.2,如图 12-6 所示。我们将在后续章节中使用这些 IP 地址。

A978-1-4842-1830-3_12_Fig6_HTML.jpg

图 12-6。

Finding IP Addresses for Zookeeper and Kafka Servers

列出 Kafka 的日志

docker logs命令输出 Docker 容器“kafka”的日志。

sudo docker logs -f kafka

输出表明 Kafka 服务器已经启动,如图 12-7 所示。

A978-1-4842-1830-3_12_Fig7_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_12_Fig8_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_12_Fig9_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_12_Fig10_HTML.jpg

图 12-10。

Starting the Kafka Consumer

生产和消费消息

在本节中,我们将把消息从 Kafka 生产者发布到在我们启动生产者时配置的 Kafka 主题“test ”,并在也订阅了“test”主题的 Kafka 消费者处消费这些消息。

如图 12-11 所示,在制作人控制台发布一条消息“Docker 的 Kafka 你好”。单击 Enter 导航到控制台中的下一行。

A978-1-4842-1830-3_12_Fig11_HTML.jpg

图 12-11。

Producing a Message at the Kafka Producer

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

A978-1-4842-1830-3_12_Fig12_HTML.jpg

图 12-12。

Consuming Messages at the Consumer

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

A978-1-4842-1830-3_12_Fig13_HTML.jpg

图 12-13。

Producing More Messages at the Producer

消息在 Kafka 消费者控制台得到输出,如图 12-14 所示。

A978-1-4842-1830-3_12_Fig14_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_13_Fig1_HTML.jpg

图 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 进程正在运行的消息。

A978-1-4842-1830-3_13_Fig2_HTML.jpg

图 13-2。

Starting and Finding Docker Service Status

接下来,用docker pull命令下载 Apache Solr 的官方 Docker 映像。

sudo docker pull solr

如图 13-3 所示下载 Docker 镜像。

A978-1-4842-1830-3_13_Fig3_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_13_Fig4_HTML.jpg

图 13-4。

Starting Docker Container for Apache Solr

运行docker logs命令来输出 Docker 容器的日志。docker 命令中可以使用容器名或容器 id。

sudo docker logs -f 8061f79d1f16

容器日志表明 Apache Solr 服务器已经启动,如图 13-5 所示。

A978-1-4842-1830-3_13_Fig5_HTML.jpg

图 13-5。

Listing Docker Container Log

启动交互式 Shell

以用户“solr”的身份启动 Docker 容器的交互式 shell。

sudo docker exec -it –user=solr solr_on_docker bash

交互式 shell(或 tty)启动,如图 13-6 所示。

A978-1-4842-1830-3_13_Fig6_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_13_Fig7_HTML.jpg

图 13-7。

Finding the Public DNS

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

A978-1-4842-1830-3_13_Fig8_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_13_Fig9_HTML.jpg

图 13-9。

Creating a Core called “gettingstarted”

在 Solr 管理控制台中,选择核心管理,如图 13-10 所示。

A978-1-4842-1830-3_13_Fig10_HTML.jpg

图 13-10。

Selecting Core Admin

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

A978-1-4842-1830-3_13_Fig11_HTML.jpg

图 13-11。

Selecting the gettingstarted Core

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

A978-1-4842-1830-3_13_Fig12_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_13_Fig13_HTML.jpg

图 13-13。

Copying solr.xml to DockerContainer

使用以下命令启动交互式终端(tty)。

sudo docker exec -it –user=solr solr_on_docker bash

/opt/solr目录运行以下命令,列出目录中的文件和目录。solr.xml应被列出,如图 13-14 所示。

A978-1-4842-1830-3_13_Fig14_HTML.jpg

图 13-14。

Listing the solr.xml File in Docker Container

运行以下命令将 solr.xml 发布到gettingstarted索引。

bin/post -c gettingstarted ./solr.xml

solr.xml文件被索引,如图 13-15 所示。

A978-1-4842-1830-3_13_Fig15_HTML.jpg

图 13-15。

indexing solr.xml

在 Solr 管理控制台中查询 Apache Solr

可以从 Solr 管理控制台查询索引文档。选择查询页签,如图 13-16 所示。

A978-1-4842-1830-3_13_Fig16_HTML.jpg

图 13-16。

Selecting the Query tab

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

A978-1-4842-1830-3_13_Fig17_HTML.jpg

图 13-17。

The /select Request Handler

点击执行查询,如图 13-18 所示。

A978-1-4842-1830-3_13_Fig18_HTML.jpg

图 13-18。

Clicking on Execute Query

查询结果返回为 JSON,如图 13-19 所示。

A978-1-4842-1830-3_13_Fig19_HTML.jpg

图 13-19。

JSON Response from Query

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

A978-1-4842-1830-3_13_Fig20_HTML.jpg

图 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 所示的输出。

A978-1-4842-1830-3_13_Fig21_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_13_Fig22_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_13_Fig23_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_13_Fig24_HTML.jpg

图 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,的被索引的单个文档被删除。

A978-1-4842-1830-3_13_Fig25_HTML.jpg

图 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 所示的文件,因为唯一索引的文件已被删除。

A978-1-4842-1830-3_13_Fig26_HTML.jpg

图 13-26。

REST Query does not list any Document after deleting the only document

删除唯一的索引文档后,在 Solr 管理控制台中运行一个查询,没有返回任何文档,如返回的 JSON 文档中的字段值 0 所示,如图 13-27 所示。

A978-1-4842-1830-3_13_Fig27_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_13_Fig28_HTML.jpg

图 13-28。

Listing Docker Container Logs

停止 Apache Solr 服务器

可以用docker ps命令列出正在运行的 Docker 容器。solr_on_docker容器列为运行中,如图 13-29 所示。

A978-1-4842-1830-3_13_Fig29_HTML.jpg

图 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容器没有被列出。

A978-1-4842-1830-3_13_Fig30_HTML.jpg

图 13-30。

Stopping Docker Container for Apache Solr

Docker 映像仍然会用docker images命令列出,如图 13-31 所示。

A978-1-4842-1830-3_13_Fig31_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_14_Fig1_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_14_Fig2_HTML.jpg

图 14-2。

Starting Docker Container for CDH including Apache Spark

为 cdh 容器启动一个交互式终端。

sudo docker exec -it cdh bash

交互终端启动,如图 14-3 所示。

A978-1-4842-1830-3_14_Fig3_HTML.jpg

图 14-3。

Starting the TTY

在 YARN 模式中,Spark 应用可以提交给 yarn-cluster 模式或 yarn-client 模式中的集群。在 yarn-cluster 模式下,Apache Spark 驱动程序运行在一个由 yarn 管理的应用主机中。在纱线客户端模式下。Spark 驱动程序在 YARN 之外的客户端进程中运行,而应用主机仅用于向 YARN 请求资源。根据提交申请的方式,--master参数为yarn-clusteryarn-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 所示。

A978-1-4842-1830-3_14_Fig4_HTML.jpg

图 14-4。

Submitting the Spark Application in yarn-cluster Mode

火花应用的输出如图 14-5 所示。

A978-1-4842-1830-3_14_Fig5_HTML.jpg

图 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/AResourceManager访问纱线容器日志。

在 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 所示。

A978-1-4842-1830-3_14_Fig6_HTML.jpg

图 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”使用。

A978-1-4842-1830-3_14_Fig7_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_14_Fig8_HTML.jpg

图 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 所示。

A978-1-4842-1830-3_15_Fig1_HTML.jpg

图 A-1。

Launching an Amazon EC2 Instance

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

A978-1-4842-1830-3_15_Fig2_HTML.jpg

图 A-2。

Selecting an AMI

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

A978-1-4842-1830-3_15_Fig3_HTML.jpg

图 A-3。

Review and Launch

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

A978-1-4842-1830-3_15_Fig4_HTML.jpg

图 A-4。

Launch

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

A978-1-4842-1830-3_15_Fig5_HTML.jpg

图 A-5。

Selecting “Create a new key pair”

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

A978-1-4842-1830-3_15_Fig6_HTML.jpg

图 A-6。

Download Key Pair

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

A978-1-4842-1830-3_15_Fig7_HTML.jpg

图 A-7。

Choose an existing Key Pair

将显示启动状态。点击实例 id,显示如图 A-8 所示的实例。

A978-1-4842-1830-3_15_Fig8_HTML.jpg

图 A-8。

Launch Status

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

A978-1-4842-1830-3_15_Fig9_HTML.jpg

图 A-9。

Amazon EC2 Instance in Pending State

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

A978-1-4842-1830-3_15_Fig10_HTML.jpg

图 A-10。

Running Instance

创建密钥对

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

A978-1-4842-1830-3_15_Fig11_HTML.jpg

图 A-11。

Network & Security ➤ Key Pairs

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

A978-1-4842-1830-3_15_Fig12_HTML.jpg

图 A-12。

Delete Key Pair

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

A978-1-4842-1830-3_15_Fig13_HTML.jpg

图 A-13。

Create Key Pair

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

A978-1-4842-1830-3_15_Fig14_HTML.jpg

图 A-14。

Create Button

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

A978-1-4842-1830-3_15_Fig15_HTML.jpg

图 A-15。

New Key Pair

启动 Amazon EC2 实例

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

A978-1-4842-1830-3_15_Fig16_HTML.jpg

图 A-16。

Actions ➤ Instance State ➤ Start

在启动实例对话框中点击是,启动如图 A-17 所示。

A978-1-4842-1830-3_15_Fig17_HTML.jpg

图 A-17。

Starting an instance

连接到 Amazon EC2 实例

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

A978-1-4842-1830-3_15_Fig18_HTML.jpg

图 A-18。

Connect

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

A978-1-4842-1830-3_15_Fig19_HTML.jpg

图 A-19。

Connect To Your Instance dialog

ssh 命令中显示的 IP 地址是 Amazon EC2 实例的公共 IP 地址。

查找公共 IP 地址

公共 IP 地址也可以从 EC2 控制台获得,如图 A-20 所示。

A978-1-4842-1830-3_15_Fig20_HTML.jpg

图 A-20。

Public IP Address

查找公共 DNS

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

A978-1-4842-1830-3_15_Fig21_HTML.jpg

图 A-21。

Public DNS

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

A978-1-4842-1830-3_15_Fig22_HTML.jpg

图 A-22。

Services ➤ VPC

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

A978-1-4842-1830-3_15_Fig23_HTML.jpg

图 A-23。

Your VPCs

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

A978-1-4842-1830-3_15_Fig24_HTML.jpg

图 A-24。

Selecting the VPC

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

A978-1-4842-1830-3_15_Fig25_HTML.jpg

图 A-25。

Edit DNS Hostnames

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

A978-1-4842-1830-3_15_Fig26_HTML.jpg

图 A-26。

Edit DNS Hostnames Dialog

添加默认安全组

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

A978-1-4842-1830-3_15_Fig27_HTML.jpg

图 A-27。

Actions ➤ Networking ➤ Change Security Groups

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

A978-1-4842-1830-3_15_Fig28_HTML.jpg

图 A-28。

The “default” group not selected

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

A978-1-4842-1830-3_15_Fig29_HTML.jpg

图 A-29。

Assign Security Groups

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

A978-1-4842-1830-3_15_Fig30_HTML.jpg

图 A-30。

Network & Security ➤ Security Groups

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

A978-1-4842-1830-3_15_Fig31_HTML.jpg

图 A-31。

Inbound ➤ Edit

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

A978-1-4842-1830-3_15_Fig32_HTML.jpg

图 A-32。

Edit inbound rules dialog

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

A978-1-4842-1830-3_15_Fig33_HTML.jpg

图 A-33。

Outbound ➤ Edit

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

A978-1-4842-1830-3_15_Fig34_HTML.jpg

图 A-34。

Edit outbound rules dialog

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

A978-1-4842-1830-3_15_Fig35_HTML.jpg

图 A-35。

Security Groups column

停止 Amazon EC2 实例

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

A978-1-4842-1830-3_15_Fig36_HTML.jpg

图 A-36。

Actions ➤ Instance State ➤ Stop

可以选择多个实例并一起停止,如图 A-37 所示。

A978-1-4842-1830-3_15_Fig37_HTML.jpg

图 A-37。

Stopping Multiple Instances

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

A978-1-4842-1830-3_15_Fig38_HTML.jpg

图 38。

Stop Instance dialog

实例被停止。

更改实例类型

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

A978-1-4842-1830-3_15_Fig39_HTML.jpg

图 39。

Actions ➤ Instance Settings ➤ Change Instance Type

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

A978-1-4842-1830-3_15_Fig40_HTML.jpg

图 A-40。

Change Instance Type dialog

点击应用,如图 A-41 所示。

A978-1-4842-1830-3_15_Fig41_HTML.jpg

图 A-41。

Applying a new Instance Type

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

A978-1-4842-1830-3_15_Fig42_HTML.jpg

图 A-42。

Upgraded Instance Type

摘要

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

posted @ 2024-08-12 11:18  绝不原创的飞龙  阅读(7)  评论(0编辑  收藏  举报