Systemd integration

Systemd is now included in both the centos:7 and centos:latest base containers, but it is not active by default. In order to use systemd, you will need to include text similar to the example Dockerfile below:

FROM centos:7
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]

Dockerfile for systemd base image

This Dockerfile deletes a number of unit files which might cause issues. From here, you are ready to build your base image.

$ docker build --rm -t local/el7-systemd .

Example systemd enabled app container

In order to use the systemd enabled base container created above, you will need to create your Dockerfile similar to the one below.

FROM local/el7-systemd
RUN yum -y install httpd; yum clean all; systemctl enable httpd.service
EXPOSE 80
CMD ["/usr/sbin/init"]

Build this image:

$ docker build --rm -t local/el7-systemd-httpd .

Running a systemd enabled app container

In order to run a container with systemd, you will need to mount the cgroups volumes from the host. Below is an example command that will run the systemd enabled httpd container created earlier.

$ docker run -ti -v /sys/fs/cgroup:/sys/fs/cgroup:ro -p 80:80 local/el7-systemd-httpd

This container is running with systemd in a limited context, with the cgroups filesystem mounted. There have been reports that if you’re using an Ubuntu host, you will need to add -v /tmp/$(mktemp -d):/run in addition to the cgroups mount.

The Dawn of a New Era in Human Spaceflight

Sailing Over the Caribbean From the International Space Station

placeHolder

没有真正意义上的亲密,
我们手牵手时感受到的触觉,不过是彼此皮肤上的原子间的斥力罢了。

Atomic Force.

— MorningRocks

在 Docker 容器里跑 Python 程序时,我们经常遇到通过print函数或者logging 模块输出的信息在容器 log 中迷之失踪,过了好久又迷之出现。这是因为 Python 在写 stdout 和 stderr 的时候有缓冲区,导致输出无法实时更新进容器 log。

有如下几种方法解决:

1.增加环境变量
对于使用print函数打印的内容,在运行容器时增加环境变量PYTHONUNBUFFERED=0就可以解决。

2.配置 logging 的 stream 参数

import logging
logging.basicConfig(stream=sys.stdout)

这样,通过 logging 模块打印的日志都会直接写到标准输出 stdout。

或者自定义两个StreamHandler分别配置为输出到 stdout 和 stderr,来对不同 log 分别进行输出处理。

3.WSGI server 配置参数
如果是以 WSGI server 运行的 web 应用,以 gunicorn 为例,在 gunicorn 的启动命令中增加参数--access-logfile - --error-logfile -即可。

Sailing Over the Caribbean From the International Space Station

Sailing Over the Caribbean From the International Space Station

placeHolder

「喝醉的酒鬼总能找到回家的路,喝醉的鸟儿则可能永远也回不了家了。」

这是数学家 George Pólya 在一百年前证明的定理。

翻译成可以简单理解的人类语言(并不是)则是:
在二维网络中随机游走是常返的,但在三维空间中则不是。

此处应有数据做支撑:
在二维网络中随机游走,回到出发点的概率是 100%;在三维空间中大约是 34%;而在八维空间中,这个概率只有 7.3%。

A drunk man will find his way home, but a drunk bird may get lost forever.

— MorningRocks

析构函数是 C++ 中一个非常重要的概念,析构函数 (destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。 析构函数往往用来做“清理善后” 的工作,例如在建立对象时用 new 开辟了一片内存空间,delete 则会调用析构函数后释放内存。

而在 Python 中没有专用的构造和析构函数,但是一般可以在__init____del__分别完成初始化和删除操作,以替代构造和析构。

但是 Python 社区中的许多人都不推荐使用 __del__,因为 Python 对对象使用了引用计数来管理,很多情况下是很难以估计是什么时候引用计数为 0 而造成销毁的,同时很多使用技巧告诉我们使用 Python 编程不用再过度优化内存使用,以避免写出 C++ 风格的代码。

在本文中,我们将明确如何来正确使用__del__

Continue reading

小时候家里管得严不让我过早接触网络和计算机,所以我第一次接触编码还是那句熟悉的九宫格手机键盘口令*#220807#,在我的印象中那是一个比 symbian 更加广阔的天地,极弱的算力和有限的内存却支撑起了众多优秀的应用程序。

最近在做一个非常 hacker 的一个项目,通过采集区域监控摄像视频流,通过 CV 算法分析获取结构化数据,然后上报到服务端进行比对和分析,最终实现区域监控无人值守高效运转,其上可以包装的产品还有很多,想想就觉得很兴奋。

Full-time 写各类软件代码已经一年多,这次又可以接触到硬件并去攻略他,唤醒了我血液中流淌着的 Hacker 基因。

0x00 Architecture

一个完整的智能监控网络需要包括 ‘Edge – Server – Frontend’ 这三块组件。

  1. Edge:边缘设备,包括 cam,nvr 及其他智能采集及分析设备;
  2. Server: 宏观上包含各类 S3对象存储,kafka消息队列,MQTT长连接等服务端云产品和 CDN 内容分发网络等第三方服务;
  3. Frontend: 前端大屏,后端系统稳定性和数据完整性展现的重要载体,一般还需要配合产品设计实现数据展示及各类不同场景下的视频流播放。

Continue reading

我带的实习生要开始搞 fpm 的落地和实现了,为了更加优雅的完成这个工具,整个 rpmbuild – Test – Beta – Production 生命周期充斥着各类异步场景。

0x00 Promise in Node.js

这段时间写大屏用 Node.js 积累了一些网络和文件操作上使用异步编程的经验,一般简单场景使用回调方式就能很好的解决问题,但当遇到比较复杂的逻辑时,为了避免 Callback Hell 的问题的,异步接口更好的处理办法就是使用 Promise 接口。

let promisify = (fn, receiver) => {
  return (...args) => {
    return new Promise((resolve, reject) => {
      fn.apply(receiver, [...args, (err, res) => {
        return err ? reject(err) : resolve(res);
      }]);
    });
  };
};

var fs = require("fs");
var readFilePromise = promisify(fs.readFile, fs); // Encapsulate Promise interface

readFilePromise("foo.json", "utf8").then(function(content){
    // normal
}).catch(function(err){
    // abnormal
})

题外话,JavaScript 从 ES8 开始支持基于 Promise 的 Async/Await 语法糖, 实现类似 Golang 协程采用同步方式写异步代码。

Continue reading

最近听了 IoT 长连接 Erlang 研发同学的技术分享,部分分享内容涉及到到了 HTTP/2,刚好在草稿箱里翻到了两年前攒的这篇文章,趁这个机会补充一下把他放出来吧。

HTTP/2 不叫 HTTP/2.0,是因为标准委员会不打算再发布子版本了,下一个新版本将是 HTTP/3。

0x00 HTTP Frames

HTTP/1.1 版的头信息肯定是文本(ASCII编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为”帧”(frame):头信息帧和数据帧。

HTTP/2 相较于 HTTP/1.* 的不同点在于,HTTP/2 将 HTTP 协议通信分解为二进制编码Frame的交换,这些Frame对应着特定Stream中的Message。所有这些都在一个 TCP 连接内复用。这是 HTTP/2 协议所有其他功能和性能优化的基础。

二进制协议的一个好处是,可以定义额外的帧。HTTP/2 定义了近十种帧,为将来的高级应用打好了基础。如果使用文本实现这种功能,解析数据将会变得非常麻烦,二进制解析则方便得多。

Frame 的基础结构由五部分组成:

  • Length: 表示 Frame Payload 的大小,是一个 24-bit 的整型,表明 Frame Payload 的大小不应该超过 2^24 – 1 byte,但其实 payload 默认的大小是不超过 2^14 byte,可以通过 SETTING Frame 来设置 SETTINGS_MAX_FRAME_SIZE 修改允许的 Payload 大小;
  • Type: 表示 Frame 的类型,目前定义了 0-9 共 10 种类型;
  • Flags: 为一些特定类型的 Frame 预留的标志位,比如 Header, Data, Setting, Ping 等,都会用到;
  • R: 1-bit 的保留位,目前没用,值必须为 0;
  • Stream Identifier: Steam 的 id 标识,表明 id 的范围只能为 0 到 2^31 – 1 之间,其中 0 用来传输控制信息,比如 Setting, Ping;客户端发起的 Stream id 必须为奇数,服务端发起的 Stream id 必须为偶数;并且每次建立新 Stream 的时候,id 必须比上一次的建立的 Stream 的 id 大;当在一个连接里,如果无限建立 Stream,最后 id 大于 2^31 时,必须从新建立 TCP 连接,来发送请求。如果是服务端的 Stream id 超过上限,需要对客户端发送一个 GOWAY 的 Frame 来强制客户端重新发起连接。

Continue reading

昨晚快下班的时候,蓝色港湾那家影院的客服小哥给我打电话说我们预定的那个包场被取消了,心态有点炸。今早到公司重新规划了路线,终于把周五 Building 的全套行程都确定下来了,明天消费升级改道去国贸。

中午有小姐姐来找我说他们新员工培训抽到了‘持续创新’的主题,打算把我做 AI 沟通助手的过程拍成一部 VCR,于是我们很愉快的聊了下研发细节,话说上次涉足演艺圈事业已经是快一年前的事了,明少当时约了一票好友一起造了一晚上,记得那时候坐我左手边的姑娘气质特别好,唱霉霉的歌也特有感觉。


转眼间接口开放平台野蛮生长了很长一段时间了,一直没有一个很正式的测试环境,每次做新需求都是从 git 上把代码拉下来重新起套新环境,这里面存在很多坑,比如 Python3 版本升级之后 virtualenv 中的 mysql 依赖就装不上了

ModuleNotFoundError: No module named 'ConfigParser'

查阅相关文档之后发现在 Python3 版本升级后,ConfigParser.py 已经更名为 configparser.py 了,可以同前版本的处理办法一样,通过重命名解决问题,但是路子太野会给之后上量扩容满坑,所以得找找其他办法。

https://github.com/PyMySQL/PyMySQL

于是我找到了 mysql 的替代模块 PyMySQL,

pip3 install PyMySQL

如果还有报错,那么:

# Ubuntu
sudo apt-get install libmysqlclient-dev

# CentOS
sudo yum install python-dev mariadb-devel

PyMySQL 的玩儿法也更加优雅,特别对于多条数据的处理逻辑也更加线性易于理解。Continue reading