'kubectl patch' 适用于 Linux Bash 但不适用于 Windows Powershell ISE

'kubectl patch' works on Linux Bash but not in Windows Powershell ISE

以下命令在 Ubuntu bash 上运行良好:

kubectl patch deployment wapi-backend-d1 --patch '{"spec": {"template": {"metadata": {"labels": {"date": "test"}}}}}'

相同的命令在 Windows Powershell 控制台 (ISE) 中不起作用。

错误是:

kubectl : Error from server (BadRequest): invalid character 's' looking for beginning of object key string
At line:1 char:1
+ kubectl patch deployment wapi-backend-d1 --patch '{"spec": {"template ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (Error from serv...ject key string:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

Powershell 控制台版本为:

PS > $PSVersionTable

Name                           Value                                                                                                                                                                                                                             
----                           -----                                                                                                                                                                                                                             
PSVersion                      5.1.14409.1005                                                                                                                                                                                                                    
PSEdition                      Desktop                                                                                                                                                                                                                           
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                                                                                                                                                                                                           
BuildVersion                   10.0.14409.1005                                                                                                                                                                                                                   
CLRVersion                     4.0.30319.42000                                                                                                                                                                                                                   
WSManStackVersion              3.0                                                                                                                                                                                                                               
PSRemotingProtocolVersion      2.3                                                                                                                                                                                                                               
SerializationVersion           1.1.0.1            

我也尝试过使用不同的补丁值的命令,因为我看到有人写道,如果已经应用补丁,补丁可能会失败。

路径 /spec/template/metadata/labels/date 确实存在于部署的 yaml 中,所以这也不是问题。

我认为这可能与 kubectl 在 Powershell 中与引号相关的工作方式不同有关,但找不到使其工作的方法。

我试过了

kubectl patch deployment wapi-backend-d1 --patch "{\"spec\": {\"template\": {\"metadata\": {\"labels\": {\"date\": \"test123\"}}}}}"

但这会导致

Error from server (NotFound): deployments.extensions "spec\: {\template\: {\metadata\: {\labels\: {\date\: \test123\}}}}}" not found

Powershell 上的命令应该是什么?

有关详细且非常有用的背景,请参阅

在经历了很多挫折之后,我决定列出我尝试过的所有引号转义变体,并想出了一个突然奏效的变体! 所以,在这里分享:

kubectl patch deployment wapi-backend-d1 --patch '{\"spec\": {\"template\": {\"metadata\": {\"labels\": {\"date\": \"test123\"}}}}}'

这是在 Powershell 中使用 kubectl 补丁的方法

此外,值得注意的是:我实际上是在尝试用时间戳对其进行修补,以在不更改容器映像标签的情况下触发滚动更新(因此设置映像对我没有帮助)。

当你尝试将你的 JSON 放入一个变量中,然后用一个变量调用 kubectl patch 时,你再次遇到转义的麻烦。这就是我最终得到的:

$patchRequest = @{
    spec = @{
        template = @{
            metadata = @{
                labels = @{
                    date = ((((Get-Date -Format o)).replace(':','-').replace('+','_')))
                }
            }
        }
    }
}
$patchJson = ((ConvertTo-Json -InputObject $patchRequest -Compress -Depth 10))
$patchJson = $patchJson.replace('"','\"')
kubectl patch deployment wapi-backend-d1 --patch $patchJson

您在 中找到了正确的解决方案,但让我尝试从概念上对其进行分解:

在传递给外部程序的字符串参数中嵌入 "(双引号):

  • (a) 首先 - 明智且不可避免地 - 您需要满足 PowerShell 关于嵌入 " 字符的语法要求。在带引号的字符串中。

  • (b) 然后 - 这一步应该不是必需的 - 您需要 \-转义嵌入的 " 字符。您希望外部程序看到

    • 这是一个 长期存在的令人讨厌的错误,至少在 PowerShell 7.2 中存在,可能 得到修复7.3 - 见 this answer.

Re (a),你有以下选择:

  • '...'-quoting(单引号),其中你可以按原样使用"

    • '{ "spec": "none" }'
    • '...' 中的所有内容都是字面上的 - 没有发生扩展(插值)。
  • "..."-quoting(双引号),其中可以使用`"""嵌入"字符:

    • "{ `"spec`": `"none`" }" - ` 是 PowerShell 的通用转义字符。
    • "{ ""spec"": ""none"" }" - "-特定转义(加倍)
    • "..."的内容进行了展开(插值),也就是说可以引用变量($var)或者子表达式($(1 + 2)) 在这些字符串中,PowerShell 将其替换为它们的值 - 有关 PowerShell 的 可扩展字符串 .
    • 的更多信息,请参阅 this answer

如果您将这样的字符串传递给其他 PowerShell 命令(cmdlet、函数或脚本),无需采取进一步行动;例如:

PS> Write-Output '3" of rain'
3" of rain

Re (b) - 即 将这些字符串传递给 外部程序 - 你 另外需要\-转义嵌入的"字符。:

  • 对上面的例子应用手动转义:

    • '{ \"spec\": \"none\" }'
    • "{ \`"spec\`": \`"none\`" }"
    • "{ \""spec\"": \""none\"" }"
  • 以编程方式转义到预先存在的字符串:

    • 将 verbatim " 替换为 verbatim \",以及任何先前存在的 紧接在 \ 之前的 \ =39=]:

      • $str = '3" of rain'; $escapedStr = $str -replace '([\]*)"', '\"'

      • 也就是说,要使外部程序最终逐字查看值 3" of rain,您必须从 PowerShell 传递文字值 3\" of rain这种 \-转义是 PowerShell 作为 shell 应该在幕后自动执行的操作,但目前不会。

  • WindowsPowerShell 中还有一个 附加错误 - 因为在 PowerShell Core - 错误处理带有 不平衡 嵌入 " 字符的字符串。如果 " 是第一个单词的 部分 :

    • 例如,上述技术不适用于 3" of rain 等文字值;也就是说,将其转义为 '3\" of rain' 确实 not 按预期工作 - 相反,您必须使用以下怪兽:`"3\`" of rain`",从技术上讲,这是一系列独立的,不带引号的参数,这意味着 (a) 不支持字符串单词之间的多个 space(它们被折叠为单个 space)和 (b) PowerShell 元字符,例如 & < > $ & | @ { 必须单独 `-转义。
    • 请注意,只有当 " 是值中第一个单词的一部分,并且第一个单词前面没有白色 space 时,错误才会出现(尽管前导白色的参数space 很少有用);例如,'3 \" of rain' 将再次起作用,因为不平衡的 " 不是第一个单词的一部分。

例子:

以下使用 choice.exe 作为示例外部程序,因为它可以重新调整用途(通过选项 /d Y /t 0)仅 echo 提示字符串给出,它显示了它如何接收从 PowerShell 传递的字符串:

& {
  # Note: For preview versions of v7.2, deactivate the experimental
  #       feature that fixes the problem, so as to show the original problem.   
  $PSNativeCommandArgumentPassing = 'Legacy'

  # Use manual \-escaping to pass what should be received as
  # verbatim { "spec": "none" } to an external program.
  choice /m '{ \"spec\": \"none\" }' /d Y /t 0
}

以上输出{ "spec": "none" } [Y,N]?Y,表明手动转义了"个字符。被逐字接收 " 个字符。通过外部程序。