第1章 持续交付:为什么需要持续交付,什么是持续交付 1
入门知识 1
赋能开发者:为什么我们要持续交付 2
快速反馈会减少上下文切换 2
自动化的、可重复的以及可靠的发布 2
定义“完成”的概念 3
什么是构建管道 4
核心的构建管道阶段 4
容器技术的影响 7
对当前架构的影响 8
总结 9
第2章 Java开发的演化 10
现代Java应用程序的需求 10
对业务增长速度和稳定性的要求 11
API经济的崛起 11
云计算的机会和成本 12
模块化归来:拥抱更小的服务 12
对持续交付的影响 13
Java部署平台的演化 13
WAR和EAR:应用服务器统治的年代 13
可执行的胖JAR文件:十二要素风格应用的出现 14
容器镜像:不断增加的可移植性(以及复杂性) 15
函数即服务:“无服务器”架构的出现 16
平台对持续交付的影响 17
DevOps、SRE和发布工程 17
研发和运维 18
站点可靠性工程 19
发布工程 21
共享责任、指标和可观察性 22
总结 22
第3章 设计持续交付的架构 24
优秀架构的基础 24
松耦合 25
高内聚 25
耦合、内聚和持续交付 26
面向业务敏捷的架构 27
不好的架构会限制业务的发展 27
复杂性和变更成本 28
API驱动的应用程序的最佳实践 29
“自上而下”构建API 29
良好的API有助于持续测试和集成 29
部署平台和架构 30
设计符合“十二要素”的云原生应用程序 30
培养机械同理心 33
面向失败的设计和持续测试 33
越来越小的服务 34
交付单体应用程序的挑战 34
微服务:当SOA遇到领域驱动设计 35
函数、lambda表达式和纳米服务(Nanoservices) 36
架构:“难以改变的东西” 37
总结 38
第4章 Java应用的部署平台、基础设施以及持续交付 39
由平台提供的功能性 39
基本的开发流程 40
传统的基础设施平台 41
传统的平台组件 41
传统基础设施平台面临的挑战 41
传统基础设施的好处 42
传统基础设施平台上的CI/CD 42
云平台 43
深入云计算 43
云计算面临的挑战 45
云计算的好处 46
云计算中的持续交付 47
平台即服务 47
简单了解PaaS的原理 48
PaaS平台面临的挑战 48
PaaS的好处 50
CI/CD和PaaS 50
容器(Docker) 50
容器平台组件 51
容器面临的挑战 52
容器的好处 53
持续交付容器 53
Kubernetes 53
Kubernetes的核心概念 54
Kubernetes面临的挑战 54
Kubernetes的好处 55
Kubemetes的持续交付 56
函数即服务/无服务器函数 56
FaaS的概念 57
FaaS面临的挑战 57
FaaS的好处 58
CI/CD和FaaS 59
使用基础设施即代码 59
总结 60
第5章 构建Java应用程序 61
分解构建过程 61
自动化构建过程 62
构建依赖 63
外部依赖 66
多模块项目 67
使用多代码库还是单代码库 67
插件 68
发布和公开构件 69
Java构建工具概述 69
Ant 69
Maven 72
Gradle 77
Bazel、Pants和Buck 80
其他JVM构建工具:SBT和Leiningen 82
Make 82
如何选择一个构建工具 83
总结 84
第6章 其他构建工具和技巧 86
Linux、Bash和基本的CLI命令 86
用户、权限和组 86
使用文件系统 90
查看和编辑文本 92
将所有东西连在一起:重定向、管道和过滤器 93
搜索和操作文本:grep、awk和sed 94
诊断工具:top、ps、netstat和iostat 95
HTTP调用和JSON操作 96
curl 96
HTTPie 100
Jq 104
编写基础脚本 105
xargs 105
管道和过滤器 105
循环 106
条件 106
总结 107
第7章 打包应用程序 108
构建一个JAR文件:循序渐进 108
构建一个可执行的胖JAR文件 112
Maven Shade插件 113
构建Spring Boot Uber JAR文件 116
瘦JAR文件——为什么我们决定不使用胖JAR 117
构建WAR文件 118
在云平台上打包 120
将部署比作烹饪:烘焙式部署还是煎炸式部署 120
构建RPM和DEB OS包 121
其他构建OS包的工具(支持Windows) 124
使用Packer创建可在多个云平台部署的机器镜像 126
创建机器镜像的其他工具 129
构建容器 129
创建Docker容器镜像 130
使用fabric8制作Docker镜像 131
打包FaaS Java应用程序 132
总结 135
第8章 在本地环境中工作(就像在生产环境中一样) 136
本地开发面临的挑战 136
mock、stub和服务虚拟化 137
模式#1:profile、mock和stub 137
使用Mockito进行mock 138
模式#2:服务虚拟化和API仿真 140
使用Hoverfly虚拟化服务 141
虚拟机:Vagrant和Packer 145
安装Vagrant 145
创建一个Vagrantfile 145
模式#3:生产环境镜像 148
容器:Kubernetes、minikube和Telepresence 149
介绍Docker Java Shop示例程序 149
构建Java应用程序和容器镜像 150
部署到Kubernetes平台 152
简单的冒烟测试 155
构建剩余的应用程序 155
在Kubemetes上部署整个 Java应用程序 155
查看部署的应用程序 156
Telepresence:在本地远程工作 157
模式#4:环境租赁 160
FaaS:AWS Lambda和SAM Local 160
安装SAM Local 161
AWS Lambda脚手架 161
测试AWS Lambda事件处理 165
SAM Local冒烟测试 168
FaaS:Azure Functions和VS Code 170
安装Azure Functions Core Tools 170
在本地构建和测试函数 173
使用VS Code进行本地和远程测试 176
总结 177
第9章 持续集成:创建构建管道的第一步 178
为什么要持续集成 178
如何实施CI 179
中心化与分布式的版本控制系统 179
Git入门 180
核心的Git CLI命令 181
Hub:一个Git和GitHub必备的工具 183
有效地使用DVCS 185
基于主干的开发 185
基于功能分支的开发 186
Gitflow 186
没有万全之策:如何选择分支策略 187
代码审查 189
我们要寻找什么 190
代码审查自动化:PMD、Checkstyle和FindBugs 191
审查pull request 196
自动化构建 197
Jenkins 197
发动你的团队 199
定期合并代码 199
“停下来”:管理失败的构建 199
不要在测试上使用@Ignore 199
保持快速的构建过程 200
平台(基础设施即代码)的CI 200
总结 201
第10章 通过管道进行部署和发布 202
介绍Extended Java Shop应用程序 202
分离部署和发布 204
部署应用程序 205
创建一个容器镜像 206
部署机制 209
一切都开始于(并且结束于)健康检查 218
部署策略 222
使用非托管的集群 232
更改数据库 236
发布功能 240
功能开关 240
语义版本控制 243
API的向后兼容性和版本 244
多阶段升级 249
管理配置和敏感信息 250
“打包式”配置 250
外部配置 251
处理敏感信息 252
总结 253
第11章 功能性测试:正确和接受度 254
为什么要测试软件 254
测试什么?敏捷测试象限介绍 254
持续测试 256
构建正确的反馈循环 256
无尽的海龟 257
人为交易 258
端到端测试 259
验收测试 261
行为驱动开发 261
stub或者虚拟化第三方服务 265
将所有这些整合在一起 265
消费者驱动的合约 265
RESTful API合约 267
消息合约 269
组件测试 271
嵌入式数据存储 271
内存消息队列 272
测试替代 273
创建内部资源或接口 274
进程内和进程外 275
集成测试 277
验证外部交互 278
测试容错性 278
单元测试 279
交互型单元测试 280
独立型单元测试 281
处理不可预知的测试 282
数据 282
还未准备好的资源 283
不确定性事件 283
如果你什么都做不了 284
自上而下的测试和自下而上的测试 284
自上而下的测试 285
自下而上的测试 286
将所有内容都融入构建管道 287
多少测试才够 288
总结 289
第12章 系统质量属性测试:验证非功能性需求 291
为什么要测试非功能性需求 291
代码质量 292
架构质量 292
ArchUnit:架构方面的单元测试 292
使用JDepend生成设计质量指标 295
性能和压力测试 297
使用Apache Benchmark进行基本的性能测试 298
使用Gatling进行压力测试 299
安全、漏洞和威胁 305
代码级别的安全验证 306
依赖项验证 311
与部署平台相关的安全问题 315
后续步骤:威胁建模 318
混乱测试 321
在生产环境中制造混乱(引入猴子) 322
在预发布环境中造成混乱 324
需要多少非功能性测试才够 325
总结 326
第13章 可观察性:监控、日志和跟踪 327
可观察性和持续交付 327
为什么要观察应用程序 327
我们希望监控:应用程序、网络和机器 329
如何观察:监控、日志和跟踪 330
报警 330
面向可观察性的系统设计 332
指标 332
指标的类型 333
Dropwizard Metrics 333
Spring Boot Actuator 335
Micrometer 336
使用指标的最佳实践 337
日志 337
日志的形式 337
SLF4J 339
Log4j 2 340
日志的最佳实践 341
请求跟踪 342
trace、span和baggage 342
Java跟踪工具:OpenZipkin、Spring Sleuth和OpenCensus 343
分布式跟踪的推荐实践 344
异常跟踪 344
Airbrake 346
系统监控工具 347
collectd 347
rsyslog 347
Sensu 348
收集和存储 348
Prometheus 349
Elastic-Logstash-Kibana 349
可视化 350
业务可视化 350
运维可视化 351
开发可视化 353
总结 354
第14章 迁移到持续交付 355
持续交付能力 355
选择你要迁移的项目 356
情景感知 357
Cynefin框架和持续交付 358
所有模型都是错误的,有些是有用的 359
开展持续交付 359
测量持续交付 360
从小处开始,尝试、学习、分享,然后重复整个过程 362
增加推广范围:领导变革 363
其他的指导和提示 365
不良实践和常见的反模式 365
丑陋的架构:改还是不改 365
总结 367
第15章 持续交付和持续改进 369
从现在开始 369
建立扎实的技术基础 369
持续交付价值(最重要的目标) 370
增加软件的共享责任 371
促进快速反馈和实验 371
在组织中开展持续交付 372
持续改进 372
总结 373