使用Python控制Headless Chrome

首先要解释一下 Headless Chrome,通俗的讲就是运行一个没有GUI的Chrome,在 Headless Chrome 出现以前有 PhantomJS ,但是自从 Headless Chrome 出现之后 PhantomJS 活跃度下降,所以维护者就宣布 了停止继续开发。那么 Headless Chrome 能够什么呢?自动化测试,网页截图,网络调试,爬虫等等任务。Google 说在可预见的未来会一直维护

关于 Headless Chrome 官方有两篇教程

在 Headless Chrome 之前使用 Python 可以结合Chrome推出的 chromedriver 来操作 PhantomJS,那么现在有了Chrome的Headless模式怎么来控制Chrome就是这篇文章要讲的内容。

Chrome DevTools Protocol

在此之前几个重要的网址:

Google官方维护了一份协议叫做 Chrome DevTools Protocol,只要是实现了这一份协议就能够编程来控制Chrome,Chrome 自带的开发者工具其实也是这一份协议的实现

再看几个 Chrome Devtools Protocol 中的概念:

  • Browser 实例可以拥有多个 Page
  • Page 拥有至少一个 frame: main frame, 其他的 frame 可能被网页标记 iframe 和 frame 创建
  • Frame 拥有一个可执行的上下文,在该上下文中 JavaScript 可以被执行,Frame 中也可能有浏览器扩展 extensions 产生的内容被执行

可以用这张 来显示其结构。

常用API

  • Browser 浏览器版本,关闭,命令行等等管理操作
  • Page 该域包含和页面相关接口,页面加载,资源内容,截图,打印等
  • Network 网络请求,Cookie,缓存,证书等内容
  • DOM 文档DOM的获取,修改,删除等
  • Runtime 该域下暴露 JavaScript 相关运行时接口,可以用来执行代码

本地启动 Headless Chrome

本地启动 Headless Chrome 可以参考这篇文章

如果需要使用 Docker 来启动Headless Chrome 也可以使用

docker run -it --rm --name alpine-chrome -p 9222:9222 einverne/alpine-chrome

更加具体的使用介绍可以查看 GitHub

启动之后可以访问: http://localhost:9222/json 来查看是否启动成功。

pychrome

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) 

打印PDF

同样使用 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)

获取网页HTML

获取动态网页的网页内容,等待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']

操纵网页元素注入JS

下面这段代码是访问 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,来抓取网页。

其他

  • https://stackoverflow.com/questions/28430479/using-google-chrome-remote-debugging-protocol
  • https://blog.phantombuster.com/web-scraping-in-2017-headless-chrome-tips-tricks-4d6521d695e8
  • https://stackoverflow.com/questions/7848878/how-to-use-google-chrome-remote-debugging-protocol-in-http
  • https://github.com/auchenberg/devtools-remote
  • https://github.com/auchenberg/chrome-devtools-app
  • https://intoli.com/blog/running-selenium-with-headless-chrome
  • https://duo.com/blog/driving-headless-chrome-with-python

2018-03-01 chrome , headless-chrome , linux , python

Linux 下的Android emulators

待办事项中一直有一个 Genymotion 模拟器的处理,挂在待办已经好几个月了,终于有时间来找一找 Linux 的安卓模拟器了, Genymotion 曾经很好用,可惜的是如今似乎已经收费。

Official

当然第一想到的就是 Android 开发者官网上提供的官方模拟器,虽然早先被诟病不少,但是似乎更新迭代很快速,现在几乎没有什么特别大的问题。

Anbox

这是我 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] 这种错误时,也不沮丧。

官网地址: https://anbox.io/

Genymotion

很可惜的是他已经不再提供免费的开发者 License。

官网: https://www.genymotion.com/


2018-02-28 android , linux , emulator

Grafana 基本使用

Grafana 是一个开源的时序性统计和监控平台,或许用这么简单的一句话无法表现 Grafana 的强大。下面是官方列出的 6 大功能,但其实细分起来 Grafana 要强大更多。

  • 可视化
  • 报警
  • 支持很多数据源,InfluxDB,Elasticsearch,MySQL 等等
  • 全平台支持
  • 无数的 dashboardsplugins
  • 支持用户系统和协作

更多 Feature 见 官网

安装

非常简单,官网就很详细

默认的账户密码都是 admin

基本概念

Data Source

数据源:正式的支持以下数据源 Graphite, InfluxDB, OpenTSDB, Prometheus, Elasticsearch, CloudWatch。从 4.3 版本开始支持 MySQL。

每个数据源都有一个独立的查询编辑器,用来动态从数据源获取数据,并展示到 Panel 上。

Organization

组织:支持多组织,以支持各种部署模式,包括使用单个 Grafana 实例为多个组织提供服务。

用户、数据源和仪表板都隶属于组织。

用户隶属于某个组织后。就拥有该组织下的所有数据源和仪表板。

User

用户: Grafana 的帐户。用户可以属于一个或多个组织,并可以通过角色分配不同级别的权限。

Role

在给每个新用户分配组织时,可以指定其角色。角色有:Admin、Editor 、Read Only Editor、Viewer。默认为 Viewer。

Dashboard

仪表板:由一行或多行的面板组成。仪表板可以看做为一个展示单元(栏目),该单元由一行或多行组件构成,每行又可以由一个面板或多个面板组成。

仪表板的时间段可以由仪表板右上方的仪表板时间选择器控制。

Row

行: 仪表板内的逻辑分隔符,用于将面板组合在一起。一行里可以有一列或多列面板。

Panel

面板:Grafana 的可视化构建块,所有的数据展示都是在面板上实现的。

每个面板都有各种各样的造型和格式化选项,让你创建完美的图片。

目前有四种面板类型:Graph,Singlestat,Dashlist,Table 和 Text。

  • Graph 面板允许你根据需要绘制出许多指标和系列。
  • Singlestat 面板需要将单个查询减少到单个数字。
  • Dashlist 和 Text 是不连接到任何数据源的特殊面板。

可以通过插件安装的方式来扩展面板类型。例如:Pie Chart、Worldmap Panel。

面板上的时间范围通常是仪表板时间选择器中设置的时间范围,但可以通过使用面板特定时间覆盖来覆盖。

Query Editor

查询编辑器:用来显示数据源,并根据数据源查询其包含的指标。

将鼠标放在面板的 Panel Title 位置,然后单击,就会显示出查询编辑,点击 Edit,就显示出查询编辑器了。

Grafana 允许您在查询编辑器中按照它们所在的行来引用查询。如果您向图形添加第二个查询,则可以通过键入#A 来引用第一个查询。这提供了一种简单而方便的方法来构建复合查询。

Templating

模板允许更多的交互式和动态的仪表板。可以让你轻松的批量生成同一类型的查询,而不用一个个添加这些 Panel。

可以根据需要自定义变量参数作为查询查询条件,这些变量参数可以是固定的,也可以是通过应用服务提供的数据,还可以是数据源动态查询的数据。

配置

如果是使用的 deb 安装,配置文件路径

/etc/grafana/grafana.ini

[database]

此处的数据源与前面提到的数据源不同,此处的数据源用来存储 Grafana 的用户、仪表板等 Grafnan 自身的信息。

默认用 sqlite3 数据源,一般也不用修改,也可以修改为 MySQL。

[security]

默认的 Grafana 管理员用户名为 admin,密码为 admin,可以进行修改,管理员密码也可以在页面中修改。

admin_user = admin
admin_password = admin

[users]

用户设置

# 是否允许新用户注册,默认为 true,如果不想让人随意注册,可以关闭
allow_sign_up = false

# 是否允许用户自己创建组织,默认为 true,为了便于管理,组织统一由管理员创建,不允许普通用户创建
allow_org_create = false

# 是否将新用户自动归属到主要的组织上(组织 id=1)。当设置为 false 时,将自动为该新用户创建一个新的组织。
auto_assign_org = true

# 新用户默认的角色
auto_assign_org_role = Viewer

其他更多见 官网

Dashboard 及语句

在 Grafana 中使用 SQL 语句,这部分待补充


2018-02-27 grafana , go

搭建自己的文件共享服务 linx server

之前用过 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

2018-02-26 linux , server , file , media , sharing , photo , linx-server

Workflow for iOS 使用指南

Workflow 是iOS上一款可以实现自动化过程的应用,在iOS 的框架内是先自定义的流程,比如发送最后拍摄的一张照片到 Instagram 这样的操作。他被 Apple 买下之后就免费开放给所有人使用了。有效的使用 Workflow 能够简化在手机上重复的操作。

Workflow 的功能应该由使用者决定,而不是开发者,所以 Workflow 和编程语言一样,需要学习。

Workflow

下面先介绍一些 Workflow 能够做到的事情,然后从中去学习 Workflow 制作的过程,从而能够自己完成自动化流程。

图片九宫格

将方形图片切割为9格图片,Workflow 地址

Google 粘贴板

用Google搜索当前粘贴板中的文字或者图片,Workflow

隐身相机

在不启动相机界面的同时拍照,并保存到相册, Workflow 地址 这一个 Workflow 只有一个选项选择前置还是后置摄像头,如果你想要更加复杂的 Workflow 允许你选择连拍数量的可以使用这个

下载到小米路由器

在手机上复制下载链接运行该Workflow即可,地址

切分全景图

将横向的全景图切分为多个图片方便分享到 Instagram,地址

每天领取支付宝红包

支付宝去年推出的分享领红包活动,虽然一开始诚意满满,不过后来就只能每天领1毛了,不过1毛也是肉嘛,反正 Workflow 点一下够省事,地址

网易云音乐听歌识曲

一键打开网易云音乐听歌识曲,地址

网购历史价格查询

下载文件

下载文件到本地或者 Dropbox

下载Instagram图片和视频

下载 YouTube 视频

网购历史价格查询

获取bilibili视频封面

还有更多好用的可以从下面的网站上获取,我平时常用的

  • App Store 换区
  • Instagram 下载
  • Google以图搜图

更多的 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 就实现了。

reference


2018-02-25 workflow , ifttt , automatic , ios

Squid http 代理

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

reference


2018-02-24 linux , ubuntu , squid , proxy , webproxy , http , https

dockerfile 指令

通常情况下,我们并不使用 docker commit 方法来构建镜像,而是使用 Dockerfile 的定义文件和 docker build 命令来构建镜像。更多 Docker 入门 的内容可以参考之前的文章。

每条指令都会创建一个新的镜像层并对镜像进行提交,Docker 大致上按照下面的流程执行 Dockerfile 中的指令:

  • Docker 从基础镜像运行一个容器
  • 执行指令,对镜像做出修改
  • 执行类似 docker commit 的操作,提交一个新的镜像层
  • Docker 再基于刚刚提交的镜像运行一个新容器
  • 执行 Dockerfile 中下一个指令,直到所有指令执行完毕

常见的命令 RUNEXPOSE 之外,Dockerfile 还支持其他很多指令。

CMD

CMD 指令用于指定容器启动时要运行的命令,类似 RUN,但是 RUN 指令是指镜像被构建时要运行的命令,而 CMD 是指定容器被启动时要运行的命令。运行的命令放在一个数组结构中

docker run 命令可以覆盖 CMD 指令

ENTRYPOINT

ENTRYPOINT 指令和 CMD 指令非常类似,之前说过 CMD 指令会被 docker run 命令覆盖,而 ENTRYPOINT 指令提供的命令不容易在启动容器时被覆盖。实际上, docker run 命令行中的指定的任何参数都会被当做参数再次传递给 ENTRYPOINT 指令中指定的命令。

WORKDIR

WORKDIR 指令用来在从镜像创建一个新的容器时,在容器内部设置一个工作目录,ENTRYPOINT 或 CMD 指定的程序会在该目录下执行。

可以通过 -w 参数在运行时覆盖工作目录

sudo docker run -it -w /var/log ubuntu pwd

ENV

ENV 指令用来在镜像构建过程中设置环境变量,新的环境变量能在后续任何 RUN 指令中使用。

同样也可以使用 -e 参数赖在运行时添加环境变量。

USER

USER 指令用来指定镜像会以什么用户去运行

USER nginx

镜像会以 nginx 用户去运行,同样也可以使用 -u 选项来覆盖该指令

VOLUME

VOLUME 指令用来像基于镜像创建的容器添加卷,一个卷可以存在一个或者多个容器内的特定目录,这个目录可以绕过联合文件系统,提供共享数据或者对数据持久化功能。

  • 卷可以再容器间共享和重用
  • 对卷的修改是立即生效的
  • 对卷的修改不会对更新镜像产生影响
  • 卷会一直存在直到没有任何容器使用

卷功能让我们可以将数据,比如源代码,数据库等其他持久化内容添加到镜像中,而不是预先将这些内容提交到镜像内部,卷允许我们在多个容器间共享内容,可以利用此功能测试容器和内部应用代码,管理日志,处理内部数据库等等。

VOLUME ["/opt/project"]

该指令会基于此镜像创建的任何容器创建一个名为 /opt/project 的挂载点

ADD

ADD 指令用来将构建环境下的文件和目录复制到镜像中。

ADD 指令通过目的地址参数末尾的字符来判断文件源是目录还是文件,如果目标地址以 / 结尾,那么 Docker 就认为源地址指向的是一个目录,如果目的地址不是 / 结尾,那么源地址就是文件。

COPY

COPY 指令和 ADD 很类似,根本不同是 COPY 只关心在构建上下文中复制本地文件,而不会去做文件提取和解压的工作。

如果目的位置不存在, Docker 会自动创建所需要的目录结构

ONBUILD

ONBUILD 指令能为镜像添加触发器,当一个镜像被用作其他镜像的基础镜像时,该镜像中的触发器会被执行。触发器会在构建过程中插入新指令,我们认为这些指令是紧跟 FROM 之后执行的。触发器可以是任何构建指令。

reference

  • 《第一本 Docker 书》

2018-02-23 linux , docker , docker-image

Docker中运行 MySQL

mysql 是 Docker 和 MySQL 官方提供的一个镜像。

启动服务器实例

拉取镜像

docker pull mysql

启动镜像

docker run --name first-mysql -e MYSQL_ROOT_PASSWORD=password -d mysql:5.7

这样就创建了一个名为 first-mysql 的 mysql 5.7 实例。

Shell 中访问容器日志查看

docker exec -it first-mysql bash

日志

docker logs first-mysql

环境变量

当启动 mysql 容器时,可以传入环境变量来改变容器的配置:

  • MYSQL_ROOT_PASSWORD:必须。用于设置MySQLroot用户的密码
  • MYSQL_DATABASE:可选。用于指定镜像启动容器时要创建的数据库。如果提供了用户/密码,则会将该用户做为此数据库的超级用户。
  • MYSQL_USERMYSQL_PASSWORD:可选。用于创建一个新用户并设置密码。
  • MYSQL_ALLOW_EMPTY_PASSWORD:可选。设置为yes时,则可以使用空密码登录
  • MYSQL_RANDOM_ROOT_PASSWORD:可选。设置为yes时会为root用户设置一个随机密码(使用pwgen),所生成的随机密码会被输出到stdout
  • MYSQL_ONETIME_PASSWORD:可选。为root用户指定一个一次性密码,该密码会在用户首次登录时强制修改

数据存储

mysql 镜像创建容器时,数据库存储会以下面两种方式存储:

  • 数据卷容器:使用Docker默认的数据管理方式来管理数据库的数据存储,在这种方式下,数据库文件会被写入数据库的内部。这种方式对于用户非常简单,缺点是很在宿主机上找到所存储的数据。
  • 外部数据卷:在宿主机创建一个数据目录,再将数据目录挂载到容器内部。这种方式可以很方便的在宿主机上找到并进行数据管理,但需要确保数据目录的存在。

使用外部数据卷时,假设宿主机有 /my/data/ 目录,可以使用 -v 选项来讲宿主机挂载到容器:

docker run --name mysql -v /my/data/:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=password -d mysql:5.7

数据备份

docker exec first-mysql sh -c 'exec mysqldump --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' > /some/path/on/your/host/all-databases.sql

在其他容器中连接mysql

官方的镜像中导出的是默认 3306 端口,其他容器可以使用 --link 参数来连接mysql容器

docker run --name other-app --link first-mysql:mysql -d other-application-use-mysql

2018-02-18 mysql , database , linux , docker

netdata 又一款 Linux 监控程序

任何服务器监控是一项很重要的事情,以前一直使用 nodequery ,虽然设置方便简洁,但是数据不够详细也是他很大问题,所以经过一番寻找又发现了这个 netdata。下面是 netdata 一系列的特性

  • 安装方便,几乎是一键
  • 实时信息显示,监控内容详细
  • 发送告警,可以向很多第三方平台发送报警通知,包括 telegram, email, slack channel 等等
  • 无磁盘 IO 操作
  • 不需要 root 权限
  • 可视化界面漂亮

官方提供了一些列的 demo : https://my-netdata.io/

一键安装

按照下面的教程安装:

https://github.com/firehol/netdata/wiki/Installation

配置 Nginx

upstream backend {
	server 127.0.0.1:19999;
	keepalive 64;
}

server {
	listen 80;
	listen [::]:80;

	index index.html index.htm index.nginx-debian.html;

	server_name status.einverne.info;

	auth_basic "Protected";
	auth_basic_user_file passwords;

	location / {
		proxy_set_header X-Forwarded-Host $host;
		proxy_set_header X-Forwarded-Server $host;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_pass http://backend;
		proxy_http_version 1.1;
		proxy_pass_request_headers on;
		proxy_set_header Connection "keep-alive";
		proxy_store off;
	}
}

主要配置如上,可以加上一个密码保护,具体 Nginx 的配置 可以参考链接。

htpasswd -c -d /etc/nginx/passwords yourusername

这行命令中的 passwords 就是之前 Nginx 配置中的 auth_basic_user_file 后的参数,通过该选项设置用户名密码。

卸载删除

netdata 是不提供卸载脚本的,如果要在系统中删除,可以使用如下

killall netdata
apt-get remove zlib1g-dev gcc make git autoconf autogen automake pkg-config
rm -Rf /usr/sbin/netdata
rm -Rf /etc/netdata
rm -Rf /usr/share/netdata
rm -Rf /usr/libexec/netdata
rm -Rf /var/cache/netdata
rm -Rf /var/log/netdata
rm -Rf /opt/netdata
userdel netdata

2018-02-16 linux , vps , monitor

使用 docker compose 管理多个容器

Docker Compose 是一个定义和启动多容器的工具,可以使用 Compose 来管理多个 Docker 容器。Compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。Docker Compose 使用 YAML 文件定义应用,之后可以使用一行简单的命令来创建或者启动所有的服务。

Dockerfile 模板文件,可以让用户很方便的定义一个单独的应用容器,但往往实际应用可能包含不止一个容器,常见的 Web 容器通常还包括一个数据库容器。Compose 允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。

Compose 中有两个重要的概念:

  • 服务 (service):应用容器,实际上可以包括若干运行相同镜像的容器实例
  • 项目 (project):由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义

使用 Compose

使用 Compose 可以简单的归纳为三步

  • 定义应用的 Dockerfile
  • 定义服务 docker-compose.yml 文件
  • 执行 docker-compose up 来启动整个服务

常见的 docker-compose.yml 文件如下:

version: '3'
services:
  web:
    build: .
    ports:
    - "5000:5000"
    volumes:
    - .:/code
    - logvolume01:/var/log
    links:
    - redis
  redis:
    image: redis
volumes:
  logvolume01: {}

安装

Compose 依赖于 Docker Engine,所以确保安装 Compose 之前 Docker 已经在本地安装成功。安装 Compose 非常简单,将编译好的二进制文件下载到本地即可,查看compose 的github release 页面 获取最新版本:

sudo curl -L https://github.com/docker/compose/releases/download/1.19.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version

示例

具体例子可参考官网或者 https://github.com/einverne/dockerfile/ 项目下有 compose-start 文件夹,其中包含示例代码:

version: '3'
services:
  web:
    build: .
    ports:
     - "5000:5000"
  redis:
    image: "redis:alpine"

在该文件夹下使用 docker-compose up 启动服务。使用 docker-compose down 关闭。如果想要在后台执行添加 -d 选项 docker-compose up -d

命令使用

Compose 命令的对象是项目本身,也可以为项目中的服务或者容器,默认为项目。 服务容器一旦构建后,将会带上一个标记名,例如对于 web 项目中的一个 db 容器,可能是 web_db。

命令选项:

-f, --file FILE 指定使用的 Compose 模板文件,默认为 docker-compose.yml,可以多次指定。
-p, --project-name NAME 指定项目名称,默认将使用所在目录名称作为项目名。

常见命令

docker-compose up          # 自动完成构建镜像,创建服务,启动服务,并关联服务等操作
docker-compose down
docker-compose start       # 启动存在的服务
docker-compose stop        # 停止
docker-compose restart     # 重启项目中服务
docker-compose exec        # 进入指定容器
docker-compose help
docker-compose image       # 列出 Compose 文件中包含的镜像
docker-compose kill [SERVICE...]
docker-compose pause [SERVICE...]
docker-compose unpause [SERVICE...]
docker-compose ps          # 列出项目中所有容器

up

大部分时候都可以直接通过该命令来启动一个项目,默认情况,docker-compose up 启动的容器都在前台,控制台将会同时打印所有容器的输出信息。

当通过 Ctrl-C 停止命令时,所有容器将会停止。如果使用 docker-compose up -d,将会在后台启动并运行所有的容器。一般推荐生产环境下使用该选项。

docker-compose up -d        # 后台执行

down

此命令将会停止 up 命令所启动的容器,并移除网络

docker-compose              # 移除停止的容器
docker-compose -v           # 此选项会移除 volumns 中定义的卷,千万小心

举例

> docker-compose down -v
Removing wordpress    ... done
Removing wordpress_db ... done
Removing network wordpress_wordpress-network
Removing volume wordpress_db_data

build

重构项目中容器

docker-compose build [options] [SERVICE...]

rm

删除所有停止状态的服务容器。

docker-compose rm [options] [SERVICES ..]

config

验证 Compose 文件格式是否正确

docker-compose config

Compose 模板文件

默认的模板文件名称为 docker-compose.yml,格式为 YAML 格式。大部分的指令和 docker run 的含义是一样的。

image

指定镜像名或者镜像ID,如果本地不存在,Compose 会拉取该镜像

image: ubuntu

volumes

数据卷挂载设置,可以设置宿主机路径 (HOST:CONTAINER) 或加上访问模式 (HOST:CONTAINER:ro)

volumes:
 - /var/lib/mysql

ports

暴露端口信息,使用宿主端口:容器端口 (HOST:CONTAINER) 格式,或者仅仅指定容器的端口(宿主将会随机选择端口)

更多详细可参考: https://yeasy.gitbooks.io/docker_practice/content/compose/compose_file.html

reference


2018-02-15 docker , dockercompose , linux

电子书

最近文章

  • 使用 Huginn 搭建自己的 IFTTT IFTTT, Zapier
  • notion 使用记录 很早就有人推荐 Notion,但是注册了用了一下,本以为就是一个在线的 Google Docs,可昨天在豆瓣看到一篇文章介绍比 Trello 更加智能的代替品,然后一看就是 Notion,于是就再来研究下 Notion。然后发现原来 Notion 可以是 Google Calendar, 可以是 Trello,可以是 Google Docs,可以是 todo list,可以是 Google Excel。甚至可以导入 word,markdown,html,csv。
  • Google Cloud Platform 使用向导 Google Cloud 提供 300 刀的初始优惠,而最近我的 Linode 节点越来越不稳定,时常撞墙,所以不得不再别人强烈推荐下注册了一下 GCP。这里就记录一下遇到的问题,其他具体的细节网上已经够多,就不再赘述。
  • html 转 pdf 命令行工具 wkhtmltopdf 最近因为用 HTML 写了一个文档,当想要输出时保存为 PDF,而 Chrome 自带的打印功能,本来就能够快速的保存为 PDF,但是却保留不了页面中的链接,所以找到了这个 wkhtmltopdf.
  • freemarker Java 模板引擎 FreeMarker is a free Java-based template engine, originally focusing on dynamic web page generation with MVC software architecture. However, it is a general purpose template engine, with no dependency on servlets or HTTP or HTML, and is thus often used for generating source code, configuration files or e-mails. by wikiPedia