Docker-componse

Docker Compose

对于现代应用来说,大多都是通过很多的微服务互相协同组成的一个完整应用。例如, 订单管理、用户管理、品类管理、缓存服务、数据库服务等,它们构成了一个电商平台的应 用。而部署和管理大量的服务容器是一件非常繁琐的事情。而 Docker Compose 就是解决这 类问题的。

简介

Docker Compose 是一个需要在 Docker 主机上进行安装的 Docker 容器编排外部工具。其 并不是通过脚本或各种冗长的 Docker 命令来将应用组件组织起来,而是通过一个声明式的 配置文件描述整个应用,然后通过一条命令完成应用部署。部署成功后,还可通过一系列简 单命令实现对其完整生命周期的管理。 Docker Compose 的前身是 Fig(无花果)。

compose 文件

Docker Compose 使用 YAML 文件来定义服务。官方推荐的默认文件名为 compose.yml , 但同时也支持 docker-compose.yml。 由于一个 compose 文件中定义的为一个项目的所有服务,所以一般为在创建 compose 文件之前先新建一个目录,目录名称一般为项目名称,然后再将项目所需的所有镜像、微服 务的 Dockerfile 放入该目录,并在该目录中新建 compose 文件。 compose 文件中包含 6 个顶级属性:version、services、networks、volumes、configs 与 secrets,及很多的它们下面所包含的属性。下面简单介绍一下常用的属性。

version

version 是一个顶级属性,但已经过时,不再需要在 compose 文件中出现了。从以下官 网说明中可以看出。

networks

networks 作为一个顶级属性,用于定义和创建应用中所使用到的所有网络。其下包含的 第一级属性即为网络名称,这个网络名称可以随意命名。而在网络名称下还可包含很多的属 性,常用属性如下:

services:
 app:
networks:
 - app_bridge: #这里使用的并不是网络名称
networks:
 app_bridge:
name: appBGnet # 这才是网络名称
driver: bridge

name

networks 下的第一级属性—网络名称,并不是真正的网络名称,而仅仅是网络名称的一 部分。在真正生成网络后,其真正的网络名称格式为:当前 compose 文件所在目录名_ networks 下的第一级属性。 但如果设置了name属性,则网络名称即为这里指定的名称,不会出现名称再合成情况。

driver

用于指定网络驱动,缺省驱动为 Bridge。

attachable

如果该属性设置为 true,则除了当前 compose 中定义的服务外,其它独立容器也可以 连接到此网络,并能与该网络中的服务及也连接到该网络的其它独立容器通信。缺省状态为 false。

volumes

volumes 作为一个顶级属性,用于定义和创建应用中所使用到的所有 volume。其下包含 的第一级属性即为 volume 的卷标,这个卷标可以随意命名。这个卷标所代表的是当前 Docker 主机中的目录,至于该目录的具体位置,是由系统自动分配的。 在网络名称下还可包含很多的属性,但这些属性并不常用,所以这里不进行介绍了。

serivces

services 是一个顶级属性,用于定义一个应用中所包含的服务。Docker Compose 会将每 个服务部署在各自的容器中。其下包含的第一级的属性即为服务名称,这个名称可以根据服 务内容随意命名。而在服务名称下还可包含很多的属性,常用属性如下:

build

用于指定一个 Dockerfile 的路径。而该 Dockerfile 则是用于创建当前服务镜像的。这个 路径可以是以斜杠(/)开头的绝对路径,也可以是相对于当前 compose 文件的、以点(.)号开头 的相对路径。

如果 Dockerfile 文件名不是默认名称,则需要通过 build 下的 context 属性指定路径, dockerfile 属性指定文件名。

例如,
build:
 context: ./
 dockerfile: myDockerfile

image

用户指定当前服务所需要使用的镜像,这个镜像可以是本地镜像,也可以是远程镜像仓 库中的镜像(会自动 pull)。 如果设置了 build,此时再设置的 image 属性即为构建出的镜像的名称与 Tag。

container_name

该属性用于设置容器名称,但并不是必须的。如果没有设置该属性,容器名称则会采用 “合成方式”。而合成时需要用到 services 下的第一级属性。 在 services 下存在一级属性,称为服务名称。该级属性是作为 services 下的第一级属性 出现的。服务名称将来会作为容器名称的一部分出现。容器的名称格式为:当前 compose 文件所在目录名_ 服务名称。 如果在 services 下没有指定 image 属性,而是使用 bild 属性,即没有现成的镜像,而是 根据 build 下指定的 Dockerfile 生成镜像,此时生成的镜像名称格式为:当前 compose 文件 所在目录名-服务名称。

ports

一个列表。前面为暴露出的端口号,后面为容器中应用的端口号。如果仅设置了一个端 口号,那么这个端口号是容器中应用的端口号,其暴露到宿主机的端口号会被随机分配。

ports:
 - 80:80 # 绑定容器的 80 端口到主机的 80 端口
 - 9000:80 # 绑定容器的 80 端口到主机的 9000 端口
 - 443 # 绑定容器的 443 端口到主机的任意端口,容器启动时随机分配绑定的主机端口号

command

用于覆盖 Dockerfile 中的 CMD 指令内容,即启动该服务容器后立即运行的命令。如果 直接按照Dockerfile中的CMD指令内容执行即可,则compose文件中无需该command属性。

depends_on

一个列表。用于指定当前服务的启动所依赖的应用名称。即列表中指定的服务会先于当 前服务启动。

deploy

用于指定当前服务容器的部署设置。其下有一个常用属性 replicas,用于指定该服务启 动的容器的数量。即实现一个服务多个容器。一旦指定了 deploy:replicas,就不能再指定 container_name 属性了。因为各个启动的容器名称不能相同,而只能由系统自动生成。

services:
 frontend:
 image: awesome/webapp
 deploy:
 mode: replicated
 replicas: 6

networks

用于指定当前服务容器要连接到的网络。该网络必须是已经存在的,或通过顶级属性 networks 创建的网络。

volumes

用于指定当前服务容器所使用到的所有 volume。这些 volume 可以使用路径与卷标两种 方式。 例如,下面是路径方式,非常直观,易于查看,但需要管理本地路径。

db:
 image: mariadb:latest
 ports:
 - "3306:3306"
 volumes:
 - /etc/mysql:/var/lib/mysql

再如,下面是卷标方式,backend 与 backup 两个服务共享了 db-data 的卷,逻辑简洁明 了,且无需管理本地路径。但具体卷标所代表的是 Docker 主机的哪个路径,并不能直观的 看到。需要通过 docker volume inspect [卷标]来查看。

services:
 backend:
 image: awesome/database
 volumes:
 - db-data:/etc/data
 backup:
 image: backup-service
 volumes:
 - db-data:/var/lib/backup/data
volumes:
 db-data:

常用命令

Docker Compose通过docker-compose系列命令查看和控制compose中的所有服务容器。

docker-compose pull

拉取 compose 中服务依赖的全部镜像或指定镜像。通过在命令后添加服务名称来指定。

docker-compose config

检查 compose 文件是否正确。可添加选项-q,表示只有存在问题时才有输出。

docker-compose up

启动 compose 中的所有容器。-d 选项表示后台启动。

docker-compose logs

查看 comopse 中所有服务或指定服务的运行日志。通过在命令后添加服务名称来指定。 默认情况下,将对不同的服务日志使用不同的颜色来区分。

docker-compose ps

列出 compose 中所有服务或指定服务。通过在命令后添加服务名称来指定。

docker-compose top

列出 compose 中当前正在运行的所有服务或指定服务。通过在命令后添加服务名称来 指定。

docker-compose images

列出 compose 中所有服务或指定服务对应的镜像。通过在命令后添加服务名称来指定。

docker-compose port

列出指定服务容器的指定端口所映射的宿主机端口。

docker-compose run

在指定服务上执行一条命令。

docker-compose exec

进入指定服务容器。通过在命令后添加服务名称来指定。

docker-compose pause

暂停 compose 中所有服务容器或指定服务容器。通过在命令后添加服务名称来指定。

docker-compose unpause

恢复 compose 中处于暂停状态的所有服务容器或指定服务容器。通过在命令后添加服 务名称来指定。

docker-compose stop

停止 compose 中所有服务容器或指定服务容器。通过在命令后添加服务名称来指定。

docker-compose restart

重启 compose 中所有服务容器或指定服务容器。通过在命令后添加服务名称来指定。

docker-compose start

启动 compose 中所有服务容器或指定服务容器。通过在命令后添加服务名称来指定。

docker-compose kill

通过发送 SIGKILL 信号停止指定服务的容器。

docker-compose rm

删除 compose 中的、处于停止状态的所有服务容器或指定服务容器。通过在命令后添 加服务名称来指定。

docker-compose down

停止并删除 compose 中的所有服务容器、网络、镜像、数据卷。

构建镜像

# 指定当前镜像继承自 openjdk:8u102,因为下面要运行 Jar 包,需要 JDK 环境
FROM openjdk:8u102
# 作者与项目相关说明
MAINTAINER zhangsan zs@163.com
LABEL version="1.0" description="this is a spring boot application"
# 将当前目录下的 jar 包 copy 到容器中。
# 注意,这个当前目录指的是 docker build 命令最后一个参数指定的上下文路径
COPY ssrm-0.0.1-SNAPSHOT.jar ssrm.jar
# 一定要执行的 exec
ENTRYPOINT ["java", "-jar", "ssrm.jar"]
# 指定对外暴露的端口号
EXPOSE 9000

Compose 编排启动项目

手工启动项目不仅繁琐易错,而且还存在一个致命问题:当前应用访问的 mysql 与 redis 只能是运行在当前 Docker 宿主机之上的,否则将无法访问到它们。因为在应用的配置文件 中已经将 mysql 与 redis 的 IP 进行了硬编码。而使用 Docker Compose 可以解决所有问题。

定义 compose.yml

在 finance 目录中新建一个文件 compose.yml

services:
  app:
    build: ./
    container_name: myapp
    ports:
      - 9000:8080
    volumes:
      - ./logs:/var/applogs
    depends_on:
      - yhdmysql
      - yhdredis
  yhdmysql:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: 111
    ports:
      - 3306:3306
    volumes:
      - /root/mysql/log:/var/log/mysql
      - /root/mysql/data:/va/log/mysql
      - /root/mysql/conf:/etc/mysql/conf.d
  yhdredis:
    image: redis:7.0
    ports:
      - 6379:6379
    volumes:
      - /root/redis/redis.conf:/etc/redis/redis.conf
      - /root/redis/data:/data
    command: redis-server /etc/redis/redis.conf

启动

image-20230326214432664

image-20230326214506531

image-20230326214531082

image-20230326214546417

指定各组件名称

前面的 compose.yml 文件中应用生成的镜像采用的是默认名称,mysql 与 redis 生成的容 器名称采用的是默认名称,生成并加入的 bridge 网络也称默认名称的网络。这些组件的所 使用的默认名称,也可以被指定名称所代替。

编写compose2.yml

services:
  app:
    build: ./
    image: financ3:2.0
    container_name: yhdapp
    ports:
      - 9000:8080
    networks:
      - ab
    volumes:
      - ./logs:/var/applogs
    depends_on:
      - yhdmysql
      - yhdredis
  yhdmysql:
    image: mysql:5.7
    container_name: yhdmysql
    environment:
      MYSQL_ROOT_PASSWORD: 111
    networks:
      - ab
    ports:
      - 3306:3306
    volumes:
      - /root/mysql/log:/var/log/mysql
      - /root/mysql/data:/va/log/mysql
      - /root/mysql/conf:/etc/mysql/conf.d
  yhdredis:
    image: redis:7.0
    container_name: yhdredis
    ports:
      - 6379:6379
    networks:
      - ab
    volumes:
      - /root/redis/redis.conf:/etc/redis/redis.conf
      - /root/redis/data:/data
    command: redis-server /etc/redis/redis.conf
networks:
  ab:

启动所有容器

这里通过-f 选项指定要使用的 compose 文件

docker-compose -f compose2.yml up -d

image-20230330150638761

查看容器

image-20230330150758346

查看网络

image-20230330150828244

查看网络详情

image-20230330151030043

image-20230330151056923

Docker 管理监控平台

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

DockerUI管理平台

docker stats

image-20230330163159652

简介

​ DockerUI 是一个开源的基于 Docker API 的 web 应用程序,提供等同 Docker 命令行的大 部分功能,支持 container 管理,image 管理。它最值得称道的是它华丽的设计和用来运行和 管理 docker 的简洁的操作界面。 其支持容器的批量操作,支持镜像管理。但不支持多集群管理。

安装

拉取镜像

docker pull uifd/ui-for-docker 拉取 docker ui 的镜像。

启动

docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock uifd/ui-for-docker

image-20230330170416257

Portainer管理平台

简介

Portainer 是一个可视化的容器镜像的图形管理工具,利用 Portainer 可以轻松构建,管理和维护 Docker 环境。

而且完全免费,基于容器化的安装方式,方便高效部署。其官网为:https://www.portainer.io/。

安装

  • 拉取镜像

image-20230410115424158

  • 新建数据卷

单独新建一个数据卷

image-20230410115528220

  • 启动容器

为了能使用 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 协议访问。

image-20230410134857761

  • 通过 https 协议访问。

image-20230410135014298

shipyard

简介

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

安装

shipyard 的安装有两种方式:自动安装与手动安装。由于手动安装比较麻烦,需要手动拉取很多镜像并启动与之对应的容器,所以一般都是使用自动安装方式。不过,手动安装的好处是,可以根据功能选择性的拉取镜像、启动容器。而自动安装则是通过运行一个部署脚本文件,实现自动拉取全部镜像并启动这些容器。

  • 拉取镜像
docker pull rethinkdb
docker pull microbox/etcd
docker pull shipyard/docker-proxy
docker pull swarm
docker pull dockerclub/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:-2375}
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

    ENABLE_TLS=1
}

# 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 return.
    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 updated"

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

  • 添加可执行权限

为 deploy 脚本文件添加可执行权限。

  • 执行脚本文件
  • 脚本运行的最后,给出了访问地址及登录的账号与密码。
  • image-20230410114900465

image-20230410115013857

CIG 监控系统

通过 docker stats 命令可以实时性地查看到当前 Docker 主机中所有容器的 CPU 占用率、内存占用量、及网络流量使用量等数据。

image-20230410135944722

但 docker stats 统计结果只能是瞬时显示实时性数据,无法存储和查询历史数据,没有健康指标预警功能。而 CIG 解决了这些问题。

CIG 简介

CIG,即 CAdvisor、InfluxDB 与 Grafana,被称为 Docker 监控三剑客。其中 CAdvisor 用于监控数据的收集,InfluxDB 用于数据存储,Grafana 用于数据展示。

  • CAdvisor

  • cAdvisor 是谷歌公司用来分析运行中的 Docker 容器的资源占用以及性能特性的工具,包括对容器的内存、CPU、网络、磁盘 IO 等监控,同时提供了 WEB 页面用于展示监控数据。cAdvisor 使用一个运行中的守护进程来收集、聚合、处理和导出运行容器相关的信息,为每个容器保存独立的参数、历史资源使用情况和完整的资源使用数据。默认情况下,CAdvisor 可以针对单个主机存储 2 分钟的监控数据。不过其提供了很多的数据集成接口用于存储监控数据,支持 InfluxDB,Redis,Kafka,Elasticsearch 等,官方推荐InfluxDB。influxDB

InfluxDB 是一个由 InfluxData 用 GO 语言开发的、开源的、高性能的、时序型数据库,专注于海量时序数据的高性能读、高性能写、高效存储与实时分析等,无需外部依赖。

  • Grafana

Grafana 是一款采用 GO 语言编写的、开源的、数据监控分析可视化平台,主要用于大

规模指标数据的可视化展示,是网络架构和应用分析中最流行的时序数据展示工具,目前已

经支持绝大部分常用的时序数据库。拥有丰富的插件及模板功能支持图表权限控制和报警。

安装

对于 CIG 的安装,采用 docker compose。所以需要先定义 compose.yml 文件,再启动所有服务容器。

  • 创建工作目录

在任意目录下创建任意名称的目录。这里在/root 下创建 cig 目录。

services:
  influxdb:
    image: tutum/influxdb:0.9
    container_name: mydb
    restart: always
    environment:
      - PRE_CREATE_DB=cadivor
    ports:
      - 8083:8083
      - 8086:8086
    volumes:
      - ./data/influxdb:/data

  cadvisor:
    image: google/cadvisor
    container_name: mycollector
    links:
      - 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
    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: {}

启动容器

通过 docker-compose up –d 启动所有容器

image-20230410144540286

查看 CIG 各页面

  • 查看 cadvisor 页面

由于其完成的是原始数据收集功能,所以该页面在打开时会较慢,有一个收集、展示的过程。在浏览器输入 docker 宿主机 ip:8080 即可访问。

image-20230410144624238

该页面看到的是当前主机的总体统计数据。点击 Docker Contianers 链接,可看到当前主机中的所有容器。

点击任意容器,可看到该容器的统计数据。例如,点击 myapp 容器,可看到如下数据:

image-20230410144813864

  • 查看 influxdb 页面

在浏览器输入 docker 宿主机 ip:8083 即可访问。

image-20230410144951324

点击右上角的“配置”图标,可打开连接配置面板。

image-20230410145013508

点击右下角的 Query Templates 按钮,可看到固定的查询模板。例如,选择 Show Databases后,在 Query 栏中即可出现该查询语句

image-20230410145055079

回车后可看到查询结果。

image-20230410145123515

这其中的 cadvisor 即为在 compose.yml 中配置的事先创建的 DB。

查看 grafana 页面

在浏览器输入 docker 宿主机 ip:3000 即可访问。

image-20230410145206290

输入用户名与密码,是在 compose.yml 中配置的 admin:admin。若为第一次登录,在 Log in 后会弹出修改密码的对话框。

配置 grafana

  • 添加数据源

此时的 grafana 与 influxDB 还没有关系,所以需要为 grafana 添加 influxDB 为其数据源。

image-20230410145411797

image-20230410145440998

image-20230410145554291

该页面向下拉,填入要连接的 DB 名称、用户名与密码。这里为 cadvisor,用户名与密码也都是 compose.yml 中配置的 root:root。

image-20230410145724348

配置 Dashboards

image-20230410145905693

image-20230410151044210

image-20230410151104445

posted @   我是一个大废物  阅读(91)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示