持续集成2--SpringCloud + Docker + Jenkins

682 阅读6分钟

一、基本框架

image.png

二、项目说明

image.png

image.png

image.png

image.png

三、本地部署

打包时通常使用mvn clean package,但是这种方式打包时不会将依赖进行打包,因此出来的jar包不可以单独使用,为了能够获取单独使用的jar包,需要在父工程中添加spring boot的打包插件

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.5.5</version>
        </plugin>
    </plugins>
</build>
  • springcloud-eureka-7001进行打包

mvn package spring-boot:repackage image.png

  • 查看jarimage.png

  • 运行jir

java -jar XXX.jar image.png

  • 查看效果 image.png

四、环境准备

4.1 Docker入门

(1)Docker简介

image.png

  • Docker是一个开源的应用容器引擎,基于Go语言,并遵循从Apache2.0协议开源。
  • Docker可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。 (Docker之前的虚拟化技术是虚拟机)
  • 容器是完全使用沙箱机制,相互之间不会有任何接口,更重要的是容器性能开销极低。

(2)Docker与传统虚拟机的对比

image.png

  • 虚拟机:底层是硬件设备,操作系统,之上是虚拟机软件,然后安装子系统,之后才可以安装软件。[至少要安装两层系统,一个在硬件上,一个在虚拟机上]
  • Docker:容器软件上面可以直接安装软件,只需要一层OS,更加透明,共享内核,减少开销
虚拟机容器
占用磁盘空间非常大,GB级小,MB甚至KB
启动速度慢,分钟级快,秒级
运行形态运行于Hypervisor上直接运行在宿主机内核上
并发性一台宿主机上十几个,最多几十个上百个,甚至数百上千
性能逊于宿主机接近宿主机本地进程
资源利用率

简单一句话总结:Docker技术就是让我们更加高效地将任何应用,在Linux服务器部署和使用

(3)Docker安装

1)安装必要的软件包

sudo yum install -y yun-util\
device-mapper-persistent-data\
lvm2

  • yum-utils是管理repository及扩展包的工具,包含一系列yum工具,提供了yum-config-manager
  • device mapper存储驱动程序需要device-mapper-persistent-datalvm2

2)设置下载Docker镜像的仓库地址

sudo yun-config-manager\
--add-repo\
https://download.docker.com/linux/centos/docker-ce.repo

  • yun-config-manager管理主要的yum配置选项,切换启用或禁用的存储库,以及添加新的存储库
  • --add-repo参数从指定文件或URL添加(和启用)软件仓库

3)列出安装的版本列表

yum list docker-ce --showduplicates |sort -r

image.png

4)安装指定版本

sudo yum install docker-ce-20.10.7.ce

5)查看版本号

docker -v image.png

6)启动docker

sudo systemctl start docker // 启动 sudo systemctl enable docker // 设置开机自启

7)添加阿里云镜像

vi /etc/docker/daemon.json

内容如下:

{
  "registry-mirrors": ["https://6x0hh8io.mirror.aliyuncs.com"]
}

其中值需要在阿里云搜索容器镜像服务,点击镜像加速器,会看到自动生成的加速器地址: image.png

(4)Docker基本命令快速入门

1)镜像相关的命令

镜像相当于是应用的安装包,在Docker部署的任何应用都需要先构建成镜像 镜像有两种基本的来源:

  • 仓库下载(Docker官方,自己部署的私有仓库)
  • 自己制作镜像
命令说明
docker search 镜像名称搜索镜像
docker pull 镜像名称拉取镜像
docker images查看本地所有镜像
docker rmi -f 镜像名称删除镜像

docker search openjdk image.png

docker pull openjdk:8-jdk-alpine image.png

2)容器相关的命令

容器是由镜像创建而来,现有镜像后有容器,容器是Docker运行软件的载体,每个应用都分别运行在Docker的每个容器中。

命令说明
docker run -i 镜像名称:标签运行容器(默认是前台运行)
-i 前台运行 -di 后台运行 -p 公开端口:容器端口 暴露端口号
docker start/stop/restart 容器名称/ID启动/停止/重启容器
docker rm -f 容器名称/ID删除容器
docker ps查看运行的容器
docker ps -a查询所有容器,包括停止的容器
docker exec -it 容器ID /bin/bash进入容器内部
  • 测试运行nginx镜像(前台) 使用docker pull下载nginx镜像 image.png

使用docker run -i nginx启动镜像 image.png

另开启一个终端通过docker ps命令查看容器运行状态 image.png

关闭运行nginx的终端,并通过docker ps -a可以查看关闭的容器 image.png

  • 测试运行nginx镜像并公开90端口(后台) 使用docker run -di -p 90:80 nginx image.png

通过IP访问nginx的90端口 image.png

4.2 Dockerfile镜像脚本

image.png

(1)Dockerfile简介

Dockerfile其实就是我们用来构建Docker镜像的指令集合,他可以让用户个性化定制Docker镜像,因为工作环境中的需求各种各样,网络上的镜像很难满足实际需求。

  • Dockerfile常见命令
命令作用
FROM image_name:tag从基础镜像上构建
MAINTAINER user_name声明镜像的作者
ENV key value设置环境变量(可多条)
RUN command编译镜像时运行的脚本(可多条)
CMD设置容器的启动命令
ENTRYPOINT设置容器的入口程序
ADD source_dir/file dest_dir/file将宿主机文件复制到容器中,如果是压缩文件将会自动解压
COPY source_dir/file dest_dir/fileADD类似,如果有压缩文件不能解压
WORKDIR path_dir设置工作目录
ARG设置编译镜像时加入的参数
VOLUMN设置容器的挂载卷
  • 镜像构建示意图 image.png 可以看到,新的镜像是从基础镜像一层一层叠加的,每安装一个软件,就在现有镜像的基础上增加一层

(2)使用Dockerfile制作微服务镜像

我们利用Dockerfile制作一个Eureka注册中心镜像

  • 上传Eureka的微服务jar包到Linux的/home目录下 image.png

  • 编写Dockerfile

因为要运行一个jar包,依靠JDK来运行,因此基础镜像为JDK镜像
从外部传入参数,用于拷贝jar包,将外部jar包拷到镜像内部并命名为app.jar
暴露7001端口
最后设置启动命令

FROM openjdk:8-jdk-alpine
ARG JAR_FILE
ADD ${JAR_FILE} /app.jar
EXPOSE 7001
ENTRYPOINT ["java", "-jar", "/app.jar"]
  • 构建镜像

docker build --build-arg JAR_FILE=springcloud-eureka-7001-1.0-SNAPSHOT.jar -t eureka:v1 . image.png

  • 查看构建结果 image.png

  • 运行Eureka容器 image.png

  • 验证构建结果 image.png

4.3 Harbor镜像仓库安装及使用

image.png image.png

Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,解决如何将本地Docker镜像传递到别的服务器上去。

除了Harbor这个私有镜像仓库之外,还有Docker官方提供的Registry,相比之下Harbor具有很多优势:

  • 提供分层传输机制,优化网络传输
    • Docker镜像是分层的,而如果每次传输都使用全量文件不经济,必须提供识别分层传输机制,以层的UUID为标识,确定传输对象
  • 提供WEB界面,优化用户体验
    • 只用镜像的名字进行传输很不方便,需要有一个用户界面以支持登录、搜索、区分公有私有镜像
  • 支持水平扩展集群
    • 当有用户对镜像的上传下载操作急用在某服务器,需要对相应的访问压力分解
  • 良好的安全机制
    • 企业中开发团队有不同的置位,能够分配不同的权限,具有更好的安全性

(1)Harbor安装--安装在Docker仓库服务器

  • 安装前应先确定已安装了Docker
  • 安装docker-composeHarbor安装时需要该软件
sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/dockercompose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose\
sudo chmod +x /usr/local/bin/docker-compose\

如果github使用不稳定,则用一下网址进行下载:

curl -L https://get.daocloud.io/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
  • docker-compose添加执行权限

sudo chmod +x /usr/local/bin/docker-compose

  • 查看docker-compose是否安装成功

docker-compose -version

image.png

  • 下载Harbor压缩包(v2.3.2

https://github.com/goharbor/harbor/releases

  • 上传Harbor压缩包并解压

tar -xzf harbor-offline-installer-v2.3.2.tgz
image.png

mkdir /opt/harbor
mv harbor/* /opt/harbor
cd /opt/harbor image.png

  • 修改Harbor的配置

vi harbor.yml
hostname: 192.168.117.37
port: 85

  • 安装Harbor

./prepare

如果提示ERROR:the protocol is https but attribute ssl_cert is not set image.png

运行完成后会自动下载一下配置文件: image.png

./install.sh

image.png

  • 启动Harbor

docker-compose up -d 启动
docker-compose stop 停止
docker-compose restart 重新启动

  • 访问Harbor

默认账户密码:admin/Harbor12345 image.png

(2)在Harbor创建用户和项目

  • 创建项目 image.png image.png

(3)本地镜像上传

  • 给镜像打上标签

docker tag eureka:v1 192.168.117.87:85/springcloud/eureka7001:v1

image.png

  • 推送镜像

docker push 192.168.117.87:85/springcloud/eureka7001:v1

image.png

  • Harbor地址加入到Docker信任列表中

vi /etc/docker/daemon.json

{ 
    "registry-mirrors": ["https://zydiol88.mirror.aliyuncs.com"],
    "insecure-registries": ["192.168.117.87:85"]
}

可能出现的一些问题:

  • 有可能会出现重启失败,是因为使用阿里云镜像配置的问题,只需要将daemon.json修改为daemon.conf重启即可
  • 如果报错为Error response from daemon...,是因为Docker自从1.3.X之后docker registry交互默认使用的是HTTPS,但是搭建私有镜像默认使用的是HTTP服务,所以与私有镜像交时出现以上错误。解决方法为在docker server启动的时候,增加启动参数,默认使用HTTP访问。

vim /usr/lib/systemd/system/docker.service image.png 然后重启Docker: systemctl restart docker

  • 如果显示权限不够,应当使用docker login登录后重新push image.png

image.png

查看效果: image.png

(4)测试服务器从Harbor中下载镜像

image.png 测试服务器也需要下载Docker,添加Harbor的新人列表,操作如上小结所述,此处不再赘述。
image.png

五、Jenkins + Docker + SpringCloud

5.1 整体流程

image.png

  • 将SpringCloud项目代码上传到Gitlab服务器
  • Jenkins从Gitlab拉取代码
  • 提交到SonarQube代码审查
  • 使用Dockerfile编译生成镜像
  • 上传到Harbor镜像仓库
  • 测试机拉取镜像并发布应用 上述过程通过Jenkins流水线项目演示完成

5.2 上传代码

  • IDEA中点击VCS->Enable Version Control Integration->选择Git
  • 项目父工程右键点击Git->add
  • Git->Commit Directory
  • Git->Repository->Remotes->粘贴GitLabclone的地址
  • Git->Repository->push

image.png

5.3 从Jenkins中拉取代码

  • 创建一个名为SpeingCloud的流水线项目 image.png

  • 将脚本直接写在IDEA项目SpringCloud中,因此Jenkins只需要拉取脚本即可。
    image.png

  • 在IDEA中创建Jenkinsfile并生成拉取代码的脚本 image.png

  • 生成的脚本中将一些参数写死,我们可以进行参数化构建,在Jenkins中勾选参数化构建: image.png

  • 重新编写脚本:
    image.png

  • 构建job:
    image.png

  • 查看构建结果 image.png

  • 查看源码 image.png

5.4 编译打包

  • 编译安装公共子工程

因为该工程不需要进行打包,因此应该将父工程中pom文件的build插件分别添加到需要打包的微服务中 image.png 服务器查看 image.png

  • 编译构建微服务工程 image.png

构建结果 image.png image.png 服务器查看 image.png

问题:在构建生产和消费模块的时候,由于依赖公共模块,构建失败 image.png

这个问题的原因是因为项目采用了父子工程,父工程中使用dependencyManagement进行依赖管理,然后在子工程中进行依赖的引入,然后子工程springcloud-consumer-dept-8080springcloud-provider-dept-8001使用了子工程springcloud-api中的实例,在本地的依赖库中找不到实例的jar包,因此需要对父工程进行编译安装,这样在本地依赖库中就有整个项目的结构,就能够找到对应的jar包。
image.png

在jenkins服务器中查看本地依赖库:
image.png

修改后能够正常打包:
image.png

5.5 使用Dockerfile编译、生成镜像

利用dockerfile-maven-plugin插件构建Docker镜像

  • 在每个微服务项目的POM中加入dockerfile-maven-plugin插件
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.5.5</version>
        </plugin>
        <!-- https://mvnrepository.com/artifact/com.spotify/dockerfile-maven-plugin -->
        <plugin>
            <groupId>com.spotify</groupId>
            <artifactId>dockerfile-maven-plugin</artifactId>
            <version>1.4.10</version>
            <configuration>
                <repository>${project.artifactId}</repository>
                <buildArgs>
                    <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
                </buildArgs>
            </configuration>
        </plugin>
    </plugins>
</build>
  • 添加Dockerfile文件 image.png

  • 添加构建脚本 image.png

  • 查看jenkins服务器执行job前的docker镜像 image.png

  • 执行job image.png

下载docker相关依赖,并执行dockerfile:
image.png

查看Jenkins服务器生成的镜像: image.png

5.6 上传镜像到Harbor服务器

  • Jenkins添加Harbor凭证 image.png

  • 通过凭证ID生成脚本 image.png

  • 修改脚本

// 脚本式语法结构
// Git凭证ID
def git_auth = "a73dc07c-4f1a-45cf-a8b3-f54c75629422"
// Git的URL地址
def git_url = "git@192.168.59.132:mygroup/springcloud.git"
// 镜像版本号
def tag = "latest"
// Harbor的url地址
def harbor_url = "192.167.117.87:85"
// Harbor的仓库名称
def harbor_preoject = "springcloud"
// Harbor登录凭证ID
def harbor_auth = "93d2878c-4678-4f9c-a52b-709b16cec99b"

node {
    stage('拉取代码') {
        checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [],
        userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
    }
    stage('安装父工程'){
        sh "mvn clean install"
    }
    stage('编译安装公共类和实体类'){
        sh "mvn -f springcloud-api clean install"
    }
    stage('编译打包微服务工程') {
        sh "mvn -f ${project_name} clean package spring-boot:repackage dockerfile:build"
    }
    stage('上传镜像') {
        // 定义镜像名称
        def imageName = "${project_name}:${tag}"
        // 打标签
        sh "docker tag ${imageName} ${harbor_url}/${harbor_preoject}/${imageName}"
        // 凭证
        withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password',usernameVariable: 'username')]) {
            // 登录
            sh "docker login -u ${username} -p ${password} ${harbor_url}"
            // 镜像上传
            sh "docker push ${harbor_url}/${harbor_preoject}/${imageName}"
            sh "echo '镜像上传成功'"
        }
    }
}
  • 查看结果 image.png

  • 查看Harbor服务器 image.png

5.7 测试服务器拉取镜像

安装Publish Over SSH 安装该插件可以实现远程发送Shell命令 通过ssh-copy-id IP将公钥发送至测试服务器

  • Jenkins配置插件 image.png

  • 生成部署脚本 image.png

  • 编辑脚本 image.png

  • Shell脚本

#! /bin/sh
# 接收外部参数
harbor_url=$1
harbor_preoject=$2
project_name=$3
tag=$4
prot=$5

imageName=$harbor_url/$harbor_preoject/$project_name:$tag

echo "$imageName"

# 查询容器是否存在,存在则删除
containerId=`docker ps -a | grep -w ${project_name}:${tag} | awk '{print $1}'`
if [ "$containerId" != "" ] ; then
    # 停掉容器
    docker stop $containerId
    # 删除容器
    docker rm $containerId
    echo "成功删除容器"
fi

# 查询镜像是否存在,存在则删除
imageId=`docker images | grep -w ${project_name} | awk '{print $3}'`
if [ "$imageId" != "" ] ; then
    # 删除镜像
    docker rmi -f $imageId
    echo "成功删除镜像"
fi

# 登录Harbor
docker login -u admin -p Harbor123456 $harbor_url

# 下载镜像
docker pull $imageName

# 启动容器
docker run -di -p $prot:$prot $imageName
echo "容器启动成功"
  • 启动job

启动前去看测试服务器中docker images image.png

Jenkins输出 image.png

测试服务器 image.png

访问 image.png