使用Jenkins、Docker和Ansible进行持续集成和交付

简介: 本文讲的是使用Jenkins、Docker和Ansible进行持续集成和交付,【编者的话】本文介绍了使用Docker、Jenkins等技术实现应用开发,测试到部署的自动化。它是一种探索。重点在于流程中的代码检测、测试、部署。部署后要做的事情没有涉及。会在后面文章中介绍。
本文讲的是使用Jenkins、Docker和Ansible进行持续集成和交付 【编者的话】本文介绍了使用Docker、Jenkins等技术实现应用开发,测试到部署的自动化。它是一种探索。重点在于流程中的代码检测、测试、部署。部署后要做的事情没有涉及。会在后面文章中介绍。

本文试图为您介绍一个设置持续集成、交付、部署工作流的可行方式。我会使用 Jenkins Docker Ansible Vagrant 来设置(配置)两个服务器。一个作为Jenkins的服务器,另一个用来模拟生产环境。前者用来检查代码、测试和构建应用程序,后者用来部署应用和后期测试。

你需要先安装好Vagrant和Git。剩下的一些工具我们会边介绍

CI/CD环境

我们将会使用Vagrant和Ansible构建Jenkins环境。Vagrant会新建一个Ubuntu虚拟机然后运行 bootstrap.sh 脚本。脚本的唯一目的是安装Ansible。一旦安装好,Ansible就可以下载Docker,并运行Jenkins进程。

Jenkins会被打包在一个Docker容器中,并通过Ansible部署。可以查看 Continuous Deployment: Implementation with Ansible and Docker 获取更多信息。

如果你不想自己实践,也可以克隆这个GitHub仓库 jenkins-docker-ansible 。一旦下载完成,我们就可以使用Vagrant启动 cd 虚拟机了。
git clone https://github.com/vfarcic/jenkins-docker-ansible.git
cd jenkins-docker-ansible
vagrant up cd

第一次在电脑上运行这条命令可能会花一些时间,所以我们可以利用Vagrant创建、配置虚拟机的时间来并行看下下面的步骤。

Vagrantfile 中有两行设置非常关键:
cd.vm.provision "shell", path: "bootstrap.sh"
cd.vm.provision :shell, inline: 'ansible-playbook /vagrant/ansible/cd.yml -c local'

首先运行 bootstrap.sh 脚本安装Ansible。我们可以使用 ANSIBLE PROVISIONER ,但是这需要我们在自己的主机上也安装Ansible。我觉得并没有必要,尤其是Windows的用户,在Windows上安装配置Ansible一点儿也不简单。此外,我们我们需要在虚拟机中安装Ansible以完成从 cd 部署应用到 prod

译者注:cd和prod是本文中启动的两个虚拟机的名字。顾名思义,cd指持续部署VM,prod指生产环境VM。
bootstrap.sh执行结束后,Ansible的配置文件 cd.yml 开始运行:
- hosts: localhost
remote_user: vagrant
sudo: yes
roles:
- java
- docker
- registry
- jenkins

Ansible会运行Java、Docker、Jenkins、Registry role。Jenkins需要Java来运行slaves。Docker用来构建和运行容器。剩下的应用会以Docker进程的方式来运行。这时就不需要直接下载依赖、包或者其它应用。Registry role会运行Docker Registry。

这里是Jenkins role的任务列表:
- name: Directories are present
file: path="{{ item }}" state=directory
with_items: directories
- name: Config files are present
copy: src='{{ item }}' dest='{{ jenkins_directory }}/{{ item }}'
with_items: configs
- name: Plugins are present
get_url: url='https://updates.jenkins-ci.org/{{ item }}' dest='{{ jenkins_directory }}/plugins'
with_items: plugins
- name: Build job directories are present
file: path='{{ jenkins_directory }}/jobs/{{ item }}' state=directory
with_items: jobs
- name: Build jobs are present
template: src=build.xml.j2 dest='{{ jenkins_directory }}/jobs/{{ item }}/config.xml' backup=yes
with_items: jobs
- name: Deployment job directories are present
file: path='{{ jenkins_directory }}/jobs/{{ item }}-deployment' state=directory
with_items: jobs
- name: Deployment jobs are present
template: src=deployment.xml.j2 dest='{{ jenkins_directory }}/jobs/{{ item }}-deployment/config.xml' backup=yes
with_items: jobs
- name: Container is running
docker: name=jenkins image=vfarcic/jenkins ports=8080:8080 volumes=/data/jenkins:/jenkins
- name: Reload
uri: url=http://localhost:8080/reload method=POST status_code=302
ignore_errors: yes

首先我们创建存放Jenkins插件和roles的目录。为了加快构建需要的容器,我们还在主机上创建了存放ivy文件(SBT可能需要用)的目录。这样每次构建Docker容器时不需要重复下载依赖了。

创建好目录后我们会复制Jenkins的文件和插件。

下一步是Jenkins的jobs。因为所有的jobs都会做相同的工作,所以我们根据需要使用两个模板( build.xml.j2 deployment.xml.j2 )来创建job。

最后,一旦job的配置文件传到Jenkins服务器里,我们就能确认Jenkins容器启动并且正确运行了。

所有的Ansible和Jenkins源代码都可以在 jenkins-docker-ansible 找到。

下面是 build.xml.j2 模板中的关键部分:
sudo docker build -t 192.168.50.91:5000/{{ item }}-tests docker/tests/
sudo docker push 192.168.50.91:5000/{{ item }}-tests
sudo docker run -t --rm
-v $PWD:/source
-v /data/.ivy2:/root/.ivy2/cache
192.168.50.91:5000/{{ item }}-tests
sudo docker build -t 192.168.50.91:5000/{{ item }} .
sudo docker push 192.168.50.91:5000/{{ item }}  

上面所有的  {{ item }}  都会被Ansible中的变量值代替。因为所有的构建job都执行相同的流程,对于所有的job我们可以使用相同的模板以及提供简单的变量值就够了。在这篇文章中, main.yml 中的变量值如下:
jobs:
- books-service

Ansible运行时,每个** {{ item }}  会被替换为 books-service  jobs**中的变量对应我们需要的item值。jobs中的变量不需要一次性匹配添加完但要根据需要逐步添加。

接着我们会看到下面这样:
jobs:
- books-service
- authentication-service
- shopping-cart-service
- books-ui

开始用Ansible部署时,来自模板的执行命令如下:
sudo docker build -t 192.168.50.91:5000/books-service-tests docker/tests/
sudo docker push 192.168.50.91:5000/books-service-tests
sudo docker run -t --rm
-v $PWD:/source
-v /data/.ivy2:/root/.ivy2/cache
localhost:5000/books-service-tests
sudo docker build -t 192.168.50.91:5000/books-service .
sudo docker push 192.168.50.91:5000/books-service

首先我们构建测试容器并push到私有registry中,然后运行测试。如果没有错误,我们会构建 books-service 容器,push到私有registry中。从这里开始, books-service已经完成了测试和构建,准备部署。

Docker出现之前,我所有的Jenkins服务构建到最后留下一堆job。因为使用大量不同的框架、语言和库,所以大部分job都不一样。管理大量的job很累人而且容易出错,这就不仅仅是复杂的问题了。管理slaves和依赖同样需要大量的时间。

Docker的出现简化了问题的复杂度。如果我们能保证每个项目有它自己的测试和应用容器,那所有的job就能做同样的事情了:构建测试容器并运行,若没有错误就构建应用容器并push到私有仓库。最后,我们只需要部署它。如果每个项目有它们自己的Dockerfile,那所有项目的构建流程都类似。另一个优点是因为有了Docker我们不需要在服务器上安装任何东西,我们唯一需要的就是能运行容器的Docker。

并不像构建job那样每次基本上都差不多,应用的部署会稍微复杂一些。虽然应用不可变并且被封装在容器里,但是仍然有一些环境变量、链接(link)和数据卷需要设置。这里就是Ansible施展拳脚的地方。我们可以使Jenkins的部署job相同但是它们的Ansible playbook名称不同。(译者注:这句个人理解不是太准确,贴出原句: We can have every Jenkins deployment job the same with only name of the Ansible playbook differing )。这样执行部署的job很容易运行部署应用的Ansible role了。这在大多数情况下都很简单。如果不使用Docker部署的话,两者的差异是巨大的。在使用Docker时我们只需要考虑数据(应用和依赖都被打包在容器里里了),没有Docker我们要考虑下载什么、更新什么以及这些变化会对服务器或虚拟机里的其它应用带来哪些影响。这也是企业不愿意更新技术栈的原因之一,例如,仍然使用java 5(或者更低)。

下面是Ansible中 books-service 中列出的例子:
- name: Directory is present
file:
path=/data/books-service/db
state=directory
- name: Latest container is pulled
shell: sudo docker pull 192.168.50.91:5000/books-service
- name: Container is absent
docker:
image=192.168.50.91:5000/books-service
name=books-service
state=absent
- name: Container is running
docker:
name=books-service
image=192.168.50.91:5000/books-service
ports=9001:8080
volumes=/data/books-service/db:/data/db
state=running 

我们要确保存储数据的目录存在,拉取最新的容器,移除运行中的进程启动新的。

让我们回来看文章开始时创建的 cd 虚拟机。如果 vagrant up cd 命令执行结束,那整个VM中的Jenkins、Docker和Registry都启动并运行起来了。

现在我们可以打开 http://localhost:8080 使用Jenkins了。Ansible的task没有创建凭证,我们需要手工创建。
  • 点击Manage Jenkins > Manage Nodes > CD > Configure
  • 点击Credentials部分的Add按钮
  • 输入vagrant作为用户名和密码,点击Add按钮
  • 选中Credentials部分新创建的key
  • 点击SaveLaunch slave agent

这些步骤本可以自动完成,但是安全起见我更喜欢手动配置。

现在启动了CD slave,它指向我们用Vagrant创建的cd虚拟机,并提供给所有的jobs使用(即使部署的job在另一台机器里执行)。

现在准备运行 books-service job。在Jenkins的主页,点击 books-service job ,就启动了第一次构建(也可以点击 Build now 手动构建),可以在 Build History 模块查看构建过程, Console Output 可以查看日志。第一次构建Docker容器可能会花一些时间。一旦job完成就会运行 books-service-deployment  job,但是我们仍然没有生产环境的VM而且Jenkins job运行的Ansible playbook也可能连不上生产环境的VM。一会儿我们再来考虑这个。现在我们将要做的是检测代码、运行测试、构建容器并push到私有registry中。

这种设置的主要优点是除了 cd 上的Docker外不需要再额外下载任何东西,因为所有一切都在容器里搞定了。我们就没必要为了下载提供编写和测试的各种框架、库而头疼了。也不会有不同版本应用间的依赖冲突了。最后,Jenkins的jobs也变得很简单,因为用于应用测试、构建、部署的逻辑全部放在了Docker文件里。换句话说,不管Jenkins要管理多少项目或应用,整个流程维护起来都很简单、一点儿不痛苦。

如果我们约定命名规范(比如本文中的例子),创建新的job就更简单了。要做的就是在Ansible配置文件 ansible/roles/jenkins/defaults/main.yml 中添加新的变量,运行 vagrant provision cd 或者直接在CD VM中运行  ansible-playbook /vagrant/ansible/cd.yml -c local

下面展示了如何将改变应用到CD服务器中(包括添加新的Jenkins Job):
[在主机的克隆仓库目录下执行]
vagrant provision cd

或者
vagrant ssh cd
ansible-playbook /vagrant/ansible/cd.yml -c local
exit

books-service 被安排每隔5分钟从仓库更新代码。这很耗资源且运行很慢。更好的设置是使用GitHub hook。有了DitHub hook只有每次push代码到仓库时才会触发构建。更多信息参见 GitHub Plugin  。类似的设置可以应用到任何其它类型的代码仓库。

生产环境

为了更贴近与真实情形,生产环境会另起一个虚拟机。目前还不需要在上面安装任何软件。随后Jenkins会运行Ansible,Ansible要确保服务器正确启动来部署每个应用。prod VM的创建方式和cd VM的相同。

[在克隆仓库目录执行命令]
vagrant up prod

cd 不同, prod 需要一个Ubuntu系统就够了,不需要包和额外的依赖。

现在我们启动并运行了 prod 环境,唯一剩下的是生成SSH Key并把它加到 cd 里。

[在克隆仓库目录执行命令]
vagrant ssh prod
ssh-keygen # Simply press enter to all questions
exit
vagrant ssh cd
ssh-keygen # Simply press enter to all questions
ssh-copy-id 192.168.50.92 # Password is "vagrant"
exit

所有要做的都在这了。我们也启动了部署应用的生产环境了。现在回到Jenkins ( http://localhost:808 0)运行 books-service-deployment  job,如果您到这一步时 books-service 还没执行结束,请耐心等待直到它结束, books-service-deployment 会自动开始。一切job都结束时,服务会被启动运行在9001端口。

现在我们添加一些信息到 books-service

[在克隆仓库目录执行命令]
vagrant ssh prod
curl -H 'Content-Type: application/json' -X PUT -d '{"_id": 1, "title": "My First Book", "author": "John Doe", "description": "Not a very good book"}' http://localhost:9001/api/v1/books
curl -H 'Content-Type: application/json' -X PUT -d '{"_id": 2, "title": "My Second Book", "author": "John Doe", "description": "Not a bad as the first book"}' http://localhost:9001/api/v1/books
curl -H 'Content-Type: application/json' -X PUT -d '{"_id": 3, "title": "My Third Book", "author": "John Doe", "description": "Failed writers club"}' http://localhost:9001/api/v1/books
exit

然后看看服务是否返回了正确的数据。在浏览器中打开 http://localhost:9001/api/v1/books 网址。你会看到之前用 crul 命令添加的3本书的信息。

我们的服务已经部署并且启动运行了。每次修改代码时,都会重复相同的流程:Jenkins会克隆代码、运行测试、构建容器、推送到registry,最后在目标服务器运行容器。

虚拟机创建,配置,构建和部署花了很多时间。但是,从现在开始大部分事情(Docker镜像IVY依赖等)下载后,再次运行的时候会非常快(不需要再重复下载)。只要把新建的Docker镜像push到registry。从这一刻起,快速就是整个流程最重要的优势了。

总结

有了Docker我们可以探索构建、测试、部署应用新的途径。容器技术的优点之一是它很简单,因为它具有不变性和自举的特点。这就没有什么理由让服务器下载运行大量依赖的包了。也不再需要做那些该死的维护不同版本应用或者是新建一个虚拟机来测试部署应用了。

Dokcer不仅让服务器配置变得简单。为每个配置提供Docker文件也意味着Jenkins job更易于维护。不再需要成百上千个jobs了并且每个job对应应用测试部署的文件都不同,有了Docker我们很简单就能让所有jobs都一样。用Dockerfile构建、测试,最后用Ansible部署Docker容器。(或者区其它工具比如 Fig

我们没有涉及到项目部署后的测试(功能测试、集成测试、压测等),这一步对成功的持续交付或部署是必须的。我们也漏掉了部署 零宕机 应用的方式。我们会在下一篇文章中的项目给出方法。(另一篇文章中)我们会在这次结束的地方开始,并且更深入地探索应用部署后要做的事情。

文章中涉及的源代码在这里 jenkins-docker-ansible 

原文链接:Continuous Integration, Delivery or Deployment with Jenkins, Docker and Ansible(翻译:adolphlwq)

==========================================

译者介绍  
adolphlwq ,南京信息工程大学本科大四学生。

原文发布时间为: 2015-09-13
本文作者:adolphlwq 
本文来自云栖社区合作伙伴DockerOne,了解相关信息可以关注DockerOne。
原文标题:使用Jenkins、Docker和Ansible进行持续集成和交付
目录
相关文章
|
1月前
|
存储 运维 安全
构建高效自动化运维体系:Ansible与Docker的完美结合
【2月更文挑战第31天】 随着云计算和微服务架构的兴起,自动化运维成为保障系统稳定性和提升部署效率的关键手段。本文将详细探讨如何通过Ansible和Docker的结合来构建一个高效、可靠且易于管理的自动化运维体系。首先,介绍自动化运维的必要性及其在现代IT基础设施中的作用;然后,分别阐述Ansible和Docker的技术特点及优势;最后,提供一个基于Ansible和Docker结合使用的实践案例,以及实施过程中遇到的挑战和解决方案。
|
1月前
|
运维 安全 网络安全
构建高效自动化运维体系:Ansible与Docker的完美融合
【2月更文挑战第30天】在当今快速迭代和持续部署的软件发展环境中,自动化运维成为确保效率和稳定性的关键。本文将探讨如何通过结合Ansible和Docker技术,构建一个高效的自动化运维体系。我们将分析Ansible的配置管理功能和Docker容器化的优势,并展示它们如何协同工作以简化部署流程,增强应用的可移植性,并提供一致性的系统环境。此外,文章还将介绍一些最佳实践,帮助读者在真实环境中实现这一整合方案。
|
19天前
|
jenkins 测试技术 持续交付
软件测试|docker搭建Jenkins+Python+allure自动化测试环境
通过以上步骤,你可以在Docker中搭建起Jenkins自动化测试环境,实现Python测试的自动化执行和Allure报告生成。 买CN2云服务器,免备案服务器,高防服务器,就选蓝易云。百度搜索:蓝易云
39 6
|
29天前
|
jenkins Java 持续交付
Docker搭建持续集成平台Jenkins最简教程
Jenkins 是一个广泛使用的开源持续集成工具,它能够自动化构建、测试和部署软件项目。在本文中,我们将使用 Docker 搭建一个基于 Jenkins 的持续集成平台。
113 2
|
1月前
|
JavaScript Java jenkins
如何利用CentOS7+docker+jenkins+gitee部署springboot+vue前后端项目(保姆教程)
如何利用CentOS7+docker+jenkins+gitee部署springboot+vue前后端项目(保姆教程)
84 0
|
1月前
|
jenkins Java 持续交付
Docker Swarm总结+Jenkins安装配置与集成(5/5)
Docker Swarm总结+Jenkins安装配置与集成(5/5)
51 0
|
1月前
|
jenkins Java 持续交付
Docker Swarm总结+Jenkins安装配置与集成snarqube和目标服务器(4/5)
Docker Swarm总结+Jenkins安装配置与集成snarqube和目标服务器(4/5)
44 0
|
jenkins Java Shell
使用 Docker 安装 Jenkins 并实现项目自动化部署
Jenkins 是一款开源的持续集成(DI)工具,广泛用于项目开发,能提供自动构建,测试,部署等功能。作为领先的开源自动化服务器,Jenkins 提供了数百个插件来支持构建、部署和自动化任何项目。
21948 2
使用 Docker 安装 Jenkins 并实现项目自动化部署
|
2月前
|
jenkins Java 持续交付
Docker 安装 Jenkins 2.414
【2月更文挑战第1天】 Docker 安装 Jenkins 2.414 镜像下载、插件配置
115 3
Docker 安装 Jenkins 2.414
|
2月前
|
jenkins 持续交付 数据安全/隐私保护
【Docker】安装Jenkins 亲测 傻瓜式安装
【Docker】安装Jenkins 亲测 傻瓜式安装
110 0