Nginx 反向代理中出现的问题及解决方法

最近在使用 nginx 反向代理时遇到了一些问题,在本文记录一下问题及相应的解决方法。 问题 1 问题现象 错误日志如下: : host not found in upstream "xx.xx.vip"in /etc/nginx/conf.d/default.conf:17 nginx: [emerg] host not found in upstream "xx.xx.vip”in /etc/nginx/conf.d/default. conf:17 从错误日志可以看出这个问题主要是 nginx 无法解析相应的域名。 解决方法 怎么解决这个问题呢,我们只需添加相应的 dns 服务器即可 resolver 8.8.8.8; 。 问题 2 问题现象 错误日志如下: 2023/07/28 01:35:43 [error] 34#34: *44 SSL_do_handshake() failed (SSL: error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error:SSL alert number 80) while SSL handshaking to upstream, client: 172.16.64.75, server: , request: "POST /v1/data/xx/filter HTTP/1.1", upstream: "https://xxxx:443/v1/data/xx/filter", host: "xx.xx.com", referrer: "https://xx.xx.com/user/login" 解决方法 这个问题主要是 https 相关配置的问题,我们只需添加这几行配置即可: ...

七月 28, 2023 · overstarry

使用 cert Manager 申请免费证书

cert manager 介绍 cert-manager 是一个可信证书管理器,可以自动为您的集群中的服务提供 SSL 证书和可靠的基础设施。它执行以下任务: 自动通过类似 Let’s Encrypt 和 eigene 之类的 Certificate Authority (CA) 重新生成即将过期的证书。 为您的集群中的服务自动生成证书。 提供一个组件库,可用于自签名证书或其他 CA API。 主要特性: 自动生成/重新生成证书 支持多种 CA 颁发的证书:Let’s Encrypt、自签名证书、HashiCorp Vault 等 支持多种记录类型:DNS01、HTTP01、Kubernetes Ingress 等 适用于支持 TLS 密码学的任何 Kubernetes API 对象 具有密钥轮换功能,可无缝替换即将到期的证书 流畅的 API,易于扩展 总的来说,cert-manager 可以让您将集群负载均衡的 TLS 实现自动化,减少运维负担。它主要用于解决基础设施中最常见的挑战:如何高可用地为应用提供 TLS 证书。 申请证书 接下来我来讲解本文的重点:如何使用 cert-manager 申请证书并配置于 ingress 上。 安装 cert-manager 执行 kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml 部署最新版本 cert-manager. 查看 pod 状态 部署后,过一会执行 kubectl get pods -n cert-manager 查看 pod 状态。 ...

七月 22, 2023 · overstarry

Golang i18n

最近在开发一个需求时,需要将英文转为中文,这就需要进行本地化的处理,通过查找相关的库,决定使用 gettext-go 来进行本地化的处理,本篇文章主要简单介绍 gettext-go 和 它在 k8s kubectl 中的运用。 gettext-go 简单介绍和使用 gettext-go 简单来说就是读取预先编写的 po 或 mo 文件来进行本地化的处理。 po 和 mo 文件是什么呢?接下来介绍一下 po 和 mo 文件 po 和 mo 文件介绍 .po 文件,.mo 文件是由 gettext 程序生成或者使用的源代码和编译结果。 1、.pot 文件 是一种模板文件,其实质与.po 文件一样,其中包含了从源代码中提取所有的翻译字符串的列表,主要提供给翻译人员使用。 2、.po 文件 (1)用程序 msginit 来分析 pot 文件,生成各语言对应的 po 文件,比如中文就是 zh_CN.po,法语就是 fr.po 文件。 (2)PO 是 Portable Object(可移植对象)的缩写形式,它是面向翻译人员的、提取于源代码的一种资源文件。 (3).po 文件可以用任何编辑器如 poEdit,vi,Emacs,editplus 打开,交给翻译人员来将其中的文字翻译成本国语言。 3、.mo 文件 (1)用 msgfmt 将.po 文件编译成 mo 文件,这是一个二进制文件,不能直接编辑。 (2)MO 是 Machine Object(机器对象)的缩写形式,它是面向计算机的、由.po 文件通过 GNU gettext 工具包编译而成的二进制文件,应用程序通过读取.mo 文件使自身的界面转换成用户使用的语言,如简体中文。 ...

七月 16, 2023 · overstarry

rueidis 简介

简介 rueidis 是一个快速的 Golang Redis 客户端,支持客户端缓存、Auto Pipelining、泛型 OM、RedisJSON、RedisBloom、RediSearch 等功能。 Features Auto pipelining for non-blocking redis commands RESP3 中的客户端缓存 Pub/Sub, Sharded Pub/Sub, Streams Redis Cluster, Sentinel, RedisJSON, RedisBloom, RediSearch, RedisTimeseries, 等。 具有客户端缓存和乐观锁定的通用对象映射 具有客户端缓存的分布式锁 rueidis mock OpenTelemetry 集成 Hooks and other 集成 提供类似 Go-redis API 的适配器 需要注意的是由于使用了一些 go1.20 版本才有的特性,如果想要使用低版本 go,必须安装相应的版本。 简单使用 package main import ( "context" "fmt" "github.com/redis/rueidis" ) func main() { // 创建 redis 客户端连接 client, err := rueidis.NewClient(rueidis.ClientOption{InitAddress: []string{"127.0.0.1:6379"}}) if err != nil { panic(err) } defer client.Close() ctx := context.Background() // 执行 redis set 命令 err = client.Do(ctx, client.B().Set().Key("key1").Value("val").Nx().Build()).Error() if err != nil { panic(err) } hm, err := client.Do(ctx, client.B().Get().Key("key1").Build()).ToString() if err != nil { panic(err) } fmt.Println(hm) } go-redis 适配器 如何快速从 go-redis 切换到 rueidis 客户端呢,rueidis 提供了 rueidiscompat.NewAdapter 方法,通过 Adapter 可以使用熟悉的 go-redis 中的方法。 ...

七月 8, 2023 · overstarry

PostgreSQL 怎么解决 division by zero 问题

问题 最近在使用 sql 进行数值计算时,发现 sql 语句运行报错,报错信息如下:division by zero,综合分析 sql 语句得出是在进行除法运算时,除数为 0 导致的。 解决 接下来我来介绍几种解决这种问题的方法: NULLIF 和 COALESCE 函数 我们可以使用 NULLIF 函数检查变量是否是 0 值,如果是 0 则为 null。使用 COALESCE 函数检查分子和分母是否有 NULL 值,然后返回默认值。 例子: SELECT COALESCE(dividend / NULLIF(divisor, 0), default_value) FROM xx CASE 表达式 我们可以使用 case when 来检查除数是否为 0,如果是 0 则使用默认值。 例子: SELECT COALESCE(dividend / NULLIF(divisor, 0), default_value) FROM xx 最终我采用了第一种方法,顺利的解决了问题,还需要多说的是在 postgresql sql 语句使用过程中,要注意所使用函数需要的参数的类型,遇到需要转换参数类型的情况,可以使用 case 函数进行类型转换。 小结 本文讲述了我遇到的 PostgreSQL 进行数值计算时遇到的 division by zero 问题的情况及解决方法。 参考 https://www.postgresql.org/docs/current/functions-conditional.html#FUNCTIONS-NULLIF https://www.postgresql.org/docs/current/sql-expressions.html#SYNTAX-EXPRESS-EVAL https://pganalyze.com/docs/log-insights/app-errors/U128 https://stackoverflow.com/questions/17681375/avoid-division-by-zero-in-postgresql

七月 1, 2023 · overstarry

Kubernetes Health check

本文我来讲解 Kubernetes 中的一个重要概念:容器的健康检查。 介绍 在 Kubernetes 中,你可以为 Pod 里的容器定义一个健康检查“探针”(Probe)。 这样,kubelet 就会根据这个 Probe 的返回值决定这个容器的状态,而不是直接以容器镜像是否运行(来自 Docker 返回的信息)作为依据。 这种机制,是生产环境中保证应用健康存活的重要手段。 k8s 主要有三种健康检查的探针:1) LivenessProbe 存活探针 2) ReadinessProbe 就绪探针 3) StartupProbe 启动探针 kubelet 使用存活探针来确定什么时候要重启容器。例如,存活探针可以探测到应用死锁(应用程序在运行,但是无法继续执行后面的步骤)情况。重启这种状态下的容器有助于提高应用的可用性,即使其中存在缺陷。 存活探针的常见模式是为就绪探针使用相同的低成本 HTTP 端点,但具有更高的 failureThreshold。这样可以确保在硬性终止 Pod 之前,将观察到 Pod 在一段时间内处于非就绪状态。 kubelet 使用就绪探针可以知道容器何时准备好接受请求流量,当一个 Pod 内的所有容器都就绪时,才能认为该 Pod 就绪。这种信号的一个用途就是控制哪个 Pod 作为 Service 的后端。若 Pod 尚未就绪,会被从 Service 的负载均衡器中剔除。 kubelet 使用启动探针来了解应用容器何时启动。如果配置了这类探针,你就可以控制容器在启动成功后再进行存活性和就绪态检查,确保这些存活、就绪探针不会影响应用的启动。启动探针可以用于对慢启动容器进行存活性检测,避免它们在启动运行之前就被杀掉。 probe 介绍 接下来我来讲解用的较多的 2 个探针:1) LivenessProbe 存活探针 2) ReadinessProbe 就绪探针 LivenessProbe 许多应用由于长时间运行导致程序异常,需要重启服务才能继续正常使用,Kubernetes 提供了存活探针 (LivenessProbe) 来发现并处理这种情况。 我们先创建一个 pod, pod 的文件如下: ...

六月 23, 2023 · overstarry

Rancher Cattle Cluster Agent Could not Resolve Host

起因 最近在使用 rancher 导入外部 k8s 集群时,遇到了一个问题:在要导入的集群上执行命令后,创建的 pod 运行错误,错误日志大概如下: INFO: Environment: CATTLE_ADDRESS=100.66.209.198 CATTLE_CA_CHECKSUM= CATTLE_CLUSTER=true CATTLE_CLUSTER_AGENT_PORT=tcp://11.11.10.11:80 CATTLE_CLUSTER_AGENT_PORT_443_TCP=tcp://11.11.10.11:443 CATTLE_CLUSTER_AGENT_PORT_443_TCP_ADDR=10.96.0.125 CATTLE_CLUSTER_AGENT_PORT_443_TCP_PORT=443 CATTLE_CLUSTER_AGENT_PORT_443_TCP_PROTO=tcp CATTLE_CLUSTER_AGENT_PORT_80_TCP=tcp://10.96.0.125:80 CATTLE_CLUSTER_AGENT_PORT_80_TCP_ADDR=10.96.0.125 CATTLE_CLUSTER_AGENT_PORT_80_TCP_PORT=80 CATTLE_CLUSTER_AGENT_PORT_80_TCP_PROTO=tcp CATTLE_CLUSTER_AGENT_SERVICE_HOST=10.96.0.125 CATTLE_CLUSTER_AGENT_SERVICE_PORT=80 CATTLE_CLUSTER_AGENT_SERVICE_PORT_HTTP=80 CATTLE_CLUSTER_AGENT_SERVICE_PORT_HTTPS_INTERNAL=443 CATTLE_CLUSTER_REGISTRY= CATTLE_INGRESS_IP_DOMAIN=sslip.io CATTLE_INSTALL_UUID=333850e4-f500-43a2-a359-e1dfd94e4f35 CATTLE_INTERNAL_ADDRESS= CATTLE_IS_RKE=false CATTLE_K8S_MANAGED=true CATTLE_NODE_NAME=cattle-cluster-agent-55b9954958-5679q CATTLE_SERVER=https://xx.xx.vip CATTLE_SERVER_VERSION=v2.6.6 INFO: Using resolv.conf: search cattle-system.svc.cluster.local svc.cluster.local cluster.local nameserver 10.96.0.10 options ndots:5 ERROR: https://xx.xx.vip/ping is not accessible (Could not resolve host: xx.xx.vip) 可以很好的看出错误的原因是域名 dns 解析错误。 解决 在发现问题后,可以根据错误日志进行相应的解决,我们先查看 coredns 的日志 kubectl logs deployment/coredns -n kube-system [ERROR] plugin/errors: 2 XX.XX.vip. A: read udp 100.108.11.198:32988->100.100.2.136:53: i/o timeout [ERROR] plugin/errors: 2 XX.XX.vip. A: read udp 100.108.11.198:53477->100.100.2.136:53: i/o timeout [ERROR] plugin/errors: 2 XX.XX.vip. AAAA: read udp 100.108.11.198:40436->100.100.2.136:53: i/o timeout 可以看到相应域名解析错误,根据以前的经验,先重启 coredns 容器尝试是否能解决问题,重启后发现问题未能解决 (可能需要重启相应节点的机器。 ...

六月 16, 2023 · overstarry

sealos version compare error

前言 最近在使用 sealos 安装更新 k8s 的过程中发现了一个问题:nfo new cluster version v1.25.10 behind the current version v1.25.8。 现在我来简单描述下过程:我想要将 k8s 版本从 v1.25.8 升级到 v1.25.10,运行更新命令:sealos run labring/kubernetes:v1.25.10-4.2.0 -f 后,出现了以下错误信息: 2023-06-09T11:30:06 info new cluster version v1.25.10 behind the current version v1.25.8 ,通过对错误信息的理解,发现提示 v1.25.10 版本比 v1.25.8 小,通过我对版本号的理解,这应该是个错误。 发现及解决问题 发现了问题,接下来要寻找出现问题的代码和解决问题。通过 Github 的代码搜索功能搜索关键字 behind the current version 顺利找到问题代码所在。 对找到的代码进行分析,发现是 versionutil.Compare(curversion, version) 方法出现了错误,我们来看看这个函数的代码: func Compare(v1, v2 string) bool { v1 = strings.Replace(v1, "v", "", -1) v2 = strings.Replace(v2, "v", "", -1) v1 = strings.Split(v1, "-")[0] v2 = strings.Split(v2, "-")[0] v1List := strings.Split(v1, ".") v2List := strings.Split(v2, ".") if len(v1List) != 3 || len(v2List) != 3 { logger.Error("error version format %s %s", v1, v2) return false } if v1List[0] > v2List[0] { return true } else if v1List[0] < v2List[0] { return false } if v1List[1] > v2List[1] { return true } else if v1List[1] < v2List[1] { return false } if v1List[2] >= v2List[2] { return true } return false } 通过对代码的分析,发现是对主次修订版本号对比时出现了问题,代码中是简单的使用了字符串比较,字符串数字比较会以字典序进行比较,所以会出现 “8” 大于 “10"的情况。正常的数字比较应该是将字符串转为数字进行相应比较。 ...

六月 10, 2023 · overstarry

Kubernetes pod 修改 hosts 文件

前言 最近看了 k8s 的书,学习了一些新的知识,将会分几篇来介绍学习到的知识,本文来先介绍 k8s 中如何修改 pod 的 hosts 文件。 我们知道当 DNS 出现问题时,可以向 Pod 的/etc/hosts 文件添加条目来提供主机名解析 Pod 级别覆盖。该如何向 hosts 文件中添加条目呢?可以使用 PodSpec 中的 HostAliases 字段添加自定义条目。 虽然我们也可以直接进入 pod 修改 host 文件来实现,但这样 pod 重建时会被覆盖,所以我们应该使用 HostAliases 来进行修改,因为该文件会由 Kubelet 管理,并且 可以在 Pod 创建/重启过程中被重写。 使用 我们该如何操作呢,接下来由我来介绍使用步骤: 1 先创建 Deployment YAML 文件来创建后台运行的 busybox pod apiVersion: apps/v1 kind: Deployment metadata: name: busybox-deployment spec: replicas: 1 selector: matchLabels: app: busybox template: metadata: labels: app: busybox spec: containers: - name: busybox image: busybox args: [ "sleep", "3600" ] resources: limits: memory: "128Mi" cpu: "500m" requests: memory: "64Mi" cpu: "250m" volumeMounts: - name: busybox-volume mountPath: /data volumes: - name: busybox-volume emptyDir: {} 查看 pod ip ...

六月 3, 2023 · overstarry

Apisix 忽略 uri 大小写

前言 最近需要忽略请求 uri 大小写,即不管 uri 的大小写都返回小写 uri 所请求的响应内容,例如请求 xx.vip/A 实际请求 xx.vip/a, 本文主要以 apisix 来讲解如何实现这个功能。 解决 遇到这个需求,首先肯定采用 apisix 的插件来实现,根据前面多次的经验,这个功能应该可以使用 serverless 插件中的 serverless-pre-function 插件来实现,具体的流程如下: 1 获取请求的 uri 2 将 uri 转为小写 3 修改请求的 uri 具体的插件内容如下: "serverless-pre-function": { "_meta": { "disable": false }, "functions": [ "return function(conf, ctx) local uri = ctx.var.uri;ctx.var.uri= string.lower(uri);ngx.log(ngx.ERR, \"match uri \", ctx.var.uri ); end" ], "phase": "rewrite" } 添加插件后,再次请求路径,发现请求结果还是没有变,查看日志发现 uri 修改成功了,不知为何还是没有修改成功。 后面又仔细研究了 proxy-rewrite 插件中修改 uri 的代码,发现它是使用了 nginx 标准的函数 ngx.req.set_uri 来赋值新的 uri。 ...

五月 26, 2023 · overstarry