Docker-Jenkins-GitLab-Harbor实现Spring项目自动化部署(一)
Docker
简介
Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 OverlayFS 类的 Union FS 等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术。
由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。
传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
优点
- 更高效地利用系统资源:由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。
- 更快速的启动时间:传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。
- 一致的运行环境:开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 「这段代码在我机器上没问题啊」 这类问题。
- 持续交付和部署:使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile 来进行镜像构建,并结合 持续集成(Continuous Integration) 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 持续部署(Continuous Delivery/Deployment) 系统进行自动部署。而且使用 Dockerfile 使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。
- 更轻松的迁移:由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。
- 更轻松的维护和扩展:Docker 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker 团队同各个开源项目团队一起维护了一大批高质量的 官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。
基本概念
镜像(Image)
操作系统分为 内核 和 用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。
Docker 镜像 是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像 不包含 任何动态数据,其内容在构建之后也不会被改变。
因为镜像包含操作系统完整的 root 文件系统,其体积往往是庞大的,因此在 Docker 设计时,就充分利用 Union FS 的技术,将其设计为分层存储的架构。所以严格来说,镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成。
镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。
分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。
容器(Container)
镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。
镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为 容器存储层。
容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。
按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume)、或者 绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。
数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。
仓库(Repository)
镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务Docker Registry。
一个 Docker Registry 中可以包含多个 仓库(Repository);每个仓库可以包含多个 标签(Tag);每个标签对应一个镜像。
通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。
仓库名经常以 两段式路径 形式出现,比如 jwilder/nginx-proxy,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。
Docker Registry 公开服务
Docker Registry 公开服务是开放给用户使用、允许用户管理镜像的 Registry 服务。一般这类公开服务允许用户免费上传、下载公开的镜像,并可能提供收费服务供用户管理私有镜像。
最常使用的 Registry 公开服务是官方的 Docker Hub,这也是默认的 Registry,并拥有大量的高质量的 官方镜像。除此以外,还有 Red Hat 的 Quay.io;Google 的 Google Container Registry,Kubernetes ;代码托管平台 GitHub 推出的 ghcr.io。
由于某些原因,在国内访问这些服务可能会比较慢。国内的一些云服务商提供了针对 Docker Hub 的镜像服务(Registry Mirror),这些镜像服务被称为 加速器。常见的有 阿里云加速器、DaoCloud 加速器 等。使用加速器会直接从国内的地址下载 Docker Hub 的镜像,比直接从 Docker Hub 下载速度会提高很多。
国内也有一些云服务商提供类似于 Docker Hub 的公开服务。比如 网易云镜像服务、DaoCloud 镜像市场、阿里云镜像库 等。
私有 Docker Registry
除了使用公开服务外,用户还可以在本地搭建私有 Docker Registry。Docker 官方提供了 Docker Registry 镜像,可以直接使用作为私有 Registry 服务。
开源的 Docker Registry 镜像只提供了 Docker Registry API 的服务端实现,足以支持 docker 命令,不影响使用。但不包含图形界面,以及镜像维护、用户管理、访问控制等高级功能。
除了官方的 Docker Registry 外,还有第三方软件实现了 Docker Registry API,甚至提供了用户界面以及一些高级功能。比如,Harbor 和 Sonatype Nexus。
Docker Compose
Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。
Compose 使用的三个步骤:
- 使用 Dockerfile 定义应用程序的环境。
- 使用 docker-compose.yml 定义构成应用程序的服务,使得服务可以在隔离环境中一起运行。
- 最后,执行 docker-compose up 命令来启动并运行整个应用程序。
Jenkins
简介
Jenkins是开源软件项目,基于Java开发的持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。
Jenkins是一个可扩展的持续集成引擎。持续集成(Continues Integration)可以说是现代软件技术开发的基础。
持续集成是一种软件开发实践,即团队开发成员经常集成他们的工作,通常每个成员至少集成一次,也就意味着每天可能会发生多次集成。
Jenkins使得每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽快地发现集成错误。许多团队发现这个过程可以大大减少集成的问题,让团队能够更快的开发内聚的软件。
功能
- 软件的持续构建和测试,Jenkins提供了一个系统,使开发人员可以很容易的将改变集成到工程中。自动化的,持续的构建有利于提高开发效率。
- 监视job的执行,job可以实现很多的功能,Jenkins可以对这些项目进行显示,让用户更清楚地注意到损毁的job。
- 项目源代码修改的检测,Jenkins能够从项目的Subversion/CVS生成最近修改的集合列表,且不会增加Subversion/CVS Repository的负载。
- 分布式构建,Jenkins可以将工程构建到多台机器,更好地利用硬件资源,节省时间。
特性
- 易于安装:只要把jenkins.war包部署到servlet容器即可,不需要数据库的支持。
- 易于配置:所有的配置都是通过其提供的web界面实现的。
- 集成RSS/E-mail:通过RSS发布构建结果或当构建完成时通过E-mail通知相关人员以及负责人。
- 生成Junit/testNG/HTMLTestRunner测试报告。
- 分布式构建支持:Jenkins能够让多台计算机一起构建、测试。
- 文件识别:Jenkins能够跟踪构建生成的jar,甚至获取到jar的版本号信息等。
- 插件支持:支持扩展插件,可以安装或开发适合自己团队使用的工具。
- 多语言构建:Jenkins是基于Java开发的,但不仅限于构建基于Java的软件。
- 构件指纹(artifact fingerprint):每次build的结果构件都被很好的自动管理,无需任何配置就可以方便地浏览下载。
基本结构
CI流程:
- 开发者检入代码到源代码仓库。
- CI系统会为每一个项目创建了一个单独的工作区。当预设或请求一次新的构建时,它将把源代码仓库的源码存放到对应的工作区。
- CI系统在对应的工作区内执行构建过程。
- (配置如果存在)构建完成后,CI系统会在一个新的构件中执行定义的一套测试。完成后触发通知(Email,RSS等等)给相关的当事人。
- (配置如果存在)构建成功,构件会被打包并转移到一个部署目标(如应用服务器)或存储为软件仓库中的一个新版本。软件仓库可以是CI系统的一部分,也可以是一个外部的仓库,诸如一个文件服务器或像Java.net、SourceForge之类的网站。
- CI系统根据请求发起相应的操作,如即时构建、生成报告,或者检索一些构建好的构件等。
GitLab
简介
GitLab提供远程访问Git存储库的服务。 除了托管代码之外,这些服务还提供用来帮助管理软件开发生命周期的附加功能。 这些附加功能包括管理不同人之间的代码共享,错误跟踪,wiki空间和其他“社交编码”工具。
GitLab是一种类似GitHub的服务,组织可以使用它来提供Git存储库的内部管理。 它是一个自我托管的Git-repository管理系统,可以保持用户代码的私密性,并且可以轻松地部署代码的更改。
Git是一个源代码版本控制系统,可让用户代码在本地跟踪更改并从远程资源推送或提取更改。
特征
- GitLab免费托管您的(私人)软件项目。
- GitLab是管理Git存储库的平台。
- GitLab提供免费的公共和私人存储库,问题跟踪和维基。
- GitLab是Git之上的一个用户友好的Web界面层,它提高了使用Git的速度。
- GitLab提供了自己的持续集成(CI)系统来管理项目,并提供用户界面以及GitLab的其他功能。
优点
- GitLab提供了GitLab Community Edition版本,供用户在他们的代码所在服务器上进行定位。
- GitLab免费提供无限数量的私人和公共存储库。
- 代码片段可以共享项目中的少量代码,而不是共享整个项目。
缺点
- 在推拉(push/pull)仓库时,它并不像GitHub那么快。
- 从一个页面切换到另一个页面时,GitLab界面需要时间。
Harbor
简介
Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器。
作为一个企业级私有 Registry 服务器,Harbor 提供了更好的性能和安全。提升用户使用 Registry 构建和运行环境传输镜像的效率。Harbor 支持安装在多个 Registry 节点的镜像资源复制,镜像全部保存在私有 Registry 中, 确保数据和知识产权在公司内部网络中管控。另外,Harbor 也提供了高级的安全特性,诸如用户管理,访问控制和活动审计等。
特性
- 基于角色的访问控制 - 用户与 Docker 镜像仓库通过“项目”进行组织管理,一个用户可以对多个镜像仓库在同一命名空间(project)里有不同的权限。
- 镜像复制 - 镜像可以在多个 Registry 实例中复制(同步)。尤其适合于负载均衡,高可用,混合云和多云的场景。
- 图形化用户界面 - 用户可以通过浏览器来浏览,检索当前 Docker 镜像仓库,管理项目和命名空间。
- AD/LDAP 支持 - Harbor 可以集成企业内部已有的 AD/LDAP,用于鉴权认证管理。
- 审计管理 - 所有针对镜像仓库的操作都可以被记录追溯,用于审计管理。
- 国际化 - 已拥有英文、中文、德文、日文和俄文的本地化版本。更多的语言将会添加进来。
- RESTful API - RESTful API 提供给管理员对于 Harbor 更多的操控, 使得与其它管理软件集成变得更容易。
- 部署简单 - 提供在线和离线两种安装工具,也可以安装到 vSphere 平台(OVA 方式)虚拟设备。
CentOS8虚拟机安装
VMWare安装;
CentOS8虚拟机安装;
设置网络连接类型为:NAT模式;
根据虚拟网络编辑器设置静态IP;
关闭防火墙。
Docker安装
在 root 用户执行。(如果以一般用户执行,各命令行之前增加sudo。)
卸载老版本Docker
1 | yum remove docker \ |
安装Docker基础包
1 | yum install -y yum-utils \ |
设置Docker稳定仓库
1 | yum-config-manager \ |
安装Docker Engine和Containerd
1 | # 安装最新版本(latest) |
解决Podman问题
其他类似问题同理(如:containers-common)
1 | # 查看podman |
解决containerd.io版本过低
1 | wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.6-3.3.el7.x86_64.rpm |
解决podman-manpages包冲突问题
1 | # 查看podman-manpages |
启动测试Docker
1 | # 启动docker |
测试结果:
安装Compose
1 | # 下载 Docker Compose |
设置开机自启动Docker
1 | systemctl enable docker.service |
卸载Docker
1 | # 删除安装包 |
Jenkins安装
新建Jenkins安装目录
1 | mkdir -p /usr/local/docker/jenkins |
新建install.sh脚本
1 | !/bin/bash |
运行install.sh脚本
#! /usr/local/docker/jenkins 路径执行
bash install.sh
安装成功
基本配置
登录Jenkins
url:http://IP:8081 ,IP:Jenkins所在宿主机IP。
获取登录密码(两种方式)
从容器启动日志中获取管理密码
docker logs jenkins
从挂载目录/usr/local/docker/jenkins/jenkins_home中获取
cat /usr/local/docker/jenkins/jenkins_home/secrets/initialAdminPassword
自定义Jenkins
直接安装推荐的插件
进入插件安装界面,联网等待插件安装。
创建管理员账号
推荐插件安装完成后,创建管理员账号。
实例配置
进行实例配置,配置Jenkins的URL。
Jenkins URL 用于给各种 Jenkins 资源提供绝对路径链接的根地址。
Jenkins安装完成
自定义插件
点击 管理Jenkins -> 管理插件,进行一些自定义插件的安装。
安装 Publish Over SSH
安装 Publish Over SSH,远程ssh的插件。
安装完成,重启。
配置全局工具
Jenkins在联网环境中,勾选自动安装,直接安装全局工具到Jenkins的tools中,通过Jenkins脚本使用全局工具。
如果Jenkins在断网环境中,手动安装本机工具,建议不配置全局工具。因为在Docker环境下,Jenkins并不能找到本机安装的工具,除非把本机安装的工具的环境添加到Jenkins的Docker运行环境中。可直接通过Publish over SSH远程登录工具,本机使用全局工具。
但,如果Jenkins安装在本机,未通过Docker容器,可配置全局工具,通过Jenkins脚本使用全局工具。
通过 系统管理 -> 全局工具配置,进行全局工具的配置。配置构建项目需要的基本环境。
JDK配置
Gradle配置
SSH Server管理
系统管理 -> 系统配置 -> Publish over SSH(拉到底部)
Passphrase和Key二选一即可 。Passphrase是密码方式登录服务器,Key是免密码方式登录服务器。
Remote Directory: 填写当前用户有权限操作的,并且必须是已经存在的路径(例如用户的主目录)。
SSH服务器默认端口号是22,点击高级即可设置Port。
配置完成后,点击 Test Configuration,返回Success即证明Jenkins所在宿主机可以正常链接到待部署机。
备注:
- 添加多个部署机器时,默认是使用之前配置的Passphrase或Key,如果配置不一样,只需在高级中勾选Use password authentication, or use a different key,重新填写即可。
- 同时操作多台待部署服务器时,可以将Jenkins所在宿主机的public_key添加到所有待部署服务器上,这样Jenkins配置中只需要填写一个Key就可以免密登录服务器,而不必密码方式登录。
- 若需要多台,点新增再添加即可。需要注意的是,如果没有配置免密登录的话,需要点击高级,勾选Use password authentication,or use a different key,并在Passphrase/Password这一栏中输入部署机远程登录密码。
配置Publish over SSH
构建GitLab触发器
Gitlab通过Webhook配置来实现功能:当GitLab对应的分支有代码提交或合并请求时,自动触发执行对应的Jenkins任务。
安装相关插件
因为墙的原因,建议离线安装GitLab Hook,或在Jenkins所在机子搭建梯子。
过程中会自动安装ruby-runtime,这个plugin也建议离线安装或者搭建梯子安装。
- GitLab Plugin
- GitLab Hook Plugin
- Build Trigger Badge(安装Build Trigger Badge插件,可以在每个构建处看到被触发的原因。)
Jenkins安全配置
如果要使用GitLab的WebHook触发对应的任务,需要提前在Jenkins -> 全局安全配置中进行相应的设置。
GitLab安装
下载GitLab的Docker镜像
docker pull gitlab/gitlab-ce
新建GitLab安装目录
1 | mkdir -p /usr/local/docker/gitlab |
新建install.sh脚本
1 | #!/bin/bash |
需要注意的是,GitLab的http服务运行在宿主机的8082端口上。
并将GitLab的配置、日志及数据目录映射到宿主机的指定文件夹,以防止重新创建容器后丢失数据。
运行install.sh脚本
bash install.sh
安装成功
docker ps -a
访问GitLab
访问地址:http://IP:8082/ ,IP:GitLab所在宿主机IP。
通过docker命令动态查看容器启动日志,确定GitLab是否已经启动完成。
docker logs gitlab -f
GitLab启动比较慢,需要耐心等待一段时间。
如果GitLab没有启动完成,访问会出现502错误。
GitLab使用
重置root帐号的密码
用户密码长度不能小于8
docker ps
docker exec -it gitlab bash
gitlab-rails console -e production
user = User.where(id: 1).first
user.password = ‘secret_pass’
user.password_confirmation = ‘secret_pass’
user.save!
exit
# 退出容器
ctrl + D
输入帐号密码登录
选择创建项目、创建组织、创建帐号
创建组织
首先创建一个组织,然后在这个组织下分别创建用户和项目,这样同组织的用户就可以使用该组织下的项目。
创建用户并修改密码
修改密码
创建项目
勾选初始化README文件
将用户分配到组织
[GitLab][Webhook]设置允许本地连接
登录root账户,点击Configure Gitlab选项
进入Settings -> Network,展开Outbound requests,选中Allow requests to the local network from web hooks and services。
Git安装
Git客户端下载地址:https://git-scm.com/downloads
下载完成后,双击运行exe安装文件,一路点击Next完成安装。
clone项目
git clone url
url获取:
添加SSH key
更多Git提交代码、拉取代码等,详见Git官方教程。
Harbor安装
离线安装就下载离线安装包,其他同理。
下载Harbor安装文件
地址:https://github.com/goharbor/harbor/releases
解压:
解压到/usr/local/docker/harbor
修改 harbor.yml.tmpl 为 harbor.yml
chmod 777 install.sh
chmod 777 prepare
修改harbor.yml
hostname修改为IP
注释443及其域名证书配置
运行install.sh
./install.sh
安装成功
访问Harbor页面
url:http://IP ,IP为Harbor所在机子的IP。
输入用户名和密码,账号是admin,密码是在配置文件中配置的harbor_admin_password。
Docker容器内登录Harbor
Docker配置daemon.json,支持http方式登录Harbor。
在 /etc/docker/ 下修改daemon.json,没有的话,则新建。
# 192.168.198.200为Harbor宿主机的IP
{
“insecure-registries”: [“192.168.198.200”]
}
重启Docker
systemctl daemon-reload
systemctl restart docker
登录Harbor
# IP为Harbor访问IP
docker login http://IP
输入用户名+密码验证登录
开启Harbor命令
cd /usr/local/docker/harbor/
docker-compose up -d
Harbor设置自启动
编辑文件/lib/systemd/system/harbor.service
1 | [Unit] |
执行命令
systemctl enable harbor
systemctl start harbor
重启测试
Harbor网址访问正常。