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
启动
指定各组件名称
前面的 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
查看容器
查看网络
查看网络详情
Docker 管理监控平台
当 Docker引擎中管理的镜像、容器、网络等对象数量变得越来越多时,通过简单的 docker 命令来管理已经显得使人力不从心了。于是就出现了很多的 Docker 可视化管理平台。我们 这里对现在较流行的、使用较多的几种平台进行介绍。
DockerUI管理平台
docker stats
简介
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
Portainer管理平台
简介
Portainer 是一个可视化的容器镜像的图形管理工具,利用 Portainer 可以轻松构建,管理和维护 Docker 环境。
而且完全免费,基于容器化的安装方式,方便高效部署。其官网为:https://www.portainer.io/。
安装
- 拉取镜像
- 新建数据卷
单独新建一个数据卷
- 启动容器
为了能使用 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 协议访问。
- 通过 https 协议访问。
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 脚本文件添加可执行权限。
- 执行脚本文件
- 脚本运行的最后,给出了访问地址及登录的账号与密码。
CIG 监控系统
通过 docker stats 命令可以实时性地查看到当前 Docker 主机中所有容器的 CPU 占用率、内存占用量、及网络流量使用量等数据。
但 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 启动所有容器
查看 CIG 各页面
- 查看 cadvisor 页面
由于其完成的是原始数据收集功能,所以该页面在打开时会较慢,有一个收集、展示的过程。在浏览器输入 docker 宿主机 ip:8080 即可访问。
该页面看到的是当前主机的总体统计数据。点击 Docker Contianers 链接,可看到当前主机中的所有容器。
点击任意容器,可看到该容器的统计数据。例如,点击 myapp 容器,可看到如下数据:
- 查看 influxdb 页面
在浏览器输入 docker 宿主机 ip:8083 即可访问。
点击右上角的“配置”图标,可打开连接配置面板。
点击右下角的 Query Templates 按钮,可看到固定的查询模板。例如,选择 Show Databases后,在 Query 栏中即可出现该查询语句
回车后可看到查询结果。
这其中的 cadvisor 即为在 compose.yml 中配置的事先创建的 DB。
查看 grafana 页面
在浏览器输入 docker 宿主机 ip:3000 即可访问。
输入用户名与密码,是在 compose.yml 中配置的 admin:admin。若为第一次登录,在 Log in 后会弹出修改密码的对话框。
配置 grafana
- 添加数据源
此时的 grafana 与 influxDB 还没有关系,所以需要为 grafana 添加 influxDB 为其数据源。
该页面向下拉,填入要连接的 DB 名称、用户名与密码。这里为 cadvisor,用户名与密码也都是 compose.yml 中配置的 root:root。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义