特斯拉 Model 3 估 7 月投產,拚下半年如期交車

美國電動車廠特斯拉(Tesla)周三盤後公布前季財報再度由盈轉虧,不過這並不打緊,因為按照特斯拉說法,Model 3 平價電動車有望如期交車,這才是投資人所最關心的。

特斯拉獲利表現不理想,去年第四季淨損 1.21 億美元,或相當於每股 0.78 美元,若扣除一次性費用,每股虧損降低至 0.69 美元,但還是高於分析師原預估每股虧 0.53 美元。

當季營收來到 22.8 億美元,較去年同期成長88%,且優於分析師預估的 22.2 億美元。特斯拉去年 11 月 21 日已完成太陽能面板廠 SolarCity 的收購作業,SolarCity 當季貢獻營收 1.31 億美元。

特斯拉當日宣布,Model 3 預計2017年 7 月可限量投產,9 月產量可開始放大,預估 2018 年每周可產出 10,000 輛。特斯拉原預期 Model 3 可在下半年開始交車,現在兌現承諾的機率大大提高,這激勵特斯拉股價盤後大漲 2.49%、暫報 280.02 美元。

第四季 Model S、Model X 產量合計來到 24,882 輛,年增 77%;銷售量合計為 22,252 輛,成長 27%。(紐約時報)

展望 2017 年,特斯拉預期 Model S 與 Model X 交車量將介於 47,000 至 50,000 輛,換算年成長率最高為 71%。另外,特斯拉還說太陽能車頂下半年就能開始量產。

(本文內容由授權使用。圖片出處:Public Domain CC0)

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

【其他文章推薦】

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

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

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

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

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

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

C/S C# WPF銳浪報表教程

前言:銳浪報表是一種中國式報表的報表開發工具。博主使用銳浪報表有一段時間了,積累了一些經驗希望能幫助你快速掌握並使用

第一章:集成項目

首先我們先去銳浪報表官網下載並安裝銳浪報表。

創建WPF應用程序。(C/S端使用銳浪報表基本都一樣

 添加銳浪報表的引用,在資源管理器目錄中找到引用並右鍵,點擊添加引用。

 在引用管理器左側目錄中展開COM並找到Grid++Report Engine 6 Type Library,勾選上點擊確定。(這裡有四個銳浪報表的引用,不要加錯了)

 在資源管理器中展開引用找到gregn6Lib

 右鍵gregn6Lib點擊屬性,將獨立設置為True,將嵌入式互操作類型設置為True

在資源管理器中右鍵WPFPrintReportRL項目——添加——新建文件夾,命名為report

 集成銳浪報表的WPF項目環境基本配置差不多了,下面我們打開安裝完畢銳浪報表的編輯器

 在上方導航目錄中找到插入——報表頭,就會生成這個UI編輯面板

如果我們需要打印一些參數,則在左上方的目錄中找到參數集合——新增——參數

 將這個參數命名,我使用的是Name,這個參數的命名就是後面程序需要在在報表中傳遞的參數

 在上方導航欄中找到插入——綜合文本框,將鼠標在UI編輯面板左鍵點擊一下生成綜合文本框,然後我們雙擊綜合文本框編輯內容。

點擊插入域引用類型選擇為參數參數選擇為剛才命名為Name的參數,點擊確定

 做完以上操作后的UI編輯面板,隨後我們另存到使用VS創建的WPFPrintReportRL項目下的report目錄中

切回VS,在資源管理器中上方找到並點擊显示所有文件,然後資源管理起中report文件夾下會显示出你剛保存的報表文件右鍵——包括在項目中

 對報表文件右鍵——屬性,將複製到輸出目錄更改為:如果較新則複製

主窗體的後台代碼,已經加入註釋,各位慢慢品味。

            GridppReport gr = new GridppReport();//報表對象
            //建議不要在報表中存儲連接字符串字符串
            //如果不設置ConnectionString或QuerySQL屬性,則會使用報表內的連接字符串和SQL語句
            gr.ConnectionString = "";//連接字符串
            gr.QuerySQL = "";//SQL語句
            gr.LoadFromFile("report\\案例報表.grf");//本地報表路徑
            gr.ParameterByName("Name").AsString = "古河渚";//主報表傳參
            gr.Print(false);//不預覽打印

接下來我們在資源管理器中右鍵WPFPrintReportRL項目——屬性——生成,將目標平台更改為x86

 隨後我們運行項目,報表如期而至打印了出來。(這裏博主使用的是虛擬打印機,點我下載,將打印機設置里默認打印機設置為 pdfFactory Pro

銳浪報表安裝后目錄中已提供案例與文檔,博主Demo項目已上傳交流群,點擊最上方標題即可交流群學習。

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

聯合國專家:防疫措施恐釀全球缺糧

摘錄自2020年03月26日自由時報報導

武漢肺炎讓全球各地都有民眾因恐慌而瘋狂囤積生活用品、糧食,聯合國糧農組織(FAO)首席經濟學家托雷羅(Maximo Torero)警告,各國實施的防疫措施,恐怕會導致全球糧食短缺。

綜合外電報導,各國為確保物資充足,紛紛祭出提高關稅、限制出口、禁止人口移動等措施。托雷羅表示,從2007年的糧食危機就有觀察到,貿易壁壘會造成價格波動,進而使狀況惡化。雖然目前全球的糧食狀況看似很好,但幾週內糧食問題就會逐漸浮現,並隨著蔬果進入收成季節,於兩個月內惡化。

限制人口流動雖然能有效防止疫情傳播,但邁入收成季的蔬果園也將難以招募到熟練的臨時工,許多作物可能來不及在腐壞前收成。托雷羅也建議消費者,可以透過避免恐慌搶購、囤貨、浪費物資,緩解防疫措施導致的糧食問題。

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

Day8-微信小程序實戰-交友小程序-首頁用戶列表渲染及多賬號調試及其點贊功能的實現

在這之前已經把編輯個人的所有信息的功能已經完成了

之後先對首頁的列表搞動態的,之前都是寫死的靜態

1、之前都是把好友寫死的,現在就在js裏面定義一個數組,用循環來動態的綁定

在onReady中定義,取真實的數據給定義的列表數組list  

通過調用  db.collection(‘users’).get()  這裏沒有加其他的限制,得到的就是所有的數據了,拿到全部的數據之後就會觸發then方法了

用then返回的res中有一個data的列表集合,有一個注意的點就是,這樣子讀取是吧數據庫中的數據的全部字段,但是我們需要用的只是

用戶的頭像和點贊數、用戶昵稱,其他的數據其實是不需要的

可以加一個field方法,可以要求返回的字段是哪些的

 

可以看到是只有一個用戶,我們為了模擬的話,就可以多賬號進行調試,

 

 1、創立多賬號

    ①首先這個多賬號的一定要是測試號,所以先進入微信的管理後台 https://mp.weixin.qq.com/

    ②進入 【成員管理】添加項目成員

    ③回到微信開發者工具中-》工具-》多賬號調試-》可以通過添加虛擬測試號來進行測試的,不用真實的微信號都可以

 

之後就是對點贊的功能進行設計了(就可以在index.wxml中給點贊的小心上加一個點擊事件即可了

(小細節在小程序中規定,在客戶端中讀取用戶列表的時候,一般不會把整個數據庫的用戶都讀取出來的,是有一個限制的

一般都是把前二十條數據給讀取出來的,如果數據一多的話,一般都是進行分頁處理了–一般都是用數據庫中的collection.skip和collection.limit,這兩個東西一起配合的話就可以做下拉加載的功能了)

由於這個點贊是要對找到用戶的id地址的,所以在wxml中給點贊這個圖標加上一個id自定義屬性的掛載

 

data-id="{{ item._id}}"

這個東西的用處就是,在點擊這個心心的時候就可以拿到這個自定義的屬性id了  

通過把handleLinks(ev)函數中把ev打印出來發現,這個自定義屬性id 的位置在

 ev.target.dataset.id

console.log就是用來測試的,如果沒效果的話,一般都是直接在點擊事件後面通過promise 的then把res打印出來看看情況是怎麼樣的

***有時候這些點擊事件無法觸發的話,就可以在檢查一下樣式,可能這個區域在前端显示是在這裏,但是實際上是在其他的地方,

 

 

 也就是布局引起的問題了

 

 

 

 可以看到這裏就是碰到的是點贊的這個圖標,但是這個樣式是在左上角進行了渲染的

這個時候為了演示把,就把自定義屬性,和點擊事件放在點贊圖標還有點贊數包含的這個text裏面了

<text bindtap="handleLinks" data-id="{{ item._id}}" >
          <!-- 點贊圖標 -->
              <text class="iconfont icondianzan"
              ></text>
          <!-- 點贊數 -->
              <text>{{ item.links }}</text>
          </text>

改完之後,再點擊心心或者是數量,就可以正常的進行點贊了

  但是發現只有給自己點贊的時候才可以改變點贊的數量,而改其他人點贊的時候就改不了

比如:

 

 

 這就是一個權限的問題了也就是只能改自己的數據(點贊數)改不了別人的數據l

 

 

因為在小程序端中,由於用戶可以直接對數據庫進行操作,所以會有一定的風險,所以就通過這個訪問權限來進行了限制

那?

怎麼修改別人的數據呢?—這個操作就要在服務端來進行操作了!  也就是在雲函數中去完成一個雲函數的操作了

 

下面就是講解 如何在 服務端來對数字字段來進行更改!

 

二、點贊功能實現與update雲函數

 由於要在服務端來做的話,就可以把這一塊的部分代碼刪掉了

  handleLinks(ev){
    let id = ev.target.dataset.id;
    db.collection('users').doc(id).update({
      data : {
        links : 5
      }
    }).then((res)=>{
      console.log(res)
    }); 
  }

需要新創一個雲函數(新建一個node.js雲函數

 

這些默認的結構都是可以刪掉的了

 

 之後就是參考 微信開放文檔 雲開發-》SDK文檔->數據庫-》collection->update-》示例代碼demo

其中:這個就是指定了數據庫的環境

cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
})

然後就是在服務端拿到數據庫db

const db = cloud.database()

然後可以在示例代碼中看到async這個異步的操作

直接複製 try catch

try {
    return await db.collection('todos').where({
      done: false
    })
    .update({
      data: {
        progress: _.inc(10)
      },
    })
  } catch(e) {
    console.error(e)
  }

return就是返回一個異步的數據,而catch就是返回錯誤信息

主要修改的就是 db.collecion()中要反問那個數據庫表單,這裏不能寫死為users,因為可能其他的地方也是要用到更新的這個功能的

所以最好就是把update這個雲函數寫成一個通用的方式

其中雲函數入口函數 

exports.main = async (event, context) => {  這個裡面的event就是前端傳參過來的對象了 就訪問 event.colletion,然後不用where而是用doc 再把event的doc也傳進來,這 ***小知識點:ES6的擴展運算符 。。。 (三個點)

更新成功了之後,就可以返回結果到前台了

這個就是update雲函數中js文件的代碼(傳進去的doc實際上是用戶的_id

 // 雲函數入口文件
const cloud = require('wx-server-sdk')

cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
})
const db = cloud.database()
// 雲函數入口函數
exports.main = async (event, context) => {
  try {
    return await db.collection(event.collection).doc(event.doc)
      .update({
        data: {
         ...event.data 
        },
      })
  } catch (e) {
    console.error(e)
  }
}

View Code

把雲函數寫好之後,這個時候雲函數還是在本地,要把這個雲函數傳到雲開發平台上

 

上傳了之後一定要去雲平台-》雲函數中去檢查一下

 

之後就可以調用這個雲函數了

再回到index.js 點贊的方法 handleLinkes方法中進行設置即可;

 

 如果雲函數沒問題,可能是雲函數裏面定義的env出了問題,就可以寫死了,傳入自己的那個環境,就不用默認的那個環境了

【注意】修改了雲函數記得要重新上傳到雲平台才行

 

 

 

 (因為在服務端是不會受到數據庫權限的限制的)

後面要優化的就是(上面的點贊是寫死給多少links的,並且不能點完之後立馬更新

可以把數據庫的links讀出來,+1之後再寫入,但是這樣的話就多了一個數據庫的操縱了  ,但是數據庫本身就提供了累加或者累減等運算的操作的

(這樣的話就只需要一次的數據庫讀取即可了)

在開放文檔 db.command裏面就有很多的方法

https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-sdk-api/database/command/Command.inc.html

示例代碼
將一個 todo 的進度自增 10:

const _ = db.command
db.collection('todos').doc('todo-id').update({
  data: {
    progress: _.inc(10)
  }
})

為了在服務端不把運算給寫死了,一般都是把運算直接通過前端來傳入的

由於前端不認識下劃線這種操作,因為前端要先解析,之後再把東西傳到服務端的,所以就可以在前端給服務端傳一個字符串的話

然後再在服務端解析即可

 data : "{links : _.inc(1)}"

在前端把這個字符串傳入到服務端中,之後就可以在服務端那邊對這個字符串進行解析了

所以在update雲函數中 就要對event.data這個傳過來的數據進行判斷,判斷它的類型,是普通的還是字符串類型的,如果是字符串類型的話就要進行解析

用js裏面的eval方法,它是把字符串轉成 js 語句的

 if(typeof event.data == 'string'){
      event.data =  eval('(' + event.data + ')')
    }

即可了(點一下心心就可以讓點贊數+1)

後面有空的話,可以繼續進行優化,也就是對一次的點贊數進行限制,或者是點一下加+1,再點一下就是取消了就-1了

後面就是要把點贊了之後,實時的把點贊數進行更新

 

可以看到給服務端那邊上傳之後,對數據庫進行了更新之後,then返回的結果res,中有一個是updated==1,就可以進行if判斷了

再用for循環對列表中的每一個元素判斷,是不是現在被點擊點贊的這個id

let updated = res.result.stats.updated;
    if(updated){
      // 先用擴展運算符 克隆一份數組
      let cloneListData = [...this.data.listData];
      for(let i = 0;i < cloneListData.length ; i++){
        if( cloneListData[i]._id == id){ 
          cloneListData[i].links++;
        }
      }
      this.setData({
        listData : cloneListData
      });
    }

點贊數增加 就是通過_inc 但是在服務端中的update函數中是用全局的,不能寫死,所以運算的規則就通過前端傳過去

為了以後其他的頁面也有更新功能的話做準備了

 

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

Tesla Q1營收倍增,Model 3排定7月量產

美國電動車廠特斯拉(Tesla)公佈首季獲利不如預期,但好消息是眾所矚目的Model 3平價電動車,有望如期量產。

特斯拉當季營收27億美元,為去年同期營收11.5億美元的兩倍多,亦優於分析師預估的26.2億美元。(路透社)

儘管如此,特斯拉當季每股虧1.33美元,遠超過分析師預估每股虧0.81美元。特斯拉去年同期每股虧1.45美元。

特斯拉說Model 3開發進度順利,將可在今年7月導入量產。不過從虧損超出預期可知,這應該是特斯拉燒錢換來的成果。

另外,特斯拉執行長Elon Musk還憂心客戶對定價只有35,000美元的Model 3期待太高,而忘了Model 3是平價車種,性能與續航力均不能與售價70,000美元的Model S相提並論。

特斯拉首季共交車25,051部,較去年同期成長64%、較去年第四季成長13%,上半年47,000-50,000部的交車目標也有望達陣。

(本文內容由授權使用。圖片出處:Tesla)  

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

德國將蓋鋰電池廠制衡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;

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

006.OpenShift持久性存儲

一 持久存儲

1.1 持久存儲概述

默認情況下,運行容器使用容器內的臨時存儲。Pods由一個或多個容器組成,這些容器一起部署,共享相同的存儲和其他資源,可以在任何時候創建、啟動、停止或銷毀。使用臨時存儲意味着,當容器停止時,寫入容器內的文件系統的數據將丟失。
當容器在停止時也需要持久的保存數據時,OpenShift使用Kubernetes持久卷(PVs)為pod提供持久存儲。

1.2 持久存儲場景

通常用於數據庫,啟動一個數據庫的pod時提供的默認臨時存儲。如果銷毀並重新創建數據庫pod,則銷毀臨時存儲並丟失數據。如果使用持久存儲,則數據庫將數據存儲到pod外部的持久卷中。如果銷毀並重新創建pod,數據庫應用程序將繼續訪問存儲數據的相同外部存儲。

1.3 持久存儲相關概念

持久卷(PV)是OpenShift資源,它只由OpenShift管理員創建和銷毀。持久卷資源表示所有OpenShift節點都可以訪問的網絡連接存儲。
持久性存儲組件:
OCP使用Kubernetes持久卷(PV)技術,允許管理員為集群提供持久性存儲。開發人員使用持久性卷聲明(PVC)請求PV資源,而不需要了解具體的底層存儲基礎設施。
Persistent Volume:PV是OpenShift集群中的資源,由PersistentVolume API對象定義,它表示集群中由管理員提供的現有網絡存儲的一部分。它是集群中的資源,就像節點是集群資源一樣。PV的生命周期獨立於使用PV的任何單獨pod。
Persistent Volume Claim:pvc由PersistentVolumeClaim API對象定義,該對象表示開發人員對存儲的請求。它與pod類似,pod消耗節點資源,而pvc消耗PV資源。

1.4 持久存儲插件

卷是掛載的文件系統,對pods及其容器可用,並且可以由許多本地或網絡連接的存儲進行備份。OpenShift使用插件來支持以下不同的後端用於持久存儲:

  • NFS
  • GlusterFS
  • OpenStack Cinder
  • Ceph RBD
  • AWS Elastic Block Store (EBS)
  • GCE Persistent Disk
  • iSCSI
  • Fibre Channel
  • Azure Disk and Azure File
  • FlexVolume (allows for the extension of storage back-ends that do not have a built-in plug-in)
  • VMWare vSphere
  • Dynamic Provisioning and Creating Storage Classes
  • Volume Security
  • Selector-Label Volume Binding

1.5 PV訪問模式

PV可以以resource provider的任何方式掛載在主機上,provider具有不同的功能,並且每個持久卷的訪問模式都設置為該特定卷支持的特定模式。例如,NFS可以支持多個讀/寫客戶端,但是特定的NFS PV可以在服務器上作為只讀導出。
每個PV接收自己的一組訪問模式,描述特定的持久卷的功能。
訪問模式見下錶:

訪問模式 CLI縮寫 描述
ReadWriteOnce RWO 卷可以被單個節點掛載為讀/寫
ReadOnlyMany ROX 卷可以由許多節點以只讀方式掛載
ReadWriteMany RWX 卷可以被許多節點掛載為讀/寫

PV claims與具有類似訪問模式的卷匹配。唯一的兩個匹配標準是訪問模式和大小。claim的訪問模式表示請求。因此,可以授予用戶更大的訪問權限,但絕不能減少訪問權限。例如,如果一個claim請求RWO,但是惟一可用的卷是NFS PV (RWO+ROX+RWX),那麼claim將匹配NFS,因為它支持RWO。
所有具有相同模式的卷都被分組,然後按大小(從最小到最大)排序。
master上負責將PV綁定到PVC上的service接收具有匹配模式的組,並在每個組上迭代(按大小順序),直到一個大小匹配為止,然後將PV綁定到PVC上。

1.6 Persistent Volume Storage Classes

PV Claims可以通過在storageClassName屬性中指定它的名稱來選擇性地請求特定的存儲類。只有與PVC具有相同存儲類名稱的請求類的pv才能綁定到PVC。
集群管理員可以為所有PVC設置一個默認存儲類,或者配置動態供應程序來服務一個或多個存儲類,這些存儲類將匹配可用PVC中的規範。

1.7 創建pv和PVC資源

pv是集群中的資源,pvc是對這些資源的請求,也充當對資源的claim檢查。pv與PVCs的相互作用具有以下生命周期:

  • 創建持久卷

集群管理員創建任意數量的pv,這些pv表示集群用戶可以通過OpenShift API使用的實際存儲的信息。

  • 定義持久卷聲明

用戶創建具有特定存儲量、特定訪問模式和可選存儲類的PVC。master監視新的pvc,要麼找到匹配的PV,要麼等待存儲類創建一個供應程序,然後將它們綁定在一起。

  • 使用持久存儲

Pods使用claims作為卷。集群檢查查找綁定卷的聲明,併為pod綁定該卷。對於那些支持多種訪問模式的卷,用戶在將其聲明用作pod中的卷時指定需要哪種模式。
一旦用戶有了一個claim,並且該claim被綁定,綁定的PV就屬於用戶,使用過程中該PV都屬於該用戶。用戶通過在pod的Volume中包含一個持久的卷claim來調度pod並訪問其聲明的pv。

1.8 使用NFS的PV

OpenShift使用隨機uid運行容器,因此將Linux用戶從OpenShift節點映射到NFS服務器上的用戶並不能正常工作。作為OpenShift pv使用的NFS共享必須遵從如下配置:

  • 屬於nfsnobody用戶和組。
  • 擁有rwx——權限(即0700)。
  • 使用all_squash選項

示例配置:
/var/export/vol *(rw,async,all_squash)
其他NFS export選項,例如sync和async,與OpenShift無關。如果使用任何一個選項,OpenShift都可以工作。但是,在高延遲環境中,添加async選項可以加快NFS共享的寫操作(例如,將image push到倉庫的場景)。
使用async選項更快,因為NFS服務器在處理請求時立即響應客戶端,而不需要等待數據寫到磁盤。
當使用sync選項時,則相反,NFS服務器只在數據寫到磁盤之後才響應客戶端。
注意:NFS共享文件系統大小和用戶配額對OpenShift沒有影響。PV大小在PV資源定義中指定。如果實際文件系統更小,則PV被創建並綁定。如果PV更大,OpenShift不會將使用的空間限製為指定的PV大小,並且允許容器使用文件系統上的所有空閑空間。OpenShift自身提供了存儲配額和存儲位置限制,可用於控制項目中的資源分配。
默認的SELinux策略不允許容器訪問NFS共享。必須在每個OpenShift實例節點中更改策略,方法是將virt_use_nfs和virt_sandbox_use_nfs變量設置為true。

  1 # setsebool -P virt_use_nfs=true
  2 # setsebool -P virt_sandbox_use_nfs=true

 

1.9 NFS回收政策

NFS支持OpenShift的Recyclable插件,根據在每個持久卷上設置的策略處理自動執行回收任務。
默認情況下,持久卷被設置為Retain。Retain reclaim策略允許手動回收資源。當刪除pv claim時,持久卷仍然存在,並且認為該卷已被釋放。但它還不能用於另一個claim,因為來自前一個claim的數據仍然保留在卷上。此時管理員可以手動回收卷。
NFS卷及其回收策略設置為Recycle,表示在從claim中釋放后將被清除。例如,當將NFS回收策略設置為Recycle后,在刪除用戶綁定到該卷的pv claim之後,會在該卷上運行rm -rf命令。在它被回收之後,NFS卷可以直接綁定到一個新的pv claim。

1.10 Supplemental group

Supplemental group是常規的Linux組。當一個進程在Linux中運行時,它有一個UID、一個GID和一個或多個Supplemental group。可以為容器的主進程設置這些屬性。
Supplemental groupid通常用於控制對共享存儲的訪問,比如NFS和GlusterFS,而fsGroup用於控制對塊存儲(如Ceph的RBD活iSCSI)的訪問。
OpenShift共享存儲插件掛載卷,以便使掛載上的POSIX權限與目標存儲上的權限匹配。例如,如果目標存儲的所有者ID是1234,組ID是5678,那麼宿主節點和容器中的掛載將具有相同的ID。因此,容器的主進程必須匹配一個或兩個id,才能訪問該卷。

  1 [root@node ~]# showmount -e
  2 Export list for master.lab.example.com:
  3 /var/export/nfs-demo *
  4 [root@services ~]# cat /etc/exports.d/nfs-demo.conf
  5 /var/export/nfs-demo
  6 ...
  7 [root@services ~]# ls -lZ /var/export -d
  8 drwx------. 10000000 650000 unconfined_u:object_r:usr_t:s0 /var/export/nfs-demo

 
圖上示例,UID 10000000和組650000可以訪問/var/export/nfs-demo export。通常,容器不應該作為root用戶運行。在這個NFS示例中,如果容器不是作為UID 10000000運行的,並且不是組650000的成員,那麼這些容器就不能訪問NFS export。

1.11 通過fsgroup使用塊存儲

fsGroup定義了pod的“file-system group”ID,該ID被添加到容器的supplemental group中。supplemental group ID應用於共享存儲,而fsGroup ID用於塊存儲。
塊存儲,如Ceph RBD、iSCSI和各種類型的雲存儲,通常專用於單個pod。與共享存儲不同,塊存儲由pod接管,這意味着pod(或image)定義中提供的用戶和組id應用於實際的物理塊設備,塊存儲通常不共享。

1.12 SELINUX和卷security

除了SCC之外,所有預定義的安全上下文約束都將seLinuxContext設置為MustRunAs。最可能匹配pod需求的SCC迫使pod使用SELinux策略。pod使用的SELinux策略可以在pod本身、image、SCC或project(提供默認值)中定義。
SELinux標籤可以在pod的securityContext中定義。,並支持user、role、type和level標籤。

1.13 ELinuxContext選項

  • MustRunAs

如果不使用預先分配的值,則要求配置seLinuxOptions。使用seLinuxOptions作為默認值,從而針對seLinuxOptions驗證。

  • RunAsAny

沒有提供默認,允許指定任何seLinuxOptions。

二 持久卷練習

2.1 前置準備

準備完整的OpenShift集群,參考《003.OpenShift網絡》2.1。

2.2 本練習準備

  1 [student@workstation ~]$ lab deploy-volume setup

2.3 配置NFS

本實驗不詳解NFS的配置和創建,直接使用/root/DO280/labs/deploy-volume/config-nfs.sh腳本實現,具體腳本內容可通過以下方式查看。
同時NFS由services節點提供。

  1 [root@services ~]# less -FiX /root/DO280/labs/deploy-volume/config-nfs.sh
  2 [root@services ~]# /root/DO280/labs/deploy-volume/config-nfs.sh		#創建NFS
  3 Export directory /var/export/dbvol created.
  4 [root@services ~]# showmount -e						#確認驗證

 

2.4 node節點掛載NFS

  1 [root@node1 ~]# mount -t nfs services.lab.example.com:/var/export/dbvol /mnt
  2 [root@node1 ~]# mount | grep /mnt
  3 [root@node1 ~]# ll -a /mnt/		#檢查相關權限

 

  1 [root@node1 ~]# umount /mnt/		#卸載

提示:建議node2也做以上掛載測試,測試完成后建議下載,NFS共享在OpenShift需要的時候會自動掛載。

2.5 創建持久卷

  1 [student@workstation ~]$ oc login -u admin -p redhat https://master.lab.example.com
  2 [student@workstation ~]$ less -FiX /home/student/DO280/labs/deploy-volume/mysqldb-volume.yml
  3 apiVersion: v1
  4 kind: PersistentVolume
  5 metadata:
  6   name: mysqldb-volume
  7 spec:
  8   capacity:
  9     storage: 3Gi
 10   accessModes:
 11   - ReadWriteMany
 12   nfs:
 13     path: /var/export/dbvol
 14     server: services.lab.example.com
 15   persistentVolumeReclaimPolicy: Recycle
 16 [student@workstation ~]$ oc create -f /home/student/DO280/labs/deploy-volume/mysqldb-volume.yml
 17 [student@workstation ~]$ oc get pv		#查看PV
 18 NAME    CAPACITYACCESS    MODES    RECLAIM    POLICY STATUS    CLAIM    STORAGECLASS    REASON    AGE
 19 mysqldb-volume    3Gi     RWX      Recycle    Available                                           1m

 

2.6 創建項目

  1 [student@workstation ~]$ oc login -u developer -p redhat https://master.lab.example.com
  2 [student@workstation ~]$ oc new-project persistent-storage

 

2.7 部署應用

  1 [student@workstation ~]$ oc new-app --name=mysqldb \
  2 --docker-image=registry.lab.example.com/rhscl/mysql-57-rhel7 \
  3 -e MYSQL_USER=ose \
  4 -e MYSQL_PASSWORD=openshift \
  5 -e MYSQL_DATABASE=quotes
  6 [student@workstation ~]$ oc status		#確認驗證
  7 In project persistent-storage on server https://master.lab.example.com:443
  8 
  9 
 10 svc/mysqldb - 172.30.39.72:3306
 11   dc/mysqldb deploys istag/mysqldb:latest
 12     deployment #1 deployed 58 seconds ago - 1 pod

2.8 配置持久卷

  1 [student@workstation ~]$ oc describe pod mysqldb | grep -A2 'Volumes'	#查看當前pod的Volume
  2 Volumes:
  3   mysqldb-volume-1:
  4     Type:    EmptyDir (a temporary directory that shares a pod's lifetime)
  5 [student@workstation ~]$ oc set volumes dc mysqldb \
  6 --add --overwrite --name=mysqldb-volume-1 -t pvc \
  7 --claim-name=mysqldb-pvclaim \
  8 --claim-size=3Gi \
  9 --claim-mode='ReadWriteMany'		#修改dc並創建PVC
 10 [student@workstation ~]$ oc describe pod mysqldb | grep -E -A 2 'Volumes|ClaimName'	#查看驗證

 

  1 [student@workstation ~]$ oc get pvc		#查看PVC
  2 NAME              STATUS    VOLUME           CAPACITY   ACCESS MODES   STORAGECLASS   AGE
  3 mysqldb-pvclaim   Bound     mysqldb-volume   3Gi        RWX                           2m

 

2.9 端口轉發

  1 [student@workstation ~]$ oc get pod
  2 NAME              READY     STATUS    RESTARTS   AGE
  3 mysqldb-2-r7wz8   1/1       Running   0          4m
  4 [student@workstation ~]$ oc port-forward mysqldb-2-r7wz8 3306:3306

 

2.10 測試數據庫

  1 [student@workstation ~]$ mysql -h127.0.0.1 -uose -popenshift \
  2 quotes < /home/student/DO280/labs/deploy-volume/quote.sql	#填充數據測試
  3 [student@workstation ~]$ mysql -h127.0.0.1 -uose -popenshift \
  4 quotes -e "select count(*) from quote;"				#確認填充完成
  5 [student@workstation ~]$ ssh root@services ls -la /var/export/dbvol	#查看NFS服務端數據
  6 ……
  7 drwxr-x---. 2 nfsnobody nfsnobody       54 Jul 21 23:43 quotes
  8 ……
  9 [student@workstation ~]$ ssh root@services ls -la /var/export/dbvol/quotes
 10 total 116
 11 drwxr-x---. 2 nfsnobody nfsnobody    54 Jul 21 23:43 .
 12 drwx------. 6 nfsnobody nfsnobody  4096 Jul 21 23:39 ..
 13 -rw-r-----. 1 nfsnobody nfsnobody    65 Jul 21 23:39 db.opt
 14 -rw-r-----. 1 nfsnobody nfsnobody  8584 Jul 21 23:43 quote.frm
 15 -rw-r-----. 1 nfsnobody nfsnobody 98304 Jul 21 23:44 quote.ibd

 

2.11 刪除PV

  1 [student@workstation ~]$ oc delete project persistent-storage	#刪除項目
  2 project "persistent-storage" deleted
  3 [student@workstation ~]$ oc delete pv mysqldb-volume		#刪除PV
  4 persistentvolume "mysqldb-volume" deleted

   

2.12 驗證持久性

刪除PV后驗證數據是否會長期保留。

  1 [student@workstation ~]$ ssh root@services ls -la /var/export/dbvol
  2 ……
  3 drwxr-x---. 2 nfsnobody nfsnobody       54 Jul 21 23:43 quotes
  4 ……
  5 [student@workstation ~]$ ssh root@services rm -rf /var/export/dbvol/*	#使用rm才可以徹底刪除

 

三 私有倉庫持久存儲

3.1 創建私有倉庫持久卷

OCP內部倉庫是source-to-image(S2I)流程的一個重要組件,該流程用於從應用程序源代碼創建pod。S2I流程的最終輸出是一個容器image,它被推送到OCP內部倉庫,然後可以用於部署。
在生產環境中,通常建議為內部倉庫提供一個持久性存儲。否則,在重新創建registry pod之後,S2I創建的pod可能無法啟動。例如,在master節點重新啟動之後。
OpenShift安裝程序配置並啟動一個默認的持久倉庫,該倉庫使用NFS共享,由Inventory文件中的openshift_hosted_registry_storage_*變量定義。在生產環境中,Red Hat建議由外部專用的存儲提供持久性存儲,該服務器配置為彈性和高可用性。
高級安裝程序將NFS服務器配置為使用外部NFS服務器上的持久存儲,在[NFS]字段中定義的一個NFS服務器的列表。該服務器與openshift_hosted_registry_storage*變量一起使用,以配置NFS服務器。
示例配置:

  1 [OSEv3:vars]
  2 openshift_hosted_registry_storage_kind=nfs		#定義OCP存儲後端
  3 openshift_hosted_registry_storage_access_modes=['ReadWriteMany']	#定義訪問模式,默認為ReadWriteMany,表示允許多個節點以讀寫形式掛載
  4 openshift_hosted_registry_storage_nfs_directory=/exports		#定義NFS服務器上的NFS存儲目錄
  5 openshift_hosted_registry_storage_nfs_options='*(rw,root_squash)'	#定義存儲卷的NFS選項。這些選項被添加到/etc/ exports.d/openshift-ansible.exports中。rw選項允許對NFS卷進行讀寫訪問,root_squash選項阻止遠程連接的根用戶擁有root特權,併為nfsnobody分配用戶ID
  6 openshift_hosted_registry_storage_volume_name=registry		#定義要用於持久倉庫的NFS目錄的名稱
  7 openshift_hosted_registry_storage_volume_size=40Gi			#定義持久卷大小
  8 ... output omitted ...
  9 [nfs]
 10 services.lab.example.com

 
在為持久倉庫安裝和配置存儲之後,OpenShift在OpenShift項目中創建一個名為register-volume的持久卷。持久性卷的容量為40gb,並且根據定義設置了Retain策略。同時默認項目中的pvc調用pv。

  1 [student@workstation ~]$ oc describe pv registry-volume
  2 Name:            registry-volume	#定義持久卷名
  3 Labels:          <none>
  4 Annotations:     pv.kubernetes.io/bound-by-controller=yes
  5 StorageClass:
  6 Status:          Bound
  7 Claim:           default/registry-claim	#定義使用持久卷的聲明
  8 Reclaim Policy:  Retain			#默認持久卷策略,具有Retain策略的卷在從其聲明中釋放后不會被擦除
  9 Access Modes:    RWX			#定義持久卷的訪問模式,由Ansible inventory文件的openshift_hosted_registry_storage_access_modes=['ReadWriteMany']變量定義
 10 Capacity:        40Gi			#定義持久卷的大小,由Ansible inventory文件的openshift_hosted_registry_storage_volume_size變量定義
 11 Message:
 12 Source:					#定義存儲後端的位置和NFS共享
 13     Type:      NFS (an NFS mount that lasts the lifetime of a pod)
 14     Server:    services.lab.example.com
 15     Path:      /exports/registry
 16     ReadOnly:  false
 17 Events:        <none>

 
運行以下命令,確認OpenShift內部倉庫已配置registry-volume作為默認的PersistentVolumeClaim。

  1 [user@demo ~] oc describe dc/docker-registry | grep -A4 Volumes
  2   Volumes:
  3    registry-storage:
  4     Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
  5     ClaimName:  registry-claim
  6     ReadOnly:   false

 
OCP內部倉庫將image和metadata存儲為普通文件和文件夾,這意味着可以檢查PV源存儲,查看倉庫是否向其寫入了文件。
在生產環境中,這是通過訪問外部NFS服務器來完成的。但是,在本環境中,NFS共享是在services的VM上配置的,因此ssh至services查看,以便於驗證OCP內部倉庫成功將image存儲到持久存儲中。
示例:一個名為hello的應用程序在default命名空間中運行,下面的命令驗證圖像是否存儲在持久存儲中。

  1 [user@demo ~] ssh root@master ls -l \
  2 /var/export/registryvol/docker/registry/v2/repositories/default/

 

四 PV綜合實驗

4.1 前置準備

準備完整的OpenShift集群,參考《003.OpenShift網絡》2.1。

4.2 本練習準備

[student@workstation ~]$ lab storage-review setup

4.3 配置NFS

本實驗不詳解NFS的配置和創建,直接使用/root/DO280/labs/deploy-volume/config-nfs.sh腳本實現,具體腳本內容可通過以下方式查看。
同時NFS由services節點提供。

  1 [root@services ~]# less -FiX /root/DO280/labs/storage-review/config-review-nfs.sh
  2 [root@services ~]# /root/DO280/labs/storage-review/config-review-nfs.sh		#創建NFS
  3 [root@services ~]# showmount -e							#確認驗證

 

4.4 創建持久卷

  1 [student@workstation ~]$ oc login -u admin -p redhat https://master.lab.example.com
  2 [student@workstation ~]$ less -FiX /home/student/DO280/labs/storage-review/review-volume-pv.yaml
  3 apiVersion: v1
  4 kind: PersistentVolume
  5 metadata:
  6   name: review-pv
  7 spec:
  8   capacity:
  9     storage: 3Gi
 10   accessModes:
 11   - ReadWriteMany
 12   nfs:
 13     path: /var/export/review-dbvol
 14     server: services.lab.example.com
 15   persistentVolumeReclaimPolicy: Recycle
 16 [student@workstation ~]$ oc create -f /home/student/DO280/labs/storage-review/review-volume-pv.yaml
 17 [student@workstation ~]$ oc get pv		#查看PV
 18 NAME    CAPACITYACCESS    MODES    RECLAIM    POLICY STATUS    CLAIM    STORAGECLASS    REASON    AGE
 19 review-pv    3Gi     RWX      Recycle    Available                                           13s

 

4.5 部署模板

  1 [student@workstation ~]$ less -FiX /home/student/DO280/labs/storage-review/instructor-template.yaml
  2 [student@workstation ~]$ oc create -n openshift -f /home/student/DO280/labs/storage-review/instructor-template.yaml
  3 #使用模板創建應用至openshift namespace中

 

4.6 創建項目

  1 [student@workstation ~]$ oc login -u developer -p redhat https://master.lab.example.com
  2 [student@workstation ~]$ oc new-project instructor

 

4.7 web部署應用

瀏覽器訪問: https://master.lab.example.com

選擇Catalog

選擇PHP,並使用instructor-template。

設置Application Hostname,然後直接下一步,模板會創建一個數據庫服務器。

單擊Continue to project overview以監視應用程序的構建過程。從提供的服務框架中,單擊講師。單擊部署配置#1條目旁邊的下拉箭頭,打開部署面板。當構建完成時,build部分的Complete旁邊應該出現一個綠色的複選標記。

4.8 端口轉發

  1 [student@workstation ~]$ oc login -u developer -p redhat https://master.lab.example.com
  2 [student@workstation ~]$ oc get pod
  3 NAME                 READY     STATUS      RESTARTS   AGE
  4 instructor-1-9fmct   1/1       Running     0          43s
  5 instructor-1-build   0/1       Completed   0          2m
  6 mysql-1-f7rrq        1/1       Running     0          2m
  7 [student@workstation ~]$ oc port-forward mysql-1-f7rrq 3306:3306

 

4.9 填充數據庫

  1 [student@workstation ~]$ mysql -h127.0.0.1 -u instructor -ppassword \
  2 instructor < /home/student/DO280/labs/storage-review/instructor.sql
  3 [student@workstation ~]$ mysql -h127.0.0.1 -u instructor -ppassword instructor -e "select * from instructors;"	#查看
  4 

4.10 測試訪問

workstations的瀏覽器訪問:http://instructor.apps.lab.example.com

4.11 測試添加數據

 
 

4.12 確認驗證

  1 [student@workstation ~]$ lab storage-review grade		#環境腳本判斷實驗

4.13 清理刪除

  1 [student@workstation ~]$ oc login -uadmin -predhat
  2 [student@workstation ~]$ oc delete project instructor
  3 [student@workstation ~]$ oc delete pv review-pv
  4 [student@workstation ~]$ ssh root@services
  5 [root@services ~]# rm -rf /var/export/review-dbvol
  6 [root@services ~]# rm -f /etc/exports.d/review-dbvol.exports

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

【其他文章推薦】

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

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

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

※超省錢租車方案

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

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

蝗蟲肆虐 巴基斯坦進入緊急狀態 或向死敵印度買殺蟲劑

摘錄自2020年2月17日香港蘋果日報報導

數以千億隻蝗蟲近日肆虐東非、西亞多國,巴基斯坦恐防今夏蝗蟲來襲,可能暫時少理與敵國印度的貿易禁令,從印度進口殺蟲劑做好準備。

據報巴基斯坦周二內閣會議議程上,列出了從印度進口殺蟲劑的選項,而正爆發武漢肺炎疫情的中國,則是巴基斯坦可選擇採購殺蟲劑的另一地方。

國家糧食安全與研究部植物保護處總幹事納茲(Dr Falak Naz)表示:「絕對是的,我們擔心6月至7月會有蝗蟲侵襲,因此我們正提早計劃做好準備。」糧食部向國會進行簡報後,巴基斯坦本月較早時就蝗禍宣佈全國進入緊急狀態,警告國家正面對20年來最嚴重的蝗災。

當地英文報章《論壇快報》(The Express Tribune)引述國家糧食安全部長巴赫蒂亞爾(Khusro Bakhtiar)說,蝗蟲目前身處印巴邊境,巴國已對超過12.14萬公頃土地上的蝗蟲採取行動,並從空中對2萬公頃的土地噴灑了殺蟲劑。

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

通用電氣將向福特採購2000輛混合動力車

通用電氣公司(GE)日前宣佈,將為公司車隊購買2000輛福特汽車公司生產的C-Max Energi插電式

C-Max Energi本月剛剛開始在市場上出售,在全電動模式下,這款車能夠行駛大約20英里,在市區的燃油里程為108英里/加侖,綜合燃油里程超過100英里/加侖,廠家建議零售價為29,995美元。

通用電氣兩年前已宣佈,計畫在2015年之前購買2.5萬輛電動及混合動力汽車,在公司總數3萬輛的車隊以及旗下GE Capital的租賃車輛中,替代能源汽車將占到至少一半的比例。

包括與福特的這筆交易在內,通用電氣現在已擁有了5000輛替代能源汽車。

作為此項交易的一部分,福特將幫助推廣通用電氣的電動汽車充電站。兩公司還計畫與喬治亞州科技大學的研究人員合作,以研究員工的駕駛和充電習慣,並將把研究結果與其他希望增加電動汽車在車隊中比例的公司進行分享。

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案