[TOC]
## 一、环境准备
本说明是针对使用需要Java 8的Jenkins发行版。还建议使用超过512MB RAM的系统,并且在安装jenkins的服务器先装好以下环境
1. Java 8(JRE或JDK)
2. git
3. gradle/maven
4. 1G可用内存
5. 40GB +可用磁盘空间
## 二、下载Jenkins
[http://mirrors.jenkins.io/war/latest/jenkins.war](http://mirrors.jenkins.io/war/latest/jenkins.war)
## 三、创建启动文件`start.sh`
~~~
nohup java -Dhudson.util.ProcessTree.disable=true -jar jenkins.war --httpPort=8080 >> nohup.out 2>&1 &
~~~
>[info] \-Dhudson.util.ProcessTree.disable=true 参数意思为:禁止Jenkins在Job构建过程结束后认为将kill掉未执行完的子进程
> [https://wiki.jenkins.io/display/JENKINS/ProcessTreeKiller](https://wiki.jenkins.io/display/JENKINS/ProcessTreeKiller)
## 四、启动和访问
* 启动
~~~
sh start.sh
~~~
* 访问
[http://192.168.28.134:8080](http://192.168.28.134:8080/)
## 五、插件安装
### 1\. 首次登录时候的插件安装
进入选择插件安装界面,选择第一个(Install suggested plugins)

### 2\. 另外的推荐安装的插件
进入`系统管理 -> 插件管理 -> 可选插件`
* [Blue Ocean](https://wiki.jenkins-ci.org/display/JENKINS/Blue+Ocean+Plugin):pipeline流水线的增强插件
* [Gitee Plugin](https://wiki.jenkins.io/display/JENKINS/Gitee+Plugin):支持码云的插件
* [Extended Choice Parameter Plug-In](http://wiki.jenkins-ci.org/display/JENKINS/Extended+Choice+Parameter+plugin):参数化构建参数扩展
## 六、全局工具配置
* Maven 配置
配置`maven`的`settings.xml`路径

* JDK 配置

* Git 配置

* Maven 配置

## 七、安全配置
### 1\. 配置匿名可读权限

### 2\. 取消跨站请求伪造保护

## 八、Jenkins中无法启动子进程的解决办法
* **场景如下**:
在Jenkins中新建了一个Job,假设你在一些列Build Step之前/之后,启动了一个进程,打个比方说启动一个**Jboss**进程。等到Build完成,你去Console Output中查看显示启动成功,甚至PID也有了。但是当你去后台查看的时候,发现其实这个进程根本不存在,并没有启动成功。因为它没有关闭继承的文件描述符,Jenkins在Job构建过程结束后认为Jboss进程未终止,因而将其kill掉了。
* **解决办法**:
启动时添加禁用参数
~~~
nohup java -Dhudson.util.ProcessTree.disable=true -jar jenkins.war --httpPort=8080 >> nohup.out 2>&1 &
~~~
## 九、ssh免密登录
### 1\. 说明
在centos里配置免密登录之后,方便Jenkins通过ssh连接服务器操作
### 2\. 获取本地客户端机器的公钥
2.1 先看看是不是已经有了,如果有内容就忽略第二步
~~~
cat ~/.ssh/id_rsa.pub
~~~
2.2 如果上一步没有这个文件我们就创建一个,运行下面命令生成(邮箱改成自己的),一路回车就好了
~~~
ssh-keygen -t rsa -C "youremail@example.com"
~~~
### 3\. 把生成的公钥发送到对方的主机上去
用ssh-copy-id命令,自动保存在对方主机的/root/.ssh/authorized\_keys文件中去,ip地址改成需要免密登录的服务器地址
~~~
ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.28.130
~~~
### 4\. 测试
~~~
ssh 192.168.28.130
~~~
### 5\. 免密登录不生效问题解决
一般来讲失败的原因有两个:目录文件的权限和目录的属主。
5.1 目录文件的权限
.ssh父目录的权限是755(我的是/root),.ssh目录权限是700,authorized\_keys文件 600
~~~
chmod 755 /root
chmod 700 /root/.ssh
chmod 600 /root/.ssh/authorized_keys
~~~
5.2 目录的属主
如果上面方法还没有解决问题,那可能是.ssh父目录的属主存在问题。
~~~
[root@node1 ~]# ls -al .ssh
total 12
drwx------ 2 root root 80 Nov 3 10:07 .
drwxr-xr-x. 11 hdfs users 4096 Nov 3 09:38 ..
-rw------- 1 root root 0 Nov 3 10:06 authorized_keys
-rw------- 1 root root 1679 Nov 3 09:38 id_rsa
-rw-r--r-- 1 root root 390 Nov 3 09:38 id_rsa.pub
-rw-r--r-- 1 root root 0 Nov 3 10:07 known_hosts
~~~
这里发现.ssh父目录(..)的属主存在问题。
修改如下
~~~
[root@node1 ~]# chown root:root /root
[root@node1 ~]# ls -al .ssh
total 16
drwx------ 2 root root 80 Nov 3 10:07 .
drwxr-xr-x. 11 root root 4096 Nov 3 09:38 ..
-rw------- 1 root root 1135 Nov 3 10:11 authorized_keys
-rw------- 1 root root 1679 Nov 3 09:38 id_rsa
-rw-r--r-- 1 root root 390 Nov 3 09:38 id_rsa.pub
-rw-r--r-- 1 root root 0 Nov 3 10:07 known_hosts
~~~
## 十、流水线简单例子
### 1\. 介绍
Jenkins从根本上讲是一种支持多种自动化模式的自动化引擎。Pipeline在Jenkins上添加了一套强大的自动化工具,支持从简单的连续集成到全面的连续输送Pipeline的用例。通过建模一系列相关任务,用户可以利用Pipeline 的许多功能:
* 代码:Pipeline以代码的形式实现,通常被检入源代码控制,使团队能够编辑,审查和迭代其传送流程。
* 耐用:Pipeline可以在计划和计划外重新启动Jenkins管理时同时存在。
* Pausable:Pipeline可以选择停止并等待人工输入或批准,然后再继续Pipeline运行。
* 多功能:Pipeline支持复杂的现实世界连续交付要求,包括并行分叉/连接,循环和执行工作的能力。
* 可扩展:Pipeline插件支持其DSL的自定义扩展 以及与其他插件集成的多个选项。
### 2\. 新建任务
新建任务 -> 流水线
#### 2.1 General
通常情况下默认就行了

如果需要参数化构建

#### 2.2 构建触发器
如果需要通过git触发构建的话需要勾选`触发远程构建`和填写`身份验证令牌`
详细的git触发配置请看[webhook配置](./Gitlab代码仓库.md)

#### 2.3 高级项目选项
不需要填
#### 2.4 流水线
2.4.1 选择`Pipeline script`
2.4.2 本项目演示环境的pipeline脚本
> 下面的脚本仅供参考
> 是建立在目标服务器和git都已经做了**免密登录**的环境下
通常情况下
~~~
pipeline {
agent any
environment {
REPOSITORY="https://192.168.28.134/xxx/test.git"
t_dir="/opt/application/test"
t_ssh="root@10.80.98.111"
api_url="10.80.98.111:9999"
sonar_url="10.80.98.111:9000"
}
stages {
stage('获取代码') {
steps {
echo "start fetch code from git:${REPOSITORY}"
deleteDir()
git "${REPOSITORY}"
}
}
stage('代码静态检查') {
steps {
echo "start code check"
sh "mvn clean compile sonar:sonar -Dsonar.host.url=http://${sonar_url}"
}
}
stage('单元测试') {
steps {
echo "start test"
sh "mvn test"
junit '**/target/surefire-reports/TEST-*.xml'
}
}
stage('打包') {
steps {
echo "start package"
sh "sed -i 's/127.0.0.1:9999/${api_url}/g' frontend/src/main/resources/static/module/apiUrl.js"
sh "mvn package -Dmaven.test.skip=true"
}
}
stage('部署') {
steps {
echo "start deploy"
sh "ssh ${t_ssh} rm -f ${t_dir}/*.jar"
script {
def apps = ['auth-server', 'user-center', 'gateway-zuul', 'job/job-admin', 'oss-server'
, 'log-server', 'code-generator', 'frontend']
for (int i = 0; i < apps.size(); ++i) {
sh "scp ${apps[i]}/target/*.jar ${t_ssh}:${t_dir}"
}
}
}
}
stage('重启') {
steps {
echo "start restart"
script {
def apps = ['auth-server', 'user-center', 'gateway-zuul', 'job/job-admin', 'oss-server'
, 'log-server', 'code-generator', 'frontend']
for (int i = 0; i < apps.size(); ++i) {
sh "ssh ${t_ssh} 'cd ${t_dir};sh shutdown.sh ${apps[i]}'"
if ("${apps[i]}" == 'sc-admin') {
sleep 60
} else {
sleep 30
}
sh "ssh ${t_ssh} 'cd ${t_dir};sh start.sh ${apps[i]}'"
}
}
}
}
}
post {
always {
echo '构建结束...'
}
success {
echo '恭喜您,构建成功!!!'
}
failure {
echo '抱歉,构建失败!!!'
}
unstable {
echo '该任务已经被标记为不稳定任务....'
}
changed {
echo ''
}
}
}
~~~
如果需要参数化构建
>[info] 脚本里的参数`service_names`和`project_version`就是通过构建时传进去的
~~~
pipeline {
agent any
environment {
git_addr="https://192.168.28.134/xxx/test.git"
target_dir="/opt/application/test"
target_ssh="root@10.80.98.111"
api_url="10.80.98.111:9999"
sonar_url="10.80.98.111:9000"
backup_dir="/opt/app/backup"
}
stages {
stage('获取代码') {
steps {
echo "start fetch code from git:${git_addr}"
deleteDir()
git "${git_addr}"
}
}
stage('代码静态检查') {
when {
environment name:'is_test', value:'是'
}
steps {
echo "start code check"
sh "mvn clean compile sonar:sonar -Dsonar.host.url=http://${sonar_url}"
}
}
stage('单元测试') {
when {
environment name:'is_test', value:'是'
}
steps {
echo "start test"
sh "mvn test"
junit '**/target/surefire-reports/TEST-*.xml'
}
}
stage('打包') {
steps {
echo "start package"
sh "sed -i 's/127.0.0.1:9999/${api_url}/g' frontend/src/main/resources/static/module/apiUrl.js"
sh "mvn package -Dmaven.test.skip=true"
}
}
stage('部署') {
steps {
echo "start deploy"
sh '''
if [ ! -d "${backup_dir}/${project_version}" ];then
mkdir -p ${backup_dir}/${project_version}
fi
'''
script {
def apps = "${service_names}".split(",")
for (int i = 0; i < apps.size(); ++i) {
if ("${apps[i]}" == 'auth-server') {
service_path = ''
} else {
service_path = '*/'
}
sh "rm -f ${backup_dir}/${project_version}/${apps[i]}.jar"
sh "cp "+service_path+"${apps[i]}/target/*.jar ${backup_dir}/${project_version}/"
sh "ssh ${target_ssh} rm -f ${target_dir}/${apps[i]}.jar"
sh "scp "+service_path+"${apps[i]}/target/*.jar ${target_ssh}:${target_dir}"
}
}
}
}
stage('重启') {
steps {
echo "start restart"
script {
def apps = "${service_names}".split(",")
for (int i = 0; i < apps.size(); ++i) {
sh "ssh ${target_ssh} 'cd ${target_dir};sh shutdown.sh ${apps[i]}'"
if ("${apps[i]}" == 'sc-admin') {
sleep 60
} else {
sleep 30
}
sh "ssh ${target_ssh} 'cd ${target_dir};sh start.sh ${apps[i]}'"
}
}
}
}
}
post {
always {
echo '构建结束...'
}
success {
echo '恭喜您,构建成功!!!'
}
failure {
echo '抱歉,构建失败!!!'
}
unstable {
echo '该任务已经被标记为不稳定任务....'
}
changed {
echo ''
}
}
}
~~~
2.4.3 目标服务器的`shutdown.sh`内容
~~~
pid=`ps ax | grep -i $1 |grep java | grep -v grep | awk '{print $1}'`
if [ -z "$pid" ] ; then
echo "No $1 running."
fi
echo "The $1(${pid}) is running..."
kill ${pid}
echo "Send shutdown request to $1(${pid}) OK"
~~~
2.4.4 目标服务器的`start.sh`内容
~~~
nohup java -Dspring.profiles.active=test -Dpigframe.nacos.server-addr=10.80.98.111:8848 -jar -Xmx256M -Xms256M $1.jar >> /dev/null 2>&1 &
~~~
- 微服务介绍
- 软件架构设计
- 系统简介
- 运行环境
- 模块介绍
- 启动部署命令参数
- 打包说明
- 开发说明
- Java8
- 认证理论
- 有网络隔离
- 无网络隔离
- token自动续签设计
- url级权限控制
- 单点登录
- 登录
- 用户名密码(+验证码)登录
- 通过openId获取token
- 通过手机号获取token
- 第三方系统接口对接
- 第三方系统单点登录
- 通用刷新token
- 账号登出接口
- 统一异常处理
- 日志埋点工具
- 审计日志
- yml自定义配置自动提示
- Redis使用
- CacheManager集成
- 搜索中心
- 网关zuul动态路由
- swagger
- 解决开发环境的服务冲突和实例乱窜
- 多租户理论
- 多租户实现
- 分布式锁
- 分布式id生成器
- 分布式事务
- 分库分表sharding-sphere
- 消息队列
- 系统幂等性
- X 实时搜索系统设计
- Spring Cloud性能调优
- 链路跟踪
- JWT的RSA非对称密钥生成
- jdk
- Oracle
- OpenJDK
- Dragonwell
- JVM介绍
- 常见JVM内存错误及解决方案
- JVM分析工具详解
- nexus
- docker
- 安装
- docker-compose安装
- 私有仓库搭建
- 指定数据储存目录
- 添加私有仓库
- 提交拉取镜像
- X 免Dockerfile文件构建项目镜像
- 持续集成部署CI/CD
- Confluence知识管理
- JIRA事务与项目跟踪软件
- Gitlab代码仓库
- Jenkins自动化部署
- SonarQube代码检测
- Rancher容器管理平台
- nacos
- 部署
- Rancher部署nacos
- 注册中心
- 配置中心
- 多环境
- 生产部署方案
- X 通过Nginx来实现环境隔离
- Sentinel详解
- 动态规则扩展
- 在生产环境中使用 Sentinel
- 启动配置项
- X 网关流控
- ELK日志系统和慢查询SQL
- docker安装
- 普通安装
- Filebeat安装部署
- ES数据定期删除
- 没数据问题排查思路
- X Logstash的grok语法调试
- 慢查询sql
- 审计日志
- Elasticsearch性能优化
- APM监控
- SkyWalking介绍
- Zipkin,Pinpoint,SkyWalking三种服务链路监控组件分析
- 服务端部署
- 客户端部署
- 日志清理
- Metrics监控
- 二进制包部署
- docker部署
- docker安装各组件监控
- Grafana仪表盘和告警配置
- JMeter压力测试工具
- 使用说明
- 分布式事务
- TX-LCN(同步)
- X SEATA(同步)
- X RocketMQ(异步)
- 消息队列
- RocketMQ
- RocketMQ安装部署
- RocketMQ常见异常处理
- SpringCloud-Stream
- RabbitMQ
- Redis
- 单机安装
- 主从复制
- 主从复制+哨兵
- cluster集群
- 持久化方案
- MySQL
- 单机安装
- 主从复制
- 主从切换
- 主主复制
- 高可用
- 分表分库
- Canal数据库日志解析消费
- Canal安装
- 实时同步数据到ElasticSearch
- FastDFS
- docker安装
- centos安装
- 项目管理系统
- 禅道
- 111