用Docker和Jenkins进行持续集成
如何从Git中提取,构建Docker镜像,并将镜像发布到Docker Hub
持续集成和持续交付(CI/CD)的方法有很大的多样性。由于各种原因,用Docker容器化应用程序是一个常见的步骤。一旦容器化,CI管道的一个关键因素是在签入时建立一个镜像,运行测试,然后将镜像发布到Docker Hub(或其他注册中心),供下游步骤使用。
本文重点介绍如何设置Jenkins从GitHub上获取更新的应用程序代码,构建Docker镜像,运行测试,并将其发布到注册中心。
你将使用一个简单的Java应用来实现这一目的,但这个过程在不同的堆栈中是非常相似的。
发布到Docker Hub
本教程很好地介绍了Java、Jenkins和Docker的基础知识。我们将在这里更进一步,描述如何拉取最新的GitHub签到,建立应用程序的Docker镜像,如果成功的话,将其发布到Docker Hub。你需要一个Docker Hub账户,它是免费的。
发布到中央容器镜像仓库(在这里是Docker Hub)是企业CI/CD的一个关键因素,因为它为从QA和测试到生产等各个阶段重复使用工件提供了一个共同的位置。
旋起Jenkins和Docker-in-Docker
为了使Jenkins具备运行Docker的能力,我们将在一个虚拟机中运行两个Docker镜像。一个容器将承载 "Docker-in-Docker"(docker:dind镜像),用于访问Docker本身,另一个将承载Jenkins。这两个容器将通过网络和卷进行交互。这是Jenkins文档中所提倡的方法。
首先,在你选择的云提供商中创建一个新的虚拟机。我将使用谷歌云平台(GCP)。
启动这个架构的一个很好的方法是用一个已经安装了Docker和Docker-in-Docker镜像的虚拟机开始。在GCP控制台,我访问了计算引擎,并点击创建新实例。我使用的是一个相当强大的N1-Medium实例,因为Docker和Jenkins都是庞大的安装。
诀窍是选择安装镜像。对于镜像名称,使用docker:dind。这将确保Docker CLI是可用的。另外,将8080端口暴露给外部流量,因为Jenkins将在该端口上监听。
一旦你的虚拟机启动,确保Docker正在运行,输入docker --version 。
现在你要创建Docker网桥,Jenkins和Docker-in-Docker容器将共享该网桥。执行docker network create jenkins 。
设置Docker-in-Docker
虚拟机已经在运行docker:dind镜像,但我们要对它进行定制。所以输入docker container list ,找到容器的(前几个字符)UID,然后用docker stop 停止它。关于这些配置的详细情况,请查看文档。
现在用清单1中的命令重新启动Docker-in-Docker容器。
清单1.运行docker:dind
docker run --name jenkins-docker --rm --detach --privileged --network jenkins --network-alias docker --env DOCKER_TLS_CERTDIR="" --volume jenkins-docker-certs:/certs/client --volume jenkins-data:/var/jenkins_home --publish 2735:2375 --publish 2376:2376 docker:dind --storage-driver overlay2
清单1启动了docker镜像,同时监听端口2375,并参与你之前创建的Jenkins网络。注意,2375是一个非SSL端口;你的安全要求可能需要在2376上监听并提供适当的密钥。
运行Jenkins容器
现在我们将运行一个官方Jenkins镜像的实例,也参与网络桥接。运行清单3中的命令。
清单3.在容器中运行Jenkins镜像
sudo docker run --name my-jenkins --detach --network jenkins --env DOCKER_HOST=tcp://docker:2375 --volume /home/matthewcarltyson/jenkins:/var/jenkins --volume /usr/bin/docker:/user/bin/docker --publish 8080:8080 --publish 50000:50000 --user root jenkins/jenkins:lt
现在Jenkins正在运行,可以访问Docker。你应该可以在:8080处打到你正在运行的虚拟机。注意,这个命令中的几个标志是可选的--特别是,只有当你打算让Jenkins代理实例作为 "主 "调用这个实例时,才需要监听50000。
Jenkins系统密码
Jenkins在其日志中输出一个密码。网页会要求它。到虚拟机命令行,输入docker container list ,获得 "jenkins "实例的UID,输入docker logs --tail 50 ,获得管理员密码。
现在把管理密码输入到网页应用程序的表格中。
配置Jenkins
继续点击安装建议的插件。接下来你会被要求创建一个管理员用户。做到这一点。同时接受默认的IP地址,并在提示时重启服务器以加载插件。
添加Docker插件
有几个Docker插件可用。我们将使用一个命名为 "Docker插件 "的富有想象力的插件,它以最小的配置为你提供大量的功能。对于更详细的控制,你可以考虑使用docker-build-step插件,或者切换到流水线构建。
去管理Jenkins -> 插件 -> 可用的,在字段中输入 "docker"。选择 "Docker插件 "并安装它。
Jenkins把Docker插件称为 "云"。再次点击管理Jenkins,现在点击中间的管理云和节点按钮。现在点击左边的配置云。
这将允许你访问你先前创建的桥梁网络,并连接到运行Docker的容器。
对于名称,使用你会认识的东西,如 "Docker"。点击Docker Cloud Details,暴露Docker Host URI字段,并在那里输入 "tcp://docker:2375"。
保存它并返回到Jenkins仪表板。
设置Jenkins项目
现在我们将设置一个Jenkins项目,该项目将使用两个构建步骤--一个是从Git repo中提取最新代码并构建应用程序,另一个是构建镜像并将其推送到Docker Hub。这样做的目的是非常简单的;在现实世界中,应用程序可能是在Dockerfile或其他 "基础设施即代码"(IaC)工具中构建的。
点击主菜单中的新项目,选择自由式项目。给它一个你喜欢的名字。
在项目细节中,滚动到Build部分,选择Execute Shell Script,然后插入清单4的内容。
清单4.下载和构建simple-java的外壳脚本
#!/bin/sh
清单4中的脚本将检出或拉出在github.com/MTyson/simp… 找到的Java项目的最新源代码。这只是一个简单的 "Hello world "Spring Boot应用。拿到最新的源代码后,脚本会修改Maven命令的权限(在实际使用中,777的权限太高了),然后执行Maven构建。
使用Docker插件来构建和发布镜像
现在在shell脚本后添加一个构建步骤,选择构建/发布Docker镜像。在Docker文件的目录栏中,输入"./idg-java-docker"。这与你在上一步中使用的 repo 名称相吻合。
在云领域,选择你之前创建的 "Docker "云。
选择 "推送镜像 "复选框。
在图像字段中,你要把Docker Hub的用户或组织的名称(在我的例子中是Matttyson)放在斜线后面,然后是图像名称,也就是 "simple-java"。所以形式是用户名/simple-java。在我的例子中,matttyson/simple-java。
现在选择注册表凭证。在一个真实的项目中,你肯定会想使用一个秘密令牌(可在Docker.io创建),但我们在这里会保持简单,使用你在Docker Hub的用户名和密码。在凭证下,点击添加。将范围设为全局,并使用带有密码的用户名。现在只需添加你用来登录Docker网络应用的用户名和密码即可。
接受新凭证后,确保它被设置为我们正在配置的构建步骤中的用户。现在保存构建。
运行构建
现在点击顶部的项目名称,回到它的概述,然后点击左边的立即构建按钮。
过了一会儿,你会看到构建出现在左下方的列表中。点击它,选择左边的控制台输出,在构建过程中观察日志的进展。
当构建完成后,你可以通过浏览器导航到Docker Hub中的存储库列表,看到你新鲜出炉的新镜像,如图1所示。