Kubernetes包管理器Helm的本质

“本质”类的文章,通常很难带流量。而且写起来非常吃力。 那我为什么还要写?写作是对自己的锻炼。写作是让自己的思想更有深度的一种有效方式。 如果你觉得这篇文章对你有帮助,也你麻烦你转发这篇文章,这是对我的帮助。谢谢。 Kubernetes 的包管理器的本质 “Helm 是 Kubernetes 的包管理器”。Helm的官方网站如是说。 那什么是“Kubernetes 的包管理器”? 我们假设需要在没包管理器的场景下部署资源,你需要一个个文件手工地执行kubectl apply -f abc.yaml,abc.yaml就是Kubernetes的资源的定义文件。 文件内容如下: --- apiVersion: apps/v1 kind: Deployment metadata: name: abc labels: app.kubernetes.io/name: abc spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: abc 当需要卸载资源呢?你又需要手工执行kubectl delete -f abc.yaml。 所以每次发布,你都必须有一个发布记录,记录下哪些YAML要执行apply,哪些yaml要执行delete。而且delete后,你还要记得将那个文件从文件夹中删除。 如果每次手工执行,工作量大不说,还很容易出错。所以,有人会想到使用Shell脚本或者Python脚本来解决这些问题。 当你通过Shell脚本或者Python脚本能自动化解决以上问题时,实际上就等于实现了一个Kubernetes 的包管理器。 当我们真正理解以上所说的Kubernetes资源的部署问题后,你就明白了Kubernetes 的包管理器其实就两个核心功能: 自动化执行Kubenetes资源更新; 跟踪Kubenetes资源更新记录(本质还是版本化)。 我们在选择包管理器时,务必要从这两个角度考虑。像Grafana公司Tanka,并不是一开始就实现“跟踪Kubenetes资源更新记录”功能,具体可以看:https://github.com/grafana/tanka/issues/88 。 Helm是如何实现包管理的 注:本文讲的是Helm3。Helm2与Helm3存在较大差异。 Helm的包:Chart 假如存在一个微服务x,我们将其部署到Kubernetes中,需要准备Deployment、HPA、Service的这三种资源的YAML文件。这三个文件,统一放在一个文件夹中。 Helm本身是一个命令行工具。通过package子命令,可以将整个文件夹打包成一个tgz的压缩包。打包命令为:helm package x-service --version 1.0 。打包结果是一个tgz包。如下图: 这个tgz包,我们称之为Chart包。本质上它就是Kubernetes的资源文件的一个集合。 我们可以将Chart包上传到Nexus这类制品管理工具进行版本化控制。这涉及到Chart的管理的工程实践,不在本文范围。 在有了Chart包以后,我们可以通过命令helm install <release> <chart路径>将svc安装到指定的Kubernetes集群上。如x-svc的部署指令将会是:helm install x-svc ./x-svc-1.0.tgz。 ...

2024-02-26 · 1 min · 164 words · 翟志军 Jack Zhai

SRE-DevOps不得不懂的:Prometheus的配置工程化

背景 Prometheus有两个最基本的组件:一个是Prometheus程序,一个是Alertmanager程序。 它们的职责分工很明确: Prometheus程序负责:定时拉取监控指标数据、存储指标数据、根据告警规则发起告警通知; Alertmanager程序负责:负责告警通知的路由,即当接收到Prometheus程序的通知后,该将通知以何种方式通知给谁。 Prometheus程序的配置最核心的配置是: # ... # 当指标数据符合什么规则进行告警通知。 # 在其它文件定义,这里只是引用该文件的路径。 rule_files: [ - <filepath_glob> ... ] # 从哪里,该如何拉取指标 scrape_configs: [ - <scrape_config> ... ] # ... Alertmanager程序的配置最核心的配置是: # ... # 告警通知路由规则 route: [- <route_config>-] # 告警通知的接收者列表,部分监控告警平台也称之为channel receivers: [- <receivers>-] # ... 在实际工作中,Prometheus和Alertmanager的配置会非常大。 严谨的软件工程要求我们在真正部署这些配置前,对其进行有效性和正确性的检查。否则SRE/DevOps的工程效率就会很低,因为你需要手工调试庞大的配置。 所以,我们需要有一种高效率的方式来保证配置的有效性和正确性。 保证Prometheus程序配置的有效性和正确性 promtool Prometheus程序提供了一个叫promtool的命令行程序。解压Prometheus的程序包后,你会发现它和Prometheus程序放在一个文件夹中。 promtool提供了一些子命令来保证Prometheus程序配置的有效性和正确性: # 校验Prometheus配置的有效性,它支持--lint="duplicate-rules"参数,用于检查重复的rule配置 check config [<flags>] <config-files>... # 校验rule配置的有效性 check rules [<flags>] <rule-files>... # 执行rules单元测试用例 test rules <test-rule-file>... 至于有效性检查,只需要执行check子命令即可,不需要过多说明。 ...

2024-02-26 · 2 min · 390 words · 翟志军 Jack Zhai

云原生部署之Helm最佳实践

半年多前,我们从传统的Ansible自动化部署迁移到了云原生部署。我们没有通过Rancher或者KubeSphere这些平台的可视化界面部署,而是选择了Helm这个命令行工具。原因有以下几点: 坚持一切版本化,一切自动化的原则; Helm在声明式思维方面相对其它工具更友好; 方便配置与制品分离; Helm目前有两个版本:v2和v3。幸运的是,我们正准备大规模使用时,v3版本发布。所以,我们没有经历升级之苦。特此说明以下最佳实践基于Helm3。 注:本文针对对Helm有一定基础的同学,如果没有基础,可以先收藏。 正片开始: 自行版本化chart maven、npm等构建工具的包会有一个唯一的官方源,但是,Helm的chart包似乎没有,你会遇到很多不同的源。这对chart的版本控制非常不利,因为你不知道哪天,远端的源就不见了。所以,最好的做法,使用helm pull命令将chart下载本地,然后指定一个版本上传制品库Nexus的Helm仓库中。上传命令为: curl -s -u '${USER_PASS}' --upload-file ${chart_name}-${charts_version}.tgz http://xxx-nexus.com/repository/helm-repo/ 使用upgrade —install子命令部署应用 刚开始学习Helm时,我们通常使用helm install来安装chart。但是,第二次执行helm install,就会报错,因为K8s中已经存在了该chart的release了。这个过程对流水线是不友好的,所以,在流水线,我们使用的是helm upgrade —install xx ./xx.tgz来部署。 尽早标准化应用,标准化chart 如果存在100个微服务,我们是不是要创建100个chart呢?事实上,一开始,我们团队就是这样的。这是因为我们的微服务一开始不够标准化,所以,chart也跟着不同。后来,我们逐渐标准化了应用。chart也变成了标准。也就是所有的后端服务使用的是同一个chart。这样做的还有利于提高我们创建新的微服务的速度。 所谓标准化,指的是pod对外提供服务的端口号、优雅停机、设置环境变量的方法等等这些通用的领域的配置都应该是统一的。 尽量少使用if-else判断 以chart中,我们应该尽量少使用if-else判断。有时,宁愿多写几个YAML也不要在同一个文件嵌套if-else。因为要尽可能的让chart本身所见即所得。 使用template子命令快速调试chart 当我们在开始chart时,每次修改都要执行一次helm upgrade来验证正确性是很不经济的。Helm提供了template子命令,用于验证我们的chart的语法的正确性。示例:helm template <chart的地址>。 定义一个全局的values.yaml chart中的values.yaml文件为我们提供了chart的默认配置。同时,我们可以在执行helm upgrade —install部署chart时,加入-f values.yaml来指定另外的values文件,比如: helm upgrade --install -f ./abc.yaml abc ./abc-chart.tgz 但是,有些配置,是全局性的,比如mysql的url。我们不希望它重复写在不同的应用的配置中。所以,我们定义一个全局的values.yaml。比如:global-value.yaml。helm的命令将变成: helm upgrade --install -f ./global-value.yaml -f ./abc.yaml abc ./abc-chart.tgz 利用helm的-f参数的顺序实现配置的优先级 当全局values文件与应用的values存在配置冲突的时候,通过会采用应用的values文件中的配置。需要注意的是 -f 参数的顺序。后一个 -f 参数的配置会覆盖前一个-f参数的配置。 多版本的实现 过去,我们通常是一个应用一个版本。但是,现在我们更多的是一个应用线上同时存在多个版本。所以,一个chart能同时部署多个版本的应用。 helm upgrade --install -f ./global-value.yaml -f ./abc.yaml --set 'image.tag={1.2.1,1.2.3}' abc ./abc-chart.tgz chart中的deployment文件: ...

2024-02-26 · 1 min · 174 words · 翟志军 Jack Zhai

可落地的云原生应用规范

应用的规范定义是一个权衡的过程,你不能一下把规范定义得太死,太死了导致无法很好的在不同团队推广,最后可能导致规范失去信用。你也不能把规范定义得太泛,导致人们不知道如何下手。 在经历了传统部署(使用Ansible自动化部署应用到虚拟机)和Kubernetes的部署(使用Helm实现自动化部署)后,我们总结出一套云原生应用规范。它无关语言,无关框架,无关部署方式。 定义此云原生应用规范,我们有以下几个目的: 节约人员沟通成本:你不需要像以前那样需要反复的问对方的服务的端口; 节约运维成本:因为应用是标准的,所以,对于所有的应用,只需要使用统一的部署方式、统一的监控方式; 节约开发新应用的成本:根据规范,我们可以搭建各种语言或者框架的工程的脚手架; 以下是规范正文: 业务端口规范 所有的Pod或部署在虚拟机上的应用要求: http协议的服务使用8000端口 grpc协议的服务使用9000端口 如果有其它协议可以在此添加 所有的Service:使用80端口 实践Tips1:遗留工作通常没有统一的端口,我们可以在部署环节通过环境变量来覆盖应用本身的端口来实现统一端口的目的。 实践Tips2:对于虚拟机上的部署,过去,一台机器上我们常常部署多个应用,所以要求每个应用的端口都不能相同。我们的做法,缩小虚拟机的配置,一个虚拟机只部署一个应用。 监控端口规范 监控端口统一使用:30000。监控端口与业务端口分离是基于安全的考虑而设计。而且监控端口只允许内部访问。 提供Prometheus监控接口/private/prom:返回 prometheus标准数据结构; 提供优雅停机接口/private/shutdown:POST请求即代表发起停机操作; 提供健康检查的接口/private/health:http code返回200代表健康; 提供应用ready接口(可以与健康检查接口相同)/private/ready:http code返回200代表ready; 提供实时修改日志级别的接口:/private/loggers 。这个接口,我们可以参考Java的Logback框架的实现。 Docker镜像规范 提供 curl 命令行,因为我们需要使用命令进行优雅机器:curl -XPOST <http://127.0.0.1:30000/private/shutdown; 应用需要提供应用进程的环境配置入口。比如JVM应用需要提供 JAVA_OPTS 的环境变量设置 实践Tips:实际工作中,可创建一些基础镜像方便开发人员使用。 日志规范 日志要求统一输出到console。输入日志统一使用json结构。json结构中必须包含字段: @timestamp: 日志打印时间 thread_name:进程名 level:日志级别 appId: 应用标识,同一个namespace全局唯一 namespace:用于隔离app,租户的功能 env:环境标识 ver:应用版本 msg:帮助debug问题的 traceId: 其实就是traceId 同时,我们建议使用以下通用字段: event:代表事件,建议不要使用带空格的字符串 method:方法名 result:代表执行结果,可以是方法的返回结果,也可以http方法的response req:代表请求参数体 以下是日志示例: {"@timestamp":"2021-07-15T17:24:07.912+08:00","userName":"Foobar","thread_name":"http-nio-8080-exec-150","level":"INFO","appId":"UserService","env":"prod","ver":"v1.0-5598","event":"register_user"} 实践Tips1:在实际工作,我们需要为不同的语言实现符合此日志规范的框架。 实践Tips2:日志规范需要配合日志处理环节考虑,在日志处理环节没有准备好之前,保持原样是更明智的选择。 小结 此规范已经在我们团队实践一年多。正在向其它团队延伸的过程。不敢说它是一套面面俱到的规范,但是它是一套能在一些团队进行落地的规范。 每个人都存在认知不足的情况,我也是人,所以我也不例外。此规范只是版本1.0。将来发现不足,持续改进。

2024-02-26 · 1 min · 62 words · 翟志军 Jack Zhai

我是如何将同事的代码改成DDD风格的

DDD是领域驱动设计的简写。前段时间听群友说行业里少有DDD的代码案例,进而对DDD没有一个感性的认识。我想这是行业里普遍存在的现象吧。所以,我就有了写此文的想法。 本文开篇介绍了行业里比较普遍的代码风格,接着,我采用DDD风格对其进行修改。 我无意说服读者要按照我认为的DDD的风格来写代码,只是想告诉大家,这个世界上,还存在另一种代码风格。 如果各位觉得这样的风格好,可以尝试一下。非常欢迎大家反馈,平时太少人和我交流这些了。 文章标题说的是“同事的代码”,其实只是为了让此文更具传播,没别的意思。 如果你觉得此文对你有帮助,麻烦转发。干货好文不易。谢谢。 本文虽是以Java语言为案例演示,也希望对其它语言的读者朋友有帮助。 行业里普遍的代码风格,简称A风格 代码结构如下: ├── domain domain模块被同事认为是用于存放专门和DB打交道的类的地方 - src/main/java/com/xx/domain/account/repository/AbcLoginInfoRepository.java - src/main/java/com/xx/domain/account/AbcLoginInfo.java ├── repository-impl - 包路径太长省略/AbcLoginInfoRepositoryImlp.java ├── server - src/main/java/com/xx/server/login/LoginService.java - src/main/java/com/xx/server/login/LoginController.java - src/main/java/com/xx/server/login/AuthCodeVo.java - src/main/java/com/xx/server/login/UserInfoVo.java - src/main/java/com/xx/config/AbcWebMvcConfigurer.java Server模块 A风格下,整个业务系统的业务逻辑都在此模块中。 LoginController.java 实现http服务: @Controller @RequestMapping public class LoginController { @Autowired LoginService loginService; // 省略一些不重要的代码 @GetMapping(value = "/login") @ResponseBody public UserInfoVo login(String code) throws IOException { UserInfoVo userInfoVo = loginService.login(code, httpServletResponse); httpServletResponse.sendRedirect("/"); return userInfoVo; } @GetMapping(value = "/logout") @ResponseBody public boolean logout() { return loginService.logout(httpServletRequest,httpServletResponse); } } UserInfoVo.java是返回给前端的用户信息的结构体: ...

2024-02-26 · 4 min · 849 words · 翟志军 Jack Zhai

这10年,我所经历的领域驱动设计(DDD)

笔者2011年入行时,运气好,遇到了我的恩师simon杨。 当时,我们几个还不知道什么叫SSH(Spring、Struts、Hibernate)的毕业生和一个高级程序员基于DDDLib就开始实践领域驱动设计。现在想想还是觉得不可思议。一毕业就开始接触这门DDD技艺。 我记得当时simon杨经常谈如何利用抽象、解耦,在不增加复杂性的同时实现简单性、一致性、灵活性、可扩展性。至于如何实现CRUD,那是具体实现的问题,可以放在最后做。当他谈到某个精妙的设计时,眼神里都满是光。 在他的教导下,我就开始似懂非懂地读《领域驱动设计》、《企业应用架构模式》、《敏捷软件开发——原则、模式与实践》等这些高层设计类的书籍。 也许你会说,对于一个刚毕业的人学习这些“高层”设计,是不是太早了,毕竟你连CRUD都还不熟练。 在我工作10年之后看来,越早学习这些,越好。当你习惯使用CRUD的思维方式来看所有的问题时,你的思维方式已经固化,是很难接受DDD这套思维方式的。我尝试过说服不同工作经验的人使用DDD,无果。 2013年,在国内,也只有Jdon网站讨论DDD。而我们已经跟着simon杨在项目上实践DDD两年了。 2014年左右,为了验证了我是否真的理解DDD,我利用一次比赛的机会采用DDD的方式设计了一个BlackJack的游戏的核心。到此,我才算是对DDD有了一个更深入的理解。 但是,在2014年以后到现在的2021年,我就再也没有接触过DDD的项目了。而我,只能在自己的工作内容范围内实践,比如某个功能、某个模块。 值得说的是,我最近3年做的是DevOps相关的工作,但是DDD的思维方式依然能帮助我很好的完成工作。 比如在实现流水线时,将构建工具逻辑与流水线流程逻辑解耦、在设计 版本号时,将构建工具本身的版本号与流水线流程生成的版本号分离。 如果你不熟悉DevOps也没有关系,你只需要知道DDD贯穿着整个系统设计的每一个细节。 现在市场上把DDD吹得很高大上,似乎只有在架构上做DDD,才叫DDD。又或者非得和微服务关联在一起,才叫DDD。 其实不然,DDD的原意是领域驱动设计。只要你是使用领域知识来驱动你的设计,这个设计可以是方法级别的设计、类级别的设计、前端UI的设计等一切设计,你都可以叫DDD。 也许,这样的话听起来就像“色即是空,空即是色”一样让人不知所云。 没办法,10年了,我也没有找到非常好的让人一下就懂这种思维方式的方法。 如果非得要我介绍一下DDD的思维是什么,我觉得就是:不停地问问题是什么,解决方案是什么。然后优先从问题域着手设计。在确定问题域设计得差不多了,才开始实现解决方案。 这里要提个问,如果拿到一个需求时,先设计MySQL的表结构,再根据表结构导出类。这样的方式符合DDD的思维方式吗?如果不符合,与DDD的思维方式有什么区别? 最后,我想说的是《领域驱动设计》我读过3遍了,也实践这么多年了,我依然记不清“战略设计”、“柔性设计”等这些术语的准确定义。我也建议各位不要去记那些术语的定义,更不要去争论那些术语的定义,而是要从DDD的原意开始去理解DDD。也就是每当遇到一个术语,你就提问:它是帮助你领域驱动设计的呢。

2024-02-26 · 1 min · 20 words · 翟志军 Jack Zhai

Effortless English英文学习小结

学习英文最大的两个问题: 正确的学习方法 坚持 正确的学习方法,我是自认为是已经掌握了的。但是,我很难坚持下来。 Effortless English是我follow最长时间的英文教程。我断断续续听了有一年了。 有一段时间,我真正地做到按照课程里的听,并练习。然后在那段时间,我的大脑会不自觉地使用英文描述生活中的事情。这种状态是真正把英文内化的一个状态。 在两天前,我看了别人推荐《把你的英语用起来!》,书中提到了“坚持这件小事”,我才发现,在过去,我的问题出在坚持。 在看了《把你的英语用起来!》我没有坚持下来的原因是: 给自己的目标期望太高了; 没有养成正面的自我激励模式。 通常我们认为坚持会是一件痛苦的事情。然而,这是一个错误的认知。如果它是一件快乐的事情,坚持是不需要痛苦了。 所以,接下来,我需要针对性解决以上两个问题。 说回Effortless English课程的学习方法。 该课程由A.J. Hoge录制的纯音频的全英文课程(没有写作和阅读)。它由一系列的由易到难的mini-story组成。 每次课一个story,它又分成三部分内容(三个音频),每部分要达到的目标有所不同: 第一部分:几分钟mini-story陈述 目标:能听懂故事的内容 第二部分:介绍Mini-story中的重点单词 不需要刻意的记忆这些单词,因为在重复听和练习过程中,自然就记住了它们 第三部分:采用不同的时态对同一个story进行复述 目的是让你自然形成英文语法的语感 AJ会在课程中提问。问题包括两类: 问你懂的(如果你不懂,说明你没有听懂第一部分)。针对这类问题,你要做的就是快速回答。回答通常只需要一两个单词。 问你不懂的(需要你猜测的)。针对这类问题,你要立刻作出猜测性的回答。 这个过程像是锻炼你的大脑肌肉,对英文问题的回答形成肌肉记忆。 而且,AJ会从各个角度对同一件事情进行提问,问发生地点、发生时间、谁参与了……。这个过程,很像父母在教两岁左右的小孩学习说话。 以上是AJ Hoge每节课的pattern。但是随着Level的上升,课程里会逐渐出现复述、跟读的练习。 复述过程是最容易放弃的阶段。 说完内容,说说学习计划。 每次课都要坚持一个星期。每天至少一个小时(早上30分钟,晚上30分钟)。 如果遇到难的课程,延长学习该课的时长,直到你真正掌握该课。 最后,我想说,Effortless English能非常好地锻炼你英文听说的真正能力,如果你学习英文的主要目标是为了雅思拿个好成绩,这个课程不能在短时间内提升你的分数。

2024-02-19 · 1 min · 37 words · 翟志军 Jack Zhai

如何将DDD应用到基础设施设计?

前段时间在面试的时候,面试官问到:你是如何将DDD(领域驱动设计)应用到基础设施的? 我很惊讶,终于有人问我这个问题了。 在过去从事基础设施(DevOps、SRE、运维)的这5年里,我经常说起DDD是一种思维模式,可以应用到任何的领域,包括基础设施的设计。 但是,从来没有人像这位面试官问起我具体的做法。 为什么没有人问?原因大概是这两个概念通常是不会放在一起的。大多数开发不会深入理解基础设施的设计,而大多数从事基础设施设计的人是不会接触到DDD。而且,开发人员对于DDD的理解,也仅局限于用它开发业务系统。 我就是那少部分人,即做基础设施的设计,又觉得自己懂DDD的人。 说回问题本身。 我所理解的DDD 我首先会向提问的人澄清我所理解的DDD。 为什么要这样呢?很久以前有一次面试,因为我说我擅长DevOps,面试官就认为我不懂GitOps。然后在这个点上他就认为我不适合,不再问我DevOps方面的问题。我只能说没有缘份。 我是这样解释DDD的: 就像开发一个象棋游戏,不论你要开发手机端,还是web端,象棋规则本身都是不变的。这个规则本身就可以理解为“领域”。 其它所有的技术(包括架构)都是具体实现,它们应该由“领域”来驱动设计。 当时的解释与以上的解释大差不差。 将DDD应用到基础设施设计的具体做法 那么该如何将DDD应用到基础设施的设计呢? DDD的思维方式要求我们首先问:我们要设计的软件的领域(核心)问题是什么? 基础设施的领域问题是什么?我的回答是配置。 我认为基础设施的搭建、维护,本质就是配置的设计、部署、维护。 寻找领域(本质)问题的能力是DDD的核心能力。 为了让读者更好理解,我们以一个一个基于云上的虚拟机的分布式系统为例。它的基础设施就包括:vpc、LB、MQ、DB等。 要搭建、维护这一套基础设施。 根据“配置管理是基础设施设计的核心问题”,我首先将基础设施的所有的配置放在清单代码(并不一定是一个文件)中,如下: vpc: # .... LB: # ... DB: # ... MQ: # ... APP1: mq_addr: "{{ MQ.addr }}" db_host: "{{ DB.addr }}" APP2: mq_addr: "{{ MQ.addr }}" db_host: "{{ DB.addr }}" app1_addr: "{{ APP1.addr }}" 从清单中,你看不出它使用何种部署方式、部署顺序。你只知道APP1引用了MQ和DB,APP2会调用APP2这样纯粹的领域知识。 现实通常是多个环境,所以,我一开始就会将不同环境的值从清单上抽离到独立的文件夹中。 第二步,我才会考虑如何部署它们。这时,我通过两个工具实现: Terraform负责云基础设施; Ansible负责业务基础设施。 Ansible是可以直接读取我们的YAML格式配置文件。而Terraform代码引用YAML代码,就没有那么方便了。 ...

2024-01-27 · 1 min · 78 words · 翟志军 Jack Zhai

程序员想告赢开发商一户一表违约

导言 正如标题所言,我是一名程序员。2023年5月之前,我是一个法盲,不懂起诉的流程,更不懂开庭的步骤。 但在过去的一年中,我以各种身份参与庭审多次,包括: 以被告的公民代理的身份,为被告辩护,参加庭审:1次 以原告的公民代理的身份,为原告辩护,参加庭审:1次 以原告的身份起诉开发商:2次 以起诉人身份参加二审:1次 以旁听的身份参加庭审:2次 多次为小区其他业主免费写起诉状、答辩状、再审申请书等多份文书。 但是结果是什么呢?后文会说。如果你只想知道官司输赢,可以直接划到文章最后。 本文比较长,你可以挑选自己感兴趣的部分开始。 如果您觉得本文有意义,还请转发给其他遇到相同问题的业主,以帮助更多的人。如果帮到你,还请用实际行动赞赏本文。 你我的权益,需要法制社会来保护,也需要你我的努力。 背景介绍 我是2017年购买的商品房,坐落在一个18线的县城。开发商是市里的一家房地产开发商。 但是直到现在小区还是由物业代抄电表,代收电费交给开发商。 在2020年和2022年的两次水灾中,其它实现了一户一表的小区,供电局很快就恢复供电了。但是我们小区停电了半个多月,因为开发商需要自己找人去修该变压器。 这里有两个背景知识: 开发商需要将小区的变压器的产权无偿移交给供电局,变压器的维护才由供电局负责; 一户一表:说大白话就是由业主与供电局直接发生供用电关系,而不是由开发商代缴电费。 业主是2020后才知道小区并不是一户一表的。所以,部分小区业主从那时开始拒绝“交电费”。开发商只能为这部分业主“垫付”电费。 2023年5月,开发商不再为业主“垫付”电费。小区因此被供电局停电。 接下来,小区业主与开发商、镇政府、供电局、住建局等多方,进行长时间地“拉扯”(中间的故事可以再写一篇文章,但是考虑到篇幅,本文不详写)。 虽然现在小区有电用,但至今小区依然没有实现一户一表。这就是多方拉扯的结局。懂的都懂。 其间,我开始研究业主与开发商之间的合同《商品房买卖合同》(由国家住建部和国家工商局2014年制定的格式合同),商品房验收条件中,关于电的部分,合同上的原文是这样的: 供电:交付时纳入城市供电网络并正式供电。 也就是合同里并没有写明“一户一表”。也请读者朋友拿出自己的合同,找到相关条文确认。因为合同一字之差就差个十万八千里。 根据这条合同条文,我们不能以“未实现一户一表”来起诉开发商。只能起诉开发商没有实现“交付时纳入城市供电网络并正式供电”。 本文为了方便,会将两“一户一表”与“交付时纳入城市供电网络并正式供电”混用,但是它们意思大致相同。注意,在庭审过程,它们不是同一事物。 这里再次提醒读者:起诉开发商,必须以合同为依据起诉。 以上简单介绍了背景知识(实际情况更复杂)。接下来解答一些读者会提出来疑问: 为什么要写下这些 在前几天,我刚刚结束了二审(判决结果还没有出),我决定将整个经历写下来。原因有二: 一是因为我这人记性不好,想记录下这段有意义的经历;二是希望为法制社会做出一点点微薄的贡献。 为什么不找律师? 我在找律师前做了很多功课,比如起诉开发商涉及的法律条文、开发商会如何抗辩等。但是,在找过多家律师所后,我最终决定不找律师。 原因有: 本县城的律师不愿意为我们打官司,有律师认为钱太少,有律师听到小区名字就说不打。部分业主甚至愿意与律师平分违约金。 隔壁县城的律师找了两个,我个人判断不可靠。当我拿出《合同》与他们讨论其中的条文时,他们并没有给出令我满意的答案,而且整个市的律师都在同一个律师协会里,懂的都懂; 省会的律师不太可能受理我们这种小金额官司。连他们的差旅费,我们可能都给不起; 小区里并不是所有的人都愿意打这个官司(这个是关键)。 我以个人名义打官司,就不会有以上问题了。 为什么不是起诉物业? 说白了,小区物业就是开发商的一家子公司。所以很多业主经常误以为物业就是开发商,毕竟“交电费”是直接交给的物业的。 小区的几次停电,部分业主跑去物业那里“闹”,这是找错对象了。因为我们小区的供电主体是开发商,不是物业。 再多说一句,如果物业没有代缴电费的权力(具体要看物业合同),所以他们也无法起诉你不交电费给他们。 为什么不是起诉开发商不移交变压器? 这在上文已经说明了,要以合同为依据来起诉。合同里并没有写“移交变压器”的条文。 集体诉讼,还是一个个单独诉讼? 在没有接触真正的诉讼流程前,我也以为我们是可以集体诉讼的。 但是在学习后,发现中国是没有集体诉讼的概念的。只能单独诉讼。如果我错了,还请纠正我。多谢。 假如有律师接受整个小区对开发商的诉讼,律师也是分别和每一位业主签法务合同。律师只不过是批量操作,并不是真正意义的集体诉讼。 我可以代理其他人的诉讼吗? 如果没有集体诉讼,那么,我将面临两个问题: 我是自己起诉开发商,还是和其业主一起? 我可以代理其他业主的起诉吗?并不是每一个业主都有时间。 对于问题1,经过深思熟虑,我做出的策略是:我以个人名义单独起诉。 因为我完全没有诉讼经验,不知道法官和开发商会如何抗辩。即使我本人这次官司输了,其他人也可以以我的诉讼经验发起另一次诉讼,直到打赢。 关于问题2,你是可以以公民代理的身份代理你的邻居或者亲戚的诉讼。中国不允许没有律师执照的人为其他人代理诉讼,公民代理算是对这机制的补充。如果我理解错了,还请纠正,谢谢。 公民代理的方法是: 取得证明你们关系。 如果是邻居关系,就拿双方的购房合同或者房产证去当地居委会开证明; 如果是亲戚关系,就拿双方的户口去公安局、居委会或者村委会。可能每个地方不一样,你需要咨询当地的居委会或者村委会; 准备授权委托书,即你的邻居或者亲戚将案件委托给你的证明; 在提交起诉状或者开庭前向法庭提交双方身份证复印件、委托书和关系证明。 以上是我个人的总结。但是,还是建议有需求的读者,请咨询当地法院。 题外话,我在给邻居代理时,发生了两件“有趣”的事情。 一件是当我给其中邻居代理房产证逾期的诉讼时,负责立案的”漂亮“的小姐姐,气急败坏似地不给任何理由地拒绝了我的代理。这超出了我认知。她不是在法院知法犯法吗? 另一件也是这个“漂亮”的小姐姐,我在立案时,故意刁难我,本来可以使用微信线上交纳诉讼费的,却跟我说法院规定月底最后三天,需要线下去银行柜台汇款。 当时,我不清楚,天真去线下交了,浪费了我大量时间。后来有一次也是月底,我看到其他所有人都不需要线下汇款。我想法院应该是没有任何理由拒绝我线上支付的。如果有懂相关法律的读者可以告诉我。 ...

2024-01-22 · 3 min · 467 words · 翟志军 Jack Zhai

Setting up EKS with Bazel, Jsonnet and Terraform

Overview In this document, I’ll describe my solution from the following parts: Part1 Architecture: describe the desired state of the architecture Part2 Implementation: Code Structure Introduce How to Build it Deploy Nginx Controller using Helm Part1: Architecture We assume that the project has a project named: health. Here’s the architecture graph, which draw by Excalidraw Network Architecture I created 4 subnets that are evenly distributed to 2 Availability Zones. Each availability zone has 2 subnets, one is public subnet,and another one is private subnet. The public subnet goes out through the Internet gateway and the private subnet goes out through the NAT gateway. ...

2024-01-20 · 7 min · 1300 words · 翟志军 Jack Zhai