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 的一些容器实现机制相关。 ...

十一月 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地址。 Consul知道这些服务的位置,因为每个服务都在其本地Consul客户端注册。操作员可以手动注册服务,配置管理工具可以在部署服务时注册服务,或者容器编排平台可以通过集成自动注册服务。 接下来我将通过配置文件手动注册服务。 新建配置文件目录 mkdir ./consul.d 新建一个服务定义文件 echo '{ "service": { "name": "web", "tags": [ "rails" ], "port": 80 } }' > ./consul.d/web.json 现在重新启动代理,使用命令行标志来指定配置目录,并在代理上启用脚本检查。 consul agent -dev -enable-script-checks -config-dir=./consul.d ...

十一月 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