{"id":44457962,"url":"https://github.com/laincloud/lainlet","last_synced_at":"2026-02-12T18:08:40.275Z","repository":{"id":57522238,"uuid":"57270387","full_name":"laincloud/lainlet","owner":"laincloud","description":"LAIN's component","archived":false,"fork":false,"pushed_at":"2018-06-08T04:48:03.000Z","size":429,"stargazers_count":2,"open_issues_count":0,"forks_count":6,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-06-21T15:45:44.861Z","etag":null,"topics":["layer0"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/laincloud.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-04-28T04:15:45.000Z","updated_at":"2018-06-08T04:48:04.000Z","dependencies_parsed_at":"2022-08-26T20:23:40.302Z","dependency_job_id":null,"html_url":"https://github.com/laincloud/lainlet","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/laincloud/lainlet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laincloud%2Flainlet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laincloud%2Flainlet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laincloud%2Flainlet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laincloud%2Flainlet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/laincloud","download_url":"https://codeload.github.com/laincloud/lainlet/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laincloud%2Flainlet/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29375739,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-12T08:51:36.827Z","status":"ssl_error","status_checked_at":"2026-02-12T08:51:26.849Z","response_time":55,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["layer0"],"created_at":"2026-02-12T18:08:39.501Z","updated_at":"2026-02-12T18:08:40.265Z","avatar_url":"https://github.com/laincloud.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Lainlet\n\n[![MIT license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://opensource.org/licenses/MIT)\n[![Build Status](https://travis-ci.org/laincloud/lainlet.svg?branch=master)](https://travis-ci.org/laincloud/lainlet)\n[![codecov](https://codecov.io/gh/laincloud/lainlet/branch/master/graph/badge.svg)](https://codecov.io/gh/laincloud/lainlet)\n\n## 介绍\n\nLainlet主要负责为Lain集群中各组件和app提供实时的集群状态数据。集群的实时状态由deployd组件更新到etcd中，由于这状态数据结构复杂，不利于其他组件直接读取；而且过多的组件watch etcd会对etcd造成一定的压力。\n\n所以Lainlet的职责，就是从 etcd 中实时获取集群及应用的相关数据。简化数据结构，并提供get和watch的http api供其他组件使用。几乎每个要获取集群数据的组件，都会在Lainlet中有一个特定的api。\n\n\n## 整体设计\n\nLainlet内部分三层, 设计的重要目标之一是方便快捷的扩展新的数据结构API。\n\n如图所示:\n\n![lainlet-design](lainlet-design.png)\n\n\n1. 最下层封装了store接口，方便后端存储换成zookeeper或其他的存储，目前只实现了etcd存储。\n1. 中间层为watcher层，实现了通用的broadcast功能和cache数据结构，并封装成watcher接口。configWatcher和nodeWatcher等只是针对不同的key实现etcd的KV结构到cache的KV结构的转换。\n1. 最上层http层，通用的watch功能。同样不同的api只需定义自己的数据结构，并实现固定的接口，就可添加新的带有watch功能的api。\n\n\n## 编译和安装\n\n### 编译\n**环境需要: go1.5+**\n```sh\ngo build -o lainlet\n```\n\n### 运行\n**环境需要: etcd**\n\n```sh\n./lainlet -h # 查看运行参数\n\n# 例子\n./lainlet -web :9001 -etcd 127.0.0.1:4001 -ip 127.0.0.1 -debug # 监听9001端口\n```\n## API\n\n### 所有的API的通用规则:\n1. 默认情况下，api都是非watch的，就像很普通的Get请求。\n   如果需要需要watch功能, 可在相应api后添加`watch=1`或`watch=true`参数. (`watch=0`或`watch=false`表示非watch)\n\n2. 所有的watch请求, 都可设置heartbeat参数,表示心跳事件. 如`?heartbeat=5`表示每5秒发送一个心跳事件. 不设置或设置成0表示不使用心跳,就不会有心跳event返回\n\n3. 所有的watch请求, 返回值格式均为:\n   ```\n    id: uint // id只有在init 和 update时候为正整数，从1开始一次递增。error和heartbeat event id均为0\n    event: string // \"init\", \"update\", \"delete\", \"error\"或 \"heartbeat\"\n    data: string // heartbeat event没有此项, error event的data为错误说明\n   ```\n   而对于Get请求, 返回值是watch请求的data部分.\n\n### API列表\n\n#### `/v2/configwatcher?target=\u003ctarget\u003e`\n返回`/lain/config/\u003ctarget\u003e`的值, 接收参数target, 如果不指定，则返回所有的配置值。格式为json\ntarget 会被作为所有配置项的前缀进行搜索，比如 `target=a` 的情况会把所有 `a` 开头的配置项都返回。\n\n#### `/v2/procwatcher`\n返回`/lain/config/pod_group/\u003cappname\u003e`的精简结构\n\n#### `/v2/coreinfowatcher`\n返回`/lain/deployd/core_info/\u003cappname\u003e`的值, 可接受参数`appname`, 如果不给定appname，则返回所有app的coreinfo信息\n\n#### `/v2/localspecwatcher`\n返回跑在指定ip上的所有的proc的name列表. 可接收参数`nodeip`, 如果不给定`nodeip`，则使用lainlet的本机\n\n#### `/v2/proxywatcher`\n专给proxy用的api, podgroup的一个精简版本\n\n#### `/v2/depends`\n返回 `/lain/deployd/depends/pods`下的数据的简化版本\n`target` 参数如果不指定，返回所有 depends 数据，如果指定，它则作为前缀匹配所有 depends，返回一部分。\n\n#### `/v2/nodes`\n返回 `/lain/nodes/nodes`下的数据的简化版本\n\n#### `/v2/containers?nodename=\u003cname\u003e`\n返回 某节点下所有container的信息列表\n\n#### `/v2/webrouter/webprocs`\n返回所有web类型的proc的信息，数据结构和coreinfo类似，但是只包含container IP, Expose和Annotation信息。\n\n\u003e 为了保证在集群异常时，webrouter 的已有配置不被删除，在调用该接口时，如果超过一半的容器没有 IP 或者没有任何容器信息，则会返回 error。\n\n#### `/v2/rebellion/localprocs`\n返回所有本地的proc的信息，数据结构和coreinfo类似，但是只包含Annotation和InstanceNo信息\n\n### 其他API\n\n#### `/debug`\n返回lainlet的debug信息\n\n#### `/version`\n返回lainlet的版本信息\n\n## 已知问题:\n\n1. 如果lain集群的node数增加到100+，每个node上一个lainlet, 每个lainletwatch etcd的连接数大约10个左右。\n   这样整个etcd集群就是承受1000+的watch连接，etcd集群是无法承受这个数量级连接的。\n\n## License\n\nLainlet is released under the [MIT license](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaincloud%2Flainlet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flaincloud%2Flainlet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaincloud%2Flainlet/lists"}