Docker 管理监控平台
当 Docker
引擎中管理的镜像、容器、网络等对象数量变得越来越多时,通过简单的 docker
命令来管理已经显得使人力不从心了。于是就出现了很多的 Docker
可视化管理平台。我们这里对现在较流行的、使用较多的几种平台进行介绍。
1. Docker UI
1.1 简介
Docker UI
是一个开源的基于 Docker API
的 web
应用程序,提供等同 Docker
命令行的大部分功能,支持 container
管理,image
管理。它最值得称道的是它华丽的设计和用来运行和管理 docker
的简洁的操作界面。
1.2 安装
1.2.1 拉取镜像
docker pull uifd/ui-for-docker
拉取 docker ui 的镜像。
docker pull uifd/ui-for-docker
1.2.2 启动容器
启动 docker ui
容器。
docker run -dp 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock uifd/ui-for-docker
1.3 访问
在浏览器中通过 docker
主机的 IP
及 9000
端口号可以打开 docker
管理平台。在管理平台中,通过导航栏可打开相关 docker
对象的的管理页面。
打开对象管理页面,对对象的所有操作都在 Actions
中。
2. Portainer
2.1 简介
Portainer
是一个可视化的容器镜像的图形管理工具,利用 Portainer
可以轻松构建,管理和维护 Docker
环境。 而且完全免费,基于容器化的安装方式,方便高效部署。其官网为:https://www.portainer.io/。
2.2 安装
2.2.1 拉取镜像
docker pull portainer/portainer-ce
2.2.2 新建数据卷
单独新建一个数据卷
docker volume create portainer_data
2.2.3 启动容器
为了能使用 http
协议进行访问,这里又新增了 9000
端口号。另外,这里还使用了portainer_data
数据卷。
docker run -d -p 8000:8000 -p 9443:9443 -p 7100:9000 \
--name portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:latest
上面那句话的意思:如果你要使用http来访问,那么你要使用到9000端口,所以我这里端口映射为7100->9000
2.3 访问
通过 http
协议访问。
通过 https
协议访问。
这里输入了 8 个 1 作为密码。进入下个页面
然后通过导航栏或快速链接,可对相应的对象进行管理。
3. shipyard
3.1 简介
shipyard
是 docker
的 web
可视化界面管理工具,是建立在 docker
集群管理工具 Citadel
之上,可以管理镜像、容器、主机等资源的 web
图形化工具,包括 core
和 extension
两个版本,core
即 shipyard
主要是把多个 Docker host
上的 containers
统一管理(支持跨越多个host),extension
即 shipyard-extensions
添加了应用路由和负载均衡、集中化日志、部署等。Shipyard
是在 Docker Swarm
实现对容器、镜像、docker
集群、仓库、节点进行管理的 web
系统。其官网为: https://shipyard-project.com。
3.2 安装
shipyard
的安装有两种方式:自动安装与手动安装。由于手动安装比较麻烦,需要手动拉取很多镜像并启动与之对应的容器,所以一般都是使用自动安装方式。不过,手动安装的好处是,可以根据功能选择性的拉取镜像、启动容器。而自动安装则是通过运行一个部署脚本文件,实现自动拉取全部镜像并启动这些容器。
3.2.1 脚本内容
以下是 shipyard
自动部署的脚本内容。复制该内容后在 Linux
系统中新建一个名称为deploy
的文件。这里在/root
下新建了一个名称为 shipyard
的目录,在该目录中新建了 deploy
文件。
#!/bin/bash
if [ "$1" != "" ] && [ "$1" = "-h" ]; then
echo "Shipyard Deploy uses the following environment variables:"
echo " ACTION: this is the action to use (deploy, upgrade, node, remove)"
echo " DISCOVERY: discovery system used by Swarm (only if using 'node' action)"
echo " IMAGE: this overrides the default Shipyard image"
echo " PREFIX: prefix for container names"
echo " SHIPYARD_ARGS: these are passed to the Shipyard controller container as controller args"
echo " TLS_CERT_PATH: path to certs to enable TLS for Shipyard"
echo " PORT: specify the listen port for the controller (default: 8080)"
echo " IP: specify the address at which the controller or node will be available (default: eth0 ip)"
echo " PROXY_PORT: port to run docker proxy (default: 2375)"
exit 1
fi
if [ -z "`which docker`" ]; then
echo "You must have the Docker CLI installed on your \$PATH"
echo " See http://docs.docker.com for details"
exit 1
fi
ACTION=${ACTION:-deploy}
IMAGE=${IMAGE:-dockerclub/shipyard:latest}
PREFIX=${PREFIX:-shipyard}
SHIPYARD_ARGS=${SHIPYARD_ARGS:-""}
TLS_CERT_PATH=${TLS_CERT_PATH:-}
CERT_PATH="/etc/shipyard"
PROXY_PORT=${PROXY_PORT:-2376}
SWARM_PORT=3375
SHIPYARD_PROTOCOL=http
SHIPYARD_PORT=${PORT:-8080}
SHIPYARD_IP=${IP}
DISCOVERY_BACKEND=etcd
DISCOVERY_PORT=4001
DISCOVERY_PEER_PORT=7001
ENABLE_TLS=0
CERT_FINGERPRINT=""
LOCAL_CA_CERT=""
LOCAL_SSL_CERT=""
LOCAL_SSL_KEY=""
LOCAL_SSL_CLIENT_CERT=""
LOCAL_SSL_CLIENT_KEY=""
SSL_CA_CERT=""
SSL_CERT=""
SSL_KEY=""
SSL_CLIENT_CERT=""
SSL_CLIENT_KEY=""
show_cert_help() {
echo "To use TLS in Shipyard, you must have existing certificates."
echo "The certs must be named ca.pem, server.pem, server-key.pem, cert.pem and key.pem"
echo "If you need to generate certificates, see https://github.com/ehazlett/certm for examples."
}
check_certs() {
if [ -z "$TLS_CERT_PATH" ]; then
return
fi
if [ ! -e $TLS_CERT_PATH ]; then
echo "Error: unable to find certificates in $TLS_CERT_PATH"
show_cert_help
exit 1
fi
if [ "$PROXY_PORT" = "2375" ]; then
PROXY_PORT=2376
fi
SWARM_PORT=3376
SHIPYARD_PROTOCOL=https
LOCAL_SSL_CA_CERT="$TLS_CERT_PATH/ca.pem"
LOCAL_SSL_CERT="$TLS_CERT_PATH/server.pem"
LOCAL_SSL_KEY="$TLS_CERT_PATH/server-key.pem"
LOCAL_SSL_CLIENT_CERT="$TLS_CERT_PATH/cert.pem"
LOCAL_SSL_CLIENT_KEY="$TLS_CERT_PATH/key.pem"
SSL_CA_CERT="$CERT_PATH/ca.pem"
SSL_CERT="$CERT_PATH/server.pem"
SSL_KEY="$CERT_PATH/server-key.pem"
SSL_CLIENT_CERT="$CERT_PATH/cert.pem"
SSL_CLIENT_KEY="$CERT_PATH/key.pem"
CERT_FINGERPRINT=$(openssl x509 -noout -in $LOCAL_SSL_CERT -fingerprint -sha256 | awk-F= '{print $2;}')
if [ ! -e $LOCAL_SSL_CA_CERT ] || [ ! -e $LOCAL_SSL_CERT ] || [ ! -e $LOCAL_SSL_KEY ] || [ !
-e $LOCAL_SSL_CLIENT_CERT ] || [ ! -e $LOCAL_SSL_CLIENT_KEY ]; then
echo "Error: unable to find certificates"
show_cert_help
exit 1
fi
}
# container functions
start_certs() {
ID=$(docker run \
-ti \
-d \
--restart=always \
--name $PREFIX-certs \
-v $CERT_PATH \
alpine \
sh)
if [ $ENABLE_TLS = 1 ]; then
docker cp $LOCAL_SSL_CA_CERT $PREFIX-certs:$SSL_CA_CERT
docker cp $LOCAL_SSL_CERT $PREFIX-certs:$SSL_CERT
docker cp $LOCAL_SSL_KEY $PREFIX-certs:$SSL_KEY
docker cp $LOCAL_SSL_CLIENT_CERT $PREFIX-certs:$SSL_CLIENT_CERT
docker cp $LOCAL_SSL_CLIENT_KEY $PREFIX-certs:$SSL_CLIENT_KEY
fi
}
remove_certs() {
docker rm -fv $PREFIX-certs > /dev/null 2>&1
}
get_ip() {
if [ -z "$SHIPYARD_IP" ]; then
SHIPYARD_IP=`docker run --rm --net=host alpine ip route get 8.8.8.8 | awk '{ print$7; }'`
fi
}
start_discovery() {
get_ip
ID=$(docker run \
-ti \
-d \
-p 4001:4001 \
-p 7001:7001 \
--restart=always \
--name $PREFIX-discovery \
microbox/etcd:latest -addr $SHIPYARD_IP:$DISCOVERY_PORT -peer-addr $SHIPYARD_IP:$DISCOVERY_PEER_PORT)
}
remove_discovery() {
docker rm -fv $PREFIX-discovery > /dev/null 2>&1
}
start_rethinkdb() {
ID=$(docker run \
-ti \
-d \
--restart=always \
--name $PREFIX-rethinkdb \
rethinkdb)
}
remove_rethinkdb() {
docker rm -fv $PREFIX-rethinkdb > /dev/null 2>&1
}
start_proxy() {
TLS_OPTS=""
if [ $ENABLE_TLS = 1 ]; then
TLS_OPTS="-e SSL_CA=$SSL_CA_CERT -e SSL_CERT=$SSL_CERT -e SSL_KEY=$SSL_KEY -e SSL_SKIP_VERIFY=1"
fi
# Note: we add SSL_SKIP_VERIFY=1 to skip verification of the client
# certificate in the proxy image. this will pass it to swarm that
# does verify. this helps with performance and avoids certificate issues
# when running through the proxy. ultimately if the cert is invalid
# swarm will fail to retur
ID=$(docker run \
-ti \
-d \
-p $PROXY_PORT:$PROXY_PORT \
--hostname=$HOSTNAME \
--restart=always \
--name $PREFIX-proxy \
-v /var/run/docker.sock:/var/run/docker.sock \
-e PORT=$PROXY_PORT \
--volumes-from=$PREFIX-certs $TLS_OPTS \
shipyard/docker-proxy:latest)
}
remove_proxy() {
docker rm -fv $PREFIX-proxy > /dev/null 2>&1
}
start_swarm_manager() {
get_ip
TLS_OPTS=""
if [ $ENABLE_TLS = 1 ]; then
TLS_OPTS="--tlsverify --tlscacert=$SSL_CA_CERT --tlscert=$SSL_CERT --tlskey=$SSL_KEY"
fi
EXTRA_RUN_OPTS=""
if [ -z "$DISCOVERY" ]; then
DISCOVERY="$DISCOVERY_BACKEND://discovery:$DISCOVERY_PORT"
EXTRA_RUN_OPTS="--link $PREFIX-discovery:discovery"
fi
ID=$(docker run \
-ti \
-d \
--restart=always \
--name $PREFIX-swarm-manager \
--volumes-from=$PREFIX-certs $EXTRA_RUN_OPTS \
swarm:latest \
m --replication --addr $SHIPYARD_IP:$SWARM_PORT --host tcp://0.0.0.0:$SWARM_PORT $TLS_OPTS $DISCOVERY)
}
remove_swarm_manager() {
docker rm -fv $PREFIX-swarm-manager > /dev/null 2>&1
}
start_swarm_agent() {
get_ip
if [ -z "$DISCOVERY" ]; then
DISCOVERY="$DISCOVERY_BACKEND://discovery:$DISCOVERY_PORT"
EXTRA_RUN_OPTS="--link $PREFIX-discovery:discovery"
fi
ID=$(docker run \
-ti \
-d \
--restart=always \
--name $PREFIX-swarm-agent $EXTRA_RUN_OPTS \
swarm:latest \
j --addr $SHIPYARD_IP:$PROXY_PORT $DISCOVERY)
}
remove_swarm_agent() {
docker rm -fv $PREFIX-swarm-agent > /dev/null 2>&1
}
start_controller() {
#-v $CERT_PATH:/etc/docker:ro \
TLS_OPTS=""
if [ $ENABLE_TLS = 1 ]; then
TLS_OPTS="--tls-ca-cert $SSL_CA_CERT --tls-cert=$SSL_CERT --tls-key=$SSL_KEY
--shipyard-tls-ca-cert=$SSL_CA_CERT --shipyard-tls-cert=$SSL_CERT --shipyard-tls-key=$SSL_KEY"
fi
ID=$(docker run \
-ti \
-d \
--restart=always \
--name $PREFIX-controller \
--link $PREFIX-rethinkdb:rethinkdb \
--link $PREFIX-swarm-manager:swarm \
-p $SHIPYARD_PORT:$SHIPYARD_PORT \
--volumes-from=$PREFIX-certs \
$IMAGE \
--debug \
server \
--listen :$SHIPYARD_PORT \
-d tcp://swarm:$SWARM_PORT $TLS_OPTS $SHIPYARD_ARGS)
}
wait_for_available() {
set +e
IP=$1
PORT=$2
echo Waiting for Shipyard on $IP:$PORT
docker pull ehazlett/curl > /dev/null 2>&1
TLS_OPTS=""
if [ $ENABLE_TLS = 1 ]; then
TLS_OPTS="-k"
fi
until $(docker run --rm ehazlett/curl --output /dev/null --connect-timeout 1 --silent --head --fail $TLS_OPTS $SHIPYARD_PROTOCOL://$IP:$PORT/ > /dev/null 2>&1); do
printf '.'
sleep 1
done
printf '\n'
}
remove_controller() {
docker rm -fv $PREFIX-controller > /dev/null 2>&1
}
if [ "$ACTION" = "deploy" ]; then
set -e
check_certs
get_ip
echo "Deploying Shipyard"
echo " -> Starting Database"
start_rethinkdb
echo " -> Starting Discovery"
start_discovery
echo " -> Starting Cert Volume"
start_certs
echo " -> Starting Proxy"
start_proxy
echo " -> Starting Swarm Manager"
start_swarm_manager
echo " -> Starting Swarm Agent"
start_swarm_agent
echo " -> Starting Controller"
start_controller
wait_for_available $SHIPYARD_IP $SHIPYARD_PORT
echo "Shipyard available at $SHIPYARD_PROTOCOL://$SHIPYARD_IP:$SHIPYARD_PORT"
if [ $ENABLE_TLS = 1 ] && [ ! -z "$CERT_FINGERPRINT" ]; then
echo "SSL SHA-256 Fingerprint: $CERT_FINGERPRINT"
fi
echo "Username: admin Password: shipyard"
elif [ "$ACTION" = "node" ]; then
set -e
if [ -z "$DISCOVERY" ]; then
echo "You must set the DISCOVERY environment variable"
echo "with the discovery system used with Swarm"
exit 1
fi
check_certs
echo "Adding Node"
echo " -> Starting Cert Volume"
start_certs
echo " -> Starting Proxy"
start_proxy
echo " -> Starting Swarm Manager"
start_swarm_manager $DISCOVERY
echo " -> Starting Swarm Agent"
start_swarm_agent
echo "Node added to Swarm: $SHIPYARD_IP"
elif [ "$ACTION" = "upgrade" ]; then
set -e
check_certs
get_ip
echo "Upgrading Shipyard"
echo " -> Pulling $IMAGE"
docker pull $IMAGE
echo " -> Upgrading Controller"
remove_controller
start_controller
wait_for_available $SHIPYARD_IP $SHIPYARD_PORT
echo "Shipyard controller update
elif [ "$ACTION" = "remove" ]; then
# ignore errors
set +e
echo "Removing Shipyard"
echo " -> Removing Database"
remove_rethinkdb
echo " -> Removing Discovery"
remove_discovery
echo " -> Removing Cert Volume"
remove_certs
echo " -> Removing Proxy"
remove_proxy
echo " -> Removing Swarm Agent"
remove_swarm_agent
echo " -> Removing Swarm Manager"
remove_swarm_manager
echo " -> Removing Controller"
remove_controller
echo "Done"
else
echo "Unknown action $ACTION"
exit 1
fi
3.2.2 添加可执行权限
为 deploy
脚本文件添加可执行权限。
3.2.3 执行脚本文件
执行该脚本文件,完成 shipyard
的自动部署。
脚本运行的最后,给出了访问地址及登录的账号与密码
3.3 访问
4. CIG 监控系统
通过 docker stats
命令可以实时性地查看到当前 Docker
主机中所有容器的 CPU 占用率、内存占用量、及网络流量使用量等数据。
docker stats
但 docker stats
统计结果只能是瞬时显示实时性数据,无法存储和查询历史数据,没有健康指标预警功能。而 CIG
解决了这些问题。
4.1 CGI简介
CIG
,即 CAdvisor
、InfluxDB
与 Grafana
,被称为 Docker
监控三剑客。其中 CAdvisor
用于监控数据的收集,InfluxDB
用于数据存储,Grafana
用于数据展示。
4.1.1 CAdvisor
cAdvisor
是谷歌公司用来分析运行中的 Docker
容器的资源占用以及性能特性的工具,包括对容器的内存、CPU、网络、磁盘 IO 等监控,同时提供了 WEB 页面用于展示监控数据。cAdvisor
使用一个运行中的守护进程来收集、聚合、处理和导出运行容器相关的信息,为每个容器保存独立的参数、历史资源使用情况和完整的资源使用数据。
默认情况下,CAdvisor
可以针对单个主机存储 2 分钟的监控数据。不过其提供了很多的数据集成接口用于存储监控数据,支持 InfluxDB
,Redis
,Kafka
,Elasticsearch
等,官方推荐InfluxDB
4.1.2 InfluxDB
InfluxDB
是一个由 InfluxData
用 GO
语言开发的、开源的、高性能的、时序型数据库,专注于海量时序数据的高性能读、高性能写、高效存储与实时分析等,无需外部依赖。
4.1.3 Grafana
Grafana
是一款采用 GO
语言编写的、开源的、数据监控分析可视化平台,主要用于大规模指标数据的可视化展示,是网络架构和应用分析中最流行的时序数据展示工具,目前已经支持绝大部分常用的时序数据库。拥有丰富的插件及模板功能支持图表权限控制和报警。
4.2 安装
对于 CIG
的安装,采用 docker compose
。所以需要先定义 compose.yml
文件,再启动所有服务容器。
4.2.1 创建工作目录
在任意目录下创建任意名称的目录。这里在/root
下创建 cig
目录。
4.2.2 定义 compose.yml
在 cig
目录中创建 compose.yml
,内容如下:
services:
influxdb:
image: tutum/influxdb:0.9
container_name: mydb
restart: always #只要docker启动,这个就启动
environment:
- PRE_CREATE_DB=cadivor
ports:
- 8083:8083 #这个是我们访问web页面要用的端口
- 8086:8086 #这个是influxdb服务的端口
volumes:
- ./data/influxdb:/data
cadvisor:
image: google/cadvisor
container_name: mycollector
links:
- influxdb:influxsrv #连接到influxdb,influxsrv是服务的别名
command: -storage_driver=influxdb -storage_driver_db=cadivor -storage_driver_host=influxsrv:8086
restart: always
ports:
- 8080:8080
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
grafana:
user: "104"
image: grafana/grafana
container_name: myui
restart: always
links:
- influxdb:influxsrv #连接到influxdb,influxsrv是服务的别名
ports:
- 3000:3000
volumes:
- grafana_data:/var/lib/grafana
environment:
- HTTP_USER=admin
- HTTP_PASS=admin
- INFLUXDB_HOST=influxsrv
- INFLUXDB_PORT=8086
- INFLUXDB_NAME=cadivor
- INFLUXDB_USER=root
- INFLUXDB_PASS=root
volumes:
grafana_data: {}
4.2.3 启动容器
通过 docker-compose up –d
启动所有容器
4.3 查看CIG各页面
4.3.1 查看 cadvisor 页面
由于其完成的是原始数据收集功能,所以该页面在打开时会较慢,有一个收集、展示的过程。在浏览器输入 docker
宿主机ip:8080
即可访问。
该页面看到的是当前主机的总体统计数据。点击 Docker Contianers
链接,可看到当前主机中的所有容器。
点击任意容器,可看到该容器的统计数据。例如,点击 myui
容器,可看到如下数据:
4.3.2 查看 influxdb 页面
在浏览器输入 docker
宿主机 ip:8083
即可访问。
点击右上角的“配置”图标,可打开连接配置面板。
点击右下角的 Query Templates
按钮,可看到固定的查询模板。例如,选择 Show Databases
后,在 Query
栏中即可出现该查询语句。
回车后可看到查询结果。
这其中的 cadivsor
即为在 compose.yml
中配置的事先创建的 DB。
4.3.3 查看 grafana 页面
在浏览器输入 docker
宿主机 ip:3000
即可访问。
输入用户名与密码,是在compose.yml
中配置的 admin:admin
。若为第一次登录,在 Login
后会弹出修改密码的对话框。
再次输入 admin
或直接 Skip
即可跳转到欢迎页面。
在欢迎页面中会有三个默认面板,都可以 Remove
掉的。
4.4 配置grafana
4.4.1 添加数据源
此时的 grafana
与 influxDB
还没有关系,所以需要为 grafana
添加 influxDB
为其数据源。
该页面向下拉,填入要连接的 DB 名称、用户名与密码。这里为 cadivor
,用户名与密码也都是 compose.yml
中配置的 root:root
。
4.4.2 配置 Dashboards
配置数据的展示仪表盘。