Table of Contents:

参考链接

开篇词 | 从 0 开始搭建一个企业级 Go 应用

Go 是云时代的语言,随着云计算平台的逐渐成熟,应用上云已经成为一个不可逆转的趋势了,而云目前是朝着云原生架构的方向演进的,云原生架构中具有统治力(影响力)的项目绝大部分又是用 Go 构建的。

本专栏的六个模块:
实战准备:我会先手把手带你准备一个实验环境,再带你部署我们的实战项目。加深你对实战项目的理解的同时,给你讲解一些部署的技能点,包括如何准备开发环境、制作 CA 证书,安装和配置用到的数据库、应用,以及 Shell 脚本编写技巧等。
实战第 1 站:规范设计:我会详细介绍开发中常见的 10 大规范,例如目录规范、日志规范、错误码规范、Commit 规范等。通过本模块,你能够学会如何设计常见的规范,为高效开发一个高质量、易阅读、易维护的 Go 应用打好基础。
实战第 2 站:基础功能设计或开发:我会教你设计或开发一些 Go 应用开发中的基础功能,这些功能会影响整个应用的构建方式,例如日志包、错误包、错误码等。
实战第 3 站:服务开发:我会带你一起解析一个企业级的 Go 项目代码,让你学会如何开发 Go 应用。在解析的过程中,我也会详细讲解 Go 开发阶段的各个技能点,例如怎么设计和开发 API 服务、Go SDK、客户端工具等。
实战第 4 站:服务测试:我会围绕实战项目来讲解进行单元测试、功能测试、性能分析和性能调优的方法,最终让你交付一个性能和稳定性都经过充分测试的、生产级可用的服务。
实战第 5 站:服务部署:本模块通过实战项目的部署,来告诉你如何部署一个高可用、安全、具备容灾能力,又可以轻松水平扩展的企业应用。这里,我会重点介绍 2 种部署方式:传统部署方式和容器化部署方式,每种方式在部署方法、复杂度和能力上都有所不同。

01 | IAM系统概述:我们要实现什么样的 Go 项目?

IAM(Identity and Access Management,身份识别与访问管理)系统是用 Go 语言编写的一个 Web 服务,用于给第三方用户提供访问控制服务。
IAM 系统可以帮用户解决的问题是:在特定的条件下,谁能够/不能够对哪些资源做哪些操作(Who is able to do what on something given some context),也即完成资源授权功能。

02 | 环境准备:如何安装和配置一个基本的 Go 开发环境?

03 | 项目部署:如何快速部署 IAM 系统?

04 | 规范设计(上):项目开发杂乱无章,如何规范?

常见规范:
* 代码风格不一:代码仓库中有多种代码风格,读 / 改他人的代码都是一件痛苦的事情,整个代码库也会看起来很乱。
* 目录杂乱无章:相同的功能被放在不同的目录,或者一个目录你根本不知道它要完成什么功能,新开发的代码你也不知道放在哪个目录或文件。这些都会严重降低代码的可维护性。
* 接口不统一:对外提供的 API 接口不统一,例如修改用户接口为/v1/users/colin,但是修改密钥接口为/v1/secret?name=secret0,难以理解和记忆。
* 错误码不规范:错误码会直接暴露给用户,主要用于展示错误类型,以定位错误问题。错误码不规范会导致难以辨别错误类型,或者同类错误拥有不同错误码,增加理解难度。

有哪些地方需要制定规范?
* 非编码类规范,主要包括开源规范、文档规范、版本规范、Commit 规范和发布规范。
* 编码类规范,则主要包括目录规范、代码规范、接口规范、日志规范和错误码规范。

小结:
1. 新开发的项目最好按照开源标准来规范,以驱动其成为一个高质量的项目。
2. 开发之前,最好提前规范好文档目录,并选择一种合适的方式来编写 API 文档。推荐markdown格式。
3. 项目要遵循版本规范,目前业界主流的版本规范是语义化版本规范,也是我推荐的版本规范。

05 | 规范设计(下):commit 信息风格迥异、难以阅读,如何规范?

今天我向你介绍了 Commit Message 规范,主要讲了业界使用最多的 Angular 规范。
Angular 规范中,Commit Message 包含三个部分:Header、Body 和 Footer。Header 对 commit 做了高度概括,Body 部分是对本次 commit 的更详细描述,Footer 部分主要用来说明本次 commit 导致的后果。格式如下:

<type>[optional scope]: <description>
// 空行
[optional body]
// 空行
[optional footer(s)]

另外,我们也需要控制 commit 的提交频率,比如可以在开发完一个功能、修复完一个 bug、下班前提交 commit。
最后,我们也需要掌握一些常见的提交操作,例如通过 git rebase -i 来合并提交 commit,通过 git commit --amend 或 git rebase -i 来修改 commit message。

06 | 目录结构设计:如何组织一个可维护、可扩展的代码目录?

目录结构是一个项目的门面。很多时候,根据目录结构就能看出开发者对这门语言的掌握程度。

根据功能,我们可以将目录结构分为结构化目录结构和平铺式目录结构两种。结构化目录结构主要用在 Go 应用中,相对来说比较复杂;而平铺式目录结构主要用在 Go 包中,相对来说比较简单。

golang-standards/project-layout

07 | 工作流设计:如何设计合理的多人开发模式?

总结
这一讲中,我基于 Git 向你介绍了 4 种开发模式,现在跟我回顾一下吧。
* 集中式工作流:开发者直接在本地 master 分支开发代码,开发完成后 push 到远端仓库 master 分支。
* 功能分支工作流:开发者基于 master 分支创建一个新分支,在新分支进行开发,开发完成后合并到远端仓库 master 分支。
* Git Flow 工作流:Git Flow 工作流为不同的分支分配一个明确的角色,并定义分支之间什么时候、如何进行交互,比较适合大型项目的开发。
* Forking 工作流:开发者先 fork 项目到个人仓库,在个人仓库完成开发后,提交 pull request 到目标远程仓库,远程仓库 review 后,合并 pull request 到 master 分支。

08 | 研发流程设计(上):如何设计 Go 项目的开发流程?

一个项目从立项到结项,中间会经历很多阶段。业界相对标准的划分,是把研发流程分为六个阶段,分别是需求阶段、设计阶段、开发阶段、测试阶段、发布阶段、运营阶段。其中,开发人员需要参与的阶段有 4 个:设计阶段、开发阶段、测试阶段和发布阶段。

研发流程也是一种规范,很难靠开发者的自觉性去遵守。为了让项目参与人员尽可能地遵守规范,需要借助一些工具、系统来对他们进行强约束。所以,在我们设计完整个研发流程之后,需要认真思考下,有哪些地方可以实现自动化,有哪些地方可以靠工具、系统来保障规范的执行。

09 | 研发流程设计(下):如何管理应用的生命周期?

10 | 设计方法:怎么写出优雅的 Go 项目?

编写高质量的 Go 应用

11 | 设计模式:Go常用设计模式概述

设计模式是啥呢?简单来说,就是将软件开发中需要重复性解决的编码场景,按最佳实践的方式抽象成一个模型,模型描述的解决方法就是设计模式。

创建型模式
它提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。
这种类型的设计模式里,单例模式和工厂模式(具体包括简单工厂模式、抽象工厂模式和工厂方法模式三种)

12 | API 风格(上):如何设计RESTful API?

REST 有一系列规范,满足这些规范的 API 均可称为 RESTful API。REST 规范把所有内容都视为资源,也就是说网络上一切皆资源。REST 架构对资源的操作包括获取、创建、修改和删除,这些操作正好对应 HTTP 协议提供的 GET、POST、PUT 和 DELETE 方法。

总结
这一讲,我介绍了两种常用 API 风格中的一种,RESTful API。REST 是一种 API 规范,而 RESTful API 则是满足这种规范的 API 接口,RESTful API 的核心是规范。
在 REST 规范中,资源通过 URI 来标识,资源名使用名词而不是动词,并且用名词复数表示,资源都是分为 Collection 和 Member 两种。RESTful API 中,分别使用 POST、DELETE、PUT、GET 来表示 REST 资源的增删改查,HTTP 方法、Collection、Member 不同组合会产生不同的操作,具体的映射你可以看下 REST 资源操作映射为 HTTP 方法 部分的表格。
为了方便用户使用和理解,每个 RESTful API 的返回格式、错误和正确消息的返回格式,都应该保持一致。RESTful API 需要支持 API 版本,并且版本应该能够向前兼容,我们可以将版本号放在 URL 中、HTTP Header 中、Form 参数中,但这里我建议将版本号放在 URL 中,例如 /v1/users,这种形式比较直观。
另外,我们可以通过脊柱命名法来命名 API 接口名。对于一个 REST 资源,其查询接口还应该支持分页 / 过滤 / 排序 / 搜索功能,这些功能可以用同一套机制来实现。 API 的域名可以采用 https://marmotedu.com/api 和 https://iam.api.marmotedu.com 两种格式。

13 | API 风格(下):RPC API介绍

假定希望用RPC作为内部API的通讯,同时也想对外提供RESTful API,又不想写两套,可以使用gRPC Gateway 插件,在生成RPC的同时也生成RESTful web server。
借助grpc-gateway插件,可以基于proto文件生成反向代理(Reverse Proxy)的代码,这个反向代理运行起来后,对外提供RESTful服务,收到RESTful请求后通过gRPC调用原来的gRPC服务

14 | 项目管理:如何编写高质量的Makefile?

熟练掌握 Makefile 语法

跟我一起写Makefile (PDF重制版) 陈皓

规划 Makefile 要实现的功能

通常而言,Go 项目的 Makefile 应该实现以下功能:
格式化代码、静态代码检查、单元测试、代码构建、文件清理、帮助等等。如果通过 docker 部署,还需要有 docker 镜像打包功能。
因为 Go 是跨平台的语言,所以构建和 docker 打包命令,还要能够支持不同的 CPU 架构和平台。为了能够更好地控制 Makefile 命令的行为,还需要支持 Options。

设计合理的 Makefile 结构

对于大型项目来说,需要管理的内容很多,所有管理功能都集成在一个 Makefile 中,可能会导致 Makefile 很大,难以阅读和维护,所以建议采用分层的设计方法,根目录下的 Makefile 聚合所有的 Makefile 命令,具体实现则按功能分类,放在另外的 Makefile 中。

我们经常会在 Makefile 命令中集成 shell 脚本,但如果 shell 脚本过于复杂,也会导致 Makefile 内容过多,难以阅读和维护。并且在 Makefile 中集成复杂的 shell 脚本,编写体验也很差。对于这种情况,可以将复杂的 shell 命令封装在 shell 脚本中,供 Makefile 直接调用,而一些简单的命令则可以直接集成在 Makefile 中。

掌握 Makefile 编写技巧

技巧 1:善用通配符和自动变量
技巧 2:善用函数
技巧 3:依赖需要用到的工具
技巧 4:把常用功能放在 /Makefile 中,不常用的放在分类 Makefile 中
技巧 5:编写可扩展的 Makefile
技巧 6:将所有输出存放在一个目录下,方便清理和查找
技巧 7:使用带层级的命名方式
技巧 8:做好目标拆分
技巧 9:设置 OPTIONS
技巧 10:定义环境变量
技巧 11:自己调用自己

15 | 研发流程实战:IAM项目是如何进行研发流程管理的?

16 | 代码检查:如何进行静态代码检查?

golangci-lint 使用技巧

技巧 1:第一次修改,可以按目录修改。
技巧 2:按文件修改,减少文件切换次数,提高修改效率。

golangci-lint run ./...|grep pkg/storage/redis_cluster.go

技巧 3:把 linters-setting.lll.line-length 设置得大一些。
技巧 4:尽可能多地使用 golangci-lint 提供的 linter。
技巧 5:每次修改代码后,都要执行 golangci-lint。
技巧 6:建议在根目录下放一个通用的 golangci-lint 配置文件。

17 | API 文档:如何生成 Swagger API 文档 ?

Swagger 和 OpenAPI 的区别

OpenAPI 是一个 API 规范,它的前身叫 Swagger 规范,通过定义一种用来描述 API 格式或 API 定义的语言,来规范 RESTful 服务开发过程,目前最新的 OpenAPI 规范是OpenAPI 3.0(也就是 Swagger 2.0 规范)。
所以,可以简单地这么理解:OpenAPI 是一个 API 规范,Swagger 则是实现规范的工具。

用 go-swagger 来生成 Swagger API 文档

在 Go 项目开发中,我们可以通过下面两种方法来生成 Swagger API 文档:
第一,如果你熟悉 Swagger 语法的话,可以直接编写 JSON/YAML 格式的 Swagger 文档。建议选择 YAML 格式,因为它比 JSON 格式更简洁直观。
第二,通过工具生成 Swagger 文档,目前可以通过swag和go-swagger两个工具来生成。

18 | 错误处理(上):如何设计一套科学的错误码?

期望错误码实现的功能
第一个功能是有业务 Code 码标识。
第二个功能,考虑到安全,希望能够对外对内分别展示不同的错误信息。

业务 Code 码设计

Code 码设计规范:纯数字表示,不同部位代表不同的服务,不同的模块。
错误代码说明:100101
10: 服务。
01: 某个服务下的某个模块。
01: 模块下的错误码序号,每个模块可以注册 100 个错误。

如何设置 HTTP Status Code

建议http status code不要太多,将错误码控制在适当的数目内,客户端比较容易处理和判断,开发也比较容易进行错误码映射。
基本上只需要这 3 个 HTTP Code:
200 - 表示请求成功执行。
400 - 表示客户端出问题。
500 - 表示服务端出问题。

如果觉得这 3 个错误码不够用,最多可以加如下 3 个错误码:
401 - 表示认证失败。
403 - 表示授权失败。
404 - 表示资源找不到,这里的资源可以是 URL 或者 RESTful 资源。

19 | 错误处理(下):如何设计错误包?

错误包需要具有哪些功能?
1. 应该能支持错误堆栈。
2. 能够支持不同的打印格式
3. 能支持 Wrap/Unwrap 功能,也就是在已有的错误上,追加一些新的信息。
4. 错误包实现Is/As方法,用于判断错误类型。
5. 能够支持两种错误创建方式:非格式化创建和格式化创建

errors.New("file not found")
errors.Errorf("file %s not found", "iam-apiserver")

20 | 日志处理(上):如何设计日志包并记录日志?

日志包需要具备哪些功能
    基础功能
        支持基本的日志信息,日志包需要支持基本的日志信息,包括时间戳、文件名、行号、日志级别和日志信息。
        支持不同的日志级别
        支持自定义配置,不同的运行环境,需要不同的日志输出配置
        支持输出到标准输出和文件

    高级功能
        支持多种日志格式
            建议在开发联调阶段使用 TEXT 格式的日志,在现网环境使用 JSON 格式的日志。一个优秀的日志库,例如 logrus,除了提供基本的输出格式外,还应该允许开发者自定义日志输出格式。
        能够按级别分类输出
        支持结构化日志
        支持日志轮转
        具备 Hook 能力
            Hook 能力可以使我们对日志内容进行自定义处理。例如,当某个级别的日志产生时,发送邮件或者调用告警接口进行告警。很多优秀的开源日志包提供了 Hook 能力,例如 logrus 和 zap。    
    可选功能
        支持颜色输出
        兼容标准库 log 包
        支持输出到不同的位置

如何记录日志?

在何处打印日志?
    在分支语句处打印日志。在分支语句处打印日志,可以判断出代码走了哪个分支,有助于判断请求的下一跳,继而继续排查问题。
    写操作必须打印日志。写操作最可能会引起比较严重的业务故障,写操作打印日志,可以在出问题时找到关键信息
    在循环中打印日志要慎重
    在错误产生的最原始位置打印日志。对于嵌套的 Error,可在 Error 产生的最初位置打印 Error 日志
    当代码调用第三方包的函数时,也要打印日志。第三方包的函数可能会产生错误,打印日志,可以帮助我们定位问题
在哪个日志级别打印日志?
    Debug 级别
        为了获取足够的信息进行 Debug,通常会在 Debug 级别打印很多日志。例如,可以打印整个 HTTP 请求的请求 Body 或者响应 Body。
        Debug 级别需要打印大量的日志,这会严重拖累程序的性能。在服务上线时我们一定要禁止掉
    
    Info 级别
        Info 级别的日志可以记录一些有用的信息,供以后的运营分析,所以 Info 级别的日志不是越多越好,也不是越少越好,应以满足需求为主要目标。
        现网的日志级别一般是 Info 级别,为了不使日志文件占满整个磁盘空间,在记录日志时,要注意避免产生过多的 Info 级别的日志。
    Warn 级别    
        Warn 级别的日志往往说明程序运行异常,不符合预期,但又不影响程序的继续运行,或者是暂时影响,但后续会恢复。
    Error 级别
        Error 级别的日志告诉我们程序执行出错,这些错误肯定会影响到程序的执行结果,例如请求失败、创建资源失败等。    


如何记录日志内容?

21 | 日志处理(下):手把手教你从 0 编写一个日志包

开源日志包选择
上面我介绍了很多日志包,每种日志包使用的场景不同,你可以根据自己的需求,结合日志包的特性进行选择:
* 标准库 log 包: 标准库 log 包不支持日志级别、日志分割、日志格式等功能,所以在大型项目中很少直接使用,通常用于一些短小的程序,比如用于生成 JWT Token 的 main.go 文件中。标准库日志包也很适合一些简短的代码,用于快速调试和验证。
* glog: glog 实现了日志包的基本功能,非常适合一些对日志功能要求不多的小型项目。
* logrus: logrus 功能强大,不仅实现了日志包的基本功能,还有很多高级特性,适合一些大型项目,尤其是需要结构化日志记录的项目。
* zap: zap 提供了很强大的日志功能,性能高,内存分配次数少,适合对日志性能要求很高的项目。另外,zap 包中的子包 zapcore,提供了很多底层的日志接口,适合用来做二次封装。

22 | 应用构建三剑客:Pflag、Viper、Cobra 核心功能介绍

// 支持长选项、默认值和使用文本,并将标志的值存储在指针中。
var name = pflag.String("name", "colin", "Input Your Name")
// 支持长选项、短选项、默认值和使用文本,并将标志的值存储在指针中。
var name = pflag.StringP("name", "n", "colin", "Input Your Name")
// 支持长选项、默认值和使用文本,并将标志的值绑定到变量。
var name string
pflag.StringVar(&name, "name", "colin", "Input Your Name")
// 支持长选项、短选项、默认值和使用文本,并将标志的值绑定到变量。
var name string
pflag.StringVarP(&name, "name", "n","colin", "Input Your Name")

函数名带Var说明是将标志的值绑定到变量,否则是将标志的值存储在指针中。
函数名带P说明支持短选项,否则不支持短选项。

现代化的命令行框架:Cobra 全解

应用程序通常遵循如下模式:APPNAME VERB NOUN --ADJECTIVE或者APPNAME COMMAND ARG --FLAG,例如:
例如:

git clone URL --bare # clone 是一个命令,URL是一个非选项参数,bare是一个选项参数

这里,VERB 代表动词,NOUN 代码名词,ADJECTIVE 代表形容词。

23 | 应用构建实战:如何构建一个优秀的企业应用框架?

我们目前见到的 Go 后端服务,基本上可以分为 API 服务和非 API 服务两类。
* API 服务:通过对外提供 HTTP/RPC 接口来完成指定的功能。比如订单服务,通过调用创建订单的 API 接口,来创建商品订单。
* 非 API 服务:通过监听、定时运行等方式,而不是通过 API 调用来完成某些任务。比如数据处理服务,定时从 Redis 中获取数据,处理后存入后端存储中。再比如消息处理服务,监听消息队列(如 NSQ/Kafka/RabbitMQ),收到消息后进行处理。

24 | Web 服务:Web 服务核心功能有哪些,如何实现?

对路由进行分组
一进程多服务
参数解析、参数校验、逻辑处理、返回结果
中间件
认证
前后端分离,跨域请求

优雅关停

方法一:借助第三方的 Go 包
如果使用第三方的 Go 包来实现优雅关闭,目前用得比较多的包是fvbock/endless

router := gin.Default()
router.GET("/", handler)
// [...]
endless.ListenAndServe(":4242", router)

方法二:编码实现
Go 1.8 版本或者更新的版本,http.Server 内置的 Shutdown 方法,已经实现了优雅关闭

HTTP 具有以下 5 种参数类型:
* 路径参数(path)。例如gin.Default().GET("/user/:name", nil), name 就是路径参数。
* 查询字符串参数(querystring)。例如/welcome?firstname=Lingfei&lastname=Kong,firstname 和 lastname 就是查询字符串参数。
* 表单参数(form)。例如curl -X POST -F 'username=colin' -F 'password=colin1234' http://mydomain.com/login,username 和 password 就是表单参数。
* HTTP 头参数(header)。例如curl -X POST -H 'Content-Type: application/json' -d '{"username":"colin","password":"colin1234"}' http://mydomain.com/login,Content-Type 就是 HTTP 头参数。
* 消息体参数(body)。例如curl -X POST -H 'Content-Type: application/json' -d '{"username":"colin","password":"colin1234"}' http://mydomain.com/login,username 和 password 就是消息体参数。

25 | 认证机制:应用程序如何进行访问认证?

认证和授权有什么区别?
认证证明了你是谁,授权决定了你能做什么。

四种基本的认证方式
1. Basic
Basic 认证(基础认证),是最简单的认证方式。它简单地将用户名:密码进行 base64 编码后,放到 HTTP Authorization Header 中。

  1. Digest

  2. OAuth

  3. Bearer

总结
在开发 Go 应用时,我们需要通过认证来保障应用的安全。认证,用来验证某个用户是否具有访问系统的权限,如果认证通过,该用户就可以访问系统,从而创建、修改、删除、查询平台支持的资源。业界目前有四种常用的认证方式:Basic、Digest、OAuth、Bearer。其中 Basic 和 Bearer 用得最多。
Basic 认证通过用户名和密码来进行认证,主要用在用户登录场景;Bearer 认证通过 Token 来进行认证,通常用在 API 调用场景。不管是 Basic 认证还是 Bearer 认证,都需要结合 HTTPS 来使用,来最大程度地保证请求的安全性。
Basic 认证简单易懂,但是 Bearer 认证有一定的复杂度,所以这一讲的后半部分通过 JWT Token,讲解了 Bearer Token 认证的原理。
JWT Token 是 Bearer 认证的一种比较好的实现,主要包含了 3 个部分:
* Header:包含了 Token 的类型、Token 使用的加密算法。在某些场景下,你还可以添加 kid 字段,用来标识一个密钥 ID。
* Payload:Payload 中携带 Token 的具体内容,由 JWT 标准中注册的声明、公共的声明和私有的声明三部分组成。
* Signature:Signature 是 Token 的签名部分,程序通过验证 Signature 是否合法,来决定认证是否通过。

26 | IAM项目是如何设计和实现访问认证功能的?

27 | 权限模型:5大权限模型是如何进行资源授权的?

总结
这一讲,我介绍了 5 种常见的权限模型。其中,ACL 最简单,ABAC 最复杂,但是功能最强大,也最灵活。RBAC 则介于二者之间。对于一些云计算厂商来说,因为它们面临的授权场景复杂多样,需要一个非常强大的授权模型,所以腾讯云、阿里云和 AWS 等云厂商普遍采用了 ABAC 模型。
如果你的资源授权需求不复杂,可以考虑 RBAC;如果你需要一个能满足复杂场景的资源授权系统,建议选择 ABAC,ABAC 的设计思路可以参考下腾讯云的 CAM、阿里云的 RAM 和 AWS 的 IAM。

28 | 控制流(上):通过iam-apiserver设计,看Web服务的构建

29|控制流(下):iam-apiserver服务核心功能实现讲解

30 | ORM:CURD 神器 GORM 包介绍及实战

31 | 数据流:通过iam-authz-server设计,看数据流服务的设计

32 | 数据处理:如何高效处理应用程序产生的数据?

33 | SDK 设计(上):如何设计出一个优秀的 Go SDK?

总结
这一讲,我主要介绍了如何设计一个优秀的 Go SDK。通过提供 SDK,可以提高 API 调用效率,减少 API 调用难度,所以大型应用通常都会提供 SDK。不同团队有不同的 SDK 设计方法,但目前比较好的实现是公有云厂商采用的 SDK 设计方式。

34 | SDK 设计(下):IAM项目Go SDK设计和实现

35 | 效率神器:如何设计和实现一个命令行客户端工具?

命令行工具是可以在操作系统上执行的一个二进制程序,提供了一种比 SDK 和 API 接口更方便快捷的访问后端服务的途径,供运维或者开发人员在服务器上直接执行使用,或者在自动化脚本中调用。

需要后台开发人员投入工作量进行研发的客户端是 SDK 和命令行工具。
其中的调用关系为:命令行工具 -> SDK -> API接口

通过学习 kubectl、istioctl、etcdctl 这些优秀的命令行工具,可以发现一个大型系统的命令行工具,通常具有下面这些特点:
* 支持命令和子命令,命令 / 子命名有自己独有的命令行参数。
* 支持一些特殊的命令。比如支持 completion 命令,completion 命令可以输出 bash/zsh 自动补全脚本,实现命令行及参数的自动补全。还支持 version 命令,version 命令不仅可以输出客户端的版本,还可以输出服务端的版本(如果有需要)。
* 支持全局 option,全局 option 可以作为所有命令及子命令的命令行参数。
* 支持 -h/help,-h/help 可以打印 xxxctl 的帮助信息

总结
这一讲,我主要剖析了 iamctl 命令行工具的实现,进而向你介绍了如何实现一个优秀的客户端工具。
对于一个大型系统 xxx 来说,通常需要有一个 xxxctl 命令行工具, xxxctl 命令行工具可以方便开发、运维使用系统功能,并能实现功能自动化。
IAM 项目参考 kubectl,实现了命令行工具 iamctl。iamctl 集成了很多功能,我们可以通过 iamctl 子命令来使用这些功能。例如,我们可以通过 iamctl 对用户、密钥和策略进行 CURD 操作;可以设置 iamctl 自动补全脚本;可以查看 IAM 系统的版本信息。甚至,你还可以使用 iamctl new 命令,快速创建一个 iamctl 子命令模板。
iamctl 使用了 cobra、pflag、viper 包来构建,每个子命令又包含了一些基本的功能,例如短描述、长描述、使用示例、命令行选项、选项校验等。iamctl 命令可以加载不同的配置文件,来连接不同的客户端。iamctl 通过 SDK 调用、REST API 调用两种方式来调用服务端 API 接口。

40 | 软件部署实战(上):部署方案及负载均衡、高可用组件介绍

41 | 软件部署实战(中):IAM 系统生产环境部署实战

42 | 软件部署实战(下):IAM系统安全加固、水平扩缩容实战

43|技术演进(上):虚拟化技术演进之路

虚拟化技术的演进过程如下:
物理机阶段 -> 虚拟机阶段 -> 容器阶段(Docker + Kubernetes) -> Serverless 阶段。

44|技术演进(下):软件架构和应用生命周期技术演进之路

单体架构

在最早的时候,我们用的软件架构是单体架构。在单体架构中,我们会将应用程序的所有功能都存放在一个代码仓库中,并且发布时,也是发布整个代码仓库的代码和功能。
在单体架构中,应用软件一般会包含四层,分别是表示层、业务逻辑层、数据访问层、数据库

SOA 架构

SOA 架构是面向服务的软件架构,它的核心理念是:基于 SOA 的架构思想,将重复共用的功能抽取为组件,以服务的方式给各系统提供服务,服务之间通过 ESB 企业服务总线进行通信。

微服务架构

微服务架构由 Matrin Fowler 在 2014 年提出,它的理念是将业务系统彻底地组件化和服务化,形成多个可以独立开发、部署和维护的服务或应用的集合。

Service Mesh

45|基于Kubernetes的云原生架构设计

云原生(Cloud Native)是一种构建和运行应用程序的方法,是一套技术体系和方法论。

什么是云原生应用?

云原生应用是指生而为云的应用,应用程序从设计之初就考虑到了云的环境,可以在云上以最佳姿势运行,充分利用和发挥云平台提供的各种能力。具体来看,云原生应用具有以下三大特点:
* 从应用生命周期管理维度来看,使用 DevOps 和 CI/CD 的方式,进行开发和交付。
* 从应用维度来看,以微服务原则进行划分设计。
* 从系统资源维度来看,采用 Docker + Kubernetes 的方式来部署。

46 | 如何制作Docker镜像?