在CoreOS上使用etcd进行服务发现时如何处理陈旧数据?

 Owi妓l_972 发布于 2023-01-29 08:44

我目前正在修改CoreOS并基于它创建一个集群.到目前为止,CoreOS在单个主机上的体验非常顺畅.但是在服务发现方面,事情变得有点模糊.不知怎的,我没有得到整体想法,因此我现在在这里寻求帮助.

我想要做的是让两个Docker容器运行,第一个依赖于第二个.如果我们谈论纯粹的Docker,我可以使用链接容器解决这个问题.到现在为止还挺好.

但是这种方法不适用于跨机器边界,因为Docker无法跨多个主机链接容器.所以我想知道如何做到这一点.

到目前为止我所了解的是,CoreOS关于如何处理这个问题的想法是使用它的etcd服务,它基本上是一个分布式键值存储,可以通过端口在本地的每个主机上访问4001,所以你不必处理(作为消费者etcd)有任何网络细节:只是访问localhost:4001,你没事.

所以,在我看来,我现在认为这意味着当提供服务的Docker旋转时,它会在本地注册自己(即其IP地址和端口)etcd,并etcd负责在整个网络中分发信息.网络.这样,例如,您获得键值对,例如:

RedisService => 192.168.3.132:49236

现在,当另一个Docker容器需要访问a时RedisService,它从其自己的本地获取IP地址和端口etcd,至少一旦信息已经通过网络分发.到现在为止还挺好.

但现在我有一个我无法回答的问题,这让我困惑了几天:当服务出现故障时会发生什么?谁清理了里面的数据etcd?如果未清除,则所有客户端都会尝试访问不再存在的服务.

我现在能想到的唯一(可靠)解决方案是利用etcd数据的TTL功能,但这需要权衡:要么你有相当高的网络流量,因为你需要每隔几秒发送一次心跳,或者你必须忍受过时的数据.两者都不好.

另一个,我能想到的"解决方案"是让服务在停机时注销,但这只适用于计划停机,而不是崩溃,电力,......

那么,你是如何解决这个问题的?

1 个回答
  • 有几种不同的方法可以解决这个问题:sidekick方法,使用ExecStopPost和删除失败.我假设的三人CoreOS,ETCD和systemd,但这些概念也适用于其他地方也.

    Sidekick方法

    这涉及在心跳到主应用程序旁边运行一个单独的进程etcd.简单来说,这只是一个永远运行的for循环.您可以使用systemd的BindsTo来确保当主机停止时,此服务注册单元也会停止.在ExecStop中,您可以明确删除您正在设置的密钥.我们还设置了60秒的TTL来处理任何不合适的停工.

    [Unit]
    Description=Announce nginx1.service
    # Binds this unit and nginx1 together. When nginx1 is stopped, this unit will be stopped too.
    BindsTo=nginx1.service
    
    [Service]
    ExecStart=/bin/sh -c "while true; do etcdctl set /services/website/nginx1 '{ \"host\": \"10.10.10.2\", \"port\": 8080, \"version\": \"52c7248a14\" }' --ttl 60;sleep 45;done"
    ExecStop=/usr/bin/etcdctl delete /services/website/nginx1
    
    [Install]
    WantedBy=local.target
    

    在复杂的一面,这可能是一个容器,它启动并命中/health应用程序提供的端点,以便在发送数据之前运行运行状况检查etcd.

    ExecStopPost

    如果您不想在主应用程序旁边运行某些内容,则可以etcdctl在主单元中使用命令在启动和停止时运行.请注意,正如您所提到的,这不会抓住所有失败.

    [Unit]
    Description=MyWebApp
    After=docker.service
    Require=docker.service
    After=etcd.service
    Require=etcd.service
    
    [Service]
    ExecStart=/usr/bin/docker run -rm -name myapp1 -p 8084:80 username/myapp command
    ExecStop=/usr/bin/etcdctl set /services/myapp/%H:8084 '{ \"host\": \"%H\", \"port\": 8084, \"version\": \"52c7248a14\" }'
    ExecStopPost=/usr/bin/etcdctl rm /services/myapp/%H:8084
    
    [Install]
    WantedBy=local.target
    

    %H是系统变量,可替换机器的主机名.如果您对更多变量的使用感兴趣,请查看CoreOS入门systemd指南.

    删除失败

    在客户端,您可以删除任何连接失败超过X次的实例.如果从中获得500或超时,则/services/myapp/instance1可以运行并继续增加故障计数,然后尝试连接到/services/myapp/目录中的其他主机.

    etcdctl set /services/myapp/instance1 '{ \"host\": \"%H\", \"port\": 8084, \"version\": \"52c7248a14\", \"failures\": 1 }'
    

    当您达到所需的阈值时,请删除密钥etcdctl.

    关于心跳可能导致的网络流量 - 在大多数情况下,您应该通过您的提供商运行的本地专用网络发送此流量,因此它应该是免费且非常快的.etcd无论如何,它总是在与同伴心跳加速,所以这只是流量的一点点增加.

    如果您有任何其他问题,请跳至Freenode上的#coreos!

    2023-01-29 08:49 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有