将 Docker Registry 设置为 Raspberry Pi 上的拉取式缓存

如果您的网速缓慢且有多个用户在下载 Docker 映像,为什么不使用它作为 Raspberry Pi 上的缓存呢?这样,在使用 Docker 时可以节省时间和带宽。Raspberry Pi 非常有用,它便携、经济且耗电量微乎其微。通过创建本教程中介绍的解决方案,每次下载映像时,它都会缓存在 Pi 上;然后对于所有后续请求,将从本地缓存提供同一个映像。

Docker 是一个流行的 DevOps 工具,它为开发人员和系统管理员提供了一个平台,使他们能构建、发布并在任何地方运行应用程序。这意味着,开发人员能在本地机器上构建 Docker 映像,将它们发布到注册表,然后在云服务器上运行它们。注册表之于 Docker 映像,就像 Git 之于编码。

“本教程中的设置有助于节省时间和带宽。Raspberry Pi 非常有用,它便携、经济且耗电量微乎其微。”

Docker Hub 是一个流行的注册表,它允许用户免费托管映像。如果您的开发小组在同一个网速缓慢或带宽有限的地方协同使用 Docker,而且所有人都从 Docker Hub 下载映像,您可能会面临一些性能挑战。可以将本地网络上的私有 Docker Registry 设置为拉取式缓存,以便每次您下载一个映像时都会缓存它,对于后续的每个请求,将从本地缓存提供该映像。这也可以节省宝贵的带宽和大量时间。例如,代理缓存的基于 Ubuntu 的映像可能被多次下载到不同机器上,但该映像仅从 Docker Hub 抓取一次。

在本教程中,您将使用 Raspberry Pi 作为 Docker Hub 的拉取式缓存。Raspberry Pi 是一种信用卡大小的小型计算机,它使用的电量非常少,完整 PC 能处理的许多工作它都能处理。我们将演示从头设置 Raspberry Pi,将 Golang 安装在 Raspberry Pi 上,以及编译 Go 二进制程序(因为 Docker Registry 是使用跨平台语言 Golang 编写的)。如果一切顺利,只需两小时即可完成所有设置。我们首先看看一些前提条件。

需要的硬件和软件

开始之前,确保您拥有以下硬件:

  • Raspberry 第 2 版或更高版本
  • 8GB 或更大的 SD 卡
  • 带以太网端口的 Web 路由器
  • LAN 线
  • 安装了 Docker 的机器

还需要安装以下软件:

  • 基本 Linux 命令行
  • Docker(在这里获取最新版本)

设置

首先设置 Raspberry Pi。如果有一个运行正常的 Raspberry Pi,可以跳过这一步。Raspberry Pi 有许多发行版,但本示例使用 Raspbian,这是 Raspberry Pi 网站上提供的官方发行版。

下载 Raspbian

打开一个新终端窗口,使用 wget 下载 Raspbian 映像,该工具已预先安装在大部分 Linux 发行版上:

$ mkdir -p ~/rpi-registry
$ cd ~/rpi-registry
$ wget https://downloads.raspberrypi.org/raspbian_lite/images/
raspbian_lite-2017-04-10/2017-04-10-raspbian-jessie-lite.zip

这会将“~/rpi-registry”目录内的发行版映像下载到您的机器上。通过执行以下命令,使用 SHA 校验和与上游的 SHA 来验证下载的映像的完整性:

$ shasum 2017-04-10-raspbian-jessie-lite.zip
c24a4c7dd1a5957f303193fee712d0d2c0c6372d  
2017-04-10-raspbian-jessie-lite.zip

如果 SHA 校验和不匹配,则必须重新下载该映像。如果网速缓慢,在下载时应该使用 torrent 选项。

准备 SD 卡

要将 Raspbian 安装在 SD 卡上,可以使用 Etcher 工具,该工具可从 https://etcher.io 下载。Etcher 是一个将映像刻录到 SD 卡和 USB 驱动器上的应用程序。它可用于 Windows、Linux 和 Mac OS X。将 SD 卡插入笔记本电脑或台式机中,打开 Etcher。然后选择下载的 Raspbian 映像,确保它检测到您的 SD 卡后,单击Flash! (参见图 1)。将映像刻录到 SD 卡上需要花几分钟。

图 1. Etcher 将映像刻录到 SD 卡上
未分类

在这里设置无头 Pi,这意味着不会向 Raspberry Pi 连接键盘或显示器,所以需要在首次引导时启用 SSH。必须这么做,因为最新的 Raspbian 构建版默认已禁用 SSH。为此,在首次引导之前,在 SD 卡的引导分区中创建一个名为“SSH”的文件。该文件不得有任何扩展名,可以是空的,也可以是一个文本文件。
为此,可以在 File Explorer 中或从终端打开 SD 卡。在 Mac OS X 上,安装路径为 /Volumes/boot:

$ cd /Volumes/boot
$ touch ssh
$ ls -la
...
-rwxrwxrwx  1 kn330  staff  4235224 Mar  2 16:52 kernel7.img
drwxrwxrwx  1 kn330  staff     8704 Apr 10 09:57 overlays
-rwxrwxrwx  1 kn330  staff        0 Jun 11 03:04 ssh
-rwxrwxrwx  1 kn330  staff  2848068 Apr  7 14:39 start.elf
...

SD 卡现在已准备好引导。将卡插入 Raspberry Pi 中并将它连接到家庭路由器。

SSH 登录

要登录,需要 Raspberry Pi 的 IP 地址,可以在路由器的管理页面上找到该信息。大多数路由的管理页面地址为 192.168.1.1,但您的可能不同,所以应手动查找您的路由器(参见图 2)。也可以使用 Nmap 等网络扫描工具找到此信息。

图 2. 您的路由器包含 Pi 的 IP 地址
未分类

拥有 IP 地址后,就可以使用 Secure Shell (SSH) 登录了,输入 pi 作为用户名和 raspberry 作为密码,这是使用 Pi 随带的 Raspbian 操作系统的默认用户名和密码:

$ ssh [email protected]
[email protected]'s password: 
The programs included with the Debian GNU/Linux system are free
software; the exact distribution terms for each program are described
in the individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
SSH is enabled and the default password for the 'pi' user has not
been changed.
This is a security risk - please login as the 'pi' user and type
'passwd' to set a new password.
pi@raspberrypi:~ $

Raspbian 现在已在运行,所以您可以继续设置 Docker Registry。请注意,分配给 Pi 的 IP 地址可能更改,所以您可能需要向它分配一个静态 IP。

代理:分发 Docker 映像

Docker Registry 是一个无状态、容易扩展的服务器端应用程序,它存储并允许您分发 Docker 映像。Docker Hub 提供了一个可免费使用的托管注册表,这是所有 Docker 客户端的默认注册表,所以在执行 docker pull ubuntu 时,它会从 Docker Hub 抓取映像。可以运行一个注册表缓存来将这些映像存储在本地,而不是经常从互联网下载它们。为此,可以使用 Docker Registry 为您的家庭或组织自行托管一个私有注册表。这个开源应用程序是使用 Golang 编写的,可在 Github 上获得。可以将 Docker Registry 作为 Docker 容器运行,但我们将从头开始构建它并在裸机 Raspberry Pi 上执行该二进制程序。

工作原理

任何 Docker 客户端第一次拉入映像时,它都会从 Docker Hub 抓取映像,并在文件系统上存储一个副本。对于任何后续请求,将从本地注册表而不是 Docker Hub 提供副本。它非常聪明,在将映像提供给客户端之前,会检测上游对映像的任何更改并更新映像(参见图 3)。

图 3. docker_proxy 检测任何更改
未分类

操作说明

Golang 允许对多个架构执行交叉编译,这意味着可以在笔记本或台式机上执行以下步骤,构建 Docker Registry 的二进制程序并将它们复制到 Raspberry Pi。出于简单性考虑,我们将介绍如何在 Raspberry Pi 自身上执行构建流程。

首先安装 Golang。

安装 Golang

安装 Go 的最容易方式是使用 gvm (Golang Version Manager),该工具类似于用于 Ruby 的 rvm 或用于 Python 应用程序的 virtualenv。

pi@raspberrypi:~ $ sudo apt-get update   pi@raspberrypi:~ $ sudo
 apt-get install -y curl git mercurial make  binutils bison gcc 
build-essential pi@raspberrypi:~ $ bash < <(curl -s -S -L
 https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/
gvm-installer) pi@raspberrypi:~ $ source /home/pi/.gvm/scripts/gvm

您可能希望将源代码 /home/pi/.gvm/scripts/gvm 添加到 ~/.bashrc 文件中,以避免每次登录时都获取它:

pi@raspberrypi:~ $ go install go1.4
pi@raspberrypi:~ $ go install go1.8
pi@raspberrypi:~ $ gvm use go1.8 [--default]
pi@raspberrypi:~ $ go -v
pi@raspberrypi:~ $ go version
 go version go1.4 linux/arm

备注:Go 1.5 C 无法用于编译,所以在安装 Go 1.8 之前,需要下载 Go 1.4。

创建注册表二进制程序

Docker Registry 存储库提供了一个 Makefile,用于构建这些二进制程序并将它们放在 bin 目录中。Registry 包含在 Docker 发行版存储库中,所以可以克隆它:

pi@raspberrypi:~ $ git clone https://github.com/docker/distribution.git
pi@raspberrypi:~ $ cd distribution

接下来,安装依赖项:

pi@raspberrypi:~ $ go get ./...

创建二进制程序:

pi@raspberrypi:~ $ GOOS=linux GOARCH=arm make binaries

设置 GOOS 和 GOARCH 环境变量,让编译器知道您正在 Linux 操作系统上针对 ARM 架构而构建。如果 make 命令成功运行,将会在 bin/ 目录中看到这些二进制程序。

pi@raspberrypi:~/distribution $ ls bin/
digest  registry  registry-api-descriptor-template

测试二进制包

需要一个配置文件才能运行该注册表。创建 ~/registry-config.yml 并将以下内容复制到其中:

version: 0.1
storage: 
  cache: 
    blobdescriptor: inmemory
  filesystem: 
    rootdirectory: /var/lib/registry
http: 
  addr: :5000

您现在已拥有运行注册表所需的所有资源,接下来运行您自己的私有注册表:

pi@raspberrypi:~ $ sudo mkdir -p /var/lib/registry
pi@raspberrypi:~ $ sudo chown $USER /var/lib/registry
pi@raspberrypi:~/distribution $ ~/distribution/bin/registry
 serve ~/registry-config.yml
WARN[0000] No HTTP secret provided - generated random secret. 
如果负载平衡器背后有多个注册表,这可能导致上传问题。要提供共享密钥,可将 http.secret 填入配置文件中,或者设置 
REGISTRY_HTTP_SECRET 环境变量。go.version=go1.8
 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e
 version="v2.6.0+unknown"INFO[0000] redis not configured
 go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-
9f6863fb6a6e version="v2.6.0+unknown"
INFO[0000] Starting upload purge in 10m0s
go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e
 version="v2.6.0+unknown"
INFO[0000] using inmemory blob descriptor cache
go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e
 version="v2.6.0+unknown"
INFO[0000] Starting cached object TTL expiration scheduler...
go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e
 version="v2.6.0+unknown"
INFO[0001] Discovered token authentication URL:
https://auth.docker.io/token  go.version=go1.8 instance.id=
a80670e6-d840-44f3-aefa-9f6863fb6a6e
INFO[0001] Registry configured as a proxy cache to 
https://registry-1.docker.io  go.version=go1.8 instance.id=
a80670e6-d840-44f3-aefa-9f6863fb6a6e version="v2.6.0+unknown"
INFO[0001] listening on [::]:5000
go.version=go1.8 instance.id=a80670e6-d840-44f3-aefa-9f6863fb6a6e
version="v2.6.0+unknown"

瞧!您自己的私有注册表正在您自己的 Raspberry Pi 上正常运行。您可能看到一些警告消息,但暂时可以安全地忽略它们。我们也检查一下来自笔记本电脑的连接:

local-osx $  curl -I 192.168.1.2:5000/v2/
HTTP/1.1 200 OK
Content-Length: 2
Content-Type: application/json; charset=utf-8
Docker-Distribution-Api-Version: registry/2.0
Date: Sun, 11 Jun 2017 13:26:18 GMT

响应代码 200 表明运行正常。

代理设置

我们测试了我们的注册表,它运行正常,但还无法执行我们希望它执行的操作。我们的目的是设置一个代理,以在首次下载时缓存映像,然后在本地为后续请求提供它们。这可以通过向配置文件中添加一个代理节来完成:

version: 0.1
storage: 
  cache: 
    blobdescriptor: inmemory
  filesystem: 
    rootdirectory: /var/lib/registry
http: 
  addr: :5000
proxy: 
 remoteurl: https://registry-1.docker.io

在这里,remoteurl 是 Docker Hub 注册表的 URL。如果愿意,也可以将端口从 5000 更改为任何其他端口。使用同一个命令运行该注册表:

pi@raspberrypi:~/distribution $ ~/distribution/bin/registry serve
 ~/registry-config.yml &

请注意末尾的 &,它使该进程在后台运行。现在可以在笔记本电脑上配置 Docker 守护进程,以使用这个注册表镜像(参见图 4)。如果使用 Docker for Mac,可通过转到 Preferences > Registry mirrors 并添加 http://192.168.1.2:5000,然后重新启动 Docker 来实现此目的。如果在任何其他操作系统上使用 Docker,可以按照相关文档(参阅“相关主题”)更新 Docker 守护进程首选项。

图 4. Docker 守护进程配置
未分类

现在,每次您在笔记本电脑上下载映像,它都会缓存在 Raspberry Pi 上的 /var/lib/registry 目录中。您可能希望在该路径挂载一个外部驱动器。我们通过拉取 Mongo Docker 映像来检验此做法:

local-osx $ time docker pull mongo
Using default tag: latest
latest: Pulling from library/mongo
56c7afbcb0f1: Pull complete
...
e233325a655e: Pull complete
Digest:
sha256:c4bc4644b967a4b58022a79cf5c9afcd25ed08180c958a74df57b7753cfc8649
Status: Downloaded newer image for mongo:latest
docker pull mongo  0.15s user 0.18s system 0% cpu 2:22.28 total

local-osx $ docker rmi mongo

local-osx $ time docker pull mongo
Using default tag: latest
latest: Pulling from library/mongo
56c7afbcb0f1: Pull complete
...
e233325a655e: Pull complete
Digest: sha256:c4bc4644b967a4b58022a79cf5c9afcd25ed08180c958a74df57b7753cfc8649
Status: Downloaded newer image for mongo:latest
docker pull mongo  0.15s user 0.13s system 0% cpu 51.303 total

可以看到,第一次拉取花了 142 秒,而第二次在 60 秒内就完成了。

结束语

如果您的网络连接缓慢且有多个用户在下载 Docker 映像,本文中介绍的设置可以帮助您节省时间和带宽。Raspberry Pi 非常有用,它便携、经济且耗电量微乎其微。您已看到使用 Raspberry Pi 作为 Docker Hub 的拉取式缓存的好处:每次您下载一个映像,它都会缓存在 Pi 上,对于每个后续请求,会从本地缓存中提供该映像。

使用 HAProxy + Keepalived 构建基于 Docker 的高可用负载均衡服务(二)

本文主要介绍把 HAProxy + Keepalived 服务组合形成单独的镜像,并能够自定义配置项。适合具有 Docker 和 Bash 相关基础的开发、运维等同学。

使用 Docker 组合构建 haproxy-keepalived 服务

未分类

上图为我们要构建的 haproxy-keepalived 服务的工作原理图,原理表述如下:

START:

  • 根据 Bash 脚本和 Docker 容器的环境变量生成 HAProxy 和 Keepalived 的配置文件
  • 在容器内部启动 HAProxy 和 Keepalived 服务

STOP:

  • ENTRYPOINT 使用 trap 接收到传递来的 SIGTERM 信号
  • 使用 kill -ITEM $pid 的方式,结束掉 HAProxy & Keepalived 两个服务。

下边会按照上述步骤介绍如何工作。

生成 HAProxy & Keepalived 配置文件

haproxy_cfg_init.sh
#!/bin/bash

HAPROXY_DIR="/usr/local/etc/haproxy"
TMP_HAPROXY="/tmp/haproxy"

TMP_FILE="${TMP_HAPROXY}/tmp.cfg"
TMP_TEMPLATE="${TMP_HAPROXY}/template.cfg"

TEMPLATE_FILE="/haproxy/template.cfg"
HAPROXY_CFG="${HAPROXY_DIR}/haproxy.cfg"

# mkdir to prevent not exists
mkdir -p ${HAPROXY_DIR}
mkdir -p ${TMP_HAPROXY}
rm -rf ${HAPROXY_DIR}/haproxy.cfg

# delete old haproxy.cfg and touch tmp.cfg
rm -rf ${HAPROXY_CFG}
rm -rf ${TMP_FILE}
touch ${TMP_FILE}

# copy template.cfg to tmp dir
cp ${TEMPLATE_FILE} ${TMP_TEMPLATE}

COUNTER=1
while [ ${COUNTER} -gt 0 ]
do
    haproxy_item=$(printenv haproxy_item${COUNTER})

    if [ -z "${haproxy_item}" ]
    then
        break;
    fi

    # echo haproxy_item to /tmp/haproxy/tmp.cfg
    echo "${haproxy_item${COUNTER}}" >> ${TMP_FILE}

    let COUNTER+=1
done
echo "Success generate tmp.cfg!"

sed -i "/#CUSTOM/r ${TMP_FILE}" ${TMP_TEMPLATE}
echo "Success generate template.cfg"

touch ${HAPROXY_CFG}
envsubst < ${TMP_TEMPLATE} > ${HAPROXY_CFG}

echo "Success generate haproxy.cfg, file content is below:"
echo "----------------haproxy.cfg------------------"
cat ${HAPROXY_CFG}
echo "------------------ End ----------------------"

容器在启动的时候,传入 haproxy_item_${CURSOR} 环境变量,上述脚本根据传入的环境变量与 template.cfg 文件结合,生成最终的 /usr/local/etc/haproxy/haproxy.cfg 配置文件。

大致相似的原理,根据 init_keepalived_conf.sh 脚本,与传入的环境变量结合,使用环境变量替换 keepalived_template.conf 文件中的环境变量,来生成 最终的 /etc/keepalived/keepalived.conf 配置文件。

#!/bin/bash
set -e

TEMPLATE="/keepalived/keepalived_template.conf"
TMP_TEMPLATE="/tmp/keepalived/tmp_keepalived_template.conf"
KEEPALIVED_FILE="/etc/keepalived/keepalived.conf"

# mkdir to prevent not exist
mkdir -p /tmp/keepalived/
mkdir -p /etc/keepalived/

# copy template to /tmp/keepalived/tmp_keepalived_template.conf
cp ${TEMPLATE} ${TMP_TEMPLATE}

envsubst < ${TMP_TEMPLATE} > ${KEEPALIVED_FILE}
echo "Success generate ${KEEPALIVED_FILE}"
echo "----------------------keepalived.conf----------------------"
cat ${KEEPALIVED_FILE}
echo "--------------------------- End ---------------------------"

容器内部启动 HAProxy & Keepalived 服务

查看 Dockerfile 文件,这个 haproxy-keepalived 镜像是基于 haproxy:1.7.9 基础镜像来做的修改。为了符合一个容器启动 HAProxy & Keepalived 两个服务的预期,我们增加了一个 docker-entrypoint-override.sh 的脚本来作为 haproxy-keepalived 镜像的 ENTRYPOINT。

在 docker-entrypoint-override.sh 中,我们分别用如下两条命令启动来启动两个服务:

  • HAProxy: exec /docker-entrypoint.sh “$@” &

    直接后台运行 haproxy:1.7.9 官方镜像的原 docker-entrypoint.sh 来启动 haproxy

  • Keepalived: exec /start_keepalived.sh “$@” &

    后台运行 start_keepalived.sh 脚本来启动 Keepalived 服务

接下来会稍微详细说一下 start_keepalived.sh 脚本:

#!/bin/bash

LANUCH_SCRIPT="keepalived --dont-fork --dump-conf --log-console --log-detail --log-facility 7 --vrrp -f /etc/keepalived/keepalived.conf"

eval $LANUCH_SCRIPT
while true; do
  k_pid=$(pidof keepalived)
  if [ -n "$k_id" ]; then
    break;
  fi

  kill -TERM $(cat /var/run/vrrp.pid)
  kill -TERM $(cat /var/run/keepalived.pid)
  echo "ERROR: Keepalived start failed, attempting restart ."
  eval $LANUCH_SCRIPT
done

echo "Keepalived started successfuly!"

在上述脚本中,我们在运行 LANUCH_SCRIPT 后,又做了一个循环判断。原因是在我们使用这个自定义的 haproxy-keepalived 服务的时候,在重启容器后 Keepalived 并不能正常启动,会有个报错:

Keepalived: Daemon is already running

但实际上,这个 Daemon 我们已经给它 kill 掉了。我们这里再执行一次判断,如果 $k_id 值不为空,则 Keepalived 启动成功;如果 $k_id 值为空,我们会再 kill 一次 Keepalived 的进程,然后重启 Keepalived。

容器停止,Graceful Shutdown

在容器停止的时候,需要做 Graceful Shutdown 的操作,在这里的目标就是:容器关闭前干掉 HAProxy & Keepalived 的进程。

仍然回到 docker-entrypoint-override.sh 脚本,在脚本中我们定义了接收 SIGITERM 信号的处理事件:

trap "stop; exit 0;" SIGTERM SIGINT

# handler for SIGINT & SIGITEM
stop() {
  echo "SIGTERM caught, terminating <haproxy & keepalived> process..."

  # terminate haproxy
  h_pid=$(pidof haproxy)

  kill -TERM $h_pid > /dev/null 2>&1
  echo "HAProxy had terminated."

  # terminate keepalived
  kill -TERM $(cat /var/run/vrrp.pid)
  kill -TERM $(cat /var/run/keepalived.pid)
  echo "Keepalived had terminated."

  echo "haproxy-keepalived service instance is successfuly terminated!"
}

当容器被 stop 或者 kill 的时候,会触发这个 handler 事件。我们在事件中对两个服务做了下简单的处理。

如何使用

首先,准备两台 Linux 虚拟机,假定 IP 分别为:192.168.0.41、192.168.0.42,并找到一个 VIP,假定为 192.168.0.40。

在 192.168.0.41 机器上新建 /data/haproxy-keepalived/docker-compose.yml 文件:

root@haproxy-master:/data/haproxy-keepalived# cat docker-compose.yml
version: '3'
services:

  haproxy-keepalived:
    image: "pelin/haproxy-keepalived"
    privileged: true
    network_mode: host
    restart: always
    environment:
      KEEPALIVED_STATE: "MASTER"
      KEEPALIVED_INTERFACE: "ens18"
      KEEPALIVED_PRIORITY: "105"
      KEEPALIVED_V_ROUTER_ID: "40"
      KEEPALIVED_VIP: "192.168.0.40"
      haproxy_item1: |-
        listen app-1
            bind *:4000
            mode http
            maxconn 300
            balance roundrobin
            server server1 192.168.0.21:4001 maxconn 300 check
            server server2 192.168.0.22:4002 maxconn 300 check
         listen app-2
            bind *:5000
            mode http
            maxconn 300
            balance roundrobin
            server server1 192.168.0.21:5001 maxconn 300 check
            server server2 192.168.0.22:5002 maxconn 300 check

注意上述配置:
KEEPALIVED_STATE             # Keepalived 节点初始状态
KEEPALIVED_INTERFACE         # Keepalived 绑定的网卡
KEEPALIVED_PRIORITY          # 权重
KEEPALIVED_V_ROUTER_ID       # router_id
KEEPALIVED_VIP               # 虚拟 IP

其中,KEEPALIVED_INTERFACE 需要根据实际情况而定。比如笔者用的 Ubuntu 16.04 的主网卡是 ens18,Ubuntu 14.04 的网卡是 eth0。

然后使用如下命令开启服务:

root@haproxy-keepalived:/data/haproxy-keepalived# docker-compose up

在启动后,访问浏览器:192.168.0.41:1080/stats 即可看到有界面出现

同理,在 42 机器上做上述操作,其中 KEEPALIVED_STATE 需要修改为 BACKUP

如何扩展

目前实现的功能:

  • 根据环境变量动态调整 HAProxy & Keepalived 配置
  • 容器 Graceful Shutdown
  • 容器能够正常 Restart,Crashed 后能正常自动重启

TODO:

  • 直接 Bind 配置文件进容器

如果需要自定义一个 haproxy-keepalived 镜像的话,可以参考上边的思路来做。当然,如果场景可以使用 Bind 的方式,那自然是更简单了。

如果可以直接 Bind 配置文件进容器,上述很多脚本都可以省略掉。但是,我们更寄期望于在容器编排工具中,使用环境变量的方式来初始化配置文件。为什么有这样的考虑?

  • 当有多台机器的时候,我们需要一台一台去修改 Bind 的配置文件。虽然可以使用 Ansible 之类的自动化机制来做,但是在这种场景下把配置和服务分离并不太合适;
  • 对以后做服务的自动伸缩机制友好。服务在伸缩之后,通过服务发现我们需要更新我们的 LB 的配置。如何更新?自然是通过我们的中心容器编排工具来自动更新。去触发脚本更新与我们的期望不符。

LICENSE

Source code: https://coding.net/u/Pelin_li/p/haproxy-keepalived/git

Based on MIT LICENSE: https://coding.net/u/Pelin_li/p/haproxy-keepalived/git/blob/master/LICENSE

使用 Docker 完成 MySQL 数据库主从配置

使用 docker 进行数据库主从配置,因为我有这个需求,而在网上搜索后发现没有满足我需求的相关实践文档,有的是一些零零碎碎的文档,而且在参照这些文档进行部署的时候我还踩了许多坑。

因此根据我自己部署成功的经验,我写了这个文档。

使用 docker 自然就需要有 docker 环境,当然 docker 的镜像在国内访问比较慢,建议使用国内的源。

构建 DockerFile

我们的工作是在 Mysql 镜像基础上进行的。

docker pull mysql:5.7.20 这条命令会下载最新的 mysql 镜像,当然也可以指定版本。

新建一个 DockerFile 文件:

FROM mysql:5.7.20

EXPOSE 3306

COPY my.cnf /etc/mysql/

CMD ["mysqld"]

在构建镜像前,我们需要 mysql 的配置文件 my.cnf ,可以先启动一个 mysql 的容器,然后进入容器复制它下来,并对其进行修改:

!includedir /etc/mysql/conf.d/
[mysqld]
pid-file=/var/run/mysqld/mysqld.pid
socket=/var/run/mysqld/mysqld.sock
datadir=/var/lib/mysql
#log-error=/var/log/mysql/error.log
# By default we only accept connections from localhost
#bind-address   = 127.0.0.1
log-bin=/var/log/mysql/mysql-bin.index
server-id=1
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

以上是我修改好的一个 my.conf 文件,我们主要修改的是以下这些选项:

#bind-address   = 127.0.0.1 # 注释这个选项可以让远程机器访问,或者可以修改为 0.0.0.0
log-bin=/var/log/mysql/mysql-bin.index # 开启 log-bin 日志,日志路径
server-id=1 # 服务器唯一ID,默认是1,一般取IP最后一段,这里看情况分配

这是我的主库的 my.cnf,从库的基本一样,只是 servier-id 不一样,从库为 2,将这个文件也放在文件夹里。

构建需要的文件结构就是以下这样:

master
├── Dockerfile
└── my.cnf
slave
├── Dockerfile
└── my.cnf

然后在master目录中使用 docker build -t master/mysql:5.7.20 . 命令构建镜像主库,从库构建命令 docker build -t slave/mysql:5.7.20 .。命令最后有个.,不要忘记,代表当前目录。-t 的意思是tag,是 –tag 的缩写,也就是命名这个镜像,如果不加docker会随机给这个镜像一个名字,建议格式为name:tag

构建完成后我们使用以下命令启动主库和从库:

docker run -p 3306 --name mysql-master -e MYSQL_ROOT_PASSWORD=root -d master/mysql:5.7.20

docker run -p 3306 --name mysql-slave --link mysql-master:master -e MYSQL_ROOT_PASSWORD=root -d slave/mysql:5.7.20

然后分别执行docker exec -it mysql-master bash和docker exec -it slave-master bash命令进入到容器内部。执行mysql -uroot -proot进入mysql环境,这时我们的环境搭建就已经完成了,下面正式配置主从连接。

当然此时docker会分配一个唯一的端口给容器,我们也可以用mysql客户端连接进行配置。使用docker ps查看端口号,就可以用客户端连接进行管理。

☁  mysql-master-slave  docker ps
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                     NAMES
6c7648e829e0        slave/mysql:5.7.20    "docker-entrypoint..."   4 minutes ago       Up 4 minutes        0.0.0.0:32769->3306/tcp   mysql-slave
483842c63235        master/mysql:5.7.20   "docker-entrypoint..."   5 minutes ago       Up 5 minutes        0.0.0.0:32768->3306/tcp   mysql-master

使用GRANT REPLICATION SLAVE ON . to ‘user’@’%’ identified by ‘mysql’; 或者 GRANT REPLICATION SLAVE ON . TO ‘user’@’192.168.1.200’ IDENTIFIED BY ‘mysql’;创建一个用户,上一个是所有ip都可以访问,下一个是指定ip才可以访问。

然后使用GRANT SELECT,REPLICATION SLAVE ON . TO ‘user’@’%’;给这个用户读取权限。

使用show master status查看mysql主容器的状态,打印如下信息:

+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 |      154 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+

使用hostname查看主容器的hostname,如我的主容器是483842c63235。

接下来配置从库mysql:

change master to
master_host='master',#要连接的主服务器的ip
master_user='user',#指定的用户名,最好不要用root
master_log_file='mysql-bin.000003',#主库记录的值
master_log_pos=154,#主库的pos值
master_port=3306,#主库3306映射的端口
master_password='mysql';#主库要连接的用户的密码了

使用start slave启动主从同步

使用命令查看show slave statusG

打印如下信息:

*************************** 1. row ***************************
               Slave_IO_State: Connecting to master
                  Master_Host: master //主服务器地址
                  Master_User: user //授权帐户名,尽量避免使用root
                  Master_Port: 3306 //数据库端口,部分版本没有此行
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000003 //同步主库的日志文件名
          Read_Master_Log_Pos: 154 //同步读取二进制日志的位置,大于等于
               Relay_Log_File: 6c7648e829e0-relay-bin.000001
                Relay_Log_Pos: 4
        Relay_Master_Log_File: mysql-bin.000003
             Slave_IO_Running: Yes //此状态必须YES
            Slave_SQL_Running: Yes //此状态必须YES
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 154
              Relay_Log_Space: 154
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 0
                  Master_UUID:
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set:
                Auto_Position: 0
         Replicate_Rewrite_DB:
                 Channel_Name:
           Master_TLS_Version:
1 row in set (0.00 sec)

这样就是完成了一组主从mysql的配置。

shell脚本

一下一个相应的shell脚本,可以在1分钟能启动一组mysql主从容器,运行这个脚本需要稍作修改,主要是mysql配置文件。

#!/bin/bash

MASTER_DIR=/var/lib/mysql/mysql-master
SLAVE_DIR=/var/lib/mysql/mysql-slave

## First we could rm the existed container
docker rm -f mysql-master
docker rm -f mysql-slave

## Rm the existed directory
rm -rf $MASTER_DIR
rm -rf $SLAVE_DIR

## Start instance
docker run -p 3306 --name mysql-master  -v /etc/master.cnf:/etc/mysql/my.cnf -v $MASTER_DIR:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -d master/mysql:5.7.20
docker run -p 3306 --name mysql-slave  -v /etc/slave.cnf:/etc/mysql/my.cnf -v $MASTER_DIR:/var/lib/mysql --link mysql-master:master -e MYSQL_ROOT_PASSWORD=root -d slave/mysql:5.7.20

## Creating a User for Replication
docker stop mysql-master mysql-slave
docker start mysql-master mysql-slave

sleep 3

docker exec -it mysql-master mysql -S /var/lib/mysql/mysql.sock -e "CREATE USER 'users'@'127.0.0.1' IDENTIFIED BY 'mysql';GRANT REPLICATION SLAVE ON *.* TO 'users'@'127.0.0.1';"

## Obtaining the Replication Master Binary Log Coordinates
master_status=`docker exec -it master mysql -S /var/lib/mysql/mysql.sock -e "show master statusG"`
master_log_file=`echo "$master_status" | awk  'NR==2{print substr($2,1,length($2)-1)}'`
master_log_pos=`echo "$master_status" | awk 'NR==3{print $2}'`
master_log_file="'""$master_log_file""'"

## Setting Up Replication Slaves 
docker exec -it mysql-slave mysql -S /var/lib/mysql/mysql.sock -e "CHANGE MASTER TO MASTER_HOST='master',MASTER_PORT=3306,MASTER_USER='users',MASTER_PASSWORD='mysql',MASTER_LOG_FILE=$master_log_file,MASTER_LOG_POS=$master_log_pos;"
docker exec -it mysql-slave mysql -S /var/lib/mysql/mysql.sock -e "start slave;"
docker exec -it mysql-slave mysql -S /var/lib/mysql/mysql.sock -e "show slave statusG"

## Creates shortcuts
grep "alias mysql-master" /etc/profile
if [ $? -eq 1 ];then
    echo 'alias mysql="docker exec -it mysql-master mysql"' >> /etc/profile
    echo 'alias master="docker exec -it mysql-master mysql -h 127.0.0.1 -P3306"' >> /etc/profile
    echo 'alias slave="docker exec -it mysql-master mysql -h 127.0.0.1 -P3307"' >> /etc/profile
    source /etc/profile
fi

Centos7.4下用Docker-Compose部署WordPress

前言

最近在学习Docker相关知识,通过阅读第一本Docker书后,正想着手实战用一下这个技术,但又不太敢直接在项目环境下动手。考虑足足三秒钟之后决定买个阿里云ECS搭建一个属于自己的基于Docker的WordPress博客Daniel Fu’s hut传送门。

本博客搭建环境(阿里云ECS的购买与基本的安全组配置等工作在文中省略,各位看官可自行研究):

  • 阿里云ECS
  • Centos 7.4

部署工具

  • Docker
  • Docker Compose(Compose工具比起单纯的Dockerfile来更为便利、更易管理)
  • WordPress和MySql5.7(运行在Docker容器中)

现在逐个讲解下如何安装:

Docker:

根据官方文档,Docker分为Community Edition (CE)和Enterprise Edition (EE)两个版本,我们作为学习和个人使用,当然选择的是Community Edition (CE),安装步骤如下:

// 步骤1 - 为了确保没有安装过老的Docker版本,先将已经安装的Docker从宿主机上删除(如果是在使用中的正式服务器,请谨慎执行此步):
$ sudo yum remove docker 
  docker-common 
  docker-selinux 
  docker-engine

// 步骤2 - 安装Docker所需的包:
$ sudo yum install -y yum-utils 
  device-mapper-persistent-data 
  lvm2

// 步骤3 - 配置到稳定的Docker CE安装库:
$ sudo yum-config-manager 
    --add-repo 
    https://download.docker.com/linux/centos/docker-ce.repo

// 步骤4 - 安装Docker CE:
$ sudo yum install docker-ce

// 步骤5 - 启动Docker服务:
$ sudo systemctl start docker

// 步骤6 - 测试是否安装成功:
// 可以通过查看版本的形式确认安装是否成功:
$ docker --version 
// 也可以通过直接运行hello-world容器来确认安装是否成功:
$ docker run hello-world

Docker Compose:

为了便于使用,我们需要安装Docker Compose来管理和运行Docker容器,Docker Compose的安装步骤如下:

// 步骤1 - 下载安装文件:
$ sudo curl -L https://github.com/docker/compose/releases/download/1.17.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

// 步骤2 - 给已下载的安装文件添加执行权限:
$ sudo chmod +x /usr/local/bin/docker-compose

// 步骤3 - 测试是否安装成功:
$ docker-compose --version

部署WordPress和MySql容器:

先创建一个工作目录,并创建名为docker-compose.yml的文件:

$ cd /usr/
$ sudo mkdir myblog && cd myblog
$ sudo vim docker-compose.yml

将如下内容保存在docker-compose.yml文件中:

version: '3'
services:
   db:
     image: mysql:5.7
     volumes:
       - db_data:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: your-mysql-root-password
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress
   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     volumes:
        - wp_site:/var/www/html
     ports:
       - "80:80"
       - "443:443"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress
volumes:
    db_data:
    wp_site:
  • 关于Composer所使用的的yml文件的语法,请参考官方文档,这里就不一一解释了(因为我自己也是刚入门,只会几个基本的用法)。

  • 和官方给的Demo不同,上述yml文件中,我在volumes中添加了wp_site的卷,并将其挂在到wordpress容器中,这样,当容器被停止或者删除后,重新安装并启动wordpress容器时,已安装的plugins也可以直接继续使用,而不是重新安装。

此时,我们直接使用docker-compose命令启动容器:

$ sudo docker-compose up -d

启动之后,我们就可以通过 http://ecs-ip (因为我们绑定的是宿主机的80端口) 来访问WordPress(如果不能访问,请查看阿里云安全组中,是否已经开启了你所指定端口的公网访问权限,一般80端口是默认开启的)。

如果需要关闭服务,则执行如下命令:

$ sudo docker-compose down

开启你的博客之旅:

我们的WordPress博客已经搭建完成,通过访问后台管理页面来初始化网站。然后找一个喜欢的主题,安装好必要的插件,我们就可以在一个属于自己的博客网站上写下自己的第一篇博客。

分享一下:这是我第一次用WordPress,还有很多东西需要慢慢摸索。目前我安装了Jetpack插件和WP Editor.MD插件,选用的主题是Sirius免费版。

遇到的挫折:

第一次安装时,当使用 sudo docker-compose up -d 命令启动容器后,提示容器启动正常,但是无法访问网站,此时通过sudo docker logs xxx_wordpress_1(xxx_wordpress_1以实际生产的容器名称为准)查看日志,看到日志中不断提示数据库无法连接的错误。花了好几个小时排查,总算找到问题所在,是因为以前在机器上写Docker相关的测试例子的时候,宿主机上设置了几个全局变量(如:ServerName、ServerHost、UserName等,可通过env命令查看当前系统环境变量),这些全局变量导致了wordpress容器无法连接到db容器。这个小插曲告诉我们,不要随便在宿主机上设置环境变量,如果必须设置,也应该做好命名和管理工作。

docker 搭建lnmp开发环境

docker学习心得

前言

耗时一周零三天,终于用docker搭建起自己的开发环境。
详细过程:请参考https://segmentfault.com/a/1190000011912956

未分类

下面说说我的心路历程:(从一个系统说起deepin)
Ubuntu16.04用的好好地,突然看见17.10发布了,界面还挺好看。果断升级为17.10。然后发现,界面看着漂亮,用的时候很难受,快捷键和16.04也不太一样,装的软件各种打不开。经过深思熟虑我就换成deepin,各种常见的软件都能装,比如QQ,微信,搜狗等等,美滋滋。来搭建一下环境lnmp,然后,桌面没了。查了一下资料,说deepin桌面版不能装。心想,弄个虚拟机吧,可以各种折腾,折腾坏了重建就行了。想到最近docker很火,果断入坑。

作者经历的各种阶段:(各位可以参考,避免浪费时间)

第一阶段:找教程
极客学院这个不错,各种概念讲的很清楚,建议新学者直接通读一遍再动手。还有,不要全看,如果只是想我一样想在本地搭建docker环境。我给你总结几点:

  1. 了解docker三个概念,镜像,容器,仓库
  2. 掌握这么几个命令和对应命令的常用参数:docker run/ps/rm/rmi/start/stop/exec (创建并运行容器/查看运行的容器/删除容器/删除镜像/启动容器/停止容器/容器外进入容器)
  3. 知道Dockerfile是什么?能做什么?我刚开始,想着只用centos官方镜像通过Dockerfile创建出自己的lnmp,想着在Dockerfile里面完成php,mysql,nginx的编译安装,后面发现还不是照着网络上的编译过程各种复制粘贴,还各种报错,自己不会解决,何必自己坑自己。
  4. 知道docker-compose是什么?能做什么?(自己看教程)

第二阶段:安装docker
安装我就不说了,着重说一下docker加速器阿里云加速器

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://4qqg0972.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

第三阶段:学习命令
第四阶段:找别人搭建的lnmp ( https://www.awaimai.com/2120.html )
第五阶段:看完之后满脑袋为什么?开始研究,最后质疑别人搭建的
第六阶段:还是用别人搭建好的(自己搭建不出来)
第七阶段:发现和自己的需求不一致,配置文件对不上
第八阶段:自己搭
第九阶段:觉得自己搭建的很好,在这写个教程,哈哈

总结:这些阶段是作者真实经历过的,可能还比这个多。作为过来人,我只想说,一定要只做一件事,不要过多的去研究,我们只是想搭建本地运行环境。

自己搭建docker lnmp 过程:

第一步:docker pull centos # 拉取官方centos镜像
第二步:docker run -it –name ‘lnmp-self’ centos /bin/bash # 创建并运行容器
第三步:使用lnmp一键安装包
第四步:docker commit -a ‘amor’ -m ‘lnmp’ b7515f3e6a82 lnmp:1.4 # 基于已有镜像的容器创建新镜像
第五步:创建Dockerfile进行微调,可能需要安装新软件等
第六步:通过docker-compose 进行管理,开放端口,挂载数据卷(挂载配置,项目目录)

这样做有以下几点好处:

  1. 避免编译安装,降低Dockerfile复杂度,避免学习使用大量的linux命令,避免使用自己不熟悉的镜像
  2. 易理解,易管理,易扩展(都是自己弄得嘛,哈哈)

下面附上自己的Dockerfile,docker-compose内容,请在第五步和第六步之后参考
Dockerfile

FROM lnmp:1.4
MAINTAINER amor ([email protected])
# ssh
RUN yum install openssh-server -y
RUN mkdir -p /data/website/
CMD ["lnmp", "start"]

docker-compose

lnmp:
  build: .
  ports:
    - "80:80"
    - "443:443"
    - "22:22"
  volumes:
    # nginx 配置文件夹
    - ./conf/nginx/:/usr/local/nginx/conf/
    # mysql 配置文件
    - ./conf/mysql/my.cnf:/etc/my.cnf:rw
    # php配置文件
    - ./conf/php/:/usr/local/php/etc/
    # 项目目录
    - /data/Nutcloud/Ubuntu/website/:/data/website/
  tty: true

目录结构(仅供参考)

.
├── conf
│   ├── mysql
│   ├── nginx
│   └── php
├── docker-compose.yml
└── Dockerfile

配置一个安全的docker宿主机

如使用Linux默认安装来运行Docker守护进程和容器,会使你的主机出现安全和性能问题。 在本文中,我们将使用CentOS7的最小安装作为示例来说明如何配置来一个安全的docker运行宿主机。

前言

 本文以CentOS为例,介绍如何配置一个符合安全要求的docker运行宿主机。如使用默认安装来运行Docker守护进程和容器,会使你的主机出现安全和性能问题。 在本文中,我们将使用CentOS7的最小安装作为示例来说明如何配置来一个安全的docker运行宿主机。 CentOS已经大规模的应用到生产系统中,已被证明是一个稳定而安全的Linux版本。如果选择使用不同的Linux发行版,本文中的做法仍然值得参考,只需要将相关的示例命令转换为你的目标环境的命令。配置需要重点关注三个方面:

1、一个不需要任何额外服务和软件的操作系统,只运行Docker所需的工具。

2、安装并配置Docker守护程序以运行容器。 这包括性能和安全的设置,配置Docker更适合于生产环境而不是开发测试环境。

3、设置访问控制的安全策略,将防火墙配置为仅允许SSH和用于外部通信的容器必要端口。

安装操作系统

最小安装

     从官方镜像中最小安装CentOS 7, 如果以前安装过CentOS,还有一些步骤需要考虑:
  • 删除所有开发工具(编译器等)

  • 删除所有监听的服务,只保留22端口以进行SSH访问。 防火墙配置阻止其他正在运行的服务和删除多余服务

更新系统源

更新系统源确保所有库和程序都运行最新的版本。

sudo yum update –y

未分类

创建一个新用户

不能使用root用户运行容器,所以必须添加一个新的用户。

例如:添加用户名为dockeruser的新用户

1、向主机添加新用户。

adduser dockeruser

2、为新用户设置密码

passwd dockeruser

3、将用户添加到wheel组以提供sudo访问权限

usermod -a -G wheel dockeruser

未分类

生成SSHD密钥

     安全最佳做法是禁用使用密码的身份验证。我们可使密钥,并将其复制到服务器作为认证密钥。 以下步骤将是如何为linux或OSX主机生成密钥。

1、 在的客户端上生成ssh密钥

ssh-keygen –t rsa

2、运行此命令将在你的主目录的.ssh目录中创建两个文件

a. id_rsa –私钥

b. id_rsa.pub –公钥

3、使用新建用户dockeruser登录到Docker主机

mkdir ~/.ssh

sudo chmod 700 ~/.ssh

4 、 将公钥复制到Docker主机。 例如

scp ~/.ssh/id_rsa.pub [email protected]:~/.ssh/authorized_keys

5、现在可以不使用密码登录到主机

ssh [email protected]

SSH禁用root登录和使用密码的身份验证

禁用root用户登录到主机系统。 另外不允许使用密码登录。这是为了防止使用暴力破解主机系统的账号 ,在上面介绍中,向系统添加了一个新用户,并将其密钥复制到服务器。 使用该用户配置主机。

1、使用新添加的用户登录到主机

2、编辑SSH程序的配置文件禁用root登录

sudo vi /etc/ssh/sshd_config

3、找到以下文本:

#PermitRootLogin yes

4、更改内容为如下

PermitRootLogin no

5、找到以下文本的行

#PasswordAuthentication yes

6、更改内容为如下

PasswordAuthentication no

7、重启SSH服务

sudo systemctl restart sshd.service

停止SSHD以外的任何服务

出于安全考虑,宿主机是用于运行容器,因此,不应该运行任何多余的服务。建议更改ssh监听端口以进一步增强安全性。 对于本文中,已经更改SSH监听端口41022。

1、列出任何开放和侦听端口

sudo nmap -sU -sS -p 1-65535 localhost

未分类

在这种情况下,我们有两个打开和侦听的TCP端口。 41022端口是可以运行的ssh侦听端口 。25端口是SMTP服务,为系统默认安装,我们需要停止。

2、停止和删除postfix

a. 停止postfix服务

sudo systemctl stop postfix

b. 检查postfix是否还在监听端口25

sudo nmap -sU -sS -p 1-65535 localhost

未分类

c. 从主机中删除postfix

sudo yum remove postfix

安装和配置Docker

安装Docker

1、配置yum以查找Docker存储库

a. 创建一个新文件来保存Docker存储库的信息

sudo vi /etc/yum.repos.d/docker-ce.repo

b. 将以下内容添加到文件中:

[docker-ce-stable]

name=Docker CE Stable – $basearch
       baseurl=https://download.docker.com/linux/centos/7/$basearch/stable

enabled=1

gpgcheck=1

gpgkey=https://download.docker.com/linux/centos/gpg

c. 保存文件

2、安装Docker软件包

sudo yum install docker-ce –y

未分类

3、启动docker

sudo service docker start

Alternate: systemctl start docker

4、验证docker是否正常运行

sudo docker run hello-world

未分类

5 、配置Docker守护进程在开机时启动

sudo chkconfig docker on

Alternate: sudo systemctl enable docker

未分类

配置Docker

通过配置Docker来增加安全性,用于生产环境限制容器资源消耗。我们通过给docker守护进程传递命令行参数来执行操作。 我们将要使用的命令行总结如下

–icc=false

禁止容器之间通信。

  • 如果了解应用环境的网络拓扑,可以启用某几个容器与容器之间来进行通信使用—link参数

(–link=CONTAINER_NAME_or_ID:ALIAS)

  • 如果需要所有容器之间相互通信,可以将其设置为true,但这种情况在某种程度上是不安全的,它允许所有容器之间的完全网络通信。

–log-level“info”

将日志级别设置为info。 日志记录有多个级别,但有时记录内容非常多,会导致磁盘耗尽。日志级别的设置是为了获取需要的日志信息,而不是获取所有记录信息,而且有些日志信息无用且占用大量磁盘空间。

–iptables=true

启用iptables规则。

–default-ulimit

为容器设置默认的ulimits。这个参数将设置限制进程和文件的数量有关。这会确保容器不会占用过多的主机资源而造成主机宕机。

  • –default-ulimit nproc=1024:2048 –default-ulimit nofile=1020:2048

Docker进程启动参数非常多,本文中只说明配置方法,更多进程启动参数请参阅docker官网。下面是进程启动参数的配置方法:

1 、编辑docker.service文件

sudo vi /usr/lib/systemd/system/docker.service

2 、找到以下文本行

ExecStart=/usr/bin/dockerd

3 、修改为如下

ExecStart=/usr/bin/dockerd –icc=false –log-level  “info” –iptables=true –default-ulimit nproc=1024:2408–default-ulimit nofile=1024:2048 

4、重新加载

sudo systemctl daemon-reload

5、重新启动Docker服务

sudo service docker restart

6、验证命令行操作现在被传递给Docker

sudo ps -eaf | grep docker 

未分类

设置访问策略

在安全性较高的系统中,防火墙配置应启用白名单策略,默认禁用所有入站和出站流量。CentOS 7的防火墙默认使用firewalld,为了方便和docker容器访问控制集成,这里将禁用firewalld并使用iptables服务用于访问控制。

1 、禁用firewalld

sudo systemctl disable firewalld

2 、安装iptables-services

sudo yum install iptables-services –y

3 、启用iptables服务

sudo systemctl enable iptables

4、配置iptables规则(在最后的规则中,将替换为你的服务器ip-address)

sudo iptables -P INPUT DROP

sudo iptables -P FORWARD DROP

sudo iptables -A INPUT -p tcp -s 0/0 -d<serverip> –sport 513:65535 –dport 22 -mstate –state NEW,ESTABLISHED -j ACCEPT

5、保存iptables规则

sudo service iptables save

6 、验证iptables规则

     sudo iptables –L

通过安装nginx进行测试

让我们通过下载并运行nginx来测试Docker的安装。

1、下载images

sudo docker pull nginx (alpine /nginx:latest)

2 、启动nginx容器

sudo docker run –name docker-nginx -p 80:80 nginx

注意:-p 80:80将容器的端口80映射到主机外部端口80。

这条命令会修改iptables的规则,以允许流量通过端口80

3 、连接到端口80上主机的IP地址

http://serverip:80

你应该在浏览器中看到以下内容:

未分类

总结

本文介绍了如何通过安全配置来生成一个相对安全的docker运行宿主机,除此之外,还需通过安装最新的安全补丁并保持系统更新,定期安全巡检等来保证docker运行环境的安全性。

使用Dockerfile创建带Apache服务的Centos Docker镜像

在宿主机上准备的文件清单:

Dockerfile
#启动ssh和apache服务的角本
run.sh

以上文件都放到/root/apache_centos目录下

mkdir -p /root/apache_centos
cd /root/apache_centos

基础镜像:以镜像centos为基础的开放SSH服务的镜像

[root@localhost apache_centos]# docker images
REPOSITORY      TAG          IMAGE ID         CREATED        VIRTUAL SIZE
sshd         dockerfile    411d5fb16366        23 hours ago        278 MB
centos            latest      0f73ae75014f        5 weeks ago         172.3 MB

一、准备run.sh文件

在/root/apache_centos目录新建run.sh

vim run.sh
#!/bin/bash
/usr/sbin/sshd &
/usr/local/apache2/bin/httpd -D FOREGROUND

二、准备Dockerfile

在/root/apache_centos目录新建Dockerfile

vim Dockerfile

文件内容如下:

#新生成的镜像是基于sshd:dockerfile镜像
FROM sshd:dockerfile
MAINTAINER by Steven
#安装wget
RUN yum install -y wget
WORKDIR /usr/local/src
#下载并解压源码包
RUN wget http://apache.fayea.com/httpd/httpd-2.4.17.tar.gz
RUN tar -zxvf httpd-2.4.17.tar.gz
WORKDIR httpd-2.4.17
#编译安装apache
RUN yum install -y gcc make apr-devel apr apr-util apr-util-devel pcre-devel
RUN ./configure --prefix=/usr/local/apache2  --enable-mods-shared=most  --enable-so
RUN make
RUN make install
#修改apache配置文件
RUN sed -i 's/#ServerName www.example.com:80/ServerName localhost:80/g' /usr/local/apache2/conf/httpd.conf
#启动apache服务
RUN /usr/local/apache2/bin/httpd
#复制服务启动脚本并设置权限
ADD run.sh /usr/local/sbin/run.sh
RUN chmod 755 /usr/local/sbin/run.sh
#开放80端口
EXPOSE 80
CMD ["/usr/local/sbin/run.sh"]

需要注意的是:在Dockerfile文件中更换当前目录不可以用“cd”命令,而要改用“WORKDIR”.

三、生成镜像

docker build -t apache_dockerfile:centos .

查看生成的镜像:

[root@localhost apache_centos]# docker images
REPOSITORY      TAG            IMAGE ID        CREATED          VIRTUAL SIZE
apache_dockerfile centos        f8f30b4a0ee8        24 minutes ago     440 MB
apache         centos        f92c55dddd07        17 hours ago       423.9 MB
sshd          dockerfile     411d5fb16366        23 hours ago       278 MB
centos         latest        0f73ae75014f        5 weeks ago       172.3 MB

四、根据镜像生成的容器并进行测试

1、生成新的容器

docker run -d -p 2222:22 -p 8000:80 apache_dockerfile:centos /usr/local/sbin/run.sh

将容器的22端口和80端口分别映射到到宿主机上的2222端口和8000端口,并运行服务脚本。

2、查看新生成的容器

[root@localhost apache_centos]# docker ps -a
CONTAINER ID IMAGE              COMMAND           CREATED      STATUS       PORTS                                        NAMES
ae560e497f39 apache_dockerfile:centos "/usr/local/sbin/run  45 seconds ago  Up 44 seconds   0.0.0.0:2222->22/tcp, 0.0.0.0:8000->80/tcp   condescending_bardeen
6490cd244c10 apache:centos        "/usr/local/apache2/  17 hours ago   Exited (0) 17 hours ago                            loving_wright
673e946b57e4 sshd:dockerfile      "/usr/local/sbin/run   18 hours ago   Exited (137)                                                    reverent_bell

3、测试

测试apache

[root@localhost apache_centos]# curl localhost:8000
<html><body><h1>It works!</h1></body></html>

成功!

测试ssh

[root@localhost apache_centos]# ssh localhost -p 2222
root@localhost's password:

成功!

利用Ansible部署运行Apache(http)的Docker容器

在自动化运维领域,除了saltstack,还有ansible这个批量安装部署工具,在写具体内容先,先谈谈我用过两个工具后的感想。

saltstack是C/S框架,要在客户端装软件,并且启动服务才能进行管理,ansible是通过ssh连接到客户端的,也就是说必须把密钥传给客户端才能进行管理,虽然可以关闭这个验证方式,但是生产环境中肯定是不能关闭的,从这一点看,还是ansible更容易配置,完全可以用脚本循环遍历所有主机来添加密钥。

使用方面,命令复杂程度相似,理解起来更容易的应该是saltstack,命令基本都是英语的组合,ansible则是依靠各种模式,参数来执行管理。

脚本编程方面,编程复杂度方面不尽相同,ansible提供群组的方式来对多主机提供管理,在推送操作到客户端时需给出明确的执行文件(yml),对于文件的存放位置没有明确的规定,saltstack需要在命令行提供主机信息,在推送时执行的是配置文件中提供的目录中的文件(sls),推送的文件也必须在这个目录中。

以上是我个人的一些见解,下面开始实战操作

环境介绍:

  • Centos 6.5
  • Ansible 2.3.0
  • Docker 1.7.1
  • Http 2.4.6-67

一、Docker操作

1. docker安装

这部分略过,如果你对docker安装和一些常用命令不了解,请参考《Docker常用命令和操作》

2. 拉取ansible镜像

docker pull ansible/centos7-ansible    #推荐使用这个镜像

拉取成功后可以在images里查看到这个镜像

未分类

3. 运行镜像,打开一个容器

docker run -it --name ansible 6883

4. 修改配置文件

vi /etc/ansible/hosts
[local]nlocalhostn  >>>>>  
[local]
localhost

这两个回车符在运行时是不能转义的,会报错

5. 提交修改后的容器

docker commit 1277 ansiblev2

6. 编写镜像构建方法

vim Dockerfile
FROM ansiblev2
MAINTAINER bin [email protected]


WORKDIR /opt/ansible    #定义工作区
RUN mkdir /opt/ansible/files    #创建必须目录
RUN mkdir /opt/ansible/template

ADD httpd.conf /opt/ansible/files    #把需要的文件复制到指定位置
ADD index.html.j2 /opt/ansible/template    
ADD web.yml /opt/ansible/

RUN ansible-playbook /opt/ansible/web.yml -c local  #运行ansible进行自动部署

VOLUME /var/www/html    #定义数据卷

CMD ["/usr/sbin/httpd","-X"]    #让httpd服务在前台运行
EXPOSE 80        #开放80端口,httpd.conf配置文件中必须也是80端口

二、Ansible操作

1. 编写服务部署方法

vim web.yml #ansible和saltstack在文字格式方面要求同样严格,如果报错,请查看格式是否正确!

- name: Configure webserver with http        #在运行时的提示信息
  hosts: local        #对本地主机组进行操作
  sudo: True        #运行时切换用户
  tasks:            #建立任务
    - name: install http
      yum: name=httpd update_cache=yes    #安装httpd,更新缓存
    - name: copy http config file
      copy: src=files/httpd.conf dest=/etc/httpd/conf    #文件复制

    - name: enable configuration
      file: >        #竖版写法,建立软连接
         dest=/etc/httpd/configure
         src=/etc/httpd/conf/
         state=link

    - name: copy index.html    #拷贝主页文件
      template: src=template/index.html.j2 dest=/var/www/html/index.html mode=0644

2. index.html.j2的内容

<html>
  <head>
    <title>Welcome to ansible!</title>
  </head>
  <body>
  <h1>http,configured by Ansible</h1>
  <p>If you can see this,Ansible successfully installed http.</p>
  <p>{{ ansible_env }}</p>    #会显示容器的环境变量
  #要想显示更多信息,可以通过ansible hostname -m setup来查看可以引用的变量
  <p>{{ ansible_env.PATH }}</p>    #显示环境变量中的PATH的值
  </body>
</html>

三、构建镜像,启动容器

1. 构建镜像

当前目录结构

未分类

docker build -t ansible/httpd .

2. 启动容器

docker run -d -p 8000:80 --name httpd ansible/httpd  #把容器的80端口映射到本地的8000端口

3. 查看容器运行情况

docker ps -a

未分类

4. 因为在构建镜像的时候指定了数据卷,可以在启动容器的时候挂载数据卷,方便代码修改

docker run -d -p 8001:80 -v /var/www/html:/var/www/html --name http2 ansible/httpd

四、测试主页

http://192.168.6.10:8000

未分类

出现如上显示为部署正常。

docker中Jenkins容器启动失败

今天在docker中启动jenkins容器时,按照官方文档中的方法执行:

docker run -p 8080:8080 -p 50000:50000 -v /your/home:/var/jenkins_home jenkins

遇到了一个权限为题,报错为:

Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?
touch: cannot touch ‘/var/jenkins_home/copy_reference_file.log’: Permission denied

原因是Jenkins镜像内部使用的用户是jenkons,但是我们启动容器时的账号是root,导致没有权限操作内部目录,我们可以稍微改一下上面的命令:

docker run -p 8080:8080 -p 50000:50000 -v /your/home:/var/jenkins_home -u 0 jenkins

这样就启动成功了。

这命令的意思是覆盖容器中内置的帐号,该用外部传入,这里传入0代表的是root帐号Id。这样再启动的时候就应该没问题了。

为Docker Swarm群集配置Nutanix持久存储为Docker Swarm群集配置Nutanix持久存储

本文介绍如何用Docker卷插件的方式,给Docker Swarm的群集挂载Nutanix存储。Nutanix Container Volume Plug-in 简称DVP,可以给容器提供数据持久化的功能。

本文使用ownCloud网盘应用做功能测试。测试的过程如下,安装部署Docker Datacenter,配置好群集,在UCP的界面里调用DVP插件建持久的数据卷,建立ownCloud服务,部署和测试该服务。

Nutanix DVP (Docker Volume Plug-in)安装和配置

这一部分描述DVP的安装部署过程,需要连接互联网;安装调试完毕之后,作虚拟机的镜像模板使用。这样Docker Swarm的其它节点也都不需要重复这个步骤了。

本文使用的是Docker社区文档稳定版 17.03.1-ce ;本文使用的OS是CentOS 7.3。所Docker安装的版本如下:

[root@centos7-temp]# docker version
Client:
 Version:      17.03.1-ce
 API version:  1.27
 Go version:   go1.7.5
 Git commit:   c6d412e
 Built:        Mon Mar 27 17:05:44 2017
 OS/Arch:      linux/amd64

Server:
 Version:      17.03.1-ce
 API version:  1.27 (minimum version 1.12)
 Go version:   go1.7.5
 Git commit:   c6d412e
 Built:        Mon Mar 27 17:05:44 2017
 OS/Arch:      linux/amd64
 Experimental: false

[root@centos7-temp]# rpm -qa|grep docker
docker-ce-17.03.1.ce-1.el7.centos.x86_64
docker-ce-selinux-17.03.1.ce-1.el7.centos.noarch

本文使用的Docker 安装yum源如下:

[root@centos7-temp]# cat /etc/yum.repos.d/docker-ce.repo
[docker-ce-stable]
name=Docker CE Stable - $basearch
baseurl=https://download.docker.com/linux/centos/7/$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg

[docker-ce-stable-debuginfo]
name=Docker CE Stable - Debuginfo $basearch
baseurl=https://download.docker.com/linux/centos/7/debug-$basearch/stable
enabled=0
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg

[docker-ce-stable-source]
name=Docker CE Stable - Sources
baseurl=https://download.docker.com/linux/centos/7/source/stable
enabled=0
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg

[docker-ce-edge]
name=Docker CE Edge - $basearch
baseurl=https://download.docker.com/linux/centos/7/$basearch/edge
enabled=0
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg

[docker-ce-edge-debuginfo]
name=Docker CE Edge - Debuginfo $basearch
baseurl=https://download.docker.com/linux/centos/7/debug-$basearch/edge
enabled=0
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg

[docker-ce-edge-source]
name=Docker CE Edge - Sources
baseurl=https://download.docker.com/linux/centos/7/source/edge
enabled=0
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg

[docker-ce-test]
name=Docker CE Test - $basearch
baseurl=https://download.docker.com/linux/centos/7/$basearch/test
enabled=0
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg

[docker-ce-test-debuginfo]
name=Docker CE Test - Debuginfo $basearch
baseurl=https://download.docker.com/linux/centos/7/debug-$basearch/test
enabled=0
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg

[docker-ce-test-source]
name=Docker CE Test - Sources
baseurl=https://download.docker.com/linux/centos/7/source/test
enabled=0
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg

本机所使用的所有安装源如下:

[root@centos7-temp]# yum repolist
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirrors.aliyun.com
 * epel: mirrors.aliyun.com
 * extras: mirrors.aliyun.com
 * updates: mirrors.aliyun.com
repo id                                   repo name                                                         status
base/7/x86_64                             CentOS-7 - Base - mirrors.aliyun.com                               9,363
docker-ce-stable/x86_64                   Docker CE Stable - x86_64                                              4
epel/x86_64                               Extra Packages for Enterprise Linux 7 - x86_64                    11,808
extras/7/x86_64                           CentOS-7 - Extras - mirrors.aliyun.com                               381
updates/7/x86_64                          CentOS-7 - Updates - mirrors.aliyun.com                            1,859
repolist: 23,415

安装docker引擎,并启动服务,并校验服务状态。安装过程参考如下:

[root@centos7-temp]# yum install -y docker-ce
[root@centos7-temp]# systemctl enable docker
[root@centos7-temp]# systemctl start docker
[root@centos7-temp]# systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2017-06-20 20:30:49 CST; 19min ago
     Docs: https://docs.docker.com
 Main PID: 875 (dockerd)
   CGroup: /system.slice/docker.service
           ├─ 875 /usr/bin/dockerd
           ├─ 942 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-in...
           ├─2008 docker-containerd-shim 0ca2346b6126de702fb4dda5f807c0a69a402eb643f15c142730277d0eb7bbcb /var/...
           └─0ca2346b6126de702fb4dda5f807c0a69a402eb643f15c142730277d0eb7bbcb
             └─2038 /usr/bin/python /code/main.py --prism-ip 10.68.69.22 --dataservices-ip 10.68.69.23 --prism-...

到目前为止,Docker安装配置完成。

下面开始安装DVP,安装和配置过程参考页面。

https://store.docker.com/plugins/nutanix-dvp-docker-volume-plug-in

下面是给操作系统安装iscsi initiator服务的参考步骤:

yum install -y iscsi-initiator-utils 
systemd-tmpfiles --create
systemctl start iscsid
systemctl enable iscsid
systemctl status iscsid
● iscsid.service - Open-iSCSI
   Loaded: loaded (/usr/lib/systemd/system/iscsid.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2017-06-20 20:30:46 CST; 24min ago
     Docs: man:iscsid(8)
           man:iscsiadm(8)
 Main PID: 888 (iscsid)
   CGroup: /system.slice/iscsid.service
           ├─882 /usr/sbin/iscsid
           └─888 /usr/sbin/iscsid

Jun 20 20:30:46 centos7-temp.zenlab.local systemd[1]: Starting Open-iSCSI...
Jun 20 20:30:46 centos7-temp.zenlab.local iscsid[878]: iSCSI logger with pid=882 started!
Jun 20 20:30:46 centos7-temp.zenlab.local systemd[1]: Failed to read PID from file /var/run/iscsid.pid: Inva...ent
Jun 20 20:30:46 centos7-temp.zenlab.local systemd[1]: Started Open-iSCSI.
Jun 20 20:30:47 centos7-temp.zenlab.local iscsid[882]: iSCSI daemon with pid=888 started!
Hint: Some lines were ellipsized, use -l to show in full.

解释一下DVP的工作原理是,它是让Docker主机通过iSCSI协议连接Nutanix的存储服务。DVP插件的配置里包含了连接存储服务和存储容器(这个容器是Nutanix的存储术语,非Docker说的容器)的相关信息。这样Docker主机上用该卷插件建立的数据卷都会指向Nutanix后台的存储容器中;数据通过iSCSI协议连接Nutanix存储服务的时候,就可以利用到Nutanix群集提供的负载均衡能力;当数据块写入Nutanix存储池的过程中和之后,就可以利用到到Nutanix存储容器所具备的其它重要特性:数据块2~3副本的高可靠性、冷热数据分成、压缩、去重、纠删码等;而且存储空间对于容器或者Docker Swarm里的服务都是透明和无限容量的。

现在做一些安装DVP的准备工作,询问Nutanix系统管理员下面信息:

  • 获得Prism 的IP
  • 获得Nutanix群集数据服务的IP,这个IP是群集上的虚拟服务IP
  • 获得群集的用户名和密码
  • 新建一个测试存储容器,获得容器名

参考下面的DVP安装命令:

docker plugin install ntnx/nutanix_volume_plugin PRISM_IP="10.68.69.22" DATASERVICES_IP="10.68.69.23" PRISM_PASSWORD="nutanix/4u" PRISM_USERNAME="admin" DEFAULT_CONTAINER="ddc-sc1" --alias nutanix

以上的命令执行结果如下:

[root@centos7-temp]# docker plugin install ntnx/nutanix_volume_plugin PRISM_IP="10.68.69.22" DATASERVICES_IP="10.68.69.23" PRISM_PASSWORD="nutanix/4u" PRISM_USERNAME="admin" DEFAULT_CONTAINER="ddc-sc1" --alias nutanix
Plugin "ntnx/nutanix_volume_plugin" is requesting the following privileges:
 - network: [host]
 - mount: [/dev]
 - mount: [/lib/modules]
 - mount: [/etc/iscsi]
 - mount: [/var/lock/iscsi]
 - mount: [/proc]
 - allow-all-devices: [true]
 - capabilities: [CAP_SYS_ADMIN CAP_SYS_PTRACE CAP_IPC_LOCK CAP_IPC_OWNER CAP_NET_ADMIN CAP_MKNOD CAP_SYS_MODULE]
Do you grant the above permissions? [y/N] y (输入y,按回车)
latest: Pulling from ntnx/nutanix_volume_plugin
be892c8cb64d: Download complete
Digest: sha256:5a3730ffae077eb6ddc0c125620283d56852528b686cbe42f2f58696eab82c0d
Status: Downloaded newer image for ntnx/nutanix_volume_plugin:latest
Installed plugin ntnx/nutanix_volume_plugin

确认VDP安装结果,这个插件应该是最新版、启动的状态,如下:

[root@centos7-temp]# docker plugin ls
ID                  NAME                DESCRIPTION                        ENABLED
f0e38fbc11b3        nutanix:latest      Nutanix volume plugin for docker   true

执行下面的测试,确认DVP工作正常。

[root@centos7-temp]# docker volume create testvol -d nutanix:latest
testvol
[root@centos7-temp]# docker volume ls
DRIVER              VOLUME NAME
nutanix:latest      testvol
[root@centos7-temp]#

回到Nutanix的Prisum界面(主要的群集管理图形化界面)中查看Storage –> table –> Volume Group,应该能看到这个命令所创建的名为testvol的数据卷。如下图所示:

未分类

在命令行删除这个测试的卷。

[root@centos7-temp]# docker volume rm testvol
testvol
[root@centos7-temp]# docker volume ls
DRIVER              VOLUME NAME
[root@centos7-temp]#

在回到Prisum界面中查看刚才看到的那个卷应该就消失了。到此为止所有节点的DVP部署配置工作就完毕了,并且确认docker服务和DVP功能都很正常。用 sys-unconfig 命令关机,把这个虚拟机在Prisum里面做一个快照备用,也可以在Nutanix的acli命令行里面把它做成一个基础镜像。

我们已经理解和熟悉了DVP的基本操作,配置和部署,下面开始安装Docker Datacenter;Docker Datacenter的架构图如下所示:

未分类

本文安装的架构是:

  • 一个 UCP manager 节点
  • 一个 DTR 节点
  • 两个 worker node 节点

在Nutanix的Prisum中用刚才制作的那个快照或者镜像模板,克隆/新建4个虚拟机。虚拟机的参考配置如下:

  • 2 vCPU
  • 4GB RAM
  • 50GB Disk

安装UCP(Docker Universal Control Plane)节点

在Nutanix的Prisum中从刚才新建的四个虚拟机中选择一个,Power on开机;ssh登录到操作系统内之后,设定主机名和IP地址。

安装配置参考文档:https://docs.docker.com/datacenter/ucp/2.1/guides/admin/install/install-offline/#download-the-offline-package

注意事项,提前下载好安装包,这个tar包里面包含了UCP需要的所有镜像,可以一次性导入到UCP的节点上。

wget https://packages.docker.com/caas/ucp_images_2.1.4.tar.gz -O docker-datacenter.tar.gz

docker load < docker-datacenter.tar.gz

载入完毕后,可以看到如下镜像。

[root@ucp-master ~]# docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
docker/ucp-metrics      2.1.4               e3e24ef156bd        3 weeks ago         92.2 MB
docker/ucp-swarm        2.1.4               d8b51d6801e5        3 weeks ago         21 MB
docker/ucp-hrm          2.1.4               38a19323327d        3 weeks ago         14.8 MB
docker/ucp-etcd         2.1.4               9aa382502e19        3 weeks ago         38.5 MB
docker/ucp-controller   2.1.4               5a852aa3039e        3 weeks ago         28 MB
docker/ucp-dsinfo       2.1.4               66ee9368796a        3 weeks ago         159 MB
docker/ucp              2.1.4               7a28dbfc44e4        3 weeks ago         19.1 MB
docker/ucp              latest              7a28dbfc44e4        3 weeks ago         19.1 MB
docker/ucp-cfssl        2.1.4               acdc1f147711        3 weeks ago         15.1 MB
docker/ucp-compose      2.1.4               25775e989077        3 weeks ago         32.9 MB
docker/ucp-auth-store   2.1.4               f27ad13dee6c        3 weeks ago         58.7 MB
docker/ucp-agent        2.1.4               d716a096c331        3 weeks ago         22.5 MB
docker/ucp-auth         2.1.4               1f4739cd3c08        3 weeks ago         25.1 MB
[root@ucp-master ~]#

安装UCP的命令参考如下:

docker run --rm -it --name ucp 
  -v /var/run/docker.sock:/var/run/docker.sock 
  docker/ucp:2.1.4 install 
  --host-address 10.68.69.12 
  --interactive

以上命令中10.68.69.12是UCP主机的ip地址,建议UCP使用固定IP。以上命令完毕后用浏览器访问这个IP。

参考以下文档,完成UCP的安装步骤,其中需要到Docker网站获得30天的试用版许可证文件。

https://docs.docker.com/datacenter/ucp/2.1/guides/admin/install/

能够正常登陆访问UCP之后,在首页下方点击 【Add Node】按钮,获得加其它节点到群集里的命令,参考命令如下:

docker swarm join 
  --token SWMTKN-1-1310ah7gzj9e7bk6a5yobo2qyiwf93ybrd29flkved1zqydd6i-7pir0884sag5pjofwzjq5o1um 
  10.68.69.12:2377

把以上命令记录在写字板中备用。

加3个节点到群集里

把剩下的三个虚拟机开机,进入操作系统后设定主机名和IP。其中的一个安装DTR(Docker镜像仓库)的节点建议使用固定IP。

在每个操作系统里面用docker命令确认DVP是否正常。

  • docker plugin ls
  • docker volume ls
  • systemctl status iscsid

下面就可以把上一步所记录命令在命令行里面执行以下,完毕之后回到UCP的界面中查看是否它们已经添加成功。如下图所示:

未分类

安装DTR-Docker镜像仓库

在UCP首页的下方,找到并点击 【Install DTR】的按钮,取得安装命令(记得从清单中选择固定IP地址的DTR主机);在登录DTR主机的控制台里面输入这个命令,命令如下:

docker run -it --rm 
  docker/dtr:2.2.5 install 
  --ucp-node 10.68.69.12 
  --ucp-insecure-tls

DTR节点没有离线安装的整合包,它需要联网下载很多相关镜像,如果网络速度不是很快的话,下载和安装的过程需要至少半个小时,过程中还需要输入UCP的管理员,用户名和密码。

参考文档如: https://docs.docker.com/datacenter/dtr/2.2/guides/admin/install/#step-3-install-dtr

DTR正常工作了以后,登录建立一个名为owncloud的镜像库,点击【New Rrepository】输入owncloud。 在一个节点上下载owncloud镜像,添加新的tag,上传到这个镜像到镜像库里备用。参考命令如下:

docker login dtr.zenlab.local
docker pull owncloud
docker tag owncloud:latest dtr.zenlab.local/admin/owncloud:latest
docker push dtr.zenlab.local/admin/owncloud:latest
Screen Shot 2017-06-20 at 10.10.13 P

未分类

注意:如果你的环境中没有DNS,就把dtr.zenlab.local换成DTR的IP地址。

以上这个步骤主要是方便以后,反复使用和测试这个镜像的可能性,如果所有的节点都有高速的互联网链接,可以忽略以上步骤。

Docker Swarm群集中使用DVP

这里使用UCP的图形化界面,在一个所有节点都配置和部署了VDP的群集上,给群集挂载外部Nutanix的数据卷。

登录UCP主页,点击Resource,点击Volumes,点击 【Create Volume】,输入相关参数,如下图所示。图中的sizeMb=500000这个参数是制定VolumeGroup的大小,不设定这个参数的话,默认是10GB。

未分类

在到Nutanix的Prism里面查看这个Volume Group是否存在。应该如下图所示:

未分类

部署OwnCloud网盘服务

登录UCP主页,点击 Service , 点击 【Create a Service】按钮;开始建立这个服务。输入服务名,镜像名;点击 【Next】按钮。

未分类

点击 【Next】按钮。进入 Resource页面,这里需要配置端口和数据卷。

未分类

未分类

最后点击【Deploy Now】按钮。 部署完毕之后,显示这个服务的状态为正常。

未分类

未分类

点击这个服务,到这个页面的最下方,找到右下角的发布端口的链接,点击后,就可以看到ownCloud的初始化配置页面了。

未分类

输入管理员的用户名和密码,进入之后,上传一些图片,测试一下功能是否正常。

未分类

尝试一些Docker Datacenter的高级功能,如服务的高可用性;同时Nutanix的DVP在底层保障了数据的持久性和完全性。测试步骤如下:

  • 找到运行owncloud的容器,删除这个容器
  • 在服务页面查看owncloud服务的状态变化
  • 等ownCloud的状态恢复正常之后
  • 再次登录ownCloud页面
  • 查看和确认刚才上传的文件是否还在

总结

Nutanix是一种融合和了计算、存储和虚拟化(内置KVM)的超融合平台。Nutanix DVP (Docker Volume Plug-in)可以让平台里的容器用上持久化存储服务。DVP不仅可以给单独虚拟机里的容器提供持久卷服务,还能给类似于Docker Swarm的其它容器编排平台提供持久化数据服务功能。我后续的文章还会分享路测试Kubernetes等其它平台。