GPT3 探索指南(八)
原文:
zh.annas-archive.org/md5/e19ec4b9c1d08c12abd2983dace7ff20译者:飞龙
附录
1. 运行我的第一个 Docker 容器
活动 1.01:从 Docker Hub 拉取并运行 PostgreSQL 容器映像
解决方案:
- 要启动 Postgres Docker 容器,首先确定需要设置数据库的默认用户名和密码凭据的环境变量。通过阅读官方 Docker Hub 页面,您可以看到
POSTGRES_USER和POSTGRES_PASSWORD环境变量的配置选项。使用-e标志传递环境变量。启动我们的 Postgres Docker 容器的最终命令如下:
docker run -itd -e "POSTGRES_USER=panoramic" -e "POSTGRES_PASSWORD=trekking" postgres:12
运行此命令将启动容器。
- 执行
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 数据库
解决方案:
- 使用
docker exec登录到数据库实例,启动容器内的 PSQL shell,传递--username标志并将--password标志留空:
$ docker exec -it <containerID> psql --username panoramic --password
这应提示您输入密码并启动 PSQL shell。
- 使用
\l命令列出所有数据库:
psql (12.2 (Debian 12.2-2.pgdg100+1))
Type "help" for help.
panoramic=# \l
将返回在容器中运行的数据库列表:
图 1.4:数据库列表
-
最后,使用
\q快捷方式退出 shell。 -
使用
docker stop和docker rm命令停止和清理容器实例。
在这个活动中,您通过使用在Activity 1.01中设置的凭据登录到容器中运行的数据库。您还列出了在容器中运行的数据库。该活动让您亲身体验了如何使用 PSQL shell 访问在任何容器中运行的数据库。
2. 使用 Dockerfiles 入门
活动 2.01:在 Docker 容器上运行 PHP 应用程序
解决方案:
- 为此活动创建一个名为
activity-02-01的新目录:
mkdir activity-02-01
- 导航到新创建的
activity-02-01目录:
cd activity-02-01
- 在
activity-02-01目录中,创建一个名为welcome.php的文件:
touch welcome.php
- 现在,使用您喜欢的文本编辑器打开
welcome.php:
vim welcome.php
- 创建
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;
?>
- 在
activity-02-01目录中,创建一个名为Dockerfile的文件:
touch Dockerfile
- 现在,使用您喜爱的文本编辑器打开
Dockerfile:
vim Dockerfile
- 将以下内容添加到
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,以使包安装变为非交互式。然后安装 apache2、php 和 curl 包,并将 PHP 文件复制到 /var/www/html 目录。接下来,配置健康检查并暴露端口 80。最后,使用 apache2ctl 命令启动 Apache web 服务器。
- 现在,构建 Docker 镜像:
$ docker image build -t activity-02-01 .
运行 build 命令后,您应该会得到以下输出:
图 2.22:构建活动-02-01 Docker 镜像
- 执行
docker container run命令以从您在上一步中构建的 Docker 镜像启动新容器:
$ docker container run -p 80:80 --name activity-02-01-container -d activity-02-01
由于您是以分离模式(使用 -d 标志)启动 Docker 容器,上述命令将输出生成的 Docker 容器的 ID。
- 现在,您应该能够查看 Apache 主页。在您喜爱的网络浏览器中转到
http://127.0.0.1/welcome.php终端节点:
图 2.23:PHP 应用程序页面
请注意,默认的 Apache 主页是可见的。在前面的输出中,您收到了 Good Morning 的输出。此输出可能会有所不同,根据您运行此容器的时间,可能会显示为 Good Afternoon 或 Good Evening。
- 现在,清理容器。首先,使用
docker container stop命令停止 Docker 容器:
$ docker container stop activity-02-01-container
- 最后,使用
docker container rm命令移除 Docker 容器:
$ docker container rm activity-02-01-container
在这个活动中,我们学习了如何使用本章中迄今为止学到的 Dockerfile 指令来将示例 PHP 应用程序 docker 化。我们使用了多个 Dockerfile 指令,包括 FROM、LABEL、ENV、RUN、COPY、WORKDIR、HEALTHCHECK、EXPOSE 和 ENTRYPOINT。
3. 管理您的 Docker 镜像
活动 3.01:使用 Git 哈希版本控制构建脚本
解决方案:
有多种方法可以完成这个活动。以下是一个例子:
- 创建一个新的构建脚本。第一行显示设置
–ex命令,将每个步骤打印到屏幕上,并且如果任何步骤失败,脚本将失败。第 3 行和第 4 行设置了你的注册表和服务名称的变量:
1 set -ex
2
3 REGISTRY=dev.docker.local:5000
4 SERVICENAME=postgresql
- 在第 6 行,将
GIT_VERSION变量设置为指向你的短 Git 提交哈希。构建脚本然后在第 7 行将这个值打印到屏幕上:
6 GIT_VERSION=`git log -1 --format=%h`
7 echo "version: $GIT_VERSION "
- 在第 9 行使用
docker build命令创建你的新镜像,并在第 11 行添加docker push命令将镜像推送到你的本地 Docker 注册表:
9 docker build -t $REGISTRY/$SERVICENAME:$GIT_VERSION .
10
11 docker push $REGISTRY/$SERVICENAME:$GIT_VERSION
脚本文件将如下所示:
1 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
- 运行以下命令来确保脚本已构建并成功运行:
./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 注册表存储
解决方案:
以下步骤描述了实现活动目标的一种方式:
- 在你的主目录中创建
test_registry目录:
mkdir /home/vincesesto/test_registry/
- 运行本地注册表,但在这种情况下,包括
-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
- 现在,像往常一样将镜像推送到新挂载的注册表中:
docker push dev.docker.local:5000/basic-app:ver1
- 为了验证镜像现在是否存储在你新挂载的目录中,列出
registry/docker/registry/v2/repositories/目录中的文件。
ls ~/test_registry/registry/docker/registry/v2/repositories/
你应该会看到你刚刚在上一步推送的新镜像:
basic-app
这个活动让我们开始使用一些更高级的 Docker 选项。别担心,将会有更多章节专门帮助你理解在运行容器时的卷挂载和存储。
4. 多阶段 Docker 文件
活动 4.01:使用多阶段 Docker 构建部署 Golang HTTP 服务器
解决方案:
- 为这个活动创建一个名为
activity-04-01的新目录:
mkdir activity-04-01
- 导航到新创建的
activity-04-01目录:
cd activity-04-01
- 在
activity-04-01目录中,创建一个名为main.go的文件:
$ touch main.go
- 现在,使用你喜欢的文本编辑器打开
main.go文件:
$ vim main.go
- 将以下内容添加到
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>")
}
- 在
activity-04-01目录中,创建一个名为Dockerfile的文件。这个文件将是多阶段Dockerfile:
touch Dockerfile
- 现在,使用你喜欢的文本编辑器打开
Dockerfile:
vim Dockerfile
- 将以下内容添加到
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有两个阶段,名为builder和runtime。构建阶段使用 Golang Docker 镜像作为父镜像,负责从 Golang 源文件创建可执行文件。运行时阶段使用alpine Docker 镜像作为父镜像,并执行从builder阶段复制的可执行文件。
- 现在,使用
docker build命令构建 Docker 镜像:
docker build -t activity-04-01:v1 .
您应该会得到以下输出:
图 4.14:构建 Docker 镜像
- 使用
docker imagels 命令列出计算机上所有可用的 Docker 镜像。验证镜像的大小:
docker images
该命令将返回所有可用的 Docker 镜像列表:
图 4.15:列出所有 Docker 镜像
在前面的输出中,您可以看到名为activity-04-01的优化 Docker 镜像的大小为 13.1 MB,而在构建阶段使用的父镜像(Golang 镜像)的大小为 370 MB。
- 执行
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
- 在您喜欢的网络浏览器中查看以下 URL 的应用程序:
http://127.0.0.1:8080/
当我们导航到 URL http://127.0.0.1:8080/时,以下图片显示了主页:
图 4.16:Golang 应用程序-主页
- 现在,在您喜欢的网络浏览器中浏览以下 URL:
http://127.0.0.1:8080/contact
当我们导航到 URL http://127.0.0.1:8080/contact时,以下图片显示了联系页面:
图 4.17:Golang 应用程序-联系我们页面
- 现在,在您喜欢的网络浏览器中输入以下 URL:
http://127.0.0.1:8080/login
当我们导航到 URL http://127.0.0.1:8080/login时,以下图片显示了登录页面:
图 4.18:Golang 应用程序-登录页面
在这个活动中,我们学习了如何部署一个 Golang HTTP 服务器,它可以根据调用 URL 返回不同的响应。在这个活动中,我们使用了多阶段的 Docker 构建来创建一个最小尺寸的 Docker 镜像。
5. 使用 Docker Compose 组合环境
活动 5.01:使用 Docker Compose 安装 WordPress
解决方案:
可以通过以下步骤创建数据库并安装 WordPress:
- 创建所需的目录并使用
cd命令进入其中:
mkdir wordpress
cd wordpress
- 创建一个名为
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: {}
- 使用
docker-compose up --detach命令启动应用程序:
图 5.22:应用程序的启动
- 使用
docker-compose ps命令检查正在运行的容器。您应该会得到以下输出:
图 5.23:WordPress 和数据库容器
- 在浏览器中打开
http://localhost:8080以检查 WordPress 设置屏幕:
图 5.24:WordPress 设置屏幕
在这个活动中,您使用 Docker Compose 创建了一个真实应用程序的部署。该应用程序包括一个数据库容器和一个 WordPress 容器。这两个容器服务都使用环境变量进行配置,通过 Docker Compose 网络和卷进行连接。
活动 5.02:使用 Docker Compose 安装全景徒步应用程序
解决方案:
可以通过以下步骤创建数据库和全景徒步应用程序:
- 创建所需的目录并切换到其中:
mkdir pta-compose
cd pta-compose
- 创建一个名为
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:
- 使用
docker-compose up --detach命令启动应用程序。您应该会得到类似以下的输出:
图 5.25:应用程序的启动
注意
您也可以使用docker-compose up -d命令来启动应用程序。
- 使用
docker-compose ps命令检查正在运行的容器。您应该会得到类似以下的输出:
图 5.26 应用程序、数据库和 nginx 容器
- 使用地址
http://0.0.0.0:8000/admin在浏览器中打开全景徒步应用程序的管理部分:
图 5.27:管理员设置登录
注意
您也可以运行firefox http://0.0.0.0:8000/admin命令来打开全景徒步应用程序的管理部分。
使用用户名admin和密码changeme登录,并添加新的照片和国家。将出现以下屏幕:
图 5.28:管理员设置视图
- 在浏览器中打开全景徒步应用程序,地址为
http://0.0.0.0:8000/photo_viewer:
图 5.29:应用程序视图
在此活动中,您使用 Docker Compose 创建了一个三层应用程序,其中包括用于 PostgreSQL 数据库、后端和代理服务的层。所有服务都使用 Docker Compose 进行配置和连接,具有其网络和存储功能。
6. Docker 网络简介
活动 6.01:利用 Docker 网络驱动程序
解决方案:
以下是根据最佳实践完成此活动的最常见方法:
- 使用
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。
- 使用
docker run命令创建一个 NGINX Web 服务器。使用-p标志将主机上的端口8080转发到容器实例上的端口80:
$ docker run -itd -p 8080:80 --name webserver1 --network webservernet nginx:latest
这将在webservernet网络中启动webserver1容器。
- 使用
docker run命令以host网络模式启动名为monitor的 Alpine Linux 容器。这样,您将知道容器可以访问主系统的主机端口以及bridge网络的 IP 地址:
$ docker run -itd --name monitor --network host alpine:latest
这将在host网络模式下启动一个 Alpine Linux 容器实例。
- 使用
docker inspect查找webserver1容器的 IP 地址:
$ docker inspect webserver1
容器的详细信息将以 JSON 格式显示;从IPAddress参数中获取 IP 地址:
图 6.27:检查 webserver1 容器实例
- 使用
docker exec命令在监控容器内部启动shshell:
$ docker exec -it monitor /bin/sh
这应该将您放入根 shell。
- 使用
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
- 使用
curl命令验证主机级别的连接是否正常工作,调用主机机器上的端口8080:
/ # curl -v http://localhost:8080
您应该收到来自 NGINX 的200 OK响应,表示在主机级别成功连接:
图 6.28:从主机上的暴露端口访问 webserver1 容器
- 同样,使用
curl命令直接通过端口80访问 Dockerbridge网络中容器的 IP 地址:
/ # curl -v 192.168.1.2:80
您应该同样收到另一个200 OK响应,表明连接成功:
图 6.29:从容器实例的 IP 地址访问 NGINX Web 服务器
在这个活动中,我们能够说明使用不同的 Docker 网络驱动程序在容器之间建立连接。这种情况适用于真实的生产基础设施,因为在部署容器化解决方案时,工程师们将努力部署尽可能不可变的基础设施。通过在 Docker 中部署容器,确切地模拟主机级别的网络,可以设计出需要在主机操作系统上进行非常少量配置的基础设施。这使得在部署和扩展 Docker 部署的主机时非常容易。诸如curl和其他监控工具的软件包可以部署到在 Docker 主机上运行的容器中,而不是安装在主机上。这保证了部署和维护的便利性,同时提高了满足不断增长的需求所需的主机部署速度。
活动 6.02:叠加网络实践
解决方案:
- 在 Docker swarm 集群中的
Machine1上使用docker network create命令创建一个名为panoramic-net的 Dockeroverlay网络,通过传递自定义的subnet、gateway和overlay网络驱动程序:
$ docker network create panoramic-net --subnet=10.2.0.0/16 --gateway=10.2.0.1 --driver overlay
- 在
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的服务。
- 在
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
- 使用
docker exec访问trekking-app服务容器内的shshell:
$ docker exec -it trekking-app.1.qhpwxol00geedkfa9p6qswmyv /bin/sh
这应该将您放入trekking-app容器实例内的根 shell 中。
- 使用
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 数据库中
解决方案:
- 运行以下命令以删除主机中的所有对象:
$ docker container rm -fv $(docker container ls -aq)
$docker image rm $(docker image ls -q)
- 获取卷名称,然后使用以下命令删除所有卷:
$docker volume ls
$docker volume rm <volume names separated by spaces>
- 获取网络名称,然后使用以下命令删除所有网络:
$docker network ls
$docker network rm <network names separated by spaces>
-
打开两个终端,一个专门用于查看
docker events --format '{{json .}}'的效果。另一个应该打开以执行先前提到的高级步骤。 -
在第一个终端中,运行以下命令:
docker events --format '{{json .}}'.
您应该得到以下输出:
图 7.11:docker events 命令的输出
- 运行以下命令在第二个终端中启动
ubuntu容器:
$docker run -d ubuntu:14.04
您应该得到以下输出:
图 7.12:docker run 命令的输出
- 使用第二个终端中的以下命令创建名为
vol1的卷:
$docker volume create vol1
- 使用第二个终端中的以下命令创建名为
net1的网络:
$docker network create net1
- 使用以下命令删除容器:
$docker container rm -fv <container ID>
- 使用以下命令删除卷和网络:
$docker volume rm vol1
$docker network rm net1
-
在
docker events终端中单击Ctrl + C以终止它。 -
检查以下两个示例以了解 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}
您会发现根据对象的不同属性和结构而有所不同。
- 运行带有卷的 PostgreSQL 容器。将容器命名为
db1:
$docker container run --name db1 -v db:/var/lib/postgresql/data -e POSTGRES_PASSWORD=password -d postgres
- 运行
exec命令,以便 bash 被要执行的命令替换。shell 将更改为posgres=#,表示您在容器内部:
$ docker container exec -it db1 psql -U postgres
- 创建一个具有两列的表:
ID为serial类型,info为json类型:
CREATE TABLE events (ID serial NOT NULL PRIMARY KEY, info json NOT NULL);
- 将第一个示例的
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}');
- 通过输入以下 SQL 语句验证数据库中是否保存了行:
select * from events;
您应该得到以下输出:
图 7.13:验证数据库中是否保存了行
- 使用 SQL 的
insert命令将 Docker 事件插入events表中。
注意
请参考packt.live/2ZKfGgB上的events.txt文件,使用insert命令插入 Docker 事件。
您应该得到以下输出:
图 7.14:在数据库中插入多行
从这个输出中,可以清楚地看到已成功将 11 个事件插入到 PostgreSQL 数据库中。
- 依次运行以下三个查询。
查询 1:
SELECT * FROM events WHERE info ->> 'status' = 'pull';
输出将如下所示:
图 7.15:查询 1 的输出
查询 2:
SELECT * FROM events WHERE info ->> 'status' = 'destroy';
输出将如下所示:
图 7.16:查询 2 的输出
查询 3:
SELECT info ->> 'id' as id FROM events WHERE info ->> 'status'= 'destroy';
输出将如下所示:
图 7.17:查询 3 的输出
在这个活动中,您学习了如何记录和监视容器,并使用 SQL 语句查询容器的事件,以及如何获得事件的 JSON 输出并保存在 PostgreSQL 数据库中。您还学习了 JSON 输出结构以及如何查询它。
活动 7.02:与主机共享 NGINX 日志文件
解决方案:
- 通过运行以下命令验证您的主机上是否没有
/var/mylogs文件夹:
$cd /var/mylogs
您应该得到以下输出:
Bash: cd: /var/mylogs: No such file or directory
- 基于 NGINX 镜像运行一个容器。在
run命令中指定主机和容器内共享卷的路径。在容器内,NGINX 使用/var/log/nginx路径存储日志文件。在主机上指定路径为/var/mylogs:
$docker container run -d -v /var/mylogs:/var/log/nginx nginx
如果您本地没有该镜像,Docker 引擎将自动拉取该镜像:
图 7.18:运行 docker run 命令的输出
- 进入
/var/mylogs路径。列出该目录中的所有文件:
$cd /var/mylogs
$ls
您应该在那里找到两个文件:
access.log error.log
- (可选)如果没有生成错误,这两个文件将是空的。你可以使用
catLinux 命令或者使用tailLinux 命令来检查内容。因为我们之前使用了cat命令,所以让我们在这个例子中使用tail命令:
$tail -f *.log
你应该得到以下的输出:
==> access.log <==
==> error.log <==
由于这个 NGINX 服务器没有生成任何错误或者没有被访问,这些文件目前是空的。然而,如果 NGINX 在任何时刻崩溃,生成的错误将会保存在error.log中。
在这个活动中,你学会了如何将容器的日志文件共享到主机上。你使用了 NGINX 服务器,所以如果它崩溃了,你可以从它的日志文件中追溯发生了什么。
8. 服务发现
活动 8.01:利用 Jenkins 和 SonarQube
解决方案:
- 安装 SonarQube 并使用以下命令作为容器运行:
docker run -d --name sonarqube -p 9000:9000 -p 9092:9092 sonarqube
你应该得到容器 ID 作为输出:
4346a99b506b1bec8000e429471dabac57e3f565b154ee921284ec685497bfae
- 使用
admin/admin凭据登录到 SonarQube:
图 8.38:登录到 SonarQube
成功登录后,应该出现类似以下的屏幕:
图 8.39:SonarQube 仪表板
-
在右上角,点击用户。会出现一个下拉菜单。点击
我的账户: -
向下滚动并点击
安全下的生成来生成一个令牌。你现在必须复制它,因为以后将无法访问它:
图 8.40:生成令牌
- 在 Jenkins 中,点击
管理 Jenkins>插件管理器。在可用列表中搜索Sonar。安装SonarQube Scanner插件。
图 8.41:安装 SonarQube Scanner 插件
- 通过点击
hit_count项目,然后点击配置选项来验证安装是否正确。在构建选项卡上点击添加构建步骤,然后点击执行 SonarQube Scanner,就像图 8.43中那样:
图 8.42:选择执行 SonarQube Scanner
- 然而,新的框将会生成错误,就像下面截图中显示的那样。为了纠正这个问题,通过
系统配置和全局工具配置选项将 SonarQube 和 Jenkins 集成起来:
图 8.43:由于 SonarQube 尚未配置而生成的错误
- 在 Jenkins 中,点击“管理 Jenkins”。点击“全局工具配置”选项,然后点击“添加 SonarQube 扫描仪”:
图 8.44:在全局工具配置页面上添加 SonarQube 扫描仪
- 输入名称“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 扫描仪添加详细信息
您现在已完成“全局工具配置”选项,现在是时候转到“配置系统”选项了。
- 在“管理 Jenkins”中,点击“配置系统”:
图 8.46:在管理 Jenkins 页面上点击配置系统
- 您现在无法进入系统配置,因为它要求“服务器身份验证令牌”。当您点击“添加”按钮时,它将不起作用。在以下步骤中将令牌输入为秘密文本,然后返回到“管理 Jenkins”:
图 8.47:在 Jenkins 配置中插入 SonarQube 令牌
- 点击“管理凭据”:
图 8.48:管理 Jenkins 页面
- 点击
Jenkins:
图 8.49:Jenkins 凭据页面
- 点击“全局凭据(不受限制)”:
图 8.50:全局凭据(不受限制)域
- 点击“添加一些凭据”:
图 8.51:添加一些凭据
- 在“类型”下拉菜单中,点击“秘密文本”:
图 8.52:选择类型为秘密文本
- 在“秘密”文本框中,粘贴您在本活动的步骤 5中复制的令牌。在
ID字段中,输入SonarQubeToken。点击“确定”:
图 8.53:将令牌添加到秘密文本框
SonarQubeToken将保存在“全局凭据”选项中。您将看到类似以下内容的屏幕:
图 8.54:SonarQubeToken 保存在全局凭据中
- 返回到“管理 Jenkins”。点击“配置系统”,然后点击“刷新”。现在,在“服务器身份验证令牌”下拉菜单中,您将找到
SonarQubeToken。勾选“启用将 SonarQube 服务器配置注入构建环境变量”。在“名称”字段中输入SonarQube。在“服务器 URL”字段中输入“http://<您的 IP>:9000”。然后点击“保存”:
您可以运行ifconfig命令来获取您的 IP。您将在输出的en0部分找到 IP:
$ ifconfig
这是将 Jenkins 与 SonarQube 集成的最后一步。让我们返回到项目中。
-
在“构建环境”中,勾选“准备 SonarQube 扫描器环境”。将“服务器身份验证令牌”设置为
SonarQubeToken: -
现在,点击项目名称,然后点击“配置”。在“构建”步骤中,在“分析属性”字段中输入以下代码:
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
点击“保存”。
- 保存后,您将在项目页面上看到 SonarQube 标志,如图 8.55所示。点击“立即构建”:
图 8.55:我们项目仪表板上显示 SonarQube 选项
- 在“构建历史”中,点击“控制台输出”。您应该会看到类似以下内容的屏幕:
图 8.56:控制台输出
-
在浏览器中检查
SonarQube的报告。输入http://<ip>:9000或http://localhost:9000。您将发现 Jenkins 自动将您的hit_count项目添加到 SonarQube 中: -
点击
hit_count。您将找到一个详细的报告。每当 Jenkins 构建项目时,SonarQube 将自动分析代码。
在本活动中,您学习了如何将 Jenkins 与 SonarQube 集成并安装所需的插件,通过在浏览器中检查 SonarQube 进行验证。您还将 SonarQube 应用于您的简单 Web 应用程序hit_counter。
活动 8.02:在全景徒步应用程序中利用 Jenkins 和 SonarQube
解决方案:
-
在 Jenkins 中创建一个名为
trekking的新项目。将其选择为FREESTYLE项目。点击“确定”。 -
在“常规”选项卡中,选择“丢弃旧构建”。
-
在“源代码管理”选项卡中,选择
GIT。然后输入 URLhttp://github.com/efoda/trekking_app:
图 8.57:插入 GitHub URL
- 在“构建触发器”中,选择“轮询 SCM”,并输入
H/15 * * * *:
图 8.58:插入调度代码
- 在“构建环境”选项卡中,选择“准备 SonarQube 扫描器环境”。从下拉菜单中选择“服务器身份验证令牌”:
图 8.59:选择 SonarQubeToken 作为服务器身份验证令牌
- 在“构建”选项卡中,在“分析属性”中输入以下代码:
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
点击“保存”。
- 选择“立即构建”。当构建成功完成时,选择“控制台输出”。以下输出将指示它已成功完成:
图 8.60:验证 Jenkins 已成功构建镜像
- 切换到浏览器中的
SonarQube选项卡,并检查输出。以下报告表明徒步应用程序有两个错误和零个安全漏洞:
图 8.61:在 SonarQube 浏览器选项卡中显示的报告
如果单击“新代码”,它将为空,因为您只构建了项目一次。当 Jenkins 再次构建它时,您将找到两次构建之间的比较。
- 如果您想编辑项目的代码,请将 GitHub 代码 fork 到您的帐户,并编辑代码以修复错误和漏洞。编辑项目的配置,使其使用您的 GitHub 代码,而不是“源代码”选项卡中提供的代码。
在这个活动中,您将 Jenkins 与 SonarQube 集成,并将其应用于全景徒步应用程序。在活动结束时,您将检查 SonarQube 生成的报告,显示代码中的错误和漏洞。
9. Docker Swarm
活动 9.01:将全景徒步应用部署到单节点 Docker Swarm
解决方案:
有许多方法可以执行此活动。以下步骤是其中一种方法:
- 为应用程序创建一个目录。在这种情况下,您将创建一个名为
Activity1的目录,并使用cd命令进入新目录:
mkdir Activity1; cd Activity1
- 从其 GitHub 存储库克隆应用程序,以确保您拥有部署到 Swarm 的 Panoramic Trekking App 服务所需的所有相关信息和应用程序:
git clone https://github.com/vincesesto/trekking_app.git
- 您不需要 NGINX 的任何支持目录,但请确保您的 Web 服务和运行的数据库在此处列出,包括
panoramic_trekking_app和photo_viewer目录以及Dockerfile、entrypoint.sh、manage.py和requirements.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
- 在目录中创建
.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
- 创建一个新的
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 镜像。
- 运行以下
docker build命令来构建镜像并适当地标记它:
docker build -t activity_web:latest .
- 现在是时候将堆栈部署到 Swarm 了。使用您创建的
docker-compose.yml文件运行以下stack deploy命令:
docker stack deploy --compose-file docker-compose.yml activity_swarm
创建网络后,您应该看到activity_swarm_web和activity_swarm_db服务可用:
Creating network activity_swarm_default
Creating service activity_swarm_web
Creating service activity_swarm_db
- 运行
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
- 最后,打开您的网络浏览器,并验证您能够从
http://localhost:8000/admin/和http://localhost:8000/photo_viewer/访问该网站。
Panoramic Trekking App 的创建和设置方式与本章中已经完成的一些其他服务类似。
活动 9.02:在 Swarm 运行时执行应用程序更新
解决方案:
有许多种方法可以执行此活动。以下步骤详细说明了一种方法:
- 如果您没有运行 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
- 在执行
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。
- 构建一个新图像,这次使用以下命令将图像标记为
patch_1:
docker build -t activity_web:patch_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
- 列出正在运行的服务,并验证新图像是否作为
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
- 通过访问
http://localhost:8000/photo_viewer/并查看标题现在显示为Patch Panoramic Trekking App来验证更改是否已应用于图像:
图 9.10:全景徒步应用程序的 Patch 版本
在此活动中,您对全景徒步应用程序进行了微小更改,以便可以对服务进行滚动更新。然后,您将图像部署到运行环境中,并执行滚动更新以验证更改是否成功。标题中的更改表明滚动更新已成功执行。
10. Kubernetes
活动 10.01:在 Kubernetes 上安装全景徒步应用程序
解决方案:
可以通过以下步骤创建数据库和全景徒步应用程序:
- 使用以下
helm命令安装数据库:
helm install database stable/postgresql --set postgresqlPassword=kubernetes
这将为 PostgreSQL 安装多个 Kubernetes 资源,并显示摘要如下:
图 10.23:数据库安装
此输出首先列出与 Helm 图表相关的信息,例如名称、部署时间、状态和修订版本,然后是与 PostgreSQL 实例相关的信息以及如何访问它。这是 Helm 图表中广泛接受的方法,在安装图表后提供此类信息。否则,将很难学习如何连接到 Helm 安装的应用程序。
- 创建一个
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部分定义了两个名为nginx和pta的容器。此外,还定义了一个名为static的卷索赔,并将其挂载到两个容器上。
- 使用以下命令部署
panoramic-trekking-appStatefulSet:
kubectl apply -f statefulset.yaml
这将为我们的应用程序创建一个 StatefulSet:
StatefulSet.apps/panoramic-trekking-app created
- 创建一个
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端口。
- 使用以下命令部署
panoramic-trekking-app服务:
kubectl apply -f service.yaml
这将创建以下 Service 资源:
Service/panoramic-trekking-app created
- 使用以下命令获取 Service 的 IP:
minikube service panoramic-trekking-app --url
http://192.168.64.14:32009
在以下步骤中存储 IP 以访问 Panoramic Trekking App。
- 在浏览器中打开 Panoramic Trekking App 的管理部分,网址为
http://$SERVICE_IP/admin:
图 10.24:管理员登录视图
- 使用用户名
admin和密码changeme登录,并添加新的照片和国家:
图 10.25:管理员设置视图
- 在浏览器中打开 Panoramic Trekking App,网址为
http://$SERVICE_IP/photo_viewer:
图 10.26:应用程序视图
照片查看器应用程序显示已从数据库中检索到照片和国家。它还表明应用程序已正确设置并且正常运行。
在这个活动中,您已经将 Panoramic Trekking App 部署到了 Kubernetes 集群。您首先使用其 Helm 图表创建了一个数据库,然后为应用程序创建了 Kubernetes 资源。最后,您从浏览器访问了应用程序,并通过添加新的照片进行了测试。在这个活动结束时,您已经了解了如何使用官方 Helm 图表部署数据库,创建一系列 Kubernetes 资源来连接数据库并部署应用程序,并从集群中收集信息以访问应用程序。该活动中的步骤涵盖了在 Kubernetes 集群中部署容器化应用程序的生命周期。
11. Docker 安全
活动 11.01:为 Panoramic Trekking App 设置 seccomp 配置文件
解决方案:
有多种方法可以创建一个seccomp配置文件,阻止用户执行mkdir、kill和uname命令。以下步骤展示了如何完成这一操作:
- 如果你本地没有
postgres镜像,请执行以下命令:
docker pull postgres
- 在你的系统上使用
wget命令获取默认的seccomp配置文件的副本。将你下载的文件命名为activity1.json:
wget https://raw.githubusercontent.com/docker/docker/v1.12.3/profiles/seccomp/default.json - O activity1.json
- 从配置文件中删除以下三个命令,以允许我们进一步锁定我们的镜像。用你喜欢的文本编辑器打开
activity1.json文件,并从文件中删除以下行。你应该删除行 1500到1504以删除uname命令,669到673以删除mkdir命令,以及行 579到583以删除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。
- 使用
–-security-opt seccomp=activity1.json选项在运行镜像时为postgres镜像分配一个新配置文件:
docker run --rm -it --security-opt seccomp=activity1.json postgres sh
- 现在你已经登录到正在运行的容器中,测试你已经分配给容器的新配置文件的权限。执行
mkdir命令在系统上创建一个新目录:
~ $ mkdir test
该命令应该显示一个Operation not permitted的输出:
mkdir: can't create directory 'test': Operation not permitted
- 为了测试你不再能够杀死正在运行的进程,你需要启动一些东西。启动
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镜像的容器中不可用ps和top命令。然而,这不会造成任何问题,因为用任意随机的 pid 号运行kill命令足以证明该命令不被允许运行。
- 使用
kill -9命令杀死top进程,后面跟着你想要杀死的进程的 PID 号。kill -9命令将尝试强制停止命令:
~ $ kill -9 8
你应该看到Operation not permitted:
sh: can't kill pid 8: Operation not permitted
- 测试
uname命令。这与其他命令有些不同:
~ $ uname
你将得到一个Operation not permitted的输出:
Operation not permitted
这是一个很好的活动,表明如果我们的镜像被攻击者访问,我们仍然可以采取很多措施来限制对它们的操作。
活动 11.02:扫描您的全景徒步应用镜像的漏洞
解决方案:
有许多方法可以扫描我们的镜像以查找漏洞。以下步骤是使用 Anchore 来验证postgres-app镜像是否对我们的应用程序安全的一种方法:
- 给镜像打标签并将其推送到您的 Docker Hub 仓库。在这种情况下,使用我们的仓库名称给
postgres-app镜像打标签,并将其标记为activity2。我们还将其推送到我们的 Docker Hub 仓库:
docker tag postgres <your repository namespace>/postgres-app:activity2 ; docker push <your repository name>/postgres-app:activity2
- 您应该仍然拥有您在本章最初使用的
docker-compose.yaml文件。如果您还没有运行 Anchore,请运行docker-compose命令并导出ANCHORE_CLI_URL、ANCHORE_CLI_URL和ANCHORE_CLI_URL变量,就像您之前做的那样,以便我们可以运行anchore-cli命令:
docker-compose up -d
- 通过运行
anchore-cli system status命令来检查 Anchore 应用的状态:
anchore-cli system status
- 使用
feeds list命令来检查 feeds 列表是否都已更新:
anchore-cli system feeds list
- 一旦所有的 feeds 都已经更新,添加我们推送到 Docker Hub 的
postgres-app镜像。使用anchore-cli提供的image add命令,并提供我们想要扫描的镜像的仓库、镜像和标签。这将把镜像添加到我们的 Anchore 数据库中,准备进行扫描:
anchore-cli image add <your repository namespace>/postgres-app:activity2
- 使用
image list命令来验证我们的镜像是否已经被分析。一旦完成,您应该在Analysis Status列中看到analyzed这个词:
anchore-cli image list
- 使用我们的镜像名称执行
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
- 最后,使用
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服务:
- 创建一个脚本,将创建一个新表并用随机值填充它。以下脚本正是我们在这种情况下想要的,因为我们想创建一个长时间的处理查询,并查看它如何影响我们容器上的资源。添加以下细节,并使用您喜欢的编辑器将文件保存为
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 行遍历一个新表,用随机值填充它。
- 如果您还没有 PostgreSQL Docker 镜像的副本,请使用以下命令从受支持的 PostgreSQL Docker Hub 存储库中拉取镜像:
docker pull postgres
- 进入新的终端窗口并运行
docker stats命令,查看正在使用的CPU百分比,以及正在使用的内存和内存百分比:
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemPerc}}\t{{.MemUsage}}"
在以下命令中,我们没有显示容器 ID,因为我们希望限制输出中显示的数据量:
NAME CPU % MEM % MEM USAGE / LIMIT
- 要简单测试这个镜像,您不需要将运行的容器挂载到特定卷上,以使用您先前为此镜像使用的数据。切换到另一个终端来监视您的 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
- 在运行测试脚本之前,切换到监视 CPU 和内存使用情况的终端。您可以看到我们的容器已经在没有真正做任何事情的情况下使用了一些资源:
NAME CPU % MEM % MEM USAGE / LIMIT
postgres-test 0.09% 0.47% 9.273MiB / 1.943GiB
- 使用以下命令进入容器内的终端:
docker exec -it postgres-test /bin/bash
- 使用
psql命令发送postgres-test容器命令以创建名为resource_test的新数据库:
psql -h localhost -U postgres -d postgres -c 'create database resource_test;'
Password for user postgres:
CREATE DATABASE
- 运行您之前创建的脚本。确保在运行脚本之前包括
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
- 移动到运行
docker stats命令的终端。您将看到一个输出,取决于系统运行的核心数量和可用的内存。正在运行的脚本似乎不太耗费内存,但它正在将容器可用的 CPU 推高到 100%:
NAME CPU % MEM % MEM USAGE / LIMIT
postgres-test 100.66% 2.73% 54.36MiB / 1.943GiB
- 在对 CPU 和内存配置进行更改后运行容器之前,删除正在运行的容器,以确保您有一个新的数据库运行,使用以下命令:
docker kill postgres-test
- 再次运行容器。在这种情况下,您将将可用的 CPU 限制为主机系统上一半的一个核心,并且由于测试不太耗费内存,将内存限制设置为
256MB:
docker run --rm --name postgres-test -e POSTGRES_PASSWORD=docker -d -p 5432:5432 --cpus 0.5 --memory 256MB postgres
- 使用
exec命令进入容器:
docker exec -it postgres-test /bin/bash
- 再次,在运行测试之前,创建
resource_test数据库:
psql -h localhost -U postgres -d postgres -c 'create database resource_test;'
Password for user postgres:
CREATE DATABASE
- 现在,为了查看对我们的资源所做的更改,限制容器可以使用的资源。再次运行
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
- 移动到运行
docker stats命令的终端。它看起来也会有所不同,因为可用于使用的 CPU 百分比将减半。您对 CPU 所做的更改减慢了脚本的运行,并且似乎也减少了内存的使用:
NAME CPU % MEM % MEM USAGE / LIMIT
postgres-test 48.52% 13.38% 34.25MiB / 256MiB
这项活动为您提供了一个很好的指示,有时您需要执行平衡的行为,当您监视和配置容器资源时。它确实澄清了您需要了解您的服务正在执行的任务,以及对配置的更改将如何影响您的服务的运行方式。
活动 12.02:使用 hadolint 改进 Dockerfile 的最佳实践
解决方案
有许多种方法可以执行此活动。以下步骤展示了一种方法:
- 使用以下
docker pull命令从hadolint存储库中拉取镜像:
docker pull hadolint/hadolint
- 使用
hadolint来检查我们在本章中一直在使用的docker-stressDockerfile并记录所呈现的警告:
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呈现的警告数量。
- 正如本章前面提到的,
hadolint维基页面将为你提供如何解决所呈现的每个警告的详细信息。然而,如果你逐行进行,应该能够解决所有这些警告。首先呈现的DL3006要求标记你正在使用的 Docker 镜像版本,这是 Ubuntu 镜像的新版本。将你的Dockerfile的行 1更改为现在包括18.08镜像版本,如下所示:
1 FROM ubuntu:18.08
- 接下来的四个警告都与我们
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/*
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}"]
- 现在,再次使用
hadolint对Dockerfile进行检查,不再呈现任何警告:
docker run --rm -i hadolint/hadolint < Dockerfile
- 如果你想百分之百确定
Dockerfile看起来尽可能好,进行最后一次测试。在浏览器中打开FROM:latest,你会看到Dockerfile显示最新更改时的没有找到问题或建议!:
图 12.4:docker-stress Dockerfile 现在遵循最佳实践
您的Dockerfiles可能比本章中呈现的要大得多,但是正如您所看到的,逐行系统地处理将帮助您纠正Dockerfiles可能存在的任何问题。使用诸如hadolint和FROM latest之类的应用程序,以及它们关于如何解决警告的建议,将使您熟悉随着实践而来的最佳实践。这就是我们活动和本章的结束,但是还有更多有趣的内容要学习,所以现在不要停下来。
13.监控 Docker 指标
活动 13.01:创建 Grafana 仪表板以监控系统内存
解决方案:
有许多方法可以执行此活动。以下步骤是一种方法:
-
确保 Prometheus 正在运行和收集数据,Docker 和
cAdvisor已配置为公开指标,并且 Grafana 正在运行并配置为使用 Prometheus 作为数据源。 -
打开 Grafana Web 界面和您在练习 13.05:在您的系统上安装和运行 Grafana中创建的
Container Monitoring仪表板 -
仪表板顶部和仪表板名称右侧有一个“添加面板”的选项。单击“添加面板”图标以添加新的仪表板面板:
图 13.26:向容器监控仪表板添加新面板
-
从下拉列表中选择
Prometheus作为我们将使用的数据源,以生成新的仪表板面板。 -
在
metrics部分,添加以下 PromQL 查询,container_memory_usage_bytes,仅搜索具有名称值的条目。然后,按每个名称求和,为每个容器提供一条线图:
sum by (name) (container_memory_usage_bytes{name!=""})
- 根据时间序列数据库中可用的数据量进行调整相对时间(如果需要)。也许将相对时间设置为
15m。前三个步骤如下图所示:
图 13.27:向容器监控仪表板添加新面板
-
选择“显示选项”并添加“内存容器使用”作为标题。
-
如果单击“保存”,您会注意到无法保存面板,因为仪表板已在启动时进行了配置。您可以导出 JSON,然后将其添加到您的配置目录中。单击“共享仪表板”按钮并导出 JSON。选择“将 JSON 保存到文件”并将仪表板文件存储在“/tmp 目录”中:
图 13.28:警告,我们无法保存新的仪表板
- 停止运行 Grafana 容器,以便您可以添加到环境中的配置文件。使用以下
docker kill命令执行此操作:
docker kill grafana
- 您已经在
provisioning/dashboards目录中有一个名为ContainerMonitoring.json的文件。从您的tmp目录中复制刚创建的 JSON 文件,并替换provisioning/dashboards目录中的原始文件:
cp /tmp/ContainerMonitoring-1579130313205.json provisioning/dashboards/ContainerMonitoring.json
- 再次启动 Grafana 图像,并使用默认管理密码登录应用程序:
docker run --rm -d --name grafana -p 3000:3000 -e "GF_SECURITY_ADMIN_PASSWORD=secret" -v ${PWD}/provisioning:/etc/grafana/provisioning grafana/Grafana
- 再次登录到 Grafana,并转到您一直在配置的“容器监控”仪表板。您现在应该在我们的仪表板顶部看到新创建的“内存容器使用情况”面板,类似于以下屏幕截图:
图 13.29:显示内存使用情况的新仪表板面板
现在应该更容易监视系统上运行的容器的内存和 CPU 使用情况。仪表板提供了比查看docker stats命令更简单的界面,特别是当您开始在系统上运行更多容器时。
活动 13.02:配置全景徒步应用程序向 Prometheus 公开指标
解决方案:
我们可以以多种方式执行此活动。在这里,我们选择向全景徒步应用程序的 PostgreSQL 容器添加导出器:
- 如果您没有全景徒步应用程序在运行,请确保至少 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。
- 上述的 GitHub 帐户有一个很好的分解如何设置配置和指标。设置一个基本的配置文件以开始。通过运行以下
docker inspect命令找到 PostgreSQL 容器正在运行的 IP 地址。这会给出容器正在运行的内部 IP 地址。您还需要替换您正在运行的容器名称为<container_name>:
docker inspect --format '{{ .NetworkSettings.IPAddress }}' <container_name>
您的 IP 地址可能与此处的不同:
172.17.0.3
-
对于这个导出器,您需要设置一些额外的配置来输入到导出器中。首先,在您的工作目录中创建一个名为
psql_exporter_config.yml的配置文件,并用文本编辑器打开该文件。 -
在下面的配置文件中输入前四行。这是导出器连接到数据库的方式。您需要提供可以访问数据库的密码以及在上一步中获得的 IP 地址,或者如果为数据库分配了域,则需要提供域:
1 databases:
2 pg:
3 dsn: postgresql+psycopg2://postgres:<password>@<ip|domain>/ postgres
4
- 将您的第一个指标添加到配置文件中。输入以下行以添加指标名称、规模类型、描述和标签:
5 metrics:
6 pg_process:
7 type: gauge
8 description: Number of PostgreSQL processes with their states
9 labels: [state]
10
- 设置一个数据库查询,以收集您想要用于
pg_process规模的指标详细信息。第 13 行显示您想要创建一个数据库查询,第 14和15 行将结果分配给您之前创建的指标。第 16至23 行是我们想要在数据库上运行的查询,以便为数据库上运行的进程数量创建一个规模:
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。
- 保存配置文件并从命令行运行导出器。导出器将在端口
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
- 打开一个网络浏览器,使用 URL
http://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
- 进入您安装了 Prometheus 的目录,用您喜欢的文本编辑器打开
prometheus.yml文件,并添加导出器详细信息,以允许 Prometheus 开始收集数据:
45 - job_name: 'postgres-web'
46 scrape_interval: 5s
47 static_configs:
48 - targets: ['0.0.0.0:9560']
- 保存您对
prometheus.yml文件所做的更改,并再次从命令行启动 Prometheus 应用程序,如下所示:
./prometheus --config.file=prometheus.yml
- 如果一切都按照应该的方式进行了,您现在应该在 Prometheus 的
Targets页面上看到postgres-web目标,如图所示:
图 13.30:在 Prometheus 上显示的新的 postgres-web 目标页面
这就是活动的结束,也是本章的结束。这些活动应该有助于巩固之前学到的知识,并为您提供了在更加用户友好的方式中收集应用程序和运行系统的指标的经验。
14. 收集容器日志
活动 14.01:为您的 Splunk 安装创建一个 docker-compose.yml 文件
解决方案:
有许多方法可以执行这项活动。以下步骤概述了一种可能的方法。
在这里,您将设置一个docker-compose.yml文件,该文件至少会以与本章中一直运行的方式运行您的 Splunk 容器。您将设置两个卷,以便挂载/opt/splunk/etc目录,以及/opt/splunk/var目录。您需要公开端口8000、9997和8088,以允许访问您的 Web 界面并允许数据转发到 Splunk 实例。最后,您需要设置一些环境变量,以接受 Splunk 许可证并添加管理员密码。让我们开始吧:
-
创建一个名为
docker-compose.yml的新文件,并用您喜欢的文本编辑器打开它。 -
从您喜欢的
Docker Compose版本开始,并创建要用于挂载var和ext目录的卷:
1 version: '3'
2
3 volumes:
4 testsplunk:
5 testsplunkindex:
6
- 使用
splunk作为主机名和splunk/splunk作为您安装的镜像来设置 Splunk 安装的服务。此外,设置SPLUNK_START_ARGS和SPLUNK_PASSWORD的环境变量,如下所示:
7 services:
8 splunk:
9 hostname: splunk
10 image: splunk/splunk
11 environment:
12 SPLUNK_START_ARGS: --accept-license
13 SPLUNK_PASSWORD: changeme
- 最后,挂载卷并公开安装所需的访问 Web 界面和从转发器和容器转发数据的端口:
14 volumes:
15 - ./testsplunk:/opt/splunk/etc
16 - ./testsplunkindex:/opt/splunk/var
17 ports:
18 - "8000:8000"
19 - "9997:9997"
20 - "8088:8088"
- 运行
docker-compose up命令,确保一切都正常工作。使用-d选项确保它作为后台守护程序在我们系统中运行:
docker-compose up -d
该命令应返回类似以下的输出:
Creating network "chapter14_default" with the default driver
Creating chapter14_splunk_1 ... done
- 一旦您的 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。
- 登录 Splunk Web 界面并访问
搜索和报告应用程序。在界面中输入source="http:docker logs" AND postgres-test查询,然后按Enter。由于您已经给我们的容器打了标签,您应该会看到您的容器带有名称和完整 ID 的标签,因此在搜索中添加postgres-test将确保只有您的 PostgreSQL 日志可见:
图 14.48:Splunk 中显示的 PostgreSQL 日志
从前面的屏幕截图中可以看出,我们的日志已经成功地通过 Splunk 流动。请注意在日志条目中添加的标签,就像前面的屏幕截图中所示的那样。
这项活动教会了我们如何在开发项目中使用 Docker Compose 实施日志记录程序。
活动 14.02:创建一个 Splunk 应用程序来监视 Panoramic Trekking App
解决方案:
有许多方法可以执行这项活动。以下步骤是一种方法。在这里,您将向作为 Panoramic Trekking App 的一部分正在运行的PostgreSQL容器添加一个导出器:
-
确保 Splunk 正在运行,并且您一直在监视的服务已经运行了一段时间,以确保您正在为这项活动收集一些日志。
-
登录 Splunk Web 界面。从 Splunk 主屏幕上,点击
应用程序菜单旁边的齿轮图标;您将看到您的 Splunk 环境的应用程序页面:
图 14.49:Splunk 环境的应用程序页面
- 点击“创建”应用按钮并填写表格。表格将类似于以下内容,其中“名称”设置为“全景徒步应用”,“文件夹名称”设置为
panoramic_trekking_app,“版本”设置为1.0.0。点击“保存”以创建新应用:
图 14.50:在 Splunk 中创建您的新应用
- 返回到 Splunk 主页,并确保您的“全景徒步应用”从“应用”菜单中可见。点击“全景徒步应用”以打开“搜索和报告”页面,以便您可以开始查询您的数据:
图 14.51:选择全景徒步应用
- 在查询栏中输入
source="http:docker logs" AND postgres-test AND INSERT AND is_superuser | stats count,然后按 Enter 键。搜索将查找作为应用程序的一部分创建的任何“超级用户”。当您的数据出现时,点击“可视化”选项卡,并将其更改为显示单个值的可视化:
图 14.52:在查询栏中输入查询
- 点击屏幕顶部的“另存为”按钮,然后选择“仪表板”面板。当您看到此屏幕时,选择要添加到新仪表板的面板,并将其命名为“PTA 监控”。还要给面板命名为“超级用户访问”,然后点击“保存”:
图 14.53:向仪表板面板添加详细信息
- 当您看到新的仪表板时,点击“编辑”和“添加”面板按钮。选择“新建”,然后选择“单个值”作为可视化类型。将“内容标题”设置为“数据库创建”。添加
source="http:docker logs" AND postgres-test AND CREATE DATABASE | stats count源字符串,然后点击“保存”。这将通过日志搜索以显示是否有人在 PostgreSQL 数据库上创建了任何数据库,这应该只在设置和创建应用程序时发生:
图 14.54:编辑仪表板面板
-
再次点击“新面板”按钮,选择“新建”,然后从可视化中选择“柱状图”。添加一个“内容标题”为“应用使用情况”,添加
source="http:docker logs" AND postgres-test AND SELECT AND photo_viewer_photo earliest=-60m | timechart span=1m count搜索查询,并点击“保存”。这个搜索将为您提供一段时间内使用应用程序查看照片的人数。 -
随意移动仪表板上的面板。当您对更改感到满意时,点击“保存”按钮。您的仪表板应该看起来类似于以下内容:
图 14.55:用于监视 PostgreSQL 使用情况的新仪表板面板
这个活动帮助您收集 Panoramic Trekking App 的日志数据,并使用 Splunk 以更用户友好的方式显示它。
15. 使用插件扩展 Docker
活动 15.01:使用网络和卷插件安装 WordPress
解决方案:
可以使用以下步骤使用卷和网络插件为数据库和 WordPress 博客创建容器:
- 使用以下命令创建一个网络:
docker network create \
--driver=store/weaveworks/net-plugin:2.5.2 \
--attachable \
wp-network
这个命令使用 Weave Net 插件创建一个网络,并使用driver标志进行指定。此外,卷被指定为attachable,这意味着您可以在将来连接到 Docker 容器。最后,容器的名称将是wp-network。您应该得到以下输出:
mk0pmhpb2gx3f6s00o57j2vd
- 使用以下命令创建一个卷:
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
- 使用以下命令创建
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连接。
- 使用以下命令创建
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上可用。
成功启动后,您将有两个运行中的mysql和wordpress容器:
docker ps
图 15.17:WordPress 和数据库容器
- 在浏览器中打开
http://localhost:8080,以检查 WordPress 设置屏幕:
图 15.18:WordPress 设置屏幕
WordPress 设置屏幕验证了 WordPress 是否使用了网络和卷插件。
在这个活动中,您使用 Weave Net 插件创建了一个自定义网络,并使用sshfs插件创建了一个自定义卷。您创建了一个使用自定义网络的数据库容器,以及一个使用自定义网络和自定义卷的 WordPress 容器。通过成功的设置,您的 Docker 容器可以通过自定义网络相互连接,并通过 SSH 使用卷。通过这个活动,您已经为一个真实的应用程序使用了 Docker 扩展。现在您可以自信地根据自己的业务需求和技术扩展 Docker。