diff --git a/Idea/3 快捷键.md b/Idea/3 快捷键.md new file mode 100644 index 00000000..7e258550 --- /dev/null +++ b/Idea/3 快捷键.md @@ -0,0 +1,16 @@ + +### 快捷键总结 + +* 文件操作 + * 文件切换 + * 打开关闭 + * 栏目窗口 +* 文本操作:一般遵循通用的文本编辑操作。 + * 光标移动 + * 选择 + * 搜索 + * 编辑 +* 语义操作:一般与具体的编辑器强相关。 + * 导航 + * 代码 + * 重构 diff --git a/Linux/Linux工具命令/Vim编辑器.md b/Linux/Linux工具命令/Vim编辑器.md index 1476cb7e..11caca8d 100644 --- a/Linux/Linux工具命令/Vim编辑器.md +++ b/Linux/Linux工具命令/Vim编辑器.md @@ -2,10 +2,13 @@ ![](image/vi-vim-cheat-sheet-sch.gif) ![](image/2022-10-26-20-54-56.png) + ## 1 vi/vim三种模式 + 基本上 vi/vim 共分为三种模式,分别是命令模式(Command mode),输入模式(Insert mode)和底线命令模式(Last line mode)。 这三种模式的作用分别是: ### 命令模式: + 用户刚刚启动 vi/vim,便进入了命令模式。 此状态下敲击键盘动作会被Vim识别为命令,而非输入字符。比如我们此时按下i,并不会输入一个字符,i被当作了一个命令。 @@ -21,6 +24,7 @@ 命令模式只有一些最基本的命令,因此仍要依靠底线命令模式输入更多命令。 ### 输入模式 + 在命令模式下按下i就进入了输入模式。 在输入模式中,可以使用以下按键: @@ -36,6 +40,7 @@ * ESC,退出输入模式,切换到命令模式 ### 底行命令模式 + 在命令模式下按下:(英文冒号)就进入了底线命令模式。 底线命令模式可以输入单个或多个字符的命令,可用的命令非常多。 @@ -50,78 +55,81 @@ ![](image/vim-vi-workmodel.png) - ## 2 命令模式 一般模式可用的光标移动、复制粘贴、搜索替换等 ### 移动光标 -|操作|效果| -|-|-| -|h 或 向左箭头键(←) |光标向左移动一个字符| -|j 或 向下箭头键(↓) |光标向下移动一个字符| -|k 或 向上箭头键(↑) |光标向上移动一个字符| -|l 或 向右箭头键(→) |光标向右移动一个字符| + +| 操作 | 效果 | +| ------------------- | -------------------- | +| h 或 向左箭头键(←) | 光标向左移动一个字符 | +| j 或 向下箭头键(↓) | 光标向下移动一个字符 | +| k 或 向上箭头键(↑) | 光标向上移动一个字符 | +| l 或 向右箭头键(→) | 光标向右移动一个字符 | 如果你将右手放在键盘上的话,你会发现 hjkl 是排列在一起的,因此可以使用这四个按钮来移动光标。 如果想要进行多次移动的话,例如向下移动 30 行,可以使用 "30j" 或 "30↓" 的组合按键, 亦即加上想要进行的次数(数字)后,按下动作即可! -|操作|效果| -|-|-| -|[Ctrl] + [f]| 屏幕『向下』移动一页,相当于 [Page Down]按键 (常用)| -|[Ctrl] + [b]| 屏幕『向上』移动一页,相当于 [Page Up] 按键 (常用)| -|[Ctrl] + [d]| 屏幕『向下』移动半页| -|[Ctrl] + [u]| 屏幕『向上』移动半页| -|+ |光标移动到非空格符的下一行| -|- |光标移动到非空格符的上一行| -|n |那个 n 表示『数字』,例如 20 。按下数字后再按空格键,光标会向右移动这一行的 n 个字符。例如 20 则光标会向后面移动 20 个字符距离。| -0 或功能键[Home] |这是数字『 0 』:移动到这一行的最前面字符处 (常用)| -$ 或功能键[End] |移动到这一行的最后面字符处(常用)| -|H |光标移动到这个屏幕的最上方那一行的第一个字符| -|M |光标移动到这个屏幕的中央那一行的第一个字符| -|L |光标移动到这个屏幕的最下方那一行的第一个字符| -|G |移动到这个档案的最后一行(常用)| -nG |n 为数字。移动到这个档案的第 n 行。例如 20G 则会移动到这个档案的第 20 行(可配合 :set nu)| -|gg |移动到这个档案的第一行,相当于 1G 啊! (常用)| -|n |n 为数字。光标向下移动 n 行(常用)| +| 操作 | 效果 | +| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| [Ctrl] + [f] | 屏幕『向下』移动一页,相当于 [Page Down]按键 (常用) | +| [Ctrl] + [b] | 屏幕『向上』移动一页,相当于 [Page Up] 按键 (常用) | +| [Ctrl] + [d] | 屏幕『向下』移动半页 | +| [Ctrl] + [u] | 屏幕『向上』移动半页 | +| + | 光标移动到非空格符的下一行 | +| - | 光标移动到非空格符的上一行 | +| n`` | 那个 n 表示『数字』,例如 20 。按下数字后再按空格键,光标会向右移动这一行的 n 个字符。例如 20`` 则光标会向后面移动 20 个字符距离。 | +| 0 或功能键[Home] | 这是数字『 0 』:移动到这一行的最前面字符处 (常用) | +| $ 或功能键[End] | 移动到这一行的最后面字符处(常用) | +| H | 光标移动到这个屏幕的最上方那一行的第一个字符 | +| M | 光标移动到这个屏幕的中央那一行的第一个字符 | +| L | 光标移动到这个屏幕的最下方那一行的第一个字符 | +| G | 移动到这个档案的最后一行(常用) | +| nG | n 为数字。移动到这个档案的第 n 行。例如 20G 则会移动到这个档案的第 20 行(可配合 :set nu) | +| gg | 移动到这个档案的第一行,相当于 1G 啊! (常用) | +| n`` | n 为数字。光标向下移动 n 行(常用) | ### 搜索替换 -|操作|效果| -|-|-| -|/word| 向光标之下寻找一个名称为 word 的字符串。例如要在档案内搜寻 vbird 这个字符串,就输入 /vbird 即可! (常用)| -|?word| 向光标之上寻找一个字符串名称为 word 的字符串。| -|n| 这个 n 是英文按键。代表重复前一个搜寻的动作。举例来说, 如果刚刚我们执行 /vbird 去向下搜寻 vbird 这个字符串,则按下 n 后,会向下继续搜寻下一个名称为 vbird 的字符串。如果是执行 ?vbird 的话,那么按下 n 则会向上继续搜寻名称为 vbird 的字符串!| -|N |这个 N 是英文按键。与 n 刚好相反,为『反向』进行前一个搜寻动作。 例如 /vbird 后,按下 N 则表示『向上』搜寻 vbird 。| -||使用 /word 配合 n 及 N 是非常有帮助的!可以让你重复的找到一些你搜寻的关键词!| -| :n1,n2s/word1/word2/g |n1 与 n2 为数字。在第 n1 与 n2 行之间寻找 word1 这个字符串,并将该字符串取代为 word2 !举例来说,在 100 到 200 行之间搜寻 vbird 并取代为 VBIRD 则:『:100,200s/vbird/VBIRD/g』。(常用)| -|:1,$s/word1/word2/g 或 :%s/word1/word2/g |从第一行到最后一行寻找 word1 字符串,并将该字符串取代为 word2 !(常用)| -|:1,$s/word1/word2/gc 或 :%s/word1/word2/gc |从第一行到最后一行寻找 word1 字符串,并将该字符串取代为 word2 !且在取代前显示提示字符给用户确认 (confirm) 是否需要取代!(常用)| + +| 操作 | 效果 | +| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| /word | 向光标之下寻找一个名称为 word 的字符串。例如要在档案内搜寻 vbird 这个字符串,就输入 /vbird 即可! (常用) | +| ?word | 向光标之上寻找一个字符串名称为 word 的字符串。 | +| n | 这个 n 是英文按键。代表重复前一个搜寻的动作。举例来说, 如果刚刚我们执行 /vbird 去向下搜寻 vbird 这个字符串,则按下 n 后,会向下继续搜寻下一个名称为 vbird 的字符串。如果是执行 ?vbird 的话,那么按下 n 则会向上继续搜寻名称为 vbird 的字符串! | +| N | 这个 N 是英文按键。与 n 刚好相反,为『反向』进行前一个搜寻动作。 例如 /vbird 后,按下 N 则表示『向上』搜寻 vbird 。 | +| | 使用 /word 配合 n 及 N 是非常有帮助的!可以让你重复的找到一些你搜寻的关键词! | +| :n1,n2s/word1/word2/g | n1 与 n2 为数字。在第 n1 与 n2 行之间寻找 word1 这个字符串,并将该字符串取代为 word2 !举例来说,在 100 到 200 行之间搜寻 vbird 并取代为 VBIRD 则:『:100,200s/vbird/VBIRD/g』。(常用) | +| :1,$s/word1/word2/g 或 :%s/word1/word2/g | 从第一行到最后一行寻找 word1 字符串,并将该字符串取代为 word2 !(常用) | +| :1,$s/word1/word2/gc 或 :%s/word1/word2/gc | 从第一行到最后一行寻找 word1 字符串,并将该字符串取代为 word2 !且在取代前显示提示字符给用户确认 (confirm) 是否需要取代!(常用) | 1234 124 234 + ### 删除、复制与贴上 -|操作|效果| -|-|-| -|x, X| 在一行字当中,x 为向后删除一个字符 (相当于 [del] 按键), X 为向前删除一个字符(相当于 [backspace] 亦即是退格键) (常用)| -|nx n |为数字,连续向后删除 n 个字符。举例来说,我要连续删除 10 个字符, 『10x』。| -|dd |删除游标所在的那一整行(常用)| -|ndd| n 为数字。删除光标所在的向下 n 行,例如 20dd 则是删除 20 行 (常用)| -|d1G| 删除光标所在到第一行的所有数据| -|dG| 删除光标所在到最后一行的所有数据| -|d$| 删除游标所在处,到该行的最后一个字符| -|d0| 那个是数字的 0 ,删除游标所在处,到该行的最前面一个字符| -|yy| 复制游标所在的那一行(常用)| -|nyy| n 为数字。复制光标所在的向下 n 行,例如 20yy 则是复制 20 行(常用)| -|y1G| 复制游标所在行到第一行的所有数据| -|yG| 复制游标所在行到最后一行的所有数据| -个符到该行行首的所有数据| -|y$| 复制光标所在的那个字符到该行行尾的所有数据| -|p, P| p 为将已复制的数据在光标下一行贴上,P 则为贴在游标上一行! 举例来说,我目前光标在第 20 行,且已经复制了 10 行数据。则按下 p 后, 那 10 行数据会贴在原本的 20 行之后,亦即由 21 行开始贴。但如果是按下 P 呢? 那么原本的第 20 行会被推到变成 30 行。 (常用)| -|J| 将光标所在行与下一行的数据结合成同一行| -|c| 重复删除多个数据,例如向下删除 10 行,[ 10cj ]| -|u| 复原前一个动作。(常用)| -|[Ctrl]+r| 重做上一个动作。(常用)| -|. |不要怀疑!这就是小数点!意思是重复前一个动作的意思。 如果你想要重复删除、重复贴上等等动作,按下小数点『.』就好了! (常用)| + +| 操作 | 效果 | +| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| x, X | 在一行字当中,x 为向后删除一个字符 (相当于 [del] 按键), X 为向前删除一个字符(相当于 [backspace] 亦即是退格键) (常用) | +| nx nX | 为数字,连续向后删除 n 个字符。举例来说,我要连续删除 10 个字符, 『10x』。 | +| dd | 删除游标所在的那一整行(常用) | +| ndd | n 为数字。删除光标所在的向下 n 行,例如 20dd 则是删除 20 行 (常用) | +| d1G | 删除光标所在到第一行的所有数据 | +| dG | 删除光标所在到最后一行的所有数据 | +| d$ | 删除游标所在处,到该行的最后一个字符 | +| d0 | 那个是数字的 0 ,删除游标所在处,到该行的最前面一个字符 | +| yy | 复制游标所在的那一行(常用) | +| nyy | n 为数字。复制光标所在的向下 n 行,例如 20yy 则是复制 20 行(常用) | +| y1G | 复制游标所在行到第一行的所有数据 | +| yG | 复制游标所在行到最后一行的所有数据 | +| 个符到该行行首的所有数据 | | +| y$ | 复制光标所在的那个字符到该行行尾的所有数据 | +| p, P | p 为将已复制的数据在光标下一行贴上,P 则为贴在游标上一行! 举例来说,我目前光标在第 20 行,且已经复制了 10 行数据。则按下 p 后, 那 10 行数据会贴在原本的 20 行之后,亦即由 21 行开始贴。但如果是按下 P 呢? 那么原本的第 20 行会被推到变成 30 行。 (常用) | +| J | 将光标所在行与下一行的数据结合成同一行 | +| c | 重复删除多个数据,例如向下删除 10 行,[ 10cj ] | +| u | 复原前一个动作。(常用) | +| [Ctrl]+r | 重做上一个动作。(常用) | +| . | 不要怀疑!这就是小数点!意思是重复前一个动作的意思。 如果你想要重复删除、重复贴上等等动作,按下小数点『.』就好了! (常用) | u 与 [Ctrl]+r 是很常用的指令!一个是复原,另一个则是重做一次~ 利用这两个功能按键,你的编辑,嘿嘿!很快乐的啦! @@ -130,59 +138,61 @@ u 与 [Ctrl]+r 是很常用的指令!一个是复原,另一个则是重做 第二部分:一般模式切换到编辑模式的可用的按钮说明 进入输入或取代的编辑模式 -|操作|效果| -|-|-| -|i, I| 进入输入模式(Insert mode):| -|i |为『从目前光标所在处输入』, I 为『在目前所在行的第一个非空格符处开始输入』。 (常用)| -|a, A| 进入输入模式(Insert mode):a为『从目前光标所在的下一个字符处开始输入』, A 为『从光标所在行的最后一个字符处开始输入』。(常用)| -|o, O| 进入输入模式(Insert mode):这是英文字母 o 的大小写。o 为『在目前光标所在的下一行处输入新的一行』; O 为在目前光标所在处的上一行输入新的一行!(常用)| -|r, R| 进入取代模式(Replace mode):| -|r| 只会取代光标所在的那一个字符一次;R会一直取代光标所在的文字,直到按下 ESC 为止;(常用)| -||上面这些按键中,在 vi 画面的左下角处会出现『--INSERT--』或『--REPLACE--』的字样。 由名称就知道该动作了吧!!特别注意的是,我们上面也提过了,你想要在档案里面输入字符时, 一定要在左下角处看到 INSERT 或 REPLACE 才能输入喔!| -|[Esc]| 退出编辑模式,回到一般模式中(常用)| +| 操作 | 效果 | +| ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| i, I | 进入输入模式(Insert mode): | +| i | 为『从目前光标所在处输入』, I 为『在目前所在行的第一个非空格符处开始输入』。 (常用) | +| a, A | 进入输入模式(Insert mode):a为『从目前光标所在的下一个字符处开始输入』, A 为『从光标所在行的最后一个字符处开始输入』。(常用) | +| o, O | 进入输入模式(Insert mode):这是英文字母 o 的大小写。o 为『在目前光标所在的下一行处输入新的一行』; O 为在目前光标所在处的上一行输入新的一行!(常用) | +| r, R | 进入取代模式(Replace mode): | +| r | 只会取代光标所在的那一个字符一次;R会一直取代光标所在的文字,直到按下 ESC 为止;(常用) | +| | 上面这些按键中,在 vi 画面的左下角处会出现『--INSERT--』或『--REPLACE--』的字样。 由名称就知道该动作了吧!!特别注意的是,我们上面也提过了,你想要在档案里面输入字符时, 一定要在左下角处看到 INSERT 或 REPLACE 才能输入喔! | +| [Esc] | 退出编辑模式,回到一般模式中(常用) | ## 4 底线模式 + 第三部分:一般模式切换到指令行模式的可用的按钮说明 指令行的储存、离开等指令 -|操作|效果| -|-|-| -|:w| 将编辑的数据写入硬盘档案中(常用)| -|:w!| 若文件属性为『只读』时,强制写入该档案。不过,到底能不能写入, 还是跟你对该档案的档案权限有关啊!| -|:q| 离开 vi (常用)| -|:q!| 若曾修改过档案,又不想储存,使用 ! 为强制离开不储存档案。 -||注意一下啊,那个惊叹号 (!) 在 vi 当中,常常具有『强制』的意思~| -|:wq| 储存后离开,若为 :wq! 则为强制储存后离开 (常用)| -|ZZ| 这是大写的 Z 喔!若档案没有更动,则不储存离开,若档案已经被更动过,则储存后离开!| -|:w [filename]| 将编辑的数据储存成另一个档案(类似另存新档)| -|:r [filename]| 在编辑的数据中,读入另一个档案的数据。亦即将 『filename』 这个档案内容加到游标所在行后面| -|:n1,n2 w [filename]| 将 n1 到 n2 的内容储存成 filename 这个档案。| -|:! command| 暂时离开 vi 到指令行模式下执行 command 的显示结果!例如『:! ls /home』即可在 vi 当中察看 /home 底下以 ls 输出的档案信息!| +| 操作 | 效果 | +| ------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| :w | 将编辑的数据写入硬盘档案中(常用) | +| :w! | 若文件属性为『只读』时,强制写入该档案。不过,到底能不能写入, 还是跟你对该档案的档案权限有关啊! | +| :q | 离开 vi (常用) | +| :q! | 若曾修改过档案,又不想储存,使用 ! 为强制离开不储存档案。 | +| | 注意一下啊,那个惊叹号 (!) 在 vi 当中,常常具有『强制』的意思~ | +| :wq | 储存后离开,若为 :wq! 则为强制储存后离开 (常用) | +| ZZ | 这是大写的 Z 喔!若档案没有更动,则不储存离开,若档案已经被更动过,则储存后离开! | +| :w [filename] | 将编辑的数据储存成另一个档案(类似另存新档) | +| :r [filename] | 在编辑的数据中,读入另一个档案的数据。亦即将 『filename』 这个档案内容加到游标所在行后面 | +| :n1,n2 w [filename] | 将 n1 到 n2 的内容储存成 filename 这个档案。 | +| :! command | 暂时离开 vi 到指令行模式下执行 command 的显示结果!例如『:! ls /home』即可在 vi 当中察看 /home 底下以 ls 输出的档案信息! | ### vim 环境的变更 -|操作|效果| -|-|-| -|:set nu| 显示行号,设定之后,会在每一行的前缀显示该行的行号| -|:set nonu| 与 set nu 相反,为取消行号!| + +| 操作 | 效果 | +| --------- | -------------------------------------------------- | +| :set nu | 显示行号,设定之后,会在每一行的前缀显示该行的行号 | +| :set nonu | 与 set nu 相反,为取消行号! | 特别注意,在 vi/vim 中,数字是很有意义的!数字通常代表重复做几次的意思! 也有可能是代表去到第几个什么什么的意思。 举例来说,要删除 50 行,则是用 『50dd』 对吧! 数字加在动作之前,如我要向下移动 20 行呢?那就是『20j』或者是『20↓』即可。 - ### 我自己的总结 移动操作 + * hjkl 字母定位 * web 单词定位 -* +- ^0$行定位 +* +- ^0$行定位 * () 段定位 * HLM G gg 页定位 * Ctrl+fbdu屏幕定位 * m`标记跳转 * : 行号跳转 * 数字+移动命令=重复多次移动 -搜索操作 + 搜索操作 * f行内搜索 * t字符定位 * /?n搜索和查询 @@ -191,12 +201,14 @@ u 与 [Ctrl]+r 是很常用的指令!一个是复原,另一个则是重做 * . redo重新执行上一个动作 修改操作 + * 插入iao * 替代r * 修改c 删除复制黏贴 + * nx xn nX Xn * dd ndd ddn d1G dG d$ d0 d^ * yy nyy yyn y1G yG y$ y0 y^ -* p \ No newline at end of file +* p diff --git a/SpringCloudAlibaba/README.md b/SpringCloud/SpringCloudAlibaba/README.md similarity index 100% rename from SpringCloudAlibaba/README.md rename to SpringCloud/SpringCloudAlibaba/README.md diff --git a/SpringCloudAlibaba/SpringCloud简介.md b/SpringCloud/SpringCloudAlibaba/SpringCloud简介.md similarity index 100% rename from SpringCloudAlibaba/SpringCloud简介.md rename to SpringCloud/SpringCloudAlibaba/SpringCloud简介.md diff --git a/SpringCloudAlibaba/_sidebar.md b/SpringCloud/SpringCloudAlibaba/_sidebar.md similarity index 100% rename from SpringCloudAlibaba/_sidebar.md rename to SpringCloud/SpringCloudAlibaba/_sidebar.md diff --git a/kubenets/helm/简介.md b/kubenets/helm/01 简介.md similarity index 93% rename from kubenets/helm/简介.md rename to kubenets/helm/01 简介.md index 4f282e54..93f53f81 100644 --- a/kubenets/helm/简介.md +++ b/kubenets/helm/01 简介.md @@ -22,6 +22,7 @@ Helm 是 Deis 开发的一个用于 Kubernetes 应用的包管理工具,主要 * 安装配置helm ### 安装 + ``` curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash ``` @@ -40,7 +41,7 @@ echo 'source <(helm completion bash)' >> /etc/profile #查看其仓库信息 helm repo list -NAME URL +NAME URL stable https://kubernetes-charts.storage.googleapis.com #如上,默认是Google,在国外,速度特别慢 local http://127.0.0.1:8879/charts @@ -68,8 +69,8 @@ helm inspect stable/mysql #下载搜索到的包到本地 helm fetch stable/mysql -#在线安装这个MySQL -helm install stable/mysql +#在线安装这个MySQL +helm install stable/mysql ``` ## 3 Chart @@ -92,8 +93,6 @@ ConfigMap * Chart可以很简单:例如,只用于部署一个服务,比如 Memcached。Chart 也可以很复杂:例如,部署整个应用,比如包含 HTTP Servers、 Database、消息中间件、cache 等。 * Chart 将这些文件放置在预定义的目录结构中,通常整个 chart 被打成 tar 包,而且标注上版本信息,便于 Helm 部署。 - - ### 目录结构 * Chart.yaml : chart 的描述文件, 包含版本信息, 名称 等. @@ -109,15 +108,14 @@ ConfigMap * deployment.yaml : kubernetes 资源文件. ( 所有类型的 kubernetes 资源文件都存放于 templates 目录下 ) * _helpers.tpl : 以 _ 开头的文件, 可以被其他模板引用. - ### Chart.yaml -在同一个集群中,一个Charts可以使用不同的config重复安装多次,每次安装都会创建一个新的Release。 +在同一个集群中,一个Charts可以使用不同的config重复安装多次,每次安装都会创建一个新的Release。 ``` apiVersion: # chart API 版本信息, 通常是 "v1" (必须) name: # chart 的名称 (必须) -version: # chart 包的版本 (必须) +version: # chart 包的版本 (必须),版本控制、只有version变化才会触发升级更新 kubeVersion: # 指定 Kubernetes 版本 (可选) type: # chart类型 (可选) description: # 对项目的描述 (可选) @@ -148,22 +146,30 @@ annotations: example: # 按名称输入的批注列表 (可选). ``` +### 部署有顺序 + +chart中所有的Kubernetes对象以及依赖会 + +* 聚合成一个单一的集合;然后 +* 按照类型和名称排序;然后 +* 按这个顺序创建/升级。 ## 4 Repository - chart Repoistory是一个可用来存储index.yaml与打包的chart文件的HTTP server。 可以理解为是存放chart的仓库,类似于docker的镜像仓库、GitHub代码仓库等。 +仓库使用 `helm repo`命令管理。 + ## 5 Config + 应用程序实例化安装时运行使用的配置信息; ## 6 Release + chart的实例化,将chart安装到k8s上,就叫做生成一个release。如果把 chart 比作程序源码的话,那么 release 则可以看做是程序运行时的进程。 chart 是用户可直接感知的对象(其表现形式就是 .tgz 格式的压缩包) release 比较抽象,它是专属于 helm 的一个逻辑概念,用来标识在 k8s 中运行的一组资源。有了 release,helm 在操作 k8s 时,就再也不用逐个管理资源,而可以将一组相关的资源当做一个整体来操作,比如删除或升级。 - - diff --git a/kubenets/helm/02 模板语法GoTemplate.md b/kubenets/helm/02 模板语法GoTemplate.md new file mode 100644 index 00000000..48ca6833 --- /dev/null +++ b/kubenets/helm/02 模板语法GoTemplate.md @@ -0,0 +1,590 @@ +## **Go语言的模板引擎** + +Go语言内置了文本模板引擎text/template和用于HTML文档的html/templant. 它们的作用机制可以简单归纳如下: + +1. 模板文件通常定义为.tmpl和.tpl为后缀(也可以使用其他后缀), 必须使用utf-8编码. +2. 模板文件中使用{{和}}包裹和标识需要传入的数据. +3. 传给模板这样的数据就可以通过点号(.)来访问,如果数据是复杂类型的数据, 可以通过{{.FieldName}}来访问它的字段. +4. 除{{和}}包裹的内容外, 其他内容均不做修改原样输出. + +--- + +## 模板引擎的使用 + +Go语言模板引擎的使用可以分文三部分: 定义模板文件/解析模板文件/渲染模板文件 + +> 定义模板文件 + +其中, 定义模板文件时需要我们按照相关语法规则去编写, 后文会详细介绍. + +> 解析模板文件 + +上面定义好了模板文件之后,可以使用下面的常用方法去解析模板文件, 得到模板对象: + +```go +func (t *Template) Parse(src string) (*Template, error) +func ParseFiles(filenames ...string) (*Template, error) +func ParseGlob(pattern string) (*Template, error) +``` + +当然, 你也可以使用 `func New(name string) *Template`函数创建一个名为 `name`的模板, 然后对其调用上面的方法去解析模板字符串或模板文件. + +> 模板渲染 + +渲染模板简单来说就是使用数据去填充模板, 当然实际上可能会复杂很多. + +```go +func(t *Template) Execute(wr io.Writer, data interface) error +func(t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error +``` + +> 基本示例 + +### 定义模板文件 + +我们按照Go模板语法定义一个 `hello.tmpl`的模板文件, 内容如下: + +```html + + + + + + + Hello + + +

Hello {{.}}

+ + +``` + +### 解析模板和渲染模板文件 + +然后我们创建一个 `main.go`文件,在其中写下HTTP server端代码如下: + +```go +// main.go +func sayHello(w http.ResponseWriter, r *http.Request) { + // 解析指定文件生成模板对象 + tmpl, err := template.ParseFiles("./hello.tmpl") + if err != nil { + fmt.Println("create template failed, err:", err) + return + } + // 利用给定数据渲染模板, 并将结果写入w + tmpl.Execute(w, "小明") +} + +func main() { + http.HandleFunc("/", sayHello) + err := http.ListenAndServe(":9090", nil) + if err != nil { + fmt.Println("HTTP SERVER failed,err:", err) + return + } +} +``` + +将上面的 `main.go`文件编译执行, 然后使用浏览器访问 `http://127.0.0.1:9090`就能看到页面上显示了 `"Hello 小明"`. 这就是一个最简单的模板渲染的示例, Go语言模板引擎详细用法请往下阅读. + +## 模板语法 + +### `{{.}}` + +模板语法都包含在 `{{`和 `}}`中间, 其中 `{{.}}`中的点表示当前对象. + +当我们传入一个结构体对象时, 我们可以根据 `.`来访问结构体的对应字段. 例如: + +```go +// main.go +type UserInfo struct { + Name string + Gender string + Age int +} + +func sayHello(w http.ResponseWriter, r *http.Request) { + // 解析指定文件生成模板对象 + tmpl, err := template.ParseFiles("./hello.tmpl") + if err != nil { + fmt.Println("create template failed,err:", err) + return + } + // 利用给定数据渲染模板, 并将结果写入w + user := UserInfo{ + Name: "小明", + Gender: "男", + Age: 18, + } + tmpl.Execute(w, user) +} +``` + +模板文件 `hello.tmpl`内容如下: + +```html + + + + + + + Hello + + +

Hello {{.Name}}

+

性别:{{.Gender}}

+

年龄:{{.Age}}

+ + +``` + +同理, 当我们传入的变量是map时, 也可以在模板文件中通过 `.`根据key来取值. + +### 注释 + +```text +{{/* a comment */}} +注释, 执行时会忽略. 可以多行. 只是不能嵌套, 并且必须紧贴分界符始止. +``` + +### 管道pipeline + +pipeline是指产生数据的操作. 比如 `{{.}}`,`{{.Name}}`等. Go模板语法中支持使用管道符号 `|`连接多个命令, 用法和unix下的管道类似: `|`前面的命令会将运算结果(或返回值)传递给后一个命令的最后一个位置. + +注意: 并不是只有使用了 `|`才是pipeline. Go模板语法中, pipeline的概念是传递数据, 只要能产生数据的,都是pipeline. + +### 变量 + +我们还可以在模板中声明变量, 用来保存传入模板的数据或其他语句生成的结构. 具体语法如下: + +```text +$obj := {{.}} +``` + +其中 `$obj`是变量的名字, 在后续代码中就可以使用该变量了 + +### 移除空格 + +有时候我们在使用模板语法的时候会不可避免的引入一下空格或者换行符, 这样模板最终渲染出来的内容可能就和我们想的不一样,这个时候可以使用 `{{-`语法去除模板内容左侧的所有空白符号, 使用 `-}}`去除模板内容右侧的所有空白的符号. + +例如: + +```text +{{- .Name -}} +``` + +注意: `-`要紧挨 `{{`和 `}}`,同时与模板值质检需要使用空格分隔. + +### 条件判断 + +Go模板语法中的条件判断有以下几种: + +```go +{{if pipeline}} T1 {{end}} +{{if pipeline}} T1 {{else}} T0 {{end}} +{{if pipeline}} T1 {{else if pipeline}} T0 {{end}} +``` + +### range + +Go的模板语法中使用 `range`关键字进行遍历, 有以下两种写法, 其中 `pipelien`的值必须是数组,切片,字典或者通道. + +```text +{{range pipeline}}T1{{end}} +如果pipeline的值其长度为0, 不会有任何输出 +{{range pipeline}}T1{{else}}T0{{end}} +如果pipeline为empty, 不改变dot并执行T0,否则dot设置为pipeline的值并执行T1. +``` + +### with + +```text +{{with pipeline}}T1{{end}} +如果pipeline为empty不产生输出,否则将dot设为pipeline的值并执行T1.不修改外面的dot. +{{with pipeline}}T1{{else}}T0{{end}} +如果pipeline为empty, 不改变dot并执行T0,否则dot设为pipeline的值并执行T1. +``` + +### 预定义函数 + +执行模板时, 函数从两个函数字典中查找: 首先是模板函数字典, 然后是全局函数字典. 一般不在模板内定义函数, 而是使用Funcs方法添加函数到模板里. + +预定义的全局函数如下: + +```text +and + 函数返回它的第一个empty参数或者最后一个参数; + 就是说`and x y`等价于`if x then y else x`;所有参数都会执行; +or + 返回第一个非empty参数或者最后一个参数; + 即`or x y`等价于`if x then x else y`; 所有参数都会执行; +not + 返回它的单个参数的布尔值的否定 +len + 返回它的参数的整数类型长度 +index + 执行结果为第一个参数以剩下的参数为索引/键指向的值; + 如`index x 1 2 3`返回x[1][2][3]的值; 每个被索引的主体必须是数组,切片,或者字典. +print + 即fmt.Sprint +printf + 即fmt.Sprintf +println + 即fmt.Sprintln +html + 返回与其参数的文本表示形式等效的转移HEML. + 这个函数在html/template中不可用 +urlquery + 以适合嵌套到网址查询中的形式返回其参数的文本表示的转义值. + 这个函数在html/template中不可用 +js + 返回与其参数的文本表示形式等效的转义javaScript. +call + 执行结果是调用第一个参数的返回值,该参数必须是函数类型,其余参数作为调用该函数的参数; + 如`call .X.Y 1 2`等价于Go语言里的dot.X.Y(1,2); + 其中Y是函数类型的字段或者字典的值,或者是其他类似情况; + call的第一个参数的执行结果必须是函数类型的值(和预定义函数如print明显不同); + 该函数类型值必须有1到2个返回值,如果有2个返回值则后一个必须是error接口类型; + 如果有2个返回值的方法返回的error非nil,模板执行会中断并返回给调用模板的执行者该错误; +``` + +### 比较函数 + +布尔函数会将任何类型的零值视为假, 其余视为真. + +下面是定义为函数的二元比较运算的集合; + +```text +eq 如果arg1 == arg2则返回真 +ne 如果arg1 != arg2则返回真 +lt 如果arg1 < arg2则返回真 +le 如果arg1 <= arg2则返回真 +gt 如果arg1 > arg2则返回真 +ge 如果arg1 >= arg2则返回真 +``` + +为了简化多参数相等检测,eq(只有eq) 可以接受2个或更多个参数, 它会将第一个参数和其余参数依次比较,返回下式的结果: + +```text +{{eq arg1 arg2 arg3}} +``` + +比较函数只适用于基本类型(或重定义的基本类型, 如`type Celsius float32). 但是,整数和浮点数不能互相比较. + +### 自定义函数 + +Go的模板支持自定义函数. + +```go +func sayHello(w http.ResponseWriter, r *http.Request) { + htmlByte, err := ioutil.ReadFile("./hello.tmpl") + if err != nil { + fmt.println("read html failed,err:",err) + } + // 自定义一个夸人的模板函数 + kua := func(arg string)(string,error) { + return arg + "真厉害",nil + } + // 采用链式操作在Parse之前调用Func添加自定义的kua函数 + tmpl,err := templage.New("hello"). + Funcs(temolate.FuncMap{"kua":kua}). + Parse(string(htmlByte)) + if err != nil { + fmt.println("create template failed,err:",err) + return + } + user := UserInfo{ + Name: "小明", + Gender: "男", + Age: 18, + } + // 使用user渲染模板,并将结果写入w + tmpl.Execute(w,user) +} +``` + +我们可以在模板文件 `hello.tmpl`中按照如下方式使用我们自定义的 `kua`函数了 + +```text +{{kua .Name}} +``` + +### 嵌套template + +我们可以在template中嵌套其他的template. 这个template可以是单独的文件, 也可以是通过 `define`定义的template. + +举个例子: `t.tmpl`文件内容如下: + +```html + + + + + + + tmpl test + + + +

测试嵌套template语法

+
+ {{template "ul.tmpl"}} + + + +{{ define "ol.tmpl"}} +
    +
  1. 吃饭
  2. +
  3. 睡觉
  4. +
  5. 打豆豆
  6. +
+{{end}} +``` + +`ul.tmpl`文件内容如下: + +```text +
    +
  • 注释
  • +
  • 日志
  • +
  • 测试
  • +
+``` + +我们注册一个 `tmplDemo`路由处理函数 + +```go +http.HandleFunc("/tmpl", tmplDemo) +``` + +`tmplDemo`函数的具体内容如下: + +```go +func tmplDemo(w http.ResponseWriter, r *http.Request) { + tmpl, err := template.ParseFiles("./t.tmpl", "./ul.tmpl") + if err != nil { + fmt.Println("create template failed, err:", err) + return + } + user := UserInfo { + Name: "小明", + Gender: "男", + Age: 12, + } + tmpl.Execute(w, user) +} +``` + +注意: 在解析模板时, 被嵌套的模板一定要在后面解析, 例如上面的示例中 `t.tmpl`模板中嵌套了 `ul.tmpl`,所以 `ul.tmpl`要在 `t.tmpl`后进行解析. + +### block + +```text +{{block "name" pipeline}} T1 {{end}} +``` + +`block`是自定义模板 `{{define "name”}} T1 {{end}}`和执行 `{{template “name” pipeline}}`缩写, 典型的用法是定义一组根模板,然后通过在其中重心定义的快模板进行自定义 + +定义一个根模板 `templates/base.tmpl`,内容如下: + +```html + + + + Go Templates + + +
+ {{block "content" . }}{{end}} +
+ + +``` + +然后定义一个 `templates/index.tmpl`,”继承”`base.tmpl`: + +```html +{{template "base.tmpl"}} + +{{define "content"}} +
Hello world!
+{{end}} +``` + +然后使用 `template.ParseGlob`按照正则匹配规则解析模板文件,然后通过 `ExecuteTemplate`渲染指定的模板: + +```go +func index(w http.ResponseWriter, r *http.Request){ + tmpl, err := template.ParseGlob("templates/*.tmpl") + if err != nil { + fmt.Println("create template failed, err:", err) + return + } + err = tmpl.ExecuteTemplate(w, "index.tmpl", nil) + if err != nil { + fmt.Println("render template failed, err:", err) + return + } +} +``` + +如果我们的模板名称冲突了, 例如不同业务线下都定义了一个 `index.tmpl`模板, 我们可以通过下面两种方法来解决. + +1. 在模板文件开头使用{{define 模板名}}的语句显式的为模板命名. +2. 可以把模板文件存放在templates文件夹下面的不同目录中, 然后使用 `template.ParseGlob(“templates/**/*.tmpl”)`解析模板 + +### 修改默认标识符 + +Go标准库的模板引擎使用的花括号 `{{`和 `}}`作为标识,而许多前端框架(如 `Vue`和 `AngularJS`)也使用 `{{`和 `}}`作为标识符,所以当我们同时使用Go语言模板引擎和以上前端框架时就会出现冲突,这个时候我们需要修改标识符,修改前端的或者修改Go语言的。这里演示如何修改Go语言模板引擎默认的标识符: + +```go +template.New("test").Delims("{[", "]}").ParseFiles("./t.tmpl") +``` + +### text/template与html/template的区别 + +`html/template`针对的是需要返回HTML内容的场景, 在模板渲染过程中会对一些有风险的内容进行转义,以此来防范跨站脚本攻击. + +例如,我定义下面的模板文件: + +```html + + + + + + + Hello + + + {{.}} + + +``` + +这个时候传入一段JS代码并使用 `html/template`去渲染该文件,会在页面上显示出转义后的JS内容。 `alert('嘿嘿嘿')` 这就是 `html/template`为我们做的事。 + +但是在某些场景下,我们如果相信用户输入的内容,不想转义的话,可以自行编写一个safe函数,手动返回一个 `template.HTML`类型的内容。示例如下: + +```go +func xss(w http.ResponseWriter, r *http.Request){ + tmpl,err := template.New("xss.tmpl").Funcs(template.FuncMap{ + "safe": func(s string)template.HTML { + return template.HTML(s) + }, + }).ParseFiles("./xss.tmpl") + if err != nil { + fmt.Println("create template failed, err:", err) + return + } + jsStr := `` + err = tmpl.Execute(w, jsStr) + if err != nil { + fmt.Println(err) + } +} +``` + +这样我们只需要在模板文件不需要转义的内容后面使用我们定义好的safe函数就可以了。 + +```text +{{ . | safe }} +``` + +## 扩展Sprig + +> https://masterminds.github.io/sprig/ + +![1706326086228](image/模板语法GoTemplate/1706326086228.png) + +##  扩展Helm + +### required + +`required`方法允许开发者声明一个模板渲染需要的值。如果在 `values.yaml`中这个值是空的,模板就不会渲染并返回开发者提供的错误信息。 + +例如: + +```yaml +{{required "A valid foo is required!" .Values.foo }} +``` + +上述示例表示当 `.Values.foo`被定义时模板会被渲染,但是未定义时渲染会失败并退出。 + +### include + +go通过define和template实现嵌套模板,无法使用go的流水线。为使包含模板成为可能,然后对该模板的输出执行操作,Helm有一个特殊的 `include`方法: + +```yaml +{{include "toYaml" $value | indent 2 }} +``` + +上面这个包含的模板称为 `toYaml`,并将当前值 `$value`传递给被引入的模板,一般会传递全局变量".",然后将这个模板的输出传给 `indent`方法。 + +由于YAML将重要性归因于缩进级别和空白,使其在包含代码片段时变成了一种好方法。但是在相关的上下文中要处理缩进。 + +### tpl + +`tpl`方法允许开发者在模板中使用字符串作为模板。将模板字符串作为值传给chart或渲染额外的配置文件时会很有用。 语法: `{{ tpl TEMPLATE_STRING VALUES }}` + +示例: + +```yaml +# values +template:"{{ .Values.name }}" +name:"Tom" + +# template +{{tpl .Values.template . }} + +# output +Tom +``` + +渲染额外的配置文件: + +```yaml +# external configuration file conf/app.conf +firstName={{ .Values.firstName }} +lastName={{ .Values.lastName }} + +# values +firstName:Peter +lastName:Parker + +# template +{{tpl (.Files.Get "conf/app.conf") . }} + +# output +firstName=Peter +lastName=Parker +``` + +### lookup + +`lookup` 函数可以用于在运行的集群中 *查找* 资源。lookup函数简述为查找 `apiVersion, kind, namespace,name -> 资源或者资源列表`。 + +| parameter | type | +| ---------- | ------ | +| apiVersion | string | +| kind | string | +| namespace | string | +| name | string | + +| 命令 | Lookup 函数 | +| ---------------------------------------- | -------------------------------------------- | +| `kubectl get pod mypod -n mynamespace` | `lookup "v1" "Pod" "mynamespace" "mypod"` | +| `kubectl get pods -n mynamespace` | `lookup "v1" "Pod" "mynamespace" ""` | +| `kubectl get pods --all-namespaces` | `lookup "v1" "Pod" "" ""` | +| `kubectl get namespace mynamespace` | `lookup "v1" "Namespace" "" "mynamespace"` | +| `kubectl get namespaces` | `lookup "v1" "Namespace" "" ""` | + +当 `lookup`返回一个对象,它会返回一个字典。这个字典可以进一步被引导以获取特定值。 + +下面的例子将返回 `mynamespace`对象的annotations属性: + +```go +(lookup "v1" "Namespace" "" "mynamespace").metadata.annotations +``` diff --git a/kubenets/helm/03 Helm命令.md b/kubenets/helm/03 Helm命令.md new file mode 100644 index 00000000..7f674d4a --- /dev/null +++ b/kubenets/helm/03 Helm命令.md @@ -0,0 +1,25 @@ +## HelmChart命令 + + +创建一个新chart: + +```console +$ helm create mychart +Created mychart/ +``` + + +打包成一个chart存档: + +```console +$ helm package mychart +Archived mychart-0.1.-.tgz +``` + + +找到chart的格式或信息的问题: + +```console +$ helm lint mychart +No issues found +``` diff --git a/kubenets/helm/04 Chart构建.md b/kubenets/helm/04 Chart构建.md new file mode 100644 index 00000000..cd78c30d --- /dev/null +++ b/kubenets/helm/04 Chart构建.md @@ -0,0 +1,166 @@ +## 1 Values和templates + +### 定义values + +* `values.yaml` 的文件。这个文件包含了默认值。 +* 在命令行使用 `helm install`命令时提供。当用户提供自定义value时,这些value会覆盖chart的 `values.yaml`文件中value。Helm安装命令允许用户使用附加的YAML values覆盖这个values: + +```console +$ helm install --generate-name --values=myvals.yaml wordpress +``` + +### 子Chart的value值 + +``` +title: "My WordPress Site" # Sent to the WordPress template + +mysql: + max_connections: 100 # Sent to MySQL + password: "secret" + +apache: + port: 8080 # Passed to Apache +``` + +> 子chart不能访问父级chart,所以MySQL无法访问 `title`属性。同样也无法访问 `apache.port`。 + +支持特殊的"global"值,`.Values.global.app`在 *所有* chart中有效。 + +``` +title: "My WordPress Site" # Sent to the WordPress template + +global: + app: MyWordPress + +mysql: + max_connections: 100 # Sent to MySQL + password: "secret" + +apache: + port: 8080 # Passed to Apache +``` + +### DDL文件结构 + +``` +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "properties": { + "image": { + "description": "Container Image", + "properties": { + "repo": { + "type": "string" + }, + "tag": { + "type": "string" + } + }, + "type": "object" + }, + "name": { + "description": "Service name", + "type": "string" + }, + "port": { + "description": "Port", + "minimum": 0, + "type": "integer" + }, + "protocol": { + "type": "string" + } + }, + "required": [ + "protocol", + "port" + ], + "title": "Values", + "type": "object" +} +``` + +这个架构会应用values值并验证它。一个满足要求的yaml如下 + +``` +name: frontend +protocol: https +port: 443 +``` + +### 用户自定义资源CRD + +当Helm安装新chart时,会上传CRD,暂停安装直到CRD可以被API服务使用,然后启动模板引擎, 渲染chart其他部分,并上传到Kubernetes。 + +CRD YAML文件应被放置在chart的 `crds/`目录中。 多个CRD(用YAML的开始和结束符分隔)可以被放置在同一个文件中。Helm会尝试加载CRD目录中 *所有的* 文件到Kubernetes。 + +CRD 文件 *无法模板化* ,必须是普通的YAML文档。 + +CRD的生命周期: + +* CRD从不重新安装。 如果Helm确定 `crds/`目录中的CRD已经存在(忽略版本),Helm不会安装或升级。 +* CRD从不会在升级或回滚时安装。Helm只会在安装时创建CRD。 +* CRD从不会被删除。自动删除CRD会删除集群中所有命名空间中的所有CRD内容。因此Helm不会删除CRD + +### 渲染templates + + + +* `.Files` 对象引用父chart的文件路径,而不是库chart的本地路径 + +### 默认变量 + +* `Release.Name`: 版本名称(非chart的) +* `Release.Namespace`: 发布的chart版本的命名空间 +* `Release.Service`: 组织版本的服务 +* `Release.IsUpgrade`: 如果当前操作是升级或回滚,设置为true +* `Release.IsInstall`: 如果当前操作是安装,设置为true +* `Chart`: `Chart.yaml`的内容。因此,chart的版本可以从 `Chart.Version` 获得, 并且维护者在 `Chart.Maintainers`里。 +* `Files`: chart中的包含了非特殊文件的类图对象。这将不允许您访问模板, 但是可以访问现有的其他文件(除非被 `.helmignore`排除在外)。 使用 `{{ index .Files "file.name" }}`可以访问文件或者使用 `{{.Files.Get name }}`功能。 您也可以使用 `{{ .Files.GetBytes }}`作为 `[]byte`访问文件内容。 +* `Capabilities`: 包含了Kubernetes版本信息的类图对象。(`{{ .Capabilities.KubeVersion }}`) 和支持的Kubernetes API 版本(`{{ .Capabilities.APIVersions.Has "batch/v1" }}`) + +> 任何未知的 `Chart.yaml`字段会被抛弃。在 `Chart`对象中无法访问。因此, `Chart.yaml`不能用于将任意结构的数据传递到模板中。 + +## 1 技巧 + +### 自动滚动部署 + +当配置文件变更时,需要触发pod的滚动升级。执行helm update命令,如果只是configmap变化但是spec.template没有变化则不会触发pod的滚动升级。需要引入一个变量。 + +`sha256sum`方法保证在另一个文件发生更改时更新负载说明: + +```yaml +kind:Deployment +spec: + template: + metadata: + annotations: + checksum/config:{{include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} +[...] +``` + +这个场景下你通常想滚动更新你的负载,可以使用类似的说明步骤,而不是使用随机字符串替换,因而经常更改并导致负载滚动更新: + +```yaml +kind:Deployment +spec: + template: + metadata: + annotations: + rollme:{{randAlphaNum 5 | quote }} +[...] +``` + +每次调用模板方法会生成一个唯一的随机字符串。这意味着如果需要同步多种资源使用的随机字符串,所有的相对资源都要在同一个模板文件中。 + +### 保留资源 + +有时在执行 `helm uninstall`时有些资源不应该被卸载。Chart的开发者可以在资源中添加额外的说明避免被卸载。 + +```yaml +kind: Secret +metadata: + annotations: + "helm.sh/resource-policy": keep +[...] +``` diff --git a/kubenets/helm/05 Hook顺序.md b/kubenets/helm/05 Hook顺序.md new file mode 100644 index 00000000..6c07a50f --- /dev/null +++ b/kubenets/helm/05 Hook顺序.md @@ -0,0 +1,122 @@ +## 简介 + + +Helm 提供了一个 *hook* 机制允许chart开发者在发布生命周期的某些点进行干预。 + + +* 安装时在加载其他chart之前加载配置映射或密钥 +* 安装新chart之前执行备份数据库的任务,然后在升级之后执行第二个任务用于存储数据。 +* 在删除发布之前执行一个任务以便在删除服务之前退出滚动。 + +### 常用钩子 + + +| 注释值 | 描述 | +| ----------------- | ---------------------------------------------- | +| `pre-install` | 在模板渲染之后,Kubernetes资源创建之前执行 | +| `post-install` | 在所有资源加载到Kubernetes之后执行 | +| `pre-delete` | 在Kubernetes删除之前,执行删除请求 | +| `post-delete` | 在所有的版本资源删除之后执行删除请求 | +| `pre-upgrade` | 在模板渲染之后,资源更新之前执行一个升级请求 | +| `post-upgrade` | 所有资源升级之后执行一个升级请求 | +| `pre-rollback` | 在模板渲染之后,资源回滚之前,执行一个回滚请求 | +| `post-rollback` | 在所有资源被修改之后执行一个回滚请求 | +| `test` | 调用Helm test子命令时执行  | + + + +### 生命周期 + + +钩子允许你在发布生命周期的关键节点上有机会执行操作。比如,考虑 `helm install`的生命周期。默认的,生命周期看起来是这样: + +1. 用户执行 `helm install foo` +2. Helm库调用安装API +3. 在一些验证之后,库会渲染 `foo`模板 +4. 库会加载结果资源到Kubernetes +5. 库会返回发布对象(和其他数据)给客户端 +6. 客户端退出 + +Helm 为 `install`周期定义了两个钩子:`pre-install`和 `post-install`。如果 `foo` chart的开发者两个钩子都执行, 周期会被修改为这样: + +1. 用户返回 `helm install foo` +2. Helm库调用安装API +3. 在 `crds/`目录中的CRD会被安装 +4. 在一些验证之后,库会渲染 `foo`模板 +5. 库准备执行 `pre-install`钩子(将hook资源加载到Kubernetes中) +6. 库按照权重对钩子排序(默认将权重指定为0),然后在资源种类排序,最后按名称正序排列。 +7. 库先加载最小权重的钩子(从负到正) +8. 库会等到钩子是 "Ready"状态(CRD除外) +9. 库将生成的资源加载到Kubernetes中。注意如果设置了 `--wait`参数,库会等所有资源是ready状态, 且所有资源准备就绪后才会执行 `post-install`钩子。 +10. 库执行 `post-install`钩子(加载钩子资源)。 +11. 库会等到钩子是"Ready"状态 +12. 库会返回发布对象(和其他数据)给客户端 +13. 客户端退出 + + +### 最佳实践 + +存储在 `templates/post-install-job.yaml`,声明了一个要运行在 `post-install`上的任务: + +```yaml +apiVersion:batch/v1 +kind:Job +metadata: +name:"{{ .Release.Name }}" +labels: +app.kubernetes.io/managed-by:{{.Release.Service | quote }} +app.kubernetes.io/instance:{{.Release.Name | quote }} +app.kubernetes.io/version:{{.Chart.AppVersion }} +helm.sh/chart:"{{ .Chart.Name }}-{{ .Chart.Version }}" +annotations: +# This is what defines this resource as a hook. Without this line, the +# job is considered part of the release. +"helm.sh/hook": post-install +"helm.sh/hook-weight": "-5" +"helm.sh/hook-delete-policy": hook-succeeded +spec: +template: +metadata: +name:"{{ .Release.Name }}" +labels: +app.kubernetes.io/managed-by:{{.Release.Service | quote }} +app.kubernetes.io/instance:{{.Release.Name | quote }} +helm.sh/chart:"{{ .Chart.Name }}-{{ .Chart.Version }}" +spec: +restartPolicy:Never +containers: +- name:post-install-job +image:"alpine:3.3" +command:["/bin/sleep","{{ default "10" .Values.sleepyTime }}"] +``` + +声明钩子: + +```yaml +annotations: + "helm.sh/hook": post-install,,post-upgrade +``` + +当子chart声明钩子时,这些也会被评估。顶级chart无法禁用子chart声明的钩子。 + +可以为钩子定义权重,这有助于建立一个确定性的执行顺序。权重使用以下注释定义: + +```yaml +annotations: + "helm.sh/hook-weight": "5" +``` + +钩子无法进行版本管理。即执行完对应的钩子后,对应的资源应该被回收(删除掉),如果upgrade过程中钩子内容发生变化,就会执行最新的钩子内容。执行完成后,对应的资源也会被删除掉。可以定义策略来决定何时删除对应的钩子资源。钩子的删除策略使用以下注释定义: + +```yaml +annotations: +"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +``` + +| 注释值 | 描述 | +| ------------------------ | --------------------------------- | +| `before-hook-creation` | 新钩子启动前删除之前的资源 (默认) | +| `hook-succeeded` | 钩子成功执行之后删除资源 | +| `hook-failed` | 如果钩子执行失败,删除资源 | + +如果没有指定钩子删除策略的注释,默认使用 `before-hook-creation` diff --git a/kubenets/helm/06 Test测试.md b/kubenets/helm/06 Test测试.md new file mode 100644 index 00000000..468eaaf0 --- /dev/null +++ b/kubenets/helm/06 Test测试.md @@ -0,0 +1,12 @@ +### 测试 + + +**test** 在helm chart中放在 `templates/`目录,并且是一个指定了容器和给定命令的任务。如果测试通过,容器应该成功退出 (exit 0) 任务的定义必须包含helm测试钩子的注释:`helm.sh/hook: test`。 + +### 使用场景 + + +* 验证你values.yaml文件中的配置可以正确注入。 + * 确保你的用户名和密码是对的 + * 确保不正确的用户名和密码不会工作 +* 判断你的服务只启动的并且正确地负载均衡 diff --git a/kubenets/helm/07 Common模板.md b/kubenets/helm/07 Common模板.md new file mode 100644 index 00000000..5b794501 --- /dev/null +++ b/kubenets/helm/07 Common模板.md @@ -0,0 +1,59 @@ +## 使用 + + +为了能使用公共代码,我们需要添加一个 `common`依赖。在 `demo/Chart.yaml`文件最后啊添加以下内容: + +```yaml +dependencies: +- name:common +version:"^0.0.5" +repository:"https://charts.helm.sh/incubator/" +``` + + +使用辅助chart中的公共代码。首先编辑负载文件 `demo/templates/deployment.yaml`如下: + +```yaml +{{- template "common.deployment" (list . "demo.deployment") -}} +{{- define "demo.deployment" -}} +## Define overrides for your Deployment resource here, e.g. +apiVersion: apps/v1 +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "demo.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "demo.selectorLabels" . | nindent 8 }} + +{{- end -}} +``` + + + + + +`demo/templates/service.yaml`变成了下面这样: + +```yaml +{{- template "common.service" (list . "demo.service") -}} +{{- define "demo.service" -}} +## Define overrides for your Service resource here, e.g. +# metadata: +# labels: +# custom: label +# spec: +# ports: +# - port: 8080 +{{- end -}} +``` + + + + +* 模板文件的名称应该反映名称中的资源类型。比如:`foo-pod.yaml`, `bar-svc.yaml` +* yaml注释中的模板字符串仍然会被解析 +* 镜像使用固定版本或者范围版本。 +* define是全局的模板,需要给不同的模板添加命名空间 diff --git a/kubenets/helm/08 Template模板.md b/kubenets/helm/08 Template模板.md new file mode 100644 index 00000000..19da6ecc --- /dev/null +++ b/kubenets/helm/08 Template模板.md @@ -0,0 +1,115 @@ +## 内置对象 + +* `Release`: `Release`对象描述了版本发布本身。包含了以下对象: + * `Release.Name`: release名称 + * `Release.Namespace`: 版本中包含的命名空间(如果manifest没有覆盖的话) + * `Release.IsUpgrade`: 如果当前操作是升级或回滚的话,该值将被设置为 `true` + * `Release.IsInstall`: 如果当前操作是安装的话,该值将被设置为 `true` + * `Release.Revision`: 此次修订的版本号。安装时是1,每次升级或回滚都会自增 + * `Release.Service`: 该service用来渲染当前模板。Helm里始终 `Helm` +* `Values`: `Values`对象是从 `values.yaml`文件和用户提供的文件传进模板的。默认为空 +* `Chart`: `Chart.yaml`文件内容。 `Chart.yaml`里的所有数据在这里都可以可访问的。比如 `{{ .Chart.Name }}-{{ .Chart.Version }}` 会打印出 `mychart-0.1.0` + * 在 [Chart 指南](https://helm.sh/zh/docs/topics/charts#Chart-yaml-%e6%96%87%e4%bb%b6) 中列出了可获得属性 +* `Files`: 在chart中提供访问所有的非特殊文件的对象。你不能使用它访问 `Template`对象,只能访问其他文件。 请查看这个 [文件访问](https://helm.sh/zh/docs/chart_template_guide/accessing_files)部分了解更多信息 + * `Files.Get` 通过文件名获取文件的方法。 (`.Files.Getconfig.ini`) + * `Files.GetBytes` 用字节数组代替字符串获取文件内容的方法。 对图片之类的文件很有用 + * `Files.Glob` 用给定的shell glob模式匹配文件名返回文件列表的方法 + * `Files.Lines` 逐行读取文件内容的方法。迭代文件中每一行时很有用 + * `Files.AsSecrets` 使用Base 64编码字符串返回文件体的方法 + * `Files.AsConfig` 使用YAML格式返回文件体的方法 +* `Capabilities`: 提供关于Kubernetes集群支持功能的信息 + * `Capabilities.APIVersions` 是一个版本列表 + * `Capabilities.APIVersions.Has $version` 说明集群中的版本 (比如,`batch/v1`) 或是资源 (比如, `apps/v1/Deployment`) 是否可用 + * `Capabilities.KubeVersion` 和 `Capabilities.KubeVersion.Version` 是Kubernetes的版本号 + * `Capabilities.KubeVersion.Major` Kubernetes的主版本 + * `Capabilities.KubeVersion.Minor` Kubernetes的次版本 + * `Capabilities.HelmVersion` 包含Helm版本详细信息的对象,和 `helm version` 的输出一致 + * `Capabilities.HelmVersion.Version` 是当前Helm语义格式的版本 + * `Capabilities.HelmVersion.GitCommit` Helm的git sha1值 + * `Capabilities.HelmVersion.GitTreeState` 是Helm git树的状态 + * `Capabilities.HelmVersion.GoVersion` 是使用的Go编译器版本 +* `Template`: 包含当前被执行的当前模板信息 + * `Template.Name`: 当前模板的命名空间文件路径 (e.g. `mychart/templates/mytemplate.yaml`) + * `Template.BasePath`: 当前chart模板目录的路径 (e.g. `mychart/templates`) + +## Values文件 + +其内容来自于多个位置: + +* chart中的 `values.yaml`文件 +* 如果是子chart,就是父chart中的 `values.yaml`文件 +* 使用 `-f`参数(`helm install -f myvals.yaml ./mychart`)传递到 `helm install` 或 `helm upgrade`的values文件 +* 使用 `--set` (比如 `helm install --set foo=bar ./mychart`)传递的单个参数 + +## 流程控制 + +控制结构(在模板语言中称为"actions")提供给你和模板作者控制模板迭代流的能力。 Helm的模板语言提供了以下控制结构: + +* `if`/`else`, 用来创建条件语句 +* `with`, 用来指定范围 +* `range`, 提供"for each"类型的循环 + +除了这些之外,还提供了一些声明和使用命名模板的关键字: + +* `define` 在模板中声明一个新的命名模板 +* `template` 导入一个命名模板 +* `block` 声明一种特殊的可填充的模板块 + +控制结构(在模板语言中称为"actions")提供给你和模板作者控制模板迭代流的能力。 Helm的模板语言提供了以下控制结构: + +* `if`/`else`, 用来创建条件语句 +* `with`, 用来指定范围 +* `range`, 提供"for each"类型的循环 + +除了这些之外,还提供了一些声明和使用命名模板的关键字: + +* `define` 在模板中声明一个新的命名模板 +* `template` 导入一个命名模板 +* `block` 声明一种特殊的可填充的模板块 + +如果是以下值时,管道会被设置为 *false* : + +* 布尔false +* 数字0 +* 空字符串 +* `nil` (空或null) +* 空集合(`map`, `slice`, `tuple`, `dict`, `array`) + +## 最佳实践 + +### Key-Value + +在java中配置文件可能需要从嵌套的yaml格式转换为扁平的properties格式。以下是在Heml场景下最常用的集中方式 + +1. value.yaml中使用yaml的嵌套格式。configmap中重写key,value引入对应的键值对 + +``` +a: + b: + c: + + +{{ .Values.a.b.c }} +``` + +1. values.yaml中使用扁平格式、configmap中作为环境变量引入扁平格式。 + +``` +configmap: + a.b.c: abc + d.e.f: def + +{{ with .Values.configmap }} +. +{{end}} + +``` + +1. values中使用扁平格式、configmap作为字符串引入震哥key=value。并将整个字符串作为configmap volumn挂载到容器中。 + +``` + custom.properties: | + {{- range $key, $value := .Values.customProperties }} + {{ $key }}={{ $value }} + {{- end }} +``` diff --git a/kubenets/helm/image/模板语法GoTemplate/1706326086228.png b/kubenets/helm/image/模板语法GoTemplate/1706326086228.png new file mode 100644 index 00000000..4fc04012 Binary files /dev/null and b/kubenets/helm/image/模板语法GoTemplate/1706326086228.png differ