晨曦's Blog

This is a window to the soul

前记

最近在部署一个由Guns开发的一套系统,在本地测试和Gitlab Runner上执行mvn package -B -Dmaven.test.skip=true都能跳过测试,但是在CI里面就没法跳过测试

解决方案

pom中加入maven-surefire-plugin并跳过测试

1
2
3
4
5
6
7
8
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>

Guns

这里我们再介绍哈guns多模块打包方案,模块如下:

  1. guns-parent 父模块
  2. guns-core guns核心模块
  3. guns-generator 代码生成模块
  4. guns-admin 后台管理模块
  5. guns-rest API模块

下面是CI文件

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
# 定义代码目录
before_script:
- rm -rf /data/
- mkdir -p /data/
- mv * .git* /data/
- cd /data/

stages:
- deploy

maven-build:
stage: deploy
only:
- master
script:
- cd guns
   - mvn clean install # 在父模块上运行install,将依赖打包到maven本地仓库
   - cd ../guns/guns-admin
   - mvn package -B -Dmaven.test.skip=true # 这里其实可以不用打包,因为前面install的时候已经打包
   - docker build ...
- docker tag ...
   - docker push ... # 构建不同项目的镜像
   - cd ../../guns/guns-rest
- mvn package -B -Dmaven.test.skip=true # 这里其实可以不用打包,因为前面install的时候已经打包
- docker build ...
- docker tag ...
- docker push ... # 构建不同项目的镜像
tags:
- spring-boot-shell

关于构建的Dockerfile可以参考

1
2
3
4
FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY target/guns-admin-1.0.0.jar app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

前记

最近公司在部署SAP,在部署SUSE的虚拟机的过程中接到SAP实施商的一个要求,需要将虚拟机的内核进行升级。原:4.4.73-7-default,目标:4.4.140-94.42-default

升级

基础配置

开始之前记得去YaST里面防火墙打开对SSH允许,以及网络设置IP地址进行设置

获取内核

获取内核的方法有很多比如:kernel 以及opensuse;不过我是通过Suse Drivers 获取的官方的补丁包

kernel-default-4.4.140-94.42.1.x86_64

安装

在安装之前可能得通过SFTP等工具将rpm包上传到虚拟机

1
2
3
// 安装包并在安装过程中显示正在安装的文件信息及安装进度

rpm -ivh kernel-default-4.4.140-94.42.1.x86_64.rpm

重启

在更新内核后需要进行重启

1
2
3
4
5
6
7
8
// 重启

reboot

// 查看新的内核版本

uname -r
4.4.140-94.42-default

大功告成!!!

环境

目前环境是Hexo +Github Pages

再来看看部署命令npm start

1
2
3
4
5
//  package.json

"scripts": {
"start": "hexo cl && hexo g && gulp && hexo d && php -f push_sitemap_to_baidu.php"
}

我们逐条来解读

hexo cl 清除缓存文件db.json和已生成的静态文件public

hexo g 生成静态文件

gulp 将静态文件进行压缩,这部分操作可以参考之前我写的文章 —— 利用 gulp 对 Hexo 博客压缩并一键之部署

php -f push_sitemap_to_baidu.php 将文章主动推送至百度,这部分操作可以参考之前我写的文章 ——Hexo 部署在 Github Pages 怎么提交 Sitemap 给百度?来我教你

.drone.yml

通过上面我们大概了解了环境,接下里我们编写.drone.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// .drone.yml

kind: pipeline
name: default

steps:
- name: publish
 image: jakehu/php-node # 包含了PHP7+Node10+GIT环境的镜像
 pull: always
commands:
- node -v
- php -v
- npm install
 - git config --global user.email "jakehu1991@gmail.com" # 对GIT进行设置
 - git config --global user.name "jakehu" # 对GIT进行设置
- npm start

这样就完了?并没有由于我们是在DroneDIND里面进行的部署,所以我们还需要对Github权限进行设置

1
2
3
4
5
6
7
8
// _config.yml

...
deploy:
- type: git
   repo: https://jakehu:password@github.com/jakehu/jakehu.github.io.git
branch: master
...

到这里就完成,只需要进行git push每次Drone就会自动把npm start所有的工作完成了

Drone运行过程

关于DroneDocker in Docker (dind)解决方案,本人历经2天尝试了各种解决方案,最终解决方案为volumes挂载,已在本文体现

为什么

为什么?为什么要使用GogsDrone?答案是习惯!!!

工作中一般使用GIT管理工具为gitlab,自有开源项目一般都是使用的github,自有私有项目之前一直用gitee;玩Nas也有好几年了,最初也想过在Nas上通过docker搭建gitlab无奈配置不过硬

怎么说呢?了解Gogs是在它出来的那一段时间,但是也一直没有用过。最近心血来潮还是想自己在Nas上做一个GIT私有服;于是挑中了GogsGitea,鉴于两个服务属于同源最后选择了Gogs

Gogs

关于Gogs的安装我这里就不过多的赘述,可以看下面的两个文档

Gogs Github

Gogs Docker

这需要说明的是Gogs支持MySQL, PostgreSQL, SQLite3, MSSQLTiDB;目前我使用的是MySQL,关于Mysql的安装部署可以查看官方文档这里也不过多赘述

Mysql 安装文档

对于在群晖Docker中去管理Mysql的工具这里我推荐adminer安装文档如下

adminer 安装文档

最后我要说的是一个是端口映射的问题,一个是卷映射的问题,如下图


最后直接访问:http://192.168.1.2:10080就 OK 了

这里贴出一下整个Gogs配置文件

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
// /data/gogs/conf/app.ini

APP_NAME = Gogs
RUN_USER = git
RUN_MODE = prod

[database]
DB_TYPE = mysql
HOST     = 192.168.1.2:3306 // mysql地址端口
NAME     = gogs
USER = root
PASSWD   = password // mysql密码
SSL_MODE = disable
PATH = data/gogs.db

[repository]
ROOT = /data/git/gogs-repositories
publish
[server]
DOMAIN           = 192.168.1.2 // 访问域名
HTTP_PORT       = 10080 // http端口
ROOT_URL         = http://192.168.1.2/ // 访问域名
DISABLE_SSH = false
SSH_PORT         = 10022 // SSH端口
START_SSH_SERVER = false
OFFLINE_MODE = false

[mailer]
ENABLED = false

[service]
REGISTER_EMAIL_CONFIRM = false
ENABLE_NOTIFY_MAIL = false
DISABLE_REGISTRATION   = true // 禁止注册,只能有管理员能加账号
ENABLE_CAPTCHA         = true
REQUIRE_SIGNIN_VIEW   = true // 默认跳转到登录页

[picture]
DISABLE_GRAVATAR = false
ENABLE_FEDERATED_AVATAR = false

[session]
PROVIDER = file

[log]
MODE = file
LEVEL = Info
ROOT_PATH = /app/gogs/log

[security]
INSTALL_LOCK = true
SECRET_KEY = security

到此为止,我们就完成了Gogs的所有安装

Drone

Drone 安装

为什么?为什么要使用Drone还是因为习惯。因为在使用Gitlab的时候使用的CI/CD都是gitlab自带的gitlab ci;所以这里我们也需要一个CI/CD的工具于是我选择了Drone,当然市场上CI/CD的工具是比较多的

Drone安装这里我们参考官方文档

Gogs 单机安装文档

Docker命令如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
docker run \
-d \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /volume1/docker/drone:/data \
-e DRONE_GIT_ALWAYS_AUTH=false \
-e DRONE_GOGS_SERVER=http://192.168.1.2:10080 \
-e DRONE_SERVER_HOST=http://192.168.1.2:10800 \
-e DRONE_DATABASE_DRIVER=mysql \
-e DRONE_DATABASE_DATASOURCE="root:password@tcp(192.168.1.2:3306)/drone?parseTime=true" \
-p 80:80 \
-p 443:443 \
--name=drone \
drone/drone:latest

这里贴别强调一下/var/run/docker.sock:/var/run/docker.sock的挂载是必不可少的,因为后面的DIND会用到,另外因为我使用了Mysql所以上面DRONE_DATABASE_DRIVER配置为mysql

接下来访问http://192.168.1.2:10800就会出现Drone登录界面,账号为Gogs管理员账号,这两个账号相通,而且也会自动同步Gogs项目

.drone.yml

在编辑.drone.yml之前我们需要在drone管理界面对项目设置

这里需要设置项目为受信任项目,如果Project settings未显示,则表示当前用户在Drone不是管理员可以更改数据库授权为管理员

1
UPDATE `users` SET `user_admin` = '1' WHERE `user_id` = '1';

接下来我们编写.drone.yml,对于.drone.yml编写我们以Spring Boot项目为例,首先我们需要编辑DockerFile

1
2
3
4
5
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ADD target/hello-1.0.0.jar app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

接下来我们编辑.drone.yml,关于.drone.yml请参考.drone.yml 文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
kind: pipeline
name: default

steps:
- name: build
image: maven:3.5-jdk-8
commands:
- mvn package -B -Dmaven.test.skip=true # 打包跳过测试

- name: publish
image: docker:dind
volumes:
- name: docker
path: /var/run/docker.sock # dind挂载来自Drone容器/var/run/docker.sock
commands:
- docker login --username=* --password=* registry.cn-shenzhen.aliyuncs.com
- docker build -t spring-boot:master .
- docker tag spring-boot:master registry.cn-shenzhen.aliyuncs.com/new/spring-boot:master
- docker push registry.cn-shenzhen.aliyuncs.com/new/spring-boot:master

volumes:
- name: docker
host:
path: /var/run/docker.sock # 这里挂载Drone容器所在/var/run/docker.sock,当然Drone容器/var/run/docker.sock来自于群晖宿主机/var/run/docker.sock

通过上面我们定义了两步,build利用mavenSpring Boot进行了打包操作;publish利用dind将打包好的jar包通过DockerFile打包成镜像并推送到镜像仓库,这里说一下我使用的镜像仓库是阿里云

这里也请注意WebHook的地址为上面安装的Drone地址请注意填写正确

下面我们看一下Drone执行过程

到这里我们就告一段落了


以上就是群晖对接整个GogsDrone过程

最近在开发一个项目是用的eggjs同时又需要对接到微信公众平台,所以记录下自己Egg对接微信的过程

验证 Token

我们知道在微信开发时都需在公众开发配置中对Token验证一次,接下来谈谈验证的步骤

第一步确定验证 URL

比如我的是https://www.jakehu.me/wechat,那么先对eggjs路由改造

1
2
3
4
5
// app/router.js

module.exports = app => {
app.router.get('/wechat', app.controller.wechat.index);
};

改造完路由后我们还必须对安全这块进行设置,屏蔽对路由/wechatcsrf验证

1
2
3
4
5
6
7
// config/config.default.js

config.security = {
csrf: {
ignore: '/wechat',
},
};

第二步编写验证 Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// app/controller/wechat.js

async index () {
const query = this.ctx.request.query;
const signature = query.signature;
const timestamp = query.timestamp;
const nonce = query.nonce;
const echostr = query.echostr;
   if (await this.check(timestamp, nonce, signature, 'token')) {
this.ctx.body = echostr;
} else {
this.ctx.body = 'It is not from weixin';
}
}

async check (timestamp, nonce, signature, token) {
const tmp = [ token, timestamp, nonce ].sort().join('');
const currSign = crypto.createHash('sha1').update(tmp).digest('hex');
return (currSign === signature);
}

然后就可以在开发者配置进行验证就好了

注:上面代码中的token即为你在开发者配置页面中填写的token

接入开发

第一步安装必要组件

这里我们用到了co-wechat插件

1
npm i co-wechat -s

安装后对插件进行配置

1
2
3
4
5
6
7
// config/config.default.js

config.wechat = {
token: 'token',
appid: 'appid',
encodingAESKey: 'encodingAESKey',
};

编写对接代码

首先是Controller的编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// app/controller/wechat.js

const wechat = require('co-wechat');
module.exports = app => {
class WechatController extends app.Controller { }

// 因为 Egg 需要用类的形式来组织,而 wechat 是通过 middleware 方法来生成中间件
WechatController.prototype.wechat = wechat({
token: 'token',
appid: 'appid',
encodingAESKey: 'encodingAESKey',
}).middleware(async (message, ctx) => {
console.log(message);
return { type: 'text', content: 'Hello world!' };
});

return WechatController;
};

其次我们对路由再进行改造

1
2
3
4
5
// app/router.js

module.exports = app => {
app.router.post('/wechat', app.controller.wechat.wechat);
};

到此就结束了,完美对接!!!


完美对接!!!

环境

公司的GIT环境一直是用Gitlab跑在阿里云的Docker环境中的,Gitlab的配置并没有做更改,然而今天发现突然报Forbidden而且还时好时坏。通过查看官方文档【Rack Attack】发现可能是项目太多并发太高触发了 IP 屏蔽

解决方案

根据官方的文档【Rack Attack】【IP whitelist】可有如下三种方法解决:

  1. 添加IP白名单
  2. 扩大每个IP HTTP authentication次数
  3. 直接关闭Rack Attack

实践

  1. 添加IP白名单

步骤:

  • vi /etc/gitlab/gitlab.rb
  • 查找rack_attack_git_basic_auth
  • gitlab_rails['rack_attack_git_basic_auth']取消注释
  • 修改ip_whitelist白名单将gitlab部署主机 IP 地址加入
    'ip_whitelist' => ["127.0.0.1","172.16.7.21"],
  • 最后执行gitlab-ctl reconfigure重载配置

在添加白名单后发现问题依然存在,于是在上述完成后继续第二种方式

  1. 扩大每个IP HTTP authentication次数

步骤:

  • maxretry调整为200

最后配置如下:

1
2
3
4
5
6
7
gitlab_rails['rack_attack_git_basic_auth'] = {
'enabled' => true,
'ip_whitelist' => ["127.0.0.1","172.16.7.21"],
'maxretry' => 200,
'findtime' => 60,
'bantime' => 3600
}

再次执行gitlab-ctl reconfigure重载配置

完美解决!!!

前记

最近在做微信开发本地测试,需要用到80端口;鉴于Eggjs默认端口为7001,于是开始了一场Eggjs绑定80端口之战

Scripts

scripts改造,将dev命令改为如下:

1
"dev": "egg-bin dev --port=80",

问题一

当运行npm run dev之后出现下面问题

1
bind EACCES null:80, code: EACCES

绑定80端口失败,看来是权限不够

解决方案:sudo高权限运行

问题二

当运行sudo npm run dev之后出现下面问题

1
sudo: npm:找不到命令

看来是bin下面没有可执行文件

解决方案:ln -s

1
2
3
4
5
6
7
$ which npm
> /home/jakehu/.nvm/versions/node/v8.12.0/bin/npm
$ sudo ln -s /home/jakehu/.nvm/versions/node/v8.12.0/bin/npm /usr/bin/npm

$ which node
> /home/jakehu/.nvm/versions/node/v8.12.0/bin/node
$ sudo ln -s /home/jakehu/.nvm/versions/node/v8.12.0/bin/node /usr/bin/node

最后只需要运行sudo npm run dev就可以了


如果出现bind EADDRINUSE null:80, code: EADDRINUSE错误,表示有程序占用80端口,pkill掉即可

虽然度娘是一个垮掉的搜索引擎,但是谁叫它在强国是垄断的存在呢。谈谈Hexo部署在Github Pages怎么提交Sitemap给百度。

Sitemap

因为Github Pages禁止百度爬虫所以这里我们不做过多的说明,无疑这种方式是行不通的

自动推送

目前在用的一种推送方式

1
自动推送是百度搜索资源平台为提高站点新增网页发现速度推出的工具,安装自动推送JS代码的网页,在页面被访问时,页面URL将立即被推送给百度

安装方式也很简单,只需要在页面中加入以下JS即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
(function(){
var bp = document.createElement('script');
var curProtocol = window.location.protocol.split(':')[0];
if (curProtocol === 'https') {
bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
}
else {
bp.src = 'http://push.zhanzhang.baidu.com/push.js';
}
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(bp, s);
})();
</script>

主动推送 (实时)

我们重点来说说主动推送

首先我们这里需要安装一下生成sitemap的包

1
npm i hexo-generator-baidu-sitemap -s

新建文件push_sitemap_to_baidu.php,这里我们通过PHP来实现

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
<?php
// 解析xml
$file = "./public/baidusitemap.xml";
$xml = simplexml_load_file($file);
$urls = array();
foreach ($xml as $key => $value) {
$url = array();
$url = (array) $value->loc;
$urls[] = current($url);
}
// 调用百度API
$api = 'http://data.zz.baidu.com/urls?site=https://www.jakehu.me&token=***';
$ch = curl_init();
$options = array(
CURLOPT_URL => $api,
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => implode("\n", $urls),
CURLOPT_HTTPHEADER => array('Content-Type: text/plain'),
);
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
// 返回结果记录
$time = date("Y-m-d H:i:s");
$content = $time . " --- " . $result . PHP_EOL;
$file = "push_sitemap.log";
$fp = fopen($file, "a+") or die("fail to open the file");
fwrite($fp, $content);
fclose($fp);

最后会在根目录下生成push_sitemap.log日志文件

然后改造package.json如下

1
2
3
"scripts": {
"push": "hexo cl && hexo g && gulp && hexo d && php -f push_sitemap_to_baidu.php"
}

这条命令包含了清理生成压缩部署推送Sitemap,关于gulp压缩部分可看这里【点击查看】

最后我们可以直接运行命令进行部署和推送npm run push,或者将push改为start直接运行npm start即可

Headless Chrome

什么是Headless Chrome

Chrome59中开始搭载Headless Chrome。这是一种在无需显示headless的环境下运行Chrome 浏览器的方式。从本质上来说,就是不用Chrome浏览器来运行Chrome的功能!它将ChromiumBlink渲染引擎提供的所有现代Web平台的功能都带入了命令行。

intoli

开始安装之前我们来了解一下这家公司

我们(intoli)是一家在数据采集,处理和分析方面具有深厚专业知识的咨询机构。

安装

intoli在其博客上介绍了几种安装Headless Chrome的方式,我们采用如下方式安装:

1
curl https://intoli.com/install-google-chrome.sh | bash

安装完成提示:

1
Successfully installed Google Chrome!

intoli 安装文档

运行 chrome

我们可以通过如下命令来启动Chrome,同时将博客截图保存

1
google-chrome-stable --no-sandbox --headless --disable-gpu --screenshot https://www.jakehu.me

Chromedriver

chromedriver可以前往淘宝镜像下载,同时通过下面命令进行验证:

1
2
3
4
./chromedriver
Starting ChromeDriver 73.0.3683.68 (47787ec04b6e38e22703e856e101e840b65afe72) on port 9515
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.

如果有如上输出则表示驱动正常运行

最近心血来潮想鼓捣鼓捣爬虫于是玩起了pyspider,不过在启动的时候却遇到了一些小问题。

1
2
3
ValueError: Invalid configuration:
- Deprecated option 'domaincontroller': use 'http_authenticator.domain_controller' instead.

最后定位在了wsgidav3.x问题,pyspider会默认安装wsgidav3.x,解决办法为先把3.x卸载,再装2.xpip install wsgidav会默认安装2.x我安装的是2.4.1

1
2
pip uninstall wsgidav  
pip install wsgidav

如果安装的wsgidav本还是3.x,可以在卸载这个版本之后,在安装命令后面加上具体版本号

1
python -m pip install wsgidav==2.4.1
0%