关闭防火墙
先在Centos7上关闭防火墙,方便验证,等服务全部部署成功后可以根据需要开启哪些端口
查看开放了哪些端口 firewall-cmd --list-all
如果显示为 FirewallD is not running 表示防火墙已关闭
永久打开8080端口
firewall-cmd --permanent --add-port=8080/tcp
执行完后一定要刷新,否则不生效
firewall-cmd --reload
docker安装
关于centos7安装docker的教程很多,这里就展开说了;只说一些注意事项:
- 使用阿里云镜像加速,不推荐使用官方的镜像地址,因为很慢
- 开启docker自启动,防止机器宕机重启后需要手动启动docker
- 修改镜像存储位置,防止镜像文件过多的占用var文件夹
- 关于docker远程部署开启2376端口,我的建议是没有安全策略的前提下不要开启,有黑客全网扫描2376端口然后入侵机器挖矿或病毒,我的机器就被入侵过
rancher1.x安装
关于为什么使用1.x的版本而不是使用2.x版本:
- ranche1.x相对于2.x版本来说,功能更加简单易上手,维护成本比较低
- 对于中小型的分布式或者微服务项目来说,docker的学习和运维成本远低于K8S
- rancher2.x的功能相对复杂,更多的功能是为了K8S或者云原生,没有必要将资源浪费在不需要的功能上
话不多说,开始安装rancher
- docker搜索rancher
docker search rancher
- 选择对应的版本 1.x的版本是 rancher/server 2.x的版本是rancher/rancher
- 拉取最新版本的镜像
docker pull rancher/server
- 单节点部署
sudo docker run -d --restart=unless-stopped -v /etc/localtime:/etc/localtime:ro -p 8080:8080 rancher/server
- 多节点部署参考官方文档
- 部署完成以后添加主机,可以先创建环境再添加 这个比较简单不多说(rancher右下角可以选择中文)
安装镜像仓库
- 个人或者小型项目推荐register
- 中大型项目必须使用Harbor
- 在rancher首页中选择环境,添加应用,添加完成后添加服务
- register的容器中存储镜像的位置是
/var/lib/registry
,宿主机可以自己选择
jenkins安装
- 在rancher首页中选择环境,添加应用,添加完成后添加服务
- 选择镜像填入:
jenkins/jenkins:lts
最新稳定版 - 私有容器端口为
8080
,因为jenkins的服务端口是8080;宿主机端口可以自己设置 - 滑到最下面选择
卷
,然后添加卷
- 总共需要添加4个卷
/home/jenkins_home:/var/jenkins_home
/var/run/docker.sock:/var/run/docker.sock
/usr/bin/docker:/usr/bin/docker
/etc/localtime:/etc/localtime:ro
- 第一个表示将jenkins的所有文件映射到主机,后续方便jenkins升级或者重启时防止数据丢失
- 第二个表示将宿主机的docker的进程通信映射到jenkins容器中,这是在容器中使用docker所必须的
- 第三个表示将宿主机的docker命令映射到jenkins容器中,可以让jenkins使用docker命令
- 第四个表示容器时间与宿主机时间同步
- 卷添加完后选择
命令
,然后在工作目录
一行选择用户
,在用户
栏填入0
,表示容器以root方式运行 - 至此jenkins关键信息全部填写完成,创建服务完成后等待服务部署成功
- 服务部署成功后可以点击端口号直接进入jenkins界面,当然也可以输入ip:port进入
使用jenkins
- 密码在容器日中可以看到
- 选择推荐插件
- 进入jenkins主界面 Dashboard
- 进入系统管理,插件管理里面安装所需要的插件
[Pipeline Maven Integration Plugin](https://plugins.jenkins.io/pipeline-maven)
[Docker Pipeline](https://plugins.jenkins.io/docker-workflow)
[Rancher](https://plugins.jenkins.io/rancher)
[DingTalk](https://plugins.jenkins.io/dingding-notifications)
[NodeJS Plugin](https://plugins.jenkins.io/nodejs)
- maven项目 Pipeline Maven Integration Plugin
- docker pipeline插件
- rancher插件,用于远程自动部署
- DingTalk用于钉钉通知
- NodeJS用于nodejs项目,比如vue
-
安装好后重启jenkins:重启方式
- 1.插件安装完成等待系统空闲自动重启
- 2.rancher中直接重启jenkins
- 3.jenkins的
IP:PORT/restart
重启
-
jenkins配置完成以后,创建钉钉群,添加机器人
-
添加nodejs,jdk,maven等配置
- 将宿主机下载好的nodejs,jdk,maven文件复制到jenkins与宿主机映射的目录;比如题主映射的是/home/jenkins_home:/var/jenkins_home;然后进入宿主机的/home/jenkins_home/workspace下,将文件加压出来
-
配置JDK
-
配置maven
-
配置nodejs
注意事项
- 别名要规范,在Jenkinsfile中严格对应
- 安装目录都是容器内的目录,不是宿主机目录
- 进入系统管理-Manage Credentials中 需要添加两个2个凭据 1.rancher的API秘钥(用于自动化部署) 2.git账户的秘钥(用户拉取代码)
关于为什么使用pipeline(管道流)
- pipeline是声明式,所有的步骤都是在代码中完成,可控性好,流程清晰
- jenkins数据丢失后可以快速的恢复
- pipeline使用的是groovy语法,简单明了清晰
- 对初中级开发人员不怎么友好
springboot项目使用pipeline
- 在项目中创建两个文件夹docker jenkins
- 在docker文件夹中创建Dockerfile文件
- 在jenkins文件夹中创建Jenkinsfile文件 废话不多说,直接上jenkinsfile内容,不懂得可以评论区讨论 最终效果是:
import java.text.SimpleDateFormat
def project_name = 'zjjg'
def git_account_credentialsId = '0ae8cb60-6585-4ba6-af3c-d9b3f73ec609'
def maven_settings_credentialsId = '3b0d6c7f-0a54-4683-a29c-3e504b8c74b3'
def dingtalk_credentialsId = '58b7a898-819b-4295-8a5c-96aaae63f513'
def image_repo_url = 'IP:5000'
def specificCause = currentBuild.getBuildCauses('hudson.model.Cause$UserIdCause')
def sdf = new SimpleDateFormat("yyyyMMddHHmmss")
def image_version = sdf.format(new Date())
def rancher_credentialsId='149a7d47-d817-4544-9947-be1b177af8a7'
def rancherUrl = 'http://IP:8088/v2-beta'
def rancherEnv = '1a5'
def rancherService = 'service/zjjgjp'
pipeline {
agent any
environment {
applier_name="$specificCause.userName"
}
parameters {
string(name: 'BRANCH', defaultValue:'yuhua-formal' ,description:'选择分支,默认雨花分支')
choice(name: 'SkipTests', choices: ['true','false'],description: '编译调过单元测试')
choice(name: 'StartFirst', choices: ['false','true'],description: '是否第一次部署')
choice(name: 'confirm', choices: ['true','false'],description: '是否升级完成自动确认')
}
stages {
stage('Send dingtalk'){
steps {
dingtalk (
robot: "${dingtalk_credentialsId}",
type: 'MARKDOWN',
title: 'XXX后端开始构建',
text: ['## XXX',
'- 任务:<font color=#6495ED>流水线任务开始执行</font>',
'- 状态:<font color=#008000>正常</font>',
'- 分支:<font color=#6495ED>${BRANCH}</font>',
'- 地址:<font color=#6495ED>[查看](http://IP:9001/job/zjjg/job/zjjg/)</font>',
'- 执行人:${applier_name}'],
)
}
}
stage('Pull Code') {
steps {
git branch: "${params.BRANCH}",
credentialsId: "${git_account_credentialsId}",
url: 'https://git.jsruiyin.com/niu_123/zjjg.git'
}
post {
failure {
dingtalk (
robot: "${dingtalk_credentialsId}",
type: 'MARKDOWN',
title: 'XXX后端构建失败',
text: ['## XXX',
'- 任务:<font color=#6495ED>流水线任务执行结束</font>',
'- 状态:<font color=#FF0000>代码拉取失败</font>',
'- 地址:<font color=#6495ED>[查看](http://IP:9001/job/zjjg/job/zjjg/)</font>',
'- 执行人:${applier_name}'],
)
}
aborted {
dingtalk (
robot: "${dingtalk_credentialsId}",
type: 'MARKDOWN',
title: 'XXX后端构建失败',
text: ['## XXX',
'- 任务:<font color=#6495ED>流水线任务执行结束</font>',
'- 状态:<font color=#FFA500>代码拉取手动终止</font>',
'- 执行人:${applier_name}'],
)
}
}
}
stage('Build Code') {
steps {
timeout(time: 30, unit: 'MINUTES') {
withMaven(
jdk: 'jdk1.8',
maven: 'maven',
mavenSettingsConfig: "${maven_settings_credentialsId}") {
sh "mvn -U clean package -Dmaven.test.skip=${SkipTests}"
}
}
}
post {
failure {
dingtalk (
robot: "${dingtalk_credentialsId}",
type: 'MARKDOWN',
title: 'XXX后端构建失败',
text: ['## XXX',
'- 任务:<font color=#6495ED>流水线任务执行结束</font>',
'- 状态:<font color=#FF0000>编译失败</font>',
'- 地址:<font color=#6495ED>[查看](http://IP:9001/job/zjjg/job/zjjg/)</font>',
'- 执行人:${applier_name}'],
)
}
aborted {
dingtalk (
robot: "${dingtalk_credentialsId}",
type: 'MARKDOWN',
title: 'XXX后端构建失败',
text: ['## XXX',
'- 任务:<font color=#6495ED>流水线任务执行结束</font>',
'- 状态:<font color=#FFA500>编译手动终止</font>',
'- 执行人:${applier_name}'],
)
}
}
}
stage('Build Docker Image'){
steps {
script {
sh "mv target/zjjg.jar docker/zjjg.jar"
def customImage = docker.build("${image_repo_url}/${project_name}:${image_version}","-f docker/Dockerfile .")
customImage.push()
sh "rm -rf docker/zjjg.jar"
}
}
post {
failure {
dingtalk (
robot: "${dingtalk_credentialsId}",
type: 'MARKDOWN',
title: 'XXX后端构建失败',
text: ['## XXX',
'- 任务:<font color=#6495ED>流水线任务执行结束</font>',
'- 状态:<font color=#FF0000>镜像构建失败</font>',
'- 地址:<font color=#6495ED>[查看](http://IP:9001/job/zjjg/job/zjjg/)</font>',
'- 执行人:${applier_name}'],
)
script {
sh "rm -rf docker/zjjg.jar"
}
}
aborted {
dingtalk (
robot: "${dingtalk_credentialsId}",
type: 'MARKDOWN',
title: 'XXX后端构建失败',
text: ['## XXX',
'- 任务:<font color=#6495ED>流水线任务执行结束</font>',
'- 状态:<font color=#FFA500>镜像构建手动终止</font>',
'- 执行人:${applier_name}'],
)
}
}
}
stage('Deploy'){
steps {
rancher(
environmentId: "${rancherEnv}",
endpoint: "${rancherUrl}",
credentialId: "${rancher_credentialsId}",
service: "${rancherService}",
image: "${image_repo_url}/${project_name}:${image_version}",
confirm: "${confirm}",
startFirst : "${StartFirst}",
ports: '8002:8002',
environments: '',
timeout: 300
)
}
post {
success {
dingtalk (
robot: "${dingtalk_credentialsId}",
type: 'MARKDOWN',
title: 'XXX后端构建完成',
text: ['## XXX',
'- 任务:<font color=#6495ED>流水线任务执行结束</font>',
'- 状态:<font color=#008000>部署成功</font>',
'- 执行人:${applier_name}'],
)
}
failure {
dingtalk (
robot: "${dingtalk_credentialsId}",
type: 'MARKDOWN',
title: 'XXX后端构建失败',
text: ['## XXX',
'- 任务:<font color=#6495ED>流水线任务执行结束</font>',
'- 状态:<font color=#FF0000>镜像启动失败</font>',
'- 地址:<font color=#6495ED>[查看](http://IP:9001/job/zjjg/job/zjjg/)</font>',
'- 执行人:${applier_name}'],
)
}
changed {
script {
echo "构建状态和之前不一致"
}
}
aborted {
dingtalk (
robot: "${dingtalk_credentialsId}",
type: 'MARKDOWN',
title: 'XXX后端构建失败',
text: ['## XXX',
'- 任务:<font color=#6495ED>流水线任务执行结束</font>',
'- 状态:<font color=#FFA500>手动终止</font>',
'- 执行人:${applier_name}'],
)
}
unstable {
script {
echo "构建结果不稳定"
}
}
}
}
}
}