Hugo Presents


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

命令的反斜杠前缀作用

发表于 2019-12-16 | 更新于 2020-05-23 | 分类于 Devel

看到这种类型的命令 \curl ... 于是研究了下,命令前面加反斜杠可以禁用 alias

比如你的 Shell 可能定义了 alias curl='curl -iL' 那么执行 \curl 的效果就是 curl 而没有 -iL 参数

或者你定义了另一个 alias customCmd='ls -lah' 那么执行 \customCmd 就会提示命令不存在

另外还有其他的方式禁用 alias :

1
2
3
"curl"
'curl'
command curl

记一个错误使用 Docker Logging 的案例

发表于 2019-11-21 | 更新于 2020-05-23 | 分类于 Devel

博主竟然都没发现自己已经错误的使用 docker logging 好几年了。

博主习惯用 fluentd 收集容器和应用的日志,类似如下配置:

1
2
3
4
5
logging:
driver: fluentd
options:
fluentd-address: 127.0.0.1:24224
tag: nginx

既然是使用 Docker 那么想当然的就要用 Docker 启动 fluentd 了,同时在使用 docker-compose 编排容器时给所有其他容器添加了 depends_on: - fluentd 配置,以保证其他容器在启动时日志服务已经起来。

本来正常使用是没有问题的,但是当 Docker 服务重启(主机重启或直接重启服务)后,发现即使时添加了 restart:always 的容器也没有自动重启,纷纷停留在 Exit 状态。

通过排查,尝试将 fluentd 直接运行在宿主机上后容器重启正常,问题解决。个人猜测 Docker 在经历重启后并没有按照 docker-compose 的 depends_on 顺序进行重启,而部分重启在尝试重启时发现日志服务不在线固重启失败。

另外 fluentd 的主机安装方式可以参考 Fluentd Installation

从 Drone 0.8 升级到 1.0

发表于 2019-11-14 | 更新于 2020-05-23 | 分类于 Devel

分享一下 Drone 升级到 1.0 后发现的新特性或者坑。

Runner

1.0 以前的时候有过一阵需要部署 drone-agent 的版本,后来 drone 又可以独立运行。直到现在 1.0 版本drone 又要求了 Runner,当然如果你还是使用 Docker 部署,那么配置运行 drone-runner-docker 就好。

Trigger, Condition

现在的条件逻辑不一样了:

Note that all triggers must evaluate to true when combining multiple triggers.

也就是每个 trigger 的执行结果都要为 true 时才能触发,这个改到导致的结果是不能像以前那样同时配置 branch 和 event tag 的条件了,官方也做了解释:

Note that you cannot use branch triggers with tags. A tag is not associated with the source branch from which it was created.

就是说 tag 创建以后跟分支就没有关系了不能同时触发 branch 和 event trigger。

不过也有解决方法,通过配置 Reference trigger 可以同时满足分支推送或 tag 推送,如下:

1
2
3
4
trigger:
ref:
- refs/heads/develop
- refs/tags/*

同理 Steps 中的 When 关键词的逻辑同上

Orgsecret

上个版本的苦衷终于得到解决,每开一个项目都要配置 secret 只有企业版才有全局 secret ,现在 1.0 可以添加组织级别的 secret 了,不过 ui 中没有体现,需要用 drone-cli 配置:

1
drone orgsecret add ined rsync_key @/home/admin/.ssh/id_rsa

添加 orgsecret 后同 org 下的仓库部署就一劳永逸了。

Gitea

和 Gitea 的连接方式变了,通过在 gitea 上创建 application 并将 clientId, clientSecret 配置到 drone 中授权连接。

pull

每一步骤可以增加这个参数来跳过每次触发时拉取最新镜像的操作,否则每次任务可能会非常耗时:

1
2
3
pull: never
pull: if-not-exists
pull: always // 默认为 always

.drone.yml

配置文件的整体结构调整也很大,比如 Volume, Steps, 插件 settings 等等。

在 Flutter 中使用畅言

发表于 2018-08-27 | 更新于 2020-05-23

前阵子参考畅言的 API 文档给 flutter 做了畅言插件:

https://pub.dartlang.org/packages/flutter_changyan 方法的调用上倒还算不麻烦,但是在登录的时候需要搭配 webview 实现,在这里分享下我的思路。

首先 flutter 提供 webview 插件:https://pub.dartlang.org/packages/flutter_webview_plugin 可以控制打开的 url 以及监听 url 的变化,所以登录思路是:

  • 先通过畅言插件获取登录 url ->
  • 监听 url change 事件 ->
  • 调用 webview 打开登录 url 当三方登录成功后会跳会预配置的域名 ->
  • url change 时间监听到访问指定 host 截取 url 中的 code 参数 ->
  • 关闭 webview
  • 用 code 参数调用畅言插件登录功能保存登录成功的 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
void _loginChangyan() {
final flutterWebviewPlugin = new FlutterWebviewPlugin();
flutterWebviewPlugin.onUrlChanged.listen((String url) {
var _uri = Uri.parse(url);
if (_uri.host == 'yourdomain.com' &&
_uri.queryParameters['code'] != null) {
Navigator.of(context).pop();
FlutterChangyan.login(_uri.queryParameters['code']).then((accessToken) {
print('login success: $accessToken');
});
}
});
FlutterChangyan.register('client id', 'client secret', 'callback url');
var loginUrl = FlutterChangyan.loginUrl();
Navigator.push(context, new MaterialPageRoute<void>(
builder: (BuildContext context) {
return new WebviewScaffold(
url: loginUrl,
appBar: new AppBar(
title: const Text('登录畅言'),
leading: new IconButton(
icon: const Icon(Icons.close),
onPressed: _handleWebViewClose
)
),
withZoom: true,
withLocalStorage: true,
);
},
));
}

golang 定义嵌套结构类型

发表于 2018-07-29 | 更新于 2020-05-23 | 分类于 Devel

现在需要用 go 对接一个接口,接口的响应数据如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"success": true,
"data": {
"name": "hugo"
},
"identifi": {
"key": "xxx",
"secret": "secret"
},
"errors": [
{
"code": "not_found",
"message": "something"
}
]
}

我们可能会写如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type Resp struct {
Success bool
Identifi RespIdentifi
Data interface{}
Errors []RespErr
}

type RespIdentifi struct {
Key string
Secret string
}
type RespError struct {
Code string
Message string
}

resp := new(Resp)
json.Unmarshal(respBody, resp)

可读性太差了,不能一眼看出来我们要解析的数据结构是怎样的,如果再稍微复杂一点的结构我们要一行一行的定义很多 type,而且很多时候我们只是需要读到响应的内容,不需要给这些嵌套的结构定义方法来操作它们。

好在 golang 是支持这样写的:

阅读全文 »

UniFi 搭配 HE DNS 配置延迟最小的 DDNS

发表于 2018-07-14 | 更新于 2020-05-23 | 分类于 Others

因为并没有用到 Unifi 中提供的 ddns 服务商:

而且 he 又提供一个非常方便的更新 ddns 记录的方法,所以这里尝试一个能及时更新 ddns 但又不至于请求接口太频繁的方法。

脚本

首先编辑一个更新 dns 的脚本,脚本的具体逻辑是读取拨号接口的 IP 并缓存,当 IP 发生变化时上报新的记录,这样不至于触发 he 的滥用限制,但是有可以通过定时任务将 ddns 延迟控制到1分钟以内:

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
#!/bin/bash
# 确保自己的公网 IP 在这个接口上
INTERFACE="pppoe0"
PRE_IP=`cat /tmp/ddns.ip`
# 将 {hostname} {key} 改成自己的,参考 https://dns.he.net/docs.html
URLS=(
"https://{hostname}:{key}@dyn.dns.he.net/nic/update?hostname={hostname}"
)
IP_RAW=`ip addr show dev $INTERFACE 2>&1`

if [ $? -ne 0 ]; then
logger -t ddns "get pppoe0 ip failed: $IP_RAW"
exit
fi

IP=`echo -e "${IP_RAW}" | grep "inet\b" | awk '{print $2}' | cut -d/ -f1`
if [ "$IP" != "$PRE_IP" ]; then
logger -t ddns "ip change to $IP"
for url in "${URLS[@]}";
do
CURL_RES=`curl -sSf4 "${url}" 2>&1`
# good ip address
# nochg ip address
if [ "${CURL_RES:0:4}" = "good" ] || [ "${CURL_RES:0:5}" = "nochg" ]; then
logger -t ddns "update ddns success: $CURL_RES"
else
logger -t ddns "update ddns failed: $CURL_RES"
exit
fi
done
echo $IP > /tmp/ddns.ip
fi

添加可执行权限后将其上传到 usg 的 /config/scripts/ddns.sh 备用。

阅读全文 »

在 Drone 中使用 etcd 获取项目配置

发表于 2018-06-09 | 更新于 2020-05-23 | 分类于 Devel

接上文有一个配置文件的发布问题待解决,于是考虑用轻量的 etcd 管理,并在发布的时候拉取配置,实践如下:

安装 etcd

  • docker-compose.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
      etcd:
    # 官方镜像
    image: quay.io/coreos/etcd
    restart: always
    depends_on:
    - fluentd
    volumes:
    # 数据目录
    - /var/local/etcd:/etcd-data
    ports:
    # 开放端口用于 drone 构建过程访问
    - 2379:2379
    environment:
    # api 版本,不过服务器不需要指定改选项
    - ETCDCTL_API=3
    command:
    - /usr/local/bin/etcd
    - --data-dir=/etcd-data
    - --name
    - tool01
    # 通告节点地址,用于 e3w 访问
    - --initial-advertise-peer-urls
    - http://etcd:2380
    - --listen-peer-urls
    - http://0.0.0.0:2380
    # 通告节点接口地址,用于 e3w 访问
    - --advertise-client-urls
    - http://etcd:2379
    - --listen-client-urls
    - http://0.0.0.0:2379
    logging:
    driver: 'fluentd'
    options:
    fluentd-address: '127.0.0.1:24224'
    tag: 'etcd'

    # etcd 的 web 管理工具 https://github.com/soyking/e3w
    e3w:
    image: soyking/e3w
    restart: always
    depends_on:
    - fluentd
    - etcd
    volumes:
    # e3w 配置文件,后面给出文件内容
    - ./e3w.ini:/app/conf/config.default.ini
    ports:
    # 开方端口用于 nginx 反代,请在 nginx 上包一层认证
    - 9002:8080
    logging:
    driver: 'fluentd'
    options:
    fluentd-address: '127.0.0.1:24224'
    tag: 'e3w'
    阅读全文 »

Drone 入门指引

发表于 2018-06-07 | 更新于 2020-05-23 | 分类于 Devel

最近在尝试用 Drone 替换动辄占用上 G 内存的 jenkins,决定把初步成果分享出来,本文会提供搭配 Gitea 的一个前端和一个 golang 项目的配置样例。

安装

安装非常简单,按照官方给的样例写好 docker-compose.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
services:  
drone-server:
image: drone/drone
restart: always
depends_on:
- fluentd
ports:
- "9001:8000"
volumes:
- /var/local/drone:/var/lib/drone/
env_file:
- .env
logging:
driver: 'fluentd'
options:
fluentd-address: '127.0.0.1:24224'
tag: 'drone-server'

drone-agent:
image: drone/agent
restart: always
depends_on:
- fluentd
- drone-server
volumes:
- /var/run/docker.sock:/var/run/docker.sock
env_file:
- .env
environment:
DRONE_SERVER: "drone-server:9000"
logging:
driver: 'fluentd'
options:
fluentd-address: '127.0.0.1:24224'
tag: 'drone-agent'

其中 .env 的文件内容为:

1
2
3
4
5
6
DRONE_HOST=ci.yourdomain.com # drone 访问域名
DRONE_OPEN=true # 是否开方注册
DRONE_GITEA=true # 是否关联 gitea
DRONE_GITEA_URL=https://git.yourdomain.com # gitea 地址
DRONE_SECRET=xxxx # drone 服务密钥
DRONE_ADMIN=someone # drone 管理帐号,可以修改项目配置
阅读全文 »

在 Docker 容器中访问主机

发表于 2018-05-04 | 更新于 2020-05-23 | 分类于 Devel

有时候多个容器不是在一个 compose 中启动的,不方便 link 起来或者是有些服务是直接跑在主机上的,所以从容器访问主机的场景十分普遍,我们需要一个类似 127.0.0.1 的 IP 地址能在容器中访问到主机。在 linux 环境中这个问题很好解决,安装完 docker 之后会出现一个 docker0 的网卡,这个网卡上绑定的 IP 就可以在容器中访问,并指向主机,默认情况下会是 172.17.0.1

但是 mac 和 windows 开发环境下不会出现这个网卡也没有这样一个 IP 来访问,不过最新的 docker 18.03 加入了一个 feature,在容器中可以通过 host.docker.internal hostname 来访问主机,解析得到的 ip 是 192.168.65.2 正是 docker 的设置中的子网网段

详情参考官方文档:
https://docs.docker.com/docker-for-mac/networking/#there-is-no-docker0-bridge-on-macos

Golang 项目结构探讨

发表于 2018-04-29 | 更新于 2020-05-23 | 分类于 Devel

当源代码文件多起来的时候原本方便的单层目录变得杂乱无章起来,但是 golang 又是以文件夹分包的,如果直接按照功能拆分包就会遇到变量共享的问题,参考了 gogs, beego 的代码后发现一个类似存放配置、全局变量的包变得必不可少,同时结合多年的 laravel 脚手架习惯得出下面的文件结构:

阅读全文 »
12
Hugo

Hugo

工欲善其事,必先利其器

18 日志
2 分类
33 标签
GitHub Weibo
© 2016 — 2021 Hugo
蜀ICP备19037151号-1