Below you will find pages that utilize the taxonomy term “kubernetes”
Posts
查看Pod重启的原因
在Kubernetes中,有时候Pod会异常重启。事后发现的时候错误原因在控制台面板里已经看不到了。
实际上Kubernetes提供了相关的工具。我们可以在不可恢复的异常发生时拦截异常,将其写入/dev/termination-log。
package main import ( "fmt" "os" ) func main() { defer func() { if r := recover(); r != nil { _ = os.WriteFile( "/dev/termination-log", []byte(fmt.Sprintf("panic: %s", r)), os.ModePerm, ) panic(r) } }() // ... } 查看的时候,我们可以在edit pod时在lastState当中找到错误信息:
apiVersion:v1kind:Pod...lastState:terminated:containerID:...exitCode:0finishedAt:...message:| panic: goroutine 1 [running]:main.main.func1()/Users/donew/src/kitty/main.go:18+0x131panic(0x5192e20,0x5640e10)/usr/local/Cellar/go/1.16/libexec/src/runtime/panic.go:965+0x1b9main.main()/Users/donew/src/kitty/main.go:21+0x5b... 也可以直接用kubectl 查看。
kubectl get pod termination-demo -o go-template="{{range .status.containerStatuses}}{{.lastState.terminated.message}}{{end}}" 写入的路径可以在terminationMessagePath中更改。
除此之外,如果项目不方便拦截错误,还可以将terminationMessagePolicy设置为FallbackToLogsOnError。 此时使用容器日志输出的最后一块作为终止消息。 日志输出限制为 2048 字节或 80 行,以较小者为准。
实际操作中,FallbackToLogsOnError的长度限制导致有时候会截取太少,丢掉重要信息。
这里提供一个简单的最佳实践:将正常的日志打印到stdout中,将致命错误打印到stderr(Go里的panic默认就是stderr,不用拦截了),然后将terminationMessagePath设置为/dev/stderr,即可精确的获取Pod重启原因。
参考阅读:https://kubernetes.io/zh/docs/tasks/debug-application-cluster/determine-reason-pod-failure/
Posts
云原生Hyperf骨架包
2020-01-22 日更新:现已提供Hyperf Helm chart。详见repo。
Hyperf官方提供了容器镜像,配置选项又非常开放,将Hyperf部署于云端本身并不复杂。下面我们以Kubernetes为例,对Hyperf默认的骨架包进行一些改造,使它可以优雅的运行于Kubernetes上。本文不是Kubernetes的入门介绍,需要读者已经对Kubernetes有一定了解。
生命周期 容器在Kubernetes上启动以后,Kubernetes会对容器进行两项检查: Liveness Probe和Readiness Probe。Liveness Probe如果没有通过,容器会被重启,而Readiness Probe没有通过,则会暂时将服务从发现列表中移除。当Hyperf作为HTTP Web server启动时,我们只需要添加两条路由就行了。
<?php namespace App\Controller; class HealthCheckController extends AbstractController { public function liveness() { return 'ok'; } public function readiness() { return 'ok'; } } <?php // in config/Routes.php Router::addRoute(['GET', 'HEAD'], '/liveness', 'App\Controller\HealthCheckController@liveness'); Router::addRoute(['GET', 'HEAD'], '/readiness', 'App\Controller\HealthCheckController@readiness'); 在Kubernetes的deployment上配置:
livenessProbe:httpGet:path:/livenessport:9501failureThreshold:1periodSeconds:10readinessProbe:httpGet:path:/readinessport:9501failureThreshold:1periodSeconds:10 当然这里我们只是简单了返回‘ok’,显然不能真正检查出健康状况。实际的检查要考虑业务具体场景和业务依赖的资源。例如对于重数据库服务我们可以检查数据库的连接池,如果连接池已满就暂时在Readiness Probe返回状态码503。
服务在Kubernetes销毁时,Kubernetes会先发来SIGTERM信号。进程有terminationGracePeriodSeconds这么长的时间(默认60秒)来自行结束。如果到时间后还没结束,Kubernetes就会发来SIGINT信号来强制杀死进程。Swoole本身是可以正确响应SIGTERM结束服务的,正常情况下不会丢失任何运行中的连接。实际生产中,如果Swoole没有响应SIGTERM退出,很有可能是因为服务端注册的定时器没有被清理。我们可以在OnWorkerExit处清理定时器来保证顺利退出。
<?php // config/autoload/server.php // ... 'callbacks' => [ SwooleEvent::ON_BEFORE_START => [Hyperf\Framework\Bootstrap\ServerStartCallback::class, 'beforeStart'], SwooleEvent::ON_WORKER_START => [Hyperf\Framework\Bootstrap\WorkerStartCallback::class, 'onWorkerStart'], SwooleEvent::ON_PIPE_MESSAGE => [Hyperf\Framework\Bootstrap\PipeMessageCallback::class, 'onPipeMessage'], SwooleEvent::ON_WORKER_EXIT => function () { Swoole\Timer::clearAll(); }, ], // .
Posts
Kubernetes on Premise: Top 5 Fallacies (Part One)
As the saying goes, Kubernetes is gradually eating the world of software. In the last year, we have switched our on premise infrastructure from Docker Swarm to Kubernetes. Adopting Kubernetes on the cloud is one thing; adopting it on premise and making it production ready is quite another. Many lessons have been learned along our journey. For those who have played with Kubernetes in the vacuum, there are probably some hidden deadly trap yet to be revealed.