GPT3-探索指南(八)

107 阅读26分钟

GPT3 探索指南(八)

原文:zh.annas-archive.org/md5/e19ec4b9c1d08c12abd2983dace7ff20

译者:飞龙

协议:CC BY-NC-SA 4.0

附录

1. 运行我的第一个 Docker 容器

活动 1.01:从 Docker Hub 拉取并运行 PostgreSQL 容器映像

解决方案

  1. 要启动 Postgres Docker 容器,首先确定需要设置数据库的默认用户名和密码凭据的环境变量。通过阅读官方 Docker Hub 页面,您可以看到POSTGRES_USERPOSTGRES_PASSWORD环境变量的配置选项。使用-e标志传递环境变量。启动我们的 Postgres Docker 容器的最终命令如下:
docker run -itd -e "POSTGRES_USER=panoramic" -e "POSTGRES_PASSWORD=trekking" postgres:12

运行此命令将启动容器。

  1. 执行docker ps命令以验证其正在运行并且健康:
$ docker ps

该命令应返回如下输出:

CONTAINER ID  IMAGE         COMMAND                 CREATED
  STATUS              PORTS               NAMES
29f115af8cdd  postgres:12   "docker-entrypoint.s…"  4 seconds ago
  Up 2 seconds        5432/tcp            blissful_kapitsa

从前面的输出可以看出,具有 ID29f115af8cdd的容器正在运行。

在这个活动中,您已成功启动了一个 PostgreSQL 版本 12 容器,该容器是 Panoramic Trekking App 的一部分,该应用程序将在本书的过程中构建。

活动 1.02:访问 Panoramic Trekking App 数据库

解决方案

  1. 使用docker exec登录到数据库实例,启动容器内的 PSQL shell,传递--username标志并将--password标志留空:
$ docker exec -it <containerID> psql --username panoramic --password

这应提示您输入密码并启动 PSQL shell。

  1. 使用\l命令列出所有数据库:
psql (12.2 (Debian 12.2-2.pgdg100+1))
Type "help" for help.
panoramic=# \l

将返回在容器中运行的数据库列表:

图 1.4:数据库列表

图 1.4:数据库列表

  1. 最后,使用\q快捷方式退出 shell。

  2. 使用docker stopdocker rm命令停止和清理容器实例。

在这个活动中,您通过使用在Activity 1.01中设置的凭据登录到容器中运行的数据库。您还列出了在容器中运行的数据库。该活动让您亲身体验了如何使用 PSQL shell 访问在任何容器中运行的数据库。

2. 使用 Dockerfiles 入门

活动 2.01:在 Docker 容器上运行 PHP 应用程序

解决方案

  1. 为此活动创建一个名为activity-02-01的新目录:
mkdir activity-02-01
  1. 导航到新创建的activity-02-01目录:
cd activity-02-01
  1. activity-02-01目录中,创建一个名为welcome.php的文件:
touch welcome.php 
  1. 现在,使用您喜欢的文本编辑器打开welcome.php
vim welcome.php 
  1. 创建 welcome.php 文件,并使用活动开始时提供的内容,然后保存并退出 welcome.php 文件:
<?php
$hourOfDay = date('H');
if($hourOfDay < 12) {
    $message = «Good Morning»;
} elseif($hourOfDay > 11 && $hourOfDay < 18) {
    $message = «Good Afternoon»;
} elseif($hourOfDay > 17){
    $message = «Good Evening»;
}
echo $message;
?>
  1. activity-02-01 目录中,创建一个名为 Dockerfile 的文件:
touch Dockerfile
  1. 现在,使用您喜爱的文本编辑器打开 Dockerfile
vim Dockerfile
  1. 将以下内容添加到 Dockerfile 中,然后保存并退出 Dockerfile
# Start with Ubuntu base image
FROM ubuntu:18.04
# Set labels
LABEL maintainer=sathsara
LABEL version=1.0 
# Set environment variables
ENV DEBIAN_FRONTEND=noninteractive
# Install Apache, PHP, and other packages
RUN apt-get update && \
    apt-get -y install apache2 \
    php \ 
    curl
# Copy all php files to the Docker image
COPY *.php /var/www/html
# Set working directory
WORKDIR /var/www/html
# Create health check
HEALTHCHECK --interval=5s --timeout=3s --retries=3 CMD curl -f   http://localhost || exit 1
# Expose Apache
EXPOSE 80
# Start Apache
ENTRYPOINT ["apache2ctl", "-D", "FOREGROUND"]

我们将使用 ubuntu 基础镜像开始这个 Dockerfile,然后设置一些标签。接下来,将 DEBIAN_FRONTEND 环境变量设置为 noninteractive,以使包安装变为非交互式。然后安装 apache2phpcurl 包,并将 PHP 文件复制到 /var/www/html 目录。接下来,配置健康检查并暴露端口 80。最后,使用 apache2ctl 命令启动 Apache web 服务器。

  1. 现在,构建 Docker 镜像:
$ docker image build -t activity-02-01 .

运行 build 命令后,您应该会得到以下输出:

图 2.22:构建活动-02-01 Docker 镜像

图 2.22:构建活动-02-01 Docker 镜像

  1. 执行 docker container run 命令以从您在上一步中构建的 Docker 镜像启动新容器:
$ docker container run -p 80:80 --name activity-02-01-container -d activity-02-01

由于您是以分离模式(使用 -d 标志)启动 Docker 容器,上述命令将输出生成的 Docker 容器的 ID。

  1. 现在,您应该能够查看 Apache 主页。在您喜爱的网络浏览器中转到 http://127.0.0.1/welcome.php 终端节点:图 2.23:PHP 应用程序页面

图 2.23:PHP 应用程序页面

请注意,默认的 Apache 主页是可见的。在前面的输出中,您收到了 Good Morning 的输出。此输出可能会有所不同,根据您运行此容器的时间,可能会显示为 Good AfternoonGood Evening

  1. 现在,清理容器。首先,使用 docker container stop 命令停止 Docker 容器:
$ docker container stop activity-02-01-container
  1. 最后,使用 docker container rm 命令移除 Docker 容器:
$ docker container rm activity-02-01-container

在这个活动中,我们学习了如何使用本章中迄今为止学到的 Dockerfile 指令来将示例 PHP 应用程序 docker 化。我们使用了多个 Dockerfile 指令,包括 FROMLABELENVRUNCOPYWORKDIRHEALTHCHECKEXPOSEENTRYPOINT

3. 管理您的 Docker 镜像

活动 3.01:使用 Git 哈希版本控制构建脚本

解决方案

有多种方法可以完成这个活动。以下是一个例子:

  1. 创建一个新的构建脚本。第一行显示设置–ex命令,将每个步骤打印到屏幕上,并且如果任何步骤失败,脚本将失败。第 3 行第 4 行设置了你的注册表和服务名称的变量:
1 set -ex
2
3 REGISTRY=dev.docker.local:5000SERVICENAME=postgresql
  1. 第 6 行,将GIT_VERSION变量设置为指向你的短 Git 提交哈希。构建脚本然后在第 7 行将这个值打印到屏幕上:
6 GIT_VERSION=`git log -1 --format=%h`
7 echo "version: $GIT_VERSION "
  1. 第 9 行使用docker build命令创建你的新镜像,并在第 11 行添加docker push命令将镜像推送到你的本地 Docker 注册表:
9 docker build -t $REGISTRY/$SERVICENAME:$GIT_VERSION .
10
11 docker push $REGISTRY/$SERVICENAME:$GIT_VERSION

脚本文件将如下所示:

set -ex
2
3 REGISTRY=dev.docker.local:5000
4 SERVICENAME= postgresql
5
6 GIT_VERSION=`git log -1 --format=%h`
7 echo "version: $GIT_VERSION "
8
9 docker build -t $REGISTRY/$SERVICENAME:$GIT_VERSION .
10
11 docker push $REGISTRY/$SERVICENAME:$GIT_VERSION
  1. 运行以下命令来确保脚本已构建并成功运行:
./build.sh

你应该会得到以下输出:

./BuildScript.sh 
++ REGISTRY=dev.docker.local:5000
++ SERVICENAME=basic-app
+++ git log -1 --format=%h
++ GIT_VERSION=49d3a10
++ echo 'version: 49d3a10 '
version: 49d3a10 
++ docker build -t dev.docker.local:5000/basic-app:49d3a10 .
Sending build context to Docker daemon  3.072kB
Step 1/1 : FROM postgres
 ---> 873ed24f782e
Successfully built 873ed24f782e
Successfully tagged dev.docker.local:5000/basic-app:49d3a10
++ docker push dev.docker.local:5000/basic-app:49d3a10
The push refers to repository [dev.docker.local:5000/basic-app]

活动 3.02:配置本地 Docker 注册表存储

解决方案

以下步骤描述了实现活动目标的一种方式:

  1. 在你的主目录中创建test_registry目录:
mkdir /home/vincesesto/test_registry/
  1. 运行本地注册表,但在这种情况下,包括-v选项,将你在前一步创建的目录连接到/var/lib/registry容器目录。还要使用:rw选项确保你可以读写该目录:
docker run -d -p 5000:5000 --restart=always --name registry -v /home/vincesesto/test_registry/registry:/var/lib/registry:rw registry
  1. 现在,像往常一样将镜像推送到新挂载的注册表中:
docker push dev.docker.local:5000/basic-app:ver1
  1. 为了验证镜像现在是否存储在你新挂载的目录中,列出registry/docker/registry/v2/repositories/目录中的文件。
ls  ~/test_registry/registry/docker/registry/v2/repositories/

你应该会看到你刚刚在上一步推送的新镜像:

basic-app

这个活动让我们开始使用一些更高级的 Docker 选项。别担心,将会有更多章节专门帮助你理解在运行容器时的卷挂载和存储。

4. 多阶段 Docker 文件

活动 4.01:使用多阶段 Docker 构建部署 Golang HTTP 服务器

解决方案:

  1. 为这个活动创建一个名为activity-04-01的新目录:
mkdir activity-04-01
  1. 导航到新创建的activity-04-01目录:
cd activity-04-01
  1. activity-04-01目录中,创建一个名为main.go的文件:
$ touch main.go
  1. 现在,使用你喜欢的文本编辑器打开main.go文件:
$ vim main.go
  1. 将以下内容添加到main.go文件中,然后保存并退出该文件:
package main
import (
    "net/http"
    "fmt"
    "log"
    "os"
)
func main() {
    http.HandleFunc("/", defaultHandler)
    http.HandleFunc("/contact", contactHandler)
    http.HandleFunc("/login", loginHandler)
    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
    }

    log.Println("Service started on port " + port)
    err := http.ListenAndServe(":"+port, nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
        return
    }
}
func defaultHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "<h1>Home Page</h1>")
}
func contactHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "<h1>Contact Us</h1>")
}
func loginHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "<h1>Login Page</h1>")
}
  1. activity-04-01目录中,创建一个名为Dockerfile的文件。这个文件将是多阶段Dockerfile
touch Dockerfile
  1. 现在,使用你喜欢的文本编辑器打开Dockerfile
vim Dockerfile
  1. 将以下内容添加到Dockerfile并保存文件:
FROM golang:1.14.2-alpine AS builder
WORKDIR /myapp
COPY main.go .
RUN go build -o main .
FROM alpine:latest AS runtime
WORKDIR /myapp
COPY --from=builder /myapp/main .
ENTRYPOINT ["./main"]
EXPOSE 8080

这个Dockerfile有两个阶段,名为builderruntime。构建阶段使用 Golang Docker 镜像作为父镜像,负责从 Golang 源文件创建可执行文件。运行时阶段使用alpine Docker 镜像作为父镜像,并执行从builder阶段复制的可执行文件。

  1. 现在,使用docker build命令构建 Docker 镜像:
docker build -t activity-04-01:v1 .

您应该会得到以下输出:

图 4.14:构建 Docker 镜像

图 4.14:构建 Docker 镜像

  1. 使用docker image ls 命令列出计算机上所有可用的 Docker 镜像。验证镜像的大小:
docker images

该命令将返回所有可用的 Docker 镜像列表:

图 4.15:列出所有 Docker 镜像

图 4.15:列出所有 Docker 镜像

在前面的输出中,您可以看到名为activity-04-01的优化 Docker 镜像的大小为 13.1 MB,而在构建阶段使用的父镜像(Golang 镜像)的大小为 370 MB。

  1. 执行docker container run命令,从您在上一步中构建的 Docker 镜像启动一个新的容器:
$ docker container run -p 8080:8080 --name activity-04-01-container activity-04-01:v1

您应该会得到类似以下的输出:

2020/08/30 05:14:10 Service started on port 8080
  1. 在您喜欢的网络浏览器中查看以下 URL 的应用程序:
http://127.0.0.1:8080/

当我们导航到 URL http://127.0.0.1:8080/时,以下图片显示了主页:

图 4.16:Golang 应用程序-主页

图 4.16:Golang 应用程序-主页

  1. 现在,在您喜欢的网络浏览器中浏览以下 URL:
http://127.0.0.1:8080/contact

当我们导航到 URL http://127.0.0.1:8080/contact时,以下图片显示了联系页面:

图 4.17:Golang 应用程序-联系我们页面

图 4.17:Golang 应用程序-联系我们页面

  1. 现在,在您喜欢的网络浏览器中输入以下 URL:
http://127.0.0.1:8080/login 

当我们导航到 URL http://127.0.0.1:8080/login时,以下图片显示了登录页面:

图 4.18:Golang 应用程序-登录页面

图 4.18:Golang 应用程序-登录页面

在这个活动中,我们学习了如何部署一个 Golang HTTP 服务器,它可以根据调用 URL 返回不同的响应。在这个活动中,我们使用了多阶段的 Docker 构建来创建一个最小尺寸的 Docker 镜像。

5. 使用 Docker Compose 组合环境

活动 5.01:使用 Docker Compose 安装 WordPress

解决方案

可以通过以下步骤创建数据库并安装 WordPress:

  1. 创建所需的目录并使用cd命令进入其中:
mkdir wordpress
cd wordpress
  1. 创建一个名为docker-compose.yaml的文件,内容如下:
version: "3"
services:
  database:
    image: mysql:5.7
    volumes:
      - data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: db
      MYSQL_USER: user
      MYSQL_PASSWORD: password
  wordpress:
    depends_on:
      - database
    image: wordpress:latest
    ports:
      - "8080:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: database:3306
      WORDPRESS_DB_USER: user
      WORDPRESS_DB_PASSWORD: password
      WORDPRESS_DB_NAME: db
volumes:
     data: {} 
  1. 使用docker-compose up --detach命令启动应用程序:图 5.22:应用程序的启动

图 5.22:应用程序的启动

  1. 使用docker-compose ps命令检查正在运行的容器。您应该会得到以下输出:图 5.23:WordPress 和数据库容器

图 5.23:WordPress 和数据库容器

  1. 在浏览器中打开http://localhost:8080以检查 WordPress 设置屏幕:图 5.24:WordPress 设置屏幕

图 5.24:WordPress 设置屏幕

在这个活动中,您使用 Docker Compose 创建了一个真实应用程序的部署。该应用程序包括一个数据库容器和一个 WordPress 容器。这两个容器服务都使用环境变量进行配置,通过 Docker Compose 网络和卷进行连接。

活动 5.02:使用 Docker Compose 安装全景徒步应用程序

解决方案

可以通过以下步骤创建数据库和全景徒步应用程序:

  1. 创建所需的目录并切换到其中:
mkdir pta-compose
cd pta-compose
  1. 创建一个名为docker-compose.yaml的文件,内容如下:
version: "3"
services:
  db:
    image: postgres
    volumes:
      - db_data:/var/lib/postgresql/data/
    environment:
      - POSTGRES_PASSWORD=docker
  web:
    image: packtworkshops/the-docker-workshop:chapter5-pta-web
    volumes:
      - static_data:/service/static
    depends_on:
      - db
  nginx:
    image: packtworkshops/the-docker-workshop:chapter5-pta-nginx
    volumes:
      - static_data:/service/static
    ports:
      - 8000:80
    depends_on:
      - web
volumes:
  db_data:
  static_data:
  1. 使用docker-compose up --detach命令启动应用程序。您应该会得到类似以下的输出:图 5.25:应用程序的启动

图 5.25:应用程序的启动

注意

您也可以使用docker-compose up -d命令来启动应用程序。

  1. 使用docker-compose ps命令检查正在运行的容器。您应该会得到类似以下的输出:图 5.26 应用程序、数据库和 nginx 容器

图 5.26 应用程序、数据库和 nginx 容器

  1. 使用地址http://0.0.0.0:8000/admin在浏览器中打开全景徒步应用程序的管理部分:图 5.27:管理员设置登录

图 5.27:管理员设置登录

注意

您也可以运行firefox http://0.0.0.0:8000/admin命令来打开全景徒步应用程序的管理部分。

使用用户名admin和密码changeme登录,并添加新的照片和国家。将出现以下屏幕:

图 5.28:管理员设置视图

图 5.28:管理员设置视图

  1. 在浏览器中打开全景徒步应用程序,地址为http://0.0.0.0:8000/photo_viewer图 5.29:应用程序视图

图 5.29:应用程序视图

在此活动中,您使用 Docker Compose 创建了一个三层应用程序,其中包括用于 PostgreSQL 数据库、后端和代理服务的层。所有服务都使用 Docker Compose 进行配置和连接,具有其网络和存储功能。

6. Docker 网络简介

活动 6.01:利用 Docker 网络驱动程序

解决方案

以下是根据最佳实践完成此活动的最常见方法:

  1. 使用docker network create命令为 NGINX Web 服务器创建一个网络。将其命名为webservernet,并为其分配子网192.168.1.0/24和网关192.168.1.1
$ docker network create webservernet --subnet=192.168.1.0/24 --gateway=192.168.1.1

这应该创建bridge网络webservernet

  1. 使用docker run命令创建一个 NGINX Web 服务器。使用-p标志将主机上的端口8080转发到容器实例上的端口80
$ docker run -itd -p 8080:80 --name webserver1 --network webservernet nginx:latest

这将在webservernet网络中启动webserver1容器。

  1. 使用docker run命令以host网络模式启动名为monitor的 Alpine Linux 容器。这样,您将知道容器可以访问主系统的主机端口以及bridge网络的 IP 地址:
$ docker run -itd --name monitor --network host alpine:latest

这将在host网络模式下启动一个 Alpine Linux 容器实例。

  1. 使用docker inspect查找webserver1容器的 IP 地址:
$ docker inspect webserver1

容器的详细信息将以 JSON 格式显示;从IPAddress参数中获取 IP 地址:

图 6.27:检查 webserver1 容器实例

图 6.27:检查 webserver1 容器实例

  1. 使用docker exec命令在监控容器内部启动sh shell:
$ docker exec -it monitor /bin/sh

这应该将您放入根 shell。

  1. 使用apk install命令在此容器内安装curl命令:
/ # apk add curl

这应该安装curl实用程序:

fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/main
/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/community
/x86_64/APKINDEX.tar.gz
(1/4) Installing ca-certificates (20191127-r1)
(2/4) Installing nghttp2-libs (1.40.0-r0)
(3/4) Installing libcurl (7.67.0-r0)
(4/4) Installing curl (7.67.0-r0)
Executing busybox-1.31.1-r9.trigger
Executing ca-certificates-20191127-r1.trigger
OK: 7 MiB in 18 packages
  1. 使用curl命令验证主机级别的连接是否正常工作,调用主机机器上的端口8080
/ # curl -v http://localhost:8080

您应该收到来自 NGINX 的200 OK响应,表示在主机级别成功连接:

图 6.28:从主机上的暴露端口访问 webserver1 容器

图 6.28:从主机上的暴露端口访问 webserver1 容器

  1. 同样,使用curl命令直接通过端口80访问 Dockerbridge网络中容器的 IP 地址:
/ # curl -v 192.168.1.2:80

您应该同样收到另一个200 OK响应,表明连接成功:

图 6.29:从 IP 访问 NGINX Web 服务器容器实例的地址

图 6.29:从容器实例的 IP 地址访问 NGINX Web 服务器

在这个活动中,我们能够说明使用不同的 Docker 网络驱动程序在容器之间建立连接。这种情况适用于真实的生产基础设施,因为在部署容器化解决方案时,工程师们将努力部署尽可能不可变的基础设施。通过在 Docker 中部署容器,确切地模拟主机级别的网络,可以设计出需要在主机操作系统上进行非常少量配置的基础设施。这使得在部署和扩展 Docker 部署的主机时非常容易。诸如curl和其他监控工具的软件包可以部署到在 Docker 主机上运行的容器中,而不是安装在主机上。这保证了部署和维护的便利性,同时提高了满足不断增长的需求所需的主机部署速度。

活动 6.02:叠加网络实践

解决方案

  1. 在 Docker swarm 集群中的Machine1上使用docker network create命令创建一个名为panoramic-net的 Dockeroverlay网络,通过传递自定义的subnetgatewayoverlay网络驱动程序:
$ docker network create panoramic-net --subnet=10.2.0.0/16 --gateway=10.2.0.1 --driver overlay
  1. Machine1上使用docker service create命令创建一个名为trekking-app的服务,加入panoramic-net网络:
$ docker service create -t --name trekking-app --replicas=1 --network panoramic-net alpine:latest

这将在panoramic-net overlay网络中启动一个名为trekking-app的服务。

  1. Machine1上使用docker service create命令创建一个名为database-app的服务,加入panoramic-net网络。设置默认凭据并指定postgres:12版本的 Docker 镜像:
$ docker service create -t --name database-app --replicas=1 --network panoramic-net -e "POSTGRES_USER=panoramic" -e "POSTGRES_PASSWORD=trekking" postgres:12
  1. 使用docker exec访问trekking-app服务容器内的sh shell:
$ docker exec -it trekking-app.1.qhpwxol00geedkfa9p6qswmyv /bin/sh

这应该将您放入trekking-app容器实例内的根 shell 中。

  1. 使用ping命令验证对database-app服务的网络连接:
/ # ping database-app

ICMP 回复应指示连接成功:

PING database-app (10.2.0.5): 56 data bytes
64 bytes from 10.2.0.5: seq=0 ttl=64 time=0.261 ms
64 bytes from 10.2.0.5: seq=1 ttl=64 time=0.352 ms
64 bytes from 10.2.0.5: seq=2 ttl=64 time=0.198 ms

在这个活动中,我们利用了 Docker 集群中的自定义 Dockeroverlay网络,以说明两个 Docker 集群服务之间的连接性,使用 Docker DNS。在真实的多层应用程序中,许多微服务可以部署在使用overlay网络网格直接相互通信的大型 Docker 集群中。了解overlay网络如何与 Docker DNS 协同工作对于实现容器化基础设施的高效可扩展性至关重要。

7. Docker 存储

活动 7.01:将容器事件(状态)数据存储在 PostgreSQL 数据库中

解决方案

  1. 运行以下命令以删除主机中的所有对象:
$ docker container rm -fv $(docker container ls -aq)

$docker image rm $(docker image ls -q)
  1. 获取卷名称,然后使用以下命令删除所有卷:
$docker volume ls
$docker volume rm <volume names separated by spaces>
  1. 获取网络名称,然后使用以下命令删除所有网络:
$docker network ls
$docker network rm <network names separated by spaces>
  1. 打开两个终端,一个专门用于查看docker events --format '{{json .}}'的效果。另一个应该打开以执行先前提到的高级步骤。

  2. 在第一个终端中,运行以下命令:

docker events --format '{{json .}}'.

您应该得到以下输出:

图 7.11:docker events 命令的输出

图 7.11:docker events 命令的输出

  1. 运行以下命令在第二个终端中启动ubuntu容器:
$docker run -d ubuntu:14.04

您应该得到以下输出:

图 7.12:docker run 命令的输出

图 7.12:docker run 命令的输出

  1. 使用第二个终端中的以下命令创建名为vol1的卷:
$docker volume create vol1
  1. 使用第二个终端中的以下命令创建名为net1的网络:
$docker network create net1
  1. 使用以下命令删除容器:
$docker container rm -fv <container ID>
  1. 使用以下命令删除卷和网络:
$docker volume rm vol1
$docker network rm net1
  1. docker events终端中单击Ctrl + C以终止它。

  2. 检查以下两个示例以了解 JSON 输出:

示例 1

{"status":"create","id":"43903b966123a7c491b50116b40827daa03
da5d350f8fef2a690fc4024547ce2","from":"ubuntu:14.04","Type":
"container","Action":"create","Actor":{"ID":"43903b966123a7c
491b50116b40827daa03da5d350f8fef2a690fc4024547ce2","Attributes":
{"image":"ubuntu:14.04","name":"upbeat_johnson"}},"scope":"local",
"time":1592516703,"timeNano":1592516703507582404}

示例 2

{"Type":"network","Action":"connect","Actor":{"ID":"52855e1561
8e37b7ecc0bb26bc42847af07cae65ddd3b68a029e40006364a9bd",
"Attributes":{"container":"43903b966123a7c491b50116b40827daa03d
a5d350f8fef2a690fc4024547ce2","name":"bridge","type":"bridge"}},
"scope":"local","time":1592516703,"timeNano":1592516703911851347}

您会发现根据对象的不同属性和结构而有所不同。

  1. 运行带有卷的 PostgreSQL 容器。将容器命名为db1
$docker container run --name db1 -v db:/var/lib/postgresql/data -e POSTGRES_PASSWORD=password -d postgres
  1. 运行exec命令,以便 bash 被要执行的命令替换。shell 将更改为posgres=#,表示您在容器内部:
$ docker container exec -it db1 psql -U postgres
  1. 创建一个具有两列的表:IDserial类型,infojson类型:
CREATE TABLE events (ID serial NOT NULL PRIMARY KEY, info json NOT NULL);
  1. 将第一个示例的JSON输出的第一行插入表中:
INSERT INTO events (info) VALUES ('{"status":"create","id":"43903b966123a7c491b50116b40827daa03da 5d350f8fef2a690fc4024547ce2","from":"ubuntu:14.04","Type":"container","Action":"create","Actor":{"ID":"43903b966123a7c49 1b50116b40827daa03da5d350f8fef2a690fc4024547ce2","Attributes":{"image":"ubuntu:14.04","name":"upbeat_johnson"}},"scope":"local","time":1592516703,"timeNano":1592516703507582404}');
  1. 通过输入以下 SQL 语句验证数据库中是否保存了行:
select * from events;

您应该得到以下输出:

图 7.13:验证数据库中是否保存了行

图 7.13:验证数据库中是否保存了行

  1. 使用 SQL 的insert命令将 Docker 事件插入events表中。

注意

请参考packt.live/2ZKfGgB上的events.txt文件,使用insert命令插入 Docker 事件。

您应该得到以下输出:

图 7.14:在数据库中插入多行

图 7.14:在数据库中插入多行

从这个输出中,可以清楚地看到已成功将 11 个事件插入到 PostgreSQL 数据库中。

  1. 依次运行以下三个查询。

查询 1

SELECT * FROM events WHERE info ->> 'status' = 'pull';

输出将如下所示:

图 7.15:查询 1 的输出

图 7.15:查询 1 的输出

查询 2

SELECT * FROM events WHERE info ->> 'status' = 'destroy';

输出将如下所示:

图 7.16:查询 2 的输出

图 7.16:查询 2 的输出

查询 3

SELECT info ->> 'id' as id FROM events WHERE info ->> 'status'=     'destroy';

输出将如下所示:

图 7.17:查询 3 的输出

图 7.17:查询 3 的输出

在这个活动中,您学习了如何记录和监视容器,并使用 SQL 语句查询容器的事件,以及如何获得事件的 JSON 输出并保存在 PostgreSQL 数据库中。您还学习了 JSON 输出结构以及如何查询它。

活动 7.02:与主机共享 NGINX 日志文件

解决方案

  1. 通过运行以下命令验证您的主机上是否没有/var/mylogs文件夹:
$cd /var/mylogs

您应该得到以下输出:

Bash: cd: /var/mylogs: No such file or directory
  1. 基于 NGINX 镜像运行一个容器。在run命令中指定主机和容器内共享卷的路径。在容器内,NGINX 使用/var/log/nginx路径存储日志文件。在主机上指定路径为/var/mylogs
$docker container run -d -v /var/mylogs:/var/log/nginx nginx

如果您本地没有该镜像,Docker 引擎将自动拉取该镜像:

图 7.18:运行 docker run 命令的输出

图 7.18:运行 docker run 命令的输出

  1. 进入/var/mylogs路径。列出该目录中的所有文件:
$cd /var/mylogs

$ls

您应该在那里找到两个文件:

access.log         error.log
  1. (可选)如果没有生成错误,这两个文件将是空的。你可以使用cat Linux 命令或者使用tail Linux 命令来检查内容。因为我们之前使用了cat命令,所以让我们在这个例子中使用tail命令:
$tail -f *.log

你应该得到以下的输出:

==>  access.log  <==
==>  error.log   <==

由于这个 NGINX 服务器没有生成任何错误或者没有被访问,这些文件目前是空的。然而,如果 NGINX 在任何时刻崩溃,生成的错误将会保存在error.log中。

在这个活动中,你学会了如何将容器的日志文件共享到主机上。你使用了 NGINX 服务器,所以如果它崩溃了,你可以从它的日志文件中追溯发生了什么。

8. 服务发现

活动 8.01:利用 Jenkins 和 SonarQube

解决方案

  1. 安装 SonarQube 并使用以下命令作为容器运行:
docker run -d --name sonarqube -p 9000:9000 -p 9092:9092 sonarqube

你应该得到容器 ID 作为输出:

4346a99b506b1bec8000e429471dabac57e3f565b154ee921284ec685497bfae
  1. 使用admin/admin凭据登录到 SonarQube:图 8.38:登录到 SonarQube

图 8.38:登录到 SonarQube

成功登录后,应该出现类似以下的屏幕:

图 8.39:SonarQube 仪表板

图 8.39:SonarQube 仪表板

  1. 在右上角,点击用户。会出现一个下拉菜单。点击我的账户

  2. 向下滚动并点击安全下的生成来生成一个令牌。你现在必须复制它,因为以后将无法访问它:图 8.40:生成令牌

图 8.40:生成令牌

  1. 在 Jenkins 中,点击管理 Jenkins > 插件管理器。在可用列表中搜索Sonar。安装SonarQube Scanner插件。图 8.41:安装 SonarQube Scanner 插件

图 8.41:安装 SonarQube Scanner 插件

  1. 通过点击hit_count项目,然后点击配置选项来验证安装是否正确。在构建选项卡上点击添加构建步骤,然后点击执行 SonarQube Scanner,就像图 8.43中那样:图 8.42:选择执行 SonarQube Scanner

图 8.42:选择执行 SonarQube Scanner

  1. 然而,新的框将会生成错误,就像下面截图中显示的那样。为了纠正这个问题,通过系统配置全局工具配置选项将 SonarQube 和 Jenkins 集成起来:图 8.43:由于 SonarQube 尚未配置而生成的错误

图 8.43:由于 SonarQube 尚未配置而生成的错误

  1. 在 Jenkins 中,点击“管理 Jenkins”。点击“全局工具配置”选项,然后点击“添加 SonarQube 扫描仪”:图 8.44:在全局工具配置页面上添加 SonarQube 扫描仪

图 8.44:在全局工具配置页面上添加 SonarQube 扫描仪

  1. 输入名称“SonarQube 扫描仪”。勾选“自动安装”。在“从 Maven 中央安装”下,在“版本”中选择SonarQube Scanner 3.2.0.1227。点击“添加安装程序”。在“标签”字段中,输入SonarQube。在“二进制存档的下载 URL”字段中,输入链接https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-3.2.0.1227-linux.zip

点击“保存”。

图 8.45:为 SonarQube 扫描仪添加详细信息

图 8.45:为 SonarQube 扫描仪添加详细信息

您现在已完成“全局工具配置”选项,现在是时候转到“配置系统”选项了。

  1. 在“管理 Jenkins”中,点击“配置系统”:图 8.46:在管理 Jenkins 页面上点击配置系统

图 8.46:在管理 Jenkins 页面上点击配置系统

  1. 您现在无法进入系统配置,因为它要求“服务器身份验证令牌”。当您点击“添加”按钮时,它将不起作用。在以下步骤中将令牌输入为秘密文本,然后返回到“管理 Jenkins”:图 8.47:在 Jenkins 配置中插入 SonarQube 令牌

图 8.47:在 Jenkins 配置中插入 SonarQube 令牌

  1. 点击“管理凭据”:图 8.48:管理 Jenkins 页面

图 8.48:管理 Jenkins 页面

  1. 点击Jenkins图 8.49:Jenkins 凭据页面

图 8.49:Jenkins 凭据页面

  1. 点击“全局凭据(不受限制)”:图 8.50:全局凭据(不受限制)域

图 8.50:全局凭据(不受限制)域

  1. 点击“添加一些凭据”:图 8.51:添加一些凭据

图 8.51:添加一些凭据

  1. 在“类型”下拉菜单中,点击“秘密文本”:图 8.52:选择类型为秘密文本

图 8.52:选择类型为秘密文本

  1. 在“秘密”文本框中,粘贴您在本活动的步骤 5中复制的令牌。在ID字段中,输入SonarQubeToken。点击“确定”:图 8.53:将令牌添加到秘密文本框

图 8.53:将令牌添加到秘密文本框

SonarQubeToken将保存在“全局凭据”选项中。您将看到类似以下内容的屏幕:

图 8.54:SonarQubeToken 保存在全局凭据中

图 8.54:SonarQubeToken 保存在全局凭据中

  1. 返回到“管理 Jenkins”。点击“配置系统”,然后点击“刷新”。现在,在“服务器身份验证令牌”下拉菜单中,您将找到SonarQubeToken。勾选“启用将 SonarQube 服务器配置注入构建环境变量”。在“名称”字段中输入SonarQube。在“服务器 URL”字段中输入“http://<您的 IP>:9000”。然后点击“保存”:

您可以运行ifconfig命令来获取您的 IP。您将在输出的en0部分找到 IP:

$ ifconfig

这是将 Jenkins 与 SonarQube 集成的最后一步。让我们返回到项目中。

  1. 在“构建环境”中,勾选“准备 SonarQube 扫描器环境”。将“服务器身份验证令牌”设置为SonarQubeToken

  2. 现在,点击项目名称,然后点击“配置”。在“构建”步骤中,在“分析属性”字段中输入以下代码:

sonar.projectKey=hit_count
sonar.projectName=hit_count
sonar.projectVersion=1.0
sonar.sources=.
sonar.language=py
sonar.sourceEncoding=UTF-8
# Test Results
sonar.python.xunit.reportPath=nosetests.xml
# Coverage
sonar.python.coverage.reportPath=coverage.xml
# Linter (https://docs.sonarqube.org/display/PLUG/Pylint+Report)
#sonar.python.pylint=/usr/local/bin/pylint
#sonar.python.pylint_config=.pylintrc
#sonar.python.pylint.reportPath=pylint-report.txt

点击“保存”。

  1. 保存后,您将在项目页面上看到 SonarQube 标志,如图 8.55所示。点击“立即构建”:图 8.55:我们项目仪表板上显示 SonarQube 选项

图 8.55:我们项目仪表板上显示 SonarQube 选项

  1. 在“构建历史”中,点击“控制台输出”。您应该会看到类似以下内容的屏幕:图 8.56:控制台输出

图 8.56:控制台输出

  1. 在浏览器中检查SonarQube的报告。输入http://<ip>:9000http://localhost:9000。您将发现 Jenkins 自动将您的hit_count项目添加到 SonarQube 中:

  2. 点击hit_count。您将找到一个详细的报告。每当 Jenkins 构建项目时,SonarQube 将自动分析代码。

在本活动中,您学习了如何将 Jenkins 与 SonarQube 集成并安装所需的插件,通过在浏览器中检查 SonarQube 进行验证。您还将 SonarQube 应用于您的简单 Web 应用程序hit_counter

活动 8.02:在全景徒步应用程序中利用 Jenkins 和 SonarQube

解决方案

  1. 在 Jenkins 中创建一个名为trekking的新项目。将其选择为FREESTYLE项目。点击“确定”。

  2. 在“常规”选项卡中,选择“丢弃旧构建”。

  3. 在“源代码管理”选项卡中,选择GIT。然后输入 URLhttp://github.com/efoda/trekking_app图 8.57:插入 GitHub URL

图 8.57:插入 GitHub URL

  1. 在“构建触发器”中,选择“轮询 SCM”,并输入H/15 * * * *图 8.58:插入调度代码

图 8.58:插入调度代码

  1. 在“构建环境”选项卡中,选择“准备 SonarQube 扫描器环境”。从下拉菜单中选择“服务器身份验证令牌”:图 8.59:选择 SonarQubeToken 作为服务器身份验证令牌

图 8.59:选择 SonarQubeToken 作为服务器身份验证令牌

  1. 在“构建”选项卡中,在“分析属性”中输入以下代码:
sonar.projectKey=trekking
sonar.projectName=trekking
sonar.projectVersion=1.0
sonar.sources=.
sonar.language=py
sonar.sourceEncoding=UTF-8
# Test Results
sonar.python.xunit.reportPath=nosetests.xml
# Coverage
sonar.python.coverage.reportPath=coverage.xml
# Linter (https://docs.sonarqube.org/display/PLUG/Pylint+Report)
#sonar.python.pylint=/usr/local/bin/pylint
#sonar.python.pylint_config=.pylintrc
#sonar.python.pylint.reportPath=pylint-report.txt

点击“保存”。

  1. 选择“立即构建”。当构建成功完成时,选择“控制台输出”。以下输出将指示它已成功完成:图 8.60:验证 Jenkins 已成功构建镜像

图 8.60:验证 Jenkins 已成功构建镜像

  1. 切换到浏览器中的SonarQube选项卡,并检查输出。以下报告表明徒步应用程序有两个错误和零个安全漏洞:图 8.61:在 SonarQube 浏览器选项卡中显示的报告

图 8.61:在 SonarQube 浏览器选项卡中显示的报告

如果单击“新代码”,它将为空,因为您只构建了项目一次。当 Jenkins 再次构建它时,您将找到两次构建之间的比较。

  1. 如果您想编辑项目的代码,请将 GitHub 代码 fork 到您的帐户,并编辑代码以修复错误和漏洞。编辑项目的配置,使其使用您的 GitHub 代码,而不是“源代码”选项卡中提供的代码。

在这个活动中,您将 Jenkins 与 SonarQube 集成,并将其应用于全景徒步应用程序。在活动结束时,您将检查 SonarQube 生成的报告,显示代码中的错误和漏洞。

9. Docker Swarm

活动 9.01:将全景徒步应用部署到单节点 Docker Swarm

解决方案

有许多方法可以执行此活动。以下步骤是其中一种方法:

  1. 为应用程序创建一个目录。在这种情况下,您将创建一个名为Activity1的目录,并使用cd命令进入新目录:
mkdir Activity1; cd Activity1
  1. 从其 GitHub 存储库克隆应用程序,以确保您拥有部署到 Swarm 的 Panoramic Trekking App 服务所需的所有相关信息和应用程序:
git clone https://github.com/vincesesto/trekking_app.git
  1. 您不需要 NGINX 的任何支持目录,但请确保您的 Web 服务和运行的数据库在此处列出,包括panoramic_trekking_appphoto_viewer目录以及Dockerfileentrypoint.shmanage.pyrequirements.txt脚本和文件:
ls -l

该命令应返回类似以下的输出:

-rw-r--r--   1 vinces  staff   533 12 Mar 15:02 Dockerfile
-rwxr-xr-x   1 vinces  staff  1077 12 Mar 15:02 entrypoint.sh
-rwxr-xr-x   1 vinces  staff   642 12 Mar 15:02 manage.py
drwxr-xr-x   9 vinces  staff   288 12 Mar 15:02 
panoramic_trekking_app
drwxr-xr-x  12 vinces  staff   384 12 Mar 15:02 photo_viewer
-rw-r--r--   1 vinces  staff   105 12 Mar 15:02 requirements.txt
  1. 在目录中创建.env.dev文件,并添加以下详细信息,供panoramic_trekking_app在其settings.py文件中使用。这些环境变量将设置数据库名称、用户、密码和其他数据库设置:
SQL_ENGINE=django.db.backends.postgresql
SQL_DATABASE=pta_database
SQL_USER=pta_user
SQL_PASSWORD=pta_password
SQL_HOST=db
SQL_PORT=5432
PGPASSWORD=docker
  1. 创建一个新的docker-compose.yml文件,并用文本编辑器打开它,并添加以下详细信息:
version: '3.3'
services:
  web:
    build: .
    image: activity_web:latest
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - static_volume:/service/static
    ports:
      - 8000:8000
    environment:
      - PGPASSWORD=docker
    env_file:
      - ./.env.dev
    depends_on:
      - db
  db:
    image: postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      - POSTGRES_PASSWORD=docker
    ports:
      - 5432:5432
volumes:
  postgres_data:
  static_volume:

如您从docker-compose.yml文件中的突出显示的行中所见,web服务依赖于activity_web:latest Docker 镜像。

  1. 运行以下docker build命令来构建镜像并适当地标记它:
docker build -t activity_web:latest .
  1. 现在是时候将堆栈部署到 Swarm 了。使用您创建的docker-compose.yml文件运行以下stack deploy命令:
docker stack deploy --compose-file docker-compose.yml activity_swarm

创建网络后,您应该看到activity_swarm_webactivity_swarm_db服务可用:

Creating network activity_swarm_default
Creating service activity_swarm_web
Creating service activity_swarm_db
  1. 运行service ls命令:
docker service ls

验证所有服务是否已成功启动,并显示1/1副本,就像我们这里一样:

ID       NAME                MODE         REPLICAS
  IMAGE
k6kh…    activity_swarm_db   replicated   1/1
  postgres:latest
copa…    activity_swarm_web  replicated   1/1
  activity_web:latest  
  1. 最后,打开您的网络浏览器,并验证您能够从http://localhost:8000/admin/http://localhost:8000/photo_viewer/访问该网站。

Panoramic Trekking App 的创建和设置方式与本章中已经完成的一些其他服务类似。

活动 9.02:在 Swarm 运行时执行应用程序更新

解决方案:

有许多种方法可以执行此活动。以下步骤详细说明了一种方法:

  1. 如果您没有运行 Swarm,请部署您在活动 9.01中创建的docker-compose.yml文件,将 Panoramic Trekking App 部署到单节点 Docker Swarm
docker stack deploy --compose-file docker-compose.yml activity_swarm

如您所见,现在所有三个服务都在运行:

Creating network activity_swarm_default
Creating service activity_swarm_web
Creating service activity_swarm_db
  1. 在执行stack deploy命令的同一目录中,使用文本编辑器打开photo_viewer/templates/photo_index.html文件,并将第四行更改为与以下详细信息匹配,基本上是在主标题中添加单词Patch

photo_index.html

1 {% extends "base.html" %}
2 {% load static %}
3 {% block page_content %}
4 <h1>Patch Panoramic Trekking App - Photo Viewer</h1>

您可以在此处找到完整的代码packt.live/3ceYnta

  1. 构建一个新图像,这次使用以下命令将图像标记为patch_1
docker build -t activity_web:patch_1 .
  1. 使用service update命令将补丁部署到您的 Swarm Web 服务。还提供要应用更新的图像名称和服务:
docker service update --image activity_web:patch_1 activity_swarm_web

输出应如下所示:


activity_swarm_web
overall progress: 1 out of 1 tasks 
1/1: running   [=======================================>] 
verify: Service converged
  1. 列出正在运行的服务,并验证新图像是否作为activity_swarm_web服务的一部分正在运行:
docker service ls

从输出中可以看出,Web 服务不再使用latest标记。它现在显示patch_1图像标记:

ID         NAME                  MODE          REPLICAS
  IMAGE
k6kh…      activity_swarm_db     replicated    1/1
  postgres:latest
cu5p…      activity_swarm_web    replicated    1/1
  activity_web:patch_1
  1. 通过访问http://localhost:8000/photo_viewer/并查看标题现在显示为Patch Panoramic Trekking App来验证更改是否已应用于图像:图 9.10:全景徒步应用程序的 Patch 版本

图 9.10:全景徒步应用程序的 Patch 版本

在此活动中,您对全景徒步应用程序进行了微小更改,以便可以对服务进行滚动更新。然后,您将图像部署到运行环境中,并执行滚动更新以验证更改是否成功。标题中的更改表明滚动更新已成功执行。

10. Kubernetes

活动 10.01:在 Kubernetes 上安装全景徒步应用程序

解决方案

可以通过以下步骤创建数据库和全景徒步应用程序:

  1. 使用以下helm命令安装数据库:
helm install database stable/postgresql --set postgresqlPassword=kubernetes

这将为 PostgreSQL 安装多个 Kubernetes 资源,并显示摘要如下:

图 10.23:数据库安装

图 10.23:数据库安装

此输出首先列出与 Helm 图表相关的信息,例如名称、部署时间、状态和修订版本,然后是与 PostgreSQL 实例相关的信息以及如何访问它。这是 Helm 图表中广泛接受的方法,在安装图表后提供此类信息。否则,将很难学习如何连接到 Helm 安装的应用程序。

  1. 创建一个statefulset.yaml文件,其中包含以下内容:
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: panoramic-trekking-app
spec:
  serviceName: panoramic-trekking-app
  replicas: 1
  selector:
    matchLabels:
      app: panoramic-trekking-app
  template:
    metadata:
      labels:
        app: panoramic-trekking-app
    spec:
      containers:
      - name: nginx
        image: packtworkshops/the-docker-workshop:          chapter10-pta-nginx
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: static
          mountPath: /service/static
      - name: pta
        image: packtworkshops/the-docker-workshop:          chapter10-pta-web
        volumeMounts:
        - name: static
          mountPath: /service/static
  volumeClaimTemplates:
  - metadata:
      name: static
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

此文件创建了一个名为panoramic-trekking-app的 Statefulset。在spec部分定义了两个名为nginxpta的容器。此外,还定义了一个名为static的卷索赔,并将其挂载到两个容器上。

  1. 使用以下命令部署panoramic-trekking-app StatefulSet:
kubectl apply -f statefulset.yaml

这将为我们的应用程序创建一个 StatefulSet:

StatefulSet.apps/panoramic-trekking-app created
  1. 创建一个service.yaml文件,内容如下:
apiVersion: v1
kind: Service
metadata:
  name: panoramic-trekking-app
  labels:
    app: panoramic-trekking-app
spec:
  ports:
  - port: 80
    name: web
  type: LoadBalancer
  selector:
    app: panoramic-trekking-app

此服务定义具有LoadBalancer类型,以访问具有标签app: panoramic-trekking-app的 Pod。端口80将可用于访问 Pod 的web端口。

  1. 使用以下命令部署panoramic-trekking-app服务:
kubectl apply -f service.yaml

这将创建以下 Service 资源:

Service/panoramic-trekking-app created
  1. 使用以下命令获取 Service 的 IP:
minikube service panoramic-trekking-app --url
http://192.168.64.14:32009

在以下步骤中存储 IP 以访问 Panoramic Trekking App。

  1. 在浏览器中打开 Panoramic Trekking App 的管理部分,网址为http://$SERVICE_IP/admin图 10.24:管理员登录视图

图 10.24:管理员登录视图

  1. 使用用户名admin和密码changeme登录,并添加新的照片和国家:图 10.25:管理员设置视图

图 10.25:管理员设置视图

  1. 在浏览器中打开 Panoramic Trekking App,网址为http://$SERVICE_IP/photo_viewer图 10.26:应用程序视图

图 10.26:应用程序视图

照片查看器应用程序显示已从数据库中检索到照片和国家。它还表明应用程序已正确设置并且正常运行。

在这个活动中,您已经将 Panoramic Trekking App 部署到了 Kubernetes 集群。您首先使用其 Helm 图表创建了一个数据库,然后为应用程序创建了 Kubernetes 资源。最后,您从浏览器访问了应用程序,并通过添加新的照片进行了测试。在这个活动结束时,您已经了解了如何使用官方 Helm 图表部署数据库,创建一系列 Kubernetes 资源来连接数据库并部署应用程序,并从集群中收集信息以访问应用程序。该活动中的步骤涵盖了在 Kubernetes 集群中部署容器化应用程序的生命周期。

11. Docker 安全

活动 11.01:为 Panoramic Trekking App 设置 seccomp 配置文件

解决方案

有多种方法可以创建一个seccomp配置文件,阻止用户执行mkdirkilluname命令。以下步骤展示了如何完成这一操作:

  1. 如果你本地没有postgres镜像,请执行以下命令:
docker pull postgres
  1. 在你的系统上使用wget命令获取默认的seccomp配置文件的副本。将你下载的文件命名为activity1.json
wget https://raw.githubusercontent.com/docker/docker/v1.12.3/profiles/seccomp/default.json - O activity1.json
  1. 从配置文件中删除以下三个命令,以允许我们进一步锁定我们的镜像。用你喜欢的文本编辑器打开activity1.json文件,并从文件中删除以下行。你应该删除行 15001504以删除uname命令,669673以删除mkdir命令,以及行 579583以删除kill命令的可用性:
1500                 {
1501                         "name": "uname",
1502                         "action": "SCMP_ACT_ALLOW",
1503                         "args": []
1504                 },

669                 {
670                         "name": "mkdir",
671                         "action": "SCMP_ACT_ALLOW",
672                         "args": []
673                 },

579                 {
580                         "name": "kill",
581                         "action": "SCMP_ACT_ALLOW",
582                         "args": []
583                 },

你可以在以下链接找到修改后的activity1.json文件:packt.live/32BI3PK

  1. 使用–-security-opt seccomp=activity1.json选项在运行镜像时为postgres镜像分配一个新配置文件:
docker run --rm -it --security-opt seccomp=activity1.json postgres sh
  1. 现在你已经登录到正在运行的容器中,测试你已经分配给容器的新配置文件的权限。执行mkdir命令在系统上创建一个新目录:
~ $ mkdir test

该命令应该显示一个Operation not permitted的输出:

mkdir: can't create directory 'test': Operation not permitted
  1. 为了测试你不再能够杀死正在运行的进程,你需要启动一些东西。启动top进程并在后台运行。在命令行中输入top,然后添加&,然后按Enter在后台运行该进程。接下来的命令提供了进程命令(ps),以查看容器上正在运行的进程:
~ $ top & ps

如下输出所示,top进程正在以PID 8运行:

PID   USER         TIME    COMMAND
 1    20002        0:00    sh
 8    20002        0:00    top
10    20002        0:00    ps
[1]+  Stopped  (tty output)       top

注意

基于postgres镜像的容器中不可用pstop命令。然而,这不会造成任何问题,因为用任意随机的 pid 号运行kill命令足以证明该命令不被允许运行。

  1. 使用kill -9命令杀死top进程,后面跟着你想要杀死的进程的 PID 号。kill -9命令将尝试强制停止命令:
~ $ kill -9 8

你应该看到Operation not permitted

sh: can't kill pid 8: Operation not permitted
  1. 测试uname命令。这与其他命令有些不同:
~ $ uname

你将得到一个Operation not permitted的输出:

Operation not permitted

这是一个很好的活动,表明如果我们的镜像被攻击者访问,我们仍然可以采取很多措施来限制对它们的操作。

活动 11.02:扫描您的全景徒步应用镜像的漏洞

解决方案:

有许多方法可以扫描我们的镜像以查找漏洞。以下步骤是使用 Anchore 来验证postgres-app镜像是否对我们的应用程序安全的一种方法:

  1. 给镜像打标签并将其推送到您的 Docker Hub 仓库。在这种情况下,使用我们的仓库名称给postgres-app镜像打标签,并将其标记为activity2。我们还将其推送到我们的 Docker Hub 仓库:
docker tag postgres <your repository namespace>/postgres-app:activity2 ; docker push <your repository name>/postgres-app:activity2
  1. 您应该仍然拥有您在本章最初使用的docker-compose.yaml文件。如果您还没有运行 Anchore,请运行docker-compose命令并导出ANCHORE_CLI_URLANCHORE_CLI_URLANCHORE_CLI_URL变量,就像您之前做的那样,以便我们可以运行anchore-cli命令:
docker-compose up -d
  1. 通过运行anchore-cli system status命令来检查 Anchore 应用的状态:
anchore-cli system status
  1. 使用feeds list命令来检查 feeds 列表是否都已更新:
anchore-cli system feeds list
  1. 一旦所有的 feeds 都已经更新,添加我们推送到 Docker Hub 的postgres-app镜像。使用anchore-cli提供的image add命令,并提供我们想要扫描的镜像的仓库、镜像和标签。这将把镜像添加到我们的 Anchore 数据库中,准备进行扫描:
anchore-cli image add <your repository namespace>/postgres-app:activity2
  1. 使用image list命令来验证我们的镜像是否已经被分析。一旦完成,您应该在Analysis Status列中看到analyzed这个词:
anchore-cli image list
  1. 使用我们的镜像名称执行image vuln命令,以查看在我们的postgres-app镜像上发现的所有漏洞的列表。这个镜像比我们之前测试过的镜像要大得多,也要复杂得多,所以当我们使用all选项时,会发现很长的漏洞列表。幸运的是,大多数漏洞要么是Negligible,要么是Unknown。运行image vuln命令并将结果传输到wc -l命令:
anchore-cli image vuln <your repository namespace>/postgres-app:activity2 all | wc -l

这将给我们一个漏洞数量的统计。在这种情况下有超过 100 个值:

108
  1. 最后,使用evaluate check命令来查看发现的漏洞是否会给我们通过或失败:
anchore-cli evaluate check <your repository namespace>/postgres-app:activity2

幸运的是,正如您从以下输出中看到的,我们通过了:

Image Digest: sha256:57d8817bac132c2fded9127673dd5bc7c3a97654
636ce35d8f7a05cad37d37b7
Full Tag: docker.io/vincesestodocker/postgres-app:activity2
Status: pass
Last Eval: 2019-11-23T06:15:32Z
Policy ID: 2c53a13c-1765-11e8-82ef-23527761d060

由于该镜像由一个大型组织提供,他们有责任确保您可以安全使用它,但由于扫描镜像如此容易,我们仍然应该扫描它们以验证它们是否 100%安全可用。

12. 最佳实践

活动 12.01:查看 Panoramic Trekking App 使用的资源

解决方案:

我们在本章中执行第一个活动的方式有很多种。以下步骤是通过使用docker stats命令查看 Panoramic Trekking App 中服务使用的资源的一种方法。在本例中,我们将使用作为 Panoramic Trekking App 的一部分运行的postgresql-app服务:

  1. 创建一个脚本,将创建一个新表并用随机值填充它。以下脚本正是我们在这种情况下想要的,因为我们想创建一个长时间的处理查询,并查看它如何影响我们容器上的资源。添加以下细节,并使用您喜欢的编辑器将文件保存为resource_test.sql
1 CREATE TABLE test_data
2 (
3     random_value NUMERIC NOT NULL,
4     row1         NUMERIC NOT NULL,
5     row2         NUMERIC NOT NULL
6 );
7 
8 INSERT INTO test_data
9     SELECT random_value.*,
10     gen.* ,
11     CEIL(RANDOM()*100)
12     FROM GENERATE_SERIES(1, 300) random_value,
13     GENERATE_SERIES(1, 900000) gen
14     WHERE gen <= random_value * 300;

第 1 行第 6 行创建新表并设置它包含的三行,而第 8 行到第 14 行遍历一个新表,用随机值填充它。

  1. 如果您还没有 PostgreSQL Docker 镜像的副本,请使用以下命令从受支持的 PostgreSQL Docker Hub 存储库中拉取镜像:
docker pull postgres
  1. 进入新的终端窗口并运行docker stats命令,查看正在使用的CPU百分比,以及正在使用的内存和内存百分比:
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemPerc}}\t{{.MemUsage}}"

在以下命令中,我们没有显示容器 ID,因为我们希望限制输出中显示的数据量:

NAME         CPU %       MEM %      MEM USAGE / LIMIT
  1. 要简单测试这个镜像,您不需要将运行的容器挂载到特定卷上,以使用您先前为此镜像使用的数据。切换到另一个终端来监视您的 CPU 和内存。启动容器并将其命名为postgres-test,确保数据库可以从主机系统访问,通过暴露运行psql命令所需的端口。我们还在此示例中使用环境变量(-e)选项指定了临时密码为docker
docker run --rm --name postgres-test -v ${PWD}/resource_test.sql:/resource_test.sql -e POSTGRES_PASSWORD=docker -d -p 5432:5432 postgres
  1. 在运行测试脚本之前,切换到监视 CPU 和内存使用情况的终端。您可以看到我们的容器已经在没有真正做任何事情的情况下使用了一些资源:
NAME            CPU %    MEM %     MEM USAGE / LIMIT
postgres-test   0.09%    0.47%     9.273MiB / 1.943GiB
  1. 使用以下命令进入容器内的终端:
docker exec -it postgres-test /bin/bash
  1. 使用psql命令发送postgres-test容器命令以创建名为resource_test的新数据库:
psql -h localhost -U postgres -d postgres -c 'create database resource_test;'
Password for user postgres: 
CREATE DATABASE
  1. 运行您之前创建的脚本。确保在运行脚本之前包括time命令,因为这将允许您查看完成所需的时间:
time psql -h localhost -U postgres -d resource_test -a -f resource_test.sql

我们已经减少了以下代码块中命令的输出。用数据填充resource_database表花费了 50 秒:

Password for user postgres: 
…
INSERT 0 13545000
real    0m50.446s
user    0m0.003s
sys     0m0.008s
  1. 移动到运行docker stats命令的终端。您将看到一个输出,取决于系统运行的核心数量和可用的内存。正在运行的脚本似乎不太耗费内存,但它正在将容器可用的 CPU 推高到 100%:
NAME            CPU %      MEM %    MEM USAGE / LIMIT
postgres-test   100.66%    2.73%    54.36MiB / 1.943GiB
  1. 在对 CPU 和内存配置进行更改后运行容器之前,删除正在运行的容器,以确保您有一个新的数据库运行,使用以下命令:
docker kill postgres-test
  1. 再次运行容器。在这种情况下,您将将可用的 CPU 限制为主机系统上一半的一个核心,并且由于测试不太耗费内存,将内存限制设置为256MB
docker run --rm --name postgres-test -e POSTGRES_PASSWORD=docker -d -p 5432:5432 --cpus 0.5 --memory 256MB postgres
  1. 使用exec命令进入容器:
docker exec -it postgres-test /bin/bash
  1. 再次,在运行测试之前,创建resource_test数据库:
psql -h localhost -U postgres -d postgres -c 'create database resource_test;'
Password for user postgres: 
CREATE DATABASE
  1. 现在,为了查看对我们的资源所做的更改,限制容器可以使用的资源。再次运行resource_test.sql脚本,并通过限制资源,特别是 CPU,我们可以看到现在完成需要超过 1 分钟:
time psql -h localhost -U postgres -d resource_test -a -f resource_test.sql
Password for user postgres: 
…
INSERT 0 13545000
real    1m54.484s
user    0m0.003s
sys     0m0.005s
  1. 移动到运行docker stats命令的终端。它看起来也会有所不同,因为可用于使用的 CPU 百分比将减半。您对 CPU 所做的更改减慢了脚本的运行,并且似乎也减少了内存的使用:
NAME            CPU %     MEM %      MEM USAGE / LIMIT
postgres-test   48.52%    13.38%     34.25MiB / 256MiB

这项活动为您提供了一个很好的指示,有时您需要执行平衡的行为,当您监视和配置容器资源时。它确实澄清了您需要了解您的服务正在执行的任务,以及对配置的更改将如何影响您的服务的运行方式。

活动 12.02:使用 hadolint 改进 Dockerfile 的最佳实践

解决方案

有许多种方法可以执行此活动。以下步骤展示了一种方法:

  1. 使用以下docker pull命令从hadolint存储库中拉取镜像:
docker pull hadolint/hadolint
  1. 使用hadolint来检查我们在本章中一直在使用的docker-stress Dockerfile并记录所呈现的警告:
docker run --rm -i hadolint/hadolint < Dockerfile

你会收到以下警告:

/dev/stdin:1 DL3006 Always tag the version of an image explicitly
/dev/stdin:2 DL3008 Pin versions in apt get install. Instead of 
'apt-get install <package>' use 'apt-get install 
<package>=<version>'
/dev/stdin:2 DL3009 Delete the apt-get lists after installing 
something
/dev/stdin:2 DL3015 Avoid additional packages by specifying 
'--no-install-recommends'
/dev/stdin:2 DL3014 Use the '-y' switch to avoid manual input 
'apt-get -y install <package>'
/dev/stdin:3 DL3025 Use arguments JSON notation for CMD 
and ENTRYPOINT arguments

与你最初测试镜像时没有真正的变化。然而,在Dockerfile中只有三行代码,所以看看是否可以减少hadolint呈现的警告数量。

  1. 正如本章前面提到的,hadolint维基页面将为你提供如何解决所呈现的每个警告的详细信息。然而,如果你逐行进行,应该能够解决所有这些警告。首先呈现的DL3006要求标记你正在使用的 Docker 镜像版本,这是 Ubuntu 镜像的新版本。将你的Dockerfile行 1更改为现在包括18.08镜像版本,如下所示:
1 FROM ubuntu:18.08
  1. 接下来的四个警告都与我们Dockerfile的第二行有关。DL3008要求固定安装的应用程序版本。在下面的情况下,将 stress 应用程序固定到 1.0.3 版本。DL3009指出你应该删除任何列表。这就是我们在下面的代码中添加行 4行 5的地方。DL3015指出你还应该使用--no-install-recommends,确保你不安装不需要的应用程序。最后,DL3014建议你包括-y选项,以确保你不会被提示验证应用程序的安装。编辑Dockerfile如下所示:
2 RUN apt-get update \
3 && apt-get install -y stress=1.0.4 --no-install-recommends \
4 && apt-get clean \
5 && rm -rf /var/lib/apt/lists/*
  1. DL3025是你的最后警告,并且指出你需要将CMD指令以 JSON 格式编写。这可能会导致问题,因为你正在尝试在 stress 应用程序中使用环境变量。为了消除这个警告,使用sh -c选项运行stress命令。这样应该仍然允许你使用环境变量运行命令:
6 CMD ["sh", "-c", "stress ${var}"]

你的完整Dockerfile,现在遵循最佳实践,应该如下所示:

FROM ubuntu:18.04
RUN apt-get update \
 && apt-get install -y stress=1.0.4 --no-install-recommends \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/*
CMD ["sh", "-c", "stress ${var}"]
  1. 现在,再次使用hadolintDockerfile进行检查,不再呈现任何警告:
docker run --rm -i hadolint/hadolint < Dockerfile
  1. 如果你想百分之百确定Dockerfile看起来尽可能好,进行最后一次测试。在浏览器中打开FROM:latest,你会看到Dockerfile显示最新更改时的没有找到问题或建议!图 12.4:docker-stress Dockerfile 现在遵循最佳实践

图 12.4:docker-stress Dockerfile 现在遵循最佳实践

您的Dockerfiles可能比本章中呈现的要大得多,但是正如您所看到的,逐行系统地处理将帮助您纠正Dockerfiles可能存在的任何问题。使用诸如hadolintFROM latest之类的应用程序,以及它们关于如何解决警告的建议,将使您熟悉随着实践而来的最佳实践。这就是我们活动和本章的结束,但是还有更多有趣的内容要学习,所以现在不要停下来。

13.监控 Docker 指标

活动 13.01:创建 Grafana 仪表板以监控系统内存

解决方案

有许多方法可以执行此活动。以下步骤是一种方法:

  1. 确保 Prometheus 正在运行和收集数据,Docker 和cAdvisor已配置为公开指标,并且 Grafana 正在运行并配置为使用 Prometheus 作为数据源。

  2. 打开 Grafana Web 界面和您在练习 13.05:在您的系统上安装和运行 Grafana中创建的Container Monitoring仪表板

  3. 仪表板顶部和仪表板名称右侧有一个“添加面板”的选项。单击“添加面板”图标以添加新的仪表板面板:图 13.26:向容器监控仪表板添加新面板

图 13.26:向容器监控仪表板添加新面板

  1. 从下拉列表中选择Prometheus作为我们将使用的数据源,以生成新的仪表板面板。

  2. metrics部分,添加以下 PromQL 查询,container_memory_usage_bytes,仅搜索具有名称值的条目。然后,按每个名称求和,为每个容器提供一条线图:

sum by (name) (container_memory_usage_bytes{name!=""})
  1. 根据时间序列数据库中可用的数据量进行调整相对时间(如果需要)。也许将相对时间设置为15m。前三个步骤如下图所示:图 13.27:向容器监控仪表板添加新面板

图 13.27:向容器监控仪表板添加新面板

  1. 选择“显示选项”并添加“内存容器使用”作为标题。

  2. 如果单击“保存”,您会注意到无法保存面板,因为仪表板已在启动时进行了配置。您可以导出 JSON,然后将其添加到您的配置目录中。单击“共享仪表板”按钮并导出 JSON。选择“将 JSON 保存到文件”并将仪表板文件存储在“/tmp 目录”中:图 13.28:警告,我们无法保存新的仪表板

图 13.28:警告,我们无法保存新的仪表板

  1. 停止运行 Grafana 容器,以便您可以添加到环境中的配置文件。使用以下docker kill命令执行此操作:
docker kill grafana
  1. 您已经在provisioning/dashboards目录中有一个名为ContainerMonitoring.json的文件。从您的tmp目录中复制刚创建的 JSON 文件,并替换provisioning/dashboards目录中的原始文件:
cp /tmp/ContainerMonitoring-1579130313205.json provisioning/dashboards/ContainerMonitoring.json
  1. 再次启动 Grafana 图像,并使用默认管理密码登录应用程序:
docker run --rm -d --name grafana -p 3000:3000 -e "GF_SECURITY_ADMIN_PASSWORD=secret" -v ${PWD}/provisioning:/etc/grafana/provisioning grafana/Grafana
  1. 再次登录到 Grafana,并转到您一直在配置的“容器监控”仪表板。您现在应该在我们的仪表板顶部看到新创建的“内存容器使用情况”面板,类似于以下屏幕截图:图 13.29:显示内存使用情况的新仪表板面板

图 13.29:显示内存使用情况的新仪表板面板

现在应该更容易监视系统上运行的容器的内存和 CPU 使用情况。仪表板提供了比查看docker stats命令更简单的界面,特别是当您开始在系统上运行更多容器时。

活动 13.02:配置全景徒步应用程序向 Prometheus 公开指标

解决方案

我们可以以多种方式执行此活动。在这里,我们选择向全景徒步应用程序的 PostgreSQL 容器添加导出器:

  1. 如果您没有全景徒步应用程序在运行,请确保至少 PostgreSQL 容器正在运行,以便您可以完成此活动。您还不需要运行 Prometheus,因为您需要先对配置文件进行一些更改。运行以下命令以验证 PostgreSQL 数据库是否正在运行:
docker run --rm -d --name postgres-test -e POSTGRES_PASSWORD=docker -p 5432:5432 postgres

要从您的 PostgreSQL 容器中收集更多指标,您可以在 GitHub 上找到用户albertodonato已经创建的导出器。使用其他人已经创建的导出器比自己创建要容易得多。文档和详细信息可以在以下网址找到:github.com/albertodonato/query-exporter

  1. 上述的 GitHub 帐户有一个很好的分解如何设置配置和指标。设置一个基本的配置文件以开始。通过运行以下docker inspect命令找到 PostgreSQL 容器正在运行的 IP 地址。这会给出容器正在运行的内部 IP 地址。您还需要替换您正在运行的容器名称为<container_name>
docker inspect --format '{{ .NetworkSettings.IPAddress }}' <container_name>

您的 IP 地址可能与此处的不同:

172.17.0.3
  1. 对于这个导出器,您需要设置一些额外的配置来输入到导出器中。首先,在您的工作目录中创建一个名为psql_exporter_config.yml的配置文件,并用文本编辑器打开该文件。

  2. 在下面的配置文件中输入前四行。这是导出器连接到数据库的方式。您需要提供可以访问数据库的密码以及在上一步中获得的 IP 地址,或者如果为数据库分配了域,则需要提供域:

1 databases:
2   pg:
3     dsn: postgresql+psycopg2://postgres:<password>@<ip|domain>/        postgres
4
  1. 将您的第一个指标添加到配置文件中。输入以下行以添加指标名称、规模类型、描述和标签:
5 metrics:
6   pg_process:
7     type: gauge
8     description: Number of PostgreSQL processes with their         states
9     labels: [state]
10
  1. 设置一个数据库查询,以收集您想要用于pg_process规模的指标详细信息。第 13 行显示您想要创建一个数据库查询,第 1415 行将结果分配给您之前创建的指标。第 1623 行是我们想要在数据库上运行的查询,以便为数据库上运行的进程数量创建一个规模:

psql_exporter_config.yml

11 queries:
12   process_stats:
13     databases: [pg]
14     metrics:
15       - pg_process
16     sql: >
17       SELECT
18         state,
19         COUNT(*) AS pg_process
20       FROM pg_stat_activity
21       WHERE state IS NOT NULL
22       GROUP BY state
23       FROM pg_stat_database

您可以在此处找到完整的代码packt.live/32C47K3

  1. 保存配置文件并从命令行运行导出器。导出器将在端口9560上公开其指标。挂载您在此活动中创建的配置文件。您还将获得adonato/query-exporter图像的最新版本:
docker run -p 9560:9560/tcp -v --name postgres-exporter ${PWD}/psql_exporter_config.yml:/psql_exporter_config.yml --rm -itd adonato/query-exporter:latest -- /psql_exporter_config.yml
  1. 打开一个网络浏览器,使用 URLhttp://0.0.0.0:9560/metrics来查看您为全景徒步应用程序运行的 PostgreSQL 容器设置的新指标:
# HELP database_errors_total Number of database errors
# TYPE database_errors_total counter
# HELP queries_total Number of database queries
# TYPE queries_total counter
queries_total{database="pg",status="success"} 10.0
queries_total{database="pg",status="error"} 1.0
# TYPE queries_created gauge
queries_created{database="pg",status="success"} 
1.5795789188074727e+09
queries_created{database="pg",status="error"} 
1.57957891880902e+09
# HELP pg_process Number of PostgreSQL processes with their states
# TYPE pg_process gauge
pg_process{database="pg",state="active"} 1.0
  1. 进入您安装了 Prometheus 的目录,用您喜欢的文本编辑器打开prometheus.yml文件,并添加导出器详细信息,以允许 Prometheus 开始收集数据:
45   - job_name: 'postgres-web'
46     scrape_interval: 5s
47     static_configs:
48     - targets: ['0.0.0.0:9560']
  1. 保存您对prometheus.yml文件所做的更改,并再次从命令行启动 Prometheus 应用程序,如下所示:
./prometheus --config.file=prometheus.yml
  1. 如果一切都按照应该的方式进行了,您现在应该在 Prometheus 的Targets页面上看到postgres-web目标,如图所示:图 13.30:在 Prometheus 上显示的新的 postgres-web 目标页面

图 13.30:在 Prometheus 上显示的新的 postgres-web 目标页面

这就是活动的结束,也是本章的结束。这些活动应该有助于巩固之前学到的知识,并为您提供了在更加用户友好的方式中收集应用程序和运行系统的指标的经验。

14. 收集容器日志

活动 14.01:为您的 Splunk 安装创建一个 docker-compose.yml 文件

解决方案

有许多方法可以执行这项活动。以下步骤概述了一种可能的方法。

在这里,您将设置一个docker-compose.yml文件,该文件至少会以与本章中一直运行的方式运行您的 Splunk 容器。您将设置两个卷,以便挂载/opt/splunk/etc目录,以及/opt/splunk/var目录。您需要公开端口800099978088,以允许访问您的 Web 界面并允许数据转发到 Splunk 实例。最后,您需要设置一些环境变量,以接受 Splunk 许可证并添加管理员密码。让我们开始吧:

  1. 创建一个名为docker-compose.yml的新文件,并用您喜欢的文本编辑器打开它。

  2. 从您喜欢的Docker Compose版本开始,并创建要用于挂载varext目录的卷:

1 version: '3'
2
3 volumes:
4   testsplunk:
5   testsplunkindex:
6
  1. 使用splunk作为主机名和splunk/splunk作为您安装的镜像来设置 Splunk 安装的服务。此外,设置SPLUNK_START_ARGSSPLUNK_PASSWORD的环境变量,如下所示:
7 services:
8   splunk:
9     hostname: splunk
10    image: splunk/splunk
11    environment:
12      SPLUNK_START_ARGS: --accept-license
13      SPLUNK_PASSWORD: changeme
  1. 最后,挂载卷并公开安装所需的访问 Web 界面和从转发器和容器转发数据的端口:
14    volumes:
15      - ./testsplunk:/opt/splunk/etc
16      - ./testsplunkindex:/opt/splunk/var
17    ports:
18      - "8000:8000"
19      - "9997:9997"
20      - "8088:8088"
  1. 运行docker-compose up命令,确保一切都正常工作。使用-d选项确保它作为后台守护程序在我们系统中运行:
docker-compose up -d

该命令应返回类似以下的输出:

Creating network "chapter14_default" with the default driver
Creating chapter14_splunk_1 ... done
  1. 一旦您的 Splunk 安装再次运行,就该是让 Panoramic Trekking App 中的一个服务运行起来,这样您就可以将日志转发到 Splunk 进行索引。在使用docker run命令时,添加日志驱动程序的详细信息,就像您在本章中之前所做的那样,并确保您包括了正确的HTTP 事件收集器的令牌:
docker run --rm -d --name postgres-test \
-e POSTGRES_PASSWORD=docker -p 5432:5432 \
--log-driver=splunk \
--log-opt splunk-url=http://127.0.0.1:8088 \
--log-opt splunk-token=5c051cdb-b1c6-482f-973f-2a8de0d92ed8 \
--log-opt splunk-insecureskipverify=true \
--log-opt tag="{{.Name}}/{{.FullID}}" \
postgres -c log_statement=all 

请注意

请注意,我们在docker run命令中使用了-c log_statement=all,这将确保我们所有的 PostgreSQL 查询都被记录并发送到 Splunk。

  1. 登录 Splunk Web 界面并访问搜索和报告应用程序。在界面中输入source="http:docker logs" AND postgres-test查询,然后按Enter。由于您已经给我们的容器打了标签,您应该会看到您的容器带有名称和完整 ID 的标签,因此在搜索中添加postgres-test将确保只有您的 PostgreSQL 日志可见:图 14.48:Splunk 中显示的 PostgreSQL 日志

图 14.48:Splunk 中显示的 PostgreSQL 日志

从前面的屏幕截图中可以看出,我们的日志已经成功地通过 Splunk 流动。请注意在日志条目中添加的标签,就像前面的屏幕截图中所示的那样。

这项活动教会了我们如何在开发项目中使用 Docker Compose 实施日志记录程序。

活动 14.02:创建一个 Splunk 应用程序来监视 Panoramic Trekking App

解决方案

有许多方法可以执行这项活动。以下步骤是一种方法。在这里,您将向作为 Panoramic Trekking App 的一部分正在运行的PostgreSQL容器添加一个导出器:

  1. 确保 Splunk 正在运行,并且您一直在监视的服务已经运行了一段时间,以确保您正在为这项活动收集一些日志。

  2. 登录 Splunk Web 界面。从 Splunk 主屏幕上,点击应用程序菜单旁边的齿轮图标;您将看到您的 Splunk 环境的应用程序页面:图 14.49:Splunk 环境的应用程序页面

图 14.49:Splunk 环境的应用程序页面

  1. 点击“创建”应用按钮并填写表格。表格将类似于以下内容,其中“名称”设置为“全景徒步应用”,“文件夹名称”设置为panoramic_trekking_app,“版本”设置为1.0.0。点击“保存”以创建新应用:图 14.50:在 Splunk 中创建您的新应用

图 14.50:在 Splunk 中创建您的新应用

  1. 返回到 Splunk 主页,并确保您的“全景徒步应用”从“应用”菜单中可见。点击“全景徒步应用”以打开“搜索和报告”页面,以便您可以开始查询您的数据:图 14.51:选择全景徒步应用

图 14.51:选择全景徒步应用

  1. 在查询栏中输入source="http:docker logs" AND postgres-test AND INSERT AND is_superuser | stats count,然后按 Enter 键。搜索将查找作为应用程序的一部分创建的任何“超级用户”。当您的数据出现时,点击“可视化”选项卡,并将其更改为显示单个值的可视化:图 14.52:在查询栏中输入查询

图 14.52:在查询栏中输入查询

  1. 点击屏幕顶部的“另存为”按钮,然后选择“仪表板”面板。当您看到此屏幕时,选择要添加到新仪表板的面板,并将其命名为“PTA 监控”。还要给面板命名为“超级用户访问”,然后点击“保存”:图 14.53:向仪表板面板添加详细信息

图 14.53:向仪表板面板添加详细信息

  1. 当您看到新的仪表板时,点击“编辑”和“添加”面板按钮。选择“新建”,然后选择“单个值”作为可视化类型。将“内容标题”设置为“数据库创建”。添加source="http:docker logs" AND postgres-test AND CREATE DATABASE | stats count源字符串,然后点击“保存”。这将通过日志搜索以显示是否有人在 PostgreSQL 数据库上创建了任何数据库,这应该只在设置和创建应用程序时发生:图 14.54:编辑仪表板面板

图 14.54:编辑仪表板面板

  1. 再次点击“新面板”按钮,选择“新建”,然后从可视化中选择“柱状图”。添加一个“内容标题”为“应用使用情况”,添加source="http:docker logs" AND postgres-test AND SELECT AND photo_viewer_photo earliest=-60m | timechart span=1m count搜索查询,并点击“保存”。这个搜索将为您提供一段时间内使用应用程序查看照片的人数。

  2. 随意移动仪表板上的面板。当您对更改感到满意时,点击“保存”按钮。您的仪表板应该看起来类似于以下内容:图 14.55:用于监视 PostgreSQL 使用情况的新仪表板面板

图 14.55:用于监视 PostgreSQL 使用情况的新仪表板面板

这个活动帮助您收集 Panoramic Trekking App 的日志数据,并使用 Splunk 以更用户友好的方式显示它。

15. 使用插件扩展 Docker

活动 15.01:使用网络和卷插件安装 WordPress

解决方案:

可以使用以下步骤使用卷和网络插件为数据库和 WordPress 博客创建容器:

  1. 使用以下命令创建一个网络:
docker network create  \
--driver=store/weaveworks/net-plugin:2.5.2 \
--attachable \
wp-network

这个命令使用 Weave Net 插件创建一个网络,并使用driver标志进行指定。此外,卷被指定为attachable,这意味着您可以在将来连接到 Docker 容器。最后,容器的名称将是wp-network。您应该得到以下输出:

mk0pmhpb2gx3f6s00o57j2vd
  1. 使用以下命令创建一个卷:
docker volume create -d vieux/sshfs \
--name wp-content \
-o sshcmd=root@localhost:/tmp \
-o password=root \
-o port=2222

这个命令使用vieux/sshfs插件通过 SSH 创建一个卷。卷的名称是wp-content,并传递了ssh命令、端口和密码的额外选项:

wp-content
  1. 使用以下命令创建mysql容器:
docker run --name mysql -d \
-e MYSQL_ROOT_PASSWORD=wordpress \
-e MYSQL_DATABASE=wordpress \
-e MYSQL_USER=wordpress \
-e MYSQL_PASSWORD=wordpress \
--network=wp-network \
mysql:5.7

这个命令以分离模式运行mysql容器,并使用环境变量和wp-network连接。

  1. 使用以下命令创建wordpress容器:
docker run --name wordpress -d \
-v wp-content:/var/www/html/wp-content \
-e WORDPRESS_DB_HOST=mysql:3306 \
-e WORDPRESS_DB_USER=wordpress \
-e WORDPRESS_DB_PASSWORD=wordpress \
-e WORDPRESS_DB_NAME=wordpress \
--network=wp-network \
-p 8080:80 \
wordpress

这个命令以分离模式运行wordpress容器,并使用环境变量和wp-network连接。此外,容器的端口80在主机系统的端口8080上可用。

成功启动后,您将有两个运行中的mysqlwordpress容器:

docker ps

图 15.17:WordPress 和数据库容器

图 15.17:WordPress 和数据库容器

  1. 在浏览器中打开http://localhost:8080,以检查 WordPress 设置屏幕:图 15.18:WordPress 设置屏幕

图 15.18:WordPress 设置屏幕

WordPress 设置屏幕验证了 WordPress 是否使用了网络和卷插件。

在这个活动中,您使用 Weave Net 插件创建了一个自定义网络,并使用sshfs插件创建了一个自定义卷。您创建了一个使用自定义网络的数据库容器,以及一个使用自定义网络和自定义卷的 WordPress 容器。通过成功的设置,您的 Docker 容器可以通过自定义网络相互连接,并通过 SSH 使用卷。通过这个活动,您已经为一个真实的应用程序使用了 Docker 扩展。现在您可以自信地根据自己的业务需求和技术扩展 Docker。