关键词
封闭网络:一个相对封闭的网络环境,仅可以使用有限的资源如:maven镜像仓库、Centos/Ubuntu源等,无法连接互联网的网络环境。
一键部署:这里所说的“一键式部署”不仅仅是指这样的场景:“编码 --> 测试 --> 提交--> CI/CD --> 部署完成”。这里更多的是在描述:“在一个离线的网络环境下,运行一个deploy.sh的文件,就可以看到所有基础设施服务如:Nexus、Gitlab、Mongodb等已部署完成,然后在你编辑业务代码并提交至远程仓库时,会触发CI、编译、测试、打包、部署,至此所有的业务模块部署成功”,实现基础设施即代码。
背景
在这个互联网无处不在的时代,网络安全尤为重要,特别是在金融和电信领域,出现网络安全问题将会带来不可估量的损失。
基于对数据安全性、保密性和独立性的考虑,为了更好地提供服务,同时有效地保护内部网络的安全,我们需要将这些对外开放的主机与内部的众多网络设备分隔开来,制定安全策略限制互联网连接。这样便能在对外提供友好服务的同时,最大限度地保护内部网络,这也导致了内网无法连接互联网而形成一个“封闭网络”。
痛点
我们通常会有这样的需求:在一个无法连接互联网的环境下setup一套dev、qa、staging包括搭建CI等环境来供不同的角色使用,但是由于安全策略或其他安全限制导致一些基础服务无法从互联网获取,如Kubenetes、Mongodb、Kafka等基础组件服务,这就给自动化部署和持续交付带来了不便,特别是在系统对第三方服务依赖较多的情况下。
本文通过部署一套复杂系统为例,来描述如何在封闭网络环境下实现一键式部署。
解决方案
基于最主要的原因: "更轻松的迁移和扩展", 我们使用Docker来部署基础组件服务。
对于一个封闭的网络环境来说,要获取基础服务镜像如上文提到的Mongodb镜像是不可能完成的任务。当然,我们可以使用docker save将构建好的镜像保存成tar包,使用U盘等介质将tar包复制到内网然后使用docker load命令还原镜像。
对于较复杂(依赖相对较多的基础组件)的系统来说,如果每个组件都如此操作将会带来很大的工作量,并且更容易出错,对于后期维护来说也是一个很大的挑战。所以使用Nexus是一个很好的选择,将Nexus作为Docker仓库保存所有的基础组件镜像。 这样不仅可以解决离线网络无法下载安装包的问题,同时可以简化配置,并保持内网环境与开发环境的一致性,给一键式部署提供了前提。
解决了网络问题,接下来就是部署和配置管理。同样的道理,如果每个基础服务都需要手动部署往往比较耗时,难以实现故障排查,并且可能带来潜在错误。所以我们需要一个自动化部署工具来提高工作效率,降低维护成本。
经过对主流的自动化工具做横向对比,最终选择使用Ansible作为配置管理和自动化部署工具。那么Ansible是什么?下文会给出详细描述。
解决了上述问题,就可以实施离线网络自动化部署了,将整个过程分为3阶段,依次是:
- Base Deploy。主要部署所有服务所依赖的基础组件Docker、Nexus和Gitlab,Docker作为基础平台,Nexus和Gitlab也部署在Docker平台上,Nexus作为私有Maven仓库和私有Docker仓库,Gitlab作为私有远程代码库。
- Infrastructure Deploy。此阶段主要使用Ansible部署集群所依赖的基础服务如Kubernetes(Pass平台)、Kafka和Mongodb等服务。
- Business Deploy。最后一个阶段测试持续集成和持续部署的阶段,使用GoCD作为CI工具,在CI上实现业务服务模块的自动化部署。
实践如下图所示:
Base Deploy
如上文所述,使用Nexus作为私有的Docker Registry和Maven Repository,Nexus是仓库管理器,它极大地简化了自己内部仓库的维护和外部仓库的访问。利用Nexus你可以只在一个地方就能够完全控制访问和部署在你所维护仓库中的每个Artifact。
Nexus存储着所有基础设施的镜像文件,如Kubernetes、Mongodb、Zookeeper和Kafka的镜像等,同时需要一个Nexus镜像文件用来部署Nexus。为Infrastructure Deploy提供基础环境和部署中所有的依赖组件。
同时为了方便Nexus的迁移和维护,我们将Nexus也部署在Docker平台上。使用一个简单的Shell脚本完成Base Deploy,一次部署Docker、Nexus和Gitlab(Gitlab作为私有的git仓库)。Deploy.sh 代码如下:
#!/bin/bash
function init_docker {...} #安装docker
function load_images {...} #加载docker容器
function run_service {...} #启动nexus、gitlab等服务
function upload_nexus_data {...} #上传nexus数据
function upload_gitlab_data {...} #上传gitlab数据
for i in ${HOST_LIST[@]};do
init_docker $i
upload_data $2
run_service $1
done
`</pre>
PS: 运行deploy.sh 之前所有主机需要配置ssh public key登录, 避免自动化过程中提示输入密码。
运行deploy.sh即可部署Nexus和Gitlab。Nexus如下图所示,可以运行docker pull 获取所有组件的镜像包括kubernetes、ansible等
Git Lab如下图所示,也可以运行git clone 获取所有的代码仓库包括Infrastructure Deploy的部署脚本。
如果条件允许可以为Nexus和Gitlab创建DNS记录,或者可以通过修改本地/etc /hosts文件来通过使用特定域名访问Nexus和Gitlab,如下文中使用的nexus-server访问Nexus、gitlab-server访问Gitlab。
Infrastructure Deploy
上文提到我们使用Ansible来实现基础设施的自动化部署,我们知道目前主流的自动化部署工具包括Puppet、Chef、Ansible。 对比来说,Chef对于开发人员要更加“友好”,而Puppet则更适合运营和系统管理类的任务,但是我们选择Ansible,主要的原因是:
Ansible是通过ssh进行所有操作,不需要在远程服务器上安装客户端,而使用Chef引擎和Puppet时,都需要在其管理的服务器上安装客户端(虽然Chef声称其可以不安装,但其无代理agent-less版本支持的功能十分有限),Ansible则会充分利用现有的东西,而且没有其他任何要求[注]。
通俗的说Ansible的部署过程就是在一台或者几台服务器上,执行一系列的命令而已。Ansible playbook是Ansible更为强大的配置管理组件,实现基于文本文件编排执行的多个任务,且多次重复执行。所以我们选择Ansible作为配置管理和自动化部署工具。
Ansible工作原理如下图:
(图片来自Ansible官网)
使用Ansible使整个过程透明化,每个部署工作都实现为独立的ansible playbook role,这样可以在不同的环境里部署指定的服务,提高部署代码的复用性。同时与Nexus配合使用,形成自动化部署的闭环,不依赖网络即可提供部署中依赖的所有组件,所有的应用程序都会以Docker image的方式提供。
在离线环境下使用Ansible是完全可行的,但是离线环境也无法直接安装Ansible,为了统一管理我们也使用Docker镜像来提供Ansible。在内网成功部署了Nexus后,使用docker pull nexus-server:5000/:即可获得Ansible镜像。同时Ansible所需playbook role文件则保存在Gitlab中,执行git clone gitlab-server:2289/.git 下载deploy代码库。 deploy代码库结构如下:
<pre>`├── environments
│ └── uat
│ └── inventory
│ └── dev
│ └── inventory
├── roles
│ ├── docker
│ ├── kubernetes
│ ├── mongodb-cluster
├── docker.yml # 在PaaS集群所有VM节点安装docker
├── kubernetes.yml # 部署PaaS平台
├── mongodb-cluster.yml # 部署mongodb sharding 集群
└── all.yml
# all.yml 一键部署所有的基础设施
---
- include: mongodb-cluster.yml
- include: kubernetes.yml
- include: docker.yml
`</pre>
运行以下命令即可实现基础设施的一键自动部署:
<pre>`docker run --rm -v WORKDIR:$(pwd) ansible:2.2.1 ansible-playbook -i uat/inventory all.yml
Business Deploy
最后Business Deploy就是标准的持续集成/交付过程,使用GoCD作为CI/CD工具,完成业务模块的持续集成和部署。关于持续集成和持续交付,请参考https://en.wikipedia.org/wiki/Continuous_delivery/
总结
玩过红警的朋友应该知道,在开局的时候你只有一个基地,需要采集资源、升级建筑、造兵攻打直到消灭所有的国家,一切都是自给自足。当然红警是可以离线玩的, 上文描述的过程和红警很类似,你只有一个基地,就是将所有部署所需要的文件如Nexus data、Gitlab repo等按照特定的目录结构打成的zip包,使用U盘或者其他存储介质拷贝到离线的网络环境,就像双击红警基地一样,运行deploy.sh即可一键部署所有的基础设施服务。
对于所有组件的升级,也比较容易,我们只需要将升级后的Docker镜像拷贝到内网,重新执行Ansible脚本即可实现基础服务的更新。
注:关于Ansible与其他工具的对比部分引用自: