Docker—10章(Docker管理监控平台)


Docker 管理监控平台

Docker 引擎中管理的镜像、容器、网络等对象数量变得越来越多时,通过简单的 docker命令来管理已经显得使人力不从心了。于是就出现了很多的 Docker 可视化管理平台。我们这里对现在较流行的、使用较多的几种平台进行介绍。

1. Docker UI

1.1 简介

Docker UI 是一个开源的基于 Docker APIweb 应用程序,提供等同 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 协议访问。

http访问

通过 https 协议访问。

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,即 CAdvisorInfluxDB Grafana,被称为 Docker 监控三剑客。其中 CAdvisor 用于监控数据的收集,InfluxDB 用于数据存储,Grafana 用于数据展示。

4.1.1 CAdvisor

cAdvisor 是谷歌公司用来分析运行中的 Docker 容器的资源占用以及性能特性的工具,包括对容器的内存、CPU、网络、磁盘 IO 等监控,同时提供了 WEB 页面用于展示监控数据。cAdvisor 使用一个运行中的守护进程来收集、聚合、处理和导出运行容器相关的信息,为每个容器保存独立的参数、历史资源使用情况和完整的资源使用数据。

默认情况下,CAdvisor 可以针对单个主机存储 2 分钟的监控数据。不过其提供了很多的数据集成接口用于存储监控数据,支持 InfluxDBRedisKafkaElasticsearch 等,官方推荐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

配置数据的展示仪表盘。


文章作者: 念心卓
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 念心卓 !
  目录