Dockerfile多阶段构建镜像

作者:matrix 发布时间:2024-07-06 分类:Golang Linux

在构建GOdocker镜像时,都需要安装很多开发环境和依赖包,如果正常打包完整环境为镜像完全没有必要。因为运行时只需要Golang打包的二进制文件,不需要完整 dev 环境。

dockerfile多阶段构建就可以完美解决,将构建和运行环境分开,可以最终镜像最小化。 😆 😆 爽~~

# 第一阶段:使用开发环境镜像进行构建,设置别名builder
FROM golang:1.22 AS builder

# 设置工作目录
WORKDIR /app

# 复制所有文件到工作目录
COPY . .

# 编译应用程序
RUN go build -o go-demo .

# 第二阶段:使用小体积的基础镜像 打包最终镜像
FROM alpine:latest

WORKDIR /app

# 从构建阶段复制编译好的可执行文件
COPY --from=builder /app/go-demo .

# 运行可执行文件
CMD ["./go-demo"]

这样就可以确保最终的镜像只包含运行应用所需的最小文件,镜像环境也只是基础的alpine镜像。

struct结构体类型2 - 嵌入结构体值 指针类型区别

作者:matrix 发布时间:2023-07-07 分类:Golang

Golang中嵌入结构体类型有两种:值或指针

结论

创建 含内嵌指针struct实例时,必须手动声明嵌入的结构指针。

伪代码如下:

package main
type BaseDao struct{name string}

# 匿名结构体字段BaseDao 
type OptDao1 struct{BaseDao} # 嵌入值
type OptDao2 struct{*BaseDao} # 嵌入指针

func main(){
  opt := OptDao2{BaseDao:&BaseDao{}} //必须手动声明嵌入的结构指针
}

上面代码中OptDao1、OptDao2嵌入了BaseDao结构体,主要区别只有嵌入值的类型不同。值和指针区别

嵌入值

创建OptDao1对象

mOptDao1 := OptDao1{}
mOptDao1.name 

代码调用会正常,属性name会获取到空字符串

其他例:

type Base struct {
    value int
}

func (b *Base) Increase() {
    b.value++
}

type Derived struct {
    Base
}

func main() {
    d := Derived{}
    d.Increase()
    fmt.Println(d.value) // 输出 1
}

嵌入指针

创建OptDao2对象

mOptDao2 := OptDao2{}
mOptDao2.name 

上面代码调用会出现nil空指针异常,runtime error: invalid memory address or nil pointer dereference,即nil指针解引用错误。

原因是访问一个nil对象的方法或属性,这就会panic。

怎么办?

mOptDao2 := OptDao2{BaseDao:&BaseDao{}}
mOptDao2.name 

创建mOptDao2实例时必须声明嵌入的结构指针

其他例:

type Base struct {
    value int
}

func (b *Base) Increase() {
    b.value++
}

type Derived struct {
    *Base
}

func main() {
    d := Derived{Base: &Base{}}
    d.Increase()
    fmt.Println(d.value) // 输出 1
}

简而言之,选择值类型嵌入还是指针类型嵌入,主要取决于你是否需要多个实例共享同一个嵌入实例的状态。如果你需要共享状态,使用指针类型嵌入。如果你不需要共享状态,使用值类型嵌入。

一般情况下选择嵌入值即可,除非多个对象需要共享一个Base结构实例。

Golang的结构体类型struct

作者:matrix 发布时间:2023-06-24 分类:Golang

熟悉面向对象语言的话,Golangstruct结构体有点像面向对象编程中的。但这两者不是完全一样,只能说都有继承、封装、多态的特点。

结构体(struct)

结构体可以将零个或多个任意类型的值聚合在一起,能描述多个数据类型

type Person struct {
  name    string
  age     int
  value   string
  address string
}

成员方法和接收者

func (p *Person) setName(name string) {
  p.name = name
}

说明:
setName 为声明的方法
p *Person为接收者(指针类型)

struc类型新增成员方法的语法很另类,像是单独给struct做绑定,绑定的时候会有接收者来指定当前实例类型。

Golang其实可以给任何类型创建成员方法:

type MyInt int
func (i MyInt) IsZero() bool{
  return i == 0
}

这里通过声明int的自定义类型MyInt,然后绑定一个成员方法。灵活~

值接收者 指针接收者

方法的接收者可以是结构体的值或者指针。上面例子的接收者是一个Person类型的指针。指针接收者的一个优点是可以直接修改接收者的字段值,还避免值的拷贝(内部实际上是拷贝的指针)。

声明为值接收者也是可以:

func (p Person) getName() string {
  return p.name
}

getName方法会在调用时复制接收者,就可能会导致性能问题。一般是建议使用指针作为接收者

小结

值接收者或者指针接收者 都能调用结构体或者内嵌结构体的方法或者属性。
给结构体绑定成员方法时,参数最好使用指针,防止值拷贝

func (this *Person) setName(name string) 


// 申明结构体struct
type Person struct {
  name    string
  age     int
  value   string
  address string
}

//结构绑定

// 给结构体绑定成员方法。 不推荐使用,内存利用低效(参数会使用值传递,会内存拷贝)
//p Person这里p表示值接收者
// func (p Person) getName() string {
// 这里的p变量指针和外部调用的mPerson不同,这里属于值拷贝!!!
//  return p.name
// }

// 给Person结构体指针绑定成员方法,同上面效果。但是参数属于引用传递
//this为指针接收者
func (this *Person) getName() string {
  return this.name
}

// 给Person结构体指针绑定方法
func (this *Person) setName(name string) {
  this.name = name
}

func main() {
  //创建实例
  // var mPerson *Person = new(Person)//返回实例指针
  // var mPerson Person = *new(Person)//返回实例
  // var mPerson Person = Person{}//返回实例
  var mPerson *Person = &Person{name: "Hi~"} //获取实例指针
  mPerson.setName("")
  fmt.Println(mPerson.getName())
}

简单好用的SLA探活工具 - EaseProbe

作者:matrix 发布时间:2022-10-02 分类:零零星星

SLA探活的需求很广泛,简单的可以自己实现。但是专门独立的探活工具倒是极少~

EaseProbeGO编写,不需要其他依赖支持直接使用二进制程序运行。

这几天测试用来给api接口、ssl证书、web 200探活,好用~

图片5579-简单好用的SLA探活工具 - EaseProbe

github仓库

https://github.com/megaease/EaseProbe

支持HTTP、TCP、SSH、SSL证书、各种数据库/消息中间件服务探活,和email、Slack、Discord、Telegram、飞书...的通知。还支持消息通知和定时发送报表,可以自定义分类告警渠道

配置config.yaml

参照官方配置,新建文件config.yaml

配置SSL证书过期检测、WEB HTTP200检测、接口HTTP状态检测:

http: # http探活

    # 默认监控网页HTTP是否为200OK
  - name: "HHTJIM.COM OK"
    url: https://www.hhtjim.com
  - name: "LINK.HHTJIM.COM OK"
    url: https://www.hhtjim.com

    # 监控接口是否返回指定状态码
  - name: link mp3 parse
    url: https://link.hhtjim.com/163/5146554.mp3
    method: GET
    insecure: true 
    success_code:
        # 配置允许的状态码范围
      - [200,206] # the code >=200 and <= 206
      - [300,308] # the code >=300 and <= 308
    timeout: 1s # default is 30 seconds

tls: # SSL证书探活

    # 监控网页证书是否临近过期(24小时内触发告警)
  - name: "www.hhtjim.com SSL EXPIRED"
    host: www.hhtjim.com:443
    insecure_skip_verify: true # dont check cert validity
    expire_skip_verify: false # dont check cert expire date
    alert_expire_before: 24h # alert if cert expire date is before X, the value is a Duration, see https://pkg.go.dev/time#ParseDuration. example: 1h, 1m, 1s. expire_skip_verify must be false to use this feature.

    # 监控网页证书是否临近过期(7天内触发告警)
  - name: "link.hhtjim.com SSL EXPIRED"
    host: link.hhtjim.com:443
    insecure_skip_verify: true 
    expire_skip_verify: false 
    alert_expire_before: 168h 

notify: # 告警通知方式

  lark:
    - name: "lark alert service"

        # 配置飞书通知机器人的webhook
      webhook: "https://open.feishu.cn/open-apis/bot/v2/hook/00000-10b1-000000-8949-00000000"

# 全局配置
settings:
  probe:
    timeout: 30s # the time out for all probes
    interval: 1m # probe every minute for all probes

说明:

参照上面注释可自由配置,我这里使用的是飞书通知。也可以其他方式告警~

探活配置参数:
https://github.com/megaease/easeprobe/blob/main/docs/Manual.md#1-probe

告警通知配置参数:
https://github.com/megaease/easeprobe/blob/main/docs/Manual.md#2-notification

开启监控

EaseProbe已经有docker镜像,可以直接一键启停。

# 首次启动
$ docker run -d  -p 8181:8181 --name sla -v $(pwd)/config.yaml:/opt/config.yaml megaease/easeprobe


# 重启
$ docker restart sla


# 关闭
$ docker stop sla

查看状态

访问http://HOST:8181`就能看到web监控面板,且支持api接口http://HOST:8181/api/v1/sla`

图片5569-简单好用的SLA探活工具 - EaseProbe

附. 飞书BOT创建

这里的告警通知使用的是群自定义机器人webhook,需要使用飞书客户端创建(web端没有找到入口)

  • 群设置

图片5581-简单好用的SLA探活工具 - EaseProbe

  • 添加自定义机器人

图片5582-简单好用的SLA探活工具 - EaseProbe

  • 复制webhook地址

参考:

https://mp.weixin.qq.com/s/c73ZPBGOMbqjT-xbRiCJ3g

https://github.com/megaease/easeprobe/blob/main/docs/Manual.md

https://open.feishu.cn/document/ukTMukTMukTM/ucTM5YjL3ETO24yNxkjN?lang=zh-CN

xiaomi开源SQL优化建议工具 - soar

作者:matrix 发布时间:2018-10-29 分类:零零星星

SOAR -- sql Optimizer And Rewriter 由小米运维 DBA 团队开发的sql 智能优化与改写工具20181021宣布开源。
github:https://github.com/xiaomi/soar

安装说明:https://github.com/xiaomi/soar/blob/master/doc/install.md

测试环境:ubuntu 16.04

安装GO

apt-get安装失败改用
源码下载:https://GOlang.google.cn/dl/
配置环境变量

解压:
> sudo tar -C /usr/local -xzf go1.11.1.linux-amd64.tar.gz

全局用户的环境变量:
> sudo vi /etc/profile

末尾添加:
export PATH=$PATH:/usr/local/go/bin

go版本查看:

> go version

source更新环境变量:

source /etc/profile

还需要配置GOPATH环境变量:表示go的工作目录 USER_NAME 为用户名
export GOPATH="/home/USER_NAME/go"

安装soar

> go get -d github.com/XiaoMi/soar
> cd ${GOPATH}/src/github.com/XiaoMi/soar && make

若安装顺利,最终会显示success。否则 build error

我前几次安装都失败

go build github.com/pingcap/tidb/parser: /usr/local/go/pkg/tool/linux_amd64/compile: signal: killed 
Makefile:69: recipe for target 'build' failed

之后google找到帖子 有人说是vps内存太低导致的,遂重启了下Ubuntu 重新make。bingo~

安装成功之后会发现~/go/src/github.com/XiaoMi/soar多出一个 soar文件。
执行测试:

> cd ~/go/src/github.com/XiaoMi/soar
> echo 'select * from film' | ./soar

图片4152-xiaomi开源SQL优化建议工具 - soar

使用soar

常用命令:https://github.com/XiaoMi/soar/blob/master/doc/cheatsheet.md

打印所有的启发式规则1

$ soar -list-heuristic-rules

打印支持的报告格式

$ soar -list-report-types

以指定格式输出报告

$ soar -report-type json

语法检查工具

$ echo "select * from tb" | soar -only-syntax-check
$ echo $?
0

$ echo "select * fromtb" | soar -only-syntax-check
At SQL 0 : syntax error at position 16 near 'fromtb'
$ echo $?
1

慢日志进行分析示例

$ pt-query-digest slow.log > slow.log.digest
# parse pt-query-digest's output which example script
$ python2.7 doc/example/digest_pt.py slow.log.digest > slow.md

SQL指纹

$ echo "select * from film where col='abc'" | soar -report-type=fingerprint

输出

select * from film where col=?

将UPDATE/DELETE/INSERT语法转为SELECT

$ echo "update film set title = 'abc'" | soar -rewrite-rules dml2select,delimiter  -report-type rewrite

输出

select * from film;

合并多条ALTER语句

$ echo "alter table tb add column a int; alter table tb add column b int;" | soar -report-type rewrite -rewrite-rules mergealter

输出

ALTER TABLE `tb` add column a int, add column b int ;

SQL美化

$ echo "select * from tbl where col = 'val'" | ./soar -report-type=pretty

输出

SELECT
  *
FROM
  tbl
WHERE
  col  = 'val';

EXPLAIN信息分析报告

$ soar -report-type explain-digest << EOF
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | film  | ALL  | NULL          | NULL | NULL    | NULL | 1131 |       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
EOF
##  Explain信息

| id | select\_type | table | partitions | type | possible_keys | key | key\_len | ref | rows | filtered | scalability | Extra |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1  | SIMPLE | *film* | NULL | ALL | NULL | NULL | NULL | NULL | 0 | 0.00% | &#x2620;&#xfe0f; **O(n)** |  |


### Explain信息解读

#### SelectType信息解读

* **SIMPLE**: 简单SELECT(不使用UNION或子查询等).

#### Type信息解读

* &#x2620;&#xfe0f; **ALL**: 最坏的情况, 从头到尾全表扫描.

markdown转HTML

通过指定-report-css, -report-javascript, -markdown-extensions, -markdown-html-flags这些参数,你还可以控制HTML的显示格式。

$ cat test.md | soar -report-type md2html > test.html

PEACE~

参考:
https://github.com/beego/wetalk/issues/32
https://www.oschina.net/news/101034/xiaomi-opensource-soar
https://juejin.im/entry/5bbf21fde51d450e61605d99