- 四、Jenkins+Docker+SpringCloud微服务持续集成(上)
- 环境准备(1)-
Docker
快速入门 - 环境准备(2)-
Dockerfile
镜像脚本快速入门 - 环境准备(3)-
Harbor
镜像仓库安装及使用 - 微服务持续集成(1)-项目代码上传到Gitlab
- 微服务持续集成(2)-从Gitlab拉取项目源码
- must be unique in a given SonarQube instance
- this is the name and version displayed in the SonarQube UI. Was mandatory
- Path is relative to the sonar-project.properties file. Replace “\” by “/“ on Windows.
- This property is optional if sonar.modules is set.
- Encoding of the source code. Default is default system encoding
- FROM java:8
- !/bin/sh
- 接收外部参数
- 103上
四、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微服务部署
本地运行微服务
本地部署微服务
mvn clean package
此时打成的jar包里面没有maven里的依赖,所以不能独立启动
所以spring cloud可以boot的maven插件进行打包
1)SpringBoot微服务项目打包必须导入该插件
org.springframework.boot
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的所有镜像和容器
yum list installed | grep docker 列出当前所有docker的包
- 1
- 2
- 3
- 4
2)安装必要的软件包
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 设置开机启动
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
内容如下:
{
"registry-mirrors": ["https://zydiol88.mirror.aliyuncs.com"]
}
- 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部署的任何应用都需要先构建成为镜像
# 镜像名称 搜索镜像 # 拉取镜像 # 查看本地所有镜像#删除镜像# 例子
docker search
docker pull 镜像名称
docker images
docker rmi -f 镜像名称
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 # 删除容器
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示例:
FROM oraclelinux:7-slim
ARG MYSQL_SERVER_PACKAGE=mysql-community-server-minimal-5.7.28
ARG MYSQL_SHELL_PACKAGE=mysql-shell-8.0.18
# Install server
RUN yum install -y https://repo.mysql.com/mysql-community-minimal-releaseel7.rpm \
https://repo.mysql.com/mysql-community-release-el7.rpm \
&& yum-config-manager --enable mysql57-server-minimal \
&& yum install -y \
$MYSQL_SERVER_PACKAGE \
$MYSQL_SHELL_PACKAGE \
libpwquality \
&& yum clean all \
&& mkdir /docker-entrypoint-initdb.d
VOLUME /var/lib/mysql
COPY docker-entrypoint.sh /entrypoint.sh
COPY healthcheck.sh /healthcheck.sh
ENTRYPOINT ["/entrypoint.sh"]
HEALTHCHECK CMD /healthcheck.sh
EXPOSE 3306 33060
CMD ["mysqld"]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
-
使用Dockerfile制作微服务镜像
我们利用Dockerfile制作一个Eureka注册中心的镜像
1)上传Eureka的微服务jar包到linux
2)编写DockerfileFROM openjdk:8-jdk-alpine
ARG JAR_FILE # 设置编译镜像时加入的参数
COPY ${JAR_FILE} app.jar # 将宿主机的文件复制到容器内,并重命名
EXPOSE 10086 # 暴露端口
ENTRYPOINT ["java","-jar","/app.jar"] # 设置容器的入口程序(可以在运行中接收参数)
1
- 2
- 3
- 4
- 5
3)构建镜像
指定jar包,传到镜像里
docker build --build-arg JAR_FILE=tensquare_eureka_server-1.0-SNAPSHOT.jar -t eureka:v1 # 指定了JAR_FILE
- 1
4)查看镜像是否创建成功
docker images
- 1
5)创建容器
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-composesudo 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
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,并解压
tar -xzf harbor-offline-installer-v1.9.2.tgz mkdir /opt/harbor
mv harbor/* /opt/harbor
cd /opt/harbor
- 1
- 2
- 3
7)修改Harbor的配置
修改hostname和port
hostname: 192.168.66.102
port: 85
vi harbor.yml
- 1
- 2
- 3
- 4
- 5
- 6
8)安装Harbor
./install.sh
./prepare
- 1
- 2
- 3
9)启动Harbor
docker-compose stop 停止
docker-compose restart 重新启动
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 |
项目管理员 | 除了读写权限,同时拥有用户管理/镜像扫描等管理权限 |
把镜像上传到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
The push refers to repository [192.168.66.102:85/tensquare/eureka]
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”]
}
vi /etc/docker/daemon.json
- 1
- 2
- 3
- 4
- 5
- 6
需要重启Docker
4)再次执行推送命令,会提示权限不足
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
docker login -u 用户名 -p 密码 192.168.66.102:85
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
-
从Harbor下载镜像
需求:在192.168.66.103服务器完成从Harbor下载镜像
1)安装Docker,并启动Docker(已经完成)
2)修改Docker配置
vi /etc/docker/daemon.json
{“registry-mirrors”:[“https://zydiol88.mirror.aliyuncs.com"],"insecure-registries":["192.168.66.102:85"]} 1
- 2
- 3
- 4
重启docker
3)先登录,再从Harbor下载镜像
docker pull 192.168.66.102:85/tensquare/eureka:v1
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
$
branches
name
doGenerateSubmoduleConfigurations
extensions
submoduleCfg
userRemoteConfigs
credentialsId
url
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
2)拉取Jenkinsfile文件
<a name="affd434c"></a>
## 微服务持续集成(3)-提交到SonarQube代码审查
<a name="e795e30c"></a>
##### 1)创建项目,并设置参数
创建tensquare_back项目,添加两个参数
<a name="475b218b"></a>
##### 2)sonar-project.properties
**每个项目**的根目录下添加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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
>
> 注意:修改sonar.projectKey和sonar.projectName
>
<a name="0a8e23f5"></a>
##### 3)修改Jenkinsfile构建脚本
//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
$
branches
name
doGenerateSubmoduleConfigurations
extensions
submoduleCfg
userRemoteConfigs
credentialsId
url
defscannerHometool
sh"
cd $project_name
$scannerHomebinsonarscanner
"
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
<a name="39e3ccf1"></a>
## 微服务持续集成(4)-使用Dockerfile编译、生成镜像
利用dockerfile-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>
com.spotify
dockerfile-maven-plugin
1.3.6
${project.artifactId}
target/${project.build.finalName}.jar
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
>
> 这个xml可以和之前的编译镜像对比一下
>
> docker build --build-arg JAR_FILE=tensquare_eureka_server-1.0-SNAPSHOT.jar -t eureka:v1
>
2)在每个微服务项目根目录下建立Dockerfile文件
FROM java:8
FROM openjdk:8-jdk-alpine ARG JAR_FILE COPY ${JAR_FILE} app.jar EXPOSE 10086 ENTRYPOINT [“java”,”-jar”,”/app.jar”]
- 1
- 2
- 3
- 4
- 5
- 6
注意:每个项目公开的端口不一样<br />3)修改Jenkinsfile构建脚本<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
$
branches name
doGenerateSubmoduleConfigurations extensions submoduleCfg
userRemoteConfigs
credentialsId url
def scannerHome tool
sh "
cd $ project_name
$ scannerHomebinsonar scanner
"
def imageName
sh
sh
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
注意:如果出现找不到父工程依赖,需要手动把父工程的依赖上传到仓库中
<a name="2cf0c90d"></a>
## 微服务持续集成(5)-上传到Harbor镜像仓库
2)使用凭证管理Harbor私服账户和密码<br />先在凭证建立Harbor的凭证,在生成凭证脚本代码
生成一个id,用片段生成器语法中的wIth-creadentials<br />1)修改Jenkinsfile构建脚本
//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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
<a name="90ee5ac0"></a>
## 微服务持续集成(6)-拉取镜像和发布应用
注意:192.168.66.103服务已经安装Docker并启动<br />JK安装publish over ssh插件,可以实现远程发送Shell命令,使得部署服务器执行一些操作
<a name="1f9f51e2"></a>
#### 配置远程部署服务器
上面所述的远程调用(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)系统配置->添加远程服务器
修改Jenkinsfile构建脚本生成远程调用模板代码
选择的片段生成器是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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
编写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
<a name="d8036d9a"></a>
# 登录Harbor私服
docker login -u itcast -p Itcast123 $harbor_url
<a name="22659ffa"></a>
# 下载镜像
docker pull $imageName
<a name="b093c1c3"></a>
# 启动容器
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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
上传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信息写成部署服务器所在的地址
<a name="88a8e196"></a>
## 微服务持续集成(7)-部署前端静态web网站
<a name="bd16b83d"></a>
### 安装Nginx服务器
yum -y install nginx 安装<br />修改nginx的端口,默认80,改为9090:<br />vi /etc/nginx/nginx.conf<br />还需要关闭selinux,将SELINUX=disabled setenforce 0 先临时关闭<br />vi /etc/selinux/config 编辑文件,永久关闭 SELINUX=disabled
103上
yum install epel-release
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
启动Nginx
systemctl enable nginx 设置开机启动 systemctl start nginx 启动 systemctl stop nginx 停止 systemctl restart nginx 重启
- 1
- 2
- 3
- 4
访问:http://192.168.66.103:9090/
<a name="0e15afea"></a>
### Jenkins安装NodeJS插件
Jenkins配置Nginx服务器<br />Manage Jenkins->Global Tool Configuration
<a name="edddc737"></a>
### 创建前端流水线项目
还是创建个带branch参数的项目
建立Jenkinsfile构建脚本<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
$
branches name
doGenerateSubmoduleConfigurations
extensions
submoduleCfg
userRemoteConfigs
credentialsId
url
sh'npm install
npm run build
'
publishers
configName
transfers
cleanRemote
excludes
execCommand
execTimeout
flatten
makeEmptyDirs
noDefaultExcludes
patternSeparator
remoteDirectory
remoteDirectorySDF
removePrefix
sourceFiles
usePromotionTimestamp
useWorkspaceInPromotion
verbose
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
完成后,访问:http://192.168.66.103:9090 进行测试。
<a name="3cc86cf6"></a>
# 5、Jenkins+Docker+SpringCloud微服务持续集成(下)
<a name="269560b3"></a>
## JK+Docker+Cloud部署方案优化
上面部署方案存在的问题:<br />1)一次只能选择一个微服务部署<br />2)只有一台生产者部署服务器<br />3)每个微服务只有一个实例,容错率低<br />优化方案:<br />1)在一个Jenkins工程中可以选择多个微服务同时发布<br />2)在一个Jenkins工程中可以选择多台生产服务器同时部署<br />3)每个微服务都是以**集群高可用**形式部署
<a name="d0d6f118"></a>
## Jenkins+Docker+SpringCloud集群部署流程说明
- 生成多个镜像
- 对多个部署服务器发起远程调用
**修改所有微服务配置**
<a name="2c84c5f6"></a>
##### 注册中心配置
缩进自己调整下<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-server1、eureka-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/
EUREKAHA
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
在启动微服务的时候,加入参数: `spring.profiles.active`来读取对应的配置
<a name="b757ac20"></a>
##### 其他微服务配置
除了Eureka注册中心以外,其他微服务配置都需要加入所有Eureka服务<br /># Eureka配置eureka:client:service-url:defaultZone:::,::# Eureka访问地址instance:prefer-ip-address:true
http//192.168.66.10310086/eurekahttp//192.168.66.10410086/eureka
- 1
- 2
- 3
- 4
- 5
- 6
- 7
把代码提交到Gitlab中
<a name="a0633d06"></a>
##### 设计Jenkins集群项目的构建参数
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
- 2
- 3
- 4
最后效果:
<a name="146121a1"></a>
## 完成微服务构建镜像,上传私服
//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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
<a name="5f4ed8b7"></a>
## 完成微服务多服务器远程发布
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 />系统配置->添加远程服务器
2)修改Docker配置信任Harbor私服地址<br />重启Docker<br />3)添加参数<br />多选框:部署服务器
最终效果:<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)集群效果
<a name="5211c872"></a>
## Nginx+Zuul集群实现高可用网关
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的访问地址
<a name="e17e9bcb"></a>
# 6、基于`K8S`构建Jenkins持续集成平台(上)
<a name="a48c3646"></a>
## Jenkins的Master-Slave分布式构建
<a name="5c8ff6cf"></a>
### 什么是Master-Slave分布式构建
Jenkins的Master-Slave分布式构建,就是通过将构建过程分配到从属Slave节点上,从而减轻Master节点的压力,而且可以同时构建多个,有点类似负载均衡的概念。
<a name="3ae5bf81"></a>
### 如何实现Master-Slave分布式构建
1)开启代理程序的TCP端口<br />Manage Jenkins -> Configure 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节点的方法
| | |
| --- | --- |
| | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dc3vSkMi-1624726844541)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image401.jpg)] |
我们选择第二种:<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风格的项目:
| | |
| --- | --- |
| | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GJiowKar-1624726844542)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image405.jpg)] |
流水线风格的项目:
<a name="51ed4e8f"></a>
## Kubernetes实现Master-Slave分布式构建方案
<a name="426c57d7"></a>
### 传统Jenkins的Master-Slave方案的缺陷
Master节点发生单点故障时,整个流程都不可用了<br />每个 Slave节点的配置环境不一样,来完成不同语言的编译打包等操作,但是这些差异化的配置导致管理起来非常不方便,维护起来也是比较费劲<br />资源分配不均衡,有的 Slave节点要运行的job出现排队等待,而有的Slave节点处于空闲状态<br />资源浪费,每台 Slave节点可能是实体机或者VM,当Slave节点处于空闲状态时,也不会完全释放掉资源<br />以上种种问题,我们可以引入Kubernates来解决!
<a name="2d3d9284"></a>
### Kubernates简介
Kubernetes(简称,K8S)是Google开源的容器集群管理系统,在Docker技术的基础上,为容器化的应用提供部署运行、资源调度、服务发现和动态伸缩等一系列完整功能,提高了大规模容器集群管理的便捷性。 其主要功能如下:<br />使用Docker对应用程序包装(package)、实例化(instantiate)、运行(run)。<br />以集群的方式运行、管理跨机器的容器。以集群的方式运行、管理跨机器的容器。解决Docker跨机器容器之间的通讯问题。解决Docker跨机器容器之间的通讯问题。<br />Kubernetes的自我修复机制使得容器集群总是运行在用户期望的状态。
<a name="d199a6b1"></a>
### Kubernates+Docker+Jenkins持续集成架构图
大致工作流程:手动/自动构建 -> Jenkins 调度 K8S API ->动态生成 Jenkins Slave pod -> Slave pod拉取 Git 代码/编译/打包镜像 ->推送到镜像仓库 Harbor -> Slave 工作完成,Pod 自动销毁 ->部署到测试或生产 Kubernetes平台。(完全自动化,无需人工干预)
<a name="20624f1b"></a>
### Kubernates+Docker+Jenkins持续集成方案好处
服务高可用:当 Jenkins Master 出现故障时,Kubernetes 会自动创建一个新的 Jenkins Master<br />容器,并且将 Volume 分配给新创建的容器,保证数据不丢失,从而达到集群服务高可用。<br />动态伸缩,合理使用资源:每次运行 Job 时,会自动创建一个 Jenkins Slave,Job 完成后,Slave自动注销并删除容器,资源自动释放,而且 Kubernetes 会根据每个资源的使用情况,动态分配<br />Slave 到空闲的节点上创建,降低出现因某节点资源利用率高,还排队等待在该节点的情况。扩展性好:当 Kubernetes 集群的资源严重不足而导致 Job 排队等待时,可以很容易的添加一个 Kubernetes Node 到集群中,从而实现扩展。
<a name="cad0ba35"></a>
## Kubeadm安装Kubernetes
<a name="934bd159"></a>
### Kubernetes的架构
| | |
| --- | --- |
| | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-li8pNku5-1624726844543)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image410.jpg)] |
API Server:用于暴露Kubernetes API,任何资源的请求的调用操作都是通过kube-apiserver提供的接口进行的。<br />Etcd:是Kubernetes提供默认的存储系统,保存所有集群数据,使用时需要为etcd数据提供备份计划。<br />Controller-Manager:作为集群内部的管理控制中心,负责集群内的Node、Pod副本、服务端点<br />(Endpoint)、命名空间(Namespace)、服务账号(ServiceAccount)、资源定额<br />(ResourceQuota)的管理,当某个Node意外宕机时,Controller Manager会及时发现并执行自动化修复流程,确保集群始终处于预期的工作状态。<br />Scheduler:监视新创建没有分配到Node的Pod,为Pod选择一个Node。<br />Kubelet:负责维护容器的生命周期,同时负责Volume和网络的管理<br />Kube proxy:是Kubernetes的核心组件,部署在每个Node节点上,它是实现Kubernetes Service的通信与负载均衡机制的重要组件。
<a name="6cdd9b57"></a>
### 安装环境说明
| **主机名称** | **IP**地址 | **安装的软件** |
| --- | --- | --- |
| 代码托管服务器 | 192.168.66.100 | Gitlab-12.4.2 |
| Docker仓库服务器 | 192.168.66.102 | Harbor1.9.2 |
| k8s-master | 192.168.66.101 | kube-apiserver、kube-controller-manager、kube- scheduler、docker、etcd、calico,NFS |
| k8s-node1 | 192.168.66.103 | kubelet、kubeproxy、Docker18.06.1-ce |
| k8s-node2 | 192.168.66.104 | kubelet、kubeproxy、Docker18.06.1-ce |
**三台机器都需要完成**<br />**修改三台机器的hostname及hosts文件**<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
<a name="c80880a1"></a>
### 设置系统参数
设置允许路由转发,不对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
<a name="d92a976a"></a>
### kube-proxy开启ipvs的前置条件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
<a name="79acc91b"></a>
### 安装kubelet、kubeadm、kubectl
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)]
<a name="0012f8bd"></a>
### kubectl常用命令
7、基于Kubernetes/K8S构建Jenkins持续集成平台(下)<br />Jenkins-Master-Slave架构图回顾:
| | |
| --- | --- |
| | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-58EODeEf-1624726844547)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image407.jpg)] |
<a name="93d0cbf6"></a>
## 安装和配置NFS
<a name="01e1a5cd"></a>
### NFS简介
NFS(Network File System),它最大的功能就是可以通过网络,让不同的机器、不同的操作系统可以共享彼此的文件。我们可以利用NFS共享Jenkins运行的配置文件、Maven的仓库依赖文件等
<a name="fc78d138"></a>
### NFS安装
我们把NFS服务器安装在192.168.66.101机器上<br />1)安装NFS服务(在所有K8S的节点都需要安装)<br />2)创建共享目录<br />3)启动服务<br />4)查看NFS共享目录
<a name="8214b32a"></a>
## 在Kubernetes安装Jenkins-Master
<a name="fc7b5465"></a>
### 创建NFS client provisioner
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)
| | |
| --- | --- |
| | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uz401naD-1624726844549)(file:///C:/Users/HAN/AppData/Local/Temp/msohtmlclip1/01/clip_image460.jpg)] |
安装过程跟之前是一样的!<br />6)先安装基本的插件<br />Localization:Chinese Git<br />Pipeline<br />Extended Choice Parameter
<a name="0769c935"></a>
## Jenkins与Kubernetes整合
<a name="bc89a134"></a>
### 安装Kubernetes插件
系统管理->插件管理->可选插件Kubernetes
<a name="07318af1"></a>
### 实现Jenkins与Kubernetes整合
系统管理->系统配置->云->新建云->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
<a name="4bb0a8c6"></a>
## 构建Jenkins-Slave自定义镜像
Jenkins-Master在构建Job的时候,Kubernetes会创建Jenkins-Slave的Pod来完成Job的构建。我们选择运行Jenkins-Slave的镜像为官方推荐镜像:jenkins/jnlp-slave:latest,但是这个镜像里面并没有Maven环境,为了方便使用,我们需要自定义一个新的镜像:<br />准备材料:<br />Dockerfile文件内容如下:<br />构建出一个新镜像:jenkins-slave-maven:latest然把镜像上传到Harbor的公共库library中
<a name="2bf1ac10"></a>
## 测试Jenkins-Slave是否可以创建
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)]
<a name="d8900059"></a>
## Jenkins+Kubernetes+Docker完成微服务持续集成
<a name="4cd5bf13"></a>
### 拉取代码,构建镜像
1)创建NFS共享目录<br />让所有Jenkins-Slave构建指向NFS的Maven的共享仓库目录<br />2)创建项目,编写构建Pipeline<br />注意:在构建过程会发现无法创建仓库目录,是因为NFS共享目录权限不足,需更改权限<br />还有Docker命令执行权限问题<br />需要手动上传父工程依赖到NFS的Maven共享仓库目录中
<a name="f264f388"></a>
### 微服务部署到K8S
修改每个微服务的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 />效果如下:
```