台達電動車充電座首度結合建案

看好電動車潛力,台中建商與台達電子合作,於新完工大樓採用台達電的電動車充電解決方案,設置兩座通用型快速充電站,充電30分鐘即可上路。

通用型充電站指Tesla之外的電動車皆適用,Tesla則要使用超級充電站(Supercharger),目前僅有台北花博公園有設置Tesla的超級充電站。

2017年1月,台達協助BMW台灣總代理汎德於台北市20處停車場建置40座電動車充電座;4月時又再次為汎德於台北101大樓建置直流和交流充電器。

(首圖來源:public domain CC0)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※教你寫出一流的銷售文案?

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

中國電動車補助改變,必翔出貨受阻、財報有困難

根據櫃買中心重大訊息公告,電動車及輔具廠商必翔實業,因子公司仍有許多待釐清事項,財報無法如期交出,因此18 日起將暫停交易。而且檢調也對必翔實業進行搜索,並且約談董事長蔣伍清明。在無法如期交出財報的消息傳出後,必翔16 日股價再度跌停板,已經連續10 個交易日跌停,股價由54.6 元下跌至每股19.2 元,跌幅超過64%。

據了解,必翔旗下子公司必翔電,近年在中國積極發展磷酸鋰鐵電池,而且在2014 年底獲得寧波雙鹿集團簽署新能源項目合作暨商務採購協議,當時成為能源類股當紅炸子雞。但是,由於中國官方的電動車補助政策改變,使得必翔電出貨受阻之外,還面臨收款不順的困境。

近期必翔電的輔導券商元大證,以及協辦券商德信證雙雙辭任雙雙辭任,還出現董事解職潮。未來,若無法順利找到輔導的券商,必翔電恐將面臨自興櫃下市的處境。

而根據必翔的公告指出,必翔之所以未能如期提交首季財報,主要因子公司揚明實業 (浙江) 在寧波所開立的二家銀行帳戶現金及相關投資理財商品合計人民幣1.7 億元,其管理及控制的合理性有待釐清。另外,另一子公司必翔電能方面共有包括營收、應收帳款、備抵呆帳以及存貨等合理性,也有進一步釐清的必要。該公司公告表示,已啟動跨境查核專案,委請專業人員組成查核小組跨境查核,將會盡速釐清問題,再補行公告。

而對於必翔無法如期交出財報,證交所表示將依證交所營業細則第50 條第1 項第1 款規定情事,公告自5 月18 日起,將停止有價證券之買賣。另外,檢調單位也於16 日至必翔公司進行搜索,並約談董事長蔣伍清明。

(合作媒體:。圖片出處:必翔)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

FB行銷專家,教你從零開始的技巧

野火、熱浪不止!澳洲全國均溫40.9℃ 創逾百年最熱日

摘錄自2019年12月18日自由時報澳洲報導

澳洲近期野火不止,又出現熱浪席捲,17日全國平均溫度達到了40.9℃,創下澳洲有紀錄以來最熱的一天。

綜合外媒報導,澳洲氣象部門表示,週二(17日)全國平均溫度高達40.9℃,打破2013年1月7日的全國均溫40.3℃,是澳洲自1910年有紀錄以來最熱的一天,澳洲內陸地區多地高溫都破45℃,澳洲氣象部門警告,預計在未來幾天內,這股熱浪將繼續積聚,恐再創新高溫紀錄。

除了高溫外,澳洲也面臨乾旱問題,今年9月至11月,澳洲經歷百年來最乾旱及第二高溫的春季,目前東岸仍有超過100處野火,高溫及乾旱加劇野火延燒,消防單位疲於奔命,目前已768棟房遭燒毀。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

※教你寫出一流的銷售文案?

※超省錢租車方案

FB行銷專家,教你從零開始的技巧

暖冬雪下太少!東奧觀賽席「人工雪」恐難施行

摘錄自2020年2月27日民視新聞網報導

距離東京奧運開幕只剩下不到150天,日本近年夏天的高溫氣候恐為參賽選手和民眾帶來不小負擔。雖然東奧組委會先前想過,在觀賽席降下人工雪,或是從其他地區徵用積雪,製作雪包為民眾降溫,但這項計畫也受到今年日本暖冬天氣影響,恐怕難以施行。

日本氣象廳公布,今年國內的長期氣象預報,當中說到將舉辦奧運的6~8月,日本全國各地將會因太平洋高氣壓出現比往年夏天更熱的酷暑氣候,氣象廳也呼籲民眾要預先做好抗暑對策。

除了人工雪外,東奧組委會想出的另一個計畫,就是和有雪國稱號的東北新潟縣南魚沼市合作,在當地的儲雪場收集100噸雪備用,未來在賽事期間製成雪包提供給觀眾消暑。但南魚沼降雪量嚴重不足,消暑雪包計畫要執行難度恐怕很高。而暖冬也為冬季的滑雪觀光產業帶來嚴重衝擊。

面對來勢洶洶的酷暑,東奧組委會除了將部分賽事的舉辦時間提前,先前也決定將馬拉松挪至札幌舉辦,試圖降低高溫影響,但效果如何還有待觀察。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※別再煩惱如何寫文案,掌握八大原則!

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※超省錢租車方案

※教你寫出一流的銷售文案?

網頁設計最專業,超強功能平台可客製化

厄瓜多原民擁抱太陽能獨木舟 盼對抗石油業入侵亞馬遜

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※教你寫出一流的銷售文案?

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

馴獸師遭棕熊攻擊 觀眾還以為是表演

摘錄自2019年10月26日三立新聞網俄羅斯報導

俄羅斯一知名馬戲團日前一名馴獸師與一隻300公斤中大棕熊進行表演,沒想到過程中大棕熊卻突然襲擊馴獸師,當下觀眾還以為是表驗內容,直到另一名馴獸師狠踹大棕熊,才引起觀眾一陣恐慌,紛紛往門口逃竄。事後馬戲團發出聲明,疑似是觀眾不斷拍照開閃光燈拍惹的禍,但所幸好馴獸師和大棕熊都沒有受到嚴重傷害。

綜合外媒報導,來自沃羅涅日州(Voronezh)的俄羅斯安史拉格馬戲團(Anshlag traveling circus)近來進行全國巡迴表演,不料日前23日卻發一起恐怖事件,馬戲團內一隻遭訓養重達660磅(近300公斤)的大棕熊,卻在表演中突然攻擊馴獸師。

影片中可見,一名馴獸師引導大棕熊推獨輪車之後,並給予大棕熊獎勵,但不知是大棕熊感覺獎勵不夠,還是怎麼了;大棕熊突然咬住馴獸師的手臂,之後將馴獸師撲倒在地,而現場觀眾看到該幕,還以為是表演內容,直到另一名訓練師上前踹了大棕熊3腳,才驚慌紛紛往門口逃竄。

報導指出,安史拉格巡迴表演馬戲團舞台上完全沒有設置柵欄,現場觀眾與舞台上的動物距離也只有數公尺,不過此事件沒有觀眾受到傷,而大棕熊事後也被電擊槍等制伏、甚至遭攻擊的馴獸師也沒有受到太重的傷。

對此,馬戲團經理明絲尼克(Lyudmila Misnik)表示,疑似是觀眾拍照時忘記關閉閃光燈,導致大棕熊受到驚嚇攻擊馴獸師,不過所幸訓練師和大棕熊均無大礙;並保證接下來的表演,包括狗、浣熊、大蟒蛇、猴子、鸚鵡,還有經典的空中飛人、魔術表演、鋼鐵人和小丑等將會如期舉行,但他也再次呼籲到場觀看表演民眾,拍照時務必關掉閃光燈,避免類似事件再次發生。

 

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

FB行銷專家,教你從零開始的技巧

德國將蓋鋰電池廠制衡Tesla,鋰電池成本望下滑

特斯拉(Tesla)懷著超級工廠大夢,準備在電池領域一統江湖,歐洲強國也不甘示弱,德國總理梅克爾(Angela Merkel)參加德國戴姆勒汽車(Daimler)斥資5 億歐元興建的鋰電池工廠的動土典禮,這項歐洲大陸的超級電池工廠計畫,將挑戰Tesla 在綠色電力領域的領導地位。

彭博報導,德國電池工廠位於柏林南部130 公里處,突顯主要汽車製造商和電力公司進入儲能的行動,這項技術對推動下一代綠色車輛,以及在需要時儲存風力與太陽能電力上至關重要。報導認為,隨著汽車製造商與電力公司同步發展,電池成本可能會迅速下滑。

彭博分析師認為,電池成本下降與能源密度增加,預計2030 年就可以看到電動車比燃料汽車更便宜的情況。根據彭博新能源財經(BNEF)數據,全球電池製造產能將在2021 年翻倍,達到2.78 億度,現在約1.03 億度,屆時歐洲市場佔比將從現在的2.5% 提高一倍。

瑞典、匈牙利和波蘭計劃中的大型工廠,以及戴姆勒在德國的電池組裝廠,預計會為福斯與雷諾等汽車製造商提供需求,屆時鋰離子電池成本將降低43%,使電動汽車成為主流。

對於公用事業而言,便宜的電池可以降低儲存單元的成本,儲存單元可將變動型再生能源如風能與太陽能的電力傳送至電網。義大利國家電力公司Enel SpA 將電池與風力發電場配套使用,電網管理人員對電力輸出的預測準度因此提高30%。

1990 年代初期消費類電子產品如電腦和手機使用的鋰離子電池,已經跨界應用於運輸和電力行業,但礙於成本,鋰電池在電網和汽車上的應用才剛剛開始,電池的興起對於電動汽車的消費者來說最為明顯,大多數主要汽車製造商將充電式電動車訂為未來10 年的中期計劃。

目前電池業務仍由亞洲電子製造商所主導。根據BNEF,韓國LG 和三星SDI 是頂級供應商,亞洲有望繼續保持領先地位,中國另有8 個工廠正在興建。

汽車製造商採取行動確保電池供應源,戴姆勒的工廠將是歐洲最大的工廠,供應旗下汽車與梅賽德斯賓士,並與屋頂太陽能安裝商Vivint Solar 合資生產家庭能源儲存系統。

2017 年1 月Tesla 的工廠完成三分之一,完工後每年產能可達35 千兆瓦,足以支持每年生產50 萬輛電動車,這將使Tesla 成為繼LG 化學之後的第2 大供應商,特斯拉也在計畫興建更多超級工廠。

戴姆勒的投資規模較小,且尚未披露產能目標。福斯正在與電池廠商討論投資項目,並計劃在德國興建原型組裝廠以開發自己的技術。位於斯德哥爾摩的創業公司NorthVolt AB 宣布計劃在2023 年在瑞典設立一家40 億歐元的電池廠。鋰電池產量大增可望降低所有應用的電池成本,讓家庭和電網的儲存更加實惠。

未來10 年電動汽車價格可望能與汽油或柴油車競爭,由於電池組是充電電動車中最昂貴的部分,佔總成本的三分之一,預計到2021 年,鋰離子電池將便宜43%,從目前的每千瓦273 美元降至156 美元。

鋰電池普及是可以預見的事,但問題是儲存對消費者或大型公用事業而言是否有利可圖仍然是一個懸而未決的問題。即使如此,電動汽車廠商也正在尋找未來,根據BNEF,2030 年前充電式電動車可能佔新車銷售的五分之一,即2,100 萬台。梅克爾訪問戴姆勒工廠展現了德國政府計劃2030 年讓600 萬輛電動汽車上路的決心。

(合作媒體:。圖片出處:Tesla)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

容器技術之Docker-swarm

  前文我聊到了docker machine的簡單使用和基本原理的說明,回顧請參考https://www.cnblogs.com/qiuhom-1874/p/13160915.html;今天我們來聊一聊docker集群管理工具docker swarm;docker swarm是docker 官方的集群管理工具,它可以讓跨主機節點來創建,管理docker 集群;它的主要作用就是可以把多個節點主機的docker環境整合成一個大的docker資源池;docker swarm面向的就是這個大的docker 資源池在上面管理容器;在前面我們都只是在單台主機上的創建,管理容器,但是在生產環境中通常一台物理機上的容器實在是不能夠滿足當前業務的需求,所以docker swarm提供了一種集群解決方案,方便在多個節點上創建,管理容器;接下來我們來看看docker swarm集群的搭建過程吧;

  docker swarm 在我們安裝好docker時就已經安裝好了,我們可以使用docker info來查看

[root@node1 ~]# docker info
Client:
 Debug Mode: false

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 19.03.11
 Storage Driver: overlay2
  Backing Filesystem: xfs
  Supports d_type: true
  Native Overlay Diff: true
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd
 init version: fec3683
 Security Options:
  seccomp
   Profile: default
 Kernel Version: 3.10.0-693.el7.x86_64
 Operating System: CentOS Linux 7 (Core)
 OSType: linux
 Architecture: x86_64
 CPUs: 4
 Total Memory: 3.686GiB
 Name: docker-node01
 ID: 4HXP:YJ5W:4SM5:NAPM:NXPZ:QFIU:ARVJ:BYDG:KVWU:5AAJ:77GC:X7GQ
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
  provider=generic
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false

[root@node1 ~]# 

  提示:從上面的信息可以看到,swarm是處於非活躍狀態,這是因為我們還沒有初始化集群,所以對應的swarm選項的值是處於inactive狀態;

  初始化集群

[root@docker-node01 ~]# docker swarm init --advertise-addr 192.168.0.41
Swarm initialized: current node (ynz304mbltxx10v3i15ldkmj1) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-6difxlq3wc8emlwxzuw95gp8rmvbz2oq62kux3as0e4rbyqhk3-2m9x12n102ca4qlyjpseobzik 192.168.0.41:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

[root@docker-node01 ~]# 

  提示:從上面反饋的信息可以看到,集群初始化成功,並且告訴我們當前節點為管理節點,如果想要其他節點加入到該集群,可以在對應節點上運行docker swarm join –token SWMTKN-1-6difxlq3wc8emlwxzuw95gp8rmvbz2oq62kux3as0e4rbyqhk3-2m9x12n102ca4qlyjpseobzik 192.168.0.41:2377 這個命令,就把對應節點當作work節點加入到該集群,如果想要以管理節點身份加入到集群,我們需要在當前終端運行docker swarm join-token manager命令

[root@docker-node01 ~]# docker swarm join-token manager
To add a manager to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-6difxlq3wc8emlwxzuw95gp8rmvbz2oq62kux3as0e4rbyqhk3-dqjeh8hp6cp99bksjc03b8yu3 192.168.0.41:2377

[root@docker-node01 ~]# 

  提示:我們執行docker swarm join-token manager命令,它返回了一個命令,並告訴我們添加一個管理節點,在對應節點上執行docker swarm join –token SWMTKN-1-6difxlq3wc8emlwxzuw95gp8rmvbz2oq62kux3as0e4rbyqhk3-dqjeh8hp6cp99bksjc03b8yu3 192.168.0.41:2377命令即可;

  到此docker swarm集群就初始化完畢,接下來我們把其他節點加入到該集群

  把docker-node02以work節點身份加入集群

[root@node2 ~]# docker swarm join --token SWMTKN-1-6difxlq3wc8emlwxzuw95gp8rmvbz2oq62kux3as0e4rbyqhk3-2m9x12n102ca4qlyjpseobzik 192.168.0.41:2377
This node joined a swarm as a worker.
[root@node2 ~]# 

  提示:沒有報錯就表示加入集群成功;我們可以使用docker info來查看當前的docker 環境詳細信息

  提示:從上面的信息可以看到,在docker-node02這台主機上docker swarm 已經激活,並且可以看到管理節點的地址;除了以上方式可以確定docker-node02以及加入到集群;我們還可以在管理節點上運行docker node ls 查看集群節點信息;

  查看集群節點信息

  提示:在管理節點上運行docker node ls 就可以列出當前集群里有多少節點已經成功加入進來;

  把docker-node03以管理節點身份加入到集群

  提示:可以看到docker-node03已經是集群的管理節點,所以可以在docker-node03這個節點執行docker node ls 命令;到此docker swarm集群就搭建好了;接下來我們來說一說docker swarm集群的常用管理

  有關節點相關管理命令

  docker node ls :列出當前集群上的所有節點

[root@docker-node01 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
ynz304mbltxx10v3i15ldkmj1 *   docker-node01       Ready               Active              Leader              19.03.11
tzkm0ymzjdmc1r8d54snievf1     docker-node02       Ready               Active                                  19.03.11
aeo8j7zit9qkoeeft3j0q1h0z     docker-node03       Ready               Active              Reachable           19.03.11
[root@docker-node01 ~]# 

  提示:該命令只能在管理節點上執行;

  docker node inspect :查看指定節點的詳細信息;

[root@docker-node01 ~]# docker node inspect docker-node01
[
    {
        "ID": "ynz304mbltxx10v3i15ldkmj1",
        "Version": {
            "Index": 9
        },
        "CreatedAt": "2020-06-20T05:57:17.57684293Z",
        "UpdatedAt": "2020-06-20T05:57:18.18575648Z",
        "Spec": {
            "Labels": {},
            "Role": "manager",
            "Availability": "active"
        },
        "Description": {
            "Hostname": "docker-node01",
            "Platform": {
                "Architecture": "x86_64",
                "OS": "linux"
            },
            "Resources": {
                "NanoCPUs": 4000000000,
                "MemoryBytes": 3958075392
            },
            "Engine": {
                "EngineVersion": "19.03.11",
                "Labels": {
                    "provider": "generic"
                },
                "Plugins": [
                    {
                        "Type": "Log",
                        "Name": "awslogs"
                    },
                    {
                        "Type": "Log",
                        "Name": "fluentd"
                    },
                    {
                        "Type": "Log",
                        "Name": "gcplogs"
                    },
                    {
                        "Type": "Log",
                        "Name": "gelf"
                    },
                    {
                        "Type": "Log",
                        "Name": "journald"
                    },
                    {
                        "Type": "Log",
                        "Name": "json-file"
                    },
                    {
                        "Type": "Log",
                        "Name": "local"
                    },
                    {
                        "Type": "Log",
                        "Name": "logentries"
                    },
                    {
                        "Type": "Log",
                        "Name": "splunk"
                    },
                    {
                        "Type": "Log",
                        "Name": "syslog"
                    },
                    {
                        "Type": "Network",
                        "Name": "bridge"
                    },
                    {
                        "Type": "Network",
                        "Name": "host"
                    },
                    {
                        "Type": "Network",
                        "Name": "ipvlan"
                    },
                    {
                        "Type": "Network",
                        "Name": "macvlan"
                    },
                    {
                        "Type": "Network",
                        "Name": "null"
                    },
                    {
                        "Type": "Network",
                        "Name": "overlay"
                    },
                    {
                        "Type": "Volume",
                        "Name": "local"
                    }
                ]
            },
            "TLSInfo": {
                "TrustRoot": "-----BEGIN CERTIFICATE-----\nMIIBaTCCARCgAwIBAgIUeBd/eSZ7WaiyLby9o1yWpjps3gwwCgYIKoZIzj0EAwIw\nEzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMjAwNjIwMDU1MjAwWhcNNDAwNjE1MDU1\nMjAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH\nA0IABMsYxnGoPbM4gqb23E1TvOeQcLcY56XysLuF8tYKm56GuKpeD/SqXrUCYqKZ\nHV+WSqcM0fD1g+mgZwlUwFzNxhajQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB\nAf8EBTADAQH/MB0GA1UdDgQWBBTV64kbvS83eRHyI6hdJeEIv3GmrTAKBggqhkjO\nPQQDAgNHADBEAiBBB4hLn0ijybJWH5j5rtMdAoj8l/6M3PXERnRSlhbcawIgLoby\newMHCnm8IIrUGe7s4CZ07iHG477punuPMKDgqJ0=\n-----END CERTIFICATE-----\n",
                "CertIssuerSubject": "MBMxETAPBgNVBAMTCHN3YXJtLWNh",
                "CertIssuerPublicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEyxjGcag9sziCpvbcTVO855BwtxjnpfKwu4Xy1gqbnoa4ql4P9KpetQJiopkdX5ZKpwzR8PWD6aBnCVTAXM3GFg=="
            }
        },
        "Status": {
            "State": "ready",
            "Addr": "192.168.0.41"
        },
        "ManagerStatus": {
            "Leader": true,
            "Reachability": "reachable",
            "Addr": "192.168.0.41:2377"
        }
    }
]
[root@docker-node01 ~]#

  docker node ps :列出指定節點上運行容器的清單

[root@docker-node01 ~]# docker node ps 
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE       ERROR               PORTS
[root@docker-node01 ~]# docker node ps docker-node01
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE       ERROR               PORTS
[root@docker-node01 ~]# 

  提示:類似docker ps 命令,我上面沒有運行容器,所以看不到對應信息;默認不指定節點名稱表示查看當前節點上的運行容器清單;

  docker node rm :刪除指定節點

[root@docker-node01 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
ynz304mbltxx10v3i15ldkmj1 *   docker-node01       Ready               Active              Leader              19.03.11
tzkm0ymzjdmc1r8d54snievf1     docker-node02       Ready               Active                                  19.03.11
aeo8j7zit9qkoeeft3j0q1h0z     docker-node03       Ready               Active              Reachable           19.03.11
[root@docker-node01 ~]# docker node rm docker-node03
Error response from daemon: rpc error: code = FailedPrecondition desc = node aeo8j7zit9qkoeeft3j0q1h0z is a cluster manager and is a member of the raft cluster. It must be demoted to worker before removal
[root@docker-node01 ~]# docker node rm docker-node02
Error response from daemon: rpc error: code = FailedPrecondition desc = node tzkm0ymzjdmc1r8d54snievf1 is not down and can't be removed
[root@docker-node01 ~]# 

  提示:刪除節點前必須滿足,被刪除的節點不是管理節點,其次就是要刪除的節點必須是down狀態;

  docker swarm leave:離開當前集群

[root@docker-node03 ~]# docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
e7958ffa16cd        nginx               "/docker-entrypoint.…"   28 seconds ago      Up 26 seconds       80/tcp              n1
[root@docker-node03 ~]# docker swarm leave 
Error response from daemon: You are attempting to leave the swarm on a node that is participating as a manager. Removing this node leaves 1 managers out of 2. Without a Raft quorum your swarm will be inaccessible. The only way to restore a swarm that has lost consensus is to reinitialize it with `--force-new-cluster`. Use `--force` to suppress this message.
[root@docker-node03 ~]# docker swarm leave -f
Node left the swarm.
[root@docker-node03 ~]# 

  提示:管理節點默認是不允許離開集群的,如果強制使用-f選項離開集群,會導致在其他管理節點無法正常管理集群;

[root@docker-node01 ~]# docker node ls
Error response from daemon: rpc error: code = Unknown desc = The swarm does not have a leader. It's possible that too few managers are online. Make sure more than half of the managers are online.
[root@docker-node01 ~]#

  提示:我們在docker-node01上現在就不能使用docker node ls 來查看集群節點列表了;解決辦法重新初始化集群;

[root@docker-node01 ~]# docker node ls 
Error response from daemon: rpc error: code = Unknown desc = The swarm does not have a leader. It's possible that too few managers are online. Make sure more than half of the managers are online.
[root@docker-node01 ~]# docker swarm init --advertise-addr 192.168.0.41
Error response from daemon: This node is already part of a swarm. Use "docker swarm leave" to leave this swarm and join another one.
[root@docker-node01 ~]# docker swarm init --force-new-cluster 
Swarm initialized: current node (ynz304mbltxx10v3i15ldkmj1) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-6difxlq3wc8emlwxzuw95gp8rmvbz2oq62kux3as0e4rbyqhk3-2m9x12n102ca4qlyjpseobzik 192.168.0.41:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

[root@docker-node01 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
ynz304mbltxx10v3i15ldkmj1 *   docker-node01       Ready               Active              Leader              19.03.11
tzkm0ymzjdmc1r8d54snievf1     docker-node02       Unknown             Active                                  19.03.11
aeo8j7zit9qkoeeft3j0q1h0z     docker-node03       Down                Active                                  19.03.11
rm3j7cjvmoa35yy8ckuzoay46     docker-node03       Unknown             Active                                  19.03.11
[root@docker-node01 ~]# 

  提示:重新初始化集群不能使用docker swarm init –advertise-addr 192.168.0.41這種方式初始化,必須使用docker swarm init –force-new-cluster,該命令表示使用從當前狀態強制創建一個集群;現在我們就可以使用docker node rm 把down狀態的節點從集群刪除;

  刪除down狀態的節點

[root@docker-node01 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
ynz304mbltxx10v3i15ldkmj1 *   docker-node01       Ready               Active              Leader              19.03.11
tzkm0ymzjdmc1r8d54snievf1     docker-node02       Ready               Active                                  19.03.11
aeo8j7zit9qkoeeft3j0q1h0z     docker-node03       Down                Active                                  19.03.11
rm3j7cjvmoa35yy8ckuzoay46     docker-node03       Down                Active                                  19.03.11
[root@docker-node01 ~]# docker node rm aeo8j7zit9qkoeeft3j0q1h0z rm3j7cjvmoa35yy8ckuzoay46
aeo8j7zit9qkoeeft3j0q1h0z
rm3j7cjvmoa35yy8ckuzoay46
[root@docker-node01 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
ynz304mbltxx10v3i15ldkmj1 *   docker-node01       Ready               Active              Leader              19.03.11
tzkm0ymzjdmc1r8d54snievf1     docker-node02       Ready               Active                                  19.03.11
[root@docker-node01 ~]# 

  docker node promote:把指定節點提升為管理節點

[root@docker-node01 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
ynz304mbltxx10v3i15ldkmj1 *   docker-node01       Ready               Active              Leader              19.03.11
tzkm0ymzjdmc1r8d54snievf1     docker-node02       Ready               Active                                  19.03.11
[root@docker-node01 ~]# docker node promote docker-node02
Node docker-node02 promoted to a manager in the swarm.
[root@docker-node01 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
ynz304mbltxx10v3i15ldkmj1 *   docker-node01       Ready               Active              Leader              19.03.11
tzkm0ymzjdmc1r8d54snievf1     docker-node02       Ready               Active              Reachable           19.03.11
[root@docker-node01 ~]# 

  docker node demote:把指定節點降級為work節點

[root@docker-node01 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
ynz304mbltxx10v3i15ldkmj1 *   docker-node01       Ready               Active              Leader              19.03.11
tzkm0ymzjdmc1r8d54snievf1     docker-node02       Ready               Active              Reachable           19.03.11
[root@docker-node01 ~]# docker node demote docker-node02
Manager docker-node02 demoted in the swarm.
[root@docker-node01 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
ynz304mbltxx10v3i15ldkmj1 *   docker-node01       Ready               Active              Leader              19.03.11
tzkm0ymzjdmc1r8d54snievf1     docker-node02       Ready               Active                                  19.03.11
[root@docker-node01 ~]# 

  docker node update:更新指定節點

[root@docker-node01 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
ynz304mbltxx10v3i15ldkmj1 *   docker-node01       Ready               Active              Leader              19.03.11
tzkm0ymzjdmc1r8d54snievf1     docker-node02       Ready               Active                                  19.03.11
[root@docker-node01 ~]# docker node update docker-node01 --availability drain 
docker-node01
[root@docker-node01 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
ynz304mbltxx10v3i15ldkmj1 *   docker-node01       Ready               Drain               Leader              19.03.11
tzkm0ymzjdmc1r8d54snievf1     docker-node02       Ready               Active                                  19.03.11
[root@docker-node01 ~]# 

  提示:以上命令把docker-node01的availability屬性更改為drain,這樣更改后docker-node01的資源就不會被調度到用來運行容器;

  為docker swarm集群添加圖形界面

[root@docker-node01 docker]# docker run --name v1 -d -p 8888:8080 -e HOST=192.168.0.41 -e PORT=8080 -v /var/run/docker.sock:/var/run/docker.sock docker-registry.io/test/visualizer
Unable to find image 'docker-registry.io/test/visualizer:latest' locally
latest: Pulling from test/visualizer
cd784148e348: Pull complete 
f6268ae5d1d7: Pull complete 
97eb9028b14b: Pull complete 
9975a7a2a3d1: Pull complete 
ba903e5e6801: Pull complete 
7f034edb1086: Pull complete 
cd5dbf77b483: Pull complete 
5e7311667ddb: Pull complete 
687c1072bfcb: Pull complete 
aa18e5d3472c: Pull complete 
a3da1957bd6b: Pull complete 
e42dbf1c67c4: Pull complete 
5a18b01011d2: Pull complete 
Digest: sha256:54d65cbcbff52ee7d789cd285fbe68f07a46e3419c8fcded437af4c616915c85
Status: Downloaded newer image for docker-registry.io/test/visualizer:latest
3c15b186ff51848130393944e09a427bd40d2504c54614f93e28477a4961f8b6
[root@docker-node01 docker]# docker ps 
CONTAINER ID        IMAGE                                COMMAND             CREATED             STATUS                            PORTS                    NAMES
3c15b186ff51        docker-registry.io/test/visualizer   "npm start"         6 seconds ago       Up 5 seconds (health: starting)   0.0.0.0:8888->8080/tcp   v1
[root@docker-node01 docker]# 

  提示:我上面的命令是從私有倉庫中下載的鏡像,原因是互聯網下載太慢了,所以我提前下載好,放在私有倉庫中;有關私有倉庫的搭建使用,請參考https://www.cnblogs.com/qiuhom-1874/p/13061984.html或者https://www.cnblogs.com/qiuhom-1874/p/13058338.html;在管理節點上運行visualizer容器后,我們就可以直接訪問該管理節點地址的8888端口,就可以看到當前容器的情況;如下圖

  提示:從上面的信息可以看到當前集群有一個管理節點和兩個work節點;現目前集群里沒有運行任何容器;

  在docker swarm運行服務

[root@docker-node01 ~]# docker service create --name myweb docker-registry.io/test/nginx:latest
i0j6wvvtfe1360ibj04jxulmd
overall progress: 1 out of 1 tasks 
1/1: running   [==================================================>] 
verify: Service converged 
[root@docker-node01 ~]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                                  PORTS
i0j6wvvtfe13        myweb               replicated          1/1                 docker-registry.io/test/nginx:latest   
[root@docker-node01 ~]# docker service ps myweb
ID                  NAME                IMAGE                                  NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
99y8towew77e        myweb.1             docker-registry.io/test/nginx:latest   docker-node03       Running             Running 1 minutes ago                       
[root@docker-node01 ~]#

  提示:docker service create 表示在當前swarm集群環境中創建一個服務;以上命令表示在swarm集群上創建一個名為myweb的服務,用docker-registry.io/test/nginx:latest鏡像;默認情況下只啟動一個副本;

  提示:可以看到當前集群中運行了一個myweb的容器,並且運行在docker-node03這台主機上;

  在swarm 集群上創建多個副本服務

[root@docker-node01 ~]# docker service create --replicas 3 --name web docker-registry.io/test/nginx:latest
mbiap412jyugfpi4a38mb5i1k
overall progress: 3 out of 3 tasks 
1/3: running   [==================================================>] 
2/3: running   [==================================================>] 
3/3: running   [==================================================>] 
verify: Service converged 
[root@docker-node01 ~]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                                  PORTS
i0j6wvvtfe13        myweb               replicated          1/1                 docker-registry.io/test/nginx:latest   
mbiap412jyug        web                 replicated          3/3                 docker-registry.io/test/nginx:latest   
[root@docker-node01 ~]#docker service ps web
ID                  NAME                IMAGE                                  NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
1rt0e7u4senz        web.1               docker-registry.io/test/nginx:latest   docker-node02       Running             Running 28 seconds ago                       
31ll0zu7udld        web.2               docker-registry.io/test/nginx:latest   docker-node02       Running             Running 28 seconds ago                       
l9jtbswl2x22        web.3               docker-registry.io/test/nginx:latest   docker-node03       Running             Running 32 seconds ago                       
[root@docker-node01 ~]# 

  提示:–replicas選項用來指定期望運行的副本數量,該選項會在集群上創建我們指定數量的副本,即便我們集群中有節點宕機,它始終會創建我們指定數量的容器在集群上運行着;

  測試:把docker-node03關機,看看我們運行的服務是否會遷移到節點2上呢?

  docker-node03關機前

  docker-node03關機后

  提示:從上面的截圖可以看到,當節點3宕機后,節點3上跑的所有容器,會全部遷移到節點2上來;這就是創建容器時用–replicas選項的作用;總結一點,創建服務使用副本模式,該服務所在節點故障,它會把對應節點上的服務遷移到其他節點上;這裏需要提醒一點的是,只要集群上的服務副本滿足我們指定的replicas的數量,即便故障的節點恢復了,它是不會把服務遷移回來的;

[root@docker-node01 ~]# docker service ps web
ID                  NAME                IMAGE                                  NODE                DESIRED STATE       CURRENT STATE             ERROR               PORTS
1rt0e7u4senz        web.1               docker-registry.io/test/nginx:latest   docker-node02       Running             Running 15 minutes ago                        
31ll0zu7udld        web.2               docker-registry.io/test/nginx:latest   docker-node02       Running             Running 15 minutes ago                        
t3gjvsgtpuql        web.3               docker-registry.io/test/nginx:latest   docker-node02       Running             Running 6 minutes ago                         
l9jtbswl2x22         \_ web.3           docker-registry.io/test/nginx:latest   docker-node03       Shutdown            Shutdown 23 seconds ago                       
[root@docker-node01 ~]# 

  提示:我們在管理節點查看服務列表,可以看到它遷移服務就是把對應節點上的副本停掉,然後在其他節點創建一個新的副本;

  服務伸縮

[root@docker-node01 ~]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                                  PORTS
i0j6wvvtfe13        myweb               replicated          1/1                 docker-registry.io/test/nginx:latest   
mbiap412jyug        web                 replicated          3/3                 docker-registry.io/test/nginx:latest   
[root@docker-node01 ~]# docker service scale myweb=3 web=5
myweb scaled to 3
web scaled to 5
overall progress: 3 out of 3 tasks 
1/3: running   [==================================================>] 
2/3: running   [==================================================>] 
3/3: running   [==================================================>] 
verify: Service converged 
overall progress: 5 out of 5 tasks 
1/5: running   [==================================================>] 
2/5: running   [==================================================>] 
3/5: running   [==================================================>] 
4/5: running   [==================================================>] 
5/5: running   [==================================================>] 
verify: Service converged 
[root@docker-node01 ~]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                                  PORTS
i0j6wvvtfe13        myweb               replicated          3/3                 docker-registry.io/test/nginx:latest   
mbiap412jyug        web                 replicated          5/5                 docker-registry.io/test/nginx:latest   
[root@docker-node01 ~]# docker service ps myweb web
ID                  NAME                IMAGE                                  NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
j7w490h2lons        myweb.1             docker-registry.io/test/nginx:latest   docker-node02       Running             Running 12 minutes ago                       
1rt0e7u4senz        web.1               docker-registry.io/test/nginx:latest   docker-node02       Running             Running 21 minutes ago                       
99y8towew77e        myweb.1             docker-registry.io/test/nginx:latest   docker-node03       Shutdown            Shutdown 5 minutes ago                       
en5rk0jf09wu        myweb.2             docker-registry.io/test/nginx:latest   docker-node03       Running             Running 31 seconds ago                       
31ll0zu7udld        web.2               docker-registry.io/test/nginx:latest   docker-node02       Running             Running 21 minutes ago                       
h1hze7h819ca        myweb.3             docker-registry.io/test/nginx:latest   docker-node03       Running             Running 30 seconds ago                       
t3gjvsgtpuql        web.3               docker-registry.io/test/nginx:latest   docker-node02       Running             Running 12 minutes ago                       
l9jtbswl2x22         \_ web.3           docker-registry.io/test/nginx:latest   docker-node03       Shutdown            Shutdown 5 minutes ago                       
od3ti2ixpsgc        web.4               docker-registry.io/test/nginx:latest   docker-node03       Running             Running 31 seconds ago                       
n1vur8wbmkgz        web.5               docker-registry.io/test/nginx:latest   docker-node03       Running             Running 31 seconds ago                       
[root@docker-node01 ~]# 

  提示:docker service scale 命令用來指定服務的副本數量,從而實現動態伸縮;

  服務暴露

[root@docker-node01 ~]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                                  PORTS
i0j6wvvtfe13        myweb               replicated          3/3                 docker-registry.io/test/nginx:latest   
mbiap412jyug        web                 replicated          5/5                 docker-registry.io/test/nginx:latest   
[root@docker-node01 ~]# docker service update  --publish-add 80:80 myweb 
myweb
overall progress: 3 out of 3 tasks 
1/3: running   [==================================================>] 
2/3: running   [==================================================>] 
3/3: running   [==================================================>] 
verify: Service converged 
[root@docker-node01 ~]#

  提示:docker swarm集群中的服務暴露和docker裏面的端口暴露原理是一樣的,都是通過iptables 規則表或LVS規則實現的;

  提示:我們可以在管理節點上看到對應80端口已經處於監聽狀態,並且在iptables規則表中多了一項訪問本機80端口都DNAT到172.18.0.2的80上了;其實不光是在管理節點,在work節點上相應的iptables規則也都發生了變化;如下

  提示:從上面的規則來看,我們訪問節點地址的80端口,都會DNAT到172.18.0.2的80;

  提示:從上面是显示結果看,我們不難得知在docker-node02運行myweb容器的內部地址是10.0.0.7,那為什麼我們訪問172.18.0.2是能夠訪問到容器內部的服務呢?

  測試:我們在docker-node02追蹤查看nginx容器的訪問日誌,看看到容器的IP地址是那個?

[root@docker-node02 ~]# docker ps
CONTAINER ID        IMAGE                                  COMMAND                  CREATED             STATUS              PORTS               NAMES
2134e1b2c689        docker-registry.io/test/nginx:latest   "/docker-entrypoint.…"   24 minutes ago      Up 24 minutes       80/tcp              nginx.1.ych7y3ugxp6o592pbz5k2i412
[root@docker-node02 ~]# docker logs -f nginx.1.ych7y3ugxp6o592pbz5k2i412 
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
10.0.0.3 - - [21/Jun/2020:02:37:11 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"
172.18.0.1 - - [21/Jun/2020:02:38:35 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"
10.0.0.2 - - [21/Jun/2020:02:53:32 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"
10.0.0.2 - - [21/Jun/2020:02:53:58 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"
^C
[root@docker-node02 ~]# 

  提示:我們在管理節點上訪問172.18.0.2在node2節點上看到的日誌是10.0.0.2的ip訪問到nginx服務;這是為什麼呢?其實原因就是在每個節點上都有一個ingress-sbox容器,該容器的地址就10.0.0.2;不同節點上的ingress-sbox的地址都不同,所以我們訪問不同節點地址,在nginx上看到地址也就不同;如下圖所示

  提示:訪問不同的節點地址,在nginx日誌上記錄的IP各不相同

  提示:從上面的截圖可以了解到每個節點的ingress-sbox容器的地址各不相同,但他們都把網關指向10.0.0.1,這意味着各個節點容器通信就可以基於這個網關來進行,從而實現了swarm集群上的容器間通信能夠基於ingress網絡進行;現在還有一個問題就是172.18.0.0/18的網絡是怎麼和10.0.0.0/24的網絡通信的?

  提示:從上面的截圖可以看到,在管理節點上有兩個網絡名稱空間,一個id為0,而id為0的網絡名稱空間中有veth0和vxlan0這兩個網卡;而veth0和vxlan0都是橋接到br0上的,br0的地址就是10.0.0.1/24;vxlan的vlan id為4096;結合上面nginx的日誌,不難想到

我們訪問管理節點上的80,通過iptables規則把流量轉發給docker-gwbridge網絡上;現在我們還不清楚docker-gwbridge網絡上那個名稱空間的網絡,但是我們清楚知道在容器內部有兩張網卡,一張是eth0,一張是eth1,而eth1就是橋接到docker-gwbridge網絡上,這也就意味着容docker-gwbridge網絡的名稱空間和容器內部的eth1網絡名稱空間相同;

  提示:從上面的截圖看,1-u5mwgfq7rb這個名稱的網絡名稱空間有三張網卡,分別是eth0,eth1和vxlan0,它們都是橋接在br0這個網卡上;而上面管理節點也在1-u5mwgfq7rb這個網絡名稱空間,並且它們中的vxlan0的vlan id都是4096,這意味着管理節點上的vxlan0可以同node2上的vxlan0直接通信(相同網絡名稱空間中的相同VLAN id是可以直接通信的),而vxlan0又是直接橋接到br0這塊網卡,所以我們在nginx日誌中能夠看到ingress-sbox容器的地址在訪問nginx;這其中的原因是ingress-sbox的網關就是br0;其實node3也是相同邏輯,不同節點上的容器間通信都是走vxlan0,與外部通信走eth1—->然後通過SNAT走docker-gwbridge—->物理網卡出去;

  提示:一個容器上有兩個網絡,一個是eth0 ingress網絡,一個是eth1屬於docker-gwbridge網絡,兩者都屬於同一容器中的網絡名稱空間,所以我們訪問172.18.0.2就會通過ingress-sbox容器把源地址更改為docker-gwbridge上的ingress-sbox的地址,從而我們在看nginx日誌,就會看到10.0.0.2的地址;ingress-sbox容器作用我們可以理解為做SNAT的作用;

  測試:訪問管理節點的80服務看看是否能夠訪問到nginx提供的頁面呢?

[root@docker-node02 ~]# docker ps
CONTAINER ID        IMAGE                                  COMMAND                  CREATED             STATUS              PORTS               NAMES
b829991d6966        docker-registry.io/test/nginx:latest   "/docker-entrypoint.…"   About an hour ago   Up About an hour    80/tcp              myweb.1.ilhkslrlnreyo6xx5j2h9isjb
8c2965fbdc27        docker-registry.io/test/nginx:latest   "/docker-entrypoint.…"   2 hours ago         Up 2 hours          80/tcp              web.2.pthe8da2n45i06oee4n7h4krd
b019d663e48e        docker-registry.io/test/nginx:latest   "/docker-entrypoint.…"   2 hours ago         Up 2 hours          80/tcp              web.3.w26gqpoyysgplm7qwhjbgisiv
a7c1afd76f1f        docker-registry.io/test/nginx:latest   "/docker-entrypoint.…"   2 hours ago         Up 2 hours          80/tcp              web.1.ho0d7u3wensl0kah0ioz1lpk5
[root@docker-node02 ~]# docker exec -it myweb.1.ilhkslrlnreyo6xx5j2h9isjb  bash
root@b829991d6966:/# cd /usr/share/nginx/html/
root@b829991d6966:/usr/share/nginx/html# ls
50x.html  index.html
root@b829991d6966:/usr/share/nginx/html# echo "this is docker-node02 index page" >index.html
root@b829991d6966:/usr/share/nginx/html# cat index.html
this is docker-node02 index page
root@b829991d6966:/usr/share/nginx/html# 

  提示:以上是在docker-node02節點上對運行的nginx容器的主頁進行了修改,接下我們訪問管理節點的80端口,看看是否能夠訪問得到work節點上的容器,它們會有什麼效果?是輪詢?還是一直訪問一個容器?

  提示:可以看到我們訪問管理節點的80端口,會輪詢的訪問到work節點上的容器;用瀏覽器測試可能存在緩存的問題,我們可以用curl命令測試比較準確;如下

[root@docker-node03 ~]# docker ps
CONTAINER ID        IMAGE                                  COMMAND                  CREATED             STATUS              PORTS               NAMES
f43fdb9ec7fc        docker-registry.io/test/nginx:latest   "/docker-entrypoint.…"   2 hours ago         Up 2 hours          80/tcp              myweb.3.pgdjutofb5thlk02aj7387oj0
4470785f3d00        docker-registry.io/test/nginx:latest   "/docker-entrypoint.…"   2 hours ago         Up 2 hours          80/tcp              myweb.2.uwxbe182qzq00qgfc7odcmx87
7493dcac95ba        docker-registry.io/test/nginx:latest   "/docker-entrypoint.…"   2 hours ago         Up 2 hours          80/tcp              web.4.rix50fhlmg6m9txw9urk66gvw
118880d300f4        docker-registry.io/test/nginx:latest   "/docker-entrypoint.…"   2 hours ago         Up 2 hours          80/tcp              web.5.vo7c7vjgpf92b0ryelb7eque0
[root@docker-node03 ~]# docker exec -it myweb.2.uwxbe182qzq00qgfc7odcmx87 bash
root@4470785f3d00:/# cd /usr/share/nginx/html/
root@4470785f3d00:/usr/share/nginx/html# echo "this is myweb.2 index page" > index.html 
root@4470785f3d00:/usr/share/nginx/html# cat index.html
this is myweb.2 index page
root@4470785f3d00:/usr/share/nginx/html# exit
exit
[root@docker-node03 ~]# docker exec -it myweb.3.pgdjutofb5thlk02aj7387oj0 bash
root@f43fdb9ec7fc:/# cd /usr/share/nginx/html/
root@f43fdb9ec7fc:/usr/share/nginx/html# echo "this is myweb.3 index page" >index.html 
root@f43fdb9ec7fc:/usr/share/nginx/html# cat index.html
this is myweb.3 index page
root@f43fdb9ec7fc:/usr/share/nginx/html# exit
exit
[root@docker-node03 ~]# 

  提示:為了訪問方便看得出效果,我們把myweb.2和myweb.3的主頁都更改了內容

[root@docker-node01 ~]# for i in {1..10} ; do curl 192.168.0.41; done
this is myweb.3 index page
this is docker-node02 index page
this is myweb.2 index page
this is myweb.3 index page
this is docker-node02 index page
this is myweb.2 index page
this is myweb.3 index page
this is docker-node02 index page
this is myweb.2 index page
this is myweb.3 index page
[root@docker-node01 ~]# 

  提示:通過上面的測試,我們在使用–publish-add 暴露服務時,就相當於在管理節點創建了一個load balance;

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

Newtonsoft 六個超簡單又實用的特性,值得一試 【上篇】

一:講故事

看完官方文檔,閱讀了一些 Newtonsoft 源碼,對它有了新的認識,先總結 六個超經典又實用的特性,同大家一起分享,廢話不多說,快來一起看看吧~~~

二:特性分析

1. 代碼格式化

如果你直接使用 JsonConvert.SerializeObject的話,默認情況下所有的json是擠壓在一塊的,特別不方便閱讀,如下所示:


        static void Main(string[] args)
        {
            var reportModel = new ReportModel()
            {
                ProductName = "法式小眾設計感長裙氣質顯瘦純白色仙女連衣裙",
                TotalPayment = 100,
                TotalCustomerCount = 2,
                TotalProductCount = 333
            };

            var json = JsonConvert.SerializeObject(reportModel);

            System.Console.WriteLine(json);
        }
    }

    public class ReportModel
    {
        public string ProductName { get; set; }
        public int TotalCustomerCount { get; set; }
        public decimal TotalPayment { get; set; }
        public int TotalProductCount { get; set; }
    }

那怎麼辦呢? JsonConvert中提供了一個 Formatting.Indented 用來格式化json,這樣在 debug 的過程中就非常友好,改造如下:

2. 踢掉沒有被賦值的字段

如果你寫過給 App 提供數據的後端服務,我相信你對手機流量這個詞特別敏感,往往一個 Model 上有十幾個字段,但需要傳給 App 可能就 三四個字段,這就造成了巨大的流量浪費,如下圖:


        static void Main(string[] args)
        {
            var reportModel = new ReportModel()
            {
                ProductName = "法式小眾設計感長裙氣質顯瘦純白色仙女連衣裙",
                TotalPayment = 100
            };

            var json = JsonConvert.SerializeObject(reportModel, Formatting.Indented);

            System.Console.WriteLine(json);
        }

從圖中可以看到,TotalCustomerCountTotalProductCount 這兩個字段就沒必要了,Netnewsoft 中提供了 DefaultValueHandling.Ignore 剔除默認值的枚舉,太實用了,改造如下:


            var json = JsonConvert.SerializeObject(reportModel, Formatting.Indented,
                                                   new JsonSerializerSettings
                                                   {
                                                       DefaultValueHandling = DefaultValueHandling.Ignore
                                                   });

3. 兼容其他語言的 駝峰,蛇形命名法

每一套編程語言都有各自偏好的命名法,比如 js 中都喜歡採用 駝峰命名法,在 mysql 中我見過最多的 蛇形命名法,而我們在 C# 中序列化的屬性一般都是大寫字母開頭,比如你看到的 特性二 中的字段,那這裏就存在問題了,有沒有辦法兼容一下,給 js 就用 駝峰,給 mysql 就用 蛇形,這樣顯得對別人友好一些,不是嘛,接下來看看怎麼改造。

  • 駝峰命名 CamelCasePropertyNamesContractResolver

            var json = JsonConvert.SerializeObject(reportModel, Formatting.Indented,
                                                   new JsonSerializerSettings
                                                   {
                                                       ContractResolver = new CamelCasePropertyNamesContractResolver()
                                                   });

  • 蛇形命名 SnakeCaseNamingStrategy

            var json = JsonConvert.SerializeObject(reportModel, Formatting.Indented,
                                                   new JsonSerializerSettings
                                                   {
                                                       ContractResolver = new DefaultContractResolver()
                                                       {
                                                           NamingStrategy = new SnakeCaseNamingStrategy()
                                                       }
                                                   });

4. 自定義屬性的名字

如果你和第三方系統進行過對接開發,通常都會遇到這個問題,就拿 OpenTaobao 來說,我的Model總不能按照它文檔這樣定義吧,而且字段名稱也不可能做到完全一致,如下圖:

所以這裏面必然要存在一個 Mapping 的過程,這就可以用 JsonProperty -> propertyName 幫你搞定,為了方便演示,我還是用 reportModel 吧。


    static void Main(string[] args)
    {
        var json = "{'title':'法式小眾設計感長裙氣質顯瘦純白色仙女連衣裙','customercount':1000,'totalpayment':100.0,'productcount':10000}";

        var reportModel = JsonConvert.DeserializeObject<ReportModel>(json);
    }

    public class ReportModel
    {
        [JsonProperty("title")] public string ProductName { get; set; }
        [JsonProperty("customercount")] public int TotalCustomerCount { get; set; }
        [JsonProperty("totalpayment")] public decimal TotalPayment { get; set; }
        [JsonProperty("productcount")] public int TotalProductCount { get; set; }
    }


5. 對字段的 正向剔除 和 反向剔除

可能有些朋友對這兩個概念不是特別了解,這裏我僅显示 Model 中的 ProductName 為例講解一下:

  • 正向剔除: 默認所有都显示,手工踢掉不显示的,使用 MemberSerialization.OptOut 配合 JsonIgnore

 		static void Main(string[] args)
        {
            var reportModel = new ReportModel()
            {
                ProductName = "法式小眾設計感長裙氣質顯瘦純白色仙女連衣裙",
                TotalPayment = 100
            };

            var json = JsonConvert.SerializeObject(reportModel, Formatting.Indented);

            System.Console.WriteLine(json);
        }

    [JsonObject(MemberSerialization.OptOut)]
    public class ReportModel
    {
        public string ProductName { get; set; }
        [JsonIgnore] public int TotalCustomerCount { get; set; }
        [JsonIgnore] public decimal TotalPayment { get; set; }
        [JsonIgnore] public int TotalProductCount { get; set; }
    }

  • 反向剔除: 默認都不显示,手工指定要显示的,使用 MemberSerialization.OptIn 配合 JsonProperty
       
    [JsonObject(MemberSerialization.OptIn)]
    public class ReportModel
    {
        [JsonProperty] public string ProductName { get; set; }
        public int TotalCustomerCount { get; set; }
        public decimal TotalPayment { get; set; }
        public int TotalProductCount { get; set; }
    }

6. 多個json 合併到 一個Model

這個特性當初打破了我對 Newtonsoft 的認知觀,不知道您呢? 通常我們都會認為 一個 json 對應一個 model,一個 model 對應一個 json,居然還可以多個 json 對應一個 model 的情況,這就有意思了,場景大家可以自己想一想哈,這裏使用 PopulateObject 方法就可以輕鬆幫你搞定,接下來看看怎麼寫這個代碼:


        static void Main(string[] args)
        {
            var json1 = "{'ProductName':'法式小眾設計感長裙氣質顯瘦純白色仙女連衣裙'}";
            var json2 = "{'TotalCustomerCount':1000,'TotalPayment':100.0,'TotalProductCount':10000}";

            var reportModel = new ReportModel();

            JsonConvert.PopulateObject(json1, reportModel);
            JsonConvert.PopulateObject(json2, reportModel);
        }

是不是有點意思

三:總結

為了怕影響閱讀體驗,這一篇就先總結六個供大家欣賞,Newtonsoft 這玩意確實非常強大,太多的東西需要去挖掘,希望本篇對你有幫助,謝謝。

如您有更多問題與我互動,掃描下方進來吧~

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

新北清潔公司,居家、辦公、裝潢細清專業服務

※別再煩惱如何寫文案,掌握八大原則!

※教你寫出一流的銷售文案?

※超省錢租車方案

FB行銷專家,教你從零開始的技巧

Nginx 如何自定義變量?

之前的兩篇文章 Nginx 變量介紹以及利用 Nginx 變量做防盜鏈 講的是 Nginx 有哪些變量以及一個常見的應用。那麼如此靈活的 Nginx 怎麼能不支持自定義變量呢,今天的文章就來說一下自定義變量的幾個模塊以及 Nginx 的 keepalive 特性。

通過映射新變量提供更多的可能性:map 模塊

  • 功能:基於已有變量,使用類似 switch {case: … default: …} 的語法創建新變量,為其他基於變量值實現功能的模塊提供更多的可能性
  • 模塊:ngx_http_map_module 默認編譯進 Nginx,通過 --without-http_map_module 禁用

指令

Syntax: map string $variable { ... }
Default: —
Context: http

Syntax: map_hash_bucket_size size;
Default: map_hash_bucket_size 32|64|128; 
Context: http

Syntax: map_hash_max_size size;
Default: map_hash_max_size 2048; 
Context: http

我們主要看一下 map string $variable { ... } 這個指令。所謂類似 switch case 的語法是指,string 的值可以有多個,可以根據 string 值的不同,來給 $variable 賦不同的值。

規則

  • 已有變量:string 需要是已有的變量,可以分為下面這三種情況
    • 字符串
    • 一個或者多個變量
    • 變量與字符串的組合
  • case 規則:{…} 內的匹配規則需要遵循以下規則,尤其是要注意當使用 hostnames 指令時,與 server name 的匹配規則是一致的,可以看之前的文章 Nginx 的配置指令
    • 字符串嚴格匹配
    • 使用 hostnames 指令,可以對域名使用前綴 * 泛域名匹配
    • ~ 和 ~* 正則表達式匹配,後者忽略大小寫
  • default 規則
    • 沒有匹配到任何規則時,使用 default
    • 確實 default 時,返回空字符串給新變量
  • 其他
    • 使用 include 語法提升可讀性
    • 使用 volatile 禁止變量值緩存

大家看到上面這些規則可能都有些暈,廢話不多說,直接來看一個實戰配置文件就懂了。

實戰

這裏我們有一個配置文件,在這個文件裏面我們定義了兩個 map 塊,分別配置了兩個變量,$name 和 $mobile,$name 中包含 hostnames 指令。

map $http_host $name {
    hostnames;

    default       0;

    ~map\.ziyang\w+\.org.cn 1;
    *.ziyang.org.cn   2;
    map.ziyang.com   3;
    map.ziyang.*    4;
}

map $http_user_agent $mobile {
    default       0;
    "~Opera Mini" 1;
}

server {
	listen 10001;
	default_type text/plain;
	location /{
		return 200 '$name:$mobile\n';
	}
}

下面看一下實際的請求:

  test_nginx curl -H "Host: map.ziyang.org.cn" 127.0.0.1:10001
2:0

為什麼會返回 2:0 呢?我們來看一下匹配順序。

map.ziyang.org.cn 有三個規則可以生效,分別是:

  • ~map.ziyang\w+.org.cn 1;
  • *.ziyang.org.cn 2;
  • map.ziyang.* 4;

而泛域名是優先於正則表達式的,* 在前的泛域名優先於在後面的泛域名,因此最終匹配到的就是:

  • *.ziyang.org.cn 2;

而第二個變量 $mobile 自然走的是 default 規則,不用多說。

這就是 map 模塊的作用,大家可以多嘗試一下。

下面再來看一個與 map 模塊有點類似的 split_clients 模塊,這個模塊也是通過生成新的變量來完成 AB 測試功能的,它可以按照變量的值,按照百分比的方式,生成新的變量。

實現 AB 測試:split_clients 模塊

  • 功能:基於已有變量創建新變量,為其他 AB 測試提供更多的可能性
    • 對已有變量的值執行 MurmurHash2 算法,得到 32 位整形哈希数字,記為 hash
    • 32 位無符號整形的最大数字 2^32-1,記為 max
    • 哈希数字與最大数字相除,hash/max,可以得到百分比 percent
    • 配置指令中指示了各個百分比構成的範圍,如 0-1%,1%-5% 等,及範圍對應的值
    • 當 percent 落在哪個範圍里,新變量的值就對應着其後的參數
  • 模塊:ngx_http_split_clients_module,默認編譯進 Nginx,通過 --without-http_split_clients_module 禁用

規則

  • 已有變量
    • 字符串
    • 一個或者多個變量
    • 變量與字符串的組合
  • case 規則:
    • xx.xx%,支持小數點后 2 位,所有項的百分比相加不能超過 100%
    • *,由它匹配剩餘的百分比(100% 減去以上所有項相加的百分比)

指令

Syntax: split_clients string $variable { ... }
Default: —
Context: http

split_clients 的指令與 map 是非常相似的,可以看一下前面的介紹,這裏不再贅述了。

下面這個配置,來看下有沒有啥問題:

split_clients "${http_testcli}" $variant {
    0.51% .one;
    20.0% .two;
    50.5% .three;
    40% .four;
    * "";
}

細心的同學可能已經發現了,所有的百分比相加已經超過了 100%,所以 Nginx 直接會拋出一個錯誤,禁止執行。

  test_nginx ./sbin/nginx -s reload
nginx: [emerg] percent total is greater than 100% in /Users/mtdp/myproject/nginx/test_nginx/conf/example/17.map.conf:31

然後將 40% .four; 這一行給屏蔽掉再試試看:

  test_nginx curl -H "testcli: split_clients.ziyang.com" --resolve "split_clients.ziyang.com:80:127.0.0.1" http://split_clients.ziyang.com
ABtestfile.three

正常執行。

geo 模塊

geo 模塊與前面兩個模塊也很相似,不同之處在於,這個模塊是基於 IP 地址或者子網掩碼這樣的變量值來生成新的變量的。

  • 功能:根據 IP 地址創建新變量

  • 模塊: ngx_http_geo_module,默認編譯進 Nginx,通過 --without-http_geo_module 禁用

  • 指令

Syntax: geo [$address] $variable { ... }
Default: —
Context: http

規則

  • 如果 geo 指令后不輸入 $address,那麼默認使用 $remote_addr 變量作為 IP 地址

  • {} 內的指令匹配:優先最長匹配

    • 通過 IP 地址及子網掩碼的方式,定義 IP 範圍,當 IP 地址在範圍內時新變量使用其後的參數值

    • default 指定了當以上範圍都未匹配上時,新變量的默認值

    • 通過 proxy 指令指定可信地址(參考 realip 模塊),此時 remote_addr 的值為 X-Forwarded-For 頭部值中最後一個 IP 地址

    • proxy_recursive 允許循環地址搜索

    • include,優化可讀性

    • delete 刪除指定網絡

geo $country {
default ZZ;
#include conf/geo.conf;
#proxy 172.18.144.211;
127.0.0.0/24 US;
127.0.0.1/32 RU;
10.1.0.0/16 RU;
192.168.1.0/24 UK;
}


問題:以下命令執行時,變量 country 的值各為多少?(proxy 實際上為客戶端地址,這裏設置為本機的局域網地址即可,我這裡是 172.18.144.211)

curl -H ‘X-Forwarded-For: 10.1.0.0,127.0.0.2’ geo.ziyang.com
curl -H ‘X-Forwarded-For: 10.1.0.0,127.0.0.1’ geo.ziyang.com
curl -H ‘X-Forwarded-For: 10.1.0.0,127.0.0.1,1.2.3.4’ geo.ziyang.com


結果如下:

```shell
  test_nginx curl -H 'X-Forwarded-For: 10.1.0.0,127.0.0.2' geo.ziyang.com
US
  test_nginx curl -H 'X-Forwarded-For: 10.1.0.0,127.0.0.1' geo.ziyang.com
RU
  test_nginx curl -H 'X-Forwarded-For: 10.1.0.0,127.0.0.1,1.2.3.4' geo.ziyang.com
ZZ

這裏可以看出來,匹配規則實際上是遵循最長匹配的規則的。

geoip 模塊

geoip 模塊可以根據 IP 地址生成對應的地址變量,用法與前面的也都類似,Nginx 是基於 MaxMind 數據庫來生成對應的地址的。

  • 功能:根據 IP 地址創建新變量
  • 模塊: ngx_http_geoip_module,默認未編譯進 Nginx,通過 --with-http_geoip_module 禁用

使用這個模塊是需要安裝 MaxMind 庫的,安裝步驟如下:

  • 安裝 MaxMind 里 geoip 的 C 開發庫(https://dev.maxmind.com/geoip/legacy/downloadable/ )
  • 編譯 Nginx 時帶上 --with-http_geoip_module 參數
  • 下載 MaxMind 中的二進制地址庫,這個地址庫是需要在指令中指定對應的地址的
  • 使用 geoip_country 或者 geoip_city 指令配置好 nginx.conf
  • 運行或者升級 Nginx

geoip_country 指令提供的變量

指令

Syntax: geoip_country file; # 指定國家類的地址文件
Default: —
Context: http

Syntax: geoip_proxy address | CIDR;
Default: —
Context: http

變量

  • $geoip_country_code:兩個字母的國家代碼,比如 CN 或者 US
  • $geoip_country_code3:三個字母的國家代碼,比如 CHN 或者 USA
  • $geoip_country_name:國家名稱,例如 “China”, “United States”

geoip_city 指令提供的變量

指令

Syntax: geoip_city file;
Default: —
Context: http

變量

  • $geoip_latitude:緯度
  • $geoip_longitude:經度
  • $geoip_city_continent_code:位於全球哪個洲,例如 EU 或 AS
  • 與 $geoip_country 指令生成的變量重疊
    • $geoip_country_code:兩個字母的國家代碼,比如 CN 或者 US
    • $geoip_country_code3:三個字母的國家代碼,比如 CHN 或者 USA
    • $geoip_country_name:國家名稱,例如 “China”, “United States”
  • $geoip_region:洲或者省的編碼,例如 02
  • $geoip_region_name:洲或者省的名稱,例如 Zhejiang 或者 Saint Petersburg
  • $geoip_city:城市名
  • $geoip_postal_code:郵編號
  • $geoip_area_code:僅美國使用的郵編號,例如 408
  • $geoip_dma_code:僅美國使用的 DMA 編號,例如 807

keepalive 模塊

前面說的都是 Nginx 的變量相關的內容,其實 Nginx 還有一個很具有特色的模塊,那就是 keepalive 模塊,由於內容不是很多,所以我就直接寫到這篇文章裏面了,單寫一篇顯得內容不夠哈。

這裏指的是 HTTP 的 keepalive,TCP 也有 keepalive,後面會說。

而且是對客戶端的 keepalive,不是對上游服務器的。

  • 功能:多個 HTTP 請求通過復用 TCP 連接,可以實現以下功能:

    • 減少握手次數
    • 通過減少併發連接數減少了服務器資源消耗
    • 降低 TCP 擁塞控制的影響,保證滑動窗口維持在一個最優的大小
  • Connection 頭部

    • close:表示請求處理完就關閉連接
    • keepalive:表示復用連接處理下一條請求
  • Keepalive 頭部:timeout=n,單位是秒,表示連接至少保持 n 秒

指令

對客戶端行為控制的指令:

Syntax: keepalive_disable none | browser ...;
Default: keepalive_disable msie6; 
Context: http, server, location

Syntax: keepalive_requests number;
Default: keepalive_requests 100; 
Context: http, server, location

Syntax: keepalive_timeout timeout [header_timeout];
Default: keepalive_timeout 75s; 
Context: http, server, location
  • keepalive_disable 設置為 none 表示對所有瀏覽器啟用 keepalive,msie6 表示在老版本 MSIE 上禁用 keepalive
  • keepalive_requests 設置允許保持 keepalive 的請求的數量
  • keepalive_timeout 表示超時時間

好了,關於 Nginx 的模塊介紹就已經全部介紹完了,有興趣的同學可以去翻我前面的系列文章。當然還有一部分重要的內容還沒有介紹,那就是關於 Nginx 的反向代理和負載均衡部分,這塊咱們單獨抽出來說,別著急,馬上乾貨就出來。

本文首發於我的個人博客:iziyang.github.io,所有配置文件我已經放在了 Nginx 配置文件,大家可以自取。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

新北清潔公司,居家、辦公、裝潢細清專業服務

※別再煩惱如何寫文案,掌握八大原則!

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※超省錢租車方案

※教你寫出一流的銷售文案?

網頁設計最專業,超強功能平台可客製化