试用最新的 Docker for Mac Beta

如何申请 Docker for Mac Beta

请访问这个地址申请,可能需要等几天:https://beta.docker.com/

Docker for Mac Beta,最大的好处就是不再依赖 VirtualBox VM 了,而是使用了更轻量化的 xhyve 作为其虚拟化方案(也即是说,仍然不是原生的,还是需要虚拟化一个 Linux 出来在上面运行 Docker Daemon)。

另外,这个版本的 Docker for Mac 使用了 Alpine Linux 发行版,作为一个更轻量化的发行版,与一般的发行版有不少区别,比如,使用 ash 替换 bash 等,具体请访问 Alpine Linux 网站获取更多信息。

使用 Docker Hub Registry Mirror

由于众所周知的原因,在国内访问 Docker Hub 的速度相当缓慢,因此需要设置一个 Docker Registry Mirror 来加速,这里使用 USTC 的 Docker Hub Mirror

就如同之前所说,Alpine Linux 发行版与一般发行版有巨大区别,因此调整 Docker Daemon 的启动参数也不大一样😂

Quick Way

NOTE: 安装了 jq 命令行工具(可以通过 brew install jq 安装),可以直接执行一行命令行搞定,否则请参阅「Slow Way」一节:

1
pinata get daemon | jq -cM '."registry-mirrors" = ["https://docker.mirrors.ustc.edu.cn"]' | pinata set daemon -

Slow Way

1. 导出当前的设置

运行以下命令,将当前设置保存到 docker-config.json 文件中:

1
2
pinata get daemon > docker-config.json
## >> {"storage-driver":"aufs","debug":true}

2. 使用文本编辑器编辑设置

使用任何一种文本编辑器,打开 docker-config.json 并按照 JSON 格式编辑为以下内容,然后保存并退出:

1
{"storage-driver":"aufs","debug":true,"registry-mirrors":["https://docker.mirrors.ustc.edu.cn"]}

3. 加载最新设置

最后,加载 docker-config.json 中的设置就可以了:

1
pinata set daemon @docker-config.json

获取 Docker Guest 的 IP 地址

有时候,我们需要得到 Docker Guest 的 IP 地址,其实不大有比较快捷的方法,比如,先运行 pinata get network,居然返回这个??WTF?!

1
hostnet

然后只有运行 pinata list 了:

These are advanced configuration settings to customise Docker.app on MacOSX.
You can set them via pinata set <key> <value> <options>.

🐳  hostname = docker
   Hostname of the virtual machine endpoint, where container ports will be
   exposed if using nat networking. Access it via 'docker.local'.

🐳  hypervisor = native (memory=2, ncpu=2)
   The Docker.app includes embedded hypervisors that run the virtual machines
   that power the containers. This setting allows you to control which the
   default one used for Linux is.

 ▸  native: a version of the xhyve hypervisor that uses the MacOSX
              Hypervisor.framework to run container VMs. Parameters:
              memory (VM memory in gigabytes), ncpu (vCPUs)


🐳  network = hostnet (docker-ipv4=192.168.65.2, host-ipv4=192.168.65.1)
   Controls how local containers can access the external network via the
   MacOS X host. This includes outbound traffic as well as publishing ports
   for external access to the local containers.

 ▸ hostnet: a mode that helps if you are using a VPN that restricts
              connectivity. Activating this mode will proxy container network
              packets via the Docker.app process as host socket traffic.
              Parameters: docker-ipv4 (docker node), host-ipv4 (host node)
 ▸     nat: a mode that uses the MacOS X vmnet.framework to route container
              traffic to the host network via a NAT.

🐳  filesystem = osxfs
   Controls the mode by which files from the MacOS X host and the container
   filesystem are shared with each other.

 ▸   osxfs: a FUSE-based filesystem that bidirectionally forwards OSX
              filesystem events into the container.


🐳  native/port-forwarding = true
   Expose container ports on the Mac, rather than the VM

 ▸    true: Container ports will be exposed on the Mac
 ▸   false: Container ports will be exposed on the VM

🐳  daemon = run 'pinata get daemon' or 'pinata set daemon [@file|-]>
   JSON configuration of the local Docker daemon. Configure any custom
   options you need as documented in:
   https://docs.docker.com/engine/reference/commandline/daemon/. Set it
   directly, or a @file or - for stdin.

因此看起来使用 pinata list | grep 'network =' 才是合理的方式之一:

*  network = hostnet (docker-ipv4=192.168.65.2, host-ipv4=192.168.65.1)

以上

在 Python 中统计文本字符个数

字符集向来都是一个大问题,即使是 Python 3.x,也最多只是能说感谢 Unicode 字符集,字符串的存取现在没有问题了。

Unicode 字符集的常见编码UTF-8UTF-16UTF-32 等常见格式,另外,GB18030 也可以算其中一种( GB18030,与 UTF-8 类似,是一种变长编码格式,最大的优势就是兼容 GBK/GB2312

但是 Unicode 就能无痛的解决所有问题吗?答案是否定的。

Read More

Golang 内存模型(一)

开始之前

首先,这是一篇菜B写的文章,可能会有理解错误的地方,发现错误请斧正,谢谢。

为了治疗我的懒癌早期,我一次就不写得太多了,这个系列想写很久了,每次都是开了个头就没有再写。这次争取把写完,弄成一个系列。

此 nil 不等彼 nil

先声明,这个标题有标题党的嫌疑。

Go 的类型系统是比较奇葩的,nil 的含义跟其它语言有些差别,这里举个例子(可以直接进入 http://play.golang.org/p/ezFhXX0dnB 运行查看结果):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import "fmt"

type A struct {
}

func main() {
var a *A = nil
var ai interface{} = a
var ei interface{} = nil

fmt.Printf("ai == nil: %v\n", ai == nil)
fmt.Printf("ai == ei: %v\n", ai == ei)
fmt.Printf("ei == a: %v\n", a == ei)
fmt.Printf("ei == nil: %v\n", ei == nil)
}

// -> 输出
// ai == nil: false
// ai == ei: false
// ei == a: false
// ei == nil: true

这里 ai != nil,对于没有用过 Go 的人来说比较费解,对我来说,这个算得上一门语言设计有歧义的地方(Golang FAQ 有对于此问题的描述,可以参考一下:http://golang.org/doc/faq#nil_error)。

简单的说就是 nil 代表 “zero value”(空值),对于不同类型,它具体所代表的值不同。比如上面的 a 为“*A 类型的空值”,而 ai 为“interface{} 类型的空值”。造成理解失误的最大问题在于,struct pointerinterface 有隐式转换(var ai interface{] = a,这里有个隐式转换),至于为什么对于 Go 这种在其它转换方面要求严格,而对于 interface 要除外呢,for convenience 吧,呵呵……

碰到了这个坑,我就开始好奇了,Go 的类型系统到底是什么样的?

Read More

在 Go 中获取 stacktrace

打印 stacktrace
1
2
3
4
5
6
buf := make([]byte, 1<<16)
// 获取 **所有** goroutine 的 stacktrace
runtime.Stack(buf, true)
// 如果需要获取 **当前** goroutine 的 stacktrace, 第二个参数需要为 `false`
runtime.Stack(buf, true)
fmt.Println(string(buf))

太诡异了,居然要指定 buffer 的大小,用起来不方便。虽然可以给个“足够大” buffer 用来容纳 stacktrace,但是什么是“足够大”?

为了确认 runtime.Stack() 函数的 behavior,需要参考一下 Go 输出 stacktrace 的实现代码。该代码是使用 GOC 写成的。

A .goc file is a combination of a limited form of Go with C.

mprof.goclink
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
func Stack(b Slice, all bool) (n int) {
uintptr pc, sp;

// Stack pointer
sp = runtime·getcallersp(&b);
// Programer pointer
pc = (uintptr)runtime·getcallerpc(&b);

// 如果选择输出所有 goroutine 的 traceback, 挂起所有goroutine,
// 在本函数完成后恢复
if(all) {
runtime·semacquire(&runtime·worldsema, false);
m->gcing = 1;
runtime·stoptheworld();
}

if(b.len == 0)
n = 0;
else{
// 重定向输出缓冲, 打印到 `b` 这个buffer里
g->writebuf = (byte*)b.array;
// buffer具有固定大小, 因此会截断
g->writenbuf = b.len;
// proc.c: runtime·goroutineheader
runtime·goroutineheader(g);
// traceback_${arch}.c
runtime·traceback(pc, sp, 0, g);
if(all)
runtime·tracebackothers(g);
n = b.len - g->writenbuf;
g->writebuf = nil;
g->writenbuf = 0;
}

if(all) {
m->gcing = 0;
runtime·semrelease(&runtime·worldsema);
runtime·starttheworld();
}
}

因为打印到buffer会截断过长的结果,因此可以写一个包装函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func StackTrace(all bool) string {
// Reserve 10K buffer at first
buf := make([]byte, 10240)

for {
size := runtime.Stack(buf, all)
// The size of the buffer may be not enough to hold the stacktrace,
// so double the buffer size
if size == len(buf) {
buf = make([]byte, len(buf)<<1)
continue
}
break
}

return string(buf)
}

例子可以在这里看到:Go Playground

使用阿里云镜像服务器

最近本机访问 163.comCentOS 镜像比较不稳定,体现在 ping 很低,但是 HTTP 连接很慢,yumfastestmirror 也不太理想,所以一般都禁用之。

发现阿里云的镜像服务器,立马换了,便秘立刻就通了。

yum 镜像

官方源镜像

1
2
3
4
5
6
# 禁用 fastestmirror 插件
sed -i.backup 's/^enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf
# 备份
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
# 使用阿里云镜像
wget -O /etc/yum.repos.d/CentOS-Base-aliyun.repo http://mirrors.aliyun.com/repo/Centos-6.repo

EPEL 镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 安装 EPEL 源
wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
wget http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
rpm -Uvh remi-release-6*.rpm epel-release-6*.rpm
# 使用阿里云镜像
if [[ ! -f /etc/yum.repos.d/epel.repo.backup ]]; then
mv /etc/yum.repos.d/epel.repo /etc/yum.repos.d/epel.repo.backup 2>/dev/null || :
fi

if [[ ! -f /etc/yum.repos.d/epel-testing.repo.backup ]]; then
mv /etc/yum.repos.d/epel-testing.repo /etc/yum.repos.d/epel-testing.repo.backup 2>/dev/null || :
fi

wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo

PyPi 镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mkdir -p ~/.pip
touch ~/.pip/pip.conf

sed -i.backup -r \
's/^index-url\s*=\s*.+$/index-url = http:\/\/mirrors.aliyun.com\/pypi\/simple\//' \
~/.pip/pip.conf

# If file not changed, write contents back to pip.conf
diff "~/.pip/pip.conf" "~/.pip/pip.conf.backup" &> /dev/null

if [ $? -eq 0 ]; then
cat > ~/.pip/pip.conf <<EOF
[global]
index-url = http://mirrors.aliyun.com/pypi/simple/
EOF
fi

RubyGems 镜像

1
2
gem source -r https://rubygems.org/
gem source -a http://mirrors.aliyun.com/rubygems/