Docker 搭建Jenkins Agent

  |  
阅读次数
  |  
字数 478
  |  
时长 ≈ 2 分钟

使用Docker搭建Jenkins服务后,因单节点不允许设置太大的执行数,所以可以创建Jenkins集群,使用Agent分担Jenkins构建的压力。

进入管理Jenkins

点击左侧菜单“Manage Jenkins(管理Jenkins)” –> “Manage Nods and Clous(管理节点)”进入节点配置界面。
Docker 搭建Jenkins Agent-1

Read More

Docker 搭建Jenkins

  |  
阅读次数
  |  
字数 304
  |  
时长 ≈ 2 分钟

使用Docker搭建Jenkins服务,因为Jenkins Job需要执行Python脚本,需要安装Paramiko模块,所以需要编写下Dockerfile进行构建。

目录结构

jenkins

  • jenkins_home
  • dockerfile_2.257
    • build.sh
    • Dockerfile
  • docker-compose.yml

编写dockerfile_2.257/Dockerfile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM jenkins/jenkins:2.257

USER root

RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list \
&& sed -i 's/security.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list \
&& apt-get clean \
&& apt-get update \
&& apt-get install -y python-pip \
&& rm -rf /var/lib/apt/lists/* \
&& pip install -i https://pypi.tuna.tsinghua.edu.cn/simple cffi \
&& pip install -i https://pypi.tuna.tsinghua.edu.cn/simple paramiko

USER jenkins

Read More

Mpvue中使用云函数

  |  
阅读次数
  |  
字数 460
  |  
时长 ≈ 2 分钟

一、介绍

在Mpvue中编辑、上传并使用小程序云函数

二、配置、使用

  1. 配置小程序云函数根目录,
    在/static目录下创建cloud/function目录,
    在该目录底下随便创建一个文件,比如“test.js”,主要目的是使发布时dist目录下面新增刚刚添加的目录。

  2. 配置project.config.json文件
    在project.config.json文件下面新增以下字段

    1
    2
    3
    {
    "cloudfunctionRoot": "/static/cloud/functions/"
    }
  3. 编译
    运行 npm run dev 编译
    注意:这可能在编译后不会生效,
    保险起见,应在后检查dist/project.config.json文件,
    看看刚刚的字段是否添加成功,如果没有,请在dist/project.config.json中也添加上述字段。

    Read More

Tampermonkey 网站自动登录脚本

  |  
阅读次数
  |  
字数 601
  |  
时长 ≈ 3 分钟

工作中经常会使用到一些内部网站,每次登录都得频繁输入用户名密码,这些动作日积月累显得很浪费时间,现在让我们来使用Chrome浏览器的Tampermonkey插件,编写一段脚本来帮我们实现自动登录功能吧。

  1. 先在Chrome浏览器的谷歌应用商店上面安装Tampermonkey。

Read More

SpringBoot integration redis分布式锁

  |  
阅读次数
  |  
字数 876
  |  
时长 ≈ 4 分钟

在使用Redis的发布/订阅功能时,由于多节点同时订阅同个通道后会同时消费,此时需要使用一定的策略来避免重复消费的情况。

以下有两种方案:

  1. 将发布者与订阅者部署在同一台机器上,然后在启动应用时动态初始化通道名称加上IP,这样由当前机器发布的消息只能由当前机器来消费,使用此方法消费者在同一机器上也最多只能部署一台。
  2. 使用分布式锁,在订阅者收到通道消息后,对当前资源加锁,抢到锁的则有权限执行业务代码。这种相对于前者而言,就显得便捷很多。本次我们使用SpringBoot Integration Redis的分布式锁完成此功能。

pom依赖

1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-redis</artifactId>
</dependency>

Read More

Dubbo Filter + SLF4J MDC 实现分布式日志追踪

  |  
阅读次数
  |  
字数 1,211
  |  
时长 ≈ 6 分钟

在使用dubbo进行分布式服务开发时,一个大系统会拆分成很多领域以及很多子服务,而且部署时会部署在不同服务器里面,这在我们使用日志排查问题时将会十分麻烦。

这里我们使用Dubbo的Filter以及SLF4J的MDC功能,来共同完成这个事情。

主要思路是:

  1. 消费端在调用调用服务端时,生成请求ID,然后将请求ID、服务器IP等参数在调用服务前进行注入,将参数带到服务提供方。
  2. 提供方在执行方法前,获取消费端设置的参数,包括请求ID、主机IP等需要用到的参数,然后设置到MDC里面,供打印日志使用,再将参数往下游服务进行传递。

代码实现:

由于dubbo在2.7.*的版本以及之前的版本包结构有所变更,
为了让大家明白这不同版本的配置差异,
这里服务端使用2.7.3的版本,消费端使用2.6.5的版本,来演示下不同版本下配置的异同。

1.定义上下游服务DubboFilter

服务消费端:ConsumerRpcTraceFilter

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
package com.faq.filter;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.common.utils.NetUtils;
import com.alibaba.dubbo.rpc.Filter;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.dubbo.rpc.RpcException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;

import java.util.UUID;

/**
* 服务消费端TraceFilter
*
* @author tidy
* @date 2019/11/15 11:23
*/
@Activate(group = {Constants.CONSUMER})
@Slf4j
public class ConsumerRpcTraceFilter implements Filter {

/**
* @param invoker
* @param invocation
*
* @return
*
* @throws RpcException
*/
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
// 如果连续调用多个服务,则会使用同个线程里之前设置的traceId
String traceId = MDC.get("traceId");
if (StringUtils.isBlank(traceId)) {
// 线程内,首次调用远端服务
traceId = UUID.randomUUID().toString();
}

// 设置日志traceId变量
MDC.put("traceId", traceId);

// 设置传递到提供端的参数
RpcContext.getContext().setAttachment("host", NetUtils.getLocalHost());
RpcContext.getContext().setAttachment("trace_id", traceId);

return invoker.invoke(invocation);
}

}

Read More

Grafana ESDOC一对多变量

  |  
阅读次数
  |  
字数 600
  |  
时长 ≈ 2 分钟

1.需求场景

需要添加一个Grafana变量,让一条ES的Document在Grafana展示时,可以出现在不同的变量筛选结果上。

2.需求效果

新建的变量名为“功能类”,需求值为(ALL、查询类、办理类、故障类、通用域)
我ES索引里面,一条Doc通过变量筛选后,可以对应多个功能类。

A -> 查询类、故障类
B -> 查询类
C -> 查询类、故障类、通用域

这里如果我们使用查询类的变量值进行筛选,应该出来A、B、C三条记录,如果使用故障类进行筛选,那出来的记录应该是A、C。

3.实现思路

  1. 在Doc上面加入新的Field,存储doc对应的功能类范围,例如上面的查询类、故障类 以及 查询类、故障类、通用域
  2. 在Grafana上新建Custom类型的变量,手动写上四个变量值。这里变量不适合使用Query类型,因为如果使用Query只能查出来查询类、故障类、通用域这种我们保存在文档里面的原始数据,而我们展示是需要每个种类单独展示的。
  3. 修改Grafana Panel,在查询语句上面使用模糊查询,将变量与Field值进行匹配。

    Read More

Dubbo 服务提供者部署在GBK服务器环境的乱码问题

  |  
阅读次数
  |  
字数 269
  |  
时长 ≈ 1 分钟

1.场景

将服务部署在一台机器上,过后发现消费端在注册中心中获取服务时,
如果获取到该服务器上的服务进行请求,处理结果为乱码,而请求另外一台服务器的服务时,结果却是正常。

2.排查

经排查这台服务器上的服务器编码为GBK,而其他正常的服务器则为UTF-8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ locale
LANG=zh_CN.GBK
LC_CTYPE="zh_CN.GBK"
LC_NUMERIC="zh_CN.GBK"
LC_TIME="zh_CN.GBK"
LC_COLLATE="zh_CN.GBK"
LC_MONETARY="zh_CN.GBK"
LC_MESSAGES="zh_CN.GBK"
LC_PAPER="zh_CN.GBK"
LC_NAME="zh_CN.GBK"
LC_ADDRESS="zh_CN.GBK"
LC_TELEPHONE="zh_CN.GBK"
LC_MEASUREMENT="zh_CN.GBK"
LC_IDENTIFICATION="zh_CN.GBK"
LC_ALL=zh_CN.GBK

3.解决

这时有两种解决方案:

  1. 修改系统的全局服务器编码为UTF-8(不知道为何,在启动脚本使用临时环境变量的方式提前执行了 export LANG=en_US.UTF-8 却无法生效。)
  2. 在启动脚本里,对jvm启动参数进行调整,设置编码格式,添加以下参数重启即可。
1
-Dfile.encoding=UTF-8

IDEA 利用Maven依赖图解决包冲突

  |  
阅读次数
  |  
字数 635
  |  
时长 ≈ 2 分钟

当我们试图向Maven项目里添加新依赖时,经常会遇到新依赖包与旧依赖包产生冲突的问题,如下图所示:

这里面,因为有两个包里面都包含完整路径为org/slf4j/impl/StaticLoggerBinder.class的类,所以导致系统不知道使用哪一个,从而启动失败,
所以,我们只需要将这两个包其中一个去除即可,现在让我们使用IDEA的一个小功能来完美解决这个包冲突问题吧。

Read More

J2EE Spring @Resource注解的扫描顺序

  |  
阅读次数
  |  
字数 836
  |  
时长 ≈ 3 分钟

让我们先来看看两段代码:

一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Service
public class FooService {}

@Service
public class BarService {}

@Controller
@RequestMapping(value = "/foo")
public class FooController {
@Resource
private FooService service;
}

@Controller
@RequestMapping(value = "/bar")
public class BarController {
@Resource
private BarService service;
}

Read More