minikube 虚拟机无法访问外网的问题排查

通过 minikube 搭建本地的 K8s 环境用于测试,但是过了一段时间,突然在虚拟机内访问不了外网,拉不到镜像了,这里记录一下排查的过程,供后续再遇到时检索。

问题的根本原因是网卡上不知道为什么绑了两个 IP,其中只有一个可用,虚拟机访问外网时本地 IP 是不可用的那一个,才导致了问题。


Istio GRPC Gateway 禁用 HTTP1.1 请求

有一组专门用于 grpc 请求的 istio-gateway 网关,但是会被通过 HTTP1.1 的请求做漏洞扫描,istio gateway 仍然能够处理,并且会将这个请求转发给后端的服务,后端服务由于协议不匹配,会直接断开连接,istio gateway 就会返回 503。

这样会误触发告警,并且也会影响观测正常的监控。



通过 Istio 代理出方向的 TCP 流量

通过 Istio 可以劫持出方向的 HTTP/HTTPS 流量到特定的 Egress Gateway。通过固定 Egress Gateway 的节点可以实现线路优化,固定出口 IP,安全审计等等功能。






Istio 控制面配置推送分析与优化

Istio 主要分为控制面和数据面,控制面负责从数据源(通常是 K8s)获取变更内容,渲染成 envoy 使用的配置文件,推送到各个 Sidecar 和 Gateway 节点。

如果对 K8s 比较熟悉的话,可以和 K8s controller 类比,只是需要计算的内容更多。


Istio DNS Proxying

原理就是通过 iptables 劫持 DNS 查询请求到 sidecar ,由 sidecar 提供 DNS 请求的响应和转发。

对于 K8s 内部的 service 名称解析,会直接返回结果。

对于外部的域名,会转发给上游的 DNS Server 查询。


Istio sidecar TCP 空闲连接 1 小时自动断开

部分服务连接 redis 会经常出现连接被断开,导致从连接池中取出连接发送请求时会失败。

从 istio accesslog 中观测到到 redis 的连接,断开时间通常是 3600s 即一个小时。


Istio 服务请求外部域名持续出错,切换 DNS 后也无法恢复

假设 K8s 集群内的服务会以串行的方式不断请求一个外部域名的 80 端口。这个域名通过 DNS 解析到一个固定 IP。当某个时间段,这个 IP 上绑定的服务突然不可用,端口无法访问。内部服务会持续的得到 HTTP 503 的响应。

此时即使将这个域名的 DNS 切到一个正常的 IP,服务仍然会得到持续的 503 错误,一直无法恢复。



减少 Istio 控制面下发的配置

默认情况下,istiod 会 watch 集群中所有的 namespace,生成对应的配置,实时的通过 xDS 协议,推送给所有实例的 sidecar 容器。

业务实例会被分发到大量不相关的配置,根本用不到,不仅增加 istiod 分发配置的时效性,也增加了 sidecar 的资源消耗。



macos 上如何实现类似 iptables 的防火墙规则

Linux 上调试开发的时候,经常需要模拟网络断开,端口无法访问等场景。

mac 上开发也有类似的需求,例如禁用掉所有到 192.168.100.2 的 80 端口的流量。可以通过 PF 防火墙来实现。



Istio Gateway 支持 gzip

目前使用的 Ingress Nginx 中开启了 gzip 压缩。在将服务网关从 Ingress Nginx 迁移到 Istio Gateway 后,也需要相应支持这个能力。


Istio 1.9 升级 1.10 ExternalAuthorization 失效的问题

近期在将 Istio 1.9.1 升级到 1.10.4。发现原来在 1.9 版本中生效的 ExternalAuthorization 的功能在控制面升级到 1.10,数据面保持在 1.9 版本时,会失效。所有的请求都不需要鉴权就能访问到后端服务。


Istio sidecar 容器启动停止问题

由于引入了 sidecar,会通过 iptables 规则将流量劫持到 sidecar 中的进程。但是 K8s 上并没有精确控制 sidecar 的能力,导致由于 sidecar 与主容器的启停顺序问题会引起一些非预期的行为。



Istio 对 Service port name 的要求

由于 Istio 需要在七层解析流量,所以劫持服务流量后需要知道协议类型才能用合适的协议规则来解析。


Kubernetes 中支持 Pod 定向迁移

原生的 K8s 并不支持将指定的 Pod 从当前节点迁移到另外一个指定的节点上。但是我们可以基于 K8s 提供的扩展能力来实现对这一功能的支持。




kubernetes 自定义控制器的高可用

自定义 controller 通常要求只能有一个实例在工作,但是为了保证高可用,就需要有一个选主的机制,保证在 leader 因为某个异常挂掉后,其他节点可以提升为 leader,然后正常工作。


kubernetes 自定义控制器

kubernetes 的 controller-manager 通过 APIServer 实时监控内部资源的变化情况,通过各种操作将系统维持在一个我们预期的状态上。比如当我们将 Deployment 的副本数增加时,controller-manager 会监听到此变化,主动创建新的 Pod。

对于通过 CRD 创建的资源,也可以创建一个自定义的 controller 来管理。


kubernetes CRD 权限管理

对于一个多个用户的集群而言,通常单个用户只有自己 namespace 的相关权限,而 kubernetes CRD 需要配置额外的权限才能使用。


kubernetes 自定义资源(CRD)

在研究 Service Mesh 的过程中,发现 Istio 很多参数都通过 kubernetes CRD 来管理,例如 VirtualService 和 DestinationRule,这种方式使部署在 k8s 集群上的服务的管理方式更趋向一致。


Service Mesh 探索之升级 HTTP/2 协议

HTTP/2 是 HTTP/1.1 的升级,在请求方法、状态码乃至 URI 和绝大多数 HTTP 头部字段等方面保持高度兼容性,同时能够减少网络延迟和连接资源占用。Service Mesh 架构中,由于两个服务之间的通信由 proxy 介入,对于依靠 HTTP/1.1 通信的服务来说,可以无缝升级到 HTTP/2 协议。


使用 telepresence 在 k8s 环境中实现快速开发

随着容器化,微服务的概念逐渐成为主流,在日常的开发测试中,会遇到一些新的问题。例如如果服务跑在 istio 这样的 ServiceMesh 平台上,依赖于 k8s 的 sidecar 功能,在本地模拟这样的场景来调试和测试是比较复杂的。而 telepresence 帮助我们缓解了这样的问题。



Service Mesh 探索之优先本地访问

在设计 Service Mesh 架构方案时,考虑到有一些基础服务,访问频率高,流量大,如果在 kubernetes 平台上采用 DaemonSet 的部署方式,每一个机器部署一个实例,访问方能够优先访问同一个节点上的该服务,则可以极大地减少网络开销和延迟。


Service Mesh 探索之流量劫持

Istio 的项目中有一个亮点就是可以将旧的应用无缝接入到 Service Mesh 的平台上来,不用修改一行代码。实现这个功能,目前主要是通过 iptables 来截获流量转发给 proxy。


Service Mesh 自研实践

最近都在做自研 Service Mesh 方案的落地和后续迭代优化,目前稳定承接了旧系统的大部分流量,这里分享一下这套架构,以及过程中的思考和遇到的一些问题。


记一次mesos集群停容器时间过长的问题排查

公司 mesos 集群某个 app 已经有数千的实例数,每次做滚动升级时,由于总资源不足,需要分批操作,每次起一批新版本实例,再停一批旧版本实例。目前停容器的策略是,先从服务发现中摘除需要停掉的节点,等待 60 秒后再停止容器,释放资源,但是实际上每次从发送停止容器的请求到容器资源被实际释放需要长达 6 分钟,导致滚动升级耗时过长。经过排查,最终确认问题出在我们使用 docker 的方式上,这里记录下分析和解决问题的过程。


为 mtcp 项目添加 udp 支持

mtcp 是一个用户态的 tcp 协议栈,结合 dpdk 可以实现高性能的收发包。mtcp 不支持 udp 协议,想要在 bind 里利用 mtcp 进行加速,需要改动源码以提供支持。


减小 golang 编译出程序的体积

Go 语言的优势是可以很方便地编译出跨平台的应用程序,而不需要为每一个平台做代码适配,也不像 JAVA 一样需要预先安装 JDK 环境。相应的问题就是 go 编译出的程序体积较大,和 c/c++ 不同,它将大多数依赖都以静态编译的方式编译进了程序中。


golang 交叉编译

golang 相比 c/c++ 的优势之一是更容易编写出跨平台的应用,而不需要为各个平台编写适配代码。和 JAVA 相比,对系统环境要求较低,不需要预先安装 JDK 等适配环境。


InfluxDB详解之TSM存储引擎解析(二)

上一篇文章主要介绍了 TSM 存储引擎一些相关的概念、组件以及数据存储的目录结构,文件组成结构等内容。这一篇将会尽量从 InfluxDB 源码的角度,深入讲解数据插入、查询、合并等操作的具体流程以及内部数据结构的设计。


go 程序中获取虚拟块设备的读写速度

最近在写程序时需要在 centos5 系统上获取 device mapper 中的虚拟块设备的读写信息。在这个过程中发现由于 go 跨平台的特性,有一些 api 是无法拿到特定平台上的一些特殊信息的,或者是需要一些小技巧来实现。


InfluxDB详解之TSM存储引擎解析(一)

InfluxDB 项目更新比较快,google 了一下网上的一些文档基本上都是简单介绍了一下,而且很多都已经过时了,比如其中使用的 TSM 存储引擎,甚至官方文档上的内容都不是最新的。在源码里的 README 中有最新的设计实现的一些概要说明。


golang 中使用 statik 将静态资源编译进二进制文件中

现在的很多程序都会提供一个 Dashboard 类似的页面用于查看程序状态并进行一些管理的功能,通常都不会很复杂,但是其中用到的图片和网页的一些静态资源,如果需要用户额外存放在一个目录,也不是很方便,如果能打包进程序发布的二进制文件中,用户下载以后可以直接使用,就方便很多。


使用gvm在不同go版本之间切换

Centos7上通过 yum 从 epel 仓库里直接安装的 go 版本还是 1.4.2,从源码编译安装最新的 go 版本比较麻烦,而且开发中有时需要调试在不同编译环境下可能存在的问题,不能忽略使用最新版本是存在某些 bug 的可能性。


linux下查看指定进程的所有连接信息

定位某个进程的网络故障时经常需要用到的一个功能就是查找所有连接的信息。通常查找某个端口的连接信息使用 ss 或者 netstat 可以轻松拿到,如果是主动与别的机器建立的连接信息则可以通过 lsof 命令来获得。


InfluxDB 与 OpenTSDB 对比测试

通过调研,在时间序列数据库的选择上,从社区活跃度,易用程度,综合性能上来看比较合适的就是 OpenTSDB 和 InfluxDB,所以对这两个数据库进行了一个简单测试。



时间序列数据库调研之OpenTSDB

Java 项目,基于 HBase(2.3版本貌似开始支持 Google BigTable 和 Cassandra) 的一个时间序列数据库,被广泛应用于监控系统中。很多大公司都在使用,社区较为活跃。


kubernetes 初探及部署实践

Kubernetes 是 Google 开源的容器集群管理系统,作为 Go 语言开发的热门项目之一,它提供了应用部署、维护、 扩展机制等功能,利用 Kubernetes 能够方便地管理跨机器运行的容器化应用,目前主要是针对 Docker 的管理。


LSM Tree 学习笔记

最近发现很多数据库都使用了 LSM Tree 的存储模型,包括 LevelDB,HBase,Google BigTable,Cassandra,InfluxDB 等。之前还没有留意这么设计的原因,最近调研时间序列数据库的时候才发现这样设计的优势所在,所以重新又复习了一遍 LSM Tree 的原理。


部署openstack的对象存储服务swift

OpenStack Swift 是一个开源项目,提供了弹性可伸缩、高可用的分布式对象存储服务,适合存储大规模非结构化数据。由于要开发自己的分布式存储应用,需要借鉴 swift 的一些架构,所以在自己的机器上搭建了一个集群环境用于测试。


搭建私有docker仓库

docker 使用起来确实非常方便,易于部署,但是在国内如果要从 DockerHub 上下载镜像实在是一件非常吃力的事,而且公司内部环境使用或者搭建类似 kubernetes 集群的话就需要搭建一个私有的 docker 镜像仓库,方便在集群上快速部署 docker 服务。


go程序中dns解析无法使用所有域名服务器

最近线上服务经常会出现异常,从错误日志来看是因为域名解析失败导致的,我们在 /etc/resolv.conf 中配置了多个域名服务器,第一个是内网的,用于解析内网域名,如果是外网域名,则会通过其他的域名服务器进行解析,按道理来说应该不会有问题,但是最近却频繁发生这样的故障,为了彻底解决问题,特意研究了一下 golang 中进行 dns 查询的源码并最终解决了此问题。


利用docker搭建gitlab及持续集成模块

版本控制的重要性应该是毋庸置疑了,git 作为现在最流行的版本控制工具,各种规模的公司都在用。通常开源项目都会放在 github 上,基础功能是免费的,私有项目收费。对于一个小团队来说,gitlab 就是另外一个替代品,可以用来搭建自己私有的git服务器。


简记用sed对文件执行批量替换字符串的方法

每次要进行一些批量的文本处理,例如 sed, awk 处理数据或者涉及到正则表达式的时候,都需要临时去再查一遍资料,看一下怎么用。这里简要记录一下对大量文件进行正则匹配后批量替换文本的方法,方便以后要用的时候回顾一下。


OpenTSDB部署与使用

OpenTSDB 是基于 HBase 存储时间序列数据的一个开源数据库,对于存储监控系统采集的数据来说非常合适,不仅在写入查询上有很高的效率,而且节省存储空间。


如何使golang项目可以在任意目录下编译

通常我们将golang项目直接放在 $GOPATH/src 目录下,所有 import 的包的路径也是相对于 GOPATH 的。我在开发 frp(一个可以用于穿透内网的反向代理工具)的时候就遇到一个比较小但是挺棘手的问题,需要使这个项目可以在任意目录里被编译,方便其他成员不需要做额外的操作就可以一同开发,这里分享一下解决的方法。


Go中如何优雅地关闭net.Listener

在开发一个 Go 语言写的服务器项目的时候,遇到一个很有意思的问题,这个程序会根据客户端的请求动态的监听本地的一个端口,并且与客户端交互结束后需要释放这个端口。Go 的标准库提供了常用的接口,开发网络服务非常方便,网上随便就可以找到很多样例代码。


使用godep管理golang项目的第三方包

go语言项目的第三方包资源现在十分丰富,使用起来也非常方便,直接在代码中 import 之后再使用 go get 命令下载到本地即可。但是在合作开发一个golang项目时,经常会遇到每个人在各自的机器上使用 go get 下载的第三方包版本不一致的情况(因为 go get 会下载指定包的最新版本),很有可能会遇到版本不兼容的情况。


终端利器 Tmux

开发过程中通过ssh到服务器是很常见的,工作中基本上90%的时间在和终端打交道,如果没有一个称手的工具,将会在不停打开新的 tab 页,窗口切换中耗费大量的时间。Tmux 是终端复用器的意思,和 screen 类似,但是高度可定制,通过 tmux 可以方便地管理大量的 ssh 连接,并且灵活地在不同窗口,不同面板之间切换。


gem 源被屏蔽的解决方法

由于国内的网络环境比较特殊,使用 gem install 安装 ruby 包的时候,往往不能成功,我们可以手动替换成阿里提供的镜像源来进行下载。


给shell的输出加上颜色

在写一些脚本的时候输出信息太多,对一些重要信息加上颜色提示会更加友好。


codis 2.x版本环境搭建与测试

Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别(有一些命令不支持),上层应用可以像使用单机的 Redis 一样,Codis 底层会处理请求的转发。Codis 支持不停机进行数据迁移, 对于前面的客户端来说是透明的, 可以简单的认为后面连接的是一个内存无限大的 Redis 服务。


mac上将socks5代理转为http代理

在 mac 上使用 ss 的时候创建的是 socks5 代理,浏览器可以正常设置使用,不过在 shell 中一些程序无法使用 socks5 代理,而需要使用 http 代理,通过设置 http_proxy 环境变量,就可以让 shell 通过 http 代理来访问网络。polipo 这款工具就可以帮助我们将 socks5 代理转换为 http 代理。


Redis集群调研

Redis作为一个使用场景很高的NoSQL数据库,支持了较为丰富的数据类型,相比于其他关系型数据库在性能方面优势明显。互联网公司通常更加倾向于将一些热点数据放入Redis中来承载高吞吐量的访问。

单机Redis在普通的服务器上通常ops上限在5w左右,开启pipeline的情况下在20-30w左右。对于大多数中小公司来说,通常单机的Redis已经足够,最多根据不同业务分散到多台Redis。


如何修改进程的名称

在开发 php 扩展的过程中,希望能创建一个独立的子进程做一些额外的处理工作,并且为子进程修改一个有意义的名称,发现还是有一些难度的。


go语言中使用smtp发送邮件及smtp协议的相关问题

go 的标准库中有一个 smtp 包提供了一个可以非常方便的使用 smtp 协议发送邮件的函数,通常情况下使用起来简单方便,不过我在使用中却意外遇到了一个会导致邮件发送出错的情况。



SSH 端口转发

作为程序员经常会有需要访问某个局域网内的某台机器的需求,例如帮别人调试某个程序,或者远程操作家里的电脑。


MongoDB常用命令

MongoDB 是一个基于分布式文件存储的数据库,由C++编写,介于关系数据库和非关系数据库之间的产品,所以在很多业务上可以取代 mysql,提供更高的性能以及更好的扩展性。虽然 MongoDB 不支持 sql 语法,但是从常用的操作命令上来说和 sql 的用法相类似。


python中使用pycurl库上传文件

在对外提供各种语言SDK的时候经常会遇到需要上传文件的问题,例如在python中我们可以借助pycurl库实现这个功能。


在C++中利用反射和简单工厂模式实现业务模块解耦

在设计一个系统框架的时候往往需要划分各个模块、组件,抽象出公共的部分,尽量避免耦合,以利于以后的扩展和复用。在这方面,JAVA的很多特性在利用各种设计模式的时候会非常容易,而在C++中就需要自己去一步步实现。


epoll使用说明

在《UNIX网络编程》一书中介绍了如何使用select/poll来实现I/O多路复用,简而言之就是通过内核的一种机制,监视多个文件描述符,一旦某个文件描述符处于就绪状态,就通知用户程序进行相应的读写操作,这样用户程序就不用阻塞在每一个文件描述符上。


如何处理僵尸进程

在使用c/c++开发过程中经常会用到多进程,需要fork一些子进程,但是如果不注意的话,就有可能导致子进程结束后变成了僵尸进程。从而逐渐耗尽系统资源。


linux core文件调试

在完成公司项目,测试进程的时候,经常会发现日志到了某一段特定的代码的时候就没了,进程直接退出,也没有捕获到任何的异常信息,如果日志打印的较多还可能比较容易发现问题 题,如果日志较少,就很难进行进一步的查错了。但是发现在该目录下生成了一个core文件,可以帮助我们查找程序崩溃的原因。


linux shell中的条件判断

在日常开发中经常需要编写一些简单的部署或者测试统计之类的脚本,直接用shell来编写几条命令就可以实现一些较为复杂的功能,十分方便。不过 linux shell 中的条件判断和其他编程语言略有不同,有一些需要特别注意的地方。


能否被8整除

题目:给定一个非负整数,问能否重排它的全部数字,使得重排后的数能被8整除。 输入格式: 多组数据,每组数据是一个非负整数。非负整数的位数不超过10000位。 输出格式 每组数据输出一行,YES或者NO,表示能否重排它的全部数字得到能被8整除的数。注意:重排可以让0开头。


使用astyle进行代码格式化

在参与团队的开发的时候,由于平台和编写代码的工具的不同等等问题,经常会遇到代码格式非常混乱的情况,严重影响了代码的阅读效率。后来发现了一款比较好的工具 – “astyle”。


Linux下如何进行文件编码格式转换

最近把项目放到github上,但是发现代码中注释的中文部分有些是乱码,检查后发现是因为我的Centos装在虚拟机上,而我是在Windows环境下通过UE来写代码的,而UE默认是使用ASCII编码。为了避免在UE里对一个个文件进行手动修改,希望在Linux上使用命令来批量转换编码格式。


使用Vim打造自己的IDE

之前一直使用UE的FTP功能编辑Linux虚拟机上的代码文件,之后再切换到Linux上去编译,调试程序,感觉这样比较麻烦,而且UE的功能也不像VS以及Eclipse的IDE那样强大,所以就查阅了一些资料,想要把Linux下最常用的文本编辑工具Vim打造成一个适合自己的IDE,可以直接ssh登陆到远程机器上直接进行开发。


vimdiff常用命令

整理了一下在使用vimdiff进行文件合并的时候用到的一些常用的命令,方便以后查询。


Git常用命令

在用Git进行项目管理的时候有一些经常会遇到的问题处理起来比较复杂,本文记录了一些常用的命令和操作。


Git使用备忘

Git是一款免费、开源的分布式版本控制系统,由于 GitHub 的存在,我们很方便的用于管理我们平时的开发项目。

Git的命令较多,虽然大多数都不是很常用,但是还是需要记下来方便日后查看。


学习Git的常用网站

学习Git的使用的过程中参考了很多的网站,主要是两个地方讲的比较清楚,例子也很丰富,特别记录一下。


主机使用代理上网,虚拟机Linux的shell如何连外网

在公司电脑上网都需要使用代理,虚拟机里面装的Linux系统需要使用yum命令来安装软件,所以需要在shell界面能连上外网才行。

因为公司限制了每个人只能用一个IP,所以虚拟机中的Linux系统使用NAT方式和主机相连。主机是Win7操作系统,会发现网络里面多了VMnet8这个网络。


C/C++获取精确到微秒级的系统时间

最近要为自己的项目开发一个日志模块,需要获取精确到微秒级的系统时间,查阅了一些资料,发现在C/C++里面可以通过 gettimeofday(struct timeval * tv,struct timezone * tz) 和 localtime(const time_t * timep) 这两个函数的配合使用来得到我想要的结果。


size() == 0和empty()的比较

最近开发公司项目的时候发现大量用到了STL模板库,而且很多地方都需要判断一个容器是否为空,看到了两种写法,分别使用了容器的 size() 函数和 empty()函数。

我觉得很好奇,这两种写法有什么区别呢?在网上查阅了一些资料,发现说empty()效率更高的占大多数。又查看了SGI STL的帮助文档,里面有一句话:


从简单实例开始,学会写Makefile(二)

如果文件间存在着相互之间的引用关系该怎么办?如果把.h文件和.cpp文件放在了不同的目录下该怎么办?如果我想生成静态库,然后在其他地方引用静态库该怎么办?如果我想将程序迁移到Unix平台下,使用不同的编译器,难道要依次修改所有的Makefile?


从简单实例开始,学会写Makefile(一)

作为一个刚刚从大学毕业的新人,进公司不久就遇到了一个不大不小的门槛——看不懂Makefile!而Makefile所干的事却关系到程序的编译和链接,一个好的Makefile文件可以极大地提升编译项目文件的效率,免去手动编译的烦恼。