WebAssembly In Go

WebAssembly 介绍 WebAssembly 是一种新的编码方式,可以在现代的网络浏览器中运行 - 它是一种低级的类汇编语言,具有紧凑的二进制格式,可以接近原生的性能运行,并为诸如 C / C ++等语言提供一个编译目标,以便它们可以在 Web 上运行。它也被设计为可以与 JavaScript 共存,允许两者一起工作。 Go 1.11 向 WebAssembly 添加了一个实验性端口。Go 1.12 对其某些部分进行了改进,预计 Go 1.13 会进一步改进。 简单入门 1 编写 main.go package main import "fmt" func main() { fmt.Println("Hello, WebAssembly!") } 2 使用命令编译 GOOS=js GOARCH=wasm go build -o main.wasm 这将生成一个可以在浏览器中运行的 WebAssembly 文件。 要在浏览器中执行 main.wasm,我们还需要一个 JavaScript 支持文件和一个 HTML 页面来将所有内容连接在一起。 3 复制 js 支持文件 cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" . 4 创建 HTML 页面 <html> <head> <meta charset="utf-8"/> <script src="wasm_exec.js"></script> <script> const go = new Go(); WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => { go.run(result.instance); }); </script> </head> <body></body> </html> 5 启动 web 服务器 ...

十一月 27, 2021 · overstarry

Containerd 配置私有仓库

问题 今天在使用 K8S 部署应用时,遇到容器镜像拉取失败的错误 imagepullbackoff ,通过对应用整体资源清单的分析,发现是使用了使用私有仓库镜像,但是没有配置私有仓库,这样就会导致容器无法拉取镜像,这个问题可以通过配置私有仓库来解决。 由于我使用了 Containerd 容器管理器,所以我需要配置私有仓库,并且配置私有仓库的地址为:https://docker.xx.vip. Containerd 没有 docker 配置私有仓库方便,需要修改 Containerd 配置文件进行配置,配置文件在 /etc/containerd/config.toml 中。 配置私有仓库 Containerd 默认没有此配置文件,需要通过命令导出配置文件 containerd config default> /etc/containerd/config.toml (需要提前创建目录)。 接下来我来讲解如何配置私有镜像仓库。 打开配置文件 找到 [plugins.“io.containerd.grpc.v1.cri”.registry] 修改相应配置,具体配置如下: [plugins."io.containerd.grpc.v1.cri".registry] [plugins."io.containerd.grpc.v1.cri".registry.mirrors] [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.xx.vip"] endpoint = ["https://docker.xx.vip"] [plugins."io.containerd.grpc.v1.cri".registry.auths] [plugins."io.containerd.grpc.v1.cri".registry.configs] [plugins."io.containerd.grpc.v1.cri".registry.configs."docker.xx.vip".auth] username = "xx" password = "xx" [plugins."io.containerd.grpc.v1.cri".registry.headers] 重启 containerd systemctl restart containerd.service 查看 containerd systemctl status containerd.service 回到 K8S 重新拉取镜像,可以看到镜像已经顺利拉取 参考 https://colstuwjx.github.io/2018/02/%E5%8E%9F%E5%88%9B-%E5%B0%8F%E5%B0%9D-containerd%E4%B8%80/ https://github.com/containerd/containerd/issues/5246

十一月 19, 2021 · overstarry

容器出现时间异常问题及解决方法

问题 最近在使用 MinIO SDK 上传资源对象时,出现了一个问题:The difference between the request time and the server's time is too large. 从错误信息可以看出客户端上传资源的时间与 Minio server 的时间相差太大,导致资源上传失败。 解决 根据错误信息得出 server 端的时间出现异常,由于我采用容器部署的方式,因此可以先查看容器的时间是否正确。 进入 Minio 容器 , 执行命令:date, 可以看到如图结果 ( UTC 时间): 而目前的时间是 ( CST 时间) : 可以看出容器的时间与实际的时间相差太大,所以导致资源上传失败。 方法 1 出现了时间异常的问题,可能很多人第一反应就是调整容器的时间,通过 ntpdate 等工具调整时间,这种解决方法方法适用于非容器的 MinIO SERVER 环境调整时间,容器因为一些限制无法使用此方法。 方法 2 在网上查看了许多相关的问题,有了一个针对容器的解决方法,执行: docker run --rm --privileged alpine hwclock -s 可以看到容器时间已经正常了: 我对这条命令不太明白,不明白为什么会影响到其它运行中的容器,可能是与 docker for win 的一些容器实现机制相关。 参考资料 https://stackoverflow.com/questions/4770635/s3-error-the-difference-between-the-request-time-and-the-current-time-is-too-la https://www.cnblogs.com/ryanlamp/p/13387358.html https://github.com/minio/minio-java/issues/701

十一月 12, 2021 · overstarry

Consul 学习

Consul 是一个全功能的服务网格解决方案,解决了操作微服务和云基础设施的网络和安全挑战。Consul 提供了一种软件驱动的路由和分段方法。它还带来了额外的好处,如故障处理、重试和网络可观察性。这些功能中的每一个都可以根据需要单独使用,也可以一起使用,建立一个完整的服务网格。 Consul 是一个分布式系统,旨在运行在一个节点集群上。一个节点可以是一个物理服务器、云实例、虚拟机或容器。连接在一起的 Consul 运行的节点集被称为数据中心。在数据中心内,Consul 可以以服务器或客户端两种模式运行。服务器代理维护 Consul 的一致状态。客户端是一个轻量级的进程,运行在每个运行服务的节点上。一个数据中心将有 3-5 个服务器和许多客户端。 安装 Consul Consul 的安装就不多介绍了,具体可以看看官网的教程 。 运行 Consul 由于我采用了本地安装的方式,我将以开发模式运行 Consul , 在实际生产中不要使用这种方法运行部署。 通过 consul agent -dev 在开发模式下启动 Consul 代理。 可以看到 consul 代理已经顺利启动。 通过 consul members 命令可以查看你的 consul 列表。 输出显示代理、它的 IP 地址、它的健康状态、它在数据中心中的角色以及一些版本信息。您可以通过提供 - 详细标志来发现其他元数据。 通过 members 命令查询的结果可能跟实际不太一样,通过 HTTP API 可以查询准确的结果 curl localhost:8500/v1/catalog/nodes。 使用命令 consul leave 可以停止 consul 代理。 注册服务 接下来介绍在 consul 注册一个服务。 Consul 的主要功能之一是服务发现。Consul 提供了一个 DNS 接口,下游服务可以用它来寻找其上游依赖的 IP 地址。 ...

十一月 6, 2021 · overstarry

Kubernetes 安装 APISIX

今天介绍如何在 k8s 上安装 APISIX 相关组件 (Apache APISIX、Apache APISIX Dashboard、Apache APISIX Ingress Controller)。 Apache APISIX 由于 APISIX helm 组件将相关组件集合在一起了,所以只要装一个就好了。 安装步骤 前提 要创建好相应的 PV . 命令 helm repo add apisix https://charts.apiseven.com helm repo update helm install apisix apisix/apisix --set gateway.type=NodePort --set ingress-controller.enabled=true --set dashboard.enabled=true --set etcd.volumePermissions.enabled=true --namespace ingress-apisix 如果看到如下信息并且执行 kubectl get pods -n ingress-apisix 就表示 apisix 安装成功。 NNAME: apisix LAST DEPLOYED: Wed Oct 27 03:00:23 2021 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: 1. Get the application URL by running these commands: export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services apisix-gateway) export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}") echo http://$NODE_IP:$NODE_PORT NAME READY STATUS RESTARTS AGE apisix-69459554d4-tc7sd 1/1 Running 0 8m49s apisix-etcd-0 1/1 Running 0 8m49s apisix-etcd-1 1/1 Running 0 8m49s apisix-etcd-2 1/1 Running 0 5m16s apisix-ingress-controller-678d8b5f6d-h6kq8 1/1 Running 0 8m49s 修改 apisix-dashboard service 的 spec.type 为 NodePort 安装过程的问题及解决 etcd pod 启动失败 2021-10-27 06:29:47.259764 C | etcdmain: cannot access data directory: mkdir /bitnami/etcd/data: permission denied ...

十月 27, 2021 · overstarry

设置 Rancher 服务器的本地 Kubernetes 集群

本篇文章介绍如何在 k8s 集群上安装 rancher。 前提 需要安装 kubectl 和 helm。 安装 Rancher Helm Chart 添加 helm chart 仓库 使用 helm repo add rancher-<CHART_REPO> https://releases.rancher.com/server-charts/<CHART_REPO> 添加 helm 仓库。 请将命令中的<CHART_REPO>,替换为 latest,stable 或 alpha。更多信息,请查看选择 Rancher 版本来选择最适合您的仓库。 latest: 建议在尝试新功能时使用。 stable: 建议在生产环境中使用。(推荐) alpha: 未来版本的实验性预览。 创建 Namespace 创建一个名为 cattle-system 的 Namespace。 kubectl create namespace cattle-system 安装 cert-manager # 如果你手动安装了CRD,而不是在Helm安装命令中添加了`--set installCRDs=true`选项,你应该在升级Helm chart之前升级CRD资源。 kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.5.1/cert-manager.crds.yaml # 添加 Jetstack Helm 仓库 helm repo add jetstack https://charts.jetstack.io # 更新本地 Helm chart 仓库缓存 helm repo update # 安装 cert-manager Helm chart helm install cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --version v1.5.1 安装完 cert-manager 后,您可以通过检查 cert-manager 命名空间中正在运行的 Pod 来验证它是否已正确部署: ...

十月 26, 2021 · overstarry

使用 sealos 部署 Kubernetes 集群

今天介绍使用 sealos 一键部署 Kubernetes 集群,sealos 是只能用丝滑一词形容的 kubernetes 高可用安装(kubernetes install)工具,一条命令,离线安装,包含所有依赖,内核负载不依赖 haproxy keepalived,纯 golang 开发,99 年证书,支持 v1.20.0 v1.19.5 v1.18.13 v1.17.15! sealos 支持的环境 Linux 发行版,CPU 架构 Debian 9+, x86_64/ arm64 Ubuntu 16.04, 18.04, 20.04, x86_64/ arm64 Centos/RHEL 7.6+, x86_64/ arm64 其他支持 systemd 的系统环境。x86_64/ arm64 Kylin arm64 kubernetes 版本 1.16+ 1.17+ 1.18+ 1.19+ 1.20+ 1.21+ 1.22+ 要求和建议 最低资源要求 2 vCpu 4G Ram 40G+ 存储 操作系统要求 ssh 可以访问各安装节点 各节点主机名不相同,并满足 kubernetes 的主机名要求。 各节点时间同步 网卡名称如果是不常见的,建议修改成规范的网卡名称,如 (eth.|en.|em.*) kubernetes1.20+ 使用 containerd 作为 cri. 不需要用户安装 docker/containerd. sealos 会安装 1.3.9 版本 containerd。 kubernetes1.19 及以下 使用 docker 作为 cri。也不需要用户安装 docker。sealos 会安装 1.19.03 版本 docker 网络和 DNS 要求: ...

十月 26, 2021 · overstarry

kratos 自定义 handler func 没有请求日志的问题及解决

出现的问题 最近在使用 kratos 开发 api 的时候,由于通过 proto 生成的 server handler 不符合业务的需求,需要通过自定义 handlerFunc 来定义接口。在开发中为了程序的可观测性,我使用了 kratos 提供的 logging 中间件。 在使用的过程中,我发现自定义的 HandlerFunc 的请求日志没有显示,而 proto 生成的请求正确显示了。 问题的原因 为了找到出现这种情况的原因,我在官方的 Github 仓库提了个 issue(#1566), 得到了维护人员的解答。 出现这种情况的原因是 自己定义的 handlerFunc 不走 middleware 中间件,需要自定义 http filter 才能解决。 解决 经过对 http filter 例子的简单研究,参考了官方的 logging 中间件,我自己实现了 logging filter. 代码: package middleware import ( "fmt" "net/http" "time" "github.com/go-kratos/kratos/v2/errors" "github.com/go-kratos/kratos/v2/log" "github.com/go-kratos/kratos/v2/transport" ) func Server(logger log.Logger) func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var ( code int32 reason string kind string operation string ) ctx := r.Context() startTime := time.Now() if info, ok := transport.FromServerContext(ctx); ok { kind = info.Kind().String() operation = info.Operation() } next.ServeHTTP(w, r) if se := errors.FromError(nil); se != nil { code = se.Code reason = se.Reason } level, stack := extractError(nil) _ = log.WithContext(ctx, logger).Log(level, "kind", "server", "component", kind, "operation", operation, "args", extractArgs(r), "code", code, "reason", reason, "stack", stack, "latency", time.Since(startTime).Seconds(), ) }) } } // extractArgs returns the string of the req func extractArgs(req interface{}) string { if stringer, ok := req.(fmt.Stringer); ok { return stringer.String() } return fmt.Sprintf("%+v", req) } // extractError returns the string of the error func extractError(err error) (log.Level, string) { if err != nil { return log.LevelError, fmt.Sprintf("%+v", err) } return log.LevelInfo, "" } 顺利的显示了请求的日志: ...

十月 22, 2021 · overstarry

Rsstest

test

十月 22, 2021 · overstarry

golang 随机 time.Sleep 出现的问题

问题 最近需要使用 rand 包随机 time.Sleep() 的时间,我的代码是这样的: package main import ( "math/rand" "time" ) func main() { rand.Seed(time.Now().UTC().UnixNano()) n := rand.Intn(10) time.Sleep(n * time.Second) } 会遇到下面的问题: Cannot use 'n * time.Second' (type int) as the type Duration Invalid operation: n * time.Second (mismatched types int and Duration) 解决的方法 使用 time.Duration 转换类型,代码如下: package main import ( "math/rand" "time" ) func main() { rand.Seed(time.Now().UTC().UnixNano()) n := rand.Intn(10) time.Sleep(time.Duration(n) * time.Second) } 问题的原因 time.Sleep 方法接收的类型是 Duration 类型。 func Sleep(d Duration) 当我们要 sleep 5s 时,参数是 5 * time.Second, Second 又是 1000 * Millisecond, Millisecond 是 1000 * Microsecond,Microsecond 是 1000 * Nanosecond,Nanosecond 是 1 纳秒,它的类型就是 Duration。最后 5s 就变成 5000000000 数值。 ...

十月 15, 2021 · overstarry