四、Jenkins+Docker+SpringCloud微服务持续集成(上)

JK+Docker+Cloud持续集成流程说明

大致流程说明:
1)开发人员每天把代码提交到Gitlab代码仓库
2) Jenkins从Gitlab中拉取项目源码,编译并打成jar包,然后构建成Docker镜像,将镜像上传到Harbor私有仓库。
3) Jenkins发送SSH远程命令,让生产部署服务器到Harbor私有仓库拉取镜像到本地,然后创建容器。
4)最后,用户可以访问到容器
服务列表(红色的软件为需要安装的软件,黑色代表已经安装)

服务器名称 IP地址 **安装的软件
代码托管服务器 192.168.66.100 Gitlab
持续集成服务器 192.168.66.101 Jenkins,Maven,Docker18.06.1-ce
Docker仓库服务器 192.168.66.102 Docker18.06.1-ce,Harbor1.9.2
生产部署服务器 192.168.66.103 Docker18.06.1-ce

SpringCloud微服务源码概述

项目架构:前后端分离
后端技术栈:SpringBoot+SpringCloud+SpringDataJpa(Spring全家桶)微服务项目结构:

  • tensquare_parent:父工程,存放基础配置
  • tensquare_common:通用工程,存放工具类
  • tensquare_eureka_server:SpringCloud的Eureka注册中心
  • tensquare_zuul:SpringCloud的网关服务
  • tensquare_admin_service:基础权限认证中心,负责用户认证(使用JWT认证)。他yaml里有euraka和jdbc、jwt
  • tensquare_gathering:一个简单的业务模块,活动微服务相关逻辑

数据库结构:

  • tensquare_user:用户认证数据库,存放用户账户数据。对应tensquare_admin_service微服务
  • tensquare_gathering:活动微服务数据库。对应tensquare_gathering微服务

微服务配置分析:启动顺序

  • tensquare_eureka
  • tensquare_zuul
  • tensquare_admin_service
  • tensquare_gathering

默认不能的登录,所以线通过网关进行登录,发送post请求进行登录

本地部署(1)-SpringCloud微服务部署

本地运行微服务

1)逐一启动微服务
2)使用postman测试功能是否可用

本地部署微服务

mvn clean package
此时打成的jar包里面没有maven里的依赖,所以不能独立启动
所以spring cloud可以boot的maven插件进行打包
1)SpringBoot微服务项目打包必须导入该插件

  1. org.springframework.boot
  2. spring-boot-maven-plugin
  • 1
  • 2
  • 3
  • 4

mvn clean package 打包后在target下产生jar包
2)本地运行微服务的jar包 java -jar xxx.jar
3)查看效果

本地部署(2)-前端静态web网站

前端技术栈:NodeJS+VueJS+ElementUI
使用Visual Studio Code打开源码 ,一般在env.js中改一下java后台的网关地址
1)本地运行
npm run dev
2)打包静态web网站
npm run build
打包后,产生dist目录的静态文件
3)部署到nginx服务器
把dist目录的静态文件拷贝到nginx的html目录,启动nginx
4)启动nginx,并访问
http://localhost:82

环境准备(1)-Docker快速入门

Docker简介

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

虚拟机 容器
占用磁盘空间 非常大,GB级 小,MB甚至KB级
启动速度 慢,分钟级 快,秒级
运行形态 运行于Hypervisor上 直接运行在宿主机内核上
并发性 一台宿主机上十几个,最多几十个 上百个,甚至数百上千个
性能 逊于宿主机 接近宿主机本地进程
资源利用率

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

Docker安装

1)卸载旧版本
yum -y remove docker的包名称 卸载docker包
rm -rf /var/lib/docker 删除docker的所有镜像和容器

  1. yum list installed | grep docker 列出当前所有docker的包
  • 1
  • 2
  • 3
  • 4

2)安装必要的软件包

  1. sudo yum install -y yum-utils \ device-mapper-persistent-data \ lvm2
  • 1

3)设置下载的镜像仓库
sudo yum-config-manager \ —add-repo \ https://download.docker.com/linux/centos/docker- ce.repo
4)列出需要安装的版本列表
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7PU178Ze-1624726844525)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image073.gif)]yum list docker-ce —showduplicates | sort -r

docker-ce.x86_64 3:18.09.1-3.el7 docker-ce-stable
docker-ce.x86_64 3:18.09.0-3.el7 docker-ce-stable
docker-ce.x86_64 18.06.1.ce-3.el7 docker-ce-stable
docker-ce.x86_64 18.06.0.ce-3.el7 docker-ce-stable

5)安装指定版本(这里使用18.0.1版本) sudo yum install docker-ce-18.06.1.ce
6)查看版本 docker -v
7)启动Docker
sudo systemctl enable docker 设置开机启动

  1. sudo systemctl start docker 启动
  • 1
  • 2
  • 3

8)添加阿里云镜像下载地址
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UYKzaVfk-1624726844525)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image073.gif)]vi /etc/docker/daemon.json
内容如下:

  1. {
  2. "registry-mirrors": ["https://zydiol88.mirror.aliyuncs.com"]
  3. }
  • 1
  • 2
  • 3

9)重启Docker
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z5UCzbvX-1624726844526)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image073.gif)]sudo systemctl restart docker

Docker基本命令

1)镜像命令
镜像:相当于应用的安装包,在Docker部署的任何应用都需要先构建成为镜像
# 镜像名称 搜索镜像 # 拉取镜像 # 查看本地所有镜像#删除镜像# 例子

  1. docker search
  2. docker pull 镜像名称
  3. docker images
  4. docker rmi -f 镜像名称
  5. docker pull openjdk:8-jdk-alpine
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2)容器命令
容器:容器是由镜像创建而来。容器是Docker运行应用的载体,每个应用都分别运行在Docker的每个容器中。
docker ps 查看运行的容器
docker ps -a
查询所有容器常用的参数:
-i:运行容器
-d:后台守方式运行(守护式)
—name:给容器添加名称
-p:公开容器端口给当前宿主机 # 常用 外部:内部
-v:挂载目录
docker exec -it 容器ID/容器名称 /bin/bash # 进入容器内部
docker start/stop/restart 容器名称/ID # 启动/停止/重启容器
docker rm -f 容器名称/ID # 删除容器

  1. docker run -i 镜像名称:标签 # 运行容器(默认是前台运行)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

    环境准备(2)-Dockerfile镜像脚本快速入门

    Dockerfile简介

    Dockerfile其实就是我们用来构建Docker镜像的源码,当然这不是所谓的编程源码,而是一些命令的组合,只要理解它的逻辑和语法格式,就可以编写Dockerfile了。
    简单点说,Dockerfile的作用:它可以让用户个性化定制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/file 和ADD相似,但是如果有压缩文件并不能解压
WORKDIR path_dir 设置工作目录
ARG 设置编译镜像时加入的参数
VOLUMN 设置容器的挂载卷/目录

RUN、CMD、ENTRYPOINT的区别?

  • RUN:用于指定 docker build 过程中要运行的命令,即是创建 Docker 镜像(image)的步骤
  • CMD:设置容器的启动命令, Dockerfile 中只能有一条 CMD 命令,如果写了多条则最后一条生效,CMD不支持接收docker run的参数。
  • ENTRYPOINT:入口程序是容器启动时执行的程序, docker run 中最后的命令将作为参数传递给入口程序 ,ENTRYPOINY类似于 CMD 指令,但可以接收docker run的参数 。

以下是mysql官方镜像的Dockerfile示例:

  1. FROM oraclelinux:7-slim
  2. ARG MYSQL_SERVER_PACKAGE=mysql-community-server-minimal-5.7.28
  3. ARG MYSQL_SHELL_PACKAGE=mysql-shell-8.0.18
  4. # Install server
  5. RUN yum install -y https://repo.mysql.com/mysql-community-minimal-releaseel7.rpm \
  6. https://repo.mysql.com/mysql-community-release-el7.rpm \
  7. && yum-config-manager --enable mysql57-server-minimal \
  8. && yum install -y \
  9. $MYSQL_SERVER_PACKAGE \
  10. $MYSQL_SHELL_PACKAGE \
  11. libpwquality \
  12. && yum clean all \
  13. && mkdir /docker-entrypoint-initdb.d
  14. VOLUME /var/lib/mysql
  15. COPY docker-entrypoint.sh /entrypoint.sh
  16. COPY healthcheck.sh /healthcheck.sh
  17. ENTRYPOINT ["/entrypoint.sh"]
  18. HEALTHCHECK CMD /healthcheck.sh
  19. EXPOSE 3306 33060
  20. CMD ["mysqld"]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

    使用Dockerfile制作微服务镜像

    我们利用Dockerfile制作一个Eureka注册中心的镜像
    1)上传Eureka的微服务jar包到linux
    2)编写Dockerfile

    1. FROM openjdk:8-jdk-alpine
    2. ARG JAR_FILE # 设置编译镜像时加入的参数
    3. COPY ${JAR_FILE} app.jar # 将宿主机的文件复制到容器内,并重命名
    4. EXPOSE 10086 # 暴露端口
    5. ENTRYPOINT ["java","-jar","/app.jar"] # 设置容器的入口程序(可以在运行中接收参数)
  • 1

  • 2
  • 3
  • 4
  • 5

3)构建镜像
指定jar包,传到镜像里

  1. docker build --build-arg JAR_FILE=tensquare_eureka_server-1.0-SNAPSHOT.jar -t eureka:v1 # 指定了JAR_FILE
  • 1

4)查看镜像是否创建成功

  1. docker images
  • 1

5)创建容器

  1. docker run -i --name=eureka -p 10086:10086 eureka:v1
  • 1

6)访问容器
http://192.168.66.101:10086

环境准备(3)-Harbor镜像仓库安装及使用

Harbor简介

Harbor(港口,港湾)是一个用于存储和分发Docker镜像的企业级Registry服务器。
除了Harbor这个私有镜像仓库之外,还有Docker官方提供的Registry。相对Registry,Harbor具有很多优势:

  • \1. 提供分层传输机制,优化网络传输 Docker镜像是是分层的,而如果每次传输都使用全量文件(所以用FTP的方式并不适合),显然不经济。必须提供识别分层传输的机制,以层的UUID为标识,确定传输的对象。
  • \2. 提供WEB界面,优化用户体验 只用镜像的名字来进行上传下载显然很不方便,需要有一个用户界面可以支持登陆、搜索功能,包括区分公有、私有镜像。
  • \3. 支持水平扩展集群 当有用户对镜像的上传下载操作集中在某服务器,需要对相应的访问压力作分解。
  • \4. 良好的安全机制 企业中的开发团队有很多不同的职位,对于不同的职位人员,分配不同的权限,具有更好的安全性。

    Harbor安装

    Harbor需要安装在192.168.66.102上面
    1)先安装Docker并启动Docker(已完成)参考之前的安装过程
    2)先安装docker-compose

    1. sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/dockercompose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
    2. sudo chmod +x /usr/local/bin/docker-compose
  • 1

  • 2

3)给docker-compose添加执行权限
sudo chmod +x /usr/local/bin/docker-compose
4)查看docker-compose是否安装成功
docker-compose -version
5)下载Harbor的压缩包 https://github.com/goharbor/harbor/releases
6)上传压缩包到linux,并解压

  1. tar -xzf harbor-oine-installer-v1.9.2.tgz mkdir /opt/harbor
  2. mv harbor/* /opt/harbor
  3. cd /opt/harbor
  • 1
  • 2
  • 3

7)修改Harbor的配置
修改hostname和port
hostname: 192.168.66.102
port: 85

  1. vi harbor.yml
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

8)安装Harbor
./install.sh

  1. ./prepare
  • 1
  • 2
  • 3

9)启动Harbor
docker-compose stop 停止
docker-compose restart 重新启动

  1. docker-compose up -d 启动
  • 1
  • 2
  • 3
  • 4
  • 5

10)访问Harbor http://192.168.66.102:85
默认账户密码:admin/Harbor12345

在Harbor创建用户和项目

1)创建项目
Harbor的项目分为公开和私有的:
公开项目:所有用户都可以访问,通常存放公共的镜像,默认有一个library公开项目。私有项目:只有授权用户才可以访问,通常存放项目本身的镜像。
我们可以为微服务项目创建一个新的项目
2)创建用户
3)给私有项目分配用户进入tensquare项目->成员

角色 权限说明
访客 对于指定项目拥有只读权限
开发人员 对于指定项目拥有读写权限
维护人员 对于指定项目拥有读写权限,创建 Webhooks
项目管理员 除了读写权限,同时拥有用户管理/镜像扫描等管理权限

4)以新用户登录Harbor,

把镜像上传到Harbor

1)给镜像打上标签
docker tag eureka:v1 192.168.66.102:85/tensquare/eureka:v1
2)推送镜像
docker push 192.168.66.102:85/tensquare/eureka:v1

  1. The push refers to repository [192.168.66.102:85/tensquare/eureka]
  2. Get https://192.168.66.102:85/v2/: http: server gave HTTP response to HTTPS client
  • 1
  • 2

这时会出现以上报错,是因为Docker没有把Harbor加入信任列表中(他信任dockerHUB)
3)把Harbor地址加入到Docker信任列表
{
“registry-mirrors”: [“https://zydiol88.mirror.aliyuncs.com“],
“insecure-registries”: [“192.168.66.102:85”]
}

  1. vi /etc/docker/daemon.json
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

需要重启Docker
4)再次执行推送命令,会提示权限不足

  1. denied: requested access to the resource is denied
  • 1

需要先登录Harbor,再推送镜像
5)登录Harbor
WARNING! Using —password via the CLI is insecure. Use —password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded

  1. docker login -u 用户名 -p 密码 192.168.66.102:85

重启docker
3)先登录,再从Harbor下载镜像
docker pull 192.168.66.102:85/tensquare/eureka:v1

  1. docker login -u 用户名 -p 密码 192.168.66.102:85
  • 1
  • 2
  • 3

    微服务持续集成(1)-项目代码上传到Gitlab

    在IDEA操作即可,参考之前的步骤。包括后台微服务和前端web网站代码

    微服务持续集成(2)-从Gitlab拉取项目源码

    在IDEA下
    1)创建Jenkinsfile文件
    //gitlab的凭证=”68f2087f-a034-4d39-a9ff-1f776dd3dfa8”{stage(‘拉取代码’){checkout([class:’GitSCM’,:[[:’*/${branch}’]],:false,:[],:[],:[[:”${git_auth}”,:’git@192.168.66.100: itheima_group/tensquare_back.git’]]])}} ```

defgit_auth node

  1. $
  2. branches
  3. name
  4. doGenerateSubmoduleConfigurations
  5. extensions
  6. submoduleCfg
  7. userRemoteConfigs
  8. credentialsId
  9. url
  1. - 1
  2. - 2
  3. - 3
  4. - 4
  5. - 5
  6. - 6
  7. - 7
  8. - 8
  9. - 9
  10. - 10
  11. - 11
  12. - 12
  13. - 13
  14. - 14
  15. - 15
  16. - 16
  17. - 17
  18. - 18
  19. - 19
  20. - 20
  21. - 21
  22. 2)拉取Jenkinsle文件
  23. <a name="affd434c"></a>
  24. ## 微服务持续集成(3)-提交到SonarQube代码审查
  25. <a name="e795e30c"></a>
  26. ##### 1)创建项目,并设置参数
  27. 创建tensquare_back项目,添加两个参数
  28. <a name="475b218b"></a>
  29. ##### 2)sonar-project.properties
  30. **每个项目**的根目录下添加sonar-project.properties

must be unique in a given SonarQube instance

sonar.projectKey=tensquare_zuul

this is the name and version displayed in the SonarQube UI. Was mandatory

prior to SonarQube 6.1. sonar.projectName=tensquare_zuul sonar.projectVersion=1.0

Path is relative to the sonar-project.properties file. Replace “\” by “/“ on Windows.

This property is optional if sonar.modules is set.

sonar.sources=. sonar.exclusions=/test/,/target/ sonar.java.binaries=. sonar.java.source=1.8 sonar.java.target=1.8 sonar.java.libraries=/target/classes/

Encoding of the source code. Default is default system encoding

sonar.sourceEncoding=UTF-8

  1. - 1
  2. - 2
  3. - 3
  4. - 4
  5. - 5
  6. - 6
  7. - 7
  8. - 8
  9. - 9
  10. - 10
  11. - 11
  12. - 12
  13. - 13
  14. - 14
  15. - 15
  16. - 16
  17. >
  18. > 注意:修改sonar.projectKeysonar.projectName
  19. >
  20. <a name="0a8e23f5"></a>
  21. ##### 3)修改Jenkinsfile构建脚本
  22. //gitlab的凭证="68f2087f-a034-4d39-a9ff-1f776dd3dfa8"//构建版本的名称="latest"{stage('拉取代码'){checkout([class:'GitSCM',:[[:'*/${branch}']],:false,:[],:[],:[[:"${git_auth}",:'git@192.168.66.100: itheima_group/tensquare_back.git']]])}stage('代码审查'){='sonarqube-scanner'//根据自己的Jenkinssonarqube-scanner环境修改withSonarQubeEnv('sonarqube6.7.4'){//引入Jenkinssonarqube环境""{}// 进入二级项目,如zuul{}//-// 代码审查""}}}

defgit_auth

deftagnode

  1. $
  2. branches
  3. name
  4. doGenerateSubmoduleConfigurations
  5. extensions
  6. submoduleCfg
  7. userRemoteConfigs
  8. credentialsId
  9. url
  10. defscannerHometool
  11. sh"
  12. cd $project_name
  13. $scannerHomebinsonarscanner
  14. "
  1. - 1
  2. - 2
  3. - 3
  4. - 4
  5. - 5
  6. - 6
  7. - 7
  8. - 8
  9. - 9
  10. - 10
  11. - 11
  12. - 12
  13. - 13
  14. - 14
  15. - 15
  16. - 16
  17. - 17
  18. - 18
  19. - 19
  20. - 20
  21. - 21
  22. - 22
  23. - 23
  24. - 24
  25. - 25
  26. - 26
  27. - 27
  28. - 28
  29. - 29
  30. - 30
  31. <a name="39e3ccf1"></a>
  32. ## 微服务持续集成(4)-使用Dockerfile编译、生成镜像
  33. 利用dockerle-maven-plugin插件构建Docker镜像,他可以通过读取`Dockerfile`然后构建出docker镜像<br />1)在每个微服务项目的pom.xml加入`dockerfile-maven-plugin`插件<br /><plugin><groupId></groupId><artifactId></artifactId><version></version><configuration><repository></repository><buildArgs><JAR_FILE></JAR_FILE></buildArgs></configuration></plugin>
  1. com.spotify
  2. dockerfile-maven-plugin
  3. 1.3.6
  4. ${project.artifactId}
  5. target/${project.build.finalName}.jar
  1. - 1
  2. - 2
  3. - 3
  4. - 4
  5. - 5
  6. - 6
  7. - 7
  8. - 8
  9. - 9
  10. - 10
  11. - 11
  12. >
  13. > 这个xml可以和之前的编译镜像对比一下
  14. >
  15. > docker build --build-arg JAR_FILE=tensquare_eureka_server-1.0-SNAPSHOT.jar -t eureka:v1
  16. >
  17. 2)在每个微服务项目根目录下建立Dockerle文件

FROM java:8

FROM openjdk:8-jdk-alpine ARG JAR_FILE COPY ${JAR_FILE} app.jar EXPOSE 10086 ENTRYPOINT [“java”,”-jar”,”/app.jar”]

  1. - 1
  2. - 2
  3. - 3
  4. - 4
  5. - 5
  6. - 6
  7. 注意:每个项目公开的端口不一样<br />3)修改Jenkinsle构建脚本<br />//gitlab的凭证="68f2087f-a034-4d39-a9ff-1f776dd3dfa8"//构建版本的名称="latest"//Harbor私服地址="192.168.66.102:85/tensquare/"{stage('拉取代码'){checkout([class:'GitSCM',:[[:'*/${branch}']],:false,:[],:[],:[[:"${git_auth}",:'git@192.168.66.100:itheima_group/tensquare_back.git']]])}stage('代码审查'){='sonarqube-scanner'withSonarQubeEnv('sonarqube6.7.4'){""{}{}//-""}}stage('编译,构建镜像'){//定义镜像名称="${project_name}:${tag}"//编译,安装公共工程"mvn -f tensquare_common clean install"//编译,构建本地镜像"mvn -f ${project_name} clean package dockerfile:build"// 多了个dockerfile:build,就是激活插件生成镜像}}

def git_auth

def tag

def harbor_url
node

  1. $
  2. branches name
  3. doGenerateSubmoduleConfigurations extensions submoduleCfg
  4. userRemoteConfigs
  5. credentialsId url
  6. def scannerHome tool
  7. sh "
  8. cd $ project_name
  9. $ scannerHomebinsonar scanner
  10. "
  11. def imageName
  12. sh
  13. sh
  1. - 1
  2. - 2
  3. - 3
  4. - 4
  5. - 5
  6. - 6
  7. - 7
  8. - 8
  9. - 9
  10. - 10
  11. - 11
  12. - 12
  13. - 13
  14. - 14
  15. - 15
  16. - 16
  17. - 17
  18. - 18
  19. - 19
  20. - 20
  21. - 21
  22. - 22
  23. - 23
  24. - 24
  25. - 25
  26. - 26
  27. - 27
  28. - 28
  29. - 29
  30. - 30
  31. - 31
  32. - 32
  33. - 33
  34. - 34
  35. - 35
  36. - 36
  37. 注意:如果出现找不到父工程依赖,需要手动把父工程的依赖上传到仓库中
  38. <a name="2cf0c90d"></a>
  39. ## 微服务持续集成(5)-上传到Harbor镜像仓库
  40. 2)使用凭证管理Harbor私服账户和密码<br />先在凭证建立Harbor的凭证,在生成凭证脚本代码
  41. 生成一个id,用片段生成器语法中的wIth-creadentials<br />1)修改Jenkinsle构建脚本

//gitlab的凭证 def git_auth = “68f2087f-a034-4d39-a9ff-1f776dd3dfa8” //构建版本的名称 def tag = “latest” //Harbor私服地址 def harbor_url = “192.168.66.102:85” //Harbor的项目名称 def harbor_project_name = “tensquare” //Harbor的凭证 def harbor_auth = “ef499f29-f138-44dd-975e-ff1ca1d8c933” node { stage(‘拉取代码’) { checkout([$class: ‘GitSCM’, branches: [[name: ‘*/${branch}’]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [ [credentialsId: “${git_auth}”, url:’git@192.168.66.100:itheima_group/tensquare_back.git’ ] ] ]) } stage(‘代码审查’) { def scannerHome = tool ‘sonarqube-scanner’ withSonarQubeEnv(‘sonarqube6.7.4’) { sh “”” cd $ {project_name} $ {scannerHome}/bin/sonar-scanner “”” } } stage(‘编译,构建镜像’) { //定义镜像名称 def imageName = “${project_name}:${tag}” //编译,安装公共工程 sh “mvn -f tensquare_common clean install” //编译,构建本地镜像 sh “mvn -f ${project_name} clean package dockerfile:build” //给镜像打标签 sh “docker tag ${imageName} ${harbor_url}/${harbor_project_name}/${imageName}” //登录Harbor,并上传镜像 withCredentials([usernamePassword( credentialsId: “${harbor_auth}”, passwordVariable: ‘password’, // 就是这样的,不用替换,在jk中配置的 usernameVariable: ‘username’)]) { //登录 sh “docker login -u ${username} -p ${password} ${harbor_url}” //上传镜像 sh “docker push ${harbor_url}/${harbor_project_name}/${imageName}” } //删除本地镜像 sh “docker rmi -f ${imageName}” sh “docker rmi -f ${harbor_url}/${harbor_project_name}/${imageName}” } }

  1. - 1
  2. - 2
  3. - 3
  4. - 4
  5. - 5
  6. - 6
  7. - 7
  8. - 8
  9. - 9
  10. - 10
  11. - 11
  12. - 12
  13. - 13
  14. - 14
  15. - 15
  16. - 16
  17. - 17
  18. - 18
  19. - 19
  20. - 20
  21. - 21
  22. - 22
  23. - 23
  24. - 24
  25. - 25
  26. - 26
  27. - 27
  28. - 28
  29. - 29
  30. - 30
  31. - 31
  32. - 32
  33. - 33
  34. - 34
  35. - 35
  36. - 36
  37. - 37
  38. - 38
  39. - 39
  40. - 40
  41. - 41
  42. - 42
  43. - 43
  44. - 44
  45. - 45
  46. - 46
  47. - 47
  48. - 48
  49. - 49
  50. - 50
  51. - 51
  52. - 52
  53. - 53
  54. - 54
  55. - 55
  56. - 56
  57. - 57
  58. <a name="90ee5ac0"></a>
  59. ## 微服务持续集成(6)-拉取镜像和发布应用
  60. 注意:192.168.66.103服务已经安装Docker并启动<br />JK安装publish over ssh插件,可以实现远程发送Shell命令,使得部署服务器执行一些操作
  61. <a name="1f9f51e2"></a>
  62. #### 配置远程部署服务器
  63. 上面所述的远程调用(jk调用部署服务器)是需要公钥私钥的<br />1)拷贝公钥到远程服务器(部署服务器)<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AatEj4hL-1624726844530)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image073.gif)]ssh-copy-id 192.168.66.103<br />2)系统配置->添加远程服务器
  64. 修改Jenkinsle构建脚本生成远程调用模板代码
  65. 选择的片段生成器是sshPublisher<br />添加一个port参数:port 10086

//gitlab的凭证 defgit_auth=”68f2087f-a034-4d39-a9ff-1f776dd3dfa8”//构建版本的名称 deftag=”latest”//Harbor私服地址 defharbor_url=”192.168.66.102:85”//Harbor的项目名称 defharbor_project_name=”tensquare”//Harbor的凭证 defharbor_auth=”ef499f29-f138-44dd-975e-ff1ca1d8c933” node{ stage(‘拉取代码’){ checkout([ $class: ‘GitSCM’, branches: [ [ name: ‘*/${ branch}’ ] ], doGenerateSubmoduleConfigurations: false, extensions: [ ], submoduleCfg: [], userRemoteConfigs: [ [ credentialsId: “${git_auth}”, url: ‘git@192.168.66.100: itheima_group/tensquare_back.git’ ] ] ]) }stage(‘代码审查’){ defscannerHome=tool’sonarqube-scanner’withSonarQubeEnv(‘sonarqube6.7.4’){ sh””” cd ${project_name} ${scannerHome}/bin/sonar-scanner “”” } }stage(‘编译,构建镜像,部署服务’){ //定义镜像名称 defimageName=”${project_name}:${tag}”//编译并安装公共工程 sh”mvn -f tensquare_common clean install”//编译,构建本地镜像 sh”mvn -f ${project_name} clean package dockerfile:build”//给镜像打标签 sh”docker tag ${imageName}${harbor_url}/${harbor_project_name}/${imageName}”//登录Harbor,并上传镜像 withCredentials([ usernamePassword(credentialsId: “${harbor_auth}”, passwordVariable: ‘password’, usernameVariable: ‘username’) ]){ //登录 sh”docker login -u ${username} -p ${password} ${harbor_url}”//上传镜像 sh”docker push ${harbor_url}/${harbor_project_name}/${imageName}” } //删除本地镜像 sh”docker rmi -f ${imageName}” sh”docker rmi -f ${harbor_url}/${harbor_project_name}/${imageName}” //=====以下为远程调用进行项目部署======== sshPublisher(publishers: [ sshPublisherDesc(configName: ‘master_server’, transfers: [ sshTransfer(cleanRemote: false, excludes: ‘’, // 触发的命令,deploy.sh execCommand: “/opt/jenkins_shell/deploy.sh $harbor_url $harbor_project_name $project_name $tag $port”, execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: ‘[ , ]+’, remoteDirectory: ‘’, remoteDirectorySDF: false, removePrefix: ‘’, sourceFiles: ‘’) ], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false) ]) } }

  1. - 1
  2. - 2
  3. - 3
  4. - 4
  5. - 5
  6. - 6
  7. - 7
  8. - 8
  9. - 9
  10. - 10
  11. - 11
  12. - 12
  13. - 13
  14. - 14
  15. - 15
  16. - 16
  17. - 17
  18. - 18
  19. - 19
  20. - 20
  21. - 21
  22. - 22
  23. - 23
  24. - 24
  25. - 25
  26. - 26
  27. - 27
  28. - 28
  29. - 29
  30. - 30
  31. - 31
  32. - 32
  33. - 33
  34. - 34
  35. - 35
  36. - 36
  37. - 37
  38. - 38
  39. - 39
  40. - 40
  41. - 41
  42. - 42
  43. - 43
  44. - 44
  45. - 45
  46. - 46
  47. - 47
  48. - 48
  49. - 49
  50. - 50
  51. - 51
  52. - 52
  53. - 53
  54. - 54
  55. - 55
  56. - 56
  57. - 57
  58. - 58
  59. - 59
  60. - 60
  61. - 61
  62. - 62
  63. - 63
  64. - 64
  65. - 65
  66. - 66
  67. - 67
  68. - 68
  69. - 69
  70. - 70
  71. 编写deploy.sh部署脚本<br />imageName=![](https://g.yuque.com/gr/latex?harbor_url%2F#card=math&code=harbor_url%2F&id=VnY9f)harbor_project_name/![](https://g.yuque.com/gr/latex?project_name%3A#card=math&code=project_name%3A&id=GVqsL)tag<br />echo "$imageName"<br />#查询容器是否存在,存在则删除<br />containerId=`docker ps -a | grep -w ${project_name}:${tag} | awk '{print $1}'`<br />if [ "$containerId" != "" ] ; then<br />#停掉容器<br />docker stop $containerId<br />#删除容器<br />docker rm $containerId<br />echo "成功删除容器"<br />fi<br />#查询镜像是否存在,存在则删除<br />imageId=`docker images | grep -w $project_name | awk '{print $3}'`<br />if [ "$imageId" != "" ] ; then<br />#删除镜像<br />docker rmi -f $imageId<br />echo "成功删除镜像"<br />fi
  72. <a name="d8036d9a"></a>
  73. # 登录Harbor私服
  74. docker login -u itcast -p Itcast123 $harbor_url
  75. <a name="22659ffa"></a>
  76. # 下载镜像
  77. docker pull $imageName
  78. <a name="b093c1c3"></a>
  79. # 启动容器
  80. docker run -di -p ![](https://g.yuque.com/gr/latex?port%3A#card=math&code=port%3A&id=wVJAu)port $imageName<br />echo "容器启动成功"

!/bin/sh

接收外部参数

harbor_url=$1 harbor_project_name=$2 project_name=$3 tag=$4 port=$5

  1. - 1
  2. - 2
  3. - 3
  4. - 4
  5. - 5
  6. - 6
  7. - 7
  8. - 8
  9. - 9
  10. - 10
  11. - 11
  12. - 12
  13. - 13
  14. - 14
  15. - 15
  16. - 16
  17. - 17
  18. - 18
  19. - 19
  20. - 20
  21. - 21
  22. - 22
  23. - 23
  24. - 24
  25. - 25
  26. - 26
  27. - 27
  28. - 28
  29. - 29
  30. - 30
  31. - 31
  32. - 32
  33. - 33
  34. 上传deploy.sh文件到/opt/jenkins_shell目录下,且文件至少有执行权限!<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5nDPzMrS-1624726844533)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image073.gif)]chmod +x deploy.sh 添加执行权限<br />**导入数据,测试微服务**:两个sql<br />要把spring里的注册中心等ip信息写成部署服务器所在的地址
  35. <a name="88a8e196"></a>
  36. ## 微服务持续集成(7)-部署前端静态web网站
  37. <a name="bd16b83d"></a>
  38. ### 安装Nginx服务器
  39. yum -y install nginx 安装<br />修改nginx的端口,默认80,改为9090:<br />vi /etc/nginx/nginx.conf<br />还需要关闭selinux,将SELINUX=disabled setenforce 0 先临时关闭<br />vi /etc/selinux/cong 编辑文件,永久关闭 SELINUX=disabled

103上

yum install epel-release

  1. - 1
  2. - 2
  3. - 3
  4. - 4
  5. - 5
  6. - 6
  7. - 7
  8. - 8
  9. - 9
  10. - 10
  11. - 11
  12. - 12
  13. 启动Nginx

systemctl enable nginx 设置开机启动 systemctl start nginx 启动 systemctl stop nginx 停止 systemctl restart nginx 重启

  1. - 1
  2. - 2
  3. - 3
  4. - 4
  5. 访问:http://192.168.66.103:9090/
  6. <a name="0e15afea"></a>
  7. ### Jenkins安装NodeJS插件
  8. Jenkins配置Nginx服务器<br />Manage Jenkins->Global Tool Conguration
  9. <a name="edddc737"></a>
  10. ### 创建前端流水线项目
  11. 还是创建个带branch参数的项目
  12. 建立Jenkinsle构建脚本<br />//gitlab的凭证="68f2087f-a034-4d39-a9ff-1f776dd3dfa8"{stage('拉取代码'){checkout([class:'GitSCM',:[[:'*/${branch}']],:false,:[],:[],:[[:"${git_auth}",:'git@192.168.66.100: itheima_group/tensquare_front.git']]])}stage('打包,部署网站'){//使用NodeJS的npm进行打包nodejs('nodejs12'){''''}//=====以下为远程调用进行项目部署========sshPublisher(:[sshPublisherDesc(:'master_server',:[sshTransfer(:false,:'',:'',:120000,:false,:false,:false,:'[,]+',:'/usr/share/nginx/html',:false,:'dist',:'dist/**')],:false,:false,:false)])}}

defgit_auth node

  1. $
  2. branches name
  3. doGenerateSubmoduleConfigurations
  4. extensions
  5. submoduleCfg
  6. userRemoteConfigs
  7. credentialsId
  8. url
  9. sh'npm install
  10. npm run build
  11. '
  12. publishers
  13. configName
  14. transfers
  15. cleanRemote
  16. excludes
  17. execCommand
  18. execTimeout
  19. flatten
  20. makeEmptyDirs
  21. noDefaultExcludes
  22. patternSeparator
  23. remoteDirectory
  24. remoteDirectorySDF
  25. removePrefix
  26. sourceFiles
  27. usePromotionTimestamp
  28. useWorkspaceInPromotion
  29. verbose
  1. - 1
  2. - 2
  3. - 3
  4. - 4
  5. - 5
  6. - 6
  7. - 7
  8. - 8
  9. - 9
  10. - 10
  11. - 11
  12. - 12
  13. - 13
  14. - 14
  15. - 15
  16. - 16
  17. - 17
  18. - 18
  19. - 19
  20. - 20
  21. - 21
  22. - 22
  23. - 23
  24. - 24
  25. - 25
  26. - 26
  27. - 27
  28. - 28
  29. - 29
  30. - 30
  31. - 31
  32. - 32
  33. - 33
  34. - 34
  35. - 35
  36. - 36
  37. - 37
  38. - 38
  39. - 39
  40. - 40
  41. - 41
  42. - 42
  43. - 43
  44. - 44
  45. - 45
  46. - 46
  47. - 47
  48. - 48
  49. 完成后,访问:http://192.168.66.103:9090 进行测试。
  50. <a name="3cc86cf6"></a>
  51. # 5、Jenkins+Docker+SpringCloud微服务持续集成(下)
  52. <a name="269560b3"></a>
  53. ## JK+Docker+Cloud部署方案优化
  54. 上面部署方案存在的问题:<br />1)一次只能选择一个微服务部署<br />2)只有一台生产者部署服务器<br />3)每个微服务只有一个实例,容错率低<br />优化方案:<br />1)在一个Jenkins工程中可以选择多个微服务同时发布<br />2)在一个Jenkins工程中可以选择多台生产服务器同时部署<br />3)每个微服务都是以**集群高可用**形式部署
  55. <a name="d0d6f118"></a>
  56. ## Jenkins+Docker+SpringCloud集群部署流程说明
  57. - 生成多个镜像
  58. - 对多个部署服务器发起远程调用
  59. **修改所有微服务配置**
  60. <a name="2c84c5f6"></a>
  61. ##### 注册中心配置
  62. 缩进自己调整下<br /># 集群版spring:application:name:----server:port:10086<br />spring:<br /># 指定profile=eureka-server1<br />profiles: eureka-server1<br />eureka:<br />instance:<br /># 指定当profile=eureka-server1时,主机名是eureka-server1<br />hostname: 192.168.66.103<br />client:<br />service-url:<br /># 将自己注册到eureka-server1eureka-server2这个Eureka上面去<br />defaultZone: http:[//192.168.66.103](//192.168.66.103):10086/eureka/,http:[//192.168.66.104](//192.168.66.104):10086/eureka/<br />---<br />server:<br />port: 10086<br />spring:<br />profiles: eureka-server2<br />eureka:<br />instance:<br />hostname: 192.168.66.104<br />client:<br />service-url:<br />defaultZone: http:[//192.168.66.103](//192.168.66.103):10086/eureka/,http:[//192.168.66.104](//192.168.66.104):10086/eureka/
  1. EUREKAHA
  1. - 1
  2. - 2
  3. - 3
  4. - 4
  5. - 5
  6. - 6
  7. - 7
  8. - 8
  9. - 9
  10. - 10
  11. - 11
  12. - 12
  13. - 13
  14. - 14
  15. - 15
  16. - 16
  17. - 17
  18. - 18
  19. - 19
  20. - 20
  21. - 21
  22. - 22
  23. - 23
  24. - 24
  25. - 25
  26. - 26
  27. - 27
  28. - 28
  29. - 29
  30. - 30
  31. - 31
  32. 在启动微服务的时候,加入参数: `spring.profiles.active`来读取对应的配置
  33. <a name="b757ac20"></a>
  34. ##### 其他微服务配置
  35. 除了Eureka注册中心以外,其他微服务配置都需要加入所有Eureka服务<br /># Eureka配置eureka:client:service-url:defaultZone:::,::# Eureka访问地址instance:prefer-ip-address:true
  1. http//192.168.66.10310086/eurekahttp//192.168.66.10410086/eureka
  1. - 1
  2. - 2
  3. - 3
  4. - 4
  5. - 5
  6. - 6
  7. - 7
  8. 把代码提交到Gitlab
  9. <a name="a0633d06"></a>
  10. ##### 设计Jenkins集群项目的构建参数
  11. 1)安装`Extended Choice Parameter`插件,支持多选框<br />2)创建流水线项目<br />tensquera_back_cluster<br />3)添加参数<br />字符串参数:分支名称branch<br />多选框:项目名称

tensquare_eureka_server@10086, tensquare_zuul@10020, tensquare_admin_service@9001, tensquare_gathering@9002

  1. - 1
  2. - 2
  3. - 3
  4. - 4
  5. 最后效果:
  6. <a name="146121a1"></a>
  7. ## 完成微服务构建镜像,上传私服

//gitlab的凭证 defgit_auth=”68f2087f-a034-4d39-a9ff-1f776dd3dfa8” //构建版本的名称 deftag=”latest” //Harbor私服地址 defharbor_url=”192.168.66.102:85” //Harbor的项目名称 defharbor_project_name=”tensquare” //Harbor的凭证 defharbor_auth=”ef499f29-f138-44dd-975e-ff1ca1d8c933” node{ //把选择的项目信息转为数组 defselectedProjects=”${project_name}”.split(‘,’) stage(‘拉取代码’){ checkout([ $class: ‘GitSCM’, branches: [[name: ‘*/${branch}’] ], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [ [ credentialsId: ‘${git_auth}’, url: ‘git@192.168.66.100: itheima_group/tensquare_back_cluster.git’ ] ] ]) }stage(‘代码审查’){ defscannerHome=tool ‘sonarqube-scanner’ withSonarQubeEnv(‘sonarqube6.7.4’){ for(inti=0;i<selectedProjects.size();i++){ //取出每个项目的名称和端口 defcurrentProject=selectedProjects[i ]; //项目名称 defcurrentProjectName=currentProject.split(‘@’)[0] //项目启动端口 defcurrentProjectPort=currentProject.split(‘@’)[1] sh””” cd ${currentProjectName} ${scannerHome}/bin/sonar-scanner “”” echo “${currentProjectName}完成代码审查” } } } stage(‘编译,构建镜像,部署服务’){ //编译并安装公共工程 sh”mvn -f tensquare_common clean install” for(inti=0;i<selectedProjects.size();i++){ //取出每个项目的名称和端口 defcurrentProject=selectedProjects[i]; //项目名称 defcurrentProjectName=currentProject.split(‘@’)[0] //项目启动端口 defcurrentProjectPort=currentProject.split(‘@’)[1] //定义镜像名称 defimageName=”${currentProjectName}:${tag}” //编译,构建本地镜像 sh”mvn -f ${currentProjectName} clean packagedockerfile:build” //给镜像打标签 sh”docker tag ${imageName}${harbor_url}/${harbor_project_name}/${imageName}” //登录Harbor,并上传镜像 withCredentials([ usernamePassword(credentialsId: “${harbor_auth}”, passwordVariable: ‘password’, usernameVariable: ‘username’) ]){ //登录 sh”docker login -u ${username} -p ${password}${harbor_url}” //上传镜像 sh”docker push ${harbor_url}/${harbor_project_name}/${imageName}” } //删除本地镜像 sh”docker rmi -f ${imageName}” sh”docker rmi -f ${harbor_url}/${harbor_project_name}/${imageName}” //=====以下为远程调用进行项目部署========// sshPublisher(publishers: [ sshPublisherDesc(configName: ‘master_server’, transfers: [ sshTransfer(cleanRemote: false, excludes: ‘’, execCommand: “/opt/jenkins_shell/deployCluster.sh $harbor_url $harbor_project_name $currentProjectName $tag $currentProjectPort”, execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: ‘[,]+’, remoteDirectory: ‘’, remoteDirectorySDF: false, removePrefix: ‘’, sourceFiles: ‘’) ], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false) ])echo”${currentProjectName}完成编译,构建镜像” } } }

  1. - 1
  2. - 2
  3. - 3
  4. - 4
  5. - 5
  6. - 6
  7. - 7
  8. - 8
  9. - 9
  10. - 10
  11. - 11
  12. - 12
  13. - 13
  14. - 14
  15. - 15
  16. - 16
  17. - 17
  18. - 18
  19. - 19
  20. - 20
  21. - 21
  22. - 22
  23. - 23
  24. - 24
  25. - 25
  26. - 26
  27. - 27
  28. - 28
  29. - 29
  30. - 30
  31. - 31
  32. - 32
  33. - 33
  34. - 34
  35. - 35
  36. - 36
  37. - 37
  38. - 38
  39. - 39
  40. - 40
  41. - 41
  42. - 42
  43. - 43
  44. - 44
  45. - 45
  46. - 46
  47. - 47
  48. - 48
  49. - 49
  50. - 50
  51. - 51
  52. - 52
  53. - 53
  54. - 54
  55. - 55
  56. - 56
  57. - 57
  58. - 58
  59. - 59
  60. - 60
  61. - 61
  62. - 62
  63. - 63
  64. - 64
  65. - 65
  66. - 66
  67. - 67
  68. - 68
  69. - 69
  70. - 70
  71. - 71
  72. - 72
  73. - 73
  74. - 74
  75. - 75
  76. - 76
  77. - 77
  78. - 78
  79. - 79
  80. - 80
  81. - 81
  82. - 82
  83. - 83
  84. - 84
  85. - 85
  86. - 86
  87. - 87
  88. - 88
  89. - 89
  90. - 90
  91. - 91
  92. - 92
  93. - 93
  94. - 94
  95. - 95
  96. - 96
  97. - 97
  98. - 98
  99. - 99
  100. <a name="5f4ed8b7"></a>
  101. ## 完成微服务多服务器远程发布
  102. 1)配置远程部署服务器<br />拷贝公钥到远程服务器<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RCoZQpty-1624726844535)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image073.gif)]ssh-copy-id 192.168.66.104<br />系统配置->添加远程服务器
  103. 2)修改Docker配置信任Harbor私服地址<br />重启Docker<br />3)添加参数<br />多选框:部署服务器
  104. 最终效果:<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wVRAztE4-1624726844536)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image380.jpg)]<br />4)修改Jenkinsfile构建脚本<br />5)编写deployCluster.sh部署脚本<br />6)集群效果
  105. <a name="5211c872"></a>
  106. ## Nginx+Zuul集群实现高可用网关
  107. 1)安装Nginx(已完成)<br />2)修改Nginx配置<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PLPGk8wR-1624726844537)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image073.gif)]vi /etc/nginx/nginx.conf<br />内容如下:<br />3)重启Nginx: systemctl restart nginx<br />4)修改前端Nginx的访问地址
  108. <a name="e17e9bcb"></a>
  109. # 6、基于`K8S`构建Jenkins持续集成平台(上)
  110. <a name="a48c3646"></a>
  111. ## Jenkins的Master-Slave分布式构建
  112. <a name="5c8ff6cf"></a>
  113. ### 什么是Master-Slave分布式构建
  114. JenkinsMaster-Slave分布式构建,就是通过将构建过程分配到从属Slave节点上,从而减轻Master节点的压力,而且可以同时构建多个,有点类似负载均衡的概念。
  115. <a name="3ae5bf81"></a>
  116. ### 如何实现Master-Slave分布式构建
  117. 1)开启代理程序的TCP端口<br />Manage Jenkins -> Congure Global Security<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WlzMsRVH-1624726844539)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image395.jpg)]<br />2)新建节点<br />Manage Jenkins—Manage Nodes—新建节点<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d9nqUjFA-1624726844539)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image396.jpg)]<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VOL3tnzB-1624726844540)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image398.jpg)]<br />有两种在Slave节点连接Master节点的方法
  118. | | |
  119. | --- | --- |
  120. | | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dc3vSkMi-1624726844541)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image401.jpg)] |
  121. 我们选择第二种:<br />2)安装和配置节点<br />下载agent.jar,并上传到Slave节点,然后执行页面提示的命令:<br />刷新页面<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UAGGOPUd-1624726844541)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image404.jpg)]<br />3)测试节点是否可用<br />自由风格和Maven风格的项目:
  122. | | |
  123. | --- | --- |
  124. | | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GJiowKar-1624726844542)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image405.jpg)] |
  125. 流水线风格的项目:
  126. <a name="51ed4e8f"></a>
  127. ## Kubernetes实现Master-Slave分布式构建方案
  128. <a name="426c57d7"></a>
  129. ### 传统Jenkins的Master-Slave方案的缺陷
  130. Master节点发生单点故障时,整个流程都不可用了<br />每个 Slave节点的配置环境不一样,来完成不同语言的编译打包等操作,但是这些差异化的配置导致管理起来非常不方便,维护起来也是比较费劲<br />资源分配不均衡,有的 Slave节点要运行的job出现排队等待,而有的Slave节点处于空闲状态<br />资源浪费,每台 Slave节点可能是实体机或者VM,当Slave节点处于空闲状态时,也不会完全释放掉资源<br />以上种种问题,我们可以引入Kubernates来解决!
  131. <a name="2d3d9284"></a>
  132. ### Kubernates简介
  133. Kubernetes(简称,K8S)是Google开源的容器集群管理系统,在Docker技术的基础上,为容器化的应用提供部署运行、资源调度、服务发现和动态伸缩等一系列完整功能,提高了大规模容器集群管理的便捷性。 其主要功能如下:<br />使用Docker对应用程序包装(package)、实例化(instantiate)、运行(run)。<br />以集群的方式运行、管理跨机器的容器。以集群的方式运行、管理跨机器的容器。解决Docker跨机器容器之间的通讯问题。解决Docker跨机器容器之间的通讯问题。<br />Kubernetes的自我修复机制使得容器集群总是运行在用户期望的状态。
  134. <a name="d199a6b1"></a>
  135. ### Kubernates+Docker+Jenkins持续集成架构图
  136. 大致工作流程:手动/自动构建 -> Jenkins 调度 K8S API ->动态生成 Jenkins Slave pod -> Slave pod拉取 Git 代码/编译/打包镜像 ->推送到镜像仓库 Harbor -> Slave 工作完成,Pod 自动销毁 ->部署到测试或生产 Kubernetes平台。(完全自动化,无需人工干预)
  137. <a name="20624f1b"></a>
  138. ### Kubernates+Docker+Jenkins持续集成方案好处
  139. 服务高可用:当 Jenkins Master 出现故障时,Kubernetes 会自动创建一个新的 Jenkins Master<br />容器,并且将 Volume 分配给新创建的容器,保证数据不丢失,从而达到集群服务高可用。<br />动态伸缩,合理使用资源:每次运行 Job 时,会自动创建一个 Jenkins SlaveJob 完成后,Slave自动注销并删除容器,资源自动释放,而且 Kubernetes 会根据每个资源的使用情况,动态分配<br />Slave 到空闲的节点上创建,降低出现因某节点资源利用率高,还排队等待在该节点的情况。扩展性好:当 Kubernetes 集群的资源严重不足而导致 Job 排队等待时,可以很容易的添加一个 Kubernetes Node 到集群中,从而实现扩展。
  140. <a name="cad0ba35"></a>
  141. ## Kubeadm安装Kubernetes
  142. <a name="934bd159"></a>
  143. ### Kubernetes的架构
  144. | | |
  145. | --- | --- |
  146. | | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-li8pNku5-1624726844543)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image410.jpg)] |
  147. API Server:用于暴露Kubernetes API,任何资源的请求的调用操作都是通过kube-apiserver提供的接口进行的。<br />Etcd:是Kubernetes提供默认的存储系统,保存所有集群数据,使用时需要为etcd数据提供备份计划。<br />Controller-Manager:作为集群内部的管理控制中心,负责集群内的NodePod副本、服务端点<br />(Endpoint)、命名空间(Namespace)、服务账号(ServiceAccount)、资源定额<br />(ResourceQuota)的管理,当某个Node意外宕机时,Controller Manager会及时发现并执行自动化修复流程,确保集群始终处于预期的工作状态。<br />Scheduler:监视新创建没有分配到NodePod,为Pod选择一个Node。<br />Kubelet:负责维护容器的生命周期,同时负责Volume和网络的管理<br />Kube proxy:是Kubernetes的核心组件,部署在每个Node节点上,它是实现Kubernetes Service的通信与负载均衡机制的重要组件。
  148. <a name="6cdd9b57"></a>
  149. ### 安装环境说明
  150. | **主机名称** | **IP**地址 | **安装的软件** |
  151. | --- | --- | --- |
  152. | 代码托管服务器 | 192.168.66.100 | Gitlab-12.4.2 |
  153. | Docker仓库服务器 | 192.168.66.102 | Harbor1.9.2 |
  154. | k8s-master | 192.168.66.101 | kube-apiserverkube-controller-managerkube- schedulerdockeretcdcalicoNFS |
  155. | k8s-node1 | 192.168.66.103 | kubeletkubeproxyDocker18.06.1-ce |
  156. | k8s-node2 | 192.168.66.104 | kubeletkubeproxyDocker18.06.1-ce |
  157. **三台机器都需要完成**<br />**修改三台机器的hostnamehosts文件**<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BPoRMle8-1624726844544)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image073.gif)]hostnamectl set-hostname k8s-master<br />hostnamectl set-hostname k8s-node1 hostnamectl set-hostname k8s-node2<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JEzXCI8T-1624726844544)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image073.gif)]cat >>/etc/hosts<<EOF 192.168.66.101 k8s-master 192.168.66.103 k8s-node1<br />192.168.66.104 k8s-node2 EOF<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DXlOT0pP-1624726844545)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image073.gif)]**关闭防火墙和关闭****SELinux** systemctl stop firewalld<br />systemctl disable firewalld setenforce 0 临时关闭<br />vi /etc/sysconfig/selinux 永久关闭<br />改为SELINUX=disabled
  158. <a name="c80880a1"></a>
  159. ### 设置系统参数
  160. 设置允许路由转发,不对bridge的数据进行处理创建文件<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nF65dwUC-1624726844545)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image073.gif)]vi /etc/sysctl.d/k8s.conf<br />内容如下:<br />net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1<br />net.ipv4.ip_forward = 1 vm.swappiness = 0<br />执行文件<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uw8UKH4S-1624726844546)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image073.gif)]sysctl -p /etc/sysctl.d/k8s.conf
  161. <a name="d92a976a"></a>
  162. ### kube-proxy开启ipvs的前置条件
  163. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-itWUaVcO-1624726844546)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image073.gif)]**所有节点关闭****swap** swapoff -a 临时关闭 vi /etc/fstab 永久关闭注释掉以下字段<br />/dev/mapper/cl-swap swap swap defaults 0 0
  164. <a name="79acc91b"></a>
  165. ### 安装kubelet、kubeadm、kubectl
  166. kubeadm: 用来初始化集群的指令。<br />kubelet: 在集群中的每个节点上用来启动 pod container 等。<br />kubectl: 用来与集群通信的命令行工具。<br />清空yum缓存<br />设置yum安装源<br />安装:<br />kubelet设置开机启动(注意:先不启动,现在启动的话会报错)<br />查看版本<br />安装的是最新版本:Kubernetes v1.16.3(可能会变化)<br />**Master****节点需要完成** 1)运行初始化命令<br />注意:apiserver-advertise-address这个地址必须是master机器的IP常用错误:<br />错误一:[WARNING IsDockerSystemdCheck]: detected cgroupfs as the Docker cgroup driver<br />作为Docker cgroup驱动程序。,Kubernetes推荐的Docker驱动程序是“systemd”<br />解决方案:修改Docker的配置: vi /etc/docker/daemon.json,加入<br />然后重启Docker<br />错误二:[ERROR NumCPU]: the number of available CPUs 1 is less than the required 2<br />解决方案:修改虚拟机的CPU的个数(处理器个数),至少为2个<br />安装过程日志:<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PNPkDkqN-1624726844547)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image418.jpg)]<br />最后,会提示节点安装的命令,必须记下来<br />2)启动kubelet<br />3)配置kubectl工具<br />4)安装Calico<br />5)等待几分钟,查看所有Pod的状态,确保所有Pod都是Running状态<br />Slave节点需要完成<br />1)让所有节点让集群环境<br />使用之前Master节点产生的命令加入集群<br />2)启动kubelet<br />3)回到Master节点查看,如果Status全部为Ready,代表集群环境搭建成功!!!<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qvgrnn7g-1624726844547)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image433.jpg)]
  167. <a name="0012f8bd"></a>
  168. ### kubectl常用命令
  169. 7、基于Kubernetes/K8S构建Jenkins持续集成平台(下)<br />Jenkins-Master-Slave架构图回顾:
  170. | | |
  171. | --- | --- |
  172. | | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-58EODeEf-1624726844547)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image407.jpg)] |
  173. <a name="93d0cbf6"></a>
  174. ## 安装和配置NFS
  175. <a name="01e1a5cd"></a>
  176. ### NFS简介
  177. NFSNetwork File System),它最大的功能就是可以通过网络,让不同的机器、不同的操作系统可以共享彼此的文件。我们可以利用NFS共享Jenkins运行的配置文件、Maven的仓库依赖文件等
  178. <a name="fc78d138"></a>
  179. ### NFS安装
  180. 我们把NFS服务器安装在192.168.66.101机器上<br />1)安装NFS服务(在所有K8S的节点都需要安装)<br />2)创建共享目录<br />3)启动服务<br />4)查看NFS共享目录
  181. <a name="8214b32a"></a>
  182. ## 在Kubernetes安装Jenkins-Master
  183. <a name="fc7b5465"></a>
  184. ### 创建NFS client provisioner
  185. nfs-client-provisioner 是一个Kubernetes的简易NFS的外部provisioner,本身不提供NFS,需要现有的NFS服务器提供存储。<br />1)上传nfs-client-provisioner构建文件<br />其中注意修改deployment.yaml,使用之前配置NFS服务器和目录<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L7rYCvzd-1624726844548)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image443.jpg)]<br />2)构建nfs-client-provisioner的pod资源<br />3)查看pod是否创建成功<br />安装Jenkins-Master<br />1)上传Jenkins-Master构建文件<br />其中有两点注意:<br />第一、在StatefulSet.yaml文件,声明了利用nfs-client-provisioner进行Jenkins-Master文件存储<br />第二、Service发布方法采用NodePort,会随机产生节点访问端口<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3hteL145-1624726844548)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image452.jpg)]<br />2)创建kube-ops的namespace<br />因为我们把Jenkins-Master的pod放到kube-ops下<br />3)构建Jenkins-Master的pod资源<br />4)查看pod是否创建成功<br />5)查看信息,并访问<br />查看Pod运行在那个Node上<br />查看分配的端口<br />最终访问地址为:http://192.168.66.103:30136 (192.168.66.103为k8s-node1的IP)
  186. | | |
  187. | --- | --- |
  188. | | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uz401naD-1624726844549)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image460.jpg)] |
  189. 安装过程跟之前是一样的!<br />6)先安装基本的插件<br />Localization:Chinese Git<br />Pipeline<br />Extended Choice Parameter
  190. <a name="0769c935"></a>
  191. ## Jenkins与Kubernetes整合
  192. <a name="bc89a134"></a>
  193. ### 安装Kubernetes插件
  194. 系统管理->插件管理->可选插件Kubernetes
  195. <a name="07318af1"></a>
  196. ### 实现Jenkins与Kubernetes整合
  197. 系统管理->系统配置->云->新建云->Kubernetes<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6QKAy2hR-1624726844549)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image463.jpg)]<br />kubernetes地址采用了kube的服务器发现:[https://kubernetes.default.svc.cluster.local](https://kubernetes.default.svc.cluster.local/)<br />namespace填kube-ops,然后点击Test Connection,如果出现 Connection test successful 的提示信息证明 Jenkins 已经可以和 Kubernetes 系统正常通信<br />Jenkins URL 地址:http://jenkins.kube-ops.svc.cluster.local:8080
  198. <a name="4bb0a8c6"></a>
  199. ## 构建Jenkins-Slave自定义镜像
  200. Jenkins-Master在构建Job的时候,Kubernetes会创建Jenkins-SlavePod来完成Job的构建。我们选择运行Jenkins-Slave的镜像为官方推荐镜像:jenkins/jnlp-slave:latest,但是这个镜像里面并没有Maven环境,为了方便使用,我们需要自定义一个新的镜像:<br />准备材料:<br />Dockerle文件内容如下:<br />构建出一个新镜像:jenkins-slave-maven:latest然把镜像上传到Harbor的公共库library
  201. <a name="2bf1ac10"></a>
  202. ## 测试Jenkins-Slave是否可以创建
  203. 1)创建一个Jenkins流水线项目<br />test_jenkins_slave<br />2)编写Pipeline,从GItlab拉取代码<br />3)查看构建日志<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kcZJqfA5-1624726844550)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image470.jpg)]
  204. <a name="d8900059"></a>
  205. ## Jenkins+Kubernetes+Docker完成微服务持续集成
  206. <a name="4cd5bf13"></a>
  207. ### 拉取代码,构建镜像
  208. 1)创建NFS共享目录<br />让所有Jenkins-Slave构建指向NFSMaven的共享仓库目录<br />2)创建项目,编写构建Pipeline<br />注意:在构建过程会发现无法创建仓库目录,是因为NFS共享目录权限不足,需更改权限<br />还有Docker命令执行权限问题<br />需要手动上传父工程依赖到NFSMaven共享仓库目录中
  209. <a name="f264f388"></a>
  210. ### 微服务部署到K8S
  211. 修改每个微服务的application.yml Eureka<br />其他微服务需要注册到所有Eureka中<br />1)安装Kubernetes Continuous Deploy插件<br />2)修改后的流水线脚本<br />3)建立k8s认证凭证<br />[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a0UUcJMK-1624726844550)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image481.jpg)]<br />kubeconfig到k8s的Master节点复制<br />5)生成Docker凭证<br />Docker凭证,用于Kubernetes到Docker私服拉取镜像<br />6)在每个项目下建立deploy.xml<br />Eureka的deply.yml<br />其他项目的deploy.yml主要把名字和端口修改:<br />7)项目构建后,查看服务创建情况<br />效果如下:

```