有很多网站可以托管 Docker 镜像, Docker 官方站点 hub.docker.com 速度在国内访问不是很快,不过幸好国内有公司做了 hub.docker.com 的镜像,通过 CDN 优化了下载。Docker Hub 为用户提供无限数量的公开镜像托管服务,但是仅提供一个私有镜像托管。Docker Hub 上镜像分为两类,一类为官方镜像,Ubuntu,redis 等等由权威三方开发和维护通过 Docker 官方认证,另一类就是普通用户镜像。
手动修改 Docker 配置 /etc/docker/daemon.json
文件增加 docker registry 镜像:
{
"registry-mirrors": [
"加速地址"
],
"insecure-registries": []
}
修改其中的 加速地址
,不同的服务提供的镜像加速地址不一样。记得修改配置之后 sudo /etc/init.d/docker restart
重启 docker。
或者
sudo systemctl daemon-reload
sudo systemctl restart docker
在 macOS 中,可以在界面中配置,在 Docker 应用中,打开偏好设置,然后在 “Docker Engine” 中配置:
修改后使用 sudo docker info
来检查配置是否生效。
如果下方公开的镜像速度不佳的话,尝试阿里云的镜像,需要开发者账号。
Docker 官方提供的镜像:
https://registry.docker-cn.com
Azure 中国镜像 包括 Docker Hub、GCR、Quay。
https://dockerhub.azk8s.cn
2020 年 5 月更新,Azure 提供的镜像已经限制只能够 Azure 的机器使用了。
Error response from daemon: error parsing HTTP 403 response body: invalid character '<' looking for beginning of value: "<html>\r\n<head><title>403 Forbidden</title></head>\r\n<body bgcolor=\"white\">\r\n<center><h1>403 Forbidden</h1></center>\r\n<hr><center>nginx/1.14.0 (Ubuntu)</center>\r\n</body>\r\n</html>\r\n"
网易提供的地址:
https://hub-mirror.c.163.com
https://mirror.baidubce.com
腾讯提供的镜像,只能在腾讯云上使用:
https://mirror.ccs.tencentyun.com
https://docker.mirrors.ustc.edu.cn
https://reg-mirror.qiniu.com
DaoCloud 提供 的加速地址:
http://6ce28dce.m.daocloud.io
这个地址不同用户看起开不一样,可以使用我的,也可以自己注册。
这个地址不知道是不是长久地址,不过失效,可以到他的官方网站 查看。
也可以使用 Docker 官方提供的镜像
https://registry.docker-cn.com
官网地址
mritd 反向代理了主流的三大仓库(Docker Hub,gcr.io,quay.io)。
不得不说的 hub.docker.com,官方提供
这是国内 DaoCloud 公司提供的
可以通过下面的链接查看 gcr.io 中存在镜像,类似于直接在 https://hub.docker.com/ 中搜索查看。
阿里云加速器 (点击管理控制台 -> 登录账号 (淘宝账号) -> 右侧镜像中心 -> 镜像加速器 -> 复制地址)。
这里是阿里云提供的镜像托管服务
然后有人 把 gcr.io/google-containers
下所有的 Docker 镜像都同步到了中央库
更多的 registry 可以参考这里
在配置完 Docker 镜像之后可以执行 docker info
查看输出中的:
Registry Mirrors:
https://docker.mirrors.ustc.edu.cn/
https://hub-mirror.c.163.com/
如果出现配置的镜像地址则表示生效了。
https://lug.ustc.edu.cn/wiki/mirrors/help/docker ↩
python 的版本管理有 pyenv,同样的 ruby 也有 rbenv,可以和 pyenv 一样在本地管理多个 ruby 版本,很久没有更新本地的 ruby 版本导致了 jekyll 的依赖不支持才想起来这件事情。
其项目地址为:
https://github.com/rbenv/rbenv
因此安装就很方便
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
然后将下面内容添加到 PATH
export PATH="$HOME/.rbenv/bin:$PATH"
运行
~/.rbenv/bin/rbenv init
根据依赖将输出内容,添加到 ~/.zshrc
重启shell,或者 source ~/.zshrc
使设置生效
再运行检查脚本
curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-doctor | bash
一切没问题就OK。
rbenv install
命令不在 rbenv
中,而是在 ruby-build中,可以通过下面的命令安装
apt-get install autoconf bison build-essential libssl-dev libyaml-dev libreadline6 libreadline6-dev zlib1g zlib1g-dev
git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
如果是 Debian(>=7) 或者 Ubuntu (>=12.10) 也可以使用
sudo apt-get update
sudo apt-get install rbenv ruby-build
rbenv install --list # 查看可用
rbenv install 2.5.0 # 安装版本
rbenv 中的 Ruby 版本有三个不同的作用域:全局(global),本地(local),当前终端(shell),和 pyenv 类似。
查找版本的优先级是 当前终端 > 本地 > 全局。
rbenv global 2.1.2
rbenv local 2.1.2
rbenv shell 2.1.2
最近 VPS 磁盘空间一直上涨报警,就想查看一下哪个文件夹占用空间比较大,可以腾出一些可用空间来。查了一圈发现 du
命令就是该功能。du
全称 disk usage,
du
文档中就是这么描述他的功能的 —- 文件占用的空间,具体用法
du [OPTIONS] ... [FILE] ...
和绝大多数的命令一样,支持很多的选项,最常用的和 df
命令一样 -h
,可以记忆 --human-readable
,用比较人性化的单位,比如 K,M,G。
所以这样就可以使用
du -d 2 -h <dir> | grep '[0-9\,]\+G'
sudo du -h --max-depth=1
来快速的找到占用空间比较大的文件夹,这里的 -d
实际是 --max-depth
的缩写形式,也就是查看 dir 目录下,最多往下查找 2 层,然后以 -h
比较友好的方式输出结果。
除了上面提到了 -h
参数,du 命令还有一些其他的参数
当我们使用 -h
选项时命令会根据不同的大小给出合适的 K, M, G 单位,方便查看,但如果想要强制命令输出统一的单位可以使用 -BM
这里将 -BM
拆开,-B
表示的是 --block-size=SIZE
, M 表示的是兆,同理可以使用 -BG
强制使用 G 单位。
du -ah –-max-depth=0
-a
显示目录中所有文件及文件夹大小-–max-depth=n
这个选项也能简写成 -d n
: 深入到第 n 层目录,此处设置为 0,即表示不深入到子目录,设置为 1,则超过 1 层深度则忽略du --exclude=/path
-s
显示总和
du -hs /path
如果使用 du -h
那么会打印出 path 下所有目录的占用情况,如果使用 -s
那么只会输出 /path 占用的空间。
使用 -c
选项会额外在最后打印两行总占用量
du -ch /Download
例如:
..
..
3.3G Downloads
3.3G total
通常情况下 du 会打印目录及其下所有子目录大小,加入有一个目录 Parent,下方有 SubDirA,SubDirB,还有很多的文件在 Parent 目录下,那么想要知道所有在 Parent 下文件占用,但是不想包括 SubDirA 和 SubDirB 的空间,那么可以使用 -S
选项。
du -h -S -d 2 /path/to/Parent
熟悉了 du
命令之后,还有一个可视化更好的工具叫做 ncdu,在终端中使用比较友好的展示来显示磁盘空间占用。
更多的命令使用方法可以参考 tecmint
经常听说 Kodi,却一直没有时间了解一下,最近整理盒子 应用,突然间想起了这个被很多人称为的神器。
Kodi 是一个强大媒体播放软件,支持 Macos, Windows, Linux, iOs 以及 Android 等众多平台,能在各种手机、电脑、平板以及机顶盒中运行。并且因为 Kodi 强大的媒体播放能力,被很多人成为家庭影院必不可少的应用。Kodi 拥有上千种插件,大大扩展了它的功能,丰富的 Kodi 插件为 Kodi 提供了无数的可能。Kodi 的插件种类很多,有音视频源插件,有字幕插件,有影视内容索引插件,有链接搜索助手插件等等。
从官网上下载 kodi 写下文章时最新的版本为 17.6,选安卓 64 位
Kodi:https://kodi.tv/
备份地址:
比如要在斐讯盒子 T1 中安装 Kodi,首先去盒子的设置 - 高级 - 远程调试打开,如果可能就把盒子的 IP 设置为固定 IP,这个 IP 下面命令中需要使用到。
通过 adb 安装过程如下:
adb connect <ip>
adb shell
adb install /path/to/kodi.apk
http://srp.nu
, 为源取个名字,更多的源地址,可以看下文如何安装源这里有两篇详细的图文教程可以参考:
在安装插件源的时候可能会遇到这几个名词
其实这是 Kodi 的版本代号。
其实看到这里就能看到 Kodi 其实绝大部分的功能都是可代替的,流媒体播放固然强大,但是我更喜欢将资源通过 samba 共享出来,在盒子上使用小白播放器,或者在手机上使用 ES Explorer 访问;Kodi 中的直播流功能强烈的依赖于整理好的直播流,而盒子上的超级直播,HDP 直播等等 应用都能很好的代替直播流;再其次 Kodi 带的 DLNA,AirPlay 投屏功能,其实装一个乐播投屏就能完美解决,更不用说我之前的两台海美迪自身就携带 DLNA,局域网投屏本身问题也不大;最后再是 Kodi 的强大的插件库,虽然强大,却无奈经年无人维护,虽然有无数的插件可以使用,却只有寥寥几个可用。所以最后其实 Kodi 也不是居家必备的良药,对于折腾我始终抱有这样的态度,用起来比怎么用要重要的很多,真正用起来才是一个软件应该提供的,我在盒子上话费时间最多的其实就是播放本地局域网共享的视频,其实本身这个功能并不需要那么强大的 Kodi,当然 Kodi 也可以,至于强大的媒体库,对于我这样看完就删,真的只有经典的才保存的玩家来说,太奢侈。
首先要解释一下 Headless Chrome,通俗的讲就是运行一个没有GUI的Chrome,在 Headless Chrome 出现以前有 PhantomJS ,但是自从 Headless Chrome 出现之后 PhantomJS 活跃度下降,所以维护者就宣布 了停止继续开发。那么 Headless Chrome 能够什么呢?自动化测试,网页截图,网络调试,爬虫等等任务。Google 说在可预见的未来会一直维护。
关于 Headless Chrome 官方有两篇教程
在 Headless Chrome 之前使用 Python 可以结合Chrome推出的 chromedriver 来操作 PhantomJS,那么现在有了Chrome的Headless模式怎么来控制Chrome就是这篇文章要讲的内容。
在此之前几个重要的网址:
Google官方维护了一份协议叫做 Chrome DevTools Protocol,只要是实现了这一份协议就能够编程来控制Chrome,Chrome 自带的开发者工具其实也是这一份协议的实现。
再看几个 Chrome Devtools Protocol 中的概念:
可以用这张图 来显示其结构。
常用API
本地启动 Headless Chrome 可以参考这篇文章。
如果需要使用 Docker 来启动Headless Chrome 也可以使用
docker run -it --rm --name alpine-chrome -p 9222:9222 einverne/alpine-chrome
更加具体的使用介绍可以查看 GitHub
启动之后可以访问: http://localhost:9222/json 来查看是否启动成功。
pychrome 是 Chrome Devtools Protocol 的 Python 实现,其他语言的实现,可以查看这个项目。Chrome官方推荐js/nodejs的实现 chrome-remote-interface 还有 node.js 实现的更高层级的 Puppeteer。
这里主要摘录几个常用的操作
使用 Page.captureScreenshot
def screenshot(browser, url, filename='image.png'):
tab = browser.new_tab()
tab.start()
tab.call_method('Page.navigate', url=url, _timeout=5)
tab.wait(10)
# 截取当前Tab屏幕,结果为图片内容Base64
screen_base64 = tab.call_method("Page.captureScreenshot")
image_data = screen_base64.get('data', '')
with open(filename, 'wb') as f:
f.write(image_data.decode('base64'))
tab.stop()
browser.close_tab(tab)
同样使用 Page
下方法
def print_to_pdf(browser, url, filename='file.pdf'):
tab = browser.new_tab()
tab.start()
tab.call_method('Page.navigate', url=url, _timeout=5)
tab.wait(10)
pdf_data = tab.call_method('Page.printToPDF', landscape=False).get('data')
with open(filename, 'wb') as f:
f.write(pdf_data.decode('base64'))
tab.stop()
browser.close_tab(tab)
def perform_input(browser):
"""向下浏览页面"""
tab = browser.new_tab()
tab.start()
tab.Page.enable()
tab.Page.navigate(url='https://www.douban.com/', _timeout=5)
tab.wait(5)
# 更多 keycode 可以参考 https://msdn.microsoft.com/en-us/library/dd375731(VS.85).aspx
keycode = int(0x22)
tab.Input.dispatchKeyEvent(type='keyDown', windowsVirtualKeyCode=keycode, nativeVirtualKeyCode=keycode)
tab.wait(3)
screen_base64 = tab.call_method("Page.captureScreenshot")
image_data = screen_base64.get('data', '')
with open("keyDown.png", 'wb') as f:
f.write(image_data.decode('base64'))
tab.stop()
browser.close_tab(tab)
获取动态网页的网页内容,等待JS执行完成后获取HTML
def get_html(browser, url):
tab = browser.new_tab()
tab.start()
tab.call_method('Page.navigate', url=url, _timeout=5)
tab.wait(10)
html = tab.Runtime.evaluate(expression="document.documentElement.outerHTML")
tab.stop()
browser.close_tab(tab)
return html['result']['value']
下面这段代码是访问 baidu,输入关键字,并点击搜索按钮,解析搜索结果并打印
def perform_click(browser):
tab = browser.new_tab()
# def loading_finished(**kwargs):
# print "[loading finished]"
#
# # when HTTP request has finished loading
# tab.set_listener("Network.loadingFinished", loading_finished)
tab.start()
# call method
# tab.Network.enable()
tab.Network.enable()
tab.Page.enable()
tab.Runtime.enable()
def dom_content_event_fired(**kwargs):
print "[content] dom content event fired"
tab.DOM.enable()
root = tab.DOM.getDocument()
root_node_id = root.get('root', {}).get('nodeId', '')
# 找到输入框
input_box = tab.DOM.querySelector(nodeId=root_node_id, selector='#kw')
# tab.DOM.setNodeValue(nodeId=input_box, value='hello')
tab.Runtime.evaluate(expression='document.getElementById("kw").value="Chrome"', )
# 找到搜索按钮
search_btn = tab.DOM.querySelector(nodeId=root_node_id, selector='#su')
remote_node = tab.DOM.resolveNode(nodeId=search_btn.get('nodeId', ''))
# 执行点击
tab.Runtime.callFunctionOn(functionDeclaration='(function() { this.click(); })',
objectId=remote_node.get('object', {}).get('objectId', {}))
tab.wait(3)
# 输出结果
html = tab.Runtime.evaluate(expression="document.documentElement.outerHTML")
html_value = html.get('result', {}).get('value', '').encode('utf-8')
soup = BeautifulSoup(html_value, 'html.parser')
l = soup.select('h3 > a')
for result in l:
print result.text
print result['href']
screen_base64 = tab.call_method("Page.captureScreenshot")
image_data = screen_base64.get('data', '')
with open("test.png", 'wb') as f:
f.write(image_data.decode('base64'))
# tab.DOM.performSearch(query='xpath', includeUserAgentShadowDOM=True)
# stop the tab (stop handle events and stop recv message from chrome)
tab.stop()
# close tab
browser.close_tab(tab)
tab.set_listener("Page.domContentEventFired", dom_content_event_fired)
# tab.call_method("Page.reload", ignoreCache=False)
tab.call_method("Page.navigate", url='https://www.baidu.com', _timeout=5)
tab.wait(20)
完整的代码可以参考 GitHub
这篇文章讲述了使用 nodejs 的库 NickJS来爬取网站的要点。
这篇使用 nodejs 的chrome-remote-interface,来抓取网页。
其他
待办事项中一直有一个 Genymotion 模拟器的处理,挂在待办已经好几个月了,终于有时间来找一找 Linux 的安卓模拟器了, Genymotion 曾经很好用,可惜的是如今似乎已经收费。
当然第一想到的就是 Android 开发者官网上提供的官方模拟器,虽然早先被诟病不少,但是似乎更新迭代很快速,现在几乎没有什么特别大的问题。
这是我 Google 出来的第二个结果,他官网的标语就是可以再 GNU/Linux 系统上运行任何 Android 应用程序。根据官网的介绍, Anbox 和 Genymotion 的虚拟化不一样, Genymotion 是在操作系统上完整的虚拟化整个系统,而 Anbox 直接使用宿主机的硬件和内核来运行 Android 程序。目前 Anbox 没有可视化界面可以安装 Apk,可以使用命令 adb install path/to/app.apk
来安装。
Anbox 这个项目还是属于起步阶段,但是体验还是非常不错的,如果遇到安装之后无法打开,或者无法安装 Failure [INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113]
这种错误时,也不沮丧。
如果要在 Anbox 中安装 arm 和 Google Play 可以参考这个项目
官网地址:https://anbox.io/
很可惜的是他已经不再提供免费的开发者 License。
官网:https://www.genymotion.com/
Grafana 是一个开源的时序性统计和监控平台,或许用这么简单的一句话无法表现 Grafana 的强大。下面是官方列出的 6 大功能,但其实细分起来 Grafana 要强大更多。
更多 Feature 见 官网
非常简单,官网就很详细
默认的账户密码都是 admin
数据源:Grafana 获取数据的配置,支持以下数据源
从 4.3 版本开始支持 MySQL。
每个数据源都有一个独立的查询编辑器,用来动态从数据源获取数据,并展示到 Panel 上。
组织:支持多组织,以支持各种部署模式,包括使用单个 Grafana 实例为多个组织提供服务。
用户、数据源和仪表板都隶属于组织。
用户隶属于某个组织后。就拥有该组织下的所有数据源和仪表板。
用户: Grafana 的帐户。用户可以属于一个或多个组织,并可以通过角色分配不同级别的权限。
在给每个新用户分配组织时,可以指定其角色。角色有:Admin、Editor 、Read Only Editor、Viewer。默认为 Viewer。
仪表板:由一行或多行的面板组成。仪表板可以看做为一个展示单元(栏目),该单元由一行或多行组件构成,每行又可以由一个面板或多个面板组成。
仪表板的时间段可以由仪表板右上方的仪表板时间选择器控制。
行: 仪表板内的逻辑分隔符,用于将面板组合在一起。一行里可以有一列或多列面板。
面板:Grafana 的可视化构建块,所有的数据展示都是在面板上实现的。
每个面板都有各种各样的造型和格式化选项,让你创建完美的图片。
目前有四种面板类型:Graph,Singlestat,Dashlist,Table 和 Text。
可以通过插件安装的方式来扩展面板类型。例如:Pie Chart、Worldmap Panel。
面板上的时间范围通常是仪表板时间选择器中设置的时间范围,但可以通过使用面板特定时间覆盖来覆盖。
查询编辑器:用来显示数据源,并根据数据源查询其包含的指标。
将鼠标放在面板的 Panel Title 位置,然后单击,就会显示出查询编辑,点击 Edit,就显示出查询编辑器了。
Grafana 允许您在查询编辑器中按照它们所在的行来引用查询。如果您向图形添加第二个查询,则可以通过键入#A 来引用第一个查询。这提供了一种简单而方便的方法来构建复合查询。
模板允许更多的交互式和动态的仪表板。可以让你轻松的批量生成同一类型的查询,而不用一个个添加这些 Panel。
可以根据需要自定义变量参数作为查询查询条件,这些变量参数可以是固定的,也可以是通过应用服务提供的数据,还可以是数据源动态查询的数据。
如果是使用的 deb 安装,配置文件路径
/etc/grafana/grafana.ini
此处的数据源与前面提到的数据源不同,此处的数据源用来存储 Grafana 的用户、仪表板等 Grafana 自身的信息。
默认用 SQLite3 数据源,一般也不用修改,也可以修改为 MySQL。
默认的 Grafana 管理员用户名为 admin,密码为 admin,可以进行修改,管理员密码也可以在页面中修改。
admin_user = admin
admin_password = admin
用户设置
# 是否允许新用户注册,默认为 true,如果不想让人随意注册,可以关闭
allow_sign_up = false
# 是否允许用户自己创建组织,默认为 true,为了便于管理,组织统一由管理员创建,不允许普通用户创建
allow_org_create = false
# 是否将新用户自动归属到主要的组织上(组织 id=1)。当设置为 false 时,将自动为该新用户创建一个新的组织。
auto_assign_org = true
# 新用户默认的角色
auto_assign_org_role = Viewer
其他更多见 官网
在 Grafana 中使用 SQL 语句,这部分待补充
Grafana 支持非常多的插件,可以扩展数据源,或者扩展显示,或者用来增强一些功能。
之前用过 https://sm.ms 这个非常好用的图片共享站,界面非常简洁,延迟也低,就想着是不是自己也能够搭建一套这样的服务私用,然而 sm.ms 并没有开源,连其 Android/iOS 客户端也并没有开源,所以只能在网上寻觅代替品,幸而遇到了 linx server。
同样是一个文件分享的站点,通过 Docker 搭建一套服务非常简单,他也能够支持使用 API 上传,界面也同样非常简洁。具体的使用可以参考 Docker 页面
docker pull einverne/linx-server
docker run -p 8080:8080 -d -v /media/meta:/data/meta -v /media/files:/data/files einverne/linx-server
源码中使用的框架和工具:
Workflow 是 iOS 上一款可以实现自动化过程的应用,在 iOS 的框架内是先自定义的流程,比如发送最后拍摄的一张照片到 Instagram 这样的操作。他被 Apple 买下之后就免费开放给所有人使用了。有效的使用 Workflow 能够简化在手机上重复的操作。
Workflow 的功能应该由使用者决定,而不是开发者,所以 Workflow 和编程语言一样,需要学习。
下面先介绍一些 Workflow 能够做到的事情,然后从中去学习 Workflow 制作的过程,从而能够自己完成自动化流程。
将方形图片切割为 9 格图片,Workflow 地址
用 Google 搜索当前粘贴板中的文字或者图片,Workflow
在不启动相机界面的同时拍照,并保存到相册, Workflow 地址 这一个 Workflow 只有一个选项选择前置还是后置摄像头,如果你想要更加复杂的 Workflow 允许你选择连拍数量的可以使用这个
在手机上复制下载链接运行该 Workflow 即可,地址
将横向的全景图切分为多个图片方便分享到 Instagram,地址
支付宝去年推出的分享领红包活动,虽然一开始诚意满满,不过后来就只能每天领 1 毛了,不过 1 毛也是肉嘛,反正 Workflow 点一下够省事,地址
一键打开网易云音乐听歌识曲,地址
下载文件到本地或者 Dropbox
还有更多好用的可以从下面的网站上获取,我平时常用的
更多的 Workflow 可以从下面网址获取
还有一个实用技巧就是实用 Google 的 site 搜索语法,比如想要搜索 Instagram 相关的 Workflow,则可以在 Google 中输入 Instagram site:https://workflow.is/workflows/
。
如果你常用 RSS,那么可以在 InoReader 中订阅该组合包:http://www.inoreader.com/bundle/0014cd63bb38
通过上面的一些例子应该可以看到一些端倪,其实 Workflow 就是把一些常用的操作给编程化,比如最简单的支付宝领取红包,其实就是使用 Safari 打开一个链接。如果再复杂一些比如切割图片,涉及到一些宽高计算,可能还有些 IF 的判断。如果再复杂一些比如 Instagram 图片下载,涉及到了下载网页内容用正则去匹配关心的内容,在比如 Google 以图搜图,涉及到了 Post 请求,然后拼凑网页链接再打开。
最最重要的一点就是网络服务提供足够的 API 能够让 Workflow 能够轻易的调用,如果有翻译服务提供了公开可调用的 API,我们就可以在 Workflow 中,获取粘贴板内容,将内容发送给翻译服务请求结果,并且将结果以通知或者其他形式告诉给用户,这样一个翻译的 Workflow 就实现了。
Squid 是一个Web代理软件,可以轻松的实现 HTTP,HTTPS,FTP 代理,通过缓存常用请求,Squid 能够减少带宽使用,提高响应速度。
sudo apt-get update
sudo apt-get install squid
Squid 的默认配置文件存放在 /etc/squid/squid.conf
下
sudo vim /etc/squid/squid.conf
Squid 的默认端口是 3128,配置文件中可以 http_port 3128
来设置
Squid 默认是不允许任何客户端连接的,通过修改配置允许所有客户端连接
http_access allow all
修改完成后重启代理服务
sudo service squid restart