如何使用Neovim调试在K8S(Okteto)运行的Golang应用程序
#go #kubernetes #neovim #debug

介绍

由于在标题中描述的状态非常复杂,因此我决定创建此帖子并分享我的发现。没有太多的飞溅,让我们右转。

请注意,我不会描述我在工作流中使用的所有技术。由于这是非常具体的话题,所以我认为每个人都处于同一浪潮中。

我们需要在Neovim Real中进行远程调试:

  • Delve Debugger安装在Okteto的容器中(这是我们的应用程序运行的地方
  • nekovi> = 0.8.0
  • 为Neovim安装的DAP插件集

kubernetes(oked)部分

为了用我们的开发容器替换原始容器,让我们先创建Okteto的清单。

在我的情况下,看起来像这样(当然,您的可能会有所不同):

name: t-s-generator
build:
  t-s-generator:
    image: golang:1.18-alpine3.14
    dockerfile: ./Dockerfile

deploy:
  - <replace by the command you use to deploy your app in k8s>

dev:
  t-s-generator:
    sync:
      rescanInterval: 15
      folders:
        - t-s-generator:/t-s-generator
    forward:
      - 8080:8080
      - 38697:38697  # this port definition is important, it's  port we are going to use for our debugger running inside Okteto and we need to have it accessible from our local PC, so our DAP client can connect to it

一旦我们为GO应用程序设置了Okteto环境,我们就可以成功执行okteto up,我们需要准备应用程序的二进制文件,因此可以通过调试器对其进行检查。
这是通过使用一些特定参数编译代码来完成的。我通过在我的本地PC上运行下面的命令来做到这一点,通常可以找到我的go.mod

GOOS=linux GOARCH=amd64 go build -gcflags=all="-N -l" .

您可以看到,我正在创建一个可以在我的k8s容器内运行的二进制,这就是我的Alpine Linux,这就是为什么所有这些Linux相关标志的原因。但是,这些gcflags目前很重要。

由于我们将本地文件夹与容器的远程文件夹同步,因此该二进制文件也应出现在K8中的DEV容器中,一旦创建。

okteto设置,二进制准备,下一步是在开发容器中安装和运行我们的调试器:

...
✓  Images successfully pulled
✓  Files synchronized
    Context:   kg01.i2.w.com
    Namespace: chama-chomo
    Name:      t-s-generator
    Forward:   8080 -> 8080
               38697 -> 38697
/app # go install github.com/go-delve/delve/cmd/dlv@latest
       ...
       ..
       .
/app # dlv dap -l 127.0.0.1:38697 --log --log-output="dap"
DAP server listening at: 127.0.0.1:38697
...

在此阶段,我们准备继续进行Neovim内的调试客户端设置。

Neo的角色

我不会描述如何在Neovim中安装插件,我将其保留给您,使用您的首选方式。当我使用Astronvim配置Neovim时,我将准确概述我已插入init.lua中的插件表:

  plugins = {
    init = {
      { "mfussenegger/nvim-dap" },
      {
        "rcarriga/nvim-dap-ui",
        config = function() require("dapui").setup() end,
      },
      {
        "theHamsta/nvim-dap-virtual-text",
        config = function() require("nvim-dap-virtual-text").setup() end,
      },
...
..
.

上面的插件具有某些先决条件,例如TreeTitter等。

DAP配置

要在Neovim中使用DAP,我们需要配置DAP'配置'和“适配器”。我个人更喜欢创建一个名为DapDebug()的包装器函数,我在该功能上设置了所有之前提到的所有内容,并在最后调用真实DAP客户端。

请注意,为了指定应该检查的二进制文件,我使用匿名函数,可以交互询问二进制路径。

local dap = require "dap"

function DapDebug()
  dap.configurations.go = {
    {
      type = "delve",
      name = "Debug (Remote binary)",
      request = "launch",
      mode = "exec",
      hostName = "127.0.0.1",
      port = "38697",
      program = function()
        local argument_string = vim.fn.input "Path to binary: "
        vim.notify("Debugging binary: " .. argument_string)
        return vim.fn.split(argument_string, " ", true)[1]
      end,
    },
  }

  -- we want to run delve manually
  dap.adapters.delve = {
    type = "server",
    host = "127.0.0.1",
    port = 38697,
  }

  require("dap").continue()
end

尽管它是完全可选的,但我设置了一些关键绑定,以与Neovim内部的调试器进行交互。我将为您分享它们,因此您可以根据自己的方式创建自己的一套绑定。

      ["<leader>ds"] = { "<cmd>lua DapDebug()<CR>", desc = "start-dap-debugger" },
      ["<leader>dC"] = { "<cmd>lua require('dapui').close()<CR>", desc = "close-dap-ui" },
      ["<leader>dT"] = { "<cmd>lua require('dapui').toggle()<CR>", desc = "toggle-dap-ui" },
      ["<leader>dO"] = { "<cmd>lua require('dapui').open()<CR>", desc = "open-dap-ui" },
      ["<leader>dc"] = { "<cmd> lua require'dap'.continue()<CR>", desc = "dap-continue" },
      ["<leader>do"] = { "<cmd> lua require'dap'.step_over()<CR>", desc = "dap-step-over" },
      ["<leader>di"] = { "<cmd> lua require'dap'.step_into()<CR>", desc = "dap-step-into" },
      ["<leader>du"] = { "<cmd> lua require'dap'.step_out()<CR>", desc = "dap-step-out" },
      ["<leader>db"] = { "<cmd>lua require'dap'.toggle_breakpoint()<CR>", desc = "set-breakpoint" },
      ["<leader>"] = {
        "<cmd>lua require'dap'.set_breakpoint(vim.fn.input('breakpoint condition: '))<CR>",
        desc = "set-conditional-breakpoint",
      },

运行调试器

在这一部分中,我想与您分享Neovim在Kubernetes中部署的应用程序(使用Okteto)中的调试会话。享受水果!

开始使用:lua DapDebug()
开始调试会话 Image description

它将要求提供二进制的位于遥控侧的位置
Image description

最后..

Image description