服务器准备:
10.10.0.201 2核 4 g
10.10.0.202 2核 2 .6g
10.10.0.201软件安装:
-
docker_mysql
-
docker_harbor
-
jenkins
10.10.0.202 软件安装:
1.gitlab安装并新建项目推送代码
在服务器新建文件夹
mkdir -p /app/gitlab
运行gitlab容器
docker run --detach \
--hostname 10.10.0.202 \
--publish 80:80 --publish 23:22 \
--name gitlab \
--restart always \
--volume /app/gitlab/config:/etc/gitlab \
--volume /app/gitlab/logs:/var/log/gitlab \
--volume /app/gitlab/data:/var/opt/gitlab \
gitlab/gitlab-ce:latest
获取管理员账号密码,进入容器
docker exec -it gitlab /bin/bash
进入控制台,大概等待1分钟
gitlab-rails console
当打开控制台后依次输入下面命令来重置管理员账号和密码。
user=User.find_by_username 'root'
user.password="gaocong666" #这里请换成一个复杂的密码
user.save!
然后退出,在页面登录即可
在gitlab中新建项目,将项目的git地址加入到idea,此时想要推送代码还需操作两个步骤:
第一:将本机的公钥配置gitlab的sshkey上
第二步,在推送仓库时需要获得一个用户的tocken,点击用户头像——》密钥——》添加新密钥,将密钥输入idea的弹框即可
10.10.0.201 软件安装:
jekins:已安装并安装了可以自动webhook的插件
1.打通jenkins与gitlab,使其可以自动构建拉取代码
首先在jenkins插件管理里面下载两个插件,gitlab插件和[GitLab Authentication plugin插件
然后进入系统管理进行设置:
新建了pipline项目后,一步步配置即可
其中流水线按照如下配置:
其中注意的点是我在构建时增加了一个拉取分支的参数,这样在用户点击构建的时候可以选取分支
下面是拉取代码时需要注意的点
最后的jenkinsfile为拉去代码的脚本,这样设置会读取项目中的jenkinsfile
里面的代码可以使用上图中最后的流水线语法自动生成
//git凭证ID
def git_auth = "ec2f1020-6b2d-4838-b347-0efcfb153990"
//git的url地址
def git_url = "http://10.10.0.202/root/spring_boot.git"
node {
stage('拉取代码') {
checkout scmGit(branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]])
}
}
到这里是可以成功拉取到了代码,接下来继续配置webhook自动构建
在我配置webhook的时候又踩坑了!!!
在我添加10.10.0.201虚拟机的jenkins上的webhook的时候,提示我报错
解决:点击这里
这样再去添加webhook测试一下
就这样测试了一下,可以了。到这里算是拉取代码这一块彻底打通了
2.根据设置构建参数编译不同的项目
在项目配置中增加一个项目名字的参数,用于后面选择不同的微服务名称就会编译打包不同的微服务,非常nice
但是当我们使用这种选择性构建的时候就不可以用webhook了,因为它无法识别你要编译打包哪个项目
由于我增加了选择项目的构建参数,所以我的jenkinsfile更改成如下格式:
ok,现在我去掉webhoook进行项目打包
报错了!!!
显示没有找到父项目工程的文件,这里需要我手动把文件放到maven的仓库内,让服务在加载依赖的时候可以读取到
现在再次打包,没有问题,把四个服务全部打包放好。
3.构建docker镜像
现在是所有的服务jar包都已经做好,接下来就要制作镜像了
- 第一步制作镜像需要使用到maven中的一个插件
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.3.6</version>
<configuration>
<repository>${project.artifactId}</repository>
<buildArgs>
<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
其中的${project.artifactId}是项目的artifactId, ArtifactID就是项目的唯一的标识符,实际对应项目的名称,就是项目根目录的名称
其中的target/${project.build.finalName}.jar是jar包的路径
- 添加了这个插件后需要修改jenkinsfile文件中的pipline语法:
#pipline中的一段代码,其中最后的dockerfile:build就会调用到上面的插件
stage('根据选择编译相应微服务') {
sh "/opt/maven3.9/apache-maven-3.9.4/bin/mvn -f ${projectname} clean package dockerfile:build"
}
- 必不可少的Dockerfile文件
#FROM java:8
#其中的 ${JAR_FILE} 就会获取到ockerfile-maven-plugin插件中的JAR_FILE的值,也就是jar包的路径加名字
FROM openjdk:8-jdk-alpine
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
EXPOSE 9001
ENTRYPOINT ["java","-jar","/app.jar"]
四个服务的Dockerfile根据实际情况进行编排,并在项目下,当Jenkins拉取代码并编译完成后,就会触发后面的dockerfile:build,而此时工作目录在那个服务下就会build下面的Dockerfile文件,产生镜像,最终四个服务的镜像都已制作完成
4.推送镜像harbor
想要推送harbor肯定是要先登录harbor,那么怎么样可以登陆呢?直接在pipline中写docker login - u xxx -p xxx 吗?当然也可以,但是这样账户密码就直接暴露在外面了,接下来用变量的方式登录harbor
第一步,先根据harbor的账号密码在Jenkins上生成一个可以登录仓库的令牌
第二步,根据片段生成器生成一段可以引用令牌中的账号密码的一个方法
第三步,在方法内写登录远程仓库的方法体
withCredentials([usernamePassword(credentialsId: "${harbor_key}", passwordVariable: 'passwd', usernameVariable: 'username')]) {
//登录harbor仓库
sh "docker login -u ${username} -p ${passwd} ${harbor_url}"
sh "echo '登录仓库成功'"
//推送镜像到仓库
sh "docker push ${harbor_url}/${harbor_repo}/${image_name}"
sh "echo '上传${image_name}成功'"
}
以下为完整pipline脚本
推送结果展示:
10.10.0.203 生产环境:
第一步:持续集成服务器与生产服务器实现免密登录
目前持续集成化服务器配置已经完成,可以一键构建相应服务镜像到远程仓库,接下来需要完成调度生产环境拉取远程仓库镜像并启动容器
那么必然需要jenkins所在的持续集成服务器远程调度生产服务器上的部署服务的脚本才可以完成,那么就要配置jenkins所在服务器与生产服务器是免密登录的
把持续集成服务器的密钥拷贝至生活服务器即可:
ssh-copy-id 10.10.0.203
第二步:配置生产服务器可以登录远程仓库
修改/etc/docker/daemon.json文件,然后重启一下docker读取配置
登陆测试:登陆成功
第三步:jenkins下载Publish Over SSH插件可以远程生产服务器
在jenkins上选择系统管理–》系统配置
第四步:增加部署服务开放端口
因为使用docker部署服务肯定是开放端口的,所以需要增加一个端口的可选参数
第五步:将部署脚本上传至生产环境
部署服务的脚本:/opt/jenkins_shell/deploy.sh

#! /bin/sh
#接收外部参数
harbor_url=$1
harbor_project_name=$2
project_name=$3
tag=$4
port=$5
imageName=$harbor_url/$harbor_project_name/$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 eric -p Eric123456 $harbor_url
# 下载镜像
docker pull $imageName
# 启动容器
docker run -di -p $port:$port $imageName
echo "容器启动成功"
上传:
第六步:在流水线脚本内增加部署服务的步骤
通过流水线生成器生成触发生产服务器部署脚本的步骤
流水线脚本中的 **execCommand: ‘’,**就是用来写脚本的地方
这里通过传入参数的方式执行脚本
/opt/jenkins_shell/deploy.sh #为生产服务器脚本位置
$harbor_url #远程仓库地址
$harbor_repo #远程仓库仓库名
$projectname# 服务项目名
$image_tag #镜像版本
$serverOpen_port #docker服务容器开放的端口,对应第四步
完整的流水线脚本
//git凭证ID
def git_auth = "ec2f1020-6b2d-4838-b347-0efcfb153990"
//git的url地址
def git_url = "http://10.10.0.202/root/spring_boot.git"
//镜像版本
def image_tag = "latest"
//harbor地址
def harbor_url = "101.34.240.151:9999"
//harbor仓库名
def harbor_repo = "spring_boot"
//jenkins配置harbor令牌
def harbor_key = "884f5348-0c5b-4b2e-bc7e-d04ebe03eb75"
//服务要开放的端口,这里的port对应Jenkins上流水线配置的port参数
def serverOpen_port = "${port}"
node {
stage('拉取代码') {
checkout scmGit(branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]])
}
stage('首先编译安装公共工程,因为别的微服务需要依赖他') {
sh "/opt/maven3.9/apache-maven-3.9.4/bin/mvn -f tensquare_common clean install"
}
stage('根据选择编译相应微服务并生成镜像') {
// projectname 就是镜像名
sh "/opt/maven3.9/apache-maven-3.9.4/bin/mvn -f ${projectname} clean package dockerfile:build"
sh "echo '成功生成${projectname}镜像'"
}
stage('将镜像推送至harbor') {
//镜像名+版本号
def image_name = "${projectname}:${image_tag}"
//将镜像打包成规范格式这样可以推送harbor仓库 ,语法 docker tag 镜像名 harbor_ip:port/远程仓库名/自定义镜像名
sh "docker tag ${image_name} ${harbor_url}/${harbor_repo}/${image_name}"
sh "echo '镜像打标签完成'"
withCredentials([usernamePassword(credentialsId: "${harbor_key}", passwordVariable: 'passwd', usernameVariable: 'username')]) {
//登录harbor仓库
sh "docker login -u ${username} -p ${passwd} ${harbor_url}"
sh "echo '登录仓库成功'"
//推送镜像到仓库
sh "docker push ${harbor_url}/${harbor_repo}/${image_name}"
sh "echo '上传${image_name}成功'"
sh "echo '开始调动生产服务器执行部署${projectname}服务脚本'"
sh "echo '${harbor_url} ${harbor_repo} ${image_name} ${image_tag} ${serverOpen_port}'"
//远程生产服务器启动部署脚本,
sshPublisher(publishers: [sshPublisherDesc(configName: '生产服务器203', transfers: [sshTransfer(cleanRemote: false, excludes: '',
execCommand: "/opt/jenkins_shell/deploy.sh $harbor_url $harbor_repo $projectname $image_tag $serverOpen_port",
execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
sh "echo '成功部署${image_name}服务'"
}
}
}
opt/jenkins_shell/deploy.sh $harbor_url $harbor_repo $projectname $image_tag $serverOpen_port",
execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: ‘[, ]+’, remoteDirectory: ‘’, remoteDirectorySDF: false, removePrefix: ‘’, sourceFiles: ‘’)], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
sh "echo '成功部署${image_name}服务'"
}
}
}