zl程序教程

您现在的位置是:首页 >  工具

当前栏目

CKA-docker 容器的管理

Docker容器 管理 CKA
2023-09-11 14:15:23 时间

 

 

 

 

 

容器的生命期的问题

 

-i 交互

-t 终端

-d 守护进程(后台运行)

-e 指定变量

--rm  临时容器            --restart=always 不能同时使用

--name 指定容器名

 

# 进入容器

docker attach <容器ID>

 

 

 

docker run -dit --name=c1 --restart=always  hub.c.163.com/library/centos

 

 

# 查看容器信息

docker inspect c1

 

 

 

docker top <容器名> 

 

 

 

# 读取容器里面的输出 

docker logs <容器名>

# 在容器mysql镜像,指定了一个变量

 

 

 # 额外的打开一个bash进程

 

 

 

 # 冒号左边是物理机,冒号右边是容器

 

  • docker exec <容器名> 命令
  • docker start <容器名>
  • docker stop <容器名>
  • docker restrart <容器名>
  • docker top <容器名>
  • docker logs -f <容器名>
  • docker inspect <容器名> 
  • docker cp <拷贝的文件> <容器名>:<目录>           docker cp <容器名>:<目录> <物理机存放地址>  # 容器之间不能这样拷贝
  •  

     

 

 

 

  weavescope  工具安装测试

容器监控工具WeaveScope

github开源项目地址

curl -L git.io/scope -o /usr/local/bin/scope

赋予可执行权限:

chmod a+x /usr/local/bin/scope

启动scope:

scope launch

 

 

 

  

数据卷的使用

-v /dir                  # 默认指定一个目录,是容器里面的目录。物理机是随机生成一个目录

-v /dir2:dir           # 冒号左边是物理机里面的目录,冒号右边的是容器目录

-v /dir2:/dir:rw    # 默认

-v /dir2:/dir:ro  # 需要手动指定只读

 

你得去理解容器里的存储信息(比如:mysql本身存放在哪里的)

# 需要自己再熟悉下 apache tomcat redis

 

 

 

 

docker网络管理

# 查看容器ip地址

  

 # 查看本地网桥

docker network list

 

# 查看网络属性

docker network inspect bridge

 

# 会生成docker0

  

# 自己创建一个网桥

docker network create -d bridge --subnet=x.x.x.x/24 <网桥名>

 PS: 如何自己通过命令查询 创建网络命令

容器网络里面有

bridge  网桥 相当于nat

host   直接变成主机网络

none 不设置网络(单独配合一些工具可以变成桥接模式,设置独立IP地址) 

 

# 加入到自己的创建的网桥

 

 

# 查看应用所需要的变量,例如wordpress

PS:可以使用hub或者163里面的 how to use 来看下所需的变量意思

 

网易:https://c.163yun.com/hub#/home

 

# 查找docker 所有相关帮助命令

man -k docker

 

 

 

# 新建一个数据库,使用了两个变量(一个是设置root密码,一个是创建数据库)

  

# 创建wordpress (正常方式)

  

# 查看更详细的信息

docker history  --no-trunc  

 

 # 再次新建后使用 --link 别名 来省略一些变量参数,并且防止容器内部IP变化导致的配置文件修改  【这部分需要进行试验一下】

 

 

 

 

  

自定义镜像

构建镜像:并非是从0到1的过程,在一个已经存在的镜像的基础上,进行构建出新的镜像

基镜像,基础镜像

最底层的---是一个干净的操作系统,一般是由厂商来提供

 

Dockefile

#############

RUN

ADD

ENV 

VOLUME

CMD

#############

 

 

 

# 通过dockerfile 生成容器

1. 生成临时容器,执行dockerfile 内容,产生容器,最后删除临时容器

 

 Dockefile 文件举例:

 

 

tar tf  <tar> 查看tar包里面内容

 

 

 

docker build -t centos:v0 .

. 当前目录去找(其他目录就用-f [dockerfile文件名],不跟文件名,默认寻找Dockerfile)

 

ADD 和 COPY 区别 (需实验)

 add 可以解压,copy 直接复制包(不带解压功能) 
PS: 目前已知能直接解压的有tar,tar.gz 

 

自己搭建一个nginx 镜像

# 可以自己修改nginx配置文件

 

 # 守护进程模式开启的方法, docker history  --no-trunc  | tail -2 

 

 EXPOSE 仅仅是个标识 <--- 告诉别人你默认用的端口是什么

# 如何判断 CMD 后面需要填写的守护进程参数(需要根据经验,或者找一个镜像通过docker histroy查看)

Nginx:

CMD ["nginx", "-g", "daemon off;"]

SSH:

CMD["sshd", "-D"]

Mysql:

CMD ["mysqld"]

Centos:

CMD ["/bin/bash"]

 

# ENV 和 用户添加

ENV

USER

# Dockerfile RUN 尽量放在一行来写,会减少镜像层数,从而减小镜像的大小

 

# 在dockerfile 里面指定用户执行进程,并设置变量 aa

# 如果创建的进程是普通用户,想用root进入  docker exec -it -uroot .....的方式

 

 

# VOLUME 定义卷

VOLUME ["dir1", "dir2"]

 

 

 

 

# ssh 的dockerfile 是如何一步步做出这个文件的

  

私有仓库 

# 搭建自己的私有仓库

1. registry

2. harbor

 

 

 

 

 

 

 

 

 使用registry 搭建私有仓库

registry  端口5000

/var/lib/registry

 

1. 仅允许https 方式访问 

http+ssl -- tls(传输层的加密)

两种只能选一种,不要都使用

# 方法一:

修改 不适用https 的方式,都需要修改

/etc/docker/daemon.json

 

 # 方法二:

 

 

  

 

 

 

 

 # 从客户端推送镜像到私有仓库

# 修改tag

 

 # 再进行推送(推送的时候一定要注意镜像tag是不是复核规范

 

 

 #使用curl命令查询的镜像数量

 

# 查询镜像的版本

 

 

 

使用脚本来实现查询镜像和版本

# 老师的脚本,仅供参考

 1 #!/bin/bash
 2 file=$(mktemp)
 3 curl -s $1:5000/v2/_catalog | jq | egrep -v '\{|\}|\[|]' | awk -F\" '{print $2}' > $file
 4 while read aa ; do
 5 tag=($(curl -s $1:5000/v2/$aa/tags/list | jq | egrep -v '\{|\}|\[|]|name' | awk -F\" '{print $2}'))
 6     for i in ${tag[*]} ; do
 7       echo $1:5000/${aa}:$i
 8     done
 9 done < $file
10 rm -rf $file
View Code

# 用脚本查询结果

 

 

 

# 删除私有仓库下面多余或无用的镜像

用老师的PY脚本

#!/usr/bin/env python
"""
Usage:
Shut down your registry service to avoid race conditions and possible data loss
and then run the command with an image repo like this:
delete_docker_registry_image.py --image awesomeimage --dry-run
"""

import argparse
import json
import logging
import os
import sys
import shutil
import glob

logger = logging.getLogger(__name__)


def del_empty_dirs(s_dir, top_level):
    """recursively delete empty directories"""
    b_empty = True

    for s_target in os.listdir(s_dir):
        s_path = os.path.join(s_dir, s_target)
        if os.path.isdir(s_path):
            if not del_empty_dirs(s_path, False):
                b_empty = False
        else:
            b_empty = False

    if b_empty:
        logger.debug("Deleting empty directory '%s'", s_dir)
        if not top_level:
            os.rmdir(s_dir)

    return b_empty


def get_layers_from_blob(path):
    """parse json blob and get set of layer digests"""
    try:
        with open(path, "r") as blob:
            data_raw = blob.read()
            data = json.loads(data_raw)
            if data["schemaVersion"] == 1:
                result = set([entry["blobSum"].split(":")[1] for entry in data["fsLayers"]])
            else:
                result = set([entry["digest"].split(":")[1] for entry in data["layers"]])
                if "config" in data:
                    result.add(data["config"]["digest"].split(":")[1])
            return result
    except Exception as error:
        logger.critical("Failed to read layers from blob:%s", error)
        return set()


def get_digest_from_blob(path):
    """parse file and get digest"""
    try:
        with open(path, "r") as blob:
            return blob.read().split(":")[1]
    except Exception as error:
        logger.critical("Failed to read digest from blob:%s", error)
        return ""


def get_links(path, _filter=None):
    """recursively walk `path` and parse every link inside"""
    result = []
    for root, _, files in os.walk(path):
        for each in files:
            if each == "link":
                filepath = os.path.join(root, each)
                if not _filter or _filter in filepath:
                    result.append(get_digest_from_blob(filepath))
    return result


class RegistryCleanerError(Exception):
    pass


class RegistryCleaner(object):
    """Clean registry"""

    def __init__(self, registry_data_dir, dry_run=False):
        self.registry_data_dir = registry_data_dir
        if not os.path.isdir(self.registry_data_dir):
            raise RegistryCleanerError("No repositories directory found inside " \
                                       "REGISTRY_DATA_DIR '{0}'.".
                                       format(self.registry_data_dir))
        self.dry_run = dry_run

    def _delete_layer(self, repo, digest):
        """remove blob directory from filesystem"""
        path = os.path.join(self.registry_data_dir, "repositories", repo, "_layers/sha256", digest)
        self._delete_dir(path)

    def _delete_blob(self, digest):
        """remove blob directory from filesystem"""
        path = os.path.join(self.registry_data_dir, "blobs/sha256", digest[0:2], digest)
        self._delete_dir(path)

    def _blob_path_for_revision(self, digest):
        """where we can find the blob that contains the json describing this digest"""
        return os.path.join(self.registry_data_dir, "blobs/sha256",
                            digest[0:2], digest, "data")

    def _blob_path_for_revision_is_missing(self, digest):
        """for each revision, there should be a blob describing it"""
        return not os.path.isfile(self._blob_path_for_revision(digest))

    def _get_layers_from_blob(self, digest):
        """get layers from blob by digest"""
        return get_layers_from_blob(self._blob_path_for_revision(digest))

    def _delete_dir(self, path):
        """remove directory from filesystem"""
        if self.dry_run:
            logger.info("DRY_RUN: would have deleted %s", path)
        else:
            logger.info("Deleting %s", path)
            try:
                shutil.rmtree(path)
            except Exception as error:
                logger.critical("Failed to delete directory:%s", error)

    def _delete_from_tag_index_for_revision(self, repo, digest):
        """delete revision from tag indexes"""
        paths = glob.glob(
            os.path.join(self.registry_data_dir, "repositories", repo,
                         "_manifests/tags/*/index/sha256", digest)
        )
        for path in paths:
            self._delete_dir(path)

    def _delete_revisions(self, repo, revisions, blobs_to_keep=None):
        """delete revisions from list of directories"""
        if blobs_to_keep is None:
            blobs_to_keep = []
        for revision_dir in revisions:
            digests = get_links(revision_dir)
            for digest in digests:
                self._delete_from_tag_index_for_revision(repo, digest)
                if digest not in blobs_to_keep:
                    self._delete_blob(digest)

            self._delete_dir(revision_dir)

    def _get_tags(self, repo):
        """get all tags for given repository"""
        path = os.path.join(self.registry_data_dir, "repositories", repo, "_manifests/tags")
        if not os.path.isdir(path):
            logger.critical("No repository '%s' found in repositories directory %s",
                             repo, self.registry_data_dir)
            return None
        result = []
        for each in os.listdir(path):
            filepath = os.path.join(path, each)
            if os.path.isdir(filepath):
                result.append(each)
        return result

    def _get_repositories(self):
        """get all repository repos"""
        result = []
        root = os.path.join(self.registry_data_dir, "repositories")
        for each in os.listdir(root):
            filepath = os.path.join(root, each)
            if os.path.isdir(filepath):
                inside = os.listdir(filepath)
                if "_layers" in inside:
                    result.append(each)
                else:
                    for inner in inside:
                        result.append(os.path.join(each, inner))
        return result

    def _get_all_links(self, except_repo=""):
        """get links for every repository"""
        result = []
        repositories = self._get_repositories()
        for repo in [r for r in repositories if r != except_repo]:
            path = os.path.join(self.registry_data_dir, "repositories", repo)
            for link in get_links(path):
                result.append(link)
        return result

    def prune(self):
        """delete all empty directories in registry_data_dir"""
        del_empty_dirs(self.registry_data_dir, True)

    def _layer_in_same_repo(self, repo, tag, layer):
        """check if layer is found in other tags of same repository"""
        for other_tag in [t for t in self._get_tags(repo) if t != tag]:
            path = os.path.join(self.registry_data_dir, "repositories", repo,
                                "_manifests/tags", other_tag, "current/link")
            manifest = get_digest_from_blob(path)
            try:
                layers = self._get_layers_from_blob(manifest)
                if layer in layers:
                    return True
            except IOError:
                if self._blob_path_for_revision_is_missing(manifest):
                    logger.warn("Blob for digest %s does not exist. Deleting tag manifest: %s", manifest, other_tag)
                    tag_dir = os.path.join(self.registry_data_dir, "repositories", repo,
                                           "_manifests/tags", other_tag)
                    self._delete_dir(tag_dir)
                else:
                    raise
        return False

    def _manifest_in_same_repo(self, repo, tag, manifest):
        """check if manifest is found in other tags of same repository"""
        for other_tag in [t for t in self._get_tags(repo) if t != tag]:
            path = os.path.join(self.registry_data_dir, "repositories", repo,
                                "_manifests/tags", other_tag, "current/link")
            other_manifest = get_digest_from_blob(path)
            if other_manifest == manifest:
                return True

        return False

    def delete_entire_repository(self, repo):
        """delete all blobs for given repository repo"""
        logger.debug("Deleting entire repository '%s'", repo)
        repo_dir = os.path.join(self.registry_data_dir, "repositories", repo)
        if not os.path.isdir(repo_dir):
            raise RegistryCleanerError("No repository '{0}' found in repositories "
                                       "directory {1}/repositories".
                                       format(repo, self.registry_data_dir))
        links = set(get_links(repo_dir))
        all_links_but_current = set(self._get_all_links(except_repo=repo))
        for layer in links:
            if layer in all_links_but_current:
                logger.debug("Blob found in another repository. Not deleting: %s", layer)
            else:
                self._delete_blob(layer)
        self._delete_dir(repo_dir)

    def delete_repository_tag(self, repo, tag):
        """delete all blobs only for given tag of repository"""
        logger.debug("Deleting repository '%s' with tag '%s'", repo, tag)
        tag_dir = os.path.join(self.registry_data_dir, "repositories", repo, "_manifests/tags", tag)
        if not os.path.isdir(tag_dir):
            raise RegistryCleanerError("No repository '{0}' tag '{1}' found in repositories "
                                       "directory {2}/repositories".
                                       format(repo, tag, self.registry_data_dir))
        manifests_for_tag = set(get_links(tag_dir))
        revisions_to_delete = []
        blobs_to_keep = []
        layers = []
        all_links_not_in_current_repo = set(self._get_all_links(except_repo=repo))
        for manifest in manifests_for_tag:
            logger.debug("Looking up filesystem layers for manifest digest %s", manifest)

            if self._manifest_in_same_repo(repo, tag, manifest):
                logger.debug("Not deleting since we found another tag using manifest: %s", manifest)
                continue
            else:
                revisions_to_delete.append(
                    os.path.join(self.registry_data_dir, "repositories", repo,
                                 "_manifests/revisions/sha256", manifest)
                )
                if manifest in all_links_not_in_current_repo:
                    logger.debug("Not deleting the blob data since we found another repo using manifest: %s", manifest)
                    blobs_to_keep.append(manifest)

                layers.extend(self._get_layers_from_blob(manifest))

        layers_uniq = set(layers)
        for layer in layers_uniq:
            if self._layer_in_same_repo(repo, tag, layer):
                logger.debug("Not deleting since we found another tag using digest: %s", layer)
                continue

            self._delete_layer(repo, layer)
            if layer in all_links_not_in_current_repo:
                logger.debug("Blob found in another repository. Not deleting: %s", layer)
            else:
                self._delete_blob(layer)

        self._delete_revisions(repo, revisions_to_delete, blobs_to_keep)
        self._delete_dir(tag_dir)

    def delete_untagged(self, repo):
        """delete all untagged data from repo"""
        logger.debug("Deleting utagged data from repository '%s'", repo)
        repositories_dir = os.path.join(self.registry_data_dir, "repositories")
        repo_dir = os.path.join(repositories_dir, repo)
        if not os.path.isdir(repo_dir):
            raise RegistryCleanerError("No repository '{0}' found in repositories "
                                       "directory {1}/repositories".
                                       format(repo, self.registry_data_dir))
        tagged_links = set(get_links(repositories_dir, _filter="current"))
        layers_to_protect = []
        for link in tagged_links:
            layers_to_protect.extend(self._get_layers_from_blob(link))

        unique_layers_to_protect = set(layers_to_protect)
        for layer in unique_layers_to_protect:
            logger.debug("layer_to_protect: %s", layer)

        tagged_revisions = set(get_links(repo_dir, _filter="current"))

        revisions_to_delete = []
        layers_to_delete = []

        dir_for_revisions = os.path.join(repo_dir, "_manifests/revisions/sha256")
        for rev in os.listdir(dir_for_revisions):
            if rev not in tagged_revisions:
                revisions_to_delete.append(os.path.join(dir_for_revisions, rev))
                for layer in self._get_layers_from_blob(rev):
                    if layer not in unique_layers_to_protect:
                        layers_to_delete.append(layer)

        unique_layers_to_delete = set(layers_to_delete)

        self._delete_revisions(repo, revisions_to_delete)
        for layer in unique_layers_to_delete:
            self._delete_blob(layer)
            self._delete_layer(repo, layer)


    def get_tag_count(self, repo):
        logger.debug("Get tag count of repository '%s'", repo)
        repo_dir = os.path.join(self.registry_data_dir, "repositories", repo)
        tags_dir = os.path.join(repo_dir, "_manifests/tags")

        if os.path.isdir(tags_dir):
            tags = os.listdir(tags_dir)
            return len(tags)
        else:
            logger.info("Tags directory does not exist: '%s'", tags_dir)
            return -1

def main():
    """cli entrypoint"""
    parser = argparse.ArgumentParser(description="Cleanup docker registry")
    parser.add_argument("-i", "--image",
                        dest="image",
                        required=True,
                        help="Docker image to cleanup")
    parser.add_argument("-v", "--verbose",
                        dest="verbose",
                        action="store_true",
                        help="verbose")
    parser.add_argument("-n", "--dry-run",
                        dest="dry_run",
                        action="store_true",
                        help="Dry run")
    parser.add_argument("-f", "--force",
                        dest="force",
                        action="store_true",
                        help="Force delete (deprecated)")
    parser.add_argument("-p", "--prune",
                        dest="prune",
                        action="store_true",
                        help="Prune")
    parser.add_argument("-u", "--untagged",
                        dest="untagged",
                        action="store_true",
                        help="Delete all untagged blobs for image")
    args = parser.parse_args()


    handler = logging.StreamHandler()
    handler.setFormatter(logging.Formatter(u'%(levelname)-8s [%(asctime)s]  %(message)s'))
    logger.addHandler(handler)

    if args.verbose:
        logger.setLevel(logging.DEBUG)
    else:
        logger.setLevel(logging.INFO)


    # make sure not to log before logging is setup. that'll hose your logging config.
    if args.force:
        logger.info(
            "You supplied the force switch, which is deprecated. It has no effect now, and the script defaults to doing what used to be only happen when force was true")

    splitted = args.image.split(":")
    if len(splitted) == 2:
        image = splitted[0]
        tag = splitted[1]
    else:
        image = args.image
        tag = None

    if 'REGISTRY_DATA_DIR' in os.environ:
        registry_data_dir = os.environ['REGISTRY_DATA_DIR']
    else:
        registry_data_dir = "/opt/registry_data/docker/registry/v2"

    try:
        cleaner = RegistryCleaner(registry_data_dir, dry_run=args.dry_run)
        if args.untagged:
            cleaner.delete_untagged(image)
        else:
            if tag:
                tag_count = cleaner.get_tag_count(image)
                if tag_count == 1:
                    cleaner.delete_entire_repository(image)
                else:
                    cleaner.delete_repository_tag(image, tag)
            else:
                cleaner.delete_entire_repository(image)

        if args.prune:
            cleaner.prune()
    except RegistryCleanerError as error:
        logger.fatal(error)
        sys.exit(1)


if __name__ == "__main__":
    main()
View Code

 

# 首先,用export定义变量 REGISTRY_DATA_DIR 也就是Registry设置的映射盘路径

# 然后,执行脚本 -i 跟上镜像完整名字

 

 

  

 

 

 

使用harbor 搭建私有仓库

 PS: 注意安装的时候上面不能同时存在Registry!!!

# 记得先修改不使用https

 

   

  

 # 安装docker 编排工具

yum install docker-compose 

 

# haror 离线包

https://github.com/goharbor/harbor/releases

解压,导入镜像.tar 

拷贝模板

cp harbor.yml.tmpl harbor.yml

修改配置文件

注释掉https(生产环境视情况)

默认是80端口(生产环境注意修改)

查看Harbor初始密码(生产环境注意修改)

admin

Harbor12345

 

运行 准备prepare 脚本

运行 安装 install.sh 脚本

  

新建项目(tag分类),取名,选择“公开”

【成员】创建用户密码方便用户push镜像过来

# 直接推送,会发现提示需要验证(就是刚刚创建的用户)

注:推送镜像的时候一定要注意命名规则,镜像名字要叫如下方式才可push

<Harbor服务器IP或域名>/<harbor项目名>/<自定义的镜像名>:<TAG>,例如:

118.xxx.xxx.2/cka/c7:loki_v1 
118.xxx.xxx.2/cka/busybox:latest

 

 

# 登录用户

 

# 拉取

docker pull 118.xxx.xxx.2/cka/busybox

 

 

 

 

限制容器资源

目的:防止各个容器资源抢占

Cgroup : linux 系统下的功能

/etc/systemd/system/memload.service.d

# 使用memload 来进行测试

 

 

 memload <数值>

方法一: 创建容器的时候参数限制

 

 

 

OOM : 内存溢出  需求内存超过限制内存值

  

# 用来长时间占用cpu  测试

  

# 查看某个命令运行在哪些CPU上 

 --cpuset-cpus=0  #指定创建的容器在哪个cpu上运行

  

  

 

# 针对CPU和内存设定值修改方法

docker update  

--cpuset-cpus <使用的CPU核心ID>   e.g.   docker update bbox_t1 --cpuset-cpus 10-15 ## 你要确定你有这么多核心的cpu才能设置这个值

--memory-swap <这个值要大于内存值> ## 如果小于就会如下报错提示   e.g. docker update bbox_t1 --memory-swap 1024m

# 内存限制小于内存的SWAP的限制值,请同步修改内存SWAP值。

 Memory limit should be smaller than already set memoryswap limit, update the memoryswap at the same time

-m <内存大小>  e.g. docker update bbox_t1 -m 512m

  

Block IO 是另一种可以限制容器使用的资源。Block IO 指的是磁盘的读写,docker 可通过设置权重、限制 bps 和 iops 的方式控制容器读写磁盘的带宽。

 

block io 权重

(1)参数说明

  • 默认情况下,所有容器能平等地读写磁盘,可以通过设置 --blkio-weight 参数来改变容器 block io 的优先级。 
  •  --blkio–weight 与 --cpu-shares 类似,设置的是相对权重值,默认为 500。

 

限制 bps 和 iops 

(1)bps 和 iops介绍:
  • bps 是 byte per second,每秒读写的数据量。 
  • iops 是 io per second,每秒 IO 的次数。
 
(2)可通过以下参数控制容器的 bps 和 iops:
  • --device-read-bps:限制读某个设备的 bps。
  • --device-write-bps:限制写某个设备的 bps。
  • --device-read-iops:限制读某个设备的 iops。
  • --device-write-iops:限制写某个设备的 iops。

 

ctop 命令研究(仅能检测容器的资源情况)

sudo wget https://github.com/bcicen/ctop/releases/download/v0.7.5/ctop-0.7.5-linux-amd64 -O /usr/local/bin/ctop

sudo chmod +x /usr/local/bin/ctop

# 界面展示

# 基本常用命令  e 进入shell模式,l 进入log模式,o查看容器ip和资源信息,q退出

 

 

 

 

监控容器 

docker stats  # 监控容器基本信息

 

# 原理读取物理机这些目录

 

 cadvisor  # google 建立一个监控容器,查看其他容器资源消耗

 

 

scope 工具: Weave是由Zett.io公司开发的,它能够创建一个虚拟网络,用于连接部署在多台主机上的Docker容器,这样容器就像被接入了同一个网络交换机,那些使用网络的应用程序不必去配置端口映射和链接等信息。外部设备能够访问Weave网络上的应用程序容器所提供的服务,同时已有的内部系统也能够暴露到应用程序容器上。Weave能够穿透防火墙并运行在部分连接的网络上,另外,Weave的通信支持加密,所以用户可以从一个不受信任的网络连接到主机。

 

cadvisor:  为了解决docker stats的问题(存储、展示),谷歌开源的cadvisor诞生了,cadvisor不仅可以搜集一台机器上所有运行的容器信息,还提供基础查询界面和http接口,方便其他组件如Prometheus进行数据抓取