微服务间的调用和应用内调用有什么区别

阿娇 发表了文章 • 0 个评论 • 152 次浏览 • 2019-06-03 11:19 • 来自相关话题

2019企业IT现状和趋势调研报告:70.7%的企业有云原生相关计划

灵雀云 发表了文章 • 0 个评论 • 122 次浏览 • 2019-06-03 11:00 • 来自相关话题

2019年第一季度,灵雀云发起了“企业IT应用现状和云原生技术落地情况”的调研,通过定向邀请,3个月内共收集了400余份有效调研问卷,这些调研问卷80%以上都来自于国内政府、金融、能源、制造、汽车等传统行业的IT从业者。 发起本次调研 ...查看全部
2019年第一季度,灵雀云发起了“企业IT应用现状和云原生技术落地情况”的调研,通过定向邀请,3个月内共收集了400余份有效调研问卷,这些调研问卷80%以上都来自于国内政府、金融、能源、制造、汽车等传统行业的IT从业者。

发起本次调研的初衷,是我们希望了解当前企业,尤其是传统企业目前IT应用开发现状、以及以DevOps、Kubernetes、微服务等为代表的云原生技术在企业的应用情况,从而勾勒出传统行业IT发展趋势,并对于判断国内用户对云原生相关技术的认知度提供一个有价值的参考。
核心要点解读:
1、 约70%的参与调研者所在企业2019年IT预算有上浮;

2、 24.4%的参与调研者表示公司IT系统基本全靠自研,企业开始自建软件研发团队,主导IT应用的研发;

3、 70.7%的参与调研者所在企业表示在2019年有容器、DevOps和微服务方面的规划;

4、 11.4%的参与调研者所在企业已经试点了具有标杆意义的云原生实践,如精英团队的DevOps实践,小范围非核心应用的微服务拆分改造实践等。


pic2.jpg



本次调研的400多位调研对象中,80%以上来自金融、能源、制造、汽车等传统行业,其中17.3%来自基础架构部门, 22.5%来自运维部门,34.1%来自研发部门,还有约10%的被调研对象为企业的CIO/CTO等高级IT管理者。


pic3.jpg



被调研企业中,服务器规模在100-500台的比例为26.8%,500-1000台的企业占比22%,1000台服务器以上规模的14.6%。



IT系统自研还是外包



pic4.jpg




在数字化转型的背景下,传统外包的做法在被逐渐改变。在此次调查中,70.7%的参与调研者表示目前IT系统是自研外包兼而有之,其中核心业务系统以自己开发为主,24.4%的参与调研者表示公司IT系统基本全靠自研,只有4.9%的参与调研者选择了纯外包选项。这表明,企业开始不再将大部分业务系统,尤其是核心业务需求开发外包,开始自建软件研发团队,主导IT应用的研发。只有企业自己主导IT研发,才能够打造IT核心竞争力。

软件能力成为企业的核心竞争力,这恰好是数字化转型的本质之一。何谓成功的数字化转型?灵雀云认为,有三大衡量标志:IT部门由成本中心转为收入中心;企业自己主导IT产品的研发;改进工具、流程、文化来提高交付速度和质量。最终,实现客户满意度的提升、打造差异化竞争优势、加速产品上市。



IT系统更新频率




PIC5.jpg



在IT系统更新频率方面,每月都要更新、升级的比例达到了51.2%的高占比。同时,每3-6个月更新一次的比例达22%。每个传统领域,都受到了来自Fintech金融科技、车联网、物联网、新零售等新技术驱动的创新业务的挑战,传统企业只有借助IT手段才能实现持续发展,在速度和规模上保持竞争力。



IT系统和研发团队TOP 3挑战



pic6.jpg




本次参与调研的企业以中大型企业为主,其中研发团队规模达到100人以上的比例高达44.3%,20-100人规模的占32.4%。

PIC7.jpg




今天,许多企业都经过了大量IT建设,从分散到集中,造成IT系统越来越复杂,信息孤岛林立,架构臃肿等问题突出。调研中企业IT系统支撑所面临的压力位列前三的挑战分别是:系统复杂性越来越高(65.9%);应用交付压力大,交付速度无法满足业务需求(61.4%);运维管理复杂度提升,IT部门很难构建一支全功能团队(53.7%)。


PIC8.jpg



同时,研发团队所面临的挑战前三甲分别是:部署和运维复杂,运维成本高(74.6%);研发、测试、运维等角色之间相互孤立(62.3%);升级和变更流程复杂,IT服务和应用交付周期长(45.7%)。此外,比较突出的挑战还有,工具链无法完整集成,工具使用困难(32.3%),单体应用过于庞大,迭代效率低下(20.4%)。


pic9.jpg



上述结果充分表明,面对高度创新、快速变化和充满不确定性的新型业务需求,传统开发模式和IT架构已经成为掣肘。70.7%的参与调研企业表示2019年有容器、DevOps和微服务方面的规划和实施计划。

只有朝着持续交付、敏捷部署、快速迭代,通过敏捷IT赋予业务足够的敏捷,才能够满足不断变化的业务需求,重塑自身的生产力,形成竞争优势,带来更好的用户体验,这最终落到以Kubernetes/容器、DevOps和微服务为核心的云原生技术的落地上。云原生架构和理念与数字化转型一脉相承,帮助企业更加顺畅地实施数字化转型。



业务上云需求最强烈,开源、数字化转型受追捧



PIC10.jpg




在企业最关注的新兴技术趋势方面,云计算占比82.9%,企业将业务上云,提升IT资源效率作为首要关注对象。大数据和人工智能紧随其后,占比分别为73.2%和46.3%。其中开源解决方案在调研对象中的关注程度达到24.4%。

当前开源技术正在进入快速发展阶段,向着企业应用的方方面面深入。开源及开源社区不断将新的工具、方法和最佳实践用于云原生的实际业务用例,解决云原生用户的关键问题。借助许多开源解决方案,云原生部署的复杂性和难度也在得以降低。

此外,数字化转型的关注度为33.6%。如今每位IT从业者言必称数字化转型,IT能力也直接指向助力数字化转型。CIO和其他IT管理者已将企业的数字化计划置于新的高度,希望通过数字化来改变企业的商业和业务模式,数字化业务将从初步试验走向大规模应用。伴随企业数字化业务的不断成熟,预计未来几年,数字化转型将进入爆发阶段。



传统企业2019年IT预算稳中有升


PIC11.jpg





本次调研中,被调研企业今年IT工作的重点包括业务上云(56.1%),云原生、大数据、人工智能等新技术采用(53.7%),打造数字化团队,引领企业的数字化创新(43.9%),选择传统业务应用的比例不足20%。越来越多的企业将工作负载放在云端,将正在开发的应用或服务托管在云平台上,云市场不断增长。


PIC12.jpg



在IT预算方面,比客观经济形势略显乐观,和2018年IT预算相比,接近70%参与调研企业2019年的IT预算略有上浮,其中增长5%以内的企业占比37.5%,增长5-10%的企业占比21.2%,增长10%以上的企业达到12.7%。

此外,调研结果显示,数字化转型是一项需要通盘考虑的工作,需要项目管理部门、技术管理部门、开发部门、运维部门共同参与,制定统一的数字化转型方案和决策并推进。有些参与调研的企业特别强调2018年已经在全公司范围内试点了具有标杆意义的云原生实践,如精英团队的DevOps实践,小范围非核心应用的微服务拆分改造实践等,并且这些都将在2019年进行大范围推广。

容器云未来:Kubernetes、Istio 和 Knative

博云BoCloud 发表了文章 • 0 个评论 • 148 次浏览 • 2019-06-03 10:38 • 来自相关话题

导读 目前以Kubernetes为基础构建的容器生态逐渐完善,这其中Kubernetes、Istio、Knative三个独立项目被越来越多的人提及,并且已经开始尝试大规模落地实践,它们恰好构成了容器云的未来拼图。今天与大家一起分享下,这三个项目究 ...查看全部
导读
目前以Kubernetes为基础构建的容器生态逐渐完善,这其中Kubernetes、Istio、Knative三个独立项目被越来越多的人提及,并且已经开始尝试大规模落地实践,它们恰好构成了容器云的未来拼图。今天与大家一起分享下,这三个项目究竟解决了什么问题,为什么它们能够一鸣惊人。


随着微服务理念不断深入人心,越来越多的企业把自己的应用逐步由单体转变成微服务架构,Container容器技术的出现恰恰加速了这个转移过程,因为它有效地解决了N多服务的快速部署问题。但是随着服务数目的增多,越来越多的企业希望能够把相关服务有效地“聚合”在一起,方便统一部署与管理。Kubenretes的出现恰恰解决了大规模微服务编排部署所带来的挑战,让整个行业意识到PaaS的落地可以成为现实。

当随着微服务体系下的服务数目越来越多,服务运维成为必然要解决的问题,于是Istio出现了,基于网络代理与控制相分离的实现策略,允许对服务控制策略进行有效合理的管控。如果你想和更多容器技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

到这里似乎到了很美好的阶段:

微服务:解决应用内聚、臃肿的问题。
Container:解决服务运行环境统一,和部署问题。
Kubernetes:解决大量微服务有效“聚合”部署问题。
Istio:解决服务上线面临的一系列治理问题。

这个阶段乍一看来,构建容器云似乎有了一个完整的链路和解决方式,一切都将变得那么“完美”。

现在让我们回过头来深入分析一下,微服务体系下的服务交互,目前是否存在问题。

首先,无论是http,还是rpc,本质上都是服务与服务的远程调用。开发应用程序中,无法做到服务与服务间的彼此透明。这样会导致一个问题:无论微服务业务拆分多么“精细”,本质上业务单元之间还是不能够独立运行和发展。同时在面向不同开发领域的衍生,无法选择最合适的实现方式。因此我们希望能够基于不同的“模板”+“配置”的方式能够把开发环境标准化处理,同时提供“事件”机制,将服务与服务交互的耦合度降到最低。

其次,服务线上运行的动态伸缩问题。当下kubernetes环境下的弹性伸缩,需要由客户搜集监测数据,并自主手动来实现,但是我们更希望服务线上能够更加自动化和智能化。

最后,服务标准化问题。我们希望服务内部的模型是标准的、能够快速复制和快速构建的;服务通信是标准的:协议标准,格式标准;运行环境是标准的:快速部署,快速迁移。

Knative的出现恰好解决远程直接调用,服务线上自动管理以及一些列标准化问题。

下面我们来看一下三者的关联:


微信图片_20190603102740.png



Kubernetes和Istio相信大家比较熟悉了,这里不做过多介绍,有需要的同学可以关注下我们之前发布的相关文章,这里我们重点来看一下Knative。

Knative是谷歌开源的serverless架构方案,旨在提供一套简单易用的serverless方案,把serverless标准化。目前参与的公司主要是Google、Pivotal、IBM、Red Hat,于2018年7月份对外发布,目前处于快速发展阶段。


Knative组成


Build
构建系统:把用户定义的应用构建成容器镜像,面向kubernetes的标准化构建,区别于Dockerfile镜像构建,重点解决kubernetes环境的构建标准化问题。

Serving
服务系统:利用Istio的部分功能,来配置应用路由,升级以及弹性伸缩。Serving中包括容器生命周期管理,容器外围对象(service,ingres)生成(恰到好处的把服务实例与访问统一在一起),监控应用请求,自动弹性负载,并且利用Virtual service和destination配置服务访问规则。只有这样才能保证服务呈现一致性以及服务运行自动化管理。

Eventing
事件系统:用于自动完成事件的绑定与触发。事件系统与直接调用最大的区别在于响应式设计,它允许运行服务本身不需要屏蔽了调用方与被调用方的关系。从而在业务层面能够实现业务的快速聚合,或许为后续业务编排创新提供事件。

现在我们换一个角度,聚焦应用服务生命周期:
**· Knative 解决应用模板+面向统一环境的标准化构建场景;
· Kubernetes作为基础设施,解决应用编排和运行环境场景;
· 加粗文字Isito作为通信基础设施层,保证应用服务运行可检测、可配置、可追踪问题。**

这三者贯穿应用服务生命周期全过程,容器云恰恰也是管理应用服务的控制平台,这就能够很好地解释,为什么Kubernetes,Istio,Knative在未来会成为构建容器云的三驾马车。

GitLab CI/CD 在 Node.js 项目中的实践

尼古拉斯 发表了文章 • 0 个评论 • 137 次浏览 • 2019-06-03 09:58 • 来自相关话题

【编者的话】近期在按照业务划分项目时,我们组被分了好多的项目过来,大量的是基于 Node.js 的,也是我们组持续在使用的语言。 #现有流程中的一些问题 在维护多个项目的时候,会暴露出一些问题: 如何有效的使用 ...查看全部
【编者的话】近期在按照业务划分项目时,我们组被分了好多的项目过来,大量的是基于 Node.js 的,也是我们组持续在使用的语言。
#现有流程中的一些问题
在维护多个项目的时候,会暴露出一些问题:

  1. 如何有效的使用 测试用例
  2. 如何有效的使用 ESLint
  3. 部署上线还能再快一些吗

* 使用了 TypeScript 以后带来的额外成本

##测试用例
首先是测试用例,最初我们设计在了 git hooks 里边,在执行 git commit 之前会进行检查,在本地运行测试用例。 如果你想和更多 GitLab 技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态。

这会带来一个时间上的问题,如果是日常开发,这么操作还是没什么问题的,但如果是线上 bug 修复,执行测试用例的时间依据项目大小可能会持续几分钟。

而为了修复 bug,可能会采用 commit 的时候添加 -n 选项来跳过 hooks,在修复 bug 时这么做无可厚非,但是即使大家在日常开发中都采用commit -n 的方式来跳过繁琐的测试过程,这个也是没有办法管控的,毕竟是在本地做的这个校验,是否遵循这个规则,全靠大家自觉。

所以一段时间后发现,通过这种方式执行测试用例来规避一些风险的作用可能并不是很有效。
##ESLint
然后就是 ESLint,我们团队基于airbnb的 ESLint 规则自定义了一套更符合团队习惯的规则,我们会在编辑器中引入插件用来帮助高亮一些错误,以及进行一些自动格式化的操作。

同时我们也在 git hooks 中添加了对应的处理,也是在 git commit 的时候进行检查,如果不符合规范则不允许提交。

不过这个与测试用例是相同的问题:

  1. 编辑器是否安装 ESLint 插件无从得知,即使安装插件、是否人肉忽略错误提示也无从得知。
  2. git hooks 可以被绕过

##部署上线的方式
之前团队的部署上线是使用shipit周边套件进行部署的。

部署环境强依赖本地,因为需要在本地建立仓库的临时目录,并经过多次ssh XXX "command"的方式完成部署 + 上线的操作。

shipit提供了一个有效的回滚方案,就是在部署后的路径添加多个历史部署版本的记录,回滚时将当前运行的项目目录指向之前的某个版本即可。(不过有一点儿坑的是,很难去选择我要回滚到那个节点,以及保存历史记录需要占用额外的磁盘空间)

不过正因为如此,shipit在部署多台服务器时会遇到一些令人不太舒服的地方。

如果是多台新增的服务器,那么可以通过在shipit配置文件中传入多个目标服务器地址来进行批量部署。

但是假设某天需要上线一些小流量(比如四台机器中的一台),因为前边提到的shipit回滚策略,这会导致单台机器与其他三台机器的历史版本时间戳不一致(因为这几台机器不是同一时间上线的)

了这个时间戳就另外提一嘴,这个时间戳的生成是基于执行上线操作的那台机器的本地时间,之前有遇到过同事在本地测试代码,将时间调整为了几天前的时间,后时间没有改回正确的时间时进行了一次部署操作,代码出现问题后却发现回滚失败了,原因是该同事部署的版本时间戳太小,shipit 找不到之前的版本(shipit 可以设置保留历史版本的数量,当时最早的一次时间戳也是大于本次出问题的时间戳的)



也就是说,哪怕有一次进行过小流量上线,那么以后就用不了批量上线的功能了 (没有去仔细研究shipit官方文档,不知道会不会有类似--force之类的忽略历史版本的操作)

基于上述的情况,我们的部署上线耗时变为了: (__机器数量__)X(__基于本地网速的仓库克隆、多次 ssh 操作的耗时总和__)。 P.S. 为了保证仓库的有效性,每次执行 shipit 部署,它都会删除之前的副本,重新克隆

尤其是服务端项目,有时紧急的 bug 修复可能是在非工作时间,这意味着可能当时你所处的网络环境并不是很稳定。

我曾经晚上接到过同事的微信,让我帮他上线项目,他家的 Wi-Fi 是某博士的,下载项目依赖的时候出了些问题。

还有过使用移动设备开热点的方式进行上线操作,有一次非前后分离的项目上线后,直接就收到了联通的短信:「您本月流量已超出XXX」(当时还在用合约套餐,一月就800M流量)。
##TypeScript
在去年下半年开始,我们团队就一直在推动 TypeScript 的应用,因为在大型项目中,拥有明确类型的 TypeScript 显然维护性会更高一些。

但是大家都知道的, TypeScript 最终需要编译转换为 JavaScript(也有 tsc 那种的不生成 JS 文件,直接运行,不过这个更多的是在本地开发时使用,线上代码的运行我们还是希望变量越少越好)。

所以之前的上线流程还需要额外的增加一步,编译 TS。

而且因为shipit是在本地克隆的仓库并完成部署的,所以这就意味着我们必须要把生成后的 JS 文件也放入到仓库中,最直观的,从仓库的概览上看着就很丑(50% TS、50% JS),同时这进一步增加了上线的成本。

总结来说,现有的部署上线流程过于依赖本地环境,因为每个人的环境不同,这相当于给部署流程增加了很多不可控因素。
#如何解决这些问题
上边我们所遇到的一些问题,其实可以分为两块:

  1. 有效的约束代码质量
  2. 快速的部署上线

所以我们就开始寻找解决方案,因为我们的源码是使用自建的 GitLab 仓库来进行管理的,首先就找到了 GitLab CI/CD。

在研究了一番文档以后发现,它能够很好的解决我们现在遇到的这些问题。

要使用 GitLab CI/CD 是非常简单的,只需要额外的使用一台服务器安装 gitlab-runner,并将要使用 CI/CD 的项目注册到该服务上就可以了。

GitLab 官方文档中有非常详细的安装注册流程:

install | runner
register | runner
group register | repo 注册 Group 项目时的一些操作

上边的注册选择的是注册 group ,也就是整个 GitLab 某个分组下所有的项目。

主要目的是因为我们这边项目数量太多,单个注册太过繁琐(还要登录到 runner 服务器去执行命令才能够注册)
##安装时需要注意的地方
官网的流程已经很详细了,不过还是有一些地方可以做一些小提示,避免踩坑。
sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner

这是 Linux 版本的安装命令,安装需要 root (管理员) 权限,后边跟的两个参数:

* --user 是 CI/CD 执行 job (后续所有的流程都是基于 job 的)时所使用的用户名
* --working-directory 是 CI/CD 执行时的根目录路径 个人的踩坑经验是将目录设置为一个空间大的磁盘上,因为 CI/CD 会生成大量的文件,尤其是如果使用 CI/CD 进行编译 TS 文件并且将其生成后的 JS 文件缓存;这样的操作会导致 innode 不足产生一些问题

--user 的意思就是 CI/CD 执行使用该用户进行执行,所以如果要编写脚本之类的,建议在该用户登录的状态下编写,避免出现无权限执行 sudo su gitlab-runner



##注册时需要注意的地方
在按照官网的流程执行时,我们的 tag 是留空的,暂时没有找到什么用途。

以及 executor 这个比较重要了,因为我们是从手动部署上线还是往这边靠拢的,所以稳妥的方式是一步步来,也就是说我们选择的是 shell ,最常规的一种执行方式,对项目的影响也是比较小的(官网示例给的是 Docker)。
##.gitlab-ci.yml 配置文件
上边的环境已经全部装好了,接下来就是需要让 CI/CD 真正的跑起来
runner 以哪种方式运行,就靠这个配置文件来描述了,按照约定需要将文件放置到 repo 仓库的根路径下。

当该文件存在于仓库中,执行 git push 命令后就会自动按照配置文件中所描述的动作进行执行了。

* quick start
* configuration

上边的两个链接里边信息非常完整,包含各种可以配置的选项。

一般来讲,配置文件的结构是这样的:
stages:
- stage1
- stage2
- stage3

job 1:
stage: stage1
script: echo job1

job 2:
stage: stage2
script: echo job2

job 3:
stage: stage2
script:
- echo job3-1
- echo job3-2

job 4:
stage: stage3
script: echo job4

stages 用来声明有效的可被执行的 stage,按照声明的顺序执行。

下边的那些 job XXX 名字不重要,这个名字是在 GitLab CI/CD Pipeline 界面上展示时使用的,重要的是那个 stage 属性,他用来指定当前的这一块 job 隶属于哪个 stage。

script 则是具体执行的脚本内容,如果要执行多行命令,就像job 3那种写法就好了。

如果我们将上述的 stage、job 之类的换成我们项目中的一些操作install_dependencies、test、eslint之类的,然后将script字段中的值换成类似npx eslint之类的,当你把这个文件推送到远端服务器后,你的项目就已经开始自动运行这些脚本了。

并且可以在Pipelines界面看到每一步执行的状态。

P.S. 默认情况下,上一个 stage 没有执行完时不会执行下一个 stage 的,不过也可以通过额外的配置来修改:

* allow failure
* when

设置仅在特定的情况下触发 CI/CD

上边的配置文件存在一个问题,因为在配置文件中并没有指定哪些分支的提交会触发 CI/CD 流程,所以默认的所有分支上的提交都会触发,这必然不是我们想要的结果。

CI/CD 的执行会占用系统的资源,如果因为一些开发分支的执行影响到了主干分支的执行,这是一件得不偿失的事情。

所以我们需要限定哪些分支才会触发这些流程,也就是要用到了配置中的 only 属性。

使用only可以用来设置哪些情况才会触发 CI/CD,一般我们这边常用的就是用来指定分支,这个是要写在具体的 job 上的,也就是大致是这样的操作:

具体的配置文档
job 1:
stage: stage1
script: echo job1
only:
- master
- dev

单个的配置是可以这样写的,不过如果 job 的数量变多,这么写就意味着我们需要在配置文件中大量的重复这几行代码,也不是一个很好看的事情。

所以这里可能会用到一个yaml的语法:

这是一步可选的操作,只是想在配置文件中减少一些重复代码的出现



.access_branch_template: &access_branch
only:
- master
- dev

job 1:
<<: *access_branch
stage: stage1
script: echo job1

job 2:
<<: *access_branch
stage: stage2
script: echo job2

一个类似模版继承的操作,官方文档中也没有提到,这个只是一个减少冗余代码的方式,可有可无。
##缓存必要的文件
因为默认情况下,CI/CD在执行每一步(job)时都会清理一下当前的工作目录,保证工作目录是干净的、不包含一些之前任务留下的数据、文件。

不过这在我们的 Node.js 项目中就会带来一个问题。

因为我们的 ESLint、单元测试 都是基于 node_modules 下边的各种依赖来执行的。

而目前的情况就相当于我们每一步都需要执行npm install,这显然是一个不必要的浪费。

所以就提到了另一个配置文件中的选项:cache

用来指定某些文件、文件夹是需要被缓存的,而不能清除:
cache:
key: ${CI_BUILD_REF_NAME}
paths:
- node_modules/

大致是这样的一个操作,CI_BUILD_REF_NAME是一个 CI/CD 提供的环境变量,该变量的内容为执行 CI/CD 时所使用的分支名,通过这种方式让两个分支之间的缓存互不影响。
##部署项目
如果基于上边的一些配置,我们将 单元测试、ESLint 对应的脚本放进去,他就已经能够完成我们想要的结果了,如果某一步执行出错,那么任务就会停在那里不会继续向后执行。

不过目前来看,后边已经没有多余的任务供我们执行了,所以是时候将 部署 这一步操作接过来了。

部署的话,我们目前选择的是通过 rsync 来进行同步多台服务器上的数据,一个比较简单高效的部署方式。

P.S. 部署需要额外的做一件事情,就是建立从gitlab runner所在机器gitlab-runner用户到目标部署服务器对应用户下的机器信任关系。

有 N 多种方法可以实现,最简单的就是在runner机器上执行 ssh-copy-id 将公钥写入到目标机器。

或者可以像我一样,提前将 runner 机器的公钥拿出来,需要与机器建立信任关系时就将这个字符串写入到目标机器的配置文件中。

类似这样的操作:ssh 10.0.0.1 "echo \"XXX\" >> ~/.ssh/authorized_keys"
大致的配置如下:
variables:
DEPLOY_TO: /home/XXX/repo # 要部署的目标服务器项目路径
deploy:
stage: deploy
script:
- rsync -e "ssh -o StrictHostKeyChecking=no" -arc --exclude-from="./exclude.list" --delete . 10.0.0.1:$DEPLOY_TO
- ssh 10.0.0.1 "cd $DEPLOY_TO; npm i --only=production"
- ssh 10.0.0.1 "pm2 start $DEPLOY_TO/pm2/$CI_ENVIRONMENT_NAME.json;"

同时用到的还有variables,用来提出一些变量,在下边使用。

`ssh 10.0.0.1 "pm2 start $DEPLOY_TO/pm2/$CI_ENVIRONMENT_NAME.json;"`,这行脚本的用途就是重启服务了,我们使用pm2来管理进程,默认的约定项目路径下的pm2文件夹存放着个个环境启动时所需的参数。

当然了,目前我们在用的没有这么简单,下边会统一提到。

并且在部署的这一步,我们会有一些额外的处理。

这是比较重要的一点,因为我们可能会更想要对上线的时机有主动权,所以 deploy 的任务并不是自动执行的,我们会将其修改为手动操作还会触发,这用到了另一个配置参数:
deploy:
stage: deploy
script: XXX
when: manual # 设置该任务只能通过手动触发的方式运行

当然了,如果不需要,这个移除就好了,比如说我们在测试环境就没有配置这个选项,仅在线上环境使用了这样的操作。
##更方便的管理 CI/CD 流程
如果按照上述的配置文件进行编写,实际上已经有了一个可用的、包含完整流程的 CI/CD 操作了。

不过它的维护性并不是很高,尤其是如果 CI/CD 被应用在多个项目中,想做出某项改动则意味着所有的项目都需要重新修改配置文件并上传到仓库中才能生效。

所以我们选择了一个更灵活的方式,最终我们的 CI/CD 配置文件是大致这样子的(省略了部分不相干的配置):
variables:
SCRIPTS_STORAGE: /home/gitlab-runner/runner-scripts
DEPLOY_TO: /home/XXX/repo # 要部署的目标服务器项目路径

stages:
- install
- test
- build
- deploy_development
- deploy_production

install_dependencies:
stage: install
script: bash $SCRIPTS_STORAGE/install.sh

unit_test:
stage: test
script: bash $SCRIPTS_STORAGE/test.sh

eslint:
stage: test
script: bash $SCRIPTS_STORAGE/eslint.sh

# 编译 TS 文件
build:
stage: build
script: bash $SCRIPTS_STORAGE/build.sh

deploy_development:
stage: deploy_development
script: bash $SCRIPTS_STORAGE/deploy.sh 10.0.0.1
only: dev # 单独指定生效分支

deploy_production:
stage: deploy_production
script: bash $SCRIPTS_STORAGE/deploy.sh 10.0.0.2
only: master # 单独指定生效分支

我们将每一步 CI/CD 所需要执行的脚本都放到了 runner 那台服务器上,在配置文件中只是执行了那个脚本文件。

这样当我们有什么策略上的调整,比如说 ESLint 规则的变更、部署方式之类的。

这些都完全与项目之间进行解耦,后续的操作基本都不会让正在使用 CI/CD 的项目重新修改才能够支持(部分需要新增环境变量的导入之类的确实需要项目的支持)。
##接入钉钉通知
实际上,当 CI/CD 执行成功或者失败,我们可以在 Pipeline 页面中看到,也可以设置一些邮件通知,但这些都不是时效性很强的。

鉴于我们目前在使用钉钉进行工作沟通,所以就研究了一波钉钉机器人。

发现有支持 GitLab 机器人,不过功能并不适用,只能处理一些 issues 之类的, CI/CD 的一些通知是缺失的,所以只好自己基于钉钉的消息模版实现一下了。

因为上边我们已经将各个步骤的操作封装了起来,所以这个修改对同事们是无感知的,我们只需要修改对应的脚本文件,添加钉钉的相关操作即可完成,封装了一个简单的函数:
function sendDingText() {
local text="$1"

curl -X POST "$DINGTALK_HOOKS_URL" \
-H 'Content-Type: application/json' \
-d '{
"msgtype": "text",
"text": {
"content": "'"$text"'"
}
}'
}

# 具体发送时传入的参数
sendDingText "proj: $CI_PROJECT_NAME[$CI_JOB_NAME]\nenv: $CI_ENVIRONMENT_NAME\ndeploy success\n$CI_PIPELINE_URL\ncreated by: $GITLAB_USER_NAME\nmessage: $CI_COMMIT_MESSAGE"

# 某些 case 失败的情况下 是否需要更多的信息就看自己自定义咯
sendDingText "error: $CI_PROJECT_NAME[$CI_JOB_NAME]\nenv: $CI_ENVIRONMENT_NAME"

上述用到的环境变量,除了DINGTALK_HOOKS_URL是我们自定义的机器人通知地址以外,其他的变量都是有 GitLab runenr所提供的。

各种变量可以从这里找到:predefined variables
##回滚处理
聊完了正常的流程,那么也该提一下出问题时候的操作了。

人非圣贤孰能无过,很有可能某次上线一些没有考虑到的地方就会导致服务出现异常,这时候首要任务就是让用户还可以照常访问,所以我们会选择回滚到上一个有效的版本去。

在项目中的 Pipeline 页面 或者 Enviroment 页面(这个需要在配置文件中某些 job 中手动添加这个属性,一般会写在 deploy 的那一步去),可以在页面上选择想要回滚的节点,然后重新执行 CI/CD 任务,即可完成回滚。

不过这在 TypeScript 项目中会有一些问题,因为我们回滚一般来讲是重新执行上一个版本 CI/CD 中的 deploy 任务,在 TS 项目中,我们在 runner 中缓存了 TS 转换 JS 之后的 dist 文件夹,并且部署的时候也是直接将该文件夹推送到服务器的(TS项目的源码就没有再往服务器上推过了)。

而如果我们直接点击 retry 就会带来一个问题,因为我们的 dist 文件夹是缓存的,而 deploy 并不会管这种事儿,他只会把对应的要推送的文件发送到服务器上,并重启服务。

而实际上 dist 还是最后一次(也就是出错的那次)编译出来的 JS 文件,所以解决这个问题有两种方法:

  1. 在 deploy 之前执行一下 build
  2. 在 deploy 的时候进行判断

第一个方案肯定是不可行的,因为严重依赖于操作上线的人是否知道有这个流程。

所以我们主要是通过第二种方案来解决这个问题。

我们需要让脚本在执行的时候知道,dist 文件夹里边的内容是不是自己想要的。

所以就需要有一个 __标识__,而做这个标识最简单有效唾手可得的就是,git commit id。

每一个 commit 都会有一个唯一的标识符号,而且我们的 CI/CD 执行也是依靠于新代码的提交(也就意味着一定有 commit)。

所以我们在 build 环节将当前的commit id也缓存了下来:
git rev-parse --short HEAD > git_version

同时在 deploy 脚本中添加额外的判断逻辑:
currentVersion=`git rev-parse --short HEAD`
tagVersion=`touch git_version; cat git_version`

if [ "$currentVersion" = "$tagVersion" ]
then
echo "git version match"
else
echo "git version not match, rebuild dist"
bash ~/runner-scripts/build.sh # 额外的执行 build 脚本
fi

这样一来,就避免了回滚时还是部署了错误代码的风险。

关于为什么不将 build 这一步操作与 deploy 合并的原因是这样的:

因为我们会有很多台机器,同时 job 会写很多个,类似 deploy_1、deploy_2、deploy_all,如果我们将 build 的这一步放到 deploy 中。

那就意味着我们每次 deploy,即使是一次部署,但因为我们选择一台台机器单独操作,它也会重新生成多次,这也会带来额外的时间成本。
##hot fix 的处理
在 CI/CD 运行了一段时间后,我们发现偶尔解决线上 bug 还是会比较慢,因为我们提交代码后要等待完整的 CI/CD 流程走完。

所以在研究后我们决定,针对某些特定情况hot fix,我们需要跳过ESLint、单元测试这些流程,快速的修复代码并完成上线。

CI/CD 提供了针对某些 Tag 可以进行不同的操作,不过我并不想这么搞了,原因有两点:

  1. 这需要修改配置文件(所有项目)
  2. 这需要开发人员熟悉对应的规则(打 Tag)

所以我们采用了另一种取巧的方式来实现,因为我们的分支都是只接收Merge Request那种方式上线的,所以他们的commit title实际上是固定的:Merge branch 'XXX'。

同时 CI/CD 会有环境变量告诉我们当前执行 CI/CD 的 commit message。
我们通过匹配这个字符串来检查是否符合某种规则来决定是否跳过这些job:
function checkHotFix() {
local count=`echo $CI_COMMIT_TITLE | grep -E "^Merge branch '(hot)?fix/\w+" | wc -l`

if [ $count -eq 0 ]
then
return 0
else
return 1
fi
}

# 使用方法

checkHotFix

if [ $? -eq 0 ]
then
echo "start eslint"
npx eslint --ext .js,.ts .
else
# 跳过该步骤
echo "match hotfix, ignore eslint"
fi

这样能够保证如果我们的分支名为 hotfix/XXX 或者 fix/XXX 在进行代码合并时, CI/CD 会跳过多余的代码检查,直接进行部署上线。 没有跳过安装依赖的那一步,因为 TS 编译还是需要这些工具的。
#小结
目前团队已经有超过一半的项目接入了 CI/CD 流程,为了方便同事接入(主要是编辑 .gitlab-ci.yml 文件),我们还提供了一个脚手架用于快速生成配置文件(包括自动建立机器之间的信任关系)。

相较之前,部署的速度明显的有提升,并且不再对本地网络有各种依赖,只要是能够将代码 push 到远程仓库中,后续的事情就和自己没有什么关系了,并且可以方便的进行小流量上线(部署单台验证有效性)。

以及在回滚方面则是更灵活了一些,可在多个版本之间快速切换,并且通过界面的方式,操作起来也更加直观。

最终可以说,如果没有 CI/CD,实际上开发模式也是可以忍受的,不过当使用了 CI/CD 以后,再去使用之前的部署方式,则会明显的感觉到不舒适。(没有对比,就没有伤害

工作中99%能用到的Git命令

JetLee 发表了文章 • 0 个评论 • 115 次浏览 • 2019-06-03 09:09 • 来自相关话题

##分支操作 git branch 创建分支git branch -b 创建并切换到新建的分支上git checkout 切换分支git branch 查看分支列表git branch -v 查看所有分支的最后一次操作git bran ...查看全部
##分支操作

  1. git branch 创建分支
  2. git branch -b 创建并切换到新建的分支上
  3. git checkout 切换分支
  4. git branch 查看分支列表
  5. git branch -v 查看所有分支的最后一次操作
  6. git branch -vv 查看当前分支
  7. git brabch -b 分支名 origin/分支名 创建远程分支到本地
  8. git branch --merged 查看别的分支和当前分支合并过的分支
  9. git branch --no-merged 查看未与当前分支合并的分支
  10. git branch -d 分支名 删除本地分支
  11. git branch -D 分支名 强行删除分支
  12. git branch origin :分支名 删除远处仓库分支
  13. git merge 分支名 合并分支到当前分支上

##暂存操作

  1. git stash 暂存当前修改
  2. git stash apply 恢复最近的一次暂存
  3. git stash pop 恢复暂存并删除暂存记录
  4. git stash list 查看暂存列表
  5. git stash drop 暂存名(例:stash@{0})移除某次暂存
  6. git stash clear 清除暂存

##回退操作

  1. git reset --hard HEAD^ 回退到上一个版本
  2. git reset --hard ahdhs1(commit_id) 回退到某个版本
  3. git checkout -- file撤销修改的文件(如果文件加入到了暂存区,则回退到暂存区的,如果文件加入到了版本库,则还原至加入版本库之后的状态)
  4. git reset HEAD file 撤回暂存区的文件修改到工作区

##标签操作

  1. git tag 标签名 添加标签(默认对当前版本)
  2. git tag 标签名 commit_id 对某一提交记录打标签
  3. git tag -a 标签名 -m '描述' 创建新标签并增加备注
  4. git tag 列出所有标签列表
  5. git show 标签名 查看标签信息
  6. git tag -d 标签名 删除本地标签
  7. git push origin 标签名 推送标签到远程仓库
  8. git push origin --tags 推送所有标签到远程仓库
  9. git push origin :refs/tags/标签名 从远程仓库中删除标签

##常规操作

  1. git push origin test 推送本地分支到远程仓库
  2. git rm -r --cached 文件/文件夹名字 取消文件被版本控制
  3. git reflog 获取执行过的命令
  4. git log --graph 查看分支合并图
  5. git merge --no-ff -m '合并描述' 分支名 不使用Fast forward方式合并,采用这种方式合并可以看到合并记录
  6. git check-ignore -v 文件名 查看忽略规则
  7. git add -f 文件名 强制将文件提交

##Git创建项目仓库

  1. git init 初始化
  2. git remote add origin url 关联远程仓库
  3. git pull
  4. git fetch 获取远程仓库中所有的分支到本地

##忽略已加入到版本库中的文件

  1. git update-index --assume-unchanged file 忽略单个文件
  2. git rm -r --cached 文件/文件夹名字 (. 忽略全部文件)

##取消忽略文件

  1. git update-index --no-assume-unchanged file

##拉取、上传免密码

  1. git config --global credential.helper stor

原文链接:https://mp.weixin.qq.com/s/r7HVSeoBw48F9adI6v9aiw

从 400+ 节点 Elasticsearch 集群的运维中,我们总结了这些经验

齐达内 发表了文章 • 0 个评论 • 148 次浏览 • 2019-06-02 20:40 • 来自相关话题

在Kubernetes上运行Kafka合适吗?

whole 发表了文章 • 0 个评论 • 321 次浏览 • 2019-06-02 11:42 • 来自相关话题

【编者的话】本文介绍了在Kubernetes运行Kafka的互补性和一些坑,以及相关方案选择。 # 介绍 Kubernetes设计的初衷是运行无状态工作负载。这些通常采用微服务架构的工作负载,是轻量级,可水平扩展,遵循十二要素应用程序, ...查看全部
【编者的话】本文介绍了在Kubernetes运行Kafka的互补性和一些坑,以及相关方案选择。
# 介绍
Kubernetes设计的初衷是运行无状态工作负载。这些通常采用微服务架构的工作负载,是轻量级,可水平扩展,遵循十二要素应用程序,可以处理环形断路和随机Monkey测试。

另一方面,Kafka本质上是一个分布式数据库。这意味着你必须处理状态,它比微服务更重量级。Kubernetes支持有状态的工作负载,但你必须谨慎对待它,正如Kelsey Hightower在最近的两条推文中指出的那样:
1.png

现在你应该在Kubernetes上运行Kafka吗?我的反问是:没有它,Kafka会跑得更好吗?这就是为什么我要指出Kafka和Kubernetes之间的相互补充性以及你可能遇到的陷阱。
# 运行时
让我们先看一下基本的东西——运行时本身。
## 进程
Kafka brokers对CPU很友好。TLS可能会引入一些开销。如果Kafka客户端使用加密,则需要更多CPU,但这不会影响brokers。如果你想和更多Kubernetes技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态
## 内存
Kafka brokers是内存消耗大户。JVM堆通常可以限制为4-5 GB,但由于Kafka大量使用页面缓存,因此还需要足够的系统内存。在Kubernetes中,可以相应地设置容器资源限制和请求。
## 存储
容器中的存储是短暂的——重启后数据将丢失。可以对Kafka数据使用emptyDir卷,这将产生相同的效果:brokers的数据将在停机后丢失。您的消息在其他broker上作为副本还是可以使用的。因此,重新启动后,失败的broker必须得复制所有的数据,这可能是一个耗时过程。

这就是你应该使用持久存储的原因。使用XFS或ext4的非本地持久性块存储更合适。我警告你:不要使用NFS。NFS v3和v4都不会起作用。简而言之,Kafka broker会因为NFS“愚蠢重命名”问题而无法删除数据目录,自行终止。如果你仍然不相信我,那么请仔细阅读这篇博文。存储必须是非本地的,以便Kubernetes在重新启动或重新定位时可以更灵活地选择另一个节点。
## 网络
与大多数分布式系统一样,Kafka性能在很大程度上取决于低网络延迟和高带宽。不要试图将所有代理放在同一节点上,因为这会降低可用性。如果Kubernetes节点出现故障,那么整个Kafka集群都会出现故障。不要跨数据中心扩展Kafka集群。这同样适用于Kubernetes集群。不同的可用区域是一个很好的权衡。
# 配置
## 清单
Kubernetes网站包含一个非常好的教程,介绍如何使用清单设置ZooKeeper。由于ZooKeeper是Kafka的一部分,因此可以通过这个了解哪些Kubernetes概念被应用在这里。一旦理解,您也可以对Kafka集群使用相同的概念。

  • Pod:Pod是Kubernetes中最小的可部署单元。它包含您的工作负载,它代表群集中的一个进程。一个Pod包含一个或多个容器。整体中的每个ZooKeeper服务器和Kafka集群中的每个Kafka broker都将在一个单独的Pod中运行。
  • StatefulSet:StatefulSet是一个Kubernetes对象,用于处理需要协调的多个有状态工作负载。StatefulSets保证Pod的有序性和唯一性的。
  • Headless Services:服务通过逻辑名称将Pod与客户端分离。Kubernetes负责负载平衡。但是,对于ZooKeeper和Kafka等有状态工作负载,客户端必须与特定实例进行通信。这就是 Headless Services发挥作用的地方:作为客户端,仍然可以获得逻辑名称,但不必直接访问Pod。
  • 持久卷:如上所述,需要配置非本地持久块存储。

Yolean提供了一套全面的清单,可以帮助您开始使用Kubernetes上的Kafka。

## Helm Charts
Helm是Kubernetes的包管理器,类似yum,apt,Homebrew或Chocolatey等OS包管理器。它允许您安装Helm Charts中描述的预定义软件包。精心设计的Helm Charts能简化所有参数正确配置的复杂任务,以便在Kubernetes上运行Kafka。有几张图表适用于Kafka的的可供选择:一个是处于演进状态的官方图表,一个来自Confluent,另一个来自Bitnami,仅举几例。
## Operators
由于Helm的一些限制,另一种工具变得非常流行:Kubernetes Operators。Operators不仅可以为Kubernetes打包软件,还可以为Kubernetes部署和管理一个软件。

评价很高的Operators名单中提到Kafka有两个,其中一个是Strimzi,Strimzi使得在几分钟内启动Kafka集群变得非常容易,几乎不需要任何配置,它增加了一些漂亮的功能,如群集间点对点TLS加密。Confluent还宣布即将推出新的Operator。
## 性能
运行性能测试以对Kafka安装进行基准测试非常重要。在您遇到麻烦之前,它会为您提供有关可能的瓶颈的地方。幸运的是,Kafka已经提供了两个性能测试工具:kafka-producer-perf-test.sh和kafka-consumer-perf-test.sh。记得经常使用它们。作为参考,可以使用Jay Kreps博客结果,或者 Stéphane Maarek在 Amazon MSK的评论
# 运维
## 监控
可见性非常重要,否则您将不知道发生了什么。如今,有一种不错的工具可以用云原生方式监控指标。Prometheus和Grafana是两种流行的工具。Prometheus可以直接从JMX导出器收集所有Java进程(Kafka,ZooKeeper,Kafka Connect)的指标。添加cAdvisor指标可为提供有关Kubernetes资源使用情况的其他信息。

Strimzi为Kafka提供了一个优雅的Grafana仪表板示例。它以非常直观的方式可视化关键指标,如未复制的和离线分区。它通过资源使用和性能以及稳定性指标来补充这些指标。因此,可以免费获得基本的Kafka集群监控!
2.png

资料来源:https://strimzi.io/docs/master/#kafka_dashboard

可以通过客户端监控(消费者和生产者指标),使用Burrow滞后监控,使用Kafka Monitor进行端到端监控,来完成这个任务
## 日志记录
日志记录是另一个关键部分。确保Kafka安装中的所有容器都记录到标准输出(stdout)和标准错误输出(stderr),并确保Kubernetes集群将所有日志聚合到中央日志记录设施中如Elasticsearch中。
## 健康检查
Kubernetes使用活跃度和就绪探测器来确定Pod是否健康。如果活跃度探测失败,Kubernetes将终止容器并在相应设置重启策略时自动重启。如果准备就绪探测失败,那么Kubernetes将通过服务从服务请求中删除该Pod。这意味着在这种情况下不再需要人工干预,这是一大优点。
## 滚动更新
StatefulSets支持自动更新:滚动更新策略将一次更新一个Kafka Pod。通过这种方式,可以实现零停机时间,这是Kubernetes带来的另一大优势。
## 扩展
扩展Kafka集群并非易事。但是,Kubernetes可以很容易地将Pod缩放到一定数量的副本,这意味着可以声明式地定义所需数量的Kafka brokers。困难的部分是在放大或缩小之前重新分配部分。同样,Kubernetes可以帮助您完成这项任务。
## 管理
通过在Pod中打开shell,可以使用现有的shell脚本完成Kafka群集的管理任务,例如创建主题和重新分配分区。这不是一个很好的解决方案。Strimzi支持与另一个Operator管理主题。这还有改进的余地。
## 备份和还原
现在Kafka的可用性还取决于Kubernetes的可用性。如果Kubernetes群集出现故障,那么在最坏的情况下Kafka群集也会故障。墨菲定律告诉我们,这也会发生在你身上,你会丢失数据。要降低此风险,请确保您具有备份想法。MirrorMaker是一种可选方案,另一种可能是利用S3进行连接备份,如Zalando的博客文章所述。
# 结论
对于中小型Kafka集群,我肯定会选择Kubernetes,因为它提供了更大的灵活性并简化了操作。如果您在延迟和/或吞吐量方面具有非常高的非功能性要求,则不同的部署选项可能更有益。

原文链接:Kafka on Kubernetes — a good fit?(译者:姜俊厚)

Kubernetes 身份管理:身份验证

老马 发表了文章 • 0 个评论 • 178 次浏览 • 2019-06-01 09:47 • 来自相关话题

与其他复杂的系统一样,Kubernetes 拥有自己的安全模型来与用户、系统进行交互。在本文中,我将介绍 Kubernetes 的一些身份验证方案,并提供有关管理集群访问权限的示例和建议。 #身份对 Kubernetes 意味着什么 ...查看全部
与其他复杂的系统一样,Kubernetes 拥有自己的安全模型来与用户、系统进行交互。在本文中,我将介绍 Kubernetes 的一些身份验证方案,并提供有关管理集群访问权限的示例和建议。
#身份对 Kubernetes 意味着什么

首先,你需要明白在 Kubernetes 中,“什么是身份”?Kubernetes 与大多数其他系统和应用程序截然不同。它是一组 API,没有 “Web 界面”、没有“登录”、“会话”或“超时”等选项框。每个 API 请求都是唯一且不同的,并且它必须包含 Kubernetes 验证和授权请求所需的所有内容。

也就是说,你要牢记这样一个道理:Kubernetes 的用户不会存在于任何持久状态中。你不需要将 Kubernetes 连接到 LDAP 目录或 Active Directory 中,但是每个请求都必须存在一种方法可以对 Kubernetes ASSERT(断言)身份。我将 ASSERT 大写,是因为它将在后文变得十分重要。Kubernetes 不会对用户进行身份验证,它验证的是断言。如果你想和更多 Kubernetes 技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态
##服务账户

服务帐户正好与我们刚刚提到的规则相反。Kubernetes 不存储有关用户的信息,但它存储服务帐户的信息(该信息为任何非人的事物)。在 Kubernetes 中,与任何内容交互的东西都会被作为服务帐户运行。例如,如果你要提交一个非常基本的 Pod:
1.jpg

在部署后的 Kubernetes 中,你可以通过运行 kubectl get pod myapp-pod -o yaml 来查看它:
2.jpg

你会发现这里存在 serviceAccount 和 serviceAccountName 属性,这两者都是 default。此服务帐户由入口控制器链为使用者注入,你可以在 Pod 上设置自己的服务帐户。

服务帐户易于创建和使用,但它们有一些缺点:

* 服务帐户的令牌是一个很长的字符串,需要被记录下来。如果处理不当,它就有可能会被利用;
* 授权服务帐户的唯一方法是通过 RBAC 进行绑定;
* 在服务帐户还在使用期间时,如果一个人泄露了令牌并且未被发觉。它可能会被一直滥用,直到被处理为止。

在日常工作中,如果你的应用程序在一个 Pod 中运行并且需要与 API 服务器通信,你就可以通过挂载到 Pod 上的一个 secret 来检索 Pod 的服务帐户。

通过上面示例 YAML,你会发现一个挂载的卷被添加到了 /var/run/secrets/kubernetes.io/serviceaccount 中,这其中有一个令牌文件包含 Pod 的服务帐户令牌。你需要注意:不要将服务帐户令牌嵌入到集群中运行的 Pod 的 secret 或配置中!因为这样的做法会使得你使用旋转令牌(rotating token)变得更加困难,并且难以管理。
##用户账户

Kubernetes 不连接任何类型的用户存储(至少不直接连接)。这意味着在每个请求中,你必须为 Kubernetes 提供足够的信息以验证调用者的身份。Kubernetes 并不关心你如何建立身份,它只关心它如何证明身份是有效的。
#Kubernetes 如何知道你是谁

##OpenID Connect


OpenID Connect 是你用来验证用户身份的选项:

* OpenID Connect 令牌具有短暂性。当该类令牌被拦截或泄露时,如果攻击者得知该令牌的字符串,那么令牌就没用了;
* 使用 OpenID Connect 的好处是:Kubernetes 永远不会拥有用户的凭据,它不可能泄漏 Kubernetes 没有的东西;
* OpenID Connect 提供的用户标识不仅可以提供用户名信息,还可以提供组信息。这使得它们通过 LDAP 目录或外部数据库管理访问变得更容易(你无需为单个用户创建 RBAC 绑定);
* 通过在 Kubernetes 和身份层之间添加“代理”,你可以更轻松地添加多种类型的身份验证,例如多因素身份验证;
* 大量的开源 OpenID Connect 可以与 Kubernetes 一起使用。

##OpenID Connect Primer

在深入研究如何使用 OpenID Connect 之前,你需要先了解一下该协议:

* OpenID Connect 是一个建立在 OAuth2 之上的断言生成协议;
* OAuth2 则是一个用于传输承载令牌授权的协议。

这两点似乎缺少一个词:认证!那是因为 OpenID Connect 不是身份验证协议。它不关心你如何进行身份验证。如果用户使用的是用户名和密码,那么一张智能卡或许看起来真的很值得信赖,但是 OpenID Connect 是一种用于生成、检索和刷新用户断言的协议。用户如何进行身份验证最终取决于 OpenID Connect 的实现。

OAuth2 是一个比较关键的协议,它可以用于传递令牌,但是它没有定义令牌是什么或如何使用。它只是定义了令牌和依赖方之间如何传递令牌。
#Kubernetes 如何使用 OpenID Connect


图 1 显示了 Kubernetes 身份验证页面:
3.jpg

以下为该图的基础知识点:

* 用户可以登录到用户身份的提供程序中;
* 身份提供者会生成一个 id_token 和一个 refresh_token;
* id_token 可以将用户的身份断言为 Kubernetes 的;
* 当 id_token 过期时,refresh_token 用于生成新的 id_token。

一个 id_token 是一个 JSON Web Token(JWT),它可以表示:

* 用户是谁;
* 用户所属的组(可选);
* 令牌有效时长;
* 它包含一个数字签名,用于验证 JWT 是否未被篡改。

用户的 ID 属性 sub 通常是用户的唯一标识符。用户经常会使用 Active Directory 的登录 ID(也称为 samAccountName),还有一些人更喜欢使用电子邮件地址。一般来说,这不是最佳的做法。用户的 ID 应该是唯一的和不可变的。虽然电子邮件地址也是唯一的,但它并不总是不可变的(例如,有时名称会更改)。

JWT 将在从 kubectl 到 Kubernetes 的每个请求上传递。其中 id_token 被称为 “承载令牌”,因为它会授予承载者访问权限而无需任何额外的检查。这意味着,如果 API 调用流程中的系统泄漏此令牌,攻击者就可以滥用该系统了。

因为这些令牌很容易被滥用,所以它们的寿命极短。我推荐它们的使用寿命在一分钟左右。这样,如果当一个令牌被泄露时,即使攻击者知道它是什么,但是令牌也已经过期。使用此类短期令牌,最重要的是在它过期后,系统会配置一个 refresh_token 去更新你的 id_token。

kubectl 知道如何通过使用 refresh_token 调用标识提供者的授权服务 URL,并更新 id_token 令牌。

refresh_token 是 Kubernetes 的 API 服务器永远不会使用的令牌,用户可以将它视为 secret。该令牌用于获取新的 JWT,此时可以使用 JWT 中新的 refresh_token。如果 id_token 的生命周期非常短,则 refresh_token 超时与非活动超时类似,通常为 15-20 分钟。这样,你的 Kubernetes 实现将符合企业中针对不活动超时的策略。使用一个 refresh_token 获取一个新 id_token 内容比使用更长时间更安全,因为这个 refresh_token 意味着以下内容:

* 它只能使用一次。一旦使用,就会生成一个新的令牌;
* 它只在用户和身份提供者之间传递,在极少情况下会被泄露;
* 如果它自己被泄漏了,就不能被用来识别你。因为它是不透明的,所以如果没有额外的信息,攻击者根本不知道该如何处理它。

Kubernetes 仪表板

仪表板没有自己的登录系统。所有这一切都可以使用代表用户的现有令牌。这意味着在仪表板前面放置了一个反向代理,它将 id_token 在每个请求上注入 ,然后反向代理会根据需求刷新令牌。
#我应该使用哪个身份提供商

在选择身份提供商时,Kubernetes 实际上只有两个要求:

* 它必须支持 OpenID Connect 发现;
* 它提供了一种生成令牌并将其注入到 〜/.kube/config 的机制中。

只要符合以上两个要求,你就可以使用了。因为这种类型的身份提供商,它使你不必手动告诉 Kubernetes 不同的 URL 在哪里,用于签名的密钥是什么 ...... 将 Kubernetes 指向所有具有这种信息发现的 URL 就容易多了。因为大多数身份提供商都支持开箱即用(通用标准)。

而关于如何从你的登录点(通常是 Web 浏览器)将令牌信息添加到 〜/.kube/config 中,可以有不同的方法。
##Web 浏览器注入

在此模型中,所有内容都集中在你的 Web 浏览器上。你可以通过浏览器进行身份验证,然后获得正确设置 kubectl 客户机的命令。例如,OpenUnison(我们自己的项目)为你提供了一个命令,该命令可用于身份验证后设置集群的配置(图 2)。
4.png

图 2 浏览器令牌

你可以使用 kubectl 的内置功能从命令行配置配置文件以完成设置。

这种方法有几个优点:

* 浏览器具有最多的身份验证选项。除了用户名和密码,你还可以集成 Kerberos、Multi-Factor 等;
* 你不需要管理复杂的 Kubernetes 配置;
* 这种方法适用于 stock kubectl 命令。

Kubectl 插件

你可以使用插件扩展 kubectl 命令。使用插件,你可以收集用户的凭据,然后生成令牌。我看到过一些插件可以从 CLI 收集到你的凭证,还有一些插件可以启动浏览器提示你登录。从 CLI 角度来看,这种方法很好,因为它可以让你的 CLI 驱动你的用户体验。这种方法的主要缺点是需要在每个工作站上安装插件。

下载配置

使用此方法,身份提供程序(或自定义应用程序)可以为你提供用于下载的完整生成配置文件。但是,如果你没有将某些内容保存到正确的位置上,就可能会产生支持问题。

选择身份提供者后,请按照其说明进行集成,其中关键项是发现 URL、标识符“claim”以及组的“claim”。
##X509 证书

证书身份验证利用客户端(通常是 kubectl 命令)和 Kubernetes API 服务器之间的 TLS 握手,通过向 API 服务器提供证书来声明身份。除了一个用例之外,这种方法并不是 “最佳实践”:

* 证书不能在 Kubernetes 中撤销。你需要等到证书过期或重新生成整个集群后才可以撤销;
* 证书的私钥永远不离开生成它的安全介质。通常情况下,你会一起“获得”密钥对和证书;
* 使用带证书的组很困难,你需要将它们嵌入到 subject 中。

你可以使用 X509 证书来进行身份验证的情形是:当你在引导集群时,或者在紧急情况下,你的身份提供程序不可用。

大多数发行版都会为每个主服务器部署密钥对。因此,如果你 ssh 进入该主服务器,则可以使用它 kubectl 管理集群。这意味着你需要锁定对主服务器的访问权限。
##Webhook

此方法允许你通过 Webhook 集成第三方登录或令牌系统。Kubernetes 不会告诉你 Kubernetes 如何验证身份,而是调用 webhook 并询问“这是谁”。

除非你是云提供商并拥有自己的身份解决方案,否则请勿这样做。几乎我见过的每一个实现都变成了一个糟糕的 OpenID Connect。
##带模拟的反向代理

这里客户端(kubectl 或其他)不直接与 API 服务器通信。它会与反向代理进行通信,然后反向代理会将头部注入请求以表示用户。这通常被当作处理高级身份验证的一种方法,因为从 API 服务器的角度来看,它需要的工作量最少。实施步骤如下:

* 创建服务帐户;
* 授权服务帐户进行模拟;
* 配置反向代理以将服务帐户和模拟标头注入到每个请求中。

这个方案现有的标准可能会更适合用户的需求,因为它易于管理和维护。
#如何将身份整合到 Kubernetes 中

要将身份整合到 Kubernetes 中,请遵循以下基本核对清单:

* 仅将服务帐户用于系统,而不是人员;
* 建议使用 OpenID Connect。因为它会受到多种系统的审核和支持,包括开源和专有系统;
* 仅对“紧急情况”使用证书认证。

遵循这些规则,你会发现团队中的开发人员会很乐意记住身份验证的密码,安防人员也会很高兴地遵守合规性的要求。

参考文献:https://www.linuxjournal.com/content/kubernetes-identity-management-authentication

原文链接:https://mp.weixin.qq.com/s/9_mS5eet8WDSMJcBzQCelg

利用Helm简化Kubernetes应用部署

Andy_Lee 发表了文章 • 0 个评论 • 167 次浏览 • 2019-06-01 09:19 • 来自相关话题

【编者的话】如果需要自动化处理复杂的Kubernetes任务,常常需要编写Yaml配置文件。由于Yaml文件格式比较复杂,即使是老手有时也不免会犯错或需要查询文档,也有人开玩笑这是使用 Yaml 编程。我们今天将介绍几个方法来帮助大家来简化 Kubernete ...查看全部
【编者的话】如果需要自动化处理复杂的Kubernetes任务,常常需要编写Yaml配置文件。由于Yaml文件格式比较复杂,即使是老手有时也不免会犯错或需要查询文档,也有人开玩笑这是使用 Yaml 编程。我们今天将介绍几个方法来帮助大家来简化 Kubernetes Yaml 文件创建。

Kubernetes 提供了丰富的 kubectl 命令,可以较为方便地处理常见任务。如果需要自动化处理复杂的Kubernetes任务,常常需要编写Yaml配置文件。由于Yaml文件格式比较复杂,即使是老司机有时也不免会犯错或需要查询文档,也有人开玩笑这是使用 Yaml 编程。我们今天将介绍几个方法来帮助大家来简化 Kubernetes Yaml 文件创建。
#模拟命令执行
kubectl中很多命令支持 --dry-run 和 -o yaml 参数,可以方便地模拟命令执行,并输出yaml格式的命令请求,这样我们就可以将执行结果 Copy & Paste到自己的编辑器中,修改完成自己的配置文件。
$ kubectl run myapp --image=nginx --dry-run -o yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
creationTimestamp: null
labels:
run: myapp
name: myapp
spec:
replicas: 1
selector:
matchLabels:
run: myapp
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
run: myapp
spec:
containers:
- image: nginx
name: myapp
resources: {}
status: {}

$ kubectl create secret generic mysecret --from-literal=quiet-phrase="Shh! Dont' tell" -o yaml --dry-run
apiVersion: v1
data:
quiet-phrase: U2hoISBEb250JyB0ZWxs
kind: Secret
metadata:
creationTimestamp: null
name: mysecret

#导出资源描述
kubectl get --export -o yaml 命令会以Yaml格式导出系统中已有资源描述。

比如,我们可以将系统中 mysql 部署的描述导成 Yaml 文件。
$ kubectl get deployment mysql --export -o yaml > mysql.yaml 

#Kompose转换
Docker Compose是最为流行的容器编排开发工具,可以方便地在Docker/Docker Swarm环境下开发、部署容器编排模板。

Kompose是Kubernetes社区开发的一个转换工具,可以方便地将简单的Docker Compose模板转化成为Kubernetes的Yaml描述文件,并在Kubernetes集群上部署和管理应用。如果你想和更多Kubernetes技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

我们可以通过 https://github.com/kubernetes/kompose 获取最新的kompose 工具。

如下 docker-compose.yaml 模板描述了一个 WordPress 编排,其中包含两个服务,wordpress服务和mysql服务,为了将 wordpress服务暴露给外部访问,我们增加了一个 Kompose 特有的标签 kompose.service.type: nodeport,将服务以NodePort方式提供对外访问方式。
version: '2'
services:
wordpress:
image: wordpress:4
environment:
- WORDPRESS_DB_PASSWORD=password
ports:
- 80:80
depends_on:
- mysql
labels:
kompose.service.type: nodeport
mysql:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=password

我们可以通过kompose convert命令转换为 Kubernetes 的 Deployment和Service的资源描述:
$ kompose convert
WARN Unsupported depends_on key - ignoring
INFO Kubernetes file "mysql-service.yaml" created
INFO Kubernetes file "wordpress-service.yaml" created
INFO Kubernetes file "mysql-deployment.yaml" created
INFO Kubernetes file "wordpress-deployment.yaml" created

也可以通过kompose convert --stdout命令输出到标准输出
#总结
Kubernetes以其开放的平台和活跃的社区征服了众多用户,然而其陡峭的学习曲线也让初学者望而生畏。今天希望通过几个技巧帮助大家简化 Kubernetes Yaml 文件的编写。

原文链接:https://yq.aliyun.com/articles/341213

Nginx反向代理与负载均衡

aoxiang 发表了文章 • 0 个评论 • 148 次浏览 • 2019-06-01 09:05 • 来自相关话题

#学到老活到老 前端圈一直很新,一直要不停的学习,而且在进入大厂的路上,还要求熟悉一门后台语言等等。用一句别人开玩笑的话来说,Java十年前的技术现在还能用,而前端的技术就不是这样的了。 突然想起了deno项目发布的 ...查看全部
#学到老活到老

前端圈一直很新,一直要不停的学习,而且在进入大厂的路上,还要求熟悉一门后台语言等等。用一句别人开玩笑的话来说,Java十年前的技术现在还能用,而前端的技术就不是这样的了。

突然想起了deno项目发布的时候,一个搞笑的issue,“求别更新了,老子学不动了”。虽然看起来是一个玩笑的issue,但却道出了前端们不得不表现出来的疲态,知识点越来越庞大,学习的内容越来越多。

也听到一些朋友们说,换成现在再面试阿里,恐怕不好进了啊。当然很多都是随便一说的玩笑话,听过一笑便可,不必当真,也不必抱怨了
好了,今天就直接来说一下主题吧,前端要了解一些运维的Nginx用法,内容不多,简单看看就好,这两个功能在工作当中就够用了,那么首先来看个问题,什么是反向代理与负载均衡。如果你想和更多Nginx技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态。
#什么是反向代理与负载均衡

##什么是反向代理

当我们有一个服务器集群,并且服务器集群中的每台服务器的内容一样的时候,同样我们要直接从个人电脑访问到服务器集群服务器的时候无法访问,必须通过第三方服务器才能访问集群。

这个时候,我们通过第三方服务器访问服务器集群的内容,但是我们并不知道是哪一台服务器提供的内容,此种代理方式称为反向代理。
##什么是负载均衡

公司会建立很多的服务器,这些服务器组成了服务器集群,然后,当用户访问网站的时候,先访问一个中间服务器,再让这个中间服务器在服务器集群中选择一个压力较小的服务器,然后将该访问请求引入选择的服务器。

所以,用户每次访问,都会保证服务器集群中的每个服务器压力趋于平衡,分担了服务器压力,避免了服务器崩溃的情况。

一句话:Nginx会给你分配服务器压力小的去访问。
#Nginx反向代理与负载均衡的实现

用户访问网站的时候首先会访问Nginx服务器,然后Nginx服务器再从服务器集群中选择压力较小的服务器,将该访问请求引向该服务器。
##Nginx配置

下面修改配置方面我就从Mac系统下来进行简单的演示,如何安装的话也暂以Mac为主了,Windows系统直接去Nginx官网下载安装即可。
安装nginx
1-进到homebrew官网,然后复制命令,预安装需要的东西
2-brew install nginx 安装nginx
3-nginx -v 显示版本号
进入nginx
cd /usr/local/etc/nginx

下图为进入Nginx文件夹下的文件内容。
1.png

当进到这个目录下,我们就可以操作Nginx了,接下来就列举一些非常非常有用的命令,多敲几遍,一定要记住。

Nginx常用命令

* 启动Nginx

* Nginx
* 当你敲完Nginx这5个键的时候,并没有任何反应,此时你只需访问localhost:8080(默认)即可
2.png


* 关闭Nginx

* 如果出现下图情况,不要惊慌,是因为之前Nginx被启动过了
* 只需nginx -s stop,停止Nginx服务
* 然后再次启动Nginx即可
3.png


* 重启Nginx

* nginx -s reload
* 每次修改完.conf文件就需要重启nginx

* 检查配置

* 检查修改的nginx.conf配置是否正确
* nginx -t
* 如果出现下面ok和successfull就代表正确了,其他的都不对

 nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful


对于我们前端来说正常工作当中,倒是不需要过多的修改Nginx的。我们之所以修改Nginx配置,是为了做一些反向代理罢了。
##proxy_pass

Nginx反向代理主要通过proxy_pass来配置,将你项目的开发机地址填写到proxy_pass后面,正常的格式为proxy_pass URL即可:
server {
listen 80;
location / {
proxy_pass http://10.10.10.10:20186;
}
}

#Upstream模块实现负载均衡


* ip_hash指令
* server指令
* upstream指令及相关变量

上面写的三个指令,我们直接通过代码来一一分析:
// 修改nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
upstream firstdemo {
server 39.106.145.33;
server 47.93.6.93;
}
server {
listen 8080;
location / {
proxy_pass http://firstdemo;
}
}
}

上面修改的nginx.conf就是上图中花圈的那个文件,Nginx配置的主要修改就在这里。化繁为简,把原本nginx.conf里的内容直接替换为上面的不到20行的代码了。

既然不到20行,那就把里面对应的内容统统解释一下吧,有个了解就好

* worker_processes

* 工作进程数,和CPU核数相同

* worker_connections

* 每个进程允许的最大连接数

* upstream模块

* 负载均衡就靠它
* 语法格式:upstream name {}
* 里面写的两个server分别对应着不同的服务器

* server模块

* 实现反向代理
* listen监督端口号
* location / {}访问根路径
* proxy_pass http://firstdemo,代理到firstdemo里两个服务器上

上面修改了nginx.conf之后,别忘了最重要的一步重启Nginx。

那么再次访问localhost:8080,会看到如下图页面:
4.png

还有另一个页面:
5.png

每次刷新都会访问不同的服务器,这样就做到了负载均衡处理
不过,更应该做到的是当用户第一次访问到其中一台服务器后,下次再访问的时候就直接访问该台服务器就好了,不用总变化了。那么就发挥了ip_hash的威力了。
// 省略...
upstream firstdemo {
ip_hash;
server 39.106.145.33;
server 47.93.6.93;
}

ip_hash它的作用是如果第一次访问该服务器后就记录,之后再访问都是该服务器了,这样比如第一次访问是33服务器,那之后再访问也会分配为33服务器访问了。
#工作中的简单使用

在公司开发项目的时候,遇到设计,产品走查环节的时候,不能每次都让他们去配一个host,毕竟这样不友好,走查起来有麻烦。所以更应该给他们直观的感受,既给一个访问地址就可以看到样子。

下面给大家看一下,我正常在公司时nginx做的反向代理配置,和咱们上面的如出一辙,只是加了一个server_name,用指定的域名去访问即可。
server {
listen 80;
server_name chd.news.so.m.qss.test.so.com ;
auth_basic off;
location / {
proxy_pass http://10.10.10.10:20186;
proxy_set_header Host $host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 60;
proxy_read_timeout 600;
proxy_send_timeout 600;
}
}

每次修改完Nginx配置后不要忘记重启Nginx才能生效,这样只需要访问chd.news.so.m.qss.test.so.com这个地址就可以查看我的开发环境,进行走查了。

这就是Nginx最大的功能,反向代理我也接触的不是很多,毕竟不是专业运维出身,可比性差了很多。略知一二,也只是方便大家工作中使用吧,再次感谢大家的收看了,哈哈。

作者:chenhongdong
链接:https://juejin.im/post/5b01336af265da0b8a67e5c9