Fly.io 部署 go 应用

前面讲解了 Fly.io 的初步入门使用,本文讲解在没有 docker 环境情况下部署 go 开发的应用。 项目 这里为了演示方便,简单使用 go 编写一个: package main import ( "fmt" "log" "net/http" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w,"hello world") }) log.Println("listening on", 8080) log.Fatal(http.ListenAndServe(":"+"8080", nil)) } 安装 Flyctl 并登录 这个步骤上篇文章已经介绍过来,还不了解如何安装登录的可以参考前面的文章。 配置 Fly 应用程序 进入项目的根目录,执行 flyctl launch,它会根据你输入的配置 (主要是应用名,部署区域,是否需要数据库和 redis) 来生成相应的配置文件,并帮你在远程构建器上打包镜像并部署,如果有 DOCKERFILE 文件就会使用你的进行构建,如果没有就会使用相应的官方文件进行构建镜像。 需要注意的是你的应用需要监听 8080 端口,否则部署时会报错 从日志可以看到打包好的镜像名是 registry.fly.io/cool-grass-2591:deployment-01GHPEDCXBC3K5NAGHNZWKT49H fly.toml 配置 我们来看看 flyctl 帮我们生成的 fly.toml 具体内容: # fly.toml file generated for cool-grass-2591 on 2022-11-13T01:32:35+08:00 app = "cool-grass-2591" kill_signal = "SIGINT" kill_timeout = 5 processes = [] [env] [experimental] allowed_public_ports = [] auto_rollback = true [[services]] http_checks = [] internal_port = 8080 processes = ["app"] protocol = "tcp" script_checks = [] [services.concurrency] hard_limit = 25 soft_limit = 20 type = "connections" [[services.ports]] force_https = true handlers = ["http"] port = 80 [[services.ports]] handlers = ["tls", "http"] port = 443 [[services.tcp_checks]] grace_period = "1s" interval = "15s" restart_limit = 0 timeout = "2s" 主要就是一些常规的服务端口配置等。 ...

十一月 12, 2022 · overstarry

Png 压缩工具

最近有一个需求,需要对 png 和 jpg 格式的图片进行压缩,jpg 格式的图片压缩比较简单,难点主要是针对 png 图片,本想继续采用前篇文章的方式将 png 转为 jpg 图片进行压缩的,但我发现部分转换后的图片出现比较大的问题,图片的背景由其它颜色变成了黑色,那看来不能采用原来的方法,得寻找新的方法,通过查阅资料发现了 2 个压缩 png 图片的工具 pngquant 和 pngcrush,接下来我就来分别介绍这 2 个工具。 pngquant pngquant 是一个命令行实用程序,也是一个用于 PNG 图像有损压缩的库。这种转换大大减少了文件大小 (通常多达 70%),并保留了完全的 alpha 透明度。 下载 可以通过官网提供的 gui 程序或者 命令行程序链接下载 pngquant,也可以通过源代码进行编译,我采用了编译好的命令行程序。 参数 options: --force 覆盖原来输出的图片 --skip-if-larger 仅当原来图片小于原图片时才保留 --output file 输出的文件路径 --ext new.png 为输出文件名设置自定义扩展名。默认情况下使用-or8.png 或-fs8.png。 --quality min-max 指示使用达到或超过最高质量 pngquant 所需的最少颜色。如果转换导致质量低于最低质量,则图像将不会被保存(如果输出到标准输出,将输出 24 位原始图像)并将以状态码 99 退出。pngquant min 和 max 是 0(最差)到 100(完美)范围内的数字 --speed N 从 1(暴力)到 10(最快)的速度/质量权衡。默认值为 3。速度 10 的质量降低 5%,但比默认值快 8 倍。 --nofs 禁用 Floyd-Steinberg dithering --posterize N output lower-precision color (e.g. for ARGB4444 output) --strip remove optional metadata (default on Mac) --verbose 打印状态信息 简单使用 压缩单个 png pngquant –force –verbose –quality=45-85 pngpath ...

十一月 5, 2022 · overstarry

apisix 实现 nginx proxy_hide_header 参数

前言 最近需要使用 apisix 反向代理 oss, 实现通过域名访问相应的资源 (由于条件的限制,不能在 oss 绑定自定义域名),我直接在 apisix dashboard 配置了路由,创建成功后,我通过浏览器访问时,发现资源不能预览会直接下载。 这样的现象让我很奇怪,通过查阅相关资料,发现使用 OSS 默认域名通过文件 URL 从浏览器访问图片或者网页文件时,Response Header 中会自动加上 Content-Disposition:attachment。即从浏览器访问这些文件时,会以附件形式进行下载。 解决 通过询问同事,得知他是通过 nginx 的 proxy_hide_header 忽略 Content-Disposition 解决的。那 apisix 该怎么实现呢,我通过自己的不断尝试和提 issue 询问官方人员,得知可以使用 response-rewrite 插件实现这个功能。 接下来我就来介绍下我尝试的过程吧,我最开始是使用 proxy-rewrite 将 Content-Disposition 设置为 inline,具体配置如下: { "uri": "/*", "name": "xx", "host": "xixi.xx.work", "plugins": { "proxy-rewrite": { "headers": { "Content-Disposition": "inline" }, "host": "xx", "regex_uri": [ "/(.*)$", "/xx/${1}" ] } }, "upstream": { "nodes": [ { "host": "xxx.com", "port": 80, "weight": 1 } ], "timeout": { "connect": 6, "send": 6, "read": 6 }, "type": "roundrobin", "scheme": "http", "pass_host": "pass", "keepalive_pool": { "idle_timeout": 60, "requests": 1000, "size": 320 } }, "status": 1 } curl 结果: ...

十一月 5, 2022 · overstarry

前后端使用 AES 加密传输数据

最近遇到前后端传输数据需要进行加密的需求,本篇文章就分别介绍使用 Node.js 和 go 进行 AES 加密解密的方法,AES 有很多不同的算法,如 aes192,aes-128-ecb,aes-256-cbc 等,根据不同的密钥长度会使用不同的算法。加密后的结果有两种表示方法:hex 和 base64,我们这里使用 hex. golang 使用 golang 实现 aes 加密,我使用标准库的方法实现,我使用的 CBC 模式。 加密 func AesEncrypt(encryptStr string, key []byte, iv string) (string, error) { encryptBytes := []byte(encryptStr) block, err := aes.NewCipher(key) if err != nil { return "", err } blockSize := block.BlockSize() encryptBytes = pkcs5Padding(encryptBytes, blockSize) blockMode := cipher.NewCBCEncrypter(block, []byte(iv)) encrypted := make([]byte, len(encryptBytes)) blockMode.CryptBlocks(encrypted, encryptBytes) return hex.EncodeToString(encrypted), nil } 解密 func AesDecrypt(decryptStr string, key []byte, iv string) (string, error) { decryptBytes, err := hex.DecodeString(decryptStr) if err != nil { return "", err } block, err := aes.NewCipher(key) if err != nil { return "", err } blockMode := cipher.NewCBCDecrypter(block, []byte(iv)) decrypted := make([]byte, len(decryptBytes)) blockMode.CryptBlocks(decrypted, decryptBytes) decrypted = pkcs5UnPadding(decrypted) return string(decrypted), nil } 运行加密解密例子 package main import ( "bytes" "crypto/aes" "crypto/cipher" "encoding/hex" "fmt" ) func AesEncrypt(encryptStr string, key []byte, iv string) (string, error) { encryptBytes := []byte(encryptStr) block, err := aes.NewCipher(key) if err != nil { return "", err } blockSize := block.BlockSize() encryptBytes = pkcs5Padding(encryptBytes, blockSize) blockMode := cipher.NewCBCEncrypter(block, []byte(iv)) encrypted := make([]byte, len(encryptBytes)) blockMode.CryptBlocks(encrypted, encryptBytes) return hex.EncodeToString(encrypted), nil } func AesDecrypt(decryptStr string, key []byte, iv string) (string, error) { decryptBytes, err := hex.DecodeString(decryptStr) if err != nil { return "", err } block, err := aes.NewCipher(key) if err != nil { return "", err } blockMode := cipher.NewCBCDecrypter(block, []byte(iv)) decrypted := make([]byte, len(decryptBytes)) blockMode.CryptBlocks(decrypted, decryptBytes) decrypted = pkcs5UnPadding(decrypted) return string(decrypted), nil } func pkcs5Padding(cipherText []byte, blockSize int) []byte { padding := blockSize - len(cipherText)%blockSize padText := bytes.Repeat([]byte{byte(padding)}, padding) return append(cipherText, padText...) } func pkcs5UnPadding(decrypted []byte) []byte { length := len(decrypted) unPadding := int(decrypted[length-1]) return decrypted[:(length - unPadding)] } func main() { data := "i am test data" key := []byte("1111111111111111") iv := "1111122211111111" encrypt, err := AesEncrypt(data, key, iv) if err != nil { panic(err) return } fmt.Println(encrypt) decrypt, err := AesDecrypt(encrypt, key, iv) if err != nil { panic(err) } fmt.Println(decrypt) } ...

十月 29, 2022 · overstarry

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 方法中有定义,为白名单处理。 ...

九月 10, 2022 · overstarry