2017年9月11日星期一

Marathonn_014:2017巴彦淖尔马拉松

2017年8月27日 5:42:56


08-20~08-28 完美假期。

和父母第一次长距离自驾游,恰逢内蒙古自治区成立70周年。
“壮美内蒙古,亮丽风景线。”

感谢我的老马车,一路上负重前行,没有出任何故障。

草原上父母渐行渐远的背影。
如繁星般散落在草原的各种不知名的小野花。
孩子叫着,跳着,奔跑着撒花:逮蚂蚱,扑蜻蜓,抓蝴蝶。
那只奇怪的、像大肚子蝈蝈的、拖着一条恐怖的大扎枪的虫子,我特意停下车跑回去看你,被你奇怪的样子深深的害怕和吸引住了,以至于忘了给你拍照,Hi,你究竟是何方妖孽?

马拉松的终点,兔兔陪我跑完最后一百米,这是他陪伴我的第七个全马,希望他有一天能懂得坚持付出的意义。

父亲看着我走路都费劲的样子,惊讶地发现:怎么,你也有白头发了吗?

2017年8月7日星期一

Marathonn_013:2017日本东京马拉松

2017年2月26日 5:11:48

迟迟没有写东京马拉松的文章是因为一直没有找到下载完赛证书的地方,难道著名的东京马拉松没有完赛证书吗?
东京马拉松不愧为六大马拉松之一,日本人的严谨与秩序充分体现在了每一个比赛环节。

对我而言,这是最艰难的一次马拉松,比之前艰难的厦门马拉松还要艰难。膝盖的旧伤,严重的雾霾,导致比赛前21天才开始恢复锻炼,赛程后半段,膝盖不由自主的抖,30公里以后,几乎是跑一公里,走一公里,成功完赛是我唯一的目标。


官方网址:http://www.marathon.tokyo
比赛时间:2017年2月26日 
报名时间:2016年8月1日 
签证办理:http://z.qyer.com/visa/list_japan/
春节假期:2017年1月28日 ~ 2017年2月3日 
游玩假期:2017年2月25日 ~ 2017年3月5日 
货币兑换:1日元=0.06481人民币元 1人民币元=15.4308日元

重要景点:东京(富士山 御殿场奥特莱斯  明治神宫 皇居 上野公园 大阪城公园、浅草寺、袛园艺伎街、心斋桥)
京都(清水寺 二条城 岚山 祗园 八坂神社 伏见稻荷 京都御所 南禅寺 京都国立博物馆)
         
东京是日本国的首都,是亚洲第一大城市,世界第二大城市。全球最大的经济中心之一。东京的著名观光景点有东京铁塔、皇居、国会议事堂、浅草寺、浜离宫、上野公园与动物园、葛西临海公园、台场与彩虹大桥、东京迪士尼乐园、代代木公园、日比谷公园、新宿御苑、幕张奥特莱斯(outlets)、奥多摩湖、Hello kitty 乐园、明治神宫、忍野八海、池袋、上野公园、东映动漫Gallery、涩谷、升仙峡、丰田汽车会馆、筑地市场、千鸟之渊、秋叶原、二重桥、隅田公园、滨离宫庭园 Tsukiji鱼市等。比较有特色的比赛有棒球和相扑,看棒球可以到后乐园站的东京球场,那里是东京巨人队的主场。看相扑可以到秋叶原附近的两国去,那里既有两国国技馆,还有许多相扑选手所属的部屋(俱乐部),每个部屋都有自己的名号与标志。江户东京博物馆也值得一看。 山手线上的几个大站的附近地区,也是游玩和观光的好地方,比如池袋附近的太阳城(Sunshine City)里集中了许多水族馆、美术馆、博物馆,新宿附近的都厅大厦、歌舞伎町、购物区,涉谷与原宿则是日本年轻人时装、音乐、化妆、随身物品、发式、甚至生活方式的信息源。上野附近集中了如日本的传统剧场、东京国立美术馆、国立科学博物馆、国立西洋美术馆、东京都美术馆等。在银座和新宿的主街道,到了星期天,禁止车辆通行,那里就成了步行者的天堂,卖艺或公演的街头艺术家、出售各种手工制品的各国小贩、在街上玩耍的年轻人,各色人等、五花八门。

京都位于日本列岛中心的关西地区,为盆地地形,面积约为610平方公里,人口为150万人,是有名的历史之城。公元794年平安京城始建于京都,历经大政奉远直至1868年迁都到东京为止的1000多年间,京都一直是日本的首都。自建城以来,京都就作为日本的经济、文化中心,它的市民们继承了其优雅的传统。京都有数百间有名的神社、神阁和古寺名刹,拥有日本二成以上的国宝,一千二百年的历史培育起来的古都让人感受到无穷的魅力。京都又是“中国化”极深的城市,许多店铺的名称上仍然有汉字的痕迹。 京都具有浓郁的日本风情,是日本人心灵的故乡。它是日本纺织物、陶瓷器、漆器、染织物等传统工艺品的产地。同时,它又是日本花道、茶道的繁盛之地,被称为“真正的日本”。京都也是接受文化熏陶的好地方,无论是艺术、佛教还是民间手工艺。游客可以通过TIC学习日本烹调技术、传统工艺(丝绸、陶瓷、造纸、庙宇行头等)、日本戏剧、茶道和插花。

行程安排:

2月25日 北京 -> 东京
飞机票查询:北京 -> 东京
http://flights.ctrip.com/international/beijing-tokyo-bjs-tyoa?2017-02-25&y
航程 航班号 出发城市 到达城市 起飞时间 到达当地时间 舱位 价格
1 CA925 北京首都T3 东京成田机场T1 2017-2-25 09:10 2017-2-25 13:40 经济舱 2097元

在成田机场购买 东京地铁 3日券(1500日元)+ 2日券(1200 日元/1日券(800 日元),兔兔不到6岁,可以免票,但最好在买票时确认一下。

成田机场 -> 住宿地点
去往民宿家庭:
京成本线(Keisei Line): 成田机场 -> 上野 70 分钟 价格 1030 日元
领取跑马装备:带上报名成功邮件,护照。
京成本线(Keisei Line): 成田机场 -> 上野 70 分钟 价格 1030 日元
JR 山手线(JR Yamanote Line):上野 -> 新桥 
        海鸥线(Yurikamome):新桥 -> 国际展示场(EXPO,Tokyo Big Sight)

入住民宿:2月25日~3月2日 信息查询:https://zh.airbnb.com/rooms/12058417 7人 5晚价格 4893元
入住酒店:2月25日~3月2日 信息查询:http://hotels.ctrip.com/international/tokyo228 双人间 每晚价格 300~500元

2月25日 东京 - 皇居 - 浅草寺 - 仲见世商店街 - 银座 - 东京塔
2月26日 马拉松/公园,购物
检录时间:上午 7:00~8:45
比赛时间:上午 9:10 鸣枪
马拉松路线:Tokyo Metropolitan Government Building ― Iidabashi ― Kanda ― Nihombashi ― Asakusa Kaminari-Mon ― Ryogoku ― Monzen-nakacho ― Ginza ― Takanawa ― Hibiya ―Tokyo Station/Gyoko-dori
比赛起点:东京新宿的东京都政厅前
  由于大江户线的都厅前站比赛当天会临时关闭,建议乘坐 JR山手线 -> 新宿站 或者 丸之内线  -> 新宿站。
比赛终点:东京地铁站

2月27日 博物馆,美食
2月28日 公园,美食
3月1日 富士山,美食

3月2日 东京 -> 京都
乘坐 东海道·山阳新干线(Tokaido-Sanyo Shinkansen)约 120 分钟
出发站 到达站 价格 备注
东京站/品川站 京都车站 12710日元 不预留座位

确认一下京都站八条口在哪里,因为坐大巴去关西机场从这里坐。
购买京都乘车券
  京都公交专用1日乘车券(500日元)
  京都观光1日/2日乘车券(公交 + 地铁,1200日元/2000日元)
  发售处:市公交・地铁问讯处,月票发售点,市公交营业厅,市公交车内(部分公交车除外),地铁各站窗口

入住民宿:3月2日~3月5日 信息查询:https://zh.airbnb.com/rooms/7536485 7人 3晚价格 4151元
入住酒店:3月2日~3月5日 信息查询:http://hotels.ctrip.com/international/kyoto734 双人间 每晚价格 600~800元

3月2日 公园,美食
3月3日 博物馆,美食
3月4日 公园,美食
3月5日 公园(上午),去大阪(下午)

3月5日 京都 -> 大阪 -> 北京
京都 -> 大阪
方式1:乘坐JR线的快速电车 HARUKA 京都站  -> 关西机场 全程1小时16分,票价 3370日元。
方式2:乘坐机场大巴,京都站八条口 -> 关西机场 全程1小时30分 ,票价 2550日元。 √
飞机票查询:大阪 -> 北京
http://flights.ctrip.com/international/osaka-beijing-osa-bjs?2017-03-05&y
航程 航班号 出发城市 到达城市 起飞时间 到达当地时间 舱位 价格
1 MU526 关西国际机场T1 北京首都机场T2 2017-3-5 17:30 2017–3-5 20:20 经济舱 1500元

http://www.kate.co.jp/scn/timetable/detail/KY
退休人员日本签证所需材料
1. 户口本(复印件)
2. 身份证(复印件)
3. 护照(原件)
4. 2寸白底彩色近照2张
5. 结婚证(复印件)
6. 退休证(复印件)
7. 本人名下近一年储蓄卡对账单(对账单必须能体现年正常入账过10万)
8. 房产本(复印件)

在职人员日本签证所需材料
1. 户口本(复印件)
2. 身份证(复印件)
3. 护照(原件)
4. 2寸白底彩色近照2张
5. 结婚证(复印件)
6. 中文在职证明(原件)
7. 营业执照或组织机构代码证副本(复印件)
8. 本人名下近一年储蓄卡对账单(对账单必须能体现年正常入账过10万)
9. 房产本(复印件)
10. 个人完税证明:商务中心区税务所 电话: 59005160 59005161 北京市朝阳区东大桥路8号SOHO尚都南塔3层

学龄前儿童日本签证所需材料
1. 出生证明(复印件)
2. 身份证(复印件)
3. 户口本(复印件)
4. 护照(原件)
5. 2寸白底彩色近照2张

Tips_030:把 LinkedIn Profile 导出成 PDF

1. 首先登陆 LinkedIn
进入后应该显示类似如下画面,即你的 Profile:

如果没显示,点击 Me,点击 View profile

2. 点击你的头像右边的 ...,会显示一个下拉列表,剩下的就不用说了吧,呵呵。

LinkedIn 的这个功能,真是方便,以后只要在线更新 LinkedIn 一份简历就可以了,需要的时候导出一份就可以了。

2017年8月4日星期五

Tips_029:使用 Google 翻译上传 PDF 文档

访问 https://translate.google.com,显示如下画面:

点击上传文档,然后选好源语言和目的语言,然后点击翻译即可。
需要说明的是,文档的大小不能超过 1 M。

注意,必须访问 https://translate.google.com 而不能访问 https://translate.google.cn,后者画面如下,没有上传文档功能,我也不知道为什么。

另外,Google 翻译只能把 PDF 内容翻译,不能另存为 PDF,虽然可以用浏览器打印功能另存为 PDF,但是格式和原文不一致,有字符重叠。
希望 Google 能把这个问题解决,那样就更完美啦。

2017年7月12日星期三

OpenShift_085:在 Web Console 上部署第三方镜像

环境:OCP 3.5

本文以部署 mywebsql 镜像为例说明,如何在 Web Console 上部署第三方镜像。
关于如何使用命令行部署第三方镜像,请参考《部署 mywebsql docker image 访问 mysql 数据库》。

1. 直接 Deploy Image
部署不成功,这是因为 Web Console 不支持 https 安全验证。


2. 以 Image Stream 方式部署
(1)允许 root 用户访问容器
oc login -u system:admin

oadm policy add-scc-to-user anyuid -z default
(2)创建 Image Stream:mywebsql
oc create -f mywebsql-is.json -n openshift
其中 mywebsql-is.json 内容如下:
{
    "kind": "ImageStream",
    "apiVersion": "v1",
    "metadata": {
        "name": "mywebsql",
        "creationTimestamp": null
    },
    "spec": {
        "dockerImageRepository": "registry.example.com:5000/quantumobject/docker-mywebsql",
        "tags": [
            {
                "name": "latest",
                "annotations": null,
                "from": {
                    "kind": "DockerImage",
                    "name": "registry.example.com:5000/quantumobject/docker-mywebsql"
                },
                "generation": 1,
                "importPolicy": {
                    "insecure": true
                }
            }
        ]
    }
}

(3)部署 Image Stream:mywebsql



3. 创建 template mywebsql(在 Master 机器上操作)
为了以后创建更简单,这里导出 mywebsql 的所有对象,并存为 template。
oc export dc,svc,route -o json --as-template=mywebsql > mywebsql.template
修改 mywebsql.template,

"image": "registry.example.com:5000/quantumobject/docker-mywebsql@sha256:a34f5050ae56bab4d8456a86666c9b431d7bead26e71a1b1003fd874b68bfb8d",
改为
"image": ""
这样做的目的是,根据 template 创建应用后,自动发布,不用再手工点击 Deploy。

oc create -f mywebsql.template -n openshift

4. 测试
oc project test
oc delete all --all


OpenShift_084:安装配置 JBoss AMQ(Route SSL)

环境:OCP 3.5

本文在 OpenShift 平台上部署一个 JBoss AMQ,配置消息持久化,通过 Route SSL 访问。

1. 修改默认的 template amq62-persistent-ssl 
oc edit template amq62-persistent-ssl -n openshift

kind: ImageStreamTag
name: jboss-amq-62:1.3
改为
kind: ImageStreamTag
name: jboss-amq-62:latest

为方便起见,建议把所有有关 amq62 的 template 都修改一遍。
oc edit template amq62-basic -n openshift
oc edit template amq62-persistent -n openshift
oc edit template amq62-persistent-ssl -n openshift
oc edit template amq62-ssl -n openshift

2. 创建 NFS Server(在 Registry 机器上操作)
yum install –y nfs-utils

export volname=amq-vol
mkdir -p /srv/nfs/${volname}
chown nfsnobody:nfsnobody /srv/nfs/${volname}
chmod 700 /srv/nfs/${volname}
echo "/srv/nfs/${volname} *(rw,sync,all_squash)" >> /etc/exports
systemctl enable nfs-server
systemctl restart rpcbind
systemctl restart nfs-server nfs-lock nfs-idmap

3. 测试 NFS Server 工作是否正常 (在 Node1/Node2 机器上操作)
export volname=amq-vol
mkdir -p /mnt/nfs
mount -t nfs registry.example.com:/srv/nfs/${volname} /mnt/nfs
umount /mnt/nfs

4. 创建 PV (在 Master 机器上操作,如果出错,此步需要重做)
echo '{
  "apiVersion": "v1",
  "kind": "PersistentVolume",
  "metadata": {
    "name": "amq-volume"
  },
  "spec": {
    "capacity": {
        "storage": "512Mi"
        },
    "accessModes": [ "ReadWriteMany" ],
    "nfs": {
        "path": "/srv/nfs/amq-vol",
        "server": "registry.example.com"
    },
    "persistentVolumeReclaimPolicy": "Recycle"
  }
}' | oc create -f -

如果出错,执行以下命令清理,然后重做

5. 创建各种对象
(1)oc new-project amq-demo
(2)创建 service account,用于 A-MQ 部署
  echo '{"kind": "ServiceAccount", "apiVersion": "v1", "metadata": {"name": "amq-service-account"}}' | oc create -f -
(3)给 amq-service-account 赋予 view 权限
  oc policy add-role-to-user view system:serviceaccount:amq-demo:amq-service-account
(4)A-MQ 需要一个 broker keyStore,一个 client keyStore,一个 client trustStore 其中包括 broker keyStore
(4.1)生成一个自签名的证书,作为 broker keyStore
keytool -genkey -dname "CN=Ma Ping,OU=SA,O=Redhat,L=CY,ST=Beijing,C=CN" -alias broker -keyalg RSA -keysize 1024 -keystore broker.ks -keypass redhat -storepass redhat -validity 365
(4.2)导出刚刚生成的 broker keyStore 证书,以便分享
keytool -export -alias broker -keystore broker.ks -storepass redhat -file broker_cert
(4.3)生成一个自签名的证书,作为 client keyStore
keytool -genkey -dname "CN=Ma Ping,OU=SA,O=Redhat,L=CY,ST=Beijing,C=CN" -alias client -keyalg RSA -keysize 1024 -keystore client.ks -keypass redhat -storepass redhat -validity 365
(4.4)创建 client trustStore,并导入之前导出的 broker 证书
keytool -import -alias broker -keystore client.ts -storepass redhat -file broker_cert
(4.5)使用 broker keyStore 创建 secret
oc secrets new amq-app-secret broker.ks
(4.6)把 secret 添加到之前创建的 service account
oc secrets add sa/amq-service-account secret/amq-app-secret

6. 部署
为简单起见,基于 amq62-persistent-ssl template,创建 my-amq62-persistent-ssl
oc get template amq62-persistent-ssl -n openshift -o json > my-amq62-persistent-ssl.json
去掉不必要的 service,只保留 broker-amq-tcp 和 broker-amq-tcp-ssl。
修改后,my-amq62-persistent-ssl.json 内容如下:
{
    "apiVersion": "v1",
    "kind": "Template",
    "labels": {
        "template": "my-amq62-persistent-ssl",
        "xpaas": "1.3.1"
    },
    "metadata": {
        "annotations": {
            "description": "Application template for JBoss A-MQ brokers. These are deployed as standalone and use persistent storage for saving messages. This template supports SSL and requires usage of OpenShift secrets.",
            "iconClass": "icon-jboss",
            "tags": "messaging,amq,jboss,xpaas",
            "version": "1.3.1"
        },
        "creationTimestamp": "2017-05-24T06:57:08Z",
        "name": "my-amq62-persistent-ssl",
        "namespace": "openshift",
        "resourceVersion": "20544",
        "selfLink": "/oapi/v1/namespaces/openshift/templates/my-amq62-persistent-ssl",
        "uid": "346b140a-404e-11e7-999f-080027873f56"
    },
    "objects": [
        {
            "apiVersion": "v1",
            "kind": "Service",
            "metadata": {
                "annotations": {
                    "description": "The broker's OpenWire port."
                },
                "labels": {
                    "application": "${APPLICATION_NAME}"
                },
                "name": "${APPLICATION_NAME}-amq-tcp"
            },
            "spec": {
                "ports": [
                    {
                        "port": 61616,
                        "targetPort": 61616
                    }
                ],
                "selector": {
                    "deploymentConfig": "${APPLICATION_NAME}-amq"
                }
            }
        },
        {
            "apiVersion": "v1",
            "kind": "Service",
            "metadata": {
                "annotations": {
                    "description": "The broker's OpenWire (SSL) port."
                },
                "labels": {
                    "application": "${APPLICATION_NAME}"
                },
                "name": "${APPLICATION_NAME}-amq-tcp-ssl"
            },
            "spec": {
                "ports": [
                    {
                        "port": 61617,
                        "targetPort": 61617
                    }
                ],
                "selector": {
                    "deploymentConfig": "${APPLICATION_NAME}-amq"
                }
            }
        },
        {
            "apiVersion": "v1",
            "kind": "DeploymentConfig",
            "metadata": {
                "labels": {
                    "application": "${APPLICATION_NAME}"
                },
                "name": "${APPLICATION_NAME}-amq"
            },
            "spec": {
                "replicas": 1,
                "selector": {
                    "deploymentConfig": "${APPLICATION_NAME}-amq"
                },
                "strategy": {
                    "rollingParams": {
                        "maxSurge": 0
                    },
                    "type": "Rolling"
                },
                "template": {
                    "metadata": {
                        "labels": {
                            "application": "${APPLICATION_NAME}",
                            "deploymentConfig": "${APPLICATION_NAME}-amq"
                        },
                        "name": "${APPLICATION_NAME}-amq"
                    },
                    "spec": {
                        "containers": [
                            {
                                "env": [
                                    {
                                        "name": "AMQ_USER",
                                        "value": "${MQ_USERNAME}"
                                    },
                                    {
                                        "name": "AMQ_PASSWORD",
                                        "value": "${MQ_PASSWORD}"
                                    },
                                    {
                                        "name": "AMQ_TRANSPORTS",
                                        "value": "${MQ_PROTOCOL}"
                                    },
                                    {
                                        "name": "AMQ_QUEUES",
                                        "value": "${MQ_QUEUES}"
                                    },
                                    {
                                        "name": "AMQ_TOPICS",
                                        "value": "${MQ_TOPICS}"
                                    },
                                    {
                                        "name": "MQ_SERIALIZABLE_PACKAGES",
                                        "value": "${MQ_SERIALIZABLE_PACKAGES}"
                                    },
                                    {
                                        "name": "AMQ_SPLIT",
                                        "value": "${AMQ_SPLIT}"
                                    },
                                    {
                                        "name": "AMQ_MESH_DISCOVERY_TYPE",
                                        "value": "${AMQ_MESH_DISCOVERY_TYPE}"
                                    },
                                    {
                                        "name": "AMQ_MESH_SERVICE_NAME",
                                        "value": "${APPLICATION_NAME}-amq-tcp"
                                    },
                                    {
                                        "name": "AMQ_MESH_SERVICE_NAMESPACE",
                                        "valueFrom": {
                                            "fieldRef": {
                                                "fieldPath": "metadata.namespace"
                                            }
                                        }
                                    },
                                    {
                                        "name": "AMQ_KEYSTORE_TRUSTSTORE_DIR",
                                        "value": "/etc/amq-secret-volume"
                                    },
                                    {
                                        "name": "AMQ_TRUSTSTORE",
                                        "value": "${AMQ_TRUSTSTORE}"
                                    },
                                    {
                                        "name": "AMQ_TRUSTSTORE_PASSWORD",
                                        "value": "${AMQ_TRUSTSTORE_PASSWORD}"
                                    },
                                    {
                                        "name": "AMQ_KEYSTORE",
                                        "value": "${AMQ_KEYSTORE}"
                                    },
                                    {
                                        "name": "AMQ_KEYSTORE_PASSWORD",
                                        "value": "${AMQ_KEYSTORE_PASSWORD}"
                                    },
                                    {
                                        "name": "AMQ_STORAGE_USAGE_LIMIT",
                                        "value": "${AMQ_STORAGE_USAGE_LIMIT}"
                                    }
                                ],
                                "image": "jboss-amq-62",
                                "imagePullPolicy": "Always",
                                "name": "${APPLICATION_NAME}-amq",
                                "ports": [
                                    {
                                        "containerPort": 8778,
                                        "name": "jolokia",
                                        "protocol": "TCP"
                                    },
                                    {
                                        "containerPort": 61616,
                                        "name": "tcp",
                                        "protocol": "TCP"
                                    },
                                    {
                                        "containerPort": 61617,
                                        "name": "tcp-ssl",
                                        "protocol": "TCP"
                                    }
                                ],
                                "readinessProbe": {
                                    "exec": {
                                        "command": [
                                            "/bin/bash",
                                            "-c",
                                            "/opt/amq/bin/readinessProbe.sh"
                                        ]
                                    }
                                },
                                "volumeMounts": [
                                    {
                                        "mountPath": "/etc/amq-secret-volume",
                                        "name": "broker-secret-volume",
                                        "readOnly": true
                                    },
                                    {
                                        "mountPath": "/opt/amq/data",
                                        "name": "${APPLICATION_NAME}-amq-pvol"
                                    }
                                ]
                            }
                        ],
                        "serviceAccountName": "amq-service-account",
                        "terminationGracePeriodSeconds": 60,
                        "volumes": [
                            {
                                "name": "broker-secret-volume",
                                "secret": {
                                    "secretName": "${AMQ_SECRET}"
                                }
                            },
                            {
                                "name": "${APPLICATION_NAME}-amq-pvol",
                                "persistentVolumeClaim": {
                                    "claimName": "${APPLICATION_NAME}-amq-claim"
                                }
                            }
                        ]
                    }
                },
                "triggers": [
                    {
                        "imageChangeParams": {
                            "automatic": true,
                            "containerNames": [
                                "${APPLICATION_NAME}-amq"
                            ],
                            "from": {
                                "kind": "ImageStreamTag",
                                "name": "jboss-amq-62:latest",
                                "namespace": "${IMAGE_STREAM_NAMESPACE}"
                            }
                        },
                        "type": "ImageChange"
                    },
                    {
                        "type": "ConfigChange"
                    }
                ]
            }
        },
        {
            "apiVersion": "v1",
            "kind": "PersistentVolumeClaim",
            "metadata": {
                "labels": {
                    "application": "${APPLICATION_NAME}"
                },
                "name": "${APPLICATION_NAME}-amq-claim"
            },
            "spec": {
                "accessModes": [
                    "ReadWriteMany"
                ],
                "resources": {
                    "requests": {
                        "storage": "${VOLUME_CAPACITY}"
                    }
                }
            }
        }
    ],
    "parameters": [
        {
            "description": "The name for the application.",
            "name": "APPLICATION_NAME",
            "required": true,
            "value": "broker"
        },
        {
            "description": "Split the data directory for each node in a mesh.",
            "name": "AMQ_SPLIT",
            "value": "false"
        },
        {
            "description": "Protocols to configure, separated by commas.  Allowed values are: `openwire`, `amqp`, `stomp` and `mqtt`.",
            "name": "MQ_PROTOCOL",
            "value": "openwire"
        },
        {
            "description": "Queue names, separated by commas.  These queues will be automatically created when the broker starts.  If left empty, queues will be still created dynamically.",
            "name": "MQ_QUEUES"
        },
        {
            "description": "Topic names, separated by commas.  These topics will be automatically created when the broker starts.  If left empty, topics will be still created dynamically.",
            "name": "MQ_TOPICS"
        },
        {
            "description": "List of packages that are allowed to be serialized for use in ObjectMessage, separated by commas. If your app doesn't use ObjectMessages, leave this blank. This is a security enforcement. For the rationale, see http://activemq.apache.org/objectmessage.html",
            "name": "MQ_SERIALIZABLE_PACKAGES"
        },
        {
            "description": "Size of persistent storage for database volume.",
            "name": "VOLUME_CAPACITY",
            "required": true,
            "value": "512Mi"
        },
        {
            "description": "User name for standard broker user.  It is required for connecting to the broker.  If left empty, it will be generated.",
            "from": "user[a-zA-Z0-9]{3}",
            "generate": "expression",
            "name": "MQ_USERNAME",
            "value": "admin"
        },
        {
            "description": "Password for standard broker user.  It is required for connecting to the broker.  If left empty, it will be generated.",
            "from": "[a-zA-Z0-9]{8}",
            "generate": "expression",
            "name": "MQ_PASSWORD",
            "value": "admin"
        },
        {
            "description": "The discovery agent type to use for discovering mesh endpoints.  'dns' will use OpenShift's DNS service to resolve endpoints.  'kube' will use Kubernetes REST API to resolve service endpoints.  If using 'kube' the service account for the pod must have the 'view' role, which can be added via 'oc policy add-role-to-user view system:serviceaccount:\u003cnamespace\u003e:default' where \u003cnamespace\u003e is the project namespace.",
            "name": "AMQ_MESH_DISCOVERY_TYPE",
            "value": "kube"
        },
        {
            "description": "Name of a secret containing SSL related files",
            "name": "AMQ_SECRET",
            "required": true,
            "value": "amq-app-secret"
        },
        {
            "description": "SSL trust store filename",
            "name": "AMQ_TRUSTSTORE",
            "required": true,
            "value": "broker.ks"
        },
        {
            "description": "SSL trust store password",
            "name": "AMQ_TRUSTSTORE_PASSWORD",
            "required": true,
            "value": "redhat"
        },
        {
            "description": "SSL key store filename",
            "name": "AMQ_KEYSTORE",
            "required": true,
            "value": "broker.ks"
        },
        {
            "description": "Password for accessing SSL keystore",
            "name": "AMQ_KEYSTORE_PASSWORD",
            "required": true,
            "value": "redhat"
        },
        {
            "description": "The A-MQ storage usage limit",
            "name": "AMQ_STORAGE_USAGE_LIMIT",
            "value": "1 gb"
        },
        {
            "description": "Namespace in which the ImageStreams for Red Hat Middleware images are installed. These ImageStreams are normally installed in the openshift namespace. You should only need to modify this if you've installed the ImageStreams in a different namespace/project.",
            "name": "IMAGE_STREAM_NAMESPACE",
            "required": true,
            "value": "openshift"
        }
    ]
}

(1)部署 my-amq62-persistent-ssl template
Add to Project --> Browse Catalog 输入 amq62,选择 my-amq62-persistent-ssl
其余保持默认,点击 Create,等待 Pods 启动成功。
(2)为 Service:broker-amq-tcp-ssl 创建 Route
(3)修改 Route,勾选中 Secure route,修改 TLS Termination,下拉列表选择 Passthrough。

7. 测试
(1)消息生产者:SSLPublisher.java

import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.Session;

import org.apache.activemq.ActiveMQSslConnectionFactory;

/**
 * 使用SSL连接器 队列消息生产者
 */
public class SSLPublisher {

    public static void main(String[] args) throws JMSException, Exception {
        /*
         * 配置参数 密钥和证书文件的访问目录 密钥密码 SSL链接地址
         */
        String keyStore = "/Users/maping/Apache/broker.ks";
        String trustStore = "/Users/maping/Apache/client.ts";
        String keyStorePassword = "redhat";
        String url = "ssl://broker-amq-tcp-ssl-amq-demo.apps.example.com:443";

        // 创建SSL连接器工厂类
        ActiveMQSslConnectionFactory sslConnectionFactory = new ActiveMQSslConnectionFactory();
        // 设置参数,并加载SSL密钥和证书信息
        sslConnectionFactory.setUserName("admin");
        sslConnectionFactory.setPassword("admin");
        sslConnectionFactory.setBrokerURL(url);
        sslConnectionFactory.setKeyAndTrustManagers(SSLUtils.loadKeyManager(keyStore, keyStorePassword), SSLUtils.loadTrustManager(trustStore),
                new java.security.SecureRandom());

        // 连接ActiveMQ
        Connection conn = sslConnectionFactory.createConnection();
        conn.start();
        Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Destination dest = session.createQueue("sslDemo");

        // 创建消息生产者,发送一条报文消息
        MessageProducer mp = session.createProducer(dest);
        Message msg = session.createTextMessage("Hello SSL!");
        mp.send(msg);
        System.out.println("success");

        // 发送完成,释放连接
        session.close();
        conn.close();
    }
}

(2)消息消费者:SSLListener.java

import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQSslConnectionFactory;

/**
 * 使用SSL连接器 队列消息消费者
 */
public class SSLListener {

    public static void main(String[] args) throws JMSException, Exception {
        /*
         * 配置参数 密钥和证书文件的访问目录 密钥密码 SSL链接地址
         */
        String keyStore = "/Users/maping/Apache/broker.ks";
        String trustStore = "/Users/maping/Apache/client.ts";
        String keyStorePassword = "redhat";
        String url = "ssl://broker-amq-tcp-ssl-amq-demo.apps.example.com:443";

        // 创建SSL连接器工厂类
        ActiveMQSslConnectionFactory sslConnectionFactory = new ActiveMQSslConnectionFactory();
        // 设置参数,并加载SSL密钥和证书信息
        sslConnectionFactory.setUserName("admin");
        sslConnectionFactory.setPassword("admin");
        sslConnectionFactory.setBrokerURL(url);
        sslConnectionFactory.setKeyAndTrustManagers(SSLUtils.loadKeyManager(keyStore, keyStorePassword), SSLUtils.loadTrustManager(trustStore),
                new java.security.SecureRandom());

        // 连接ActiveMQ
        Connection conn = sslConnectionFactory.createConnection();
        conn.start();
        Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Destination dest = session.createQueue("sslDemo");
        // 设置消息消费者,在匿名内部类中打印消息内容
        MessageConsumer mc = session.createConsumer(dest);
        mc.setMessageListener(new MessageListener() {
            @Override
            public void onMessage(Message msg) {
                if (msg instanceof TextMessage) {
                    try {
                        TextMessage tmsg = (TextMessage) msg;
                        System.out.println(tmsg.getText());
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                } else {
                    System.out.println(msg.toString());
                }
            }
        });

        // 不关闭连接,让客户端一直连着ActiveMQ
    }
}
(3)SSL 工具类:SSLListener.java

import java.io.FileInputStream;
import java.security.KeyStore;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

/**
 * SSL 工具类 加载密钥和证书文件
 */
public class SSLUtils {

    /**
     * 加载证书文件
     *
     * @param trustStore
     * @return
     * @throws java.security.NoSuchAlgorithmException
     * @throws java.security.KeyStoreException
     * @throws java.io.IOException
     * @throws java.security.GeneralSecurityException
     */
    public static TrustManager[] loadTrustManager(String trustStore) throws java.security.NoSuchAlgorithmException, java.security.KeyStoreException,
            java.io.IOException, java.security.GeneralSecurityException {
        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(new FileInputStream(trustStore), null);
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(ks);
        System.out.println("init TrustManagers finish");
        return tmf.getTrustManagers();
    }

    /**
     * 加载密钥文件
     *
     * @param keyStore
     * @param keyStorePassword
     * @return
     * @throws java.security.NoSuchAlgorithmException
     * @throws java.security.KeyStoreException
     * @throws java.security.GeneralSecurityException
     * @throws java.security.cert.CertificateException
     * @throws java.io.IOException
     * @throws java.security.UnrecoverableKeyException
     */
    public static KeyManager[] loadKeyManager(String keyStore, String keyStorePassword) throws java.security.NoSuchAlgorithmException,
            java.security.KeyStoreException, java.security.GeneralSecurityException, java.security.cert.CertificateException, java.io.IOException,
            java.security.UnrecoverableKeyException {
        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(new FileInputStream(keyStore), keyStorePassword.toCharArray());
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(ks, keyStorePassword.toCharArray());
        System.out.println("init KeyManager finish");
        return kmf.getKeyManagers();
    }
}

(4)在 Web Console 中查看,点击 Pod,点击 Open Java Console


8. 如果有错,执行以下命令清除,然后重做
oc project amq-demo
oc delete pvc broker-amq-claim
oc delete pv amq-volume
oc delete all --all
oc delete template my-amq62-persistent-ssl -n openshift
oc create -f my-amq62-persistent-ssl.json -n openshift

参考文献:
1. http://blog.csdn.net/dailywater/article/details/52833307

OpenShift_083:安装配置 JBoss AMQ(NodePort)

环境:OCP 3.5

本文以最简单的方式在 OpenShift 平台上部署一个 JBoss AMQ。使用 NodePort 方式直接暴露 Node 上的 TCP 端口,供外部访问。

1. 修改默认的 template amq62-basic
oc edit template amq62-basic -n openshift

kind: ImageStreamTag
name: jboss-amq-62:1.3
改为
kind: ImageStreamTag
name: jboss-amq-62:latest

为方便起见,建议把所有有关 amq62 的 template 都修改一遍。
oc edit template amq62-basic -n openshift
oc edit template amq62-persistent -n openshift
oc edit template amq62-persistent-ssl -n openshift
oc edit template amq62-ssl -n openshift

2. 部署
(1)oc new-project test
(2)Add to Project --> Browse Catalog 输入 amq62,选择 amq62-basic
MQ_USERNAME:admin
MQ_PASSWORD:admin
其余保持默认,点击 Create
等待 Pods 启动成功。
(3)修改 Service:broker-amq-tcp,把 ClusterIP 改为 NodePort
(4)查看 Node Port 端口
oc get svc broker-amq-tcp
输出如下:
NAME             CLUSTER-IP      EXTERNAL-IP   PORT(S)           AGE
broker-amq-tcp   172.30.35.185   <nodes>       61616:32472/TCP   6m
(5)查看 Pod 运行在哪个 Node 上
oc get pod -o wide
NAME                 READY     STATUS    RESTARTS   AGE       IP            NODE
broker-amq-1-kk5cz   1/1       Running   0          7m        10.128.0.37   node2.example.com

3. 测试
  cd ~/Apache/activemq/bin
(1)生产消息
./activemq producer --brokerUrl tcp://node2.example.com:32472 --user admin --password admin --destination queue://testQueue --messageSize 1024 --messageCount 10 --parallelThreads 10
(2)消费消息
./activemq consumer --brokerUrl tcp://node2.example.com:32472 --user admin --password admin --destination queue://testQueue --messageCount 10 --parallelThreads 10

在 Web Console 中查看,点击 Pod,点击 Open Java Console

5. 如果有错,执行以下命令清除,然后重做
 oc delete dc/broker-amq  svc/broker-amq-amqp  svc/broker-amq-mqtt  svc/broker-amq-stomp svc/broker-amq-tcp

2017年7月4日星期二

Cloud_032:SDN 介绍(摘录+整理)

1. 什么是 SDN ?
软件定义网络(Software Defined Network,SDN)是一种新型网络架构,是网络虚拟化的一种实现方式。
在数据中心里,网络技术是最为封闭的一部分,这导致长期以来网络成为数据中心发展的瓶颈,SDN 就是要打破这种网络的封闭性,让网络也能变得和虚拟池化后的计算、存储资源一样,成为一种可灵活调配的资源。
SDN 的核心理念是将网络层面的功能和数据层面的功能与网络设备硬件解耦,变成抽象化的功能,再通过外置的控制器来控制这些抽象化对象。
SDN 包含控制器和 OpenFlow 两大部分:
(1)控制器是一个软件,可以对整个网络设备进行管理和控制。
(2)OpenFlow 是控制器与网络设备之间互通的语言;
控制器通过 OpenFlow 对所有网络设备进行管理和控制。

2. SDN 与 Overlay 的关系
Overlay 提供了一种解决数据层面转发和多租户隔离的技术手段。SDN 定义了一种控制和管理的网络架构。
VxLAN 是部署 SDN 的先决条件,两者在未来数据中心里的作用并不冲突,可以有机地结合,共同发挥作用。

3. VDC
虚拟数据中心(Virtual Data Center),即对数据中心全面实现虚拟化,包括服务器的虚拟化、安全的虚拟化、网络的虚拟化。
VDC 中的网络虚拟化的实现技术是 VMware 的 Neutron。
Neutron 的目的是为 OpenStack 云更灵活地划分物理网络,在多租户环境下提供给每个租户独立的网络环境。
Neutron 提供 API 来实现这种目标。
用户可以使用 Neutron API 创建自己的网络对象,如果要和物理环境下的概念映射的话,这个网络对象相当于一个巨大的交换机,可以拥有无限多个动态可创建和销毁的虚拟端口。
SDN 实现的是三层以下的虚拟化,而 VDC 关注的是四到七层的虚拟化。
Neutron 提供接近应用层的网络虚拟化技术,是对 SDN 的有效补充。

2017年7月2日星期日

Cloud_031:VxLAN 原理详解(摘录+整理)

1. 什么是 VxLAN ?
虚似扩展局域网(Virtual Extensible LAN,VxLAN)是一种网络虚似化技术,是由 Ciscio科和 VMware 共同提出来的,是对 VLAN 的一种扩展,用于满足日益增长的云计算部署要求。

2. 为什么要使用 VxLAN ?
(1)虚拟机规模受网络规格限制
在大二层网络环境下,数据报文是通过查询 MAC 地址表进行二层转发,而 MAC 地址表的容量限制了虚拟机的数量。
(2)网络隔离能力限制
VLAN 在大规模的虚拟化网络中部署存在如下限制:
仅能表示 4096 个 VLAN,无法满足大二层网络中大量用户群的需求;
传统二层网络无法满足网络动态调整的需求。
(3)虚拟机迁移范围受网络架构限制
为了保证虚拟机动态迁移过程中业务不中断,不仅需要保持虚拟机的 IP 地址、MAC 地址不变,运行状态(比如TCP 会话)也必须保持不变,这就要求网络是一个二层网络,并且要求网络本身具备多路径的冗余备份和可靠性。

3. VxLAN 报文格式



4. VxLAN 网络结构




4. VxLAN 网关





参考文献:
1. http://developer.huawei.com/cn/ict/Products/Agile_Network/Components/DCN/detail/net/VXLAN
2. http://www.cnblogs.com/hbgzy/p/5279269.html
3. http://www.sdnlab.com/7241.html

Cloud_30:大二层网络 (摘录+整理)

首先要说明的是,大二层网络是针对虚拟化数据中心的虚拟机动态迁移这一特定需求而提出的概念,对于其它类型的网络并无特殊的价值和意义。
为了保证虚拟机动态迁移过程中业务不中断,不仅需要保持虚拟机的 IP 地址、MAC 地址不变,运行状态(比如TCP 会话)也必须保持不变,这就要求迁移的起始和目标位置必须在同一个二层网络,并且要求网络本身具备多路径的冗余备份和可靠性。
所以,为了实现虚拟机的大范围甚至跨地域的动态迁移,就要求把虚拟机迁移可能涉及的所有服务器都纳入同一个二层网络域。
这就是大二层网络的需求由来,一个真正的大二层网络至少要能容纳 1 万以上的主机,才能称之为大二层网络。
而传统的基于 VLAN + xSTP 的二层网络,由于环路和广播风暴、以及 xSTP 协议的性能限制等原因,通常能容纳的主机数量不会超过 1千,无法实现大二层网络。


当前,实现大二层网络的主要技术有以下几种:

1. 网络设备虚拟化技术
网络设备虚拟化是将相互冗余的两台或多台物理网络设备组合在一起,虚拟化成一台逻辑网络设备,在整个网络中只呈现为一个节点。例如华为的 CSS 框式堆叠、iStack 盒式堆叠、SVF 框盒堆叠技术等。


网络设备虚拟化再配合链路聚合技术,就可以把原来网络的多节点、多链路的结构变成逻辑上单节点、单链路的结构,解决了二层网络中的环路问题。没有了环路问题,就不需要xSTP,二层网络就可以范围无限(只要虚拟网络设备的接入能力允许),从而实现大二层网络。

2. 大二层转发技术
大二层转发技术是通过定义新的转发协议,改变传统二层网络的转发模式,将三层网络的路由转发模式引入到二层网络中。例如 TRILL、SPB 等。
以 TRILL 为例,TRILL 协议在原始以太帧外封装一个TRILL 帧头,再封装一个新的以太帧来实现对原始以太帧的透明传输,支持 TRILL 的交换机可通过 TRILL 帧头里的 Nickname 标识来进行转发,而 Nickname 就像路由一样,可通过 IS-IS 路由协议进行收集、同步和更新。


3. Overlay 技术
前两种技术都是网络设备厂商提供的,需要使用专用的网络设备。而 Overlay 技术是 IT 厂商提出的,目的就是为了摆脱对网络设备厂商的依赖。

Overlay 技术是通过用隧道封装的方式,将源主机发出的原始二层报文封装后在现有网络中进行透明传输,从而实现主机之间的二层通信。通过封装和解封装,相当于一个大二层网络叠加在现有的基础网络之上,所以称为 Overlay 技术。
Overlay 技术通过隧道封装的方式,忽略承载网络的结构和细节,可以把整个承载网络当作一台“巨大无比的二层交换机”, 每一台主机都是直连在“交换机”的一个端口上。而承载网络之内如何转发都是 “交换机”内部的事情,主机完全不可见。
Overlay 技术主要有 VxLAN、NVGRE、STT 等。


参考文献:
1. http://blog.sina.com.cn/s/blog_4878aa7d0102vjm9.html

Cloud_029:VPN 原理详解 (摘录+整理)

虚拟专用网络(Virtual Private Network,VPN),是一个在一个公用网络中建立一个临时的、安全的连接,是一条穿过公用网络的安全、稳定的隧道。
说得再通俗一点,VPN 实际上是"线路中的线路",所不同的是,由 VPN 组成的线路物理上是不存在的,是通过技术手段虚拟出来的。它为两台计算机建立一个逻辑上的专用通道,具有良好的保密和不受干扰性,使双方能进行自由而安全的点对点连接。
VPN 根据用户的身份和权限,在茫茫的广域网中为用户拉出一条专线。

VPN 是对企业内部网的扩展,它可以帮助异地用户、公司分支机构、商业伙伴及供应商同公司的内部网建立可信的安全连接,并保证数据的安全传输。
客户不必再租用昂贵的专线,只需购买 VPN 硬件设备或 VPN 软件产品以及一定的上网费用。


Cloud_28:VLAN 原理详解(摘录+整理)

1. 什么是 LAN ?
局域网(Local Area Network,LAN)是指在某一区域内由多台计算机互联成的计算机组。局域网是封闭型的,可以由两台计算机组成,也可以由上千台计算机组成。
局域网一般是通过二层交换机建立的,二层交换机是一种基于 MAC 地址识别、能够完成封装转发数据包功能的网络设备。

2. 什么是广播 ?什么是广播域 ?
广播是一种信息的传播方式,指网络中的某一设备同时向网络中所有的其它设备发送数据,这个数据所能广播到的范围称为广播域。
广播域是指网络中所有能接收到同样广播消息的设备的集合。

3. 什么是 VLAN ?
局域网中的机器 A 想要和机器 B 通信,要在广播域中进行 ARP 广播,来获取机器 B 的 MAC 地址。
这种广播会影响到网络整体的传输性能。

图中,是一个由 5 台二层交换机(交换机1~5)以及连接大量客户机构成的局域网。
交换机 1 收到 ARP 请求后,会把它转发给除接收端口外的其它所有端口,同样,交换机 2 收到 ARP 请求后,也会把它转发给除接收端口外的其它所有端口,.....,最终 ARP 请求会被转发到同一网络中的所有客户机上。
如此一来,一方面广播信息消耗了网络整体的带宽;另一方面,收到广播信息的计算机还要消耗一部分 CPU 来对它进行处理。造成了网络带宽和 CPU 的无谓消耗。
请注意一下,这个 ARP 请求原本是为了获得计算机 B 的 MAC 地址而发出的,也就是说只要计算机 B 能收到就可以了,但结果却是传遍整个网络,导致所有的计算机都收到了它。

那么,网络上都有哪些广播信息呢?
(1)ARP 请求:建立 IP 地址和 MAC 地址的映射关系。
(2)RIP:一种路由协议,每隔 30 秒路由器都会对邻近的其它路由器广播一次路由信息。
(3)DHCP:用于自动设定 IP 地址的协议。
(4)NetBEUI:Windows下使用的网络协议。
(5)IPX:Novell Netware 使用的网络协议。
(6)Apple Talk:苹果公司的 Macintosh 计算机使用的网络协议。

因此,如果能够有效地分割广播域,就可以减少网络中不必要的消息广播。
在二层交换机上分割广播域的技术,就是 VLAN。

4. 如何实现 VLAN ?
在交换机上生成红、蓝两个 VLAN:同时设置端口 1 和 2 属于红色 VLAN;端口 3 和 4 属于蓝色 VLAN。
这样设置以后,广播消息只会转发给同属于一个 VLAN 的其它端口。
就这样,VLAN 通过限制广播转发的范围分割了广播域。可以理解为将一台交换机在逻辑上分割成了数台虚拟交换机。


注意,在交换机上设置 VLAN 后,如果未做其它处理,VLAN 之间是互不相通的。
明明接在同一台交换机上,但却无法通信,这个事实可能让人难以接受。
那么,如果 VLAN 之间需要通信时怎么办 ?
VLAN 之间的通信需要路由器提供中继服务,可以使用普通的路由器,也可以使用三层交换机。

5. VLAN 的划分方式

5.1 静态 VLAN
静态 VLAN 是基于端口的 VLAN,顾名思义,就是明确指定各端口属于哪个 VLAN 的设定方法。
由于需要一个个端口地指定,因此当网络中的计算机数目超过上百台后,设定操作就会变得烦杂无比。
并且,客户机每次变更所连端口,都必须同时更改该端口所属 VLAN,这显然不适合那些需要经常改变拓补结构的网络。


5.2 动态 VLAN
动态 VLAN 分为三类:
(1)基于 MAC 地址的 VLAN
(2)基于 IP 地址的 VLAN
(3)基于用户的 VLAN

5.2.1 基于 MAC 地址的 VLAN
通过查询并记录端口所连计算机上网卡的 MAC 地址来决定端口的所属 VLAN。即无论机器连在交换机哪个端口,该机器都属于同一个 VLAN。
如果计算机更换了网卡,还是需要更改设定。
由于是基于 MAC 地址决定所属 VLAN,因此这是一种在 OSI 第二层设定访问连接的办法。


5.2.2 基于 IP 地址的 VLAN
通过所连计算机的 IP 地址来决定端口所属 VLAN。即只要机器的 IP 地址不变,该机器都属于同一个 VLAN。
因此,与基于 MAC 地址的 VLAN 相比,基于 IP 地址的 VLAN 设定更为灵活,是一种在 OSI 的第三层设定访问连接的方法。


5.2.3 基于用户的 VLAN
根据交换机各端口连接的的计算机上的当前登录的用户来决定该端口属于哪个 VLAN。
这里的用户是操作系统的用户,是一种在 OSI 的第四层以上设定访问连接的方法。

6. 如何实现跨多台交换机的 VLAN ?
到此为止,讲的都是使用单台交换机如何设置 VLAN。如何实现跨多台交换机的 VLAN ?
如下图所示,此时,交换机 1 和交换机 2 该如何连接呢 ?


最简单的方法,当然是在交换机 1 和交换机 2 上各设一个红、蓝 VLAN 专用的接口,然后用网线互联。
但是,这个办法从扩展性和管理效率来看都不好。
比如,在现有网络基础上再新建 VLAN 时,为了让这个 VLAN 能够互通,就需要在交换机间连接新的网线。并且,VLAN 越多,交换机间互联所需的端口也越来越多,交换机端口的利用效率会很低,是对资源的一种浪费,也限制了网络的扩展。
为了避免这种低效率的连接方式,人们想办法让交换机间互联的网线集中到一根上,这就是汇聚链接(Trunk Link)。

6.1 什么是汇聚链接 ?
汇聚链接(Trunk Link)指的是能够转发多个不同 VLAN 的通信的端口。
汇聚链路上流通的数据帧,都被附加了用于识别分属于哪个 VLAN 的特殊信息。
用户只需要简单地将交换机间互联的端口设定为汇聚链接就可以了。
我们看看汇聚链接是如何实现跨越交换机间的 VLAN 的:
(1) A 发送的数据帧从交换机 1 经过汇聚链路到达交换机 2 时,在数据帧上附加了表示属于红色 VLAN 的标记。
(2) 交换机 2 收到数据帧后,经过检查 VLAN 标识后,发现这个数据帧是属于红色 VLAN 的,因此去除标记后,根据需要将原始的数据帧只转发给其它属于红色 VLAN 的端口。


另外,由于汇聚链路上流通着多个 VLAN 的数据,负载较重。因此,在设定汇聚链接时,必须支持 100Mbps 以上的传输速度。
另外,默认条件下,汇聚链接(端口)会转发交换机上存在的所有 VLAN 的数据。换一个角度看,可以认为汇聚链接(端口)同时属于交换机上所有的 VLAN。

6.2 VLAN 的汇聚方式
在交换机的汇聚链接上,通过对数据帧附加 VLAN 信息,可以构建跨越多台交换机的 VLAN。
附加VLAN信息的方法,最具有代表性的有:IEEE 802.1Q 和 ISL。

6.2.1 IEEE 802.1Q
IEEE 802.1Q,俗称“Dot One Q”,是经过IEEE认证的对数据帧附加VLAN识别信息的协议。
在此,请大家先回忆一下以太网数据帧的标准格式。
IEEE 802.1Q 所附加的 VLAN 识别信息,位于以太网数据帧中的“发送源 MAC 地址”与“类型”之间。具体内容为 2 字节的 TPID(Tag Protocol IDentifier)和 2 字节的 TCI(Tag Control Information),共计 4 字节。
TPID 的值固定为 0x8100,它标示网络帧承载的 802.1Q 类型,交换机通过它来确定数据帧内附加了基于 IEEE 802.1Q 的 VLAN 信息。
真正的 VLAN ID,保存在 TCI中,一共有 12 位,因此最多可供识别 4096 个 VLAN。
在数据帧中添加了 4 字节的内容,那么循环冗余校验(Cyclic Redundancy Check, CRC) 值也会有所变化。
而当数据帧离开汇聚链路时,TPID 和 TCI 会被去除,这时会重新计算 CRC 。


6.2.2 ISL(Inter Switch Link)
ISL 是 Cisco 支持的一种与 IEEE 802.1Q 类似的、用于在汇聚链路上附加 VLAN 信息的协议。
使用 ISL 后,每个数据帧头部都会被附加 26 字节的 ISL Header,并且在帧尾附带上通过对包括 ISL Header 在内的整个数据帧进行计算后得到的 4字节 CRC 值。
总共增加了 30 字节的信息。
在使用 ISL 的环境下,由于原先的数据帧及其 CRC 都被完整保留,无需重新计算 CRC,因此当数据帧离开汇聚链路时,只要简单地去除 ISL Header和新 CRC 就可以了。



7. 如何实现 VLAN 之间的路由 ?
在使用路由器进行 VLAN 间路由时,与构建横跨多台交换机的 VLAN 时的情况类似,还是会遇到“该如何连接路由器与交换机”这个问题。
路由器和交换机的接线方式,大致有以下两种:
(1)将路由器与交换机上的每个 VLAN 分别连接。
(2)不论 VLAN 有多少个,路由器与交换机之间使用汇聚链接,只用一条网线连接。
采用(1)的办法,不难想象它的扩展性很成问题。每增加一个新的 VLAN,都需要消耗路由器的端口和交换机上的访问链接,而且还需要重新布设一条网线。
采用(2)的办法,即使之后在交换机上新建 VLAN,仍只需要一条网线连接交换机和路由器。只需要在路由器上新设一个对应新 VLAN 的子接口就可以了。


因此一般采用第 (2) 种方法,具体实现过程为:
(1)首先将用于连接路由器的交换机端口设为汇聚链接(Trunk Link),而路由器上的端口也必须支持汇聚链路。
(2)双方用于汇聚链路的协议自然也必须相同。
(3)在路由器上定义对应各个 VLAN 的子接口。尽管实际与交换机连接的物理端口只有一个,但可以把它分割为多个虚拟端口。
VLAN 将交换机从逻辑上分割成了多台,因而用于 VLAN 间路由的路由器,也必须拥有分别对应各个 VLAN 的虚拟接口。

7.1 同一 VLAN 内的通信

(1)计算机 A 发出 ARP 请求信息,请求解析 B 的 MAC 地址。
(2)交换机收到数据帧后,检索 MAC 地址列表中与收信端口同属一个 VLAN 的表项。结果发现,计算机 B 连接在端口 2 上,于是交换机将数据帧转发给端口 2,最终计算机 B 收到该帧。
收发信双方同属一个 VLAN 之内的通信,一切处理均在交换机内完成。

7.2 不同 VLAN 间的通信

(1)计算机 A 从通信目标的 IP 地址(192.168.2.1)得出 计算机 C 与本机不属于同一个网段。因此会向设定的默认网关发数据帧。在发送数据帧之前,需要先用 ARP 获取路由器的 MAC 地址。
(2)得到路由器的 MAC 地址 R 后,接下来就是按图中所示的步骤发送往 计算机 C 的数据帧。

参考文献:
1. http://blog.csdn.net/phunxm/article/details/9498829/