#501 Git 分支管理策略(工作流)

2021-04-07

Git Logo

Git Flow

荷兰程序员 Vincent Driessen 2010 年提出。

Git Flow
PDF 下载

  • master 主干
  • develop 开发分支
  • feature/xxx 功能开发分支(临时)
    基于 develop 创建,开发完成之后:合并到 develop 分支,删除
  • release/xxx 预发布分支(临时)
    基于 develop 创建,测试通过之后:合并到 master 分支,打 tag,合并到 develop 分支,删除
  • hotfix/xxx 问题修复分支(临时)
    基于 master 创建,问题修复之后:合并到 master 分支,打 tag,合并到 develop 分支,删除

特点:基于版本交付

PS: 作者于 10 年后,也就是 2020 年,更新了一次,表示:对于互联网应用的开发应该考虑更加简单的工作流,比如 GitHub Flow。但不管怎样,应该结合自身的实际情况,不能盲目照搬。

GitHub Flow

GitHub Flow

  1. 从 master 拉分支,提交,推送
  2. pull request
  3. 评审,测试
  4. merge 到 master

特点:基本不涉及项目的分支管理,主要是对多人协作方式提出建议:Pull Request。适合多人参与的开源项目,由项目管理员负责维护主干。

中间可以借助自动化工具来静态分析、部署、测试,提升开发速度。但这些工具不是 GitHub Flow 专有,或者说不是它的特色。

这套逻辑看似非常简单,但要硬套到企业项目开发流程中可能会非常复杂,水土不服。
PS: 虽然 git 新增了一个 request-pull 子命令,但可能很鸡肋,不可能脱离 Web 来参与讨论、评审代码。

GitLab Flow

GitLab Flow

分不同环境:

  • master 开发分支,管理方式就是 GitHub Flow,不过就是 Pull Request 改名为了 Merge Request
  • pre-production 预发布分支,只能从 master 合并
  • production 发布分支,只能从 pre-production 合并

如果需要发布:

  1. 从 master 拉分支,比如:20-04-stable,创建语义化版本号。
  2. 如果后期有严重 BUG,可以从 master cherry-pick 过来。

特点:比 GitHub Flow 更进一步,对项目的发布和部署提出了建议,并支持多个环境。

主要是其中有一点特别好的就是: Upstream First, 上游优先。所有环境以及维护分支的提交必须来自 master 分支。

我的思考

当然,还是那句老话:适合自己的就是最好的。
项目分支管理流程要和项目自身的特点,以及团队成员的技术水平相匹配。

Git Flow 的整套流程挺完备的,符合一般开发的习惯,只是对其作出规范而已。
GitHub Flow 也好,GitLab Flow 也好,都可以看做是 Git Flow 的补充。

GitHub Flow 和 GitLab Flow 都假定 master 分支是可发布的,而 Git Flow 从 master 拆分出了一个 develop 作为缓冲,我认为这个设计比较合理。

Git Flow 有几个需要注意的问题:

  1. 合并的时候保留之前的合并记录,谨慎快进 (--no-ff)
  2. hotfix, release 分支推送到 master 发布之后,切记还要同步推送到 develop 分支
  3. 必须坚持 master, develop 上不随意推送(还是得靠 Pull Request 机制)
  4. 如果有不属于当前发布周期需要的开发,不要合并到 develop
  5. 临时分支必须快用快销,不要长时间保留,且合并之后理解删除

我设想中的开发流程

1,基本参照 Git Flow (借助工具)

上游优先原则:master 分支作为所有可发布环境的上游

2,自动化测试:

  • develop, release, master: 只要有变更就触发一次自动化测试
  • 此外, master 应该保持一定频率的定时自动化测试

3,老版本需要维护就在 tag 上拉分支。

现实场景中,可能要为 abc 环境上的某个老版本 v1.0.0 修复 BUG、加功能,或对已有功能进行一些调整。

git branch maintain/abc v1.0.0 # 一旦分叉,就需要长期保留该分支
# maintain/abc/develop
# maintain/abc/feature/xxx
# maintain/abc/hotfix/xxx
# maintain/abc/release/xxx
# 视情况,可以简化处理,不用上面这些分支

PS: 最后需要重新发布的时候可以对版本号加上附加的标识 v1.0.0.1.abc

5,如果是 OEM,针对客户有关的信息、资源应该留给打包系统来统一处理

此外:

  1. 项目应有明确的 roadmap
  2. 代码评审
  3. 数据库设计统一管理
  4. 项目文档,需求库,用例库
  5. 版本号基本上遵循语义化版本规范
  6. 提交记录遵循 git commit message 规范 (借助工具)
  7. CI/CD + 自动化测试

参考资料与拓展阅读

#500 iptables (2): 基本操作

2021-04-04

命令参数

iptables -[ACD] chain rule-specification [options]
iptables -I chain [rulenum] rule-specification [options]
iptables -R chain rulenum rule-specification [options]
iptables -D chain rulenum [options]
iptables -[LS] [chain [rulenum]] [options]
iptables -[FZ] [chain] [options]
iptables -[NX] chain
iptables -E old-chain-name new-chain-name
iptables -P chain target [options]

链相关

  • --new -N [chain] 链:创建
  • --delete-chain -X [chain] 链:删除
  • --rename-chain -E old-chain new-chain 链:更名
  • --list -L [chain [rulenum]] 列出指定链或所有链中的所有规则(表格形式)
  • --list-rules -S [chain [rulenum]] 同上,不过是按照规则定义的格式列出 很好用
  • --flush -F [chain] 清空规则
  • --zero -Z [chain [rulenum]] 计数器清零(数据包计数器,流量计数器)
  • --policy -P chain target 修改策略

规则相关

  • --append -A chain rule-specification 附加规则
  • --check -C chain rule-specification 检查规则是否存在
  • --delete -D chain rule-specification 删除匹配规则
  • --delete -D chain rulenum 删除 指定序号的 规则
  • --insert -I chain [rulenum] 插入到指定位置(默认插入到第一个)
  • --replace -R chain rulenum 替换 指定序号的 规则

规则说明

常用命令

查看

sudo iptables -S
sudo iptables -t nat -S POSTROUTING

sudo iptables -nL
sudo iptables -nL INPUT

sudo iptables -nL --line-numbers

sudo iptables -Z
sudo iptables -Z INPUT
sudo iptables -Z INPUT 1

# 如果是这么定义的话:
#             -A INPUT -m conntrack --ctstate INVALID -j DROP
sudo iptables -D INPUT -m conntrack --ctstate INVALID -j DROP
sudo iptables -D INPUT 3

访问拦截

# 对指定端口放行
sudo iptables -I INPUT -p tcp --dport 1022 -j ACCEPT

# 禁止来自无线网络的流量访问某端口(突发奇想的一个小例子)
sudo iptables -A PREROUTINE -i wlp6s0 --dport 22 -j DROP

NAT

iptables -t nat -A POSTROUTING -d 192.168.0.102 -j SNAT --to 192.168.0.1
iptables -t nat -A PREROUTING -d 202.202.202.2 -j DNAT --to-destination 192.168.0.102
iptables -t nat -D PREROUTING -p tcp --dport 8080 -i eth2.2 -j REDIRECT --to 80

对指定流量打标记

内核可以给这个包加上一个标记(可能存在包的数据结构中,总之,只对本地环境有效),可以实现流量的统计、限制等其他复杂的控制。

标记值最大可以到 2^32

iptables -t mangle -A PREROUTING -s 192.168.1.3 -j MARK --set-mark 60
iptables -t mangle -A PREROUTING -p tcp --dport 22 -j MARK --set-mark 2

//打标记
iptables -t mangle -A PREROUTING -j MARK --set-mark 33
//匹配标记
iptables -t nat -A PREROUTING -m mark --mark 33  -j ACCEPT
//or-mark
iptables -t mangle -A PREROUTING -j MARK --or-mark 0x400
//掩码匹配
iptables -t nat -A PREROUTING -m mark --mark 0x400/0x400  -j ACCEPT

iptables -t mangle -A INPUT -m state --state NEW -j MARK --set-mark 1
iptables -t mangle -A INPUT -j CONNMARK --save-mark
iptables -t mangle -A INPUT -j CONNMARK --restore-mark

iptables -t mangle -A PREROUTING -mttl --ttl-eq 64 -j MARK --set-mark 10
iptables -t mangle -A PREROUTING -mttl --ttl-eq 123 -j MARK --set-mark 20
iptables -t filter -A FORWARD -m mark--mark 10 -j ACCEPT
iptables -t filter -A FORWARD -m mark--mark 20 -j DROP

iptables -t mangle -A QOS_MARK_FORWARD_eth1 -j CONNMARK --restore-mark --nfmask 0xfffff --ctmask 0xfffff
iptables -t mangle -A QOS_MARK_FORWARD_eth1 -m mark --mark 0x0/0xfffff -j QOS_RULES_FORWARD_eth1
iptables -t mangle -A QOS_RULES_FORWARD_eth1 -j CONNMARK --save-mark --nfmask 0xfffff --ctmask 0xfffff

iptables -t mangle -A POSTROUTING -m iprange --src-range 192.168.0.2-192.168.0.200 -j MARK --or-mark 0x1

-m mark
-m connmark
-j MARK
-j CONNMARK
-j CONNSECMARK
-j SECMARK

  • --set-mark value 设置nfmark值
  • --and-mark value nfmark与value与运算
  • --or-mark value nfmark与value或运算

匹配

  • [!] --mark value[/mask]
iptables -t mangle -A INPUT -m mark --mark 1

限速

思路:hashlimit 模块

屏蔽指定网站

利用 string 模块 (xt_string.ko) 做域名匹配:

sudo iptables -A OUTPUT -m string --string baidu.com --algo bm -j LOG --log-prefix "iptables-test:blocked:baidu.com: "
sudo iptables -A OUTPUT -m string --string baidu.com --algo bm -j DROP
sudo iptables -vnL
curl https://www.baidu.com/
tail -f /var/log/syslog | grep "iptables-test"
sudo iptables -F OUTPUT

sudo iptables -A FORWARD -m string --string baidu.com --algo bm -j LOG --log-prefix "iptables-test:blocked:baidu.com: "
sudo iptables -A FORWARD -m string --string baidu.com --algo bm -j DROP

HTTPS 居然也可以生效,其原理我还不清楚,到底是匹配到了包的哪一部分包含了 baidu.com 呢?

提示:

  1. 这个规则也可以放到 INPUT 链上。
  2. 如果加上 -p tcp –dport 80 可能更加精确,免得别的什么包里面包含了 baidu.com 被拦截。
  3. 可以加多个 string 参数。

如果是 HTTP 的话,在我的理解范围之内,可以做到更细致的匹配,比如匹配到路径,甚至 Cookie。

string match options:
--from                       Offset to start searching from
--to                         Offset to stop searching
--algo                       Algorithm
--icase                      Ignore case (default: 0)
[!] --string string          Match a string in a packet
[!] --hex-string string      Match a hex string in a packet

algo 的选项:bm, kmp,参考 man iptables-extensions

参考资料与拓展阅读

#499 iptables (1): 基础知识

2021-04-03

iptables 的历史变更,发展趋势,和其他技术的关联我也曾花了不少时间去了解,可以说还是很不全面,就不献丑了(或者以后再来说说)。

这里就单单讲一下 iptables。

基本思想

在网络数据传输过程中有几个关键点埋上钩子,每个钩子上绑定了一个规则链(CHAIN)。
我们在这些链上注册一些处理规则(RULE),也就是 条件操作
网络包走到埋点的地方时,内核会逐个规则检查,如果符合条件就会执行预定操作。

此外:

  1. 这些处理规则按照不同类型,分成了五类,存在五张不同的表中。
  2. 每个规则链可以设置一个预定的操作(文档中称之为:策略 Policy)。

五个点

  • PREROUTING 路由:内核收到网络包之后,判断该包是否是自己的,应该给哪个程序
  • INPUT 用户程序收到包之前(内核判断是自己的包之后,传输到用户程序)
  • OUTPUT 程序往外发包
  • FORWARD 这个包不是自己的,然后需要中转出去
  • POSTROUTING 路由:系统判断该包应该怎么发出

PS:可以自定义新的链,然后再别的链中引用。我所处理的任务都没有到需要创建新链的地步,所以没有接触过。

五张表

应该说是五个功能。

  • filter 过滤,即判断这个包。默认
  • nat 地址转换
  • mangle 数据包修改,日常网络管理应该不会用到
  • raw 数据包修改(在内核处理之前)
  • security unknown

操作类型

  • ACCEPT 放行
  • DROP 拦截
  • REJECT 拦截,但是告知对方
  • MARK 加标记

NAT

  • SNAT 源地址转换
  • DNAT 目的地址转换
  • REDIRECT 端口转换

参考资料与拓展阅读

#498 Golang: possible resource leak,'defer' is called in the 'for' loop

2021-04-01

类似代码:

for _, f := range files {
    fp, err := os.Open(f)
    if err != nil {
        panic(err)
    }
    defer fp.Close()
    // do something
}

Goland 提示:possible resource leak,'defer' is called in the 'for' loop

defer 是在最后函数退出时执行,但是变量已经经过循环覆盖,可能会导致内存泄漏。
似乎 Golang 的 defer 还是不够聪明。

换种写法:

for _, f := range files {
    func () {
        fp, err := os.Open(f)
        if err != nil {
            panic(err)
        }
        defer fp.Close()
        // do something
    }()
}

#497 Golang ORM 框架

2021-03-30
  • GORM
  • ent
  • Xorm 转到Gitea
  • Bun
  • Reform
  • GoRose

GitHub 搜索结果

  1. go-gorm/gorm shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    The fantastic ORM library for Golang, aims to be developer friendly
  2. ent/ent shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    An entity framework for Go
  3. geektutu/7days-golang shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    7 days golang programs from scratch (web framework Gee, distributed cache GeeCache, object relational mapping ORM framework GeeORM, rpc framework GeeRPC etc) 7 天用 Go 动手写/从零实现系列
  4. gogf/gf shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    GoFrame is a modular, powerful, high-performance and enterprise-class application development framework of Golang.
  5. sqlc-dev/sqlc shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    Generate type-safe code from SQL
  6. go-xorm/xorm shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    Simple and Powerful ORM for Go, support mysql,postgres,tidb,sqlite3,mssql,oracle, Moved to https://gitea.com/xorm/xorm
  7. volatiletech/sqlboiler shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    Generate a Go ORM tailored to your database schema.
  8. go-pg/pg shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    Golang ORM with focus on PostgreSQL features and performance
  9. go-gorp/gorp shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    Go Relational Persistence - an ORM-ish library for Go
  10. xo/xo shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    Command line tool to generate idiomatic Go code for SQL databases supporting PostgreSQL, MySQL, SQLite, Oracle, and Microsoft SQL Server
  11. upper/db shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    Data access layer for PostgreSQL, CockroachDB, MySQL, SQLite and MongoDB with ORM-like features.
  12. uptrace/bun shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    SQL-first Golang ORM
  13. xxjwxc/gormt shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    database to golang struct
  14. steebchen/prisma-client-go shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    Prisma Client Go is an auto-generated and fully type-safe database client
  15. xormplus/xorm shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    xorm 是一个简单而强大的 Go 语言 ORM 库,通过它可以使数据库操作非常简便。本库是基于原版 xorm 的定制增强版本,为 xorm 提供类似 ibatis 的配置文件及动态 SQL 支持,支持 AcitveRecord 操作
  16. go-reform/reform shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    A better ORM for Go, based on non-empty interfaces and code generation.
  17. gobuffalo/pop shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    A Tasty Treat For All Your Database Needs
  18. bobohume/gonet shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    go 分布式服务器,基于内存 mmo
  19. unionj-cloud/go-doudou shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    go-doudou(doudou pronounce /dəudəu/)is OpenAPI 3.0 (for REST) spec and Protobuf v3 (for grpc) based lightweight microservice framework. It supports monolith service application as well.
  20. gohouse/gorose shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    GoRose(go orm), a mini database ORM for golang, which inspired by the famous php framwork laravle's eloquent. It will be friendly for php developer and python or ruby developer. Currently provides six major database drivers: mysql,sqlite3,postgres,oracle,mssql, Clickhouse.
  21. huandu/go-sqlbuilder shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    A flexible and powerful SQL string builder library plus a zero-config ORM.

#496 Golang 入门项目 httpbin 总结

2021-03-29

httpbin 是我练手的一个非常简单的小项目,功能就是:
1. HTTP POST 请求 (POST /) 提交一个字符串,服务器返回一个 ID。
1. HTTP GET 请求 (GET /xxxx),返回 ID 对应的字符串。

#495 网卡名称的变迁(ethX -> enpXsY)

2021-03-15

早几年前,Linux 系统的网卡名称都是 eth0、wlan0,后来都变了个风格,就拿我的电脑举例:enp7s0, wlp6s0。
这到底是是什么原因呢?
最近突然好奇,去查了资料才知道为什么。
在 Fedora 的技术资料中找到,这个和 Systemd 有关,然后又在 freedesktop 官网 Systemd 的手册中找到了详细的说明。
现在的命名方案有好长一段,估计要看个半个小时(如果感兴趣可以仔细阅读一下),解开我的疑问却不需要那么复杂。

#492 谷歌身份认证器

2021-03-08

基础概念

身份验证器

Authenticator

密码就算是身份验证器。
加密密钥,比如 SSH 的公钥私钥(密钥对)

动态密码

One-time Password, 缩写: OTP, 又叫做一次性密码

我们常用的的短信验证码就是一种非常方便快捷的动态密码形式。
早些年一些网络服务,比如谷歌、网易通行证等,可能会提供一个动态口令表,包含十几个密码,可以保存为图片,或者纯文本,上面的密码可以逐个使用,每个密码只能用一次。

  • RFC4226 HOTP: An HMAC-Based One-Time Password Algorithm
  • RFC6238 TOTP: Time-Based One-Time Password Algorithm

HOTP 基于 HMAC 算法

简单来说就是根据密钥和计数器来生成一个一次性密码。
除了记住密钥之外,你还要记住这是第几次使用。

  • HOTP value = HOTP(K, C) mod 10d
  • HOTP(K, C) = truncate(HMACH(K, C))
  • truncate(MAC) = extract31(MAC, MAC[(19 × 8) + 4:(19 × 8) + 7] × 8)
  • MAC[(19 × 8) + 4:(19 × 8) + 7] × 8
    取第十九字节的后四位(小端序), 转成一个有符号整型数(小端序),作为截取 MAC 的位置
  • extract31(MAC, i) = MAC[i × 8 + 1:i × 8 + (4 × 8) − 1]
  • MAC[i × 8 + 1:i × 8 + (4 × 8) − 1]
    从上一步得到的位置处,取四个字节,去掉符号位(小端序)

TOTP 基于时间

  1. 协商起始时间 T0 和时间间隔 TX
  2. 双方分别计算时间计数器 CT
  3. TOTP value(K) = HOTP value(K, CT)

多重要素验证

Multi-factor authentication, 缩写: MFA
Two-factor authentication, 缩写: 2FA

谷歌身份验证器

Google 身份验证器是一款 TOTP 与 HOTP 的两步验证软件令牌,此软件用于 Google 的认证服务。此项服务所使用的算法已列于 RFC 6238 和 RFC 4226 中。
Google 身份验证器给予用户一个六位到八位的一次性密码用于进行登录 Google 或其他站点时的附加验证。其同样可以给第三方应用生成口令,例如密码管理员或网络硬盘。先前版本的 Google 身份验证器开放源代码,但之后的版本以专有软件的形式公开。

谷歌验证器基于 TOTP,但是更进一步简化,以约定代替了协商过程。

  1. T0 为 Unix 时间
  2. TX 为 30 秒
  3. 哈希算法为 sha1

此外:

虽然不是很大的创新,而且这个软件验证器实现很简单,但是免费、开放(不需要做任何谷歌服务绑定),加上谷歌的强大影响力,这个软件验证器被很多系统采用。
最后,其他提供动态口令的应用都需要来兼容谷歌身份验证器。

PS: RedHat 开发并维护了开源的 FreeOTP 分支项目。

PS: 微软也有一个 Microsoft Authenticator,阿里云 APP 中有一个 虚拟MFA 功能,都是一个意思。
微软家的为自己提供 8 位密码,别人家的就 6 位,区别对待(虽然感觉好像也并没有什么影响)
阿里云 MFA 是需要手机 APP 登录进去之后才能使用的。

Just4Fun

import base64
import hashlib
import hmac
import time

DEFAULT_INTERVAL = 30  # Google Authenticator: 30 秒
DEFAULT_HASH = hashlib.sha1


def get_hotp_token(secret: str, counter: int, hash_algorithm=DEFAULT_HASH, length=6):
    padding_len = 8 - len(secret) % 8
    if padding_len != 8:
        assert 1 <= padding_len <= 7
        secret += '=' * padding_len
    key = base64.b32decode(secret, True)
    message = (counter & 0xffffffffffffffff).to_bytes(8, 'big')
    mac = hmac.new(key, message, hash_algorithm).digest()
    loc = mac[-1] & 0x0F
    token = (int.from_bytes(mac[loc:loc+4], 'big') & 0x7fffffff) % (10 ** length)
    return token


def get_totp_token(secret, interval=DEFAULT_INTERVAL):
    time_counter = int(time.time()) // interval
    return get_hotp_token(secret, time_counter)


if __name__ == '__main__':
    print('%06d' % get_totp_token(sys.argv[1]))

参考资料与拓展阅读