'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
,表明手动转义了"
个字符。被逐字接收 "
个字符。通过外部程序。
以下命令在 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
,表明手动转义了"
个字符。被逐字接收 "
个字符。通过外部程序。