0%

介绍

**Gluster**是一个大尺度文件系统。

主要功能
简单卷
  1. distribute volume 分布式卷,两台主机的磁盘融合一个磁盘
  2. stripe volume 条带卷,一个文件分成数据块存储到不同的地方
  3. replica volume 复制卷,一个文件分别保存到两台主机
复合卷

1+2,1+3,2+3,1+2+3

总结常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
gluster peer status     #查看集群各主机连接状态
gluster volume list #查看挂载卷信息
gluster volume list #查看卷列表
#创建挂在卷,force忽略在root目录创建挂在卷的警告
gluster volume create swarm-volume replica 3 worker:/xuan/docker/gluster-volume home:/xuan/docker/gluster-volume xuanps:/xuan/docker/gluster-volume force
gluster volume start swarm-volume #启动
gluster volume stop swarm-volume #停止
gluster volume delete swarm-volume #删除 ,了文件还会保留
#挂载本地目录到glusterfs卷(swarm-volume),在本地目录添加的会自动同步到其他挂载卷
#eg在本机mnt添加文件,其他volume-name目录也会添加mount [-参数] [设备名称] [挂载点]
mount -t glusterfs worker:/swarm-volume /mnt/
umount worker:/swarm-volume #卸载了就不会同步了
#重置,删除所有数据
systemctl stop glusterd
rm -rf /var/lib/glusterd/
systemctl start glusterd
#删除节点
gluster peer detach home

安装

准备工作:

三台局域网主机(centos7 修改主机名

hostname ip 备注
xuanps 10.14.0.1
worker 10.14.0.4
home 10.14.0.5

三台都需要安装GlusterFS

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
#搜索glusterfs可安装的版本
yum search centos-release-gluster
#安装最新长期稳定版本(Long Term Stable)的gluster软件
yum -y install centos-release-gluster
#安装glusterfs-server
yum --enablerepo=centos-gluster*-test install glusterfs-server
glusterfs -V #测试
systemctl enable glusterd #开机启动
systemctl start glusterd #启动
systemctl status glusterd #查看是否正常运行
#修改hosts不然不能通过主机名连接到对方
vim /etc/hosts
#----------三台都要添加如下设置--------------------------
10.14.0.1 xuanps
10.14.0.4 worker
10.14.0.5 home
#------------------------------------------------------
#从xuanps上执行下面两条,其他主机不用执行
gluster peer probe worker
gluster peer probe home
#三台都执行该命令是否都是connected
gluster peer status
#查看挂载卷信息
gluster volume info
#创建挂在卷,force忽略在root目录创建挂在卷的警告
gluster volume create volume-name replica 3 worker:/xuan/docker/gluster-volume/test home:/xuan/docker/gluster-volume/test xuanps:/xuan/docker/gluster-volume/test force
#启动
gluster volume start volume-name
#启动nfs同步,测试需验证,这里要不要开启
gluster volume set volume-name nfs.disable off
#挂载本地目录到glusterfs卷(volume-name),在本地目录添加的会自动同步到其他挂载卷
#eg在本机mnt添加文件,其他volume-name目录也会添加
mount -t glusterfs worker:/volume-name /mnt/

参考

官网:https://www.gluster.org/

文档

centos官方安装手册

基于 GlusterFS 实现 Docker 集群的分布式存储

docker 安装docker-volume-glusterfs

前提,首先安装好GlusterFS分布式文件系统,可以参考centos7 安装 GlusterFS

sapk/docker-volume-gluster安装(弃)

不足:无法删除volume,且无法复用

1
2
3
4
5
6
7
8
9
10
#安装插件,三台主机都安装(保险起见)
docker plugin install sapk/plugin-gluster
# docker volume create --driver sapk/plugin-gluster --opt voluri="<volumeserver>,<otherserver>,<otheroptionalserver>:<volumename>" --name test
#volumeserver 主机名,可以指定多个,volumenam是 GlusterFS文件系统的挂载劵名,test是swarm挂载卷名
docker volume create --driver sapk/plugin-gluster --opt voluri="worker,home,xuanps:swarm-volume" --name test
#运行ubuntu容器进行测试
docker run -v test:/mnt --rm -ti ubuntu
#进去之后创建文件,其他系统盘也能看到该文件了, 但是其他系统不会创建挂载卷
echo "hello">/mnt/testfile

docker-compose 使用

1
2
3
4
5
volumes:
some_vol:
driver: sapk/plugin-gluster
driver_opts:
voluri: "<volumeserver>:<volumename>"

calavera/docker-volume-glusterfs官方安装(废弃 测试时发现运行找不到插件,太老了,换新插件)

1
2
3
4
5
6
7
8
9
#---------------------------废弃,网络原因下载不下来--------------------------------
#为了环境干净,安装docker golang容器工具(--rm参数,运行后销毁容器)
docker run -v /tmp/bin:/go/bin \
--rm golang go get github.com/golang/example/hello/...
#测试,执行该命令会输出Hello, Go examples!,如果没输出,说明容器环境和主机环境不一致
/tmp/bin/hello
#----------------准备工作完成正式开始安装---------------------------------------------------------
#通过golang容器工具下载插件,下载到/tmp/bin目录
docker run -v /tmp/bin:/go/bin --rm golang go get github.com/calavera/docker-volume-glusterfs

手动去下载,通过sftp等工具传到服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
mv docker-volume-glusterfs_linux_amd64 docker-volume-glusterfs   #重命名
cp ./docker-volume-glusterfs /usr/bin #放到bin目录
chmod 777 /usr/bin/docker-volume-glusterfs #添加权限
#其他两台主机,然后复制到其他服务器上
scp root@10.14.0.1:~/docker-volume-glusterfs ~
#依次放到bin目录添加权限
cp ~/docker-volume-glusterfs /usr/bin
chmod 777 /usr/bin/docker-volume-glusterfs
# 三台主机都执行该命令,该命令会前端运行
docker-volume-glusterfs -servers xuanps:worker:home
# 测试使用
sudo docker run --volume-driver glusterfs --volume swarm-volume:/data alpine ash
touch /data/helo

额外的 docker 卷插件

官方插件列表

官方插件商店

rancher/convoy

主要功能快照、备份、还原

总结:适用于单节点,单主机,的本地卷管理

calavera/docker-volume-glusterfs

centos7 安装 GlusterFS

Pure Storage Docker Volume Plugin

Hedvig Docker Volume Plugin

依赖于hedvig cluster

REX-Ray

github: rexray/rexray

参考:每天5分钟玩转 OpenStack Rex-Ray

………..居然没找到一个合适的提供者

rexray/cis-nfs 待测试,NFS似乎不满足需求

参考

Docker与Golang的巧妙结合

基于 GlusterFS 实现 Docker 集群的分布式存储

Docker 应用之owncloud

官网:library/owncloud

默认会创建挂载卷-v /<mydatalocation>:/var/www/html

细分挂载卷

  • -v /<mydatalocation>/apps:/var/www/html/apps installed / modified apps
  • -v /<mydatalocation>/config:/var/www/html/config local configuration
  • -v /<mydatalocation>/data:/var/www/html/data the actual data of your ownCloud (网盘文件)

安装

1
2
3
4
5
docker pull owncloud
#默认安装,会默认创建一个挂载卷
docker run -d -p 14007:80 owncloud:8.1
#将网盘文件存储指向到oss,注意挂载目录的权限问题,否则没权限操作会报错
docker run -v /ossfs/owncloud:/var/www/html/data -d -p 14007:80 owncloud:latest

体验

虽然成功存储到了oss里面但是极度卡,就算是阿里云内网ossfs,一样的卡,因此放弃存到ossfs,可以考虑备份放到ossfs

阿里云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 "$@"