Fly.io初体验

前言 最近在群里看到群友提到了 Fly.io 这个 应用部署平台,相比其它平台,Fly.io 提供了数据库。本篇文章我就来简单介绍如何使用 Fly.io。 安装 flyctl Flyctl 是一个应用命令行工具,可以让你很方便的从创建用户、创建应用并部署应用。 Windows 安装 iwr https://fly.io/install.ps1 -useb | iex Linux 安装 curl -L https://fly.io/install.sh | sh MAC 安装 brew install flyctl 或者 curl -L https://fly.io/install.sh | sh 注册 Fly.io 账号 使用 flyctl auth signup 命令进行用户注册,你可以使用电子邮件注册,也可以使用 Github 账号进行登录。 登录账号 使用 flyctl auth login 命令登录你的 Fly.io 账号,由于我没有 Fly.io 账号,前面注册时就会登录,可以直接跳过这步。 启动应用程序 接下来我们就可以进行应用的部署了,Fly.io 使用的是 docker 镜像的方式进行应用部署的,由于我本地环境的限制,本文我使用一个基础的 flyio/hellofly:latest 镜像进行部署使用。 每个应用使用 fly.toml 配置文件来告诉 Fly.io 如何进行部署。我们使用 flyctl launch 命令生成相应的配置文件。 ...

十月 22, 2022 · overstarry

AI绘画初体验

前言 最近我发现各个群里出现了一股利用 AI 进行绘画的潮流,今天我也尝试使用 Stable Diffusion 模型 进行 AI 绘画。 Stable Diffusion 简介 Stable Diffusion 是一个文本到图像的模型,将使人们可以在几秒钟内创造出令人惊叹的艺术作品。它在速度和质量方面都有突破,这意味着它可以在消费级GPU上运行 开始 我们采用别人封装的 stable-diffusion-webui 平台进行绘画,由于各种条件限制,我们使用 github上提供的 Google colab notbook 进行部署(https://colab.research.google.com/drive/1IplUv47g9CgtlJmFnyT2sDyNYDEeMJDi?usp=sharing). 打开链接,我简单的看了下代码,前面是基础的安装运行环境、需要的 Python package .我们依次运行即可。 我们直接来到 1.4 Connect to Google Drive, 勾选 download_if_missing ,然后到 https://huggingface.co/settings/tokens 复制你的 toekn 并填入。(huggingface 注册耗费了许多时间,reCAPTCHA 没有通过). 点击运行后就开始拉取模型。 如果运行发现报错了: remote: Access to model CompVis/stable-diffusion-v-1-4-original is restricted and you are not in the authorized list. Visit https://huggingface.co/CompVis/stable-diffusion-v-1-4-original to ask for access. fatal: unable to access 'https://huggingface.co/CompVis/stable-diffusion-v-1-4-original/': The requested URL returned error: 403 你需要到 https://huggingface.co/CompVis/stable-diffusion-v-1-4-original 授权模型的访问权限。授权后重新运行即可。 ...

十月 15, 2022 · overstarry

Kubernetes Configmaps mounted with subPath not update when changed

起因 最近在使用 k8s 部署应用时,我使用 ConfigMaps 的方式来挂载应用的配置文件。在我的知识储备中,k8s 修改 cm 的内容,pod 里的配置文件应该也会同步更新才是,但是我进入 pod , 发现配置还是旧版本没有更新,需要重启 pod 才会生效。 问题 那为什么配置没有及时更新呢? 通过查阅资料,我发现使用 subPath 挂载的容器不会接收到配置更新。这是为什么呢,相比于没有使用 subPath 有什么区别呢? subPath 使用了符号链接的方式挂载文件,容器内的文件是一个链接到存储在一个隐藏的带有时间戳目录中的同名文件。当 configMaps 更新时,符号链接会更新,但挂载在容器中的文件绑定保持不变。 解决 使用 path字段为特定 ConfigMap 项指定所需的文件路径 具体如下: apiVersion: v1 kind: Pod metadata: name: dapi-test-pod spec: containers: - name: test-container image: registry.k8s.io/busybox command: [ "/bin/sh","-c","cat /etc/config/keys" ] volumeMounts: - name: config-volume mountPath: /etc/config volumes: - name: config-volume configMap: name: special-config items: - key: SPECIAL_LEVEL path: keys restartPolicy: Never 亲测这样是可以正常更新的,但同目录下的其它文件会删除掉,看了几个相关的 issues , 发现你还可以手动创建符号链接到相应的文件夹, 小结 使用 subPath 挂载配置至容器时,配置更新时,容器内的配置不能同步更新,这是 k8s 官方处于各种原因做出的限制,目前还没有很好的办法来解决这个问题。 参考 https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#mounted-configmaps-are-updated-automatically https://github.com/kubernetes/kubernetes/issues/50345 https://github.com/kubernetes/kubernetes/blob/master/pkg/volume/util/atomic_writer.go

十月 2, 2022 · overstarry

Easeprobe简单介绍使用

本篇文章将由我来介绍一款健康/状态检查工具 - Easeprobe 的简单使用。 介绍 EaseProbe 是一个由用 Go 编写的简单、独立、轻量级的工具,可以进行健康/状态检查, EaseProbe 主要完成3个目标工具: 探测、通知、报告 探测 EaseProbe 支持多种方法来执行其探测,例如: * HTTP。检查HTTP状态码,支持mTLS,HTTP Basic Auth,可以设置Request Header/Body。(HTTP 探针配置) * TCP。检查是否可以建立 TCP 连接。(TCP 探针配置) * shell。运行 Shell 命令并检查结果。(Shell 命令探针配置) * SSH。通过 SSH 运行远程命令并检查结果。支持堡垒/跳转服务器(SSH 命令探针配置) * TLS。使用 TLS 连接到给定端口并(可选)验证已撤销或过期的证书(TLS 探针配置) * Host。在远程主机上运行 SSH 命令并检查 CPU、内存和磁盘使用情况。(主机负载探针) * client。支持以下本机客户端。它们都支持 mTLS 和数据检查,请参阅Native Client Probe 配置 * MySQL。连接到 MySQL 服务器并运行SHOW STATUSSQL。 * Redis。连接到 Redis 服务器并运行PING命令。 * Memcache。连接到 Memcache 服务器并运行version命令或验证给定的键/值对。 * MongoDB。连接到 MongoDB 服务器并执行 ping。 * Kafka。连接到 Kafka 服务器并执行所有主题的列表。 * PostgreSQL。连接到 PostgreSQL 服务器并运行SELECT 1SQL。 * Zookeeper。连接到 Zookeeper 服务器并运行get /命令。 通知 EaseProbe 支持多种通知方式向你发送通知,例如: slack、钉钉、企业微信、邮件、Telegram 等。 ...

九月 24, 2022 · overstarry

gRPC中间件

本文我来介绍 gRPC 中的中间件相关知识。 介绍 gRPC 中间件基于前面讲解的拦截器相关概念,它是一组拦截器、辅助、工具的集合,在我们使用 gRPC 开发应用时,往往会使用到各种中间件。它允许在服务端或客户端以拦截器链条形式应用多个中间件。 因为拦截器经常用来实现一些通用的功能 ,如鉴权认证、日志、监控等,所以使用 gRPC 中间件来实现这些可重用功能是十分合适的。下面的代码就分别暂时服务端和客户端使用中间件的例子: import "github.com/grpc-ecosystem/go-grpc-middleware" myServer := grpc.NewServer( grpc.StreamInterceptor(grpc_middleware.ChainStreamServer( grpc_ctxtags.StreamServerInterceptor(), grpc_opentracing.StreamServerInterceptor(), grpc_prometheus.StreamServerInterceptor, grpc_zap.StreamServerInterceptor(zapLogger), grpc_auth.StreamServerInterceptor(myAuthFunction), grpc_recovery.StreamServerInterceptor(), )), grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer( grpc_ctxtags.UnaryServerInterceptor(), grpc_opentracing.UnaryServerInterceptor(), grpc_prometheus.UnaryServerInterceptor, grpc_zap.UnaryServerInterceptor(zapLogger), grpc_auth.UnaryServerInterceptor(myAuthFunction), grpc_recovery.UnaryServerInterceptor(), )), ) import "github.com/grpc-ecosystem/go-grpc-middleware" clientConn, err = grpc.Dial( address, grpc.WithUnaryInterceptor(grpc_middleware.ChainUnaryClient(monitoringClientUnary, retryUnary)), grpc.WithStreamInterceptor(grpc_middleware.ChainStreamClient(monitoringClientStream, retryStream)), ) 常用的中间件 go-grpc-middleware 项目提供了一些常用的中间件: 认证 grpc_auth - 一个可定制的(通过AuthFunc)身份验证中间件 日志记录 grpc_ctxtags - 将Tag地图添加到上下文的库,数据从请求正文填充 grpc_zap - 将zap日志库集成到 gRPC 处理程序中。 grpc_logrus - 将logrus日志库集成到 gRPC 处理程序中。 grpc_kit - 将go-kit/log日志库集成到 gRPC 处理程序中。 grpc_grpc_logsettablegrpclog.LoggerV2 - 一个允许在运行时替换记录器的包装器(线程安全)。 监控 grpc_prometheus - Prometheus 客户端和服务器端监控中间件 otgrpc - OpenTracing客户端和服务器端拦截器 grpc_opentracing - OpenTracing客户端和服务器端拦截器,支持流式处理和处理程序返回的标签 otelgrpc - OpenTelemetry客户端和服务器端拦截器 客户端中间件 grpc_retry - 一个通用的 gRPC 响应代码重试机制,客户端中间件 ...

九月 18, 2022 · overstarry

Gitlab CVE-2021-22205

起因 最近一台服务器出现服务器资源 cpu、内存过高的情况,通过对进程的分析,发现是 gitlab 容器进程,怀疑是 gitlab 被入侵运行了挖矿病毒,通过对 gitlab 日志的分析,可以得出入侵者是利用了 gitlab 的 CVE-2021-22205 的漏洞,对 gitlab 进行了攻击。 CVE-2021-22205 介绍 CVE-2021-22205是一个严重的严重性漏洞(CVSS 10.0),它是由第三方文件解析器Exif-Tool对图像文件进行不当验证的结果,导致远程命令执行漏洞,可能导致您的GitLab实例被攻击。 以下版本受到漏洞影响: 11.9.x - 13.8.7 13.9.0 - 13.9.5 13.10.0 - 13.10.2 解决 gitlab 发布了 GitLab 13.10.3、13.9.6 和 13.8.8 版本来解决这个漏洞。请尽快升级。 如果无法即使更新和使用热更新补丁解决,可以通过将exiftool脚本替换为cat -。这个解决方案将防止从上传的图像中剥离所有的exif数据。 将 /opt/gitlab/embedded/bin/exiftool 脚本内容替换为 #!/bin/bash cat - 这种方法不是长久之计,每次重启容器时都要手动修改文件,还是尽快更新版本。 原因 根据gitlab的官方漏洞issues来看,当访问接口/uploads/user上传图像文件时,GitLab Workhorse会将扩展名为jpg、jpeg、tiff文件传递给ExifTool。用于删除其中不合法的标签。具体的标签在workhorse/internal/upload/exif/exif.go中的startProcessing方法中有定义,为白名单处理。 而ExifTool在解析文件的时候会忽略文件的扩展名,尝试根据文件的内容来确定文件类型,其中支持的类型有DjVu。 关键在于ExifTool在解析DjVu注释的ParseAnt函数中存在漏洞,所以我们就可以通过构造DjVu文件并插入恶意注释内容将其改为jpg后缀上传,因为gitlab并未在这个过程中验证文件内容是否是允许的格式,最后让ExifTool以DjVu形式来解析文件,造成了ExifTool代码执行漏洞。 该漏洞存在于ExifTool的7.44版本以上,在12.4版本中修复。Gitlab v13.10.2使用的ExifTool版本为11.70。并且接口/uploads/user可通过获取的X-CSRF-Token和未登录Session后来进行未授权访问。最终造成了GitLab未授权的远程代码执行漏洞。 其它 gitlab 提供了对 gitlab 安全的一些最佳实践: https://about.gitlab.com/blog/2020/05/20/gitlab-instance-security-best-practices/ 参考 https://hackerone.com/reports/1154542 https://www.anquanke.com/post/id/266606 https://mp.weixin.qq.com/s?__biz=Mzg3MDAzMDQxNw==&mid=2247491418&idx=1&sn=853be1256de894c3c579a07738c11590 https://about.gitlab.com/blog/2021/11/04/action-needed-in-response-to-cve2021-22205/ https://forum.gitlab.com/t/cve-2021-22205-how-to-determine-if-a-self-managed-instance-has-been-impacted/60918?_gl=11y48o1u_gaODE5OTE4NTMuMTY2MjgxODQ3OQ.._ga_ENFH3X7M5Y*MTY2MjgxODQ5MC4xLjAuMTY2MjgxOTE4Ny4wLjAuMA.. https://forum.gitlab.com/t/cve-2021-22205-how-to-determine-if-a-self-managed-instance-has-been-impacted/60918/2?_gl=11y48o1u_gaODE5OTE4NTMuMTY2MjgxODQ3OQ.._ga_ENFH3X7M5Y*MTY2MjgxODQ5MC4xLjAuMTY2MjgxOTE4Ny4wLjAuMA.. https://about.gitlab.com/releases/2021/04/14/security-release-gitlab-13-10-3-released/ https://hackerone.com/vakzz?type=user https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22205

九月 10, 2022 · overstarry

gRPC请求抓包

前言 本文来简单介绍如何使用 wireshark 来获取 gRPC 请求。 wireshark 配置 在进行对 gRPC 请求抓包前,得来几个准备。 设置 proto 文件路径 依次打开 编辑 > 首选项 > Protocols > ProtoBuf, 点击如图选项,添加 proto 文件所在的路径。记得勾选右边的 “Load all files” 选项。 设置TCP 消息解码 默认情况下,界面上显示的都是 TCP 数据包。依次点击菜单栏的 分析 -> 解码为… (或者右击随便一行)。 把 9000 (你的 gRPC 服务端端口) 端口的 TCP 消息解码成 HTTP2 协议信息。 开始抓包 现在开始捕获 gRPC 请求消息,为了避免其他无关的流量,在捕获选项设置筛选 tcp port 9000 只获得跟服务端相关的流量。 我们使用 postman 向服务端发送请求。回到 wireshark 界面,我们就可以看到许多流量,通过前面设置的解码,我们可以很方便的获得 gRPC 消息的具体内容。 小结 本文简单介绍了如何使用 wireshark 捕获 gRPC 请求流量。在使用Wireshark抓包时把未识别的HTTP/2协议手动设置为HTTP/2,这样会方便很多。 ...

九月 3, 2022 · overstarry

gRPC服务反射协议

本文主要介绍 gRPC 的服务反射协议和相关的应用。 介绍 gRPC 服务反射协议 (server reflection) 是在 gRPC 服务端定义的一个服务,它能提供该服务器端上可公开使用的 gRPC 服务的信息,简单的来说,就是服务反射向客户端提供了服务端注册的服务的信息。 因此客户端不需要预编译服务定义就能与服务端交互了。 客户端想要与服务端程序进行通信,必须要有所定义的服务信息,需要编译生产客户端存根,借助 gRPC 服务反射协议,我们就可以无需编译服务定义就能通信。 使用 该如何开启服务反射协议呢? 很简单,只需要通过一行代码即可开启: reflection.Register() package main import ( "context" "flag" "fmt" "log" "net" "google.golang.org/grpc" "google.golang.org/grpc/reflection" ecpb "google.golang.org/grpc/examples/features/proto/echo" hwpb "google.golang.org/grpc/examples/helloworld/helloworld" ) var port = flag.Int("port", 50051, "the port to serve on") // hwServer is used to implement helloworld.GreeterServer. type hwServer struct { hwpb.UnimplementedGreeterServer } // SayHello implements helloworld.GreeterServer func (s *hwServer) SayHello(ctx context.Context, in *hwpb.HelloRequest) (*hwpb.HelloReply, error) { return &hwpb.HelloReply{Message: "Hello " + in.Name}, nil } type ecServer struct { ecpb.UnimplementedEchoServer } func (s *ecServer) UnaryEcho(ctx context.Context, req *ecpb.EchoRequest) (*ecpb.EchoResponse, error) { return &ecpb.EchoResponse{Message: req.Message}, nil } func main() { flag.Parse() lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port)) if err != nil { log.Fatalf("failed to listen: %v", err) } fmt.Printf("server listening at %v\n", lis.Addr()) s := grpc.NewServer() // Register Greeter on the server. hwpb.RegisterGreeterServer(s, &hwServer{}) // Register RouteGuide on the same server. ecpb.RegisterEchoServer(s, &ecServer{}) // Register reflection service on gRPC server. reflection.Register(s) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } } 服务端开启服务反射协议后,就可以通过 gRPC CLI 工具来检查服务端了。这里就不多介绍了,接下来我们来看看服务反射协议在 kratos 中的使用。 ...

八月 27, 2022 · overstarry

Prometheus_operato

安装Metrics Server 有了 Metrics Server,用户就可以访问Kubernetes 核心监控数据(core metrics)。这其中包括了 Pod、Node、容器、Service 等主要 Kubernetes 核心概念的 Metrics。 Resource MetricsAPI: https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/resource-metrics-api.md kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml 部署Prometheus kube-prometheus 下载存储库 git clone https://github.com/prometheus-operator/kube-prometheus 使用manifests中的配置文件创建监控stack cd kube-prometheus kubectl create -f manifests/setup until kubectl get servicemonitors --all-namespaces ; do date; sleep 1; echo ""; done kubectl create -f manifests/ 访问dashboards 通过 kubectl --namespace monitoring port-forward svc/prometheus-k8s 9090 就能展现prometheus ui grafana kubectl --namespace monitoring port-forward svc/grafana 3000 默认账户密码admin/admin,进入后会要求修改密码,可以看到已经有了预添加了数据源 可以看到有了许多K8S监控的默认看板 ...

八月 23, 2022 · overstarry

Go进行浏览器网页截图

前言 在本文中将介绍使用 golang 进行加载某个网站并进行截图。 chromedp 我们将使用 chromedp 通过浏览器驱动来加载网页并截图。 具体的步骤如下: 1 启动 chrome 浏览器 2 加载网页 (还可进行其他浏览器操作) 3 截图并保存 需要注意的是项目使用了 Chrome 的驱动,如果没有 Chrome 将不能顺利运行,需要运行 https://hub.docker.com/r/chromedp/headless-shell/ 来进行 或运行其他 版本的 Chrome 。 安装 go get -u github.com/chromedp/chromedp 示例 package main import ( "context" "io/ioutil" "log" "github.com/chromedp/chromedp" ) func main() { ctx, cancel := chromedp.NewContext(context.Background(), chromedp.WithDebugf(log.Printf)) defer cancel() url := "https://www.minigame.vip/" filename := "minigame.png" var imageBuf []byte // 捕获某个元素的截图 if err := chromedp.Run(ctx, elementScreenshot(`https://pkg.go.dev/`, `img.Homepage-logo`, &imageBuf)); err != nil { log.Fatal(err) } if err := ioutil.WriteFile("elementScreenshot.png", imageBuf, 0644); err != nil { log.Fatal(err) } if err := chromedp.Run(ctx, ScreenshotTasks(url, &imageBuf)); err != nil { log.Fatal(err) } if err := ioutil.WriteFile(filename, imageBuf, 0644); err != nil { log.Fatal(err) } } func elementScreenshot(urlstr, sel string, res *[]byte) chromedp.Tasks { return chromedp.Tasks{ chromedp.Navigate(urlstr), chromedp.Screenshot(sel, res, chromedp.NodeVisible), } } func ScreenshotTasks(url string, imageBuf *[]byte) chromedp.Tasks { return chromedp.Tasks{ chromedp.Navigate(url), chromedp.FullScreenshot(imageBuf, 90), } } 上面的例子分别是对网页中的单个元素进行截图和对网页全局截图。 ...

八月 20, 2022 · overstarry