头图

安装ctr

1、添加yum源

curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repoyum install -y yum-utils
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

2、安装containerd

yum -y install containerd.io-1.6.6

3、生成containerd配置文件

mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml

4、修改配置文件,修改以下两项配置即可。

vim /etc/containerd/config.tomlSystemdCgroup = true
sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.7"
SystemdCgroup:使用SystemdCgroup驱动
sandbox_image:配置国内的沙箱镜像地址
沙箱镜像是一个特殊的镜像,其中包含了容器运行时所需的文件和工具,以及用于隔离容器的命名空间和cgroups等资源控制机制。当容器运行时需要创建新的沙箱时,会使用该配置项指定的镜像作为基础镜像来创建沙箱。

5、启动 && 设置自启动

systemctl enable containerd  --now

6、配置镜像源

编辑Containerd的配置文件 /etc/containerd/config.toml, 在 [plugins."io.containerd.grpc.v1.cri".registry] 下方添加 config_path

    [plugins."io.containerd.grpc.v1.cri".registry]
      config_path = "/etc/containerd/certs.d"

创建目录 /etc/containerd/certs.d/docker.io,在其中添加包含下面内容的 hosts.toml 文件

server = "https://docker.io" # 源镜像地址
[host."https://xxxxxx.mirror.aliyuncs.com"] # 镜像加速地址
重启 Containerd
systemctl restart containerd

使用ctr 部署 skywalking

skywalking-oap-server

ctr run \
    --net-host \
    --env TZ=Asia/Shanghai \
    --env SW_ES_USER="elastic" \
    --env SW_ES_PASSWORD="xxxxxxxxxxxx" \
    --env SW_STORAGE=elasticsearch \
    --env SW_STORAGE_ES_CLUSTER_NODES=192.168.1xx.xx:3xx00 \
    --label "io.containerd.runtime.name=skywalking-oap-server" \
    --detach \
    docker.io/apache/skywalking-oap-server:9.3.1 skywalking-oap-server

skywalking-ui

ctr run \
    -d \
    --net-host \
    --env TZ=Asia/Shanghai \
    --env SW_OAP_ADDRESS=http://192.168.1xx.xx:12800 \
    docker.io/apache/skywalking-ui:9.3.1 \
    skywalking-ui

启用nginx 身份验证给skywalking web端

yum install epel-release -y
yum install nginx -y
yum install httpd-tools -y

vim /etc/nginx/nginx.conf   #添加以下配置:

server {

    listen       80;

    server_name  example.com; # 替换成自己的域名或 IP 地址

    location / {

        proxy_pass http://localhost:8080; # 将请求转发到 SkyWalking 服务器

        auth_basic "Restricted"; # 启用基本身份验证,显示提示信息

        auth_basic_user_file /etc/nginx/htpasswd; # 指定存储用户名和密码的文件路径

    }

}

设置admin密码

touch /etc/nginx/htpasswd。

#执行以下命令:

htpasswd -c /etc/nginx/htpasswd admin

image.png

image.png

gin 接入 skywalking
这里使用第三方库 go2sky 以及 go2sky 的 gin 中间件

go get -u github.com/SkyAPM/go2sky
go get github.com/SkyAPM/go2sky-plugins/gin/v3

代码示例
两个 gin 服务 demo-server1 和 demo-server2,demo-server1 调用 demo-server2 demo-server2 提供 POST /user/info 接口 demo-server1 提供 GET /tracer 接口

  • demo-server2 代码如下

    package main
    
    import (
    "fmt"
    "time"
    
    "github.com/SkyAPM/go2sky"
    "github.com/SkyAPM/go2sky/reporter"
    "github.com/gin-gonic/gin"
    
    v3 "github.com/SkyAPM/go2sky-plugins/gin/v3"
    )
    
    const (
    serverName = "demo-server2"
    serverPort = 8082
    )
    
    var skyAddr = "localhost:11800"
    
    type Params struct {
    Name string
    }
    
    func panicErr(err error) {
    if err != nil {
      panic(err)
    }
    }
    
    func main() {
    r := gin.Default()
    // skyAddr 是 skywaling 的 grpc 地址,默认是 localhost:11800, 默认心跳检测时间是 1s
    rp, err := reporter.NewGRPCReporter(skyAddr, reporter.WithCheckInterval(5*time.Second))
    panicErr(err)
    // 初始化一个 tracer,一个服务只需要一个 tracer,其含义是这个服务名称
    tracer, err := go2sky.NewTracer(serverName, go2sky.WithReporter(rp))
    panicErr(err)
    // gin 使用 sky 自带的 middleware
    r.Use(v3.Middleware(r, tracer))
    
    // 自定义一个接口
    r.POST("/user/info", func(context *gin.Context) {
      // LocalSpan 可以理解为本地日志的 tracer,一般用户当前应用
      span, ctx, err := tracer.CreateLocalSpan(context.Request.Context())
      panicErr(err)
      // 每一个 span 都有一个名字去标实操作的名称!
      span.SetOperationName("UserInfo")
      // 记住重新设置一个 ctx,再其次这个 ctx 不是 gin 的 ctx,而是 http request 的 ctx
      context.Request = context.Request.WithContext(ctx)
    
      params := new(Params)
      err = context.BindJSON(params)
      panicErr(err)
      // 记录日志信息
      span.Log(time.Now(), "[UserInfo]", fmt.Sprintf(serverName+" satrt, req : %+v", params))
      local := gin.H{
        "msg": fmt.Sprintf(serverName+" time : %s", time.Now().Format("15:04:05.9999")),
      }
      context.JSON(200, local)
      span.Log(time.Now(), "[UserInfo]", fmt.Sprintf(serverName+" end, resp : %s", local))
      // 切记最后要设置 span - end,不然就是一个非闭环的
      span.End()
    })
    
    r.Run(fmt.Sprintf(":%d", serverPort))
    }
  • demo-server1 代码如下

    package main
    
    import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "time"
    
    "github.com/SkyAPM/go2sky"
    "github.com/SkyAPM/go2sky/reporter"
    "github.com/gin-gonic/gin"
    
    v3 "github.com/SkyAPM/go2sky-plugins/gin/v3"
    agentv3 "skywalking.apache.org/repo/goapi/collect/language/agent/v3"
    )
    
    const (
    serverName       = "demo-server1"
    serverPort       = 8081
    remoteServerName = "demo-server2"
    remoteServerAddr = "localhost:8082"
    remotePath       = "/user/info"
    )
    
    var skyAddr = "localhost:11800"
    
    func panicErr(err error) {
    if err != nil {
      log.Fatal(err.Error())
    }
    }
    
    type Params struct {
    Name string
    }
    
    var tracer *go2sky.Tracer
    
    func skyMiddleware(r *gin.Engine) {
    var err error
    rp, err := reporter.NewGRPCReporter(skyAddr, reporter.WithCheckInterval(5*time.Second))
    panicErr(err)
    tracer, err = go2sky.NewTracer(serverName, go2sky.WithReporter(rp))
    panicErr(err)
    r.Use(v3.Middleware(r, tracer))
    }
    
    func trace(context *gin.Context) {
    span, ctx, err := tracer.CreateLocalSpan(context.Request.Context())
    panicErr(err)
    span.SetOperationName("Trace")
    
    context.Request = context.Request.WithContext(ctx)
    span.Log(time.Now(), "[Trace]", fmt.Sprintf(serverName+" satrt, params : %s", time.Now().Format("15:04:05.9999")))
    
    result := make([]map[string]interface{}, 0)
    
    //1、请求一次
    {
      url := fmt.Sprintf("http://%s%s", remoteServerAddr, remotePath)
    
      params := Params{
        Name: serverName + time.Now().Format("15:04:05.9999"),
      }
      buffer := &bytes.Buffer{}
      _ = json.NewEncoder(buffer).Encode(params)
      req, err := http.NewRequest(http.MethodPost, url, buffer)
      panicErr(err)
    
      // op_name 是每一个操作的名称
      reqSpan, err := tracer.CreateExitSpan(context.Request.Context(), "invoke - "+remoteServerName, "localhost:8082/user/info", func(headerKey, headerValue string) error {
        req.Header.Set(headerKey, headerValue)
        return nil
      })
      panicErr(err)
      reqSpan.SetComponent(2)
      reqSpan.SetSpanLayer(agentv3.SpanLayer_RPCFramework) // rpc 调用
    
      resp, err := http.DefaultClient.Do(req)
      panicErr(err)
      defer resp.Body.Close()
    
      reqSpan.Log(time.Now(), "[HttpRequest]", fmt.Sprintf("开始请求,请求服务:%s, 请求地址:%s, 请求参数:%+v", remoteServerName, url, params))
      body, err := ioutil.ReadAll(resp.Body)
      panicErr(err)
      fmt.Printf("接受到消息: %s\n", body)
      reqSpan.Tag(go2sky.TagHTTPMethod, http.MethodPost)
      reqSpan.Tag(go2sky.TagURL, url)
      reqSpan.Log(time.Now(), "[HttpRequest]", fmt.Sprintf("结束请求,响应结果:%s", body))
      reqSpan.End()
      res := map[string]interface{}{}
      err = json.Unmarshal(body, &res)
      panicErr(err)
      result = append(result, res)
    }
    
    //2 、再请求一次
    {
      url := fmt.Sprintf("http://%s%s", remoteServerAddr, remotePath)
    
      params := Params{
        Name: serverName + time.Now().Format("15:04:05.9999"),
      }
      buffer := &bytes.Buffer{}
      _ = json.NewEncoder(buffer).Encode(params)
      req, err := http.NewRequest(http.MethodPost, url, buffer)
      panicErr(err)
    
      // 出去必须用这个携带 header
      reqSpan, err := tracer.CreateExitSpan(context.Request.Context(), "invoke - "+remoteServerName, "localhost:8082/user/info", func(headerKey, headerValue string) error {
        req.Header.Set(headerKey, headerValue)
        return nil
      })
      panicErr(err)
      reqSpan.SetComponent(2)
      reqSpan.SetSpanLayer(agentv3.SpanLayer_RPCFramework) // rpc 调用
    
      resp, err := http.DefaultClient.Do(req)
      panicErr(err)
      defer resp.Body.Close()
    
      reqSpan.Log(time.Now(), "[HttpRequest]", fmt.Sprintf("开始请求,请求服务:%s, 请求地址:%s, 请求参数:%+v", remoteServerName, url, params))
      body, err := ioutil.ReadAll(resp.Body)
      panicErr(err)
      fmt.Printf("接受到消息: %s\n", body)
    
      reqSpan.Tag(go2sky.TagHTTPMethod, http.MethodPost)
      reqSpan.Tag(go2sky.TagURL, url)
      reqSpan.Log(time.Now(), "[HttpRequest]", fmt.Sprintf("结束请求,响应结果:%s", body))
      reqSpan.End()
      res := map[string]interface{}{}
      err = json.Unmarshal(body, &res)
      panicErr(err)
      result = append(result, res)
    }
    
    // 设置响应结果
    local := gin.H{
      "msg": result,
    }
    context.JSON(200, local)
    span.Log(time.Now(), "[Trace]", fmt.Sprintf(serverName+" end, resp : %s", local))
    span.End()
    {
      span, ctx, err := tracer.CreateEntrySpan(context.Request.Context(), "Send", func(s string) (string, error) {
        return "", nil
      })
      context.Request = context.Request.WithContext(ctx)
      panicErr(err)
      span.SetOperationName("Send")
      span.Log(time.Now(), "[Info]", "send resp")
      span.End()
    }
    }
    
    func main() {
    
    // 这些都一样
    r := gin.Default()
    // 使用 go2sky gin 中间件
    skyMiddleware(r)
    
    // 调用接口
    r.GET("/trace", trace)
    
    r.Run(fmt.Sprintf(":%d", serverPort))
    }

调用测试

浏览器 访问 刷新 http://localhost:8081/trace

image.png


锅包肉
89 声望17 粉丝

这个人很懒,没有什么说的。