Golang Templates

Golang Template 今天来讲讲 golang 中的标准库 template, Go 标准库提供了几个 package 可以产生输出结果,主要有 2 个:text/template 和 html/template, text/template 提供根据模板输出内容,html/template 产生安全的 HTML 的输出,这两个库的使用方式很相似,文中的例子大部分是基于 html/template 展示的。 解析和创建模板 模板命名 template 所使用的库没有限定扩展名,但最经常使用的后缀是 .tmpl, 编辑器对.tmpl 的支持最好,官方的例子也是使用 .tmpl, .tpl 也经常使用。 创建模板 通过 Parse 方法可以创建文件名为名字的模板。 package main import ( "fmt" "html/template" "log" ) func main() { tpl, err := template.New("index").Parse("index.tmpl") if err != nil { log.Fatalln(err) } } 解析多个模板 通过 template.ParseFiles(filenames …string) 方法可以解析一组模板,使用各个文件名作为模板名称。 template.ParseGlob(pattern) 方法会根据 pattern 解析所有匹配的模板并保存。 package main import "html/template" func main() { template.ParseFiles("index.tmpl", "index2.tmpl") } 解析字符串模板 除了可以解析文件,还可以解析字符串模板。 ...

九月 3, 2021 · 2 分钟 · overstarry

Wire 入门

今天我们来讲一讲 Wire 的入门使用。 Wire 是什么 go 的依赖注入工具常见有 2 种,一类是通过反射在运行时进行依赖注入,典型代表是 uber 开源的 dig,另外一类是通过 generate 进行代码生成,典型代表就是我今天要将的 Google 开源的 wire。使用 dig 功能会强大一些,但是缺点就是错误只能在运行时才能发现,这样如果不小心的话可能会导致一些隐藏的 bug 出现。使用 wire 的缺点就是功能限制多一些,但是好处就是编译的时候就可以发现问题,并且生成的代码其实和我们自己手写相关代码差不太多,更符合直觉,心智负担更小。 Wire 使用 安装 Wire 的安装十分简单,只要执行 go get github.com/google/wire/cmd/wire , wire 命令行工具就会被安装到 $GOPATH/bin 目录下。 核心概念 在正式使用前,我来介绍一下 Wire 中的 2 个重要概念:Provider 和 Injector。 Provider Provider 是一个普通的函数,这个函数会返回构建依赖关系所需的组件。如下所示,就是一个 provider 函数,在实际使用的时候,往往是一些简单工厂函数。 func NewDb(opt *DbOpt)(*Db, error){...} 在使用中,不能存在 2 个 Provider 返回相同的类型。 Injector Injector 是由 wire 自动生成的函数。函数内部会按根据依赖顺序调用相关 Provider。 我们往往在 wire.go 文件中定义 Injector 函数签名。然后通过 wire 命令行工具生成完整函数。由于 wire.go 中的函数并没有真正返回值,为避免编译器报错,简单地用 panic 函数包装起来即可。不用担心执行时报错,因为它不会实际运行,只是用来生成真正的代码的依据。 ...

八月 27, 2021 · 2 分钟 · overstarry

Go 泛型初探

go 泛型初探 go1.17 于几天前正式发布,虽然 go 的泛型还没正式发布,但 go 的泛型代码已经并入 master 分支,所以我们可以在 go1.17 版本中提前试用泛型。 下载 go1.17 如果你目前没有 go 的任何版本,你只能去官网链接下载 1.17 版本,如果已有了 go 的其它版本,你可以通过以下方式下载使用 go1.17: go get golang.org/dl/go1.17 go1.17 download go1.17 version 这样就 1.17 就下好了。 例子 接下来我们来看看 2 个使用泛型的例子。 例子 1: package main import ("fmt") func print[T any](s []T) { for _, v := range s { fmt.Println(v) } } func main() { print([]string{"Hello, ", "overstarry\n"}) print([]int64{1, 2, 3}) print([]float64{1, 2, 3}) } go 使用[] 定义类型参数,与 java、c++ 等的<>有很大不同,any 关键字来表示任意类型约束。然后怎么运行呢?简单的 go run\build 是肯定不行的,要运行泛型代码,你需要在 run\build 后加-G 参数, 运行的命令是: ...

八月 20, 2021 · 1 分钟 · overstarry

Functional_Options

Functional Options 今天我来讲一下在 go 语言编程中一种很常用的编程模式 - Functional Options 模式。Functional Options 模式是目前在 Go 语言中最流行的一种编程模式,在 Kubernetes 等开源项目中就有 Functional Options 的影子。接下来我们就来聊一聊 Functional Options 和它解决的问题。 常见的使用场景 在我们编程中,我们会经常性的需要对一个对象进行相关的配置。比如下面这个结构实体: type Server struct { Addr string Port int Protocol string TLS *tls.Config } 在这个 Server 对象中,我们可以看到: 有侦听的 IP 地址 Addr 和端口号 Port,这两个配置选项是必填的。 然后,还有协议 Protoco 字段,这几个字段是不能为空的,但是有默认值的,例如协议的默认值是 tcp。 还有一个 TLS 这个是 HTTPS 安全链接,需要配置相关的证书和私钥。这个是可以为空的,为空就是不使用 HTTPS。 所以根据上述结构体的描述,我们需要有多种不同的创建不同配置 Server 的函数签名,如下所示: func NewDefaultServer(addr string, port int) (*Server, error) { return &Server{addr, port, "tcp", nil}, nil } func NewTLSServerWithMaxConnAndTimeout(addr string, port int, tls *tls.Config) (*Server, error) { return &Server{addr, port, "tcp", tls}, nil } 因为 go 语言与 Python 等语言是不同的,没用重载函数,所你得用不同的函数名来应对不同的配置选项。 新增配置对象 要解决这个问题,最常见的方式是使用一个配置对象,如下所示: type Config struct { Protocol string TLS *tls.Config } type Server struct { Addr string Port int Conf *Config } 我们将那些不是必填的字段存入新的结构体中,于是 Server 结构体就变成如上图所示的样子。 于是,我们只需要一个 NewServer() 的函数了,在使用前需要构造 Config 对象。 ...

八月 14, 2021 · 2 分钟 · overstarry

Docker_grafana 启动失败

Docker grafana 启动失败 今天在使用 Docker 启动 grafana 的时候,遇到了一个问题,问题如图: 为什么会出现这个问题 根据错误日志的提示,打开 http://docs.grafana.org/installation/docker/#migrate-to-v51-or-later 网址,根据官方的描述,grafana Docker 镜像在版本 5.1 及以后有了重大改变: * 在容器启动过程中不会改变文件的权限 * 默认用户 ID 由 104 变为 472 * 删除了以下的隐式卷: * /var/lib/grafana * /etc/grafana * /var/log/grafana 解决 根据官方文档的提示,我仔细查看了我的 compose 文件,发现我加了 user: ‘104’ , 应该是此行的原因导致 grafana 没有启动成功,删除此行,顺利启动。

八月 12, 2021 · 1 分钟 · overstarry

Nginx 搭建静态图片资源服务器

Nginx 搭建静态图片资源服务器 本文介绍使用 Docker Nginx 搭建静态图片资源服务器的过程和搭建中间遇到的问题。 我使用 Docker compose 搭建静态图片资源服务器,我使用的 compose 文件内容如下: version: '3.1' services: nginx: restart: always image: nginx container_name: asset ports: - 80:80 volumes: - ./nginx.conf:/etc/nginx/nginx.conf - ./uploads:/usr/share/nginx/uploads - ./conf.d:/etc/nginx/conf.d /srv/msg/storage/uploads:/usr/share/nginx/uploads 将本地的图片文件夹挂载到容器内的 /usr/share/nginx/uploads 文件夹 nginx.conf 是 Nginx 的主配置文件,conf.d 是各个网站配置的文件夹。我的 nginx.conf 内容如下: user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; include /etc/nginx/conf.d/*.conf; server { listen 80 default_server; listen [::]:80 default_server; server_name 192.168.1.117; root /usr/share/nginx/uploads/; location /{ autoindex on; } error_page 404 /404.html; location = /40x.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } } } 静态资源图片服务器的配置文件如下: ...

八月 6, 2021 · 2 分钟 · overstarry

Traefik 入门使用

Traefik 入门使用 简介 Traefik(发音为 traffic)是一个现代 HTTP 反向代理和负载均衡设施,使部署微服务变得容易。Traefik 与你现有的基础设施组件(Docker、Swarm 模式、Kubernetes、Consul、Etcd、…)集成,并自动和动态地配置自己。将 Traefik 指向你的基础设施组件应该是你唯一需要的配置步骤。 快速入门 在这里我使用 Docker 来快速使用 Traefik。 先创建一个 docker-compose.yml 文件,写入如下内容: version: '3' services: reverse-proxy: # 使用的 traefik2.4 Docker 镜像版本 image: traefik:v2.4 # 通过命令行参数启动 traefik,启用不安全模式以使用 dashboard,配置发现使用了 docker command: --api.insecure=true --providers.docker ports: # The HTTP port - "80:80" # dashboard 端口 - "8080:8080" volumes: # 监听 docker 事件 - /var/run/docker.sock:/var/run/docker.sock 执行 docker-compose up -d reverse-proxy 启动 docker-compose up -d reverse-proxy 打开浏览器输入 http://localhost:8080/api/rawdata 访问看见 Traefik’s API rawdata,就表示安装成功了。 ...

八月 6, 2021 · 3 分钟 · overstarry

Go_Modules 指南和常见问题

Go Modules 简明使用 Go Modules 是从 go1.11 开始初步支持,到现在的 1.16、1.17 默认开启,是目前 go 项目的推荐包管理方式。接下来让我们看一下 go modules 的简单使用方法。 使用 Go Modules 初始化 # go mod init [包路径] go mod init github.com/overstarry/go-mod-example 执行上述命令会生成 go.mod 文件 module github.com/overstarry/kratos-demo go 1.16 添加依赖 在当前项目的目录中执行 go get 命令,会添加相应的库到 mod 文件中 go get github.com/go-kratos/kratos/v2 这个命令会在 mod 文件里添加以下信息 require ( github.com/go-kratos/kratos/v2 v2.0.1 ) 在 go get 的时候如果不手动指定版本信息,会自动拉取最新的版本的包 如果想要拉取指定版本可以通过 go get github.com/go-kratos/kratos/v2 v2.0.1 的方式,支持 @版本号 例如 @v2.0.1 @分支名 例如 @master @commit tag 例如 @6cff360233dc4457f1536e4f3df4e4e740fd3410 // indirect 表示,我们在代码中没有直接应用这个包 执行完 go get 命令之后还会在目录下生成一个 go.sum 文件 github.com/go-kratos/kratos/v2 v2.0.0-rc7 h1:Qvpz07BefgMFQycSDb57NlWhtYGz4me3wh8E1naI9/k= github.com/go-kratos/kratos/v2 v2.0.0-rc7/go.mod h1:/2bGobqE+/F9kKOe4Re0OO5X2NWNGt+7n2e8Y5DHFRc= github.com/go-kratos/kratos/v2 v2.0.1 h1:iFteVlcLWnAQu5n4I5bTN63svW+0YylGwhNTYO2MkOQ= github.com/go-kratos/kratos/v2 v2.0.1/go.mod h1:Jz6fuJFF2SLczQ7Y8ocKieVGgstQKa+R9NX09bCHekU= 这个文件主要包含当前依赖的所有的包。 ...

七月 30, 2021 · 1 分钟 · overstarry

Gitlab CI 构建 docker 镜像

Gitlab CI 构建 docker 镜像 利用 Gitlab CI 结合 Docker 构建 docker 镜像主要有三种方法。 将 Docker 执行器与 Docker 镜像一起使用。 使用 shell 执行器 Docker socket 绑定 现在来讲讲我的具体使用过程和遇到的一些问题,由于我的 gitlab-runners 使用了 docker 执行器,所以我主要使用了 1 和 3 两种方法。 由于网上的相关文章主要是采用 Docker in Docker 的方式,所以最开始我也是采用这种方式。 我的 ci 脚本是: services: - docker:dind variables: OUTPUT_NAME: bot DOCKER_HOST: tcp://localhost:2375 DOCKER_DRIVER: overlay2 DOCKER_TLS_CERTDIR: "" build_docker_image_and_push_to_nexus: stage: build image: docker:stable extends: .go-cache script: - docker info - docker build -t docker.overtsarry.vip/bot:1.0.1 . - docker login --username=$username docker.overtsarry.vip --password $pwd - docker push docker.overtsarry.vip/bot:1.0.1 运行 CI,发现 CI 运行失败,具体报错是 ...

七月 22, 2021 · 2 分钟 · overstarry

Hugo Github_page 自定义域名

部署好 GithubPage 后,觉得提供的域名不好,想要换成自己的域名,该如何操作呢。下面来介绍下给 Github Page 设置自定义域的方式。 在 Github 上,打开 GithubPage 所在仓库。 在仓库名称下,单击 Settings(设置)。 在左侧边栏中,单击 Pages(页面)。 在 “Custom domain(自定义域)“下,输入自定义域,然后单击 Save(保存)。这将创建一个在发布源根目录中添加 CNAME 文件的提交。 导航到您的 DNS 提供程序并创建 CNAME 记录,使子域指向您站点的默认域。就是在你域名的提供商进行相应域名的解析,添加对应的 CNAME 记录集。 6.(可选)要为您的站点实施 HTTPS 加密,请选择 Enforce HTTPS(实施 HTTPS)。可能要过 24 小时才能使用此选项。 上面这是常规的标准做法,由于我是采用 Github actions 构建生成站点,每次 CI 运行时,都会重新生成仓库文件,CNAME 文件都需要重新创建,十分不方便。于是在 Hugo site static 文件夹创建 CNAME 文件,这样每次运行 CI 时,都不需要重复上面步骤。 参考链接 https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site

七月 15, 2021 · 1 分钟 · overstarry