0%

阿里云ESC服务器挂载 OSS 文件系统

ossfs 能让您在Linux/Mac OS X 系统中把Aliyun OSS bucket 挂载到本地文件 系统中,您能够便捷的通过本地文件系统操作OSS 上的对象,实现数据的共享。

阿里云oss官方:ossfs挂载,您可以理解为把挂载的bucket当做一个ecs目录来操作的,存储文件到挂载的bucket中是占用的这个bucket的内存,不会占用您ecs的内存。

安装

  1. 下载文件ossfs_1.80.3_centos7.0_x86_64.rpm到阿里云

  2. 安装sudo yum localinstall ossfs_1.80.3_centos7.0_x86_64.rpm

  3. 写入oss配置echo my-bucket:my-access-key-id:my-access-key-secret > /etc/passwd-ossfs,例:

    1
    echo ossfs-xuan:LTAIw5M5SHnIoNcm:ci1Oj7*******ZqDziBj > /etc/passwd-ossfs
  4. 更改配置文件权限chmod 640 /etc/passwd-ossfs

  5. 创建挂载目录mkdir /ossfs

  6. 挂载ossfs ossfs-xuan /ossfs -ourl=oss-cn-shenzhen-internal.aliyuncs.com

额外的命令

1
2
3
4
#允许linux其他用户对改oss文件系统进行操作
ossfs ossfs-xuan /ossfs -ourl=oss-cn-shenzhen-internal.aliyuncs.com -o allow_other
#卸载挂载oss目录
umount /ossfs

错误

InvalidBucketName错误可以看出BucketName重复了

1
2
3
4
5
6
7
8
9
ossfs: bad request
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>InvalidBucketName</Code>
<Message>The specified bucket is not valid.</Message>
<RequestId>5A93BFD701A3E286AC09FDDD</RequestId>
<HostId>ossfs-xuan.ossfs-xuan.oss-cn-shenzhen-internal.aliyuncs.com</HostId>
<BucketName>ossfs-xuan.ossfs-xuan</BucketName>
</Error>

解决:-ourl=oss-cn-shenzhen-internal.aliyuncs.com不需要带BucketName

自动初始化gitment评论

暂时不采用,见不足。

需求

每次发布文章,会自动产生issue但是发布一篇就要点击initialize comments按钮才能初始化评论,下面的步骤通过GitHub api实现ruby脚本自动初始化评论

步骤

  1. 添加sitemap,参考hexo seo优化Google添加站点地图

    主要再配置文件.travis.yml添加 - npm install hexo-generator-sitemap --save,编译后会产生一个sitemap.xml对应url:http://bolg.iexxk.com/sitemap.xml,url后面会用到

  2. 在github的setting->Developer settings-> Personal access tokens->Generate new token生成一个新的token 勾选repo,记住保存好token只会显示一次

  3. 在travis-ci添加GITMENT环境变量存储上一步生成的token,似乎GitHub不能把token明码直接放到脚本里,会导致GitHub的token失效消失

  4. 新建脚本文件comment.rb,放到source\目录,一次填入自己的信息,这里新加了忽略openssl的校验,以及token通过命令传参进行传入

    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
    username = "xuanfong1" # GitHub 用户名
    new_token = ARGV.first # GitHub Token,通过命令行参数传进来,获取第一个参数
    repo_name = "xuanfong1.github.io" # 存放 issues
    sitemap_url = "http://bolg.iexxk.com/sitemap.xml" # sitemap
    kind = "gitment" # "Gitalk" or "gitment"

    require 'open-uri'
    require 'faraday'
    require 'active_support'
    require 'active_support/core_ext'
    require 'sitemap-parser'
    # 忽略openssl校验
    require 'openssl'
    OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

    puts"Token: #{new_token}"

    sitemap = SitemapParser.new sitemap_url
    urls = sitemap.to_a

    conn = Faraday.new(:url => "https://api.github.com/repos/#{username}/#{repo_name}/issues") do |conn|
    conn.basic_auth(username, new_token)
    conn.adapter Faraday.default_adapter
    end

    urls.each_with_index do |url, index|
    title = open(url).read.scan(/<title>(.*?)<\/title>/).first.first.force_encoding('UTF-8')
    response = conn.post do |req|
    req.body = { body: url, labels: [kind, url], title: title }.to_json
    end
    puts response.body
    sleep 15 if index % 20 == 0
    end
  5. 添加脚本执行命令,在.travis.yml添加安装 - gem install faraday activesupport sitemap-parser和执行脚本 - ruby comment.rb ${GITMENT}

    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
    language: node_js
    node_js: stable
    install:
    - npm install
    - npm install hexo-generator-sitemap --save
    - npm install hexo-generator-baidu-sitemap --save
    - gem install faraday activesupport sitemap-parser
    script:
    - hexo cl
    - hexo g
    after_script:
    - cd ./public
    - git init
    - git config user.name "xuanfong1"
    - git config user.email "xuan.fong1@163.com"
    - git add .
    - git commit -m "update"
    - git push --force --quiet "https://${BLOG_GITHUB}@${GH_REF}" master:master
    - ruby comment.rb ${GITMENT}
    branches:
    only:
    - hexo
    env:
    global:
    - GH_REF: github.com/xuanfong1/xuanfong1.github.io.git
不足
  1. 会初始化多余的评论,例如目录页,没做过滤
  2. 编译时间长
  3. 相同issues可以创建多次,而且官方没提供删除接口
  4. 概率性出现验证失败
错误解决
  1. 证书错误

    1
    OpenSSL::SSL::SSLError SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed

    解决,在脚本添加忽略证书校验

    1
    2
    require 'openssl'
    OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
参考

自动初始化 Gitalk 和 Gitment 评论

需求

每次新建文章时都要新建文件然后复制文章头,或者复制其他文件,很麻烦,因此弄一个命令直接生产一个文件带模板

脚本详解

前面几篇介绍过关于nodejs文件系统了这里就不介绍了,主要解释下脚本如何传参数

process.argv[2]第一个参数,为什么是2,因为1是脚本文件本身所以第一个参数就是2,第二个参数就是3,依次叠加

关于文章默认创建时间以及更新时间都是以当前时间为准

命令使用

1
2
3
4
5
filename <参数1> <参数2> <参数4>
#参数1 文件名也是标题名
#参数2 分类,也就是类别
#参数3 标签,多个用英文逗号分离
#当一个参数都没默认会创建一个空标题文件名为newfile.md的文件标签和分类默认也为空

eg: 假设脚本文件名字为new执行new 标题 java java,nodejs会生成一个标题.md文件内容如下

1
2
3
4
5
6
7
---
title: 标题
date: 2018-01-30 00:07:03
updated: 2018-01-30 00:23:06
categories: java
tags: [java,nodejs]
---
额外注意

如果脚本放的目录就是文章生产的目录,因此放入hexo时记得设置.gitignore不要让这个文件也被上传编译了

脚本内容
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
56
57
58
59
60
61
62
63
#!/usr/bin/env node
/*
通过改模板快速创建文章
*/

/*
---
title: WSL使用ssh
date: 2017-11-22 22:12:28
updated: 2018-01-30 00:23:06
categories: WSL
tags: [ssh,ubuntu,sshd]
---
*/
console.log("开始创建文章");
//取第一个参数,因为1被脚本自己本身占用,所以这里是2
var title=process.argv[2]?process.argv[2]:""; //标题也是文件名
var categories=process.argv[3]?process.argv[3]:""; //分类
var tags=process.argv[4]?process.argv[4]:""; //标签 英文逗号分离
var filename=process.argv[2]?process.argv[2]:"newfile";

var fs = require("fs"); //请求文件系统
var template=[];
template.push('---'+'\r');
template.push('title: '+title+'\r');
template.push('date: '+getFormatDate(Date.now())+'\r');
template.push('updated: '+getFormatDate(Date.now())+'\r');
template.push('categories: '+categories+'\r');
template.push('tags: ['+tags+']'+'\r');
template.push('---'+'\r');
var result=template.join('');
fs.writeFile(filename+'.md', result, 'utf8',function(err) { //写入新的文件内容
if (err) return console.log("写文件错误:",err);
console.log("创建"+title+".md文件成功:",result);
});


/*
timeStr:时间,格式可为:"September 16,2016 14:15:05、
"September 16,2016"、"2016/09/16 14:15:05"、"2016/09/16"、
'2014-04-23T18:55:49'和毫秒
dateSeparator:年、月、日之间的分隔符,默认为"-",
timeSeparator:时、分、秒之间的分隔符,默认为":"
*/
function getFormatDate(timeStr, dateSeparator, timeSeparator) {
dateSeparator = dateSeparator ? dateSeparator : "-";
timeSeparator = timeSeparator ? timeSeparator : ":";
var date = new Date(timeStr),
year = date.getFullYear(),// 获取完整的年份(4位,1970)
month = date.getMonth(),// 获取月份(0-11,0代表1月,用的时候记得加上1)
day = date.getDate(),// 获取日(1-31)
hour = date.getHours(),// 获取小时数(0-23)
minute = date.getMinutes(),// 获取分钟数(0-59)
seconds = date.getSeconds(),// 获取秒数(0-59)
Y = year + dateSeparator,
M = ((month + 1) > 9 ? (month + 1) : ('0' + (month + 1))) + dateSeparator,
D = (day > 9 ? day : ('0' + day)) + ' ',
h = (hour > 9 ? hour : ('0' + hour)) + timeSeparator,
m = (minute > 9 ? minute : ('0' + minute)) + timeSeparator,
s = (seconds > 9 ? seconds : ('0' + seconds)),
formatDate = Y + M + D + h + m + s;
return formatDate;
}

前提介绍

上篇介绍了批量写入文件的修改时间用于hexo博客的初始化,这篇是在上篇基础上添加的新需求

上篇有的方法这篇就不介绍了

需求描述

由于每次修改了文章,都要改文章的头部的更新时间,如此机械的事当然要交给程序来做啦,因此写了此脚本

设计

  1. 更新文章更新时间脚本逻辑updateFileTime.nodejs

       graph LR
    a[遍历文章目录]-->b[读取文件内容]
    b-->c[读取文间修改时间]
    link-->d[文件修改时间和文章时间比较]
    d-->|满足条件|f[替换文章更新时间为文件修改时间]
    link2-->g[最后修改回文件的修改时间和访问时间]
  2. 执行脚本update.sh,用于一键推送发布博客

graph LR
  c[脚本updateFileTime.nodejs]-->a[本地git]
  a-->|git推送|f[github仓库hexo分支]
  link-->|hexo编译|b[travis]
  b-->|部署|g[github.io]

脚本内容解读

updateFileTime.nodejs脚本

匹配文章updated: 2018-04-25 20:47:32字段的正则表达式RegExp

1
(updated:\s*)((\d{2}(([02468][048])|([13579][26]))[\-\/\s]?((((0?[13578])|(1[02]))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\-\/\s]?((0?[1-9])|([1-2][0-9])))))|(\d{2}(([02468][1235679])|([13579][01345789]))[\-\/\s]?((((0?[13578])|(1[02]))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\-\/\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\s((([0-1][0-9])|(2?[0-3]))\:([0-5]?[0-9])((\s)|(\:([0-5]?[0-9])))))

脚本用到的主要方法有

1
2
3
4
5
6
7
8
9
var data;//文章内容
RegExp.test(data);//文章内容包含正则匹配的内容返回true,没有false
//取出正则匹配到的值,返回是数组['updated: 2018-04-25 20:47:32']
var updateds=data.match(RegExp);
//时间格式化为2018/01/29 21:33:30,因为这样就可以通过Date.parse()得到时间了
var updated=updateds[0].replace("updated: ","").replace(/-/g,"/");
//修改文件的状态信息,防止该脚本更改修改时间,导致后来修改时间不准确
//其实文件内容变了,但并不会记录此脚本的改的记录,因此要重新打开文章才会发现时间改变
fs.utimes(file,atime,mtime,function(err){});//atime访问时间,mtime修改时间
updateFileTime.nodejs脚本内容
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#!/usr/bin/env node
/*
批量更新修改时间
用于bolg自动更新修改时间
*/

console.log('文件创建时间读取并写入文件指定字段demo');
var fs = require("fs"); //请求文件系统
var file = "./txt"; //设置读取和写入的文件,当前目录下的test文件
var RegExp=/(updated:\s*)((\d{2}(([02468][048])|([13579][26]))[\-\/\s]?((((0?[13578])|(1[02]))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\-\/\s]?((0?[1-9])|([1-2][0-9])))))|(\d{2}(([02468][1235679])|([13579][01345789]))[\-\/\s]?((((0?[13578])|(1[02]))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\-\/\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\s((([0-1][0-9])|(2?[0-3]))\:([0-5]?[0-9])((\s)|(\:([0-5]?[0-9])))))/g;

fs.readdir("./",function(err,files){
var len=files.length;
var file=null;
for(var i=0;i<len;i++){
file=files[i];
console.log("读取文件:",file);
if(file.indexOf(".md")>-1){
console.log("处理文件:",file);
writeFileTime(file,fs);
}
}
});

/*
file:读取时间的文件以及写入内容的文件
fs: 文件系统
*/
function writeFileTime(file,fs){
fs.readFile(file, 'utf8',function(err, data) { //读取文件内容
if (err) return console.log("读取文件内容错误:",err);
//console.log("文件"+file+"的内容:",data);
if(RegExp.test(data)){ //如果有匹配的字符串则进去
fs.stat(file,function(err, stats) { //读取文件信息,创建时间等
if (err) return console.log("读取文件信息错误:",err);
var updateds=data.match(RegExp);
console.log("updated数组:",updateds);
if(updateds.length>1) console.log("文件"+file+"匹配到多处update字段");
var updated=updateds[0].replace("updated: ","").replace(/-/g,"/"); //时间格式化为2018/01/29 21:33:30
console.log("updated:",updated);
if(new Date(stats.mtime).getTime()-new Date(Date.parse(updated))>1000*60*5){
var result= data.replace(RegExp,"updated: "+getFormatDate(stats.mtime)); //替换更新时间
fs.writeFile(file, result, 'utf8',function(err) { //写入新的文件内容
if (err) return console.log("写文件错误:",err);
fs.utimes(file,new Date(stats.atime),new Date(stats.mtime),function(err){ //还原访问时间和修改时间
if (err) return console.log("修改时间失败:",err);
console.log(file,"成功更新时间");
});
});
}
});
}
});
}

/*
timeStr:时间,格式可为:"September 16,2016 14:15:05、
"September 16,2016"、"2016/09/16 14:15:05"、"2016/09/16"、
'2014-04-23T18:55:49'和毫秒
dateSeparator:年、月、日之间的分隔符,默认为"-",
timeSeparator:时、分、秒之间的分隔符,默认为":"
*/
function getFormatDate(timeStr, dateSeparator, timeSeparator) {
dateSeparator = dateSeparator ? dateSeparator : "-";
timeSeparator = timeSeparator ? timeSeparator : ":";
var date = new Date(timeStr),
year = date.getFullYear(),// 获取完整的年份(4位,1970)
month = date.getMonth(),// 获取月份(0-11,0代表1月,用的时候记得加上1)
day = date.getDate(),// 获取日(1-31)
hour = date.getHours(),// 获取小时数(0-23)
minute = date.getMinutes(),// 获取分钟数(0-59)
seconds = date.getSeconds(),// 获取秒数(0-59)
Y = year + dateSeparator,
M = ((month + 1) > 9 ? (month + 1) : ('0' + (month + 1))) + dateSeparator,
D = (day > 9 ? day : ('0' + day)) + ' ',
h = (hour > 9 ? hour : ('0' + hour)) + timeSeparator,
m = (minute > 9 ? minute : ('0' + minute)) + timeSeparator,
s = (seconds > 9 ? seconds : ('0' + seconds)),
formatDate = Y + M + D + h + m + s;
return formatDate;
}
update.sh脚本

由于懒得去设置目录,就直接cd切换过去,再切换回来把

其中"$*" 表示介绍所有参数,例如./update.sh 我是提交信息 哈哈哈哈就会被传递到git commit -m "我是提交信息 哈哈哈哈"

1
2
#!/bin/sh
cd source/_posts/ && ./updateFileTime.nodejs && cd .. && cd .. && git add --all && git commit -m "$*" && git push origin hexo

更新优化版本,添加图片自动更新链接,以及优化为同步和异步两个版本

同步版本

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#!/usr/bin/env node
/*
同步版本
批量更新修改时间
用于bolg自动更新修改时间
批量替换本地链接为网络链接,使用七牛图床
*/

console.log('开始检测更新时间和图片');
var fs = require("fs"); //请求文件系统
var file = "./txt"; //设置读取和写入的文件,当前目录下的test文件
var RegExp=/(updated:\s*)((\d{2}(([02468][048])|([13579][26]))[\-\/\s]?((((0?[13578])|(1[02]))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\-\/\s]?((0?[1-9])|([1-2][0-9])))))|(\d{2}(([02468][1235679])|([13579][01345789]))[\-\/\s]?((((0?[13578])|(1[02]))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\-\/\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\s((([0-1][0-9])|(2?[0-3]))\:([0-5]?[0-9])((\s)|(\:([0-5]?[0-9])))))/g;
var imgReg=/\!\[[\s\S]*?\]\([\s\S]*?\)/g;

var files= fs.readdirSync("./");

var len=files.length;
var file=null;
for(var i=0;i<len;i++){
file=files[i];
//console.log("读取文件:",file);
if(file.indexOf(".md")>-1){
//console.log("处理文件:",file);
writeFileTime(file,fs);
}
}


/*
file:读取时间的文件以及写入内容的文件
fs: 文件系统
*/
function writeFileTime(file,fs){
var data = fs.readFileSync(file, 'utf8');
if(RegExp.test(data)){ //如果有匹配的字符串则进去
var stats= fs.statSync(file);
var updateds=data.match(RegExp);
var updated=updateds[0].replace("updated: ","").replace(/-/g,"/"); //时间格式化为2018/01/29 21:33:30
if(new Date(stats.mtime).getTime()-new Date(Date.parse(updated))>1000*60*5){
console.log(file,"时间处理:"+updateds[0]);
var result= data.replace(updateds[0],"updated: "+getFormatDate(stats.mtime)); //替换更新时间
fs.writeFileSync(file, result, 'utf8');
fs.utimesSync(file,new Date(stats.atime),new Date(stats.mtime));
console.log(file,"成功更新时间:"+updateds[0].replace(updateds[0],"updated: "+getFormatDate(stats.mtime)));
}
}
if(imgReg.test(data)){ //匹配markdown图片
console.log(file,"开始处理图片");
var imgpaths=data.match(imgReg);
for (var i = imgpaths.length - 1; i >= 0; i--) {
var imgpath=imgpaths[i];
console.log(imgpath);
if (imgpath.indexOf("xuanfong1.github.io\\source\\_posts\\image")!=-1) {
console.log(file,"处理:"+imgpath);
var filenametemp= imgpath.split('\\').pop();
var filename=filenametemp.slice(0,filenametemp.length-1);
var result=data.replace(imgpath,"![](https://raw.githubusercontent.com/xuanfong1/xuanfong1.github.io/master/image/src_dir/"+filename+")");
fs.writeFileSync(file, result, 'utf8');
console.log("成功替换:"+imgpath.replace(imgpath,"![](http://ohdtoul5i.bkt.clouddn.com/"+filename+")"));
}
if (imgpath.indexOf("xuanfong1.github.io/source/_posts/image")!=-1) {
console.log(file,"处理:"+imgpath);
var filenametemp= imgpath.split('/').pop();
var filename=filenametemp.slice(0,filenametemp.length-1);
var result=data.replace(imgpath,"![](http://ohdtoul5i.bkt.clouddn.com/"+filename+")");
fs.writeFileSync(file, result, 'utf8');
console.log("成功替换:"+imgpath.replace(imgpath,"![](http://ohdtoul5i.bkt.clouddn.com/"+filename+")"));
}
}
}
}

/*
timeStr:时间,格式可为:"September 16,2016 14:15:05、
"September 16,2016"、"2016/09/16 14:15:05"、"2016/09/16"、
'2014-04-23T18:55:49'和毫秒
dateSeparator:年、月、日之间的分隔符,默认为"-",
timeSeparator:时、分、秒之间的分隔符,默认为":"
*/
function getFormatDate(timeStr, dateSeparator, timeSeparator) {
dateSeparator = dateSeparator ? dateSeparator : "-";
timeSeparator = timeSeparator ? timeSeparator : ":";
var date = new Date(timeStr),
year = date.getFullYear(),// 获取完整的年份(4位,1970)
month = date.getMonth(),// 获取月份(0-11,0代表1月,用的时候记得加上1)
day = date.getDate(),// 获取日(1-31)
hour = date.getHours(),// 获取小时数(0-23)
minute = date.getMinutes(),// 获取分钟数(0-59)
seconds = date.getSeconds(),// 获取秒数(0-59)
Y = year + dateSeparator,
M = ((month + 1) > 9 ? (month + 1) : ('0' + (month + 1))) + dateSeparator,
D = (day > 9 ? day : ('0' + day)) + ' ',
h = (hour > 9 ? hour : ('0' + hour)) + timeSeparator,
m = (minute > 9 ? minute : ('0' + minute)) + timeSeparator,
s = (seconds > 9 ? seconds : ('0' + seconds)),
formatDate = Y + M + D + h + m + s;
return formatDate;
}

异步版本

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#!/usr/bin/env node
/*
异步版本
批量更新修改时间
用于bolg自动更新修改时间
批量替换本地链接为网络链接,使用七牛图床
*/

console.log('开始检测更新时间和图片');
var fs = require("fs"); //请求文件系统
var file = "./txt"; //设置读取和写入的文件,当前目录下的test文件
var RegExp=/(updated:\s*)((\d{2}(([02468][048])|([13579][26]))[\-\/\s]?((((0?[13578])|(1[02]))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\-\/\s]?((0?[1-9])|([1-2][0-9])))))|(\d{2}(([02468][1235679])|([13579][01345789]))[\-\/\s]?((((0?[13578])|(1[02]))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\-\/\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\s((([0-1][0-9])|(2?[0-3]))\:([0-5]?[0-9])((\s)|(\:([0-5]?[0-9])))))/g;
var imgReg=/\!\[[\s\S]*?\]\([\s\S]*?\)/g;

fs.readdir("./",function(err,files){
var len=files.length;
var file=null;
for(var i=0;i<len;i++){
file=files[i];
//console.log("读取文件:",file);
if(file.indexOf(".md")>-1){
//console.log("处理文件:",file);
writeFileTime(file,fs);
}
}
});

/*
file:读取时间的文件以及写入内容的文件
fs: 文件系统
*/
function writeFileTime(file,fs){
fs.readFile(file, 'utf8',function(err, data) { //读取文件内容
if (err) return console.log("读取文件内容错误:",err);
//console.log("文件"+file+"的内容:",data);
if(RegExp.test(data)){ //如果有匹配的字符串则进去
fs.stat(file,function(err, stats) { //读取文件信息,创建时间等
if (err) return console.log("读取文件信息错误:",err);
var updateds=data.match(RegExp);
//console.log("updated数组:",updateds);
//if(updateds.length>1) console.log("文件"+file+"匹配到多处update字段");
var updated=updateds[0].replace("updated: ","").replace(/-/g,"/"); //时间格式化为2018/01/29 21:33:30
//console.log("updated:",updated);
if(new Date(stats.mtime).getTime()-new Date(Date.parse(updated))>1000*60*5){
console.log(file,"时间处理:"+updateds[0]);
var result= data.replace(updateds[0],"updated: "+getFormatDate(stats.mtime)); //替换更新时间
fs.writeFile(file, result, 'utf8',function(err) { //写入新的文件内容
if (err) return console.log("写文件错误:",err);
fs.utimes(file,new Date(stats.atime),new Date(stats.mtime),function(err){ //还原访问时间和修改时间
if (err) return console.log("修改时间失败:",err);
console.log("成功更新时间:"+updateds[0].replace(updateds[0],"updated: "+getFormatDate(stats.mtime)));
});
});
}
});
}
if(imgReg.test(data)){ //匹配markdown图片
var imgpaths=data.match(imgReg);
for (var i = imgpaths.length - 1; i >= 0; i--) {
var imgpath=imgpaths[i];
if (imgpath.indexOf("xuanfong1.github.io\\source\\_posts\\image")!=-1 || imgpath.indexOf("xuanfong1.github.io/source/_posts/image")!=-1) {
console.log(file,"处理:"+imgpath);
var filenametemp= imgpath.split('\\').pop();
var filename=filenametemp.slice(0,filenametemp.length-1);
var result=data.replace(imgpath,"![](http://ohdtoul5i.bkt.clouddn.com/"+filename+")");
fs.writeFile(file, result, 'utf8',function(err) { //写入新的文件内容
if (err) return console.log("写文件错误:",err);
console.log("成功替换:"+imgpath.replace(imgpath,"![](http://ohdtoul5i.bkt.clouddn.com/"+filename+")"));
});
}
if (imgpath.indexOf(imgpath.indexOf("xuanfong1.github.io/source/_posts/image")!=-1) {
console.log(file,"处理:"+imgpath);
var filenametemp= imgpath.split('/').pop();
var filename=filenametemp.slice(0,filenametemp.length-1);
var result=data.replace(imgpath,"![](http://ohdtoul5i.bkt.clouddn.com/"+filename+")");
fs.writeFile(file, result, 'utf8',function(err) { //写入新的文件内容
if (err) return console.log("写文件错误:",err);
console.log("成功替换:"+imgpath.replace(imgpath,"![](http://ohdtoul5i.bkt.clouddn.com/"+filename+")"));
});
}
}
}
});
}

/*
timeStr:时间,格式可为:"September 16,2016 14:15:05、
"September 16,2016"、"2016/09/16 14:15:05"、"2016/09/16"、
'2014-04-23T18:55:49'和毫秒
dateSeparator:年、月、日之间的分隔符,默认为"-",
timeSeparator:时、分、秒之间的分隔符,默认为":"
*/
function getFormatDate(timeStr, dateSeparator, timeSeparator) {
dateSeparator = dateSeparator ? dateSeparator : "-";
timeSeparator = timeSeparator ? timeSeparator : ":";
var date = new Date(timeStr),
year = date.getFullYear(),// 获取完整的年份(4位,1970)
month = date.getMonth(),// 获取月份(0-11,0代表1月,用的时候记得加上1)
day = date.getDate(),// 获取日(1-31)
hour = date.getHours(),// 获取小时数(0-23)
minute = date.getMinutes(),// 获取分钟数(0-59)
seconds = date.getSeconds(),// 获取秒数(0-59)
Y = year + dateSeparator,
M = ((month + 1) > 9 ? (month + 1) : ('0' + (month + 1))) + dateSeparator,
D = (day > 9 ? day : ('0' + day)) + ' ',
h = (hour > 9 ? hour : ('0' + hour)) + timeSeparator,
m = (minute > 9 ? minute : ('0' + minute)) + timeSeparator,
s = (seconds > 9 ? seconds : ('0' + seconds)),
formatDate = Y + M + D + h + m + s;
return formatDate;
}

环境

系统:wsl

环境:nodejs

步骤
  1. 创建脚本
  2. 编写脚本内容
  3. 修改脚本为执行文件chmod +x scriptfilename

需求描述

批量把文档的修改时间写入该文档的指定字段位置

eg:添加hexo 文章的修改时间
脚本内容解读

file文件系统的主要方法解释

1
2
3
4
5
6
var fs = require("fs"); //请求文件系统
fs.readdir("./",function(err,files){}); //读取./也就是当前目录的所有文件
fs.readFile(file, 'utf8',function(err, data) {}); //读取"file"文件内容data
fs.stat(file,function(err, stats) {}); //读取文件信息,创建时间等
fs.writeFile(file, result, 'utf8',function(err) {}); //写入file文件内容result,会覆盖原来的
datastring.replace(/正则表达式:/g,"新的内容");//正则替换/正则内容/g,datastring数据源

文件信息stats返回的是json信息格式如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Stats {
dev: 12,
mode: 33279,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
blksize: 512,
ino: 4785074604307105,
size: 1297,
blocks: 8,
atimeMs: 1517144361661.3943,
mtimeMs: 1517146617920.6301,
ctimeMs: 1517146647324.5525,
birthtimeMs: 1517146647324.5525,
atime: 2018-01-28T12:59:21.661Z, //访问时间
mtime: 2018-01-28T13:36:57.921Z, //修改时间
ctime: 2018-01-28T13:37:27.325Z, //创建时间
birthtime: 2018-01-28T13:37:27.325Z }

批量读取脚本路径的当前目录的所有文件,通过判段文件名是否包含.md防止改了不必要的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
console.log('文件创建时间读取并写入文件指定字段demo');
var fs = require("fs"); //请求文件系统
var file = "./txt"; //设置读取和写入的文件,当前目录下的test文件

fs.readdir("./",function(err,files){
var len=files.length;
var file=null;
for(var i=0;i<len;i++){
file=files[i];
console.log("读取文件:",file);
if(file.indexOf(".md")>-1){
console.log("处理文件:",file);
writeFileTime(file,fs);
}
}
});

单文件读取并写入修改时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
file:读取时间的文件以及写入内容的文件
fs: 文件系统
*/
function writeFileTime(file,fs){
fs.readFile(file, 'utf8',function(err, data) { //读取文件内容
if (err) return console.log("读取文件内容错误:",err);
console.log("文件"+file+"的内容:",data);
fs.stat(file,function(err, stats) { //读取文件信息,创建时间等
if (err) return console.log("读取文件信息错误:",err);
console.log("文件"+file+"的信息:",stats); //打印文件的信息
console.log("创建时间是:",stats.mtime);
console.log("格式化",getFormatDate(stats.mtime));
var result = data.replace(/categories:/g, "updated: "+getFormatDate(stats.mtime)+"\r"+"categories:");//data:替换为date:2018.....
console.log("修改后文件内容为:",result);
fs.writeFile(file, result, 'utf8',function(err) { //写入新的文件内容
if (err) return console.log("写文件错误:",err);
});
});
});
}

时间格式化方法

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
/*
timeStr:时间,格式可为:"September 16,2016 14:15:05、
"September 16,2016"、"2016/09/16 14:15:05"、"2016/09/16"、
'2014-04-23T18:55:49'和毫秒
dateSeparator:年、月、日之间的分隔符,默认为"-",
timeSeparator:时、分、秒之间的分隔符,默认为":"
*/
function getFormatDate(timeStr, dateSeparator, timeSeparator) {
dateSeparator = dateSeparator ? dateSeparator : "-";
timeSeparator = timeSeparator ? timeSeparator : ":";
var date = new Date(timeStr),
year = date.getFullYear(),// 获取完整的年份(4位,1970)
month = date.getMonth(),// 获取月份(0-11,0代表1月,用的时候记得加上1)
day = date.getDate(),// 获取日(1-31)
hour = date.getHours(),// 获取小时数(0-23)
minute = date.getMinutes(),// 获取分钟数(0-59)
seconds = date.getSeconds(),// 获取秒数(0-59)
Y = year + dateSeparator,
M = ((month + 1) > 9 ? (month + 1) : ('0' + (month + 1))) + dateSeparator,
D = (day > 9 ? day : ('0' + day)) + ' ',
h = (hour > 9 ? hour : ('0' + hour)) + timeSeparator,
m = (minute > 9 ? minute : ('0' + minute)) + timeSeparator,
s = (seconds > 9 ? seconds : ('0' + seconds)),
formatDate = Y + M + D + h + m + s;
return formatDate;
}

最终脚本内容

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#!/usr/bin/env node
/*
批量添加修改时间
用于bolg初始化修改时间
*/

console.log('文件创建时间读取并写入文件指定字段demo');
var fs = require("fs"); //请求文件系统
var file = "./txt"; //设置读取和写入的文件,当前目录下的test文件

fs.readdir("./",function(err,files){
var len=files.length;
var file=null;
for(var i=0;i<len;i++){
file=files[i];
console.log("读取文件:",file);
if(file.indexOf(".md")>-1){
console.log("处理文件:",file);
writeFileTime(file,fs);
}
}
});
/*
file:读取时间的文件以及写入内容的文件
fs: 文件系统
*/
function writeFileTime(file,fs){
fs.readFile(file, 'utf8',function(err, data) { //读取文件内容
if (err) return console.log("读取文件内容错误:",err);
console.log("文件"+file+"的内容:",data);
fs.stat(file,function(err, stats) { //读取文件信息,创建时间等
if (err) return console.log("读取文件信息错误:",err);
console.log("文件"+file+"的信息:",stats); //打印文件的信息
console.log("创建时间是:",stats.mtime);
console.log("格式化",getFormatDate(stats.mtime));
var result = data.replace(/categories:/g, "updated: "+getFormatDate(stats.mtime)+"\r"+"categories:");//data:替换为date:2018.....
console.log("修改后文件内容为:",result);
fs.writeFile(file, result, 'utf8',function(err) { //写入新的文件内容
if (err) return console.log("写文件错误:",err);
});
});
});
}

/*
timeStr:时间,格式可为:"September 16,2016 14:15:05、
"September 16,2016"、"2016/09/16 14:15:05"、"2016/09/16"、
'2014-04-23T18:55:49'和毫秒
dateSeparator:年、月、日之间的分隔符,默认为"-",
timeSeparator:时、分、秒之间的分隔符,默认为":"
*/
function getFormatDate(timeStr, dateSeparator, timeSeparator) {
dateSeparator = dateSeparator ? dateSeparator : "-";
timeSeparator = timeSeparator ? timeSeparator : ":";
var date = new Date(timeStr),
year = date.getFullYear(),// 获取完整的年份(4位,1970)
month = date.getMonth(),// 获取月份(0-11,0代表1月,用的时候记得加上1)
day = date.getDate(),// 获取日(1-31)
hour = date.getHours(),// 获取小时数(0-23)
minute = date.getMinutes(),// 获取分钟数(0-59)
seconds = date.getSeconds(),// 获取秒数(0-59)
Y = year + dateSeparator,
M = ((month + 1) > 9 ? (month + 1) : ('0' + (month + 1))) + dateSeparator,
D = (day > 9 ? day : ('0' + day)) + ' ',
h = (hour > 9 ? hour : ('0' + hour)) + timeSeparator,
m = (minute > 9 ? minute : ('0' + minute)) + timeSeparator,
s = (seconds > 9 ? seconds : ('0' + seconds)),
formatDate = Y + M + D + h + m + s;
return formatDate;
}

Registry官网

本地仓库安装无绑定oss

  1. htpasswd网页生成密码保存到./auth/htpasswd,加密方式选中bcrypt,或者执行命令生成htpasswd -Bbn test 123456 > auth/htpasswd

  2. 编辑vim docker-compose.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    registry:
    restart: always
    image: "registry:2.6.2"
    ports:
    - 14005:5000
    environment:
    - REGISTRY_AUTH=htpasswd #授权模式
    - REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm
    - REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd #密码的地址
    volumes:
    - ./auth:/auth #密码存储的挂载卷
    - ./data:/var/lib/registry #本地仓库挂载的卷
  3. 启动容器docker-compose up

  4. 创建镜像docker tag <镜像名字> 127.0.0.1:14005<镜像名字>

  5. 登陆仓库docker login 127.0.0.1:14005输入账号密码或者docker login -u admin -p 123456 127.0.0.1:14005

  6. 上传镜像docker push 127.0.0.1:14005<镜像名字> 或者拉取镜像docker pull 127.0.0.1:14005<镜像名字>

绑定oss

  1. 修改上面的第6步骤

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    registry:
    restart: always
    image: "registry:2.6.2"
    ports:
    - 14005:5000
    environment:
    - REGISTRY_AUTH=htpasswd
    - REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm
    - REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd
    - REGISTRY_STORAGE=oss #必填
    - REGISTRY_STORAGE_OSS_ACCESSKEYID=你的阿里云ACCESSKEYID,带oss权限 #必填
    - REGISTRY_STORAGE_OSS_ACCESSKEYSECRET=你的阿里云ACCESSKEYSECRET,带oss权限 #必填
    - REGISTRY_STORAGE_OSS_REGION=节点区域(oss-cn-hangzhou) #必填
    - REGISTRY_STORAGE_OSS_BUCKET=buket的名字(t-docker-registry) #必填
    - REGISTRY_STORAGE_OSS_ENDPOINT=t-docker-registry.oss-cn-hangzhou.aliyuncs.com #非必填
    volumes:
    - ./auth:/auth
  2. 如果报如下错误

    参考Private registry push fail: server gave HTTP response to HTTPS client
    1
    2
    3
    4
    5
    Error response from daemon: received unexpected HTTP status: 503 Service Unavailable
    #或者
    Error response from daemon: login attempt to http://127.0.0.1:14005/v2/ failed with status: 503 Service Unavailable
    #或者
    Error response from daemon: Get https://112.74.51.136:14005/v2/: http: server gave HTTP response to HTTPS client

    设置vim /etc/docker/daemon.json

    1
    2
    3
    4
    5
    6
    {
    //这句是仓库加速地址,以前的
    "registry-mirrors": ["your aliyun 加速地址"],
    //添加这句,只有通过这个ip访问才不报错,如果有其他ip访问,也要加进来,不然就不用那个ip访问
    "insecure-registries":["112.74.51.136:14005"]
    }

    然后sudo systemctl daemon-reload重启systemctl restart docker

    幻觉:失败了一次,重启又可以了?

docker registry 证书配置

部署配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
registry:
restart: always
image: "registry:2.6.2"
ports:
- 14005:5000
environment:
- REGISTRY_AUTH=htpasswd #授权模式
- REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm
- REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd #密码的地址
- REGISTRY_HTTP_TLS_KEY=/certs/domain.key
- REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt
volumes:
- /dockerdata/v-registry/auth:/auth #密码存储的挂载卷
- /dockerdata/v-registry/registry:/var/lib/registry #本地仓库挂载的卷
- /dockerdata/v-registry/certs:/certs #https

/dockerdata/v-registry/生成证书,注意在hostname设置时,不要忽略www

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@environment-test1 v-registry]# sudo mkdir -p certs && sudo openssl req -newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key -x509 -days 365 -out certs/domain.crt
Generating a 4096 bit RSA private key
...........................................................++
..++
writing new private key to 'certs/domain.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:www.3sreform.com
Email Address []:

再各个使用仓库的宿主机创建目录mkdir -p /etc/docker/certs.d/www.3sreform.com:14005

然后把生成的证书放到该目录下并改名为ca.crt

最后重启docker

sudo systemctl daemon-reloadsudo systemctl restart docker

最后用docker login www.3sreform.com:14005 -u admin -p <密码>测试

最后push是,镜像开头必须是www.3sreform.com

参考

Docker搭建registry 私人仓库

gitlab-runner镜像自定义

仓库DockerHub:gitlab/gitlab-runner

gitlab版本

gitlab-runner (2018.1.16)

gitlab-runner_amd64.deb

准备工作
1
2
3
wget https://packages.gitlab.com/runner/gitlab-runner/packages/linuxmint/sonya/gitlab-runner_10.3.0_amd64.deb/download -O gitlab-runner_amd64.deb
#编译
sudo docker build -t xuan-runner:v1 .
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
FROM ubuntu:14.04

RUN apt-get update -y && \
apt-get upgrade -y && \
apt-get install -y ca-certificates wget apt-transport-https vim nano && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

ARG DOCKER_MACHINE_VERSION=0.13.0
ARG DUMB_INIT_VERSION=1.0.2

COPY gitlab-runner_amd64.deb /tmp/
#COPY checksums /tmp/
#runner diy
COPY jdk1.8.0_161 /usr/lib/jvm/java-8-oracle
COPY gradle-4.4.1 /usr/lib/gradle

RUN dpkg -i /tmp/gitlab-runner_amd64.deb; \
apt-get update && \
apt-get -f install -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
rm /tmp/gitlab-runner_amd64.deb && \
gitlab-runner --version && \
mkdir -p /etc/gitlab-runner/certs && \
chmod -R 700 /etc/gitlab-runner && \
wget -q https://github.com/docker/machine/releases/download/v${DOCKER_MACHINE_VERSION}/docker-machine-Linux-x86_64 -O /usr/bin/docker-machine && \
chmod +x /usr/bin/docker-machine && \
docker-machine --version && \
wget -q https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/dumb-init_${DUMB_INIT_VERSION}_amd64 -O /usr/bin/dumb-init && \
chmod +x /usr/bin/dumb-init && \
dumb-init --version
#&& \
# sha256sum --check --strict /tmp/checksums
ENV J2SDKDIR /usr/lib/jvm/java-8-oracle
ENV J2REDIR /usr/lib/jvm/java-8-oracle/jre
ENV PATH $PATH:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8-oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin
ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
ENV DERBY_HOME /usr/lib/jvm/java-8-oracle/db
ENV GRADLE_HOME /usr/lib/gradle
ENV PATH $GRADLE_HOME/bin:$PATH

COPY entrypoint /
RUN chmod +x /entrypoint

VOLUME ["/etc/gitlab-runner", "/home/gitlab-runner"]
ENTRYPOINT ["/usr/bin/dumb-init", "/entrypoint"]
CMD ["run", "--user=gitlab-runner", "--working-directory=/home/gitlab-runner"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash

# gitlab-runner data directory
DATA_DIR="/etc/gitlab-runner"
CONFIG_FILE=${CONFIG_FILE:-$DATA_DIR/config.toml}
# custom certificate authority path
CA_CERTIFICATES_PATH=${CA_CERTIFICATES_PATH:-$DATA_DIR/certs/ca.crt}
LOCAL_CA_PATH="/usr/local/share/ca-certificates/ca.crt"

update_ca() {
echo "Updating CA certificates..."
cp "${CA_CERTIFICATES_PATH}" "${LOCAL_CA_PATH}"
update-ca-certificates --fresh >/dev/null
}

if [ -f "${CA_CERTIFICATES_PATH}" ]; then
# update the ca if the custom ca is different than the current
cmp --silent "${CA_CERTIFICATES_PATH}" "${LOCAL_CA_PATH}" || update_ca
fi

# launch gitlab-runner passing all arguments
exec gitlab-runner "$@"

dockerhub版本(废弃)

原因:该版本安装的是gitlab-ci-multi-runner是之前的版本现在已更名为gitlab-runner,而且运行报错

[dumb-init] /entrypoint: Exec format error,以为是最后句名字报错,但是修改报同样的错

ayufan/gitlab-ci-multi-runner (2016.5月更新)

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
#--file name--Dockerfile---
#指定基础镜像
FROM ubuntu:14.04

#远程拷贝文件到指定目录,带自动解压功能
ADD https://github.com/Yelp/dumb-init/releases/download/v1.0.2/dumb-init_1.0.2_amd64 /usr/bin/dumb-init
RUN chmod +x /usr/bin/dumb-init

RUN apt-get update -y && \
apt-get upgrade -y && \
apt-get install -y ca-certificates wget apt-transport-https vim nano && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

RUN echo "deb https://packages.gitlab.com/runner/gitlab-ci-multi-runner/ubuntu/ `lsb_release -cs` main" > /etc/apt/sources.list.d/runner_gitlab-ci-multi-runner.list && \
wget -q -O - https://packages.gitlab.com/gpg.key | apt-key add - && \
apt-get update -y && \
apt-get install -y gitlab-ci-multi-runner && \
wget -q https://github.com/docker/machine/releases/download/v0.7.0/docker-machine-Linux-x86_64 -O /usr/bin/docker-machine && \
chmod +x /usr/bin/docker-machine && \
apt-get clean && \
mkdir -p /etc/gitlab-runner/certs && \
chmod -R 700 /etc/gitlab-runner && \
rm -rf /var/lib/apt/lists/*

ADD entrypoint /
RUN chmod +x /entrypoint
#匿名卷,如果运行时没有指定卷则自动创建匿名卷
VOLUME ["/etc/gitlab-runner", "/home/gitlab-runner"]
#应用运行前执行的脚本
ENTRYPOINT ["/usr/bin/dumb-init", "/entrypoint"]
#启动容器前执行的命令
CMD ["run", "--user=gitlab-runner", "--working-directory=/home/gitlab-runner"]
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
#--file name--entrypoint---
#!/bin/bash

# gitlab-ci-multi-runner data directory
DATA_DIR="/etc/gitlab-runner"
CONFIG_FILE=${CONFIG_FILE:-$DATA_DIR/config.toml}
# custom certificate authority path
CA_CERTIFICATES_PATH=${CA_CERTIFICATES_PATH:-$DATA_DIR/certs/ca.crt}
LOCAL_CA_PATH="/usr/local/share/ca-certificates/ca.crt"

update_ca() {
echo "Updating CA certificates..."
cp "${CA_CERTIFICATES_PATH}" "${LOCAL_CA_PATH}"
update-ca-certificates --fresh >/dev/null
}

if [ -f "${CA_CERTIFICATES_PATH}" ]; then
# update the ca if the custom ca is different than the current
cmp --silent "${CA_CERTIFICATES_PATH}" "${LOCAL_CA_PATH}" || update_ca
fi

# launch gitlab-ci-multi-runner passing all arguments
#这句报错,版本问题,似乎是multi-runner是之前的版本,先更新为gtilab-runner
#exec gitlab-ci-multi-runner "$@" ,
exec gitlab-runner "$@"

单机应用gitlab

MySQL
1
2
3
4
5
6
7
8
9
#下载
docker pull mysql
#启动mysql容器,返回容器id (-p 3306:3306 指定外部连接端口,不指定外部连接不上)
docker run --name gitlab-mysql -e MYSQL_ROOT_PASSWORD=Mimais163. -d mysql
#连接进入mysql命令行
docker run -it --link gitlab-mysql:mysql --rm mysql sh -c 'exec mysql -h"$MYSQL_PORT_3306_TCP_ADDR" -P"$MYSQL_PORT_3306_TCP_PORT" -uroot -p"$MYSQL_ENV_MYSQL_ROOT_PASSWORD"'
#MySQL命令
show databases; #显示数据库
quit #退出命令行
redis
1
2
3
4
#下载
docker pull redis
#启动redis容器
docker run --name gitlab-redis -d redis
sameersbn/gitlab
在 Docker 中使用 GitLab

sameersbn/gitlabgitlab/gitlab-ce区别在于前者需要MySQL和redis,后者集成所有环境

安装法一
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#下载docker-compose.yml脚本
wget https://raw.githubusercontent.com/sameersbn/docker-gitlab/master/docker-compose.yml
#安装pwgen密码生产器
yum install pwgen
#生成三个密码
pwgen -Bsv1 64
#修改docker-compose.yml下这三个参数
-GITLAB_SECRETS_DB_KEY_BASE=CvpwfRsb5sNpmGRcX5fQFzTNtdkd5pNMK623PVP9rkwLsTDW4VlXMLmT4bKRLVzC
-GITLAB_SECRETS_SECRET_KEY_BASE=cFdsD8xSKVCShL76hpWP3NdjTCm3XbtV7d3BXB9XZNHclq8n743s3vFTkMg3DppJ
-GITLAB_SECRETS_OTP_KEY_BASE=P8rH42vPgg5pZ34Nt8t3pwnCBcPXNkjqV8kTxBlQCkFkSCXGhXvDRSGm2bBx593q
#运行脚本
docker-compose up
#运行网页www.exxk.me:10080
#用户名root
安装法二
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#下载安装
docker pull sameersbn/gitlab
#查看镜像
docker images
#运行
sudo docker run --detach \
--hostname gitlab.xuan.com \
--publish 10443:443 --publish 10080:80 --publish 10022:22 \
--name gitlab \
--restart always \
--volume /srv/gitlab/config:/etc/gitlab \
--volume /srv/gitlab/logs:/var/log/gitlab \
--volume /srv/gitlab/data:/var/opt/gitlab \
gitlab/gitlab-ce:latest
#查看运行的镜像
docker ps

访问地址http://112.74.51.136:10080

  • 注意开放端口
运行

编辑运行参数文件vim docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
web:
image: 'gitlab/gitlab-ce:latest'
restart: always
hostname: 'gitlab.example.com'
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://gitlab.example.com:9090'
gitlab_rails['gitlab_shell_ssh_port'] = 2224
ports:
- '9090:9090'
- '2224:22'
volumes:
- '/srv/gitlab/config:/etc/gitlab'
- '/srv/gitlab/logs:/var/log/gitlab'
- '/srv/gitlab/data:/var/opt/gitlab'

执行docker-compose up -d 运行

sameersbn/gitlab-ci-multi-runner

1
2
3
4
5
6
7
8
9
#下载
docker pull gitlab/gitlab-runner
#运行
docker run -d --name gitlab-runner --restart always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /srv/gitlab-runner/config:/etc/gitlab-runner \
gitlab/gitlab-runner:latest
#注册
docker exec -it gitlab-runner gitlab-runner register

执行后进入设置:相关参数见 gitlab->project-settings->Pipelines

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#进入设置
Running in system-mode.

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
#Specify the following URL during the Runner setup:http://exxk.me:10080/
> http://exxk.me:10080/
Please enter the gitlab-ci token for this runner:
#Use the following registration token during setup:qg78V4rsaxabgULs-cps
> qg78V4rsaxabgULs-cps
Please enter the gitlab-ci description for this runner:
> [dd8f66b4b9ac]: aa
Please enter the gitlab-ci tags for this runner (comma separated):
> cc
Whether to run untagged builds [true/false]:
> [false]:
Whether to lock Runner to current project [true/false]:
> [false]:
Registering runner... succeeded runner=qg78V4rs
Please enter the executor: docker, parallels, shell, docker+machine, kubernetes, docker-ssh, ssh, virtualbox, docker-ssh+machine:
# 选择runner 运行的环境 这里是docker
> docker
Please enter the default Docker image (e.g. ruby:2.1):
> tomcat
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!

集群应用gitlab

准备工作

1
2
3
mkdir -p /srv/docker/gitlab/postgresql
mkdir -p /srv/docker/gitlab/redis
mkdir -p /srv/docker/gitlab/gitlab

vim gitlab.yml见末尾

1
2
3
4
5
6
7
8
9
10
#启动gitlab
docker stack deploy -c gitlab.yml gitlab
#查看gitlab
docker stack ps gitlab
#停止删除gitlab
docker stack rm gitlab
#查看服务
docker service ls
#查看服务详情
docker service ps --no-trunc <service id>

gitlab.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
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# gitlab.yml文件
version: '3'
services:
postgresql:
image: sameersbn/postgresql:9.6-2
environment:
- TZ=Asia/Shanghai
- DB_NAME=gitlabhq_production
- DB_USER=gitlab
- DB_PASS=xxxxx
- DB_EXTENSION=pg_trgm
volumes:
- /srv/docker/gitlab/postgresql:/var/lib/postgresql
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints: [node.role == worker]
redis:
image: sameersbn/redis:latest
command:
- --loglevel warning
environment:
- TZ=Asia/Shanghai
volumes:
- /srv/docker/gitlab/redis:/var/lib/redis
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints: [node.role == worker]
gitlab:
image: sameersbn/gitlab:9.5.4
environment:
- TZ=Asia/Shanghai
- GITLAB_HOST=exxk.me
- GITLAB_PORT=10080
- GITLAB_SSH_PORT=10022
- DB_HOST=postgresql
- DB_USER=gitlab
- DB_PASS=xxxx
- GITLAB_SECRETS_DB_KEY_BASE=xxxxzTNtdkd5pNMK623PVP9rkwLsTDW4VlXMLmT4bKRLVzC
- GITLAB_SECRETS_SECRET_KEY_BASE=xxxxxjTCm3XbtV7d3BXB9XZNHclq8n743s3vFTkMg3DppJ
- GITLAB_SECRETS_OTP_KEY_BASE=xxxxxxBcPXNkjqV8kTxBlQCkFkSCXGhXvDRSGm2bBx593q
- GITLAB_TIMEZONE=Beijing
- GITLAB_ROOT_PASSWORD=mimais163
- REDIS_HOST=redis
- REDIS_PORT=6379
- SMTP_USER=986905087@qq.com
- SMTP_PASS=xxxxx
- SMTP_HOST=smtp.qq.com
- SMTP_PORT=465
- SMTP_TLS=true

volumes:
- /srv/docker/gitlab/gitlab:/home/git/data
ports:
- 10080:80
- 10022:22
depends_on:
- postgresql
- redis
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints: [node.role == worker]
参考:compose-v3

额外nginx

1
2
3
4
docker service create -p 8080:80 --name webserver nginx
docker service inspect --format="{{json .Endpoint.Spec.Ports}}" webserver
[{"Protocol":"tcp","TargetPort":80,"PublishedPort":8080,"PublishMode":"ingress"}]
docker service update --replicas 1 webserver

gitlabRunner 镜像

gitlab/gitlab-runner:latest

安装java环境

  1. 下载jre,jre只是运行环境jdk包括jre还有编译环境

    server-jre-8u161-linux-x64.tar.gz

  2. 移动文件到挂载卷sudo mv server-jre-8u161-linux-x64.tar.gz /var/lib/docker/volumes/gitLabRuner_home/_data

  3. 进入gitlab-runner 容器sudo docker exec -it <容器id> bash

  4. 进入挂载目录cd /home/gitlab-runner/

  5. 解压文件tar zxvf server-jre-8u161-linux-x64.tar.gz

  6. 创建目录 然后移动文件并重命名mkdir /usr/lib/jvm && mv jdk1.8.0_161 /usr/lib/jvm/java-8-oracle

  7. 添加环境变量配置文件vim /etc/profile.d/jdk.sh然后再添加执行权限chmod +x /etc/profile.d/jdk.sh

    1
    2
    3
    4
    5
    export J2SDKDIR=/usr/lib/jvm/java-8-oracle
    export J2REDIR=/usr/lib/jvm/java-8-oracle/jre
    export PATH=$PATH:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8-oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin
    export JAVA_HOME=/usr/lib/jvm/java-8-oracle
    export DERBY_HOME=/usr/lib/jvm/java-8-oracle/db
  8. 运行脚本使环境变量生效source /etc/profile

  9. 测试echo $JAVA_HOME输出/usr/lib/jvm/java-8-oracle或者java -version

安装Gradle环境

  1. 下载gradle-4.4.1-bin.zip

  2. 移动文件到挂载卷sudo mv gradle-4.4.1-bin.zip /var/lib/docker/volumes/gitLabRuner_home/_data/

  3. 解压unzip /var/lib/docker/volumes/gitLabRuner_home/_data/gradle-4.4.1-bin.zip

  4. 进入gitlab-runner 容器sudo docker exec -it <容器id> bash

  5. 进入挂载目录cd /home/gitlab-runner/

  6. 移动目录mv gradle-4.4.1 /usr/lib/gradle

  7. vim /etc/profile.d/gradle.sh并添加执行权限``

    1
    2
    export GRADLE_HOME=/usr/lib/gradle 
    export PATH=$GRADLE_HOME/bin:$PATH
  8. 运行脚本使环境变量生效source /etc/profile

  9. 测试gradle -version

制作镜像

  1. 清理安装包
  2. 清理命令历史history -c
  3. ctrl+p+q退出容器不留记录
  4. sudo docker commit -m "add java gradle" -a "iexxk" db38 exxk/gitlab-runner-gradle:v1.0

问题

  1. 通过exec命令进入容器后执行source /etc/profile生效环境变量,再次进入就没有该变量了,commit制作的镜像也没有生效环境变量

    解决:1.通过启动容器时设置环境变量或执行命令,再commit保存,不采用因为每一次提交都会使镜像变大,且是黑盒不易维护

总结

通过commit方法制作镜像会成为黑盒,且不容易维护,而且没提交一次,都会增大镜像的容量,因此采用dockerfile的形式制作镜像, commit适合用于保存犯罪现场。

对应操作记录docker通过commit制作带Gradle和java环境的镜像

JRebel

热部署插件

激活:Help->JRebel->Activate 废弃

激活2 废弃

激活三

选择Connect to License Server 输入:

服务器iphttp://127.0.0.1:8888/zsc

随便写zsc@123.com

https://jingyan.baidu.com/article/14bd256e9152a5bb6d2612ee.html

https://gitee.com/gsls200808/JrebelLicenseServerforJava

MyBatis plugin

sql语句跳转生成

Alibaba java Coding Guidelines

代码格式优化检查

Lombok

日志插件

checkstyle

代码样式

参考

JAVA后端工作流推荐三–IDEA安装Checkstyle、FindBugs、Markdown等插件及其使用