Ciel's blog

Hi, this is Ciel!

参考文档

externalTrafficPolicy - Technotes (adelerhof.eu)
Configure kubenet networking in Azure Kubernetes Service (AKS) - Azure Kubernetes Service | Microsoft Learn

环境背景及问题现象

  • AKS集群使用kubenetes网络插件
  • 服务通过Internal LB暴露
  • 通过clusterIP访问服务正常,但通过Internal LB IP访问时出现大概率失败小概率成功的情况

排查分析

  • 首先检查ILB的探测情况,探测存在部分失败的情况。

  • 检查健康探测配置规则,由于AKS的LB为AKS托管,规则都是自动配置的;查看LB探测规则为以TCP方式探测NodePort的高位端口;以此推测s集群中service使用的是externalTrafficPolicy: Cluster的流量分发模式。

  • 在此模式下,探测流量被Node接收后会跟进iptables规则平均分发给不同节点上的实际业务pod进行响应。Node在做转发时,会进行SNAT。如果node到pod的通信有问题,则会导致仅有分发到同一节点上的Pod的探测成功,跨节点的探测不成功。

    alt text
    图片来源

  • 进一步检查集群NSG配置,发现Node与Pod之间的流量未放通。

    Configure kubenet networking in Azure Kubernetes Service (AKS) - Azure Kubernetes Service | Microsoft Learn
    alt text

解决方案

调整放通node与pod之间的流量后访问正常。

知识点延申

  1. 当service的externalTrafficPolicy的配置不同时,LB的探测有如下不同的行为:

    • 当externalTrafficPolicy设置为cluster时(default),LB使用的TCP探测模式,且请求会由后端实际的业务pod响应。此模式下,集群中所有的节点都会接收流量,当该节点没有部署对应的service pod时,请求将由该节点转发给部署了service pod的节点上,同时源IP地址被替换为节点的IP地址。

    • 当externalTrafficPolicy设置为local时, LB对后端应用(探测方式为http/https,探测路径为/healthz)的探测流量由节点上对应kube proxy的node port端口处理,不再由后端的应用来处理。当服务的Pod没有分布在所有节点上时,探测请求到达没有pod的节点上,会拿到503的返回,此时metrics可能会显示部分不健康,属于预期现象。
      alt text

  2. 如果同时设置了externalTrafficPolicy: local以及以下annotation,externalTrafficPolicy配置的优先级更高,LB的探测方式依然会是HTTP(s)。

    1
    2
    3
    annotation:
    service.beta.kubernetes.io/port_443_health-probe_protocol: "tcp"
    service.beta.kubernetes.io/port_80_health-probe_protocol: "tcp"

关于WAF 拦截排查的官方指导doc请见: Troubleshoot - Azure Web Application Firewall | Microsoft Learn

查找LogA日志

LogA sample 可参考: Examining logs using Azure Log Analytics - Azure Application Gateway | Microsoft Learn

  • 可以先根据URI以及**action_s == “blocked”**过滤出被block的请求;
  • 针对某一请求,过滤transaction ID,即可找到这个请求匹配了哪些WAF 规则,rule 949110 代表改请求被block。

判断分析

  • 如果请求被customer rule拦截,需要进一步检查custom rule是否符合预期;
  • 如果请求被托管规则拦截,可以从拦截日志中找到匹配的正则表达式,或者从coreruleset官方找到对应的正则表达式(注意对应的规则版本);
  • 通过在线工具,比如regex101: build, test, and debug regex,可以进一步判断匹配情况。

举例如下匹配情况:

注:==ARGS==表示是key:vlue pair里的value的内容匹配上了;如果看到==ARGS_NAMES==,则表示是key:vlue pair里的key的名称匹配上了。==REQUEST_COOKIES==则代表cokkie的内容匹配上了。

关于WAF匿名积分模式

What is Azure Web Application Firewall on Azure Application Gateway? - Azure Web Application Firewall | Microsoft Learn

There’s a threshold of 5 for the Anomaly Score to block traffic.

Severity Value
Critical 5
Error 4
Warning 3
Notice 2
check setvar:’tx.inbound_anomaly_score_pl2=+%{tx.==critical==_anomaly_score}’”

常见拦截解决方案

请先确认被block的内容在业务上是否是预期的,或是否可以避免,如果确实需要bypass拦截。针对不同的匹配场景,一般有以下bypass的方式,可以根据实际业务情况选用具体方案:

  1. Exclusion: 针对特定的Header/cookie/args的名称或内容,允许WAF不进行特定OWASP rule的检查;【Recommended】
Matching variable的三种类型:Web application firewall exclusion lists in Azure Application Gateway - Azure portal | Microsoft Learn

文档中的举例: My-Header: 1=1
1. Name (与Value意义等同,推荐使用Value)
如果是想要不检查值的内容“1=1”,请使用 RequestHeaderValues 匹配变量、运算符 contains 和选择器 (My-Header)。
2. Key
如果是想要不检查键的内容“My-Header”,可以使用 RequestHeaderKeys 请求属性为标头键配置排除项。
3. Value (与Name意义等同,推荐使用Value)

  1. custom rule: 将满足条件(如匹配uri)的请求放行;
  2. disable specific OWASP rule (by listener / path-based rule WAF policy): disable rule具有全局效果,但也可以通过配置by listener / path-based rule 的WAF policy实现更精细粒度的控制。

git是一个分布式版本控制系统,不同类型的版本控制软件还有svn,mercurial,vss,SourceAnywhere等。 而Github是一个集成了git的服务。

不管是使用Github,Coding还是Gitlab,我们都需要熟悉Git这一版本管理工具。本文简单介绍Git的工作原理,并总结了一些常用的git指令,冲突解决等,以便自己查看。

基本介绍

(图片均来自网络)

image-20230810010331314

从上图可以看出git的组成和基本指令。git在本地的包括工作区,暂存区,以及本地仓库,stash。远端仓库就是Github,Coding,Gitlab等工具。

Git的存储方式

因为每一个版本之间可能有重叠,为了节省空间,git不是将每一个独立存放,而是以快照的形式存放。如下图所示:

Git分支

一般有两类分支:

  • Merge分支(通常为master分支):Merge分支是为了可以随时发布release而创建的分支,可以使用Jenkins之类的CI工具进行自动化编译以及测试。
  • Topic分支:用来进行功能开发的

HEAD指向的是现在使用中的分支的最后一次更新。通常默认指向master分支的最后一次更新。通过移动HEAD,就可以变更使用的分支。

我们经常需要根据一个提交去查找它的祖先提交,如查找 HEAD 的第三个祖先提交。 这时就可以用到Git 中的 ~^,其具体用法见文章

  • Git中~^的区别?

    在git中,我们其实可以通过^和~来定位某个具体的commit,而不用每次都去敲繁琐的hash值。

    • ^代表父提交,当一个提交有多个父提交时,可以通过在^后面跟上一个数字,表示第几个父提交,^相当于^1.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      $ git log --graph --oneline

      * f44239d D
      * 7a3fb3d C
      |\
      | * 07b920c B
      |/
      * 71bd2cf A
      ...

      这时候,我们是不能通过 ~ 去找到 07b920c (B) 这个提交的。 如果一个提交有多个父提交,那么 ~ 只会找第一个父提交。 那么我们应该怎么找到 07b920c (B) 呢? 答案是:HEAD~^2

      <rev>^<n> 用来表示一个提交的第 n 个父提交,如果不指定 n,那么默认为 1。 和 ~ 不同的是,HEAD^^^ 并不等价于 HEAD^3,而是等价与HEAD^1^1^1

    • ~<n>相当于连续的<n>^.

    • (<commit>|HEAD)~n = (<commit>|HEAD)^^^…(^的个数为n)

分支规范

git上的分支命名规范

A successful Git branching model:

分支合并

在 git 中合并分支有两种选择:merge 和 rebase。

merge

  • fast-forward:

  • non fast-forward:

rebase

4 以补丁的形式打到 3 上,形成了新的提交 4’。

rebase类似于打补丁。rebase的时候,修改冲突后的提交不是使用commit命令,而是执行rebase命令指定 –continue选项。若要取消rebase,指定 –abort选项。

但是,无论哪一种,都有可能产生冲突。

两种方法区别:

  • merge
    保持修改内容的历史记录,但是历史记录会很复杂。
  • rebase
    历史记录简单,是在原有提交的基础上将差异内容反映进去。
    因此,可能导致原本的提交内容无法正常运行。

Git合并及冲突解决

冲突发生一般由于对同一个文件的修改不一致时。当有冲突发生时,一般需要手动合并冲突(也可以借助软件,如smartgit)。冲突标示一般为:

1
2
3
4
5
<<<<<<<HEAD
本地仓库内容
=======
远程仓库内容
>>>>>>>

手动合并后需要并删除标示行。

可能发生冲突的情况时:

  • 本地拉取 git pull = git fetch + git merge

    1. 当远端有更新,本地库没有有变化,拉取操作远端会覆盖本地库(远端版本高于本地)
    2. 当远端修改,本地库也有修改,拉取操作会产生冲突文件(远端版本和本地版本冲突)
    3. 当本地库修改,而远端没有变化,拉取不会产生变化(本地版本高于远端版本)
    4. 当本地库版本低于远端版本,则无法推送,必须先拉取在操作,否则报错
  • 远程推送

    1. 首先,可以试图用git push origin branch-name推送自己的修改;
    2. 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令git branch –set-upstream branch-name origin/branch-name。
    3. 如果合并有冲突,则解决冲突,并在本地提交;
    4. 没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功!
  • 分支合并

    1. 当资源分支版本高于目标分支时,合并,资源分支同名文件会覆盖目标分支;
    2. 当目标分支版本高于资源分支时,合并,提示Already up-to-date.(已经更新),目标分支内容不会变化;

Git常用指令

此处总结一些常用的Git指令,一以便查用。

初始

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 第一次安裝git之後,先設定自己的名字與信箱,因為Git用名字與信箱來分辨貢獻者
git config --global user.name "First Last"
git config --global user.email "user@example.com"

# 初始化,使當前目錄成為git目錄
git init
# 加上專案的說明文件(非必要)
touch README.md
# 加入暫存區
git add README.md
# 提交到本地容器
git commit -m "initial commit"

# 將本地的repository上傳到遠端(如github)的repository
# 將遠端容器命名為origin
git remote add origin <URL>
# 從本地端的master branch上傳到origin的master branch
git push -u origin master

# 从远端仓库克隆到本地
git clone <URL>

远端数据库操作

1
2
3
4
5
git pull
# 取得远程数据库的最新历史记录。取得的提交会导入到没有名字的分支,这个分支可以从名为FETCH_HEAD的退出。
git fetch
git push
git clone <URL>

Git记录查看

1
2
3
# 显示git flow
# 指定--graph选项,能以文本形式显示更新记录的流程图。指定--oneline选项,能在一行中显示提交的信息。
$ git log --graph --oneline

Git分支(branch)

1
2
3
4
5
6
7
8
9
10
11
12
13
git branch # 列出本地分支(前方有星號的為目前所在分支)
git branch -r # 列出遠端分支
git branch -a # 列出所有分支(本地+遠端)
git show-branch # 列出本地分支所包含的(有差異的)commit
git branch [branchname] [commit] # 在指定commit上建立分支
git branch -d [branchname] # 刪除指定分支
git branch -m [old-name] [new-name] # 重新命名分支
git branch [new-branch] [old-branch] # 由old-branch複製出新分支

git checkout [branch] # 切換到指定分支
git checkout [commit] # 也可以切換到任何commit
# 若commit不在任何branch上,用 git branch 查看時,會顯示 (no branch)
git checkout -b [new-branch] # 建立並切換到該分支(從目前分支複製)

stash

还未提交的修改内容以及新添加的文件,留在索引区域或工作树的情况下切换到其他的分支时,修改内容会从原来的分支移动到目标分支。

但是如果在checkout的目标分支中相同的文件也有修改,checkout会失败的。这时要么先提交修改内容,要么用stash暂时保存修改内容后再checkout。

stash是临时保存文件修改内容的区域。stash可以暂时保存工作树和索引里还没提交的修改内容,您可以事后再取出暂存的修改,应用到原先的分支或其他的分支上。

使用時機:

  1. 你不得不修改一個緊急Bug,你可以先把目前工作目錄的變更丟到stash,這時候你的工作目錄和上次剛提交內容的狀況一樣,等到修完Bug後再把stash中剛剛做到一半的東西還原以繼續
  2. 今天的工作時間結束後,還有未完成的部分
  3. pull到一個不乾淨的樹而不用merge
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
git stash                # 將目前把目前工作區的修改丟到stash裡
git stash save [message] # 將目前把目前工作區的修改丟到stash裡
git stash pop # 取出最新放入的一筆修改,並從stash中移除(若有衝突時會保留)
git stash apply # 將最新投入的一筆修改套用在工作目錄上
git stash drop # 從stash中移除最新的一筆修改
git stash show [stashName] # 列出某一筆stash的修改內容
# 命名:最新的為 stash@{0}, 以此類推
git stash show -p [stashName] # 列出某一筆stash的詳細變更
# 命名:最新的為 stash@{0}, 以此類推
git stash list # 列出所有在stash的修改
git stash [file] # 將檔案丟進stash
git stash clear # 清空stash
git stash branch [branchName] # 用最新一筆stash新增branch
git stash -p # 挑選要暫存的修改
git stash --includev # 同時暫存尚未在版本控制中的檔案(也就是從來沒被add過的檔案)

Git合併(merge)

1
2
3
4
git merge [branch/commit] 
# 將指定的版本合併到目前所在的分支
# 也就是說,只有目前的分支會被影響!
# 该命令将指定分支导入到HEAD指定的分支。

產生衝突時:先用git diff/status查看,修改后再提交

Git比較

1
2
3
4
5
6
7
8
9
git diff [commit] # 比較指定版本和當前目錄的差別(不包含staging area)(預設為HEAD)
git diff # 比較目前版本與工作目錄的不同([commit]=HEAD)
git diff --cached/--staged [commit] # 比較暫存區(staging area)與指定版本(預設是HEAD)的不同
git diff [commit] [commit] # 比較兩個版本的差別
git diff [...] [filename] # 比較特定檔案差異
git diff -S[string] # 只列出變更中,有包含string字串的差異
git diff --stat # 差異資訊(只顯示檔名和行數)
git diff -w # 不將空白視為變更
git diff [version1]:[file1] [version2]:[file2] # 比較兩個版本的指定檔案

Git标签

Git可以使用2种标签:轻标签和注解标签。打上的标签是固定的,不能像分支那样可以移动位置。

  • 轻标签
    • 添加名称
  • 注解标签
    • 添加名称
    • 添加注解
    • 添加签名

一般情况下,发布标签是采用注解标签来添加注解或签名的。轻标签是为了在本地暂时使用或一次性使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 添加轻标签
$ git tag <tagname>
# 显示标签列表
$ git tag
# 显示包含标签资料的历史记录
$ git log --decorate

# 添加注解标签
$ git tag -a <tagname>
# 显示标签的列表和注解
$ git tag -n

# 删除标签
$ git tag -d <tagname>

改写提交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# e.g.
$ git reset HEAD^ # 回退所有内容到上一个版本
$ git reset HEAD^ hello.php # 回退 hello.php 文件的版本到上一个版本
$ git reset 052e # 回退到指定版本

# 修改最近的提交
$ git commit --amend
# 取消过去的提交(否定而非删除)
$ git revert HEAD
# 遗弃提交(删除)
$ git reset --hard HEAD~~
# 还原到resset之前的状态
$ git reset --hard ORIG_HEAD
# 提取提交:从其他分支复制指定的提交,然后导入到现在的分支。
$ git cherry-pick [commit]

# 汇合提交:两个提交就合并成一个提交
$ git rebase -i HEAD~~
# 指令会打开文本编辑器,将第二行的“pick”改成“squash”,然后保存并退出。然后执行:
$ git commit --amend
$ git rebase --continue

# 把分支上的所有提交都汇合到master上
$ git checkout master
$ git merge --squash [branchName]

模式说明:

模式名称 HEAD的位置 索引 工作树
soft 修改 不修改 不修改
mixed 修改 修改 不修改
hard 修改 修改 修改

git reset –hard 操作后的数据恢复

第三方平台使用

添加SSH Key到远端服务器

  1. 打开terminal,输入命令ls -al ~/.ssh,检查是否显示有id_rsa.pub或者id_dsa.pub存在,如果存在请直接跳至第3步。
  2. 在bash中输入ssh-keygen -t rsa -C ”yourEmail@example.com
  3. 打开id_rsa.pub文件,并且复制全部内容
  4. 打开第三方平台账户,添加SSH Keys

就此,就可以使用ssh链接免密码上传本地仓库到远端仓库,或反之。

使用pycharm开发代码上传到GitLab和GitHub

References

浅析 Git 思想和工作原理

图解Git

Git常用指令

使用原理视角看 Git

GitLab 多人协同合作开发流程

Git &Gitlab协同流程

猴子都能懂的git入门(讲得蛮清晰也很完整的一个教程)

0%