0%

gpg_usage.png
加密的一个简单但又实用的任务就是发送加密电子邮件。多年来,为电子邮件进行加密的标准一直是PGP(Pretty Good Privacy)。程序员Phil Zimmermann特别为电子邮件的保密编写的PGP。这个软件非常好用,迅速流传开来,成了许多程序员的必备工具。但是,它是商业软件,不能自由使用。作为PGP的替代,如今已经有一个开放源代码的类似产品可供使用。GPG(Gnu Privacy Guard),它不包含专利算法,能够无限制的用于商业应用。

环境

  • RHEL7.2
    默认以安装GPG
  • GPG 2.0.22
    libgcrypt 1.5.3

使用方法

生成密钥

使用--gen-key生成一副新的密钥对

1
2
3
4
5
6
7
8
9
10
11
$ gpg --gen-key
gpg (GnuPG) 2.0.22; Copyright (C) 2013 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

请选择您要使用的密钥种类:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (仅用于签名)
(4) RSA (仅用于签名)
您的选择?

第一段是版权声明,然后让用户自己选择加密算法。默认选择第一个选项,表示加密和签名都使用RSA算法。

1
2
RSA 密钥长度应在 1024 位与 4096 位之间。
您想要用多大的密钥尺寸?(2048)

这一步要让我们输入密钥长度,长度越长越安全,默认为2048。

1
2
3
4
5
6
7
8
您所要求的密钥尺寸是 2048 位              
请设定这把密钥的有效期限。
0 = 密钥永不过期
<n> = 密钥在 n 天后过期
<n>w = 密钥在 n 周后过期
<n>m = 密钥在 n 月后过期
<n>y = 密钥在 n 年后过期
密钥的有效期限是?(0)

如果密钥只是个人使用,并且你很确定可以有效保管私钥,建议选择第一个选项,即永不过期。注意,如果想设置在2年后过期,那么应该输入2y,然后回车 回答完上面三个问题以后,系统让你确认。

1
2
密钥于 日 10/ 8 11:20:32 2017 CST 过期
以上正确吗?(y/n)

到这里,我们对要生成的密钥的配置已经完成了,然后我们还需要一个标识,接下来按照要求依次输入就行了

1
2
3
4
5
6
7
8
9
10
11
12
You need a user ID to identify your key; the software constructs the user ID
from the Real Name, Comment and Email Address in this form:
"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"

真实姓名:Zhang San
电子邮件地址:zhangsan@x163.com
注释:

您选定了这个用户标识:
“Zhang San <zhangsan@163.com>”

更改姓名(N)、注释(C)、电子邮件地址(E)或确定(O)/退出(Q)?

输入o确定,然后在弹出的窗口输入密码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
我们需要生成大量的随机字节。这个时候您可以多做些琐事(像是敲打键盘、移动
鼠标、读写硬盘之类的),这会让随机数字发生器有更好的机会获得足够的熵数。
.+++++
...+++++
我们需要生成大量的随机字节。这个时候您可以多做些琐事(像是敲打键盘、移动
鼠标、读写硬盘之类的),这会让随机数字发生器有更好的机会获得足够的熵数。
....................+++++
...........+++++
gpg: /home/XXXX/.gnupg/trustdb.gpg:建立了信任度数据库
gpg: 密钥 74A64469 被标记为绝对信任
公钥和私钥已经生成并经签名。

gpg: 正在检查信任度数据库
gpg: 需要 3 份勉强信任和 1 份完全信任,PGP 信任模型
gpg: 深度:0 有效性: 1 已签名: 0 信任度:0-,0q,0n,0m,0f,1u
gpg: 下次信任度数据库检查将于 2017-10-08 进行
pub 2048R/74A64469 2016-10-08 [有效至:2017-10-08]
密钥指纹 = 2187 78CA 2E78 83C2 039C E47B D94A 622A 74A6 5569
uid Zhang San <zhangsan@163.com>
sub 2048R/490E5BC8 2016-10-08 [有效至:2017-10-08]

请注意上面的字符串”74A64469”,这是”用户ID”的Hash字符串,可以用来替代”用户ID”。到此为止,我们已经完成了生成公钥和私钥的任务了,文件在/home/XXXX/.gnupg/pubring.gpg

这时,最好再生成一张”撤销证书”,以备以后密钥作废时,可以请求外部的公钥服务器撤销你的公钥。使用--gen-revoke 74A64469进行,此处不再赘述。

查看密钥列表

使用--list-keys列出当前用户已有的密钥

1
2
3
4
5
6
$ gpg --list-keys
/home/zhoub/.gnupg/pubring.gpg
------------------------------
pub 2048R/6058BC49 2017-05-16
uid zhou bo (for coreos build) <zhoubofsy@hotmail.com>
sub 2048R/A47EF901 2017-05-16

第一行显示公钥文件名(pubring.gpg),第二行显示公钥特征(2048位,RSA,Hash字符串和生成时间),第三行显示”用户ID”,第四行显示私钥特征(格式与公钥相同)。
如果你要从密钥列表中删除某个密钥,可以使用delete-key参数gpg --delete-key [用户ID]

输出密钥

** 公钥导出 **
公钥文件(.gnupg/pubring.gpg)以二进制形式储存,armor参数可以将其转换为ASCII码显示。gpg --armor --output public-key.txt --export [用户ID]

** 私钥导出 **
export-secret-keys参数可以转换私钥

1
gpg --armor --output private-key.txt --export-secret-keys

上传公钥

公钥服务器是网络上专门储存用户公钥的服务器。send-keys参数可以将公钥上传到服务器gpg --send-keys [用户ID] --keyserver hkp://subkeys.pgp.net使用上面的命令,你的公钥就被传到了服务器subkeys.pgp.net,然后通过交换机制,所有的公钥服务器最终都会包含你的公钥。

由于公钥服务器没有检查机制,任何人都可以用你的名义上传公钥,所以没有办法保证服务器上的公钥的可靠性。通常,你可以在网站上公布一个公钥指纹,让其他人核对下载到的公钥是否为真。fingerprint参数生成公钥指纹。gpg --fingerprint [用户ID]

输入密钥

除了生成自己的密钥,还需要将他人的公钥或者你的其他密钥输入系统。这时可以使用import参数gpg --import [密钥文件]

为了获得他人的公钥,可以让对方直接发给你,或者到公钥服务器上寻找gpg --keyserver hkp://subkeys.pgp.net --search-keys [用户ID]
或者

1
2
3
4
5
6
$ gpg --recv-keys E82E4209
gpg: 下载密钥‘E82E4209’,从 hkp 服务器 keys.gnupg.net
gpg: 密钥 E82E4209:公钥“Vladimir 'phcoder' Serbinenko <phcoder@gmail.com>”已导入
gpg: 没有找到任何绝对信任的密钥
gpg: 合计被处理的数量:1
gpg: 已导入:1

加密和解密

使用--encrypt参数用于加密。假设有一个原始文件test.txt

** 使用公钥(Hash字符串)加密:**

1
$ gpg --recipient 74A64469 --output test_en.txt --encrypt test.txt
  • --recipient参数指定接收者的公钥
  • --output参数指定加密后的文件名
  • --encrypt参数指定源文件

** 使用私钥解密:**

1
2
3
4
5
6
7
8
9
10
11
$ gpg test_en.txt

bogon:Desktop XXXX$ gpg test_en.txt

您需要输入密码,才能解开这个用户的私钥:“Zhang San <zhangsan@163.com>”
2048 位的 RSA 密钥,钥匙号 490E5BC8,建立于 2016-10-08 (主钥匙号 74A64469)

gpg: 由 2048 位的 RSA 密钥加密,钥匙号为 490E5BC8、生成于 2016-10-08
“Zhang San <zhangsan@163.com>”
gpg: test_en.txt:未知的后缀名
请输入新的文件名 [test.txt]: test2.txt

签名

有时,我们不需要加密文件,只需要对文件签名,表示这个文件确实是我本人发出的。--sign参数用来签名

1
$ gpg --sign test.txt

然后生成了一个test.txt.gpg文件,我们打开这个文件后,发现这也是一个二进制的数据,这并不是加密后的数据,与上边的二进制数据不一样。
如果想生成ASCII码的签名文件,可以使用--clearsign参数

1
$ gpg --clearsign test.txt

然后生成了一个test.txt.asc文件。
如果想生成单独的签名文件,与文件内容分开存放,可以使用--detach-sign参数

1
$ gpg --detach-sign test.txt

多产生一个,sig的二进制签名文件,如果想采用ASCII码形式,要加上--armor参数。

签名+加密

如果想同时签名和加密,可使用这种格式gpg --local-user [发信者ID] --recipient [接收者ID] --armor --sign --encrypt test.txt

  • --local-user参数指定用发信者的私钥签名
  • --recipient参数指定用接收者的公钥加密
  • --armor参数表示采用ASCII码形式显示
  • --sign参数表示需要签名
  • --encrypt参数表示指定源文件

验证签名

收到别人签名后的文件,需要用对方的公钥验证签名是否为真。使用--verify参数用来验证

1
2
3
4
5
6
gpg --verify test.txt.sig test.txt
gpg: Signature made Wed 17 May 2017 04:12:50 PM CST using RSA key ID 74A64469
gpg: Good signature from "Zhang San <zhangsan@163.com>"
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 0B77 E327 B365 316D F112 4521 ABC0 9164 6058 BC49

参考&鸣谢

coreos_build.jpg

介绍

CoreOS,一个轻量的linux分布式操作系统。CoreOS中的应用都以容器形式在系统中运行。个人觉得CoreOS不能算是一个linux发行版,只能算是一种订制系统。(BTW,CoreOS的订制应该是源自Gentoo这个发行版)

环境

  • CoreOS的编译与操作系统无关(此处使用的是RHEL7.2),硬件要求必须是X86-64系统。
  • 编译系统必须安装 curl、git、python2、bzip2
  • CoreOS SDK编译有两种方法(Option1 & Option2),Option1 需要选择和需要编译的CoreOS相匹配的golang版本。
  • 使用Option2 方法安装,需要设置https_proxy代理(否则,无法法访问GoogleSource)

制作&安装

本人使用Option2方法完成CoreOS编译,并使用coreos-install安装CoreOS到xen vm上。

制作

准备

安装Repo

下载repo,用于下载CoreOS SDK

1
2
curl http://storage.googleapis.com/git-repo-downloads/repo > ./repo
chmod a+x ./repo

下载SDK

创建一个目录用于存放coreos sdk

1
2
mkdir coreos
cd coreos

repo初始化目录,并同步git repos

1
2
repo init -u https://github.com/coreos/manifest.git
repo sync

Chroot到coreos SDK

1
./chromite/bin/cros_sdk

编译

设置core用户登陆密码

设置core用户密码,已被系统安装完后登陆系统使用。

1
./set_shared_user_password.sh

选择目标编译平台

选择amd64-usrarm64-usr

1
./setup_board --default --board=amd64-usr

编译Packages

1
./build_packages

制作CoreOS镜像

可以选择编译开发版(dev)还是生成版(prod)

1
./build_image prod

制作可以引导CoreOS镜像

1
./image_to_vm.sh --board=amd64-usr --format=xen --from=/mnt/host/source/src/build/images/amd64-usr/developer-1409.0.0+2017-05-15-1456-a1/coreos_production_image.bin --disk_layout=base
  • --format 根据不同需要选择制作不同格式的可引导镜像
  • --disk_layout 默认是空,建议选择base

安装

*** 经过上述步骤的操作,已经将coreos镜像制作完成,并放置在”./src/build/images/amd64-usr”目录下。 ***

安装的过程需要使用liveCD启动,然后挂在需要安装的裸盘,使用coreos-install安装。镜像的传递是,先将镜像放置到一个webserver上,然后coreos-install再通过这个webserver下载、并安装。

*** 在将镜像放置到webserver之前,需要先将镜像压缩成bz2文件,然后再将bz2进行签名 ***(签名无法使用官方的私钥,只能自己申请,详细请见)。

步骤

*** 本人的安装步骤,不是唯一的、方便、快捷的方法,更多安装方式建议阅者自行调研 ***

下载coreos-install安装脚本

1
wget https://raw.githubusercontent.com/coreos/init/master/bin/coreos-install

修改coreos-install中的公钥

在coreos-install中有个变量GPG_KEY用于存储官方的公钥,需要将这个公钥换成你给镜像签名时对应的公钥。

** 此处略去俺公钥内容 **

镜像在下载到目标机后,coreos-install会对下载的镜像进行校验,这是不替换公钥,只能想办法让官方帮你签名

使用coreos-install安装CoreOS

使用liveCD启动系统后,先确认需要安装CoreOS的硬盘,然后执行coreos-install进行安装

1
sudo ./coreos-install -d /dev/xvda -V 1409.0.0 -o xen -v -b http://192.168.1.82:8000 -c /media/configdrive/openstack/latest/user_data
  • -d 指定安装目标设备
  • -V 指定安装版本,一定要与URL中的路径能匹配上
  • -o 镜像名称中需要指出是xenorkvmor…
  • -b 镜像下载URL

问题&解决

不能引导问题

若成功编译安装,但不能正常引导,可以对比做bzip2之前镜像的前512字节和安装后xvda的前512字节是否一致。本人遇到不能引导问题,是因为本应使用bzip2压缩的镜像使用了tar

参考&鸣谢

  • 感谢同事为我提供的VPN翻墙服务
  • 感谢同事为我提供的WebService服务,方便完成网络安装CoreOS
  • container linux document

iptables是一个配置Linux内核防火墙的命令行工具,是netfilter项目的一部分。术语iptables也经常代指该内核级防火墙。iptables用于ipv4,ip6tables用于ipv6。
( nftables已经包含在Linux kernel 3.13中,以后会取代iptables成为主要的Linux防火墙工具。 )

版本

iptables v1.4.21

介绍

理解 iptables 如何工作的关键是下面这张图。图中在上面的小写字母代表”表”,在下面的大写字母代表”链”。从任何网络端口进来的每一个 IP 数据包都要从上到下的穿过这张图。一种常见的困扰是认为 iptables 对从内部端口进入的数据包和从面向互联网端口进入的数据包采取不同的处理方式,相反,iptabales 对从任何端口进入的数据包都会采取相同的处理方式。可以定义规则使 iptables 采取不同的方式对待从不同端口进入的数据包。当然一些数据包是用于本地进程的,因此在图中表现为从顶端进入,到Local Process停止,而另一些数据包是由本地进程生成的,因此在图中表现为从Local Process发出,一直向下穿过该流程图。

iptables_traverse.jpg

  1. 数据包到达网络接口,比如 eth0
  2. 进入 raw 表的 PREROUTING 链,这个链的作用是赶在连接跟踪之前处理数据包
  3. 如果进行了连接跟踪,在此处理
  4. 进入 mangle 表的 PREROUTING 链,在此可以修改数据包,比如 TOS 等
  5. 进入 nat 表的 PREROUTING 链,可以在此做DNAT,但不要做过滤
  6. 决定路由,看是交给本地主机还是转发给其它主机
    一种情况是,数据包就是发给本地主机的:
  7. 进入 mangle 表的 INPUT 链,这里是在路由之后,交由本地主机之前,我们也可以进行一些相应的修改
  8. 进入 filter 表的 INPUT 链,在这里我们可以对流入的所有数据包进行过滤,无论它来自哪个网络接口
  9. 交给本地主机的应用程序进行处理
  10. 处理完毕后进行路由决定,看该往那里发出
  11. 进入 raw 表的 OUTPUT 链,这里是在连接跟踪处理本地的数据包之前
  12. 连接跟踪对本地的数据包进行处理
  13. 进入 mangle 表的 OUTPUT 链,在这里我们可以修改数据包,但不要做过滤
  14. 进入 nat 表的 OUTPUT 链,可以对防火墙自己发出的数据做 NAT
  15. 再次进行路由决定
  16. 进入 filter 表的 OUTPUT 链,可以对本地出去的数据包进行过滤
  17. 进入 mangle 表的 POSTROUTING 链,到这里已经做完了所有的路由决定,但数据包仍然在本地主机,我们还可以进行某些修改
    注意,这里不光对经过防火墙的数据包进行处理,还对防火墙自己产生的数据包进行处理
  18. 进入 nat 表的 POSTROUTING 链,在这里一般都是用来做 SNAT ,不要在这里进行过滤
  19. 进入出去的网络接口
    一种情况是,数据包要转发给其它主机:
  20. 进入 mangle 表的 FORWARD 链,这里也比较特殊,这是在第一次路由决定之后,在进行最后的路由决定之前,我们仍然可以对数据包进行某些修改
  21. 进入 filter 表的 FORWARD 链,在这里我们可以对所有转发的数据包进行过滤。需要注意的是:经过这里的数据包是转发的,方向是双向的
  22. 进入 mangle 表的 POSTROUTING 链,到这里已经做完了所有的路由决定,但数据包仍然在本地主机,我们还可以进行某些修改
  23. 进入 nat 表的 POSTROUTING 链,在这里一般都是用来做 SNAT ,不要在这里进行过滤
  24. 进入出去的网络接口

该流程图描述链了在任何接口上收到的网络数据包是按照怎样的顺序穿过表的交通管制链。第一个路由策略包括决定数据包的目的地是本地主机(这种情况下,数据包穿过 INPUT 链),还是其他主机(数据包穿过 FORWARD 链);中间的路由策略包括决定给传出的数据包使用那个源地址、分配哪个接口;最后一个路由策略存在是因为先前的 mangle 与 nat 链可能会改变数据包的路由信息。数据包通过路径上的每一条链时,链中的每一条规则按顺序匹配;无论何时匹配了一条规则,相应的 target/jump 动作将会执行。最常用的3个 target 是 ACCEPT, DROP ,或者 jump 到用户自定义的链。内置的链有默认的策略,但是用户自定义的链没有默认的策略。在 jump 到的链中,若每一条规则都不能提供完全匹配,那么数据包像这张图片描述的一样返回到调用链。在任何时候,若 DROP target 的规则实现完全匹配,那么被匹配的数据包会被丢弃,不会进行进一步处理。如果一个数据包在链中被 ACCEPT,那么它也会被所有的父链 ACCEPT,并且不再遍历其他父链。然而,要注意的是,数据包还会以正常的方式继续遍历其他表中的其他链。

iptables_user_kernel_traverse.png

表(Tables)

  • raw 用于配置数据包,raw 中的数据包不会被系统跟踪。
    作用:决定数据包是否被状态跟踪机制处理,优先级最高,设置raw时一般是为了不再让iptables做数据包的链接跟踪处理,提高性能
    内核模块:iptable_raw
    chains:OUTPUT, PREROUTING
  • filter 是用于存放所有与防火墙相关操作的默认表。
    作用:过滤数据包
    内核模块:iptables_filter
    chains:INPUT, FORWARD, OUTPUT
  • nat 用于网络地址转换(例如:端口转发)。
    作用:网络地址转换
    内核模块:iptables_nat
    chains:PREROUTING, POSTROUTING, OUTPUT
  • mangle 用于对特定数据包的修改。
    作用:修改数据包的服务类型、TTL、并且可以配置路由实现QOS
    内核模块:iptable_mangle
    chains:PREROUTING, POSTROUTING, INPUT, OUTPUT, FORWARD
  • security 用于强制访问控制网络规则。
    Todo…

表之间的顺序:raw –> mangle –> nat –> filter

链(Chains)

  • 表由链组成,链是一些按顺序排列的规则的列表。
    默认的filter表包含INPUTOUTPUTFORWARD3条内建的链,这3条链作用于数据包过滤过程中的不同时间点,nat表包含PREROUTINGPOSTROUTINGOUTPUT链。
  • 默认情况下,任何链中都没有规则,可以向链中添加自己想用的规则
    链的默认规则通常设置为ACCEPT,如果想确保任何包都不能通过规则集,那么可以重置为DROP。默认的规则总是在一条链的最后生效,所以在默认规则生效前数据包需要通过所有存在的规则。
  • 用户可以加入自己定义的链,从而使规则集更有效并且易于修改。

规则(Rules)

数据包的过滤基于 规则。规则由一个目标(数据包包匹配所有条件后的动作)和很多匹配(导致该规则可以应用的数据包所满足的条件)指定。一个规则的典型匹配事项是数据包进入的端口(例如:eth0 或者 eth1)、数据包的类型(ICMP, TCP, 或者 UDP)和数据包的目的端口。

目标使用-j或者--jump选项指定。目标可以是用户定义的链(例如,如果条件匹配,跳转到之后的用户定义的链,继续处理)、一个内置的特定目标或者是一个目标扩展。内置目标是 ACCEPT, DROP, QUEUE 和 RETURN,目标扩展是 REJECT and LOG。如果目标是内置目标,数据包的命运会立刻被决定并且在当前表的数据包的处理过程会停止。如果目标是用户定义的链,并且数据包成功穿过第二条链,目标将移动到原始链中的下一个规则。目标扩展可以被终止(像内置目标一样)或者不终止(像用户定义链一样)。

策略(police)

Usage

iptables_usage_main.jpg

iptables_usage_param.jpg

示例

Todo…

参考&鸣谢

依托现有虚拟化资源引入docker容器机制

xen_container_plan.png

  • scheduler
    根据VM宿主机的负载或其他情况,决定容器运行在哪个VM上。
  • monitor
    监控VM宿主机和容器健康情况,当有容器或宿主机宕掉时,报告想过情况,其他模块根据monitor的报告做出相应的响应。
  • controller
    控制容器的启动停止、迁移、扩展等操作
  • docker engine
    ……
  • pipework
    管理容器网络,目前pipework支持手动配置容器ip,网关及路由;对DHCP支持存在问题;(考虑将pipework以plugin方式加入docker engine)
  • xe-daemon
    采集容器监控数据,并通过xenbus将数据发给xenserver

方案

网络

xen_container_network_plan.png

  • 宿主机有两个网络,一个管理网,一个数据网,宿主机内的所有容器使用数据网络
  • 利用linux自带的bridge将宿主机的数据网与容器的veth pair相连,由此二层网络联通
  • 宿主机开通ip_forward,实现三层转发
  • 容器通过pipework脚本完成ip地址、路由、网关的配置

网络操作流程

  1. 根据网段创建bridge
    使用docker network create --gateway {宿主机IP} --subnet {宿主机子网} -d bridge -o com.docker.network.bridge.name="{网桥设备名称}" {DockerNetwork名称}创建bridge。
    eg:
    1
    2
    3
    4
    5
    $ docker network create --gateway 10.37.129.4 --subnet 10.37.129.0/24 -d bridge -o com.docker.network.bridge.name="xennet0" xennet
    $ brctl show
    bridge name bridge id STP enabled interfaces
    docker0 8000.0242df249633 no
    xennet0 8000.0242688f16c2 no
  2. 桥接出口网卡
    使用brctl addif {bridge名称} {网卡名称}将出口网卡添加到指定网桥中,此处应根据xscontainer使用用户的权限决定是否需要增加sudo操作
    eg:
    1
    2
    3
    4
    5
    $ sudo brctl addif xennet0 enp0s6
    $ brctl show
    bridge name bridge id STP enabled interfaces
    docker0 8000.0242df249633 no
    xennet0 8000.0242688f16c2 no enp0s6
  3. 创建固定IP容器
    创建容器需要分配固定IP,该IP需要业务层分配,并与bridge同网段。
    eg:
    1
    2
    3
    4
    5
    6
    7
    8
    $ docker run -d --name c1 --network xennet --ip 10.37.129.100 centos:7.3.1611 /usr/sbin/init
    $ docker run -d --name c2 --network xennet --ip 10.37.129.200 centos:7.3.1611 /usr/sbin/init
    $ brctl show
    bridge name bridge id STP enabled interfaces
    docker0 8000.0242df249633 no
    xennet0 8000.0242688f16c2 no enp0s6
    veth990ee82
    vethf1f6fcb

宿主机重启流程

*** 由于宿主机重启会导致bridge中记录的桥接出口网卡信息丢失,所以在宿主机重启后需要重新桥接出口网卡 ***

  1. 桥接出口网卡
    同上
  2. 恢复原有容器
    使用docker run or docker start恢复容器

共享存储

通过虚拟机挂载共享存储

  • 需要记录虚机挂载共享存储与容器的对应关系
  • 在创建、迁移、删除容器时,需要对相关存储资源进行分配或回收

容器直接挂载共享存储

  • 一般容器
    使用RBD/NBD-RBD块设备存储,或NFS存储。对于RBD/NBD-RBD方式需要添加驱动;对于NFS方式docker原生支持。
  • Registry容
    使用RGW对象存储(S3/Swift),测试中。。。

监控

XenContainer

调度

接口

服务发现(DNS)、负载均衡、容器镜像库均已容器形式提供服务。

xen_container_flow.png

  • scheduler、monitor、controller 从头写吧
  • docker engine 需要修改一些api接口
  • pipework 需要从shell改成golang,以plugin方式加入docker engine
  • xe-daemon 需要增加ip地址采集
  • DNS Container 从头写吧

*** 技术相关调研,请见下节“参” ***

PIPEWORK 是一个简单易用的Docker容器网络配置工具,由Docker的工程师Jérôme Petazzoni开发。通过使用ip、brctl、ovs-vsctl等命令来为Docker容器配置自定义的网桥、网卡、路由等。

docker-network-pipework-frame.png

  • 使用新建的br0网桥替代默认的docker0网桥
  • 容器网络类型选择none

配置步骤

  1. 在Github上获取pipework
    Todo
  2. 创建网桥
    1
    $ sudo brctl addbr br0
  3. 连接宿主机网卡
    1
    $ sudo brctl addif eth1
  4. 设置网桥ip,并激活网桥
    1
    2
    $ sudo ip addr add 192.168.6.66/24 dev br0
    $ sudo ip link set dev br0 up
  5. 创建容器,网络类型指定为none
    1
    $ docker run -it --rm --net none --name nonenet_1 192.168.6.109:5000/my_ubuntu:v1 /bin/bash
  6. 使用PIPEWORK创建容器网络
    1
    2
    3
    4
    5
    $ sudo ./pipework br0 nonenet_1 192.168.6.67/24@192.168.6.1
    $ brctl show
    bridge name bridge id STP enabled interfaces
    br0 8000.8ef4503cf344 no eth1
    veth1pl7289

鸣谢&参考

什么是服务发现

容器可以对其它容器提供服务,如mysql(数据库服务)、nginx、mangodb等等。这些服务都可以通过IP+Port方式访问。由于容器会经常重建迁移,所以IP会发生变化,如果调用服务的程序使用IP访问就会很不方便,为此可以使用DNS、zookeeper、etcd等技术实现服务访问与IP的解耦。这种解耦方式叫做服务发现。

版本

  • Kubernetes v1.4.0
  • kube-dns 1.9(image tag)

Kubernetes服务发现概述

k8s-service-discovery.png

  • Kube-dns 以容器的形式为K8s集群提供DNS服务
  • Etcd用于存储K8s中的服务、容器等信息,Kube-dns的数据也是从Etcd中获取的
  • healthz 监控DNS Pod中的Kube-dns、dnsmasq容器
  • dnsmasq以代理形式将外部访问转发给Kube-dns容器,走10053端口

Kube-dns

k8s-kube-dns-analysis.png

  • miekg监听10053端口,接收dnsmasq转发过来的DNS请求
  • KubeDNS中的Cache模块从Etcd中获取Service和Namespace信息,用户完成Service域名到Service地址的映射
  • SkyDNS Server 完成DNS协议交互逻辑
    该模块在KubeDNS启动时将自身注册到miekg中;并实现接口ServeDNS,当miekg收到DNS请求后,将调用该接口进行处理。
  • KubeDNS中模块实现了backend接口
    在ServeDNS处理DNS请求时,需要调用backend接口的Records和ReverseRecord method,backend接口会比对Cache中的内容,然后返回结果。

参考&鸣谢

k8s 1.2版本开始提供Ingress来实现对外暴露服务;目前k8s有三种暴露方式

  • LoadBlancer Service
  • NodePort Service
  • Ingress

K8s-LBS

LBS是k8s与云平台深度结合的一个组件,当使用LBS暴露服务时,实际上是通过底层云平台申请创建一个负载均衡器来向外暴露服务。目前LBS支持的云平台有GCE、DigitalOcean、Aliyun、私有云Openstack等等,由于LBS与云平台深度结合,所以只能在这些平台上使用。

NodePort

k8s_nodeport

k8s的端口分为:

  • Port
    service上暴露出来的端口,提供给集群(集群指整个容器集群)内部客户访问的端口。
  • NodePort
    node上暴露的端口,提供给集群外部客户访问的端口。
  • TargetPort
    endpoint上暴露的端口,也可以当作Pod上暴露的端口,无论从Port或NodePort上来的数据最终都会经过kube-proxy转发到Pod的TargetPort端口上。

k8s的IP分为:

  • ClusterIP
    service上虚拟ip地址,它由kube-proxy使用iptables规则重新定向到本地端口,再均衡到后端的Pod上。
  • NodeIP
    node节点的物理ip地址,它被kube-proxy使用iptables规则重定向到本地端口。
  • ContainerIP/PodIP
    K8s中以Pod为最小部署单位,一个Pod中共享一个网络资源(无论Pod中有几个容器)。每个Pod启动时,会自动创建一个镜像为gcr.io/google_containers/pause:0.8.0的容器,容器内部与外部的通信经由此容器代理,所以ContainerIP就是PodIP。

暴露方法及API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Service
metadata:
name: svc-1
labels:
name: svc-1
spec:
type: NodePort
ports:
- port: 2222
targetPort: 22
nodePort: 30022
selector:
name: rc-test

API操作

实现原理

ip地址及端口的暴露都是通过修改iptables规则来实现的。

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# iptables -t nat -L -n
...
Chain KUBE-NODEPORTS (1 references)
target prot opt source destination
KUBE-MARK-MASQ tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-lonely: */ tcp dpt:30023
KUBE-SVC-E6FDK4HG4F4JSB77 tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-lonely: */ tcp dpt:30023
KUBE-MARK-MASQ tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-tmp: */ tcp dpt:30099
KUBE-SVC-OOWDNB3NCXKPBPZE tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-tmp: */ tcp dpt:30099
KUBE-MARK-MASQ tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-1: */ tcp dpt:30022
KUBE-SVC-D25WXD2YSOVKEUTU tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-1: */ tcp dpt:30022
...
Chain KUBE-SEP-2LNK4QUGPB2C5PDO (2 references)
target prot opt source destination
KUBE-MARK-MASQ all -- 192.168.6.110 0.0.0.0/0 /* default/kubernetes:https */
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/kubernetes:https */ recent: SET name: KUBE-SEP-2LNK4QUGPB2C5PDO side: source mask: 255.255.255.255 tcp to:192.168.6.110:6443

Chain KUBE-SEP-5GTCHBFJM5RAI7LS (1 references)
target prot opt source destination
KUBE-MARK-MASQ all -- 10.254.86.9 0.0.0.0/0 /* default/svc-lonely: */
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-lonely: */ tcp to:10.254.86.9:22

Chain KUBE-SEP-BCYRFQ26LZTOSSU7 (1 references)
target prot opt source destination
KUBE-MARK-MASQ all -- 10.254.86.4 0.0.0.0/0 /* default/svc-1: */
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-1: */ tcp to:10.254.86.4:22

Chain KUBE-SEP-CLKUH4WMQ3CNBJ7K (1 references)
target prot opt source destination
KUBE-MARK-MASQ all -- 10.254.86.2 0.0.0.0/0 /* default/svc-1: */
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-1: */ tcp to:10.254.86.2:22

Chain KUBE-SEP-D3FORTYMXA7BVSDA (1 references)
target prot opt source destination
KUBE-MARK-MASQ all -- 10.254.86.8 0.0.0.0/0 /* default/svc-1: */
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-1: */ tcp to:10.254.86.8:22

Chain KUBE-SEP-F4EJGNTAH3JOOQC6 (1 references)
target prot opt source destination
KUBE-MARK-MASQ all -- 10.254.86.3 0.0.0.0/0 /* default/svc-1: */
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-1: */ tcp to:10.254.86.3:22

Chain KUBE-SEP-HO23WAVQKIB2R4KD (1 references)
target prot opt source destination
KUBE-MARK-MASQ all -- 10.254.86.10 0.0.0.0/0 /* default/svc-tmp: */
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-tmp: */ tcp to:10.254.86.10:99

Chain KUBE-SERVICES (2 references)
target prot opt source destination
KUBE-SVC-E6FDK4HG4F4JSB77 tcp -- 0.0.0.0/0 10.254.162.24 /* default/svc-lonely: cluster IP */ tcp dpt:2223
KUBE-SVC-OOWDNB3NCXKPBPZE tcp -- 0.0.0.0/0 10.254.119.86 /* default/svc-tmp: cluster IP */ tcp dpt:9999
KUBE-SVC-NPX46M4PTMTKRN6Y tcp -- 0.0.0.0/0 10.254.0.1 /* default/kubernetes:https cluster IP */ tcp dpt:443
KUBE-SVC-D25WXD2YSOVKEUTU tcp -- 0.0.0.0/0 10.254.159.12 /* default/svc-1: cluster IP */ tcp dpt:2222
KUBE-NODEPORTS all -- 0.0.0.0/0 0.0.0.0/0 /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL

Chain KUBE-SVC-D25WXD2YSOVKEUTU (2 references)
target prot opt source destination
KUBE-SEP-CLKUH4WMQ3CNBJ7K all -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-1: */ statistic mode random probability 0.25000000000
KUBE-SEP-F4EJGNTAH3JOOQC6 all -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-1: */ statistic mode random probability 0.33332999982
KUBE-SEP-BCYRFQ26LZTOSSU7 all -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-1: */ statistic mode random probability 0.50000000000
KUBE-SEP-D3FORTYMXA7BVSDA all -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-1: */

Chain KUBE-SVC-E6FDK4HG4F4JSB77 (2 references)
target prot opt source destination
KUBE-SEP-5GTCHBFJM5RAI7LS all -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-lonely: */

Chain KUBE-SVC-NPX46M4PTMTKRN6Y (1 references)
target prot opt source destination
KUBE-SEP-2LNK4QUGPB2C5PDO all -- 0.0.0.0/0 0.0.0.0/0 /* default/kubernetes:https */ recent: CHECK seconds: 180 reap name: KUBE-SEP-2LNK4QUGPB2C5PDO side: source mask: 255.255.255.255
KUBE-SEP-2LNK4QUGPB2C5PDO all -- 0.0.0.0/0 0.0.0.0/0 /* default/kubernetes:https */

Chain KUBE-SVC-OOWDNB3NCXKPBPZE (2 references)
target prot opt source destination
KUBE-SEP-HO23WAVQKIB2R4KD all -- 0.0.0.0/0 0.0.0.0/0 /* default/svc-tmp: */

Ingress

Todo…

参考&鸣谢

Docker网络技术,用来保证Container之间正常通讯的技术,作为Docker自身提供的网络分为4种,Bridge、Host、None、Container。本文重点介绍** Bridge **

环境

  • Docker 版本
    Docker version 1.12.5, build 7392c3b
  • OS 版本
    Red Hat Enterprise Linux Server release 7.2 (Maipo)
  • kernel 版本
    Linux 3.10.0-327.el7.x86_64

Bridge介绍

longlong ago :-)

docker-network-bridge-br0

早期的二层网络中,bridge可以连接不同的LAN网,当host1 发出一个数据包时,LAN1的其他主机和网桥br0都会收到该数据包。网桥再将数据包从入口端广播到其他端口上(我的理解是,多端口网桥叫交换机)。因此,LAN2上的主机也会接收到host1发出的数据包,从而实现不同LAN网上所有主机的通信。

docker-network-bridge-linux

后来linux kernel借鉴桥设备的原理实现了虚拟bridge,用到了veth pair技术,实现了不同子网通讯的二层基础。

Docker Bridge

(正题)Docker Bridge不同于linux bridge也不同于桥设备,但Docker Bridge的构建基于linux bridgeNetwork Namespaceiptables

  • Network Namespace
    实现了子网之间的隔离
  • iptables
    解决了NAT映射问题,使容器有(被)访问外网的能力。
  • linux bridge
    实现了Host内跨子网通讯

docker-network-bridge-main

在桥接模式下,Docker Daemon将veth0附加到docker0网桥上,保证宿主机的报文有能力发往veth0。再将veth1添加到Docker容器所属的网络命名空间,保证宿主机的网络报文若发往veth0可以立即被veth1收到。容器如果需要联网,则需要采用NAT方式。准确的说,是NATP(网络地址端口转换)方式。NATP包含两种转换方式:SNAT和DNAT。

下行访问流程

docker-network-bridge-downflow
由于容器的IP与端口对外都是不可见的,所以数据包的目的地址为宿主机的ip和端口,为192.168.1.10:24。
数据包经过路由器发给宿主机eth0,再经eth0转发给docker0网桥。
由于存在DNAT(Destination NAT,修改数据包的目的地址)规则,会将数据包的目的地址转换为容器的ip和端口,为172.17.0.n:24。宿主机上的docker0网桥识别到容器ip和端口,于是将数据包发送附加到docker0网桥上的veth0接口,veth0接口再将数据包发送给容器内部的veth1接口,容器接收数据包并作出响应。
docker-network-bridge-downflow-detail

上行访问流程

看了上面的下行访问流程用到了DNAT,那么上行访问一定会使用SNAT了吧。可实时却并非如此。
容器内的请求可以正常发送到host外,是因为host开启的ip_forward。如果host关闭转发功能echo 0 > /proc/sys/net/ipv4/ip_forward,容器能的请求只能发送到于自己相同网段的节点容器内,不同网段及跨主机的网段是不通的。
docker-network-bridge-upflow-detail

Docker bridge中关键技术

Docker bridge充分利用了linux bridge和iptabels、namespace等技术。将其中需要很多命令做成自动化脚本以方便执行维护。如:pipework是一个shell脚本,用于完成bridge网络管理。

veth pair

veth pair是一对虚拟网卡,从一张veth网卡发出的数据包可以直接到达它的peer veth,两者之间存在着虚拟链路。veth网卡和常规的以太网区别仅在于xmit接口:将数据发送到其peer,触发peer的Rx 过程。
docker-network-bridge-vethpair
veth pair是用于不同network namespace间进行通信的方式,veth pair将一个network namespace数据发往另一个network namespace的veth。如果多个network namespace需要进行通信,则需要借助bridge。

*** 属于iproute2工具包中的ip-link提供的功能 ***

创建veth pair,vp16与vp19是一对儿,vp26与vp29是一对儿。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ sudo ip link add vp16 type veth peer name vp19
$ sudo ip link add vp26 type veth peer name vp29
$ sudo ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 00:1c:42:c6:de:63 brd ff:ff:ff:ff:ff:ff
3: vp19@vp16: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether b6:62:99:1e:0c:2a brd ff:ff:ff:ff:ff:ff
4: vp16@vp19: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 1e:ea:cf:86:51:ab brd ff:ff:ff:ff:ff:ff
5: vp29@vp26: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 4e:16:07:e6:77:2c brd ff:ff:ff:ff:ff:ff
6: vp26@vp29: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether be:98:08:90:da:7a brd ff:ff:ff:ff:ff:ff

创建namespace ns19和ns29,并设置vp19和vp29的netns

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ sudo ip netns add ns19
$ sudo ip netns add ns29
$ sudo ip netns list
ns19
ns29

$ sudo ip link set netns ns19 vp19
$ sudo ip link set netns ns29 vp29
$ sudo ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 00:1c:42:c6:de:63 brd ff:ff:ff:ff:ff:ff
4: vp16@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 1e:ea:cf:86:51:ab brd ff:ff:ff:ff:ff:ff link-netnsid 0
6: vp26@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether be:98:08:90:da:7a brd ff:ff:ff:ff:ff:ff link-netnsid 1

设置完netns后,在当前namespace中查看网卡信息就看不到vp19和vp29这两个网卡了,但在ns19和ns29 namespace中却能查看到对应的网卡。

1
2
3
4
5
6
7
8
9
10
$ sudo ip netns exec ns19 ip link show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: vp19@if4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether b6:62:99:1e:0c:2a brd ff:ff:ff:ff:ff:ff link-netnsid 0
$ sudo ip netns exec ns29 ip link show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: vp29@if6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 4e:16:07:e6:77:2c brd ff:ff:ff:ff:ff:ff link-netnsid 0

此时将这四个网卡激活,并配置ip,他们便可以相互通讯了。

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
$ sudo ip link set dev vp16 up
$ sudo ip link set dev vp26 up
$ sudo ip netns exec ns19 ip link set dev vp19 up
$ sudo ip netns exec ns29 ip link set dev vp29 up

$ sudo ip addr add 192.168.200.16/24 dev vp16
$ sudo ip addr add 192.168.200.26/24 dev vp26
$ sudo ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp0s5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:1c:42:c6:de:63 brd ff:ff:ff:ff:ff:ff
inet 192.168.3.5/24 brd 192.168.3.255 scope global enp0s5
valid_lft forever preferred_lft forever
inet6 fe80::21c:42ff:fec6:de63/64 scope link
valid_lft forever preferred_lft forever
4: vp16@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 1e:ea:cf:86:51:ab brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.200.16/24 scope global vp16
valid_lft forever preferred_lft forever
inet6 fe80::1cea:cfff:fe86:51ab/64 scope link
valid_lft forever preferred_lft forever
6: vp26@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether be:98:08:90:da:7a brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet 192.168.200.26/24 scope global vp26
valid_lft forever preferred_lft forever
inet6 fe80::bc98:8ff:fe90:da7a/64 scope link
valid_lft forever preferred_lft forever

$ sudo ip netns exec ns19 ip addr add 192.168.200.19/24 dev vp19
$ sudo ip netns exec ns19 ip addr show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: vp19@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether b6:62:99:1e:0c:2a brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.200.19/24 scope global vp19
valid_lft forever preferred_lft forever
inet6 fe80::b462:99ff:fe1e:c2a/64 scope link
valid_lft forever preferred_lft forever

$ sudo ip netns exec ns29 ip addr add 192.168.200.29/24 dev vp29
$ sudo ip netns exec ns29 ip addr show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: vp29@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 4e:16:07:e6:77:2c brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.200.29/24 scope global vp29
valid_lft forever preferred_lft forever
inet6 fe80::4c16:7ff:fee6:772c/64 scope link
valid_lft forever preferred_lft forever
  • ns19、ns29这两个namespace的网络不能ping通各自的192.168.200.0网段的ip地址
    将ns19、ns29中的lo设备激活(up),便能ping通各自的ip地址了。
  • ns19 namespace的网络能ping同192.168.200.16192.168.200.26,但不能ping通192.168.200.29
    ns29 namespace的网络却不能ping通任何一个ip地址。
  • 将ns29所对应的veth pair划分独立网段(192.168.29.0),veth pair对应的两个网卡便能正常ping通
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
$ sudo ip netns exec ns19 ping 192.168.200.16
ING 192.168.200.16 (192.168.200.16) 56(84) bytes of data.
64 bytes from 192.168.200.16: icmp_seq=1 ttl=64 time=0.060 ms
64 bytes from 192.168.200.16: icmp_seq=2 ttl=64 time=0.065 ms
...
$ sudo ip netns exec ns19 ping 192.168.200.26
PING 192.168.200.26 (192.168.200.26) 56(84) bytes of data.
64 bytes from 192.168.200.26: icmp_seq=1 ttl=64 time=0.041 ms
64 bytes from 192.168.200.26: icmp_seq=2 ttl=64 time=0.063 ms
64 bytes from 192.168.200.26: icmp_seq=3 ttl=64 time=0.057 ms
...
$ sudo ip netns exec ns29 ping 192.168.200.26 -w 5
PING 192.168.200.26 (192.168.200.26) 56(84) bytes of data.

--- 192.168.200.26 ping statistics ---
6 packets transmitted, 0 received, 100% packet loss, time 4999ms
$ sudo ip netns exec ns29 ping 192.168.200.16 -w 5
PING 192.168.200.16 (192.168.200.16) 56(84) bytes of data.

--- 192.168.200.16 ping statistics ---
6 packets transmitted, 0 received, 100% packet loss, time 4999ms
$ sudo ip netns exec ns29 ip addr delete 192.168.200.29/24 dev vp29
$ sudo ip netns exec ns29 ip addr add 192.168.29.29/24 dev vp29
$ sudo ip addr delete 192.168.200.26/24 dev vp26
$ sudo ip addr add 192.168.29.26/24 dev vp26
$ sudo ip netns exec ns29 ping 192.168.29.26
PING 192.168.29.26 (192.168.29.26) 56(84) bytes of data.
64 bytes from 192.168.29.26: icmp_seq=1 ttl=64 time=0.059 ms
64 bytes from 192.168.29.26: icmp_seq=2 ttl=64 time=0.051 ms
...

brctl

brctl是bridge-utils包中的程序,用于管理linux bridge的CLI工具。

创建bridge设备

1
2
3
4
$ sudo brctl addbr vb
$ sudo brctl show
bridge name bridge id STP enabled interfaces
vb 8000.000000000000 no

将网卡vp16和vp26添加到bridge设备中,可实现vp19与vp29的通讯

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ sudo brctl addif vb vp16
$ sudo brctl addif vb vp26
$ sudo brctl show
bridge name bridge id STP enabled interfaces
vb 8000.1eeacf8651ab no vp16
vp26
$ sudo ip netns exec ns29 ping 192.168.200.19
PING 192.168.200.19 (192.168.200.19) 56(84) bytes of data.
64 bytes from 192.168.200.19: icmp_seq=1 ttl=64 time=0.063 ms
64 bytes from 192.168.200.19: icmp_seq=2 ttl=64 time=0.072 ms
...
$ sudo ip netns exec ns19 ping 192.168.200.29
PING 192.168.200.29 (192.168.200.29) 56(84) bytes of data.
64 bytes from 192.168.200.29: icmp_seq=1 ttl=64 time=0.066 ms
64 bytes from 192.168.200.29: icmp_seq=2 ttl=64 time=0.058 ms
...

若希望namespace网络能ping通宿主机内所有网络,需要添加默认网关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ sudo ip netns exec ns19 ping 192.168.3.5
connect: Network is unreachable
$ sudo ip netns exec ns29 ping 192.168.3.5
connect: Network is unreachable
$ sudo ip netns exec ns19 route add default gw 192.168.200.1
$ sudo ip netns exec ns19 route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.200.1 0.0.0.0 UG 0 0 0 vp19
192.168.200.0 0.0.0.0 255.255.255.0 U 0 0 0 vp19
$ sudo ip netns exec ns19 ping 192.168.3.5
PING 192.168.3.5 (192.168.3.5) 56(84) bytes of data.

--- 192.168.3.5 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 2999ms

配置完默认网关后,网络不可达变成了访问超时,此时需要将网卡vp16vp26的IP地址删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ sudo ip addr delete 192.168.200.16/24 dev vp16
$ sudo ip addr delete 192.168.200.26/24 dev vp26
$ sudo ip addr show
...
4: vp16@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master vb state UP group default qlen 1000
link/ether 1e:ea:cf:86:51:ab brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::1cea:cfff:fe86:51ab/64 scope link
valid_lft forever preferred_lft forever
6: vp26@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master vb state UP group default qlen 1000
link/ether be:98:08:90:da:7a brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::bc98:8ff:fe90:da7a/64 scope link
valid_lft forever preferred_lft forever
7: vb: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 1e:ea:cf:86:51:ab brd ff:ff:ff:ff:ff:ff
inet 192.168.200.1/24 scope global vb
valid_lft forever preferred_lft forever
inet6 fe80::1cea:cfff:fe86:51ab/64 scope link
valid_lft forever preferred_lft forever
$ sudo ip netns exec ns19 ping 192.168.3.5
PING 192.168.3.5 (192.168.3.5) 56(84) bytes of data.
64 bytes from 192.168.3.5: icmp_seq=1 ttl=64 time=0.064 ms
64 bytes from 192.168.3.5: icmp_seq=2 ttl=64 time=0.062 ms
...

iptables/netfilter

netfilter是Linux操作系统核心层内部的一个数据包处理模块,它具有网络地址转换(Network Address Translate)、数据包过滤、数据包处理、地址伪装、透明代理,以及基于用户及媒体访问控制(Media Access Control,MAC)地址的过滤和基于状态的过滤、包速率限制等。** netfilter工作在三层 **

iptables是与netfilter交互的CLI工具。

按照上述的配置方式,只能做到访问宿主机内的所有网络,若希望ping通宿主机所在网络的其它主机,需要开启ip_forward(echo 1 >> /proc/sys/net/ipv4/ip_forward,需要以root身份操作,仅仅使用root权限不够),并关闭防火墙(iptables)或配置防火墙POSTROUTING

1
2
3
4
5
6
7
8
9
10
11
12
13
$ sudo iptables -t nat -A POSTROUTING -s 192.168.200.0/24 -p all -j MASQUERADE
hain PREROUTING (policy ACCEPT)
target prot opt source destination

Chain INPUT (policy ACCEPT)
target prot opt source destination

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 192.168.200.0/24 0.0.0.0/0

TUN/TAP驱动

Todo.

参考&鸣谢

什么是服务发现

容器可以对其它容器提供服务,如mysql(数据库服务)、nginx、mangodb等等。这些服务都可以通过IP+Port方式访问。由于容器会经常重建迁移,所以IP会发生变化,如果调用服务的程序使用IP访问就会很不方便,为此可以使用DNS、zookeeper、etcd等技术实现服务访问与IP的解耦。这种解耦方式叫做服务发现。

版本

  • rancher-dns v0.13.3

Rancher服务发现构成及更新流程

rancher-dns-and-metadata

  • Cattle
    容器管理器(rancher核心)。
  • Event Subscriber
    轻量级的消息队列,用于通知rancher-metadata更新数据
    ** 猜测:采用websocket协议通讯,Cattle为消息生产者,rancher-metadata、scheduler、rancher-agent为消费者或消息订阅者 **
  • rancher-dns
    向容器提供DNS服务
  • rancher-metadata
    rancher中的元数据管理器

rancher-dns结构

rancher-dns-struct

  • TCP、UDP Listen
    rancher-dns监听53端口,用于接收域名解析请求。
  • miekg DNS
    DNS协议封装解析库
  • ROUTE
    处理域名解析业务逻辑
  • metadata client
    负责与rancher-metadata同步answer数据,每5秒同步一次。
  • answers
    负责存储解析metadata client同步来的answer数据(/etc/rancher/answers.json

rancher-dns ROUTE工作流程

rancher-dns-route-workflow

*** 关于域名协议流程参见:《DNS协议》中相关内容 ***

mac-sqlite-ad-bugfix

问题

mac上有很多流氓软件,尤其是你通过非app store安装的时候。今天我遇到了这样一个问题,mac的通知中心通知我Get it NOW!,这是SQLite Editor的一个广告推送。频率为每天一次,记住当它提示你get的时候,千万别点,点了便每天会自动打开App Store + Web来提示你购买。我操,真是烦死了。

版本

OS X 10.11.6

解决方法

  • 清理base-sqlite的推送程序
    在”/Users/zhoub/Library/Application Support”目录下,有一个”com.asoffertest.base-sqlite”目录,这里面的asoffer.py就是完成广告推送的罪魁祸首,不要由于果断将”com.asoffertest.base-sqlite”目录删除。
  • 清理NotificationCenter数据库中的记录
    虽然清理了推送程序,但是通知中心中依然有推送程序的选项卡——一个叫python的选项卡。所以需要按照《Mac中NotificationCenter残留应用删除》的方法清除“python选项卡”。
  • 重启系统
    ……系统启动后,通知中心的选项卡中没有“python”了。

原因

上诉的推送程序本人也不知道是装哪个软件装上的。但本人在MPlayerX官网上下载过osx安装包,并安装过。然后提示我已经安装了mackeeper,mackeeper可是个…以前就被这个mk(mackeeper)坑过,这次估计又是这厮搞得。

*** 以上纯属猜测,没有直接根据。***