地球傳出「警訊」 南極半島創30年來最暖

摘錄自2020年10月3日自由時報報導

據智利聖地牙哥大學(University of Santiago de Chile)研究顯示,2020年是過去30年以來,南極半島平均溫度最高的一年,1到8月期間的溫度達到攝氏2到3度。聲明表示,溫度相較於過去,大約上升攝氏2度以上。

智利南極研究所(INACH)的氣候學家柯德洛(Raul Cordero)指出,南極半島最北端今年截至目前的平均最高溫已超過攝氏0度,這是31年以來首見。柯德洛認為這是地球向人類傳達的「警訊」,在這個區域也可以看見海洋持續快速暖化。

南極半島位於南極洲最北端,當地有許多國家的科學與軍事基地,包括阿根廷、智利與英國。儘管南極半島平均溫度上升,南半球冬季的高溫卻也出現新低,8月到9月期間,最高溫為攝氏零下16.8度,是自1970年以來的最低溫,氣候出現極端化。

氣候變遷
國際新聞
南極
全球暖化
歷史高溫

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

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

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

※想知道最厲害的網頁設計公司"嚨底家"!

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

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

俄遠東堪察加地區發生海水污染 環團憂生態災難

摘錄自2020年10月4日中央社報導

俄羅斯當局今(4日)通知遠東堪察加地區民眾遠離一處原始海灘,因發生不明原因的海水污染。綠色和平組織表示,這是當地發生「生態災難」的證據,並已造成一些衝浪者發燒和嘔吐。

路透社報導,污染地點在堪察加地區(Kamchatka Region)的卡拉克提斯基(Khalaktyrsky)海灘,目前還不清楚原因。俄羅斯當局表示,初步檢測發現海水有高含量的石油產品和化學物質苯酚。綠色和平組織(Greenpeace)要求當局盡速找到污染源。

這片海灘位在太平洋沿岸,布滿黑色火山砂,全長數十公里,是熱門觀光景點。綠色和平組織暗示,這起污染可能數週前已開始。綠色和平組織在聲明中表示,來到卡拉克提斯基海灘的民眾,數週以來就注意到污染情況。接觸過海水的人都出現不良反應,包括喉嚨痠痛、視力惡化、眼睛乾澀、噁心、身體虛弱、嘔吐和發燒。

海洋
污染治理
國際新聞
俄國

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

【其他文章推薦】

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

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

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

※超省錢租車方案

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

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

【其他文章推薦】

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

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

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

※超省錢租車方案

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

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

疫情肆虐油價跌 石油巨擘被迫減少探勘轉向綠能

摘錄自2020年10月4日中央社報導

疫情重創石油需求及油價,迫使能源巨擘縮減探勘規模,儘管尋找新油田對他們的生計依舊至關重要,他們仍將必須加強綠能投資。

根據研究團體Westwood統計,與疫情前計畫相比,能源業在英國北海水域探勘計畫削減7成,在挪威外海削減3成。

美國石油巨擘埃克森美孚公司(ExxonMobil)共砍了三成的探勘計畫,投資額減少100億美元。歐洲對手埃尼(Eni)、英國石油公司(BP)及艾基挪(Equinor)都有類似行動。根據美國軒尼詩布恩律師事務所(Haynes & Boone)統計,美國今年有30多家石油探勘和生產公司聲請破產。

根據能源諮詢機構「雷斯塔德能源」(Rystad Energy)估計,如果油價持續在當前每桶40美元左右徘徊,到了2022年可能還會有150家類似的公司消失。

能源轉型
國際新聞
石油
綠能

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

【其他文章推薦】

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

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

※超省錢租車方案

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

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

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

日本新潟「新世代熊」不怕人9天7人遇襲 半年內出沒逾700次

摘錄自2020年10月4日中央社報導

日本新潟縣近半年「熊出沒」次數創新高,次數多達逾700次,甚至發生近9天內有7人遭熊襲受傷的意外。專家推測,山上食物缺乏及不怕人的「新世代熊」逐年增加,恐是熊出沒次數創新高的原因。

專家提醒,在北海道、東北及北陸等很多熊棲息的地區,「由於熊分布區域愈來愈廣,大家應該要認知這是一種近在身旁的動物」。新潟縣政府表示,「熊出沒」次數主要是統計熊被目擊到或是被發現出沒痕跡的次數;縣府本月1日已發布「熊出沒警戒警報」。

日本新潟放送(BSN)報導,發生在新潟縣關川村的兩人遭熊攻擊事件,由於案發地附近約700公尺有一間小學,目前小學生都在警察等人護送下上下學。縣府表示,作為熊的食物之一的山毛櫸本季結果數量,是近10年來最少的一季,這些熊應該是下山到人居住的地方覓食,全縣各地都有必要警戒熊出沒。

生物多樣性
國際新聞
日本
人與動物衝突事件簿
人熊衝突

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

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

聯合國:恢復自然環境的資金缺口 高達7000億美元

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

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

【其他文章推薦】

※超省錢租車方案

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

※回頭車貨運收費標準

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

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

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

CocosCreator實現微信排行榜

1. 概述

不管是在現實生活還是當今遊戲中,各式各樣的排名層出不窮。如果我們做好一款遊戲,卻沒有實現排行榜,一定是不完美的。排行榜不僅是玩家了解自己實力的途徑,也是遊戲運營刺激用戶留存的一種途徑。在微信小遊戲中普遍存以下兩種排名

  • 好友關係排名
  • 世界排名

其中好友的排名,需要通過微信子域實現。在子域上下文中,只能調用微信提供相關的api,且數據傳輸只能進不能出。即使在子域中調用雲函數也不行。這個對數據很嚴格,開發略為複雜。但好處也很明顯

  • 無需用戶確認授權就可實現排名
  • 排名信息均為自己好友,刺激效果更明顯

儘管這樣,我們還是先實現世界排行。世界排行需要用戶授權。早期只需要調用wx.authorize就可以實現,現在很不穩定(好像廢棄了)。所以不得不通過生成一個授權按鈕來實現

2. 微信雲開發

微信小遊戲為開發者提供了一部分免費的雲環境。可以實現文件存儲,數據存儲以及通過雲函數實現服務端接口。開通方式也很簡單,這裏不做說明。既然要實現排名,優先選用雲函數來實現對應的api。要實現雲函數,需要在project.config.json文件中通過屬性cloudfunctionRoot指定雲函數目錄。由於,是通過cocoscretor開發,每次構建發布都會清空輸出內容。為了解決人肉複製粘貼,我們需要通過定製小遊戲構建模板實現微信小遊戲所有代碼的管理。小遊戲地心俠士構建模板如下

從圖中,可以看到獲取openid、獲取世界排名、保存用戶授權信息等雲函數都放在cocoscreator代碼環境中。這樣在開發完成后,通過cocoscreator構建發布,對應的雲函數也會一起打包過去

3. 實現世界排行

3.1 獲取玩家openid

首先在構建模板的cloud-functions文件件中,使用npm初始一個名為getOpenId的node項目。初始好以後,運行npm install wx-server-sdk@latest --save。這樣就建立好了一個雲函數的基本框架。

我們在index.js文件,輸入以下代碼

// author:herbert 464884492
// project:地心俠士  獲取用戶openid
const cloud = require('wx-server-sdk')
cloud.init()
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()
  return {
    event,
    openid: wxContext.OPENID,
    appid: wxContext.APPID,
    unionid: wxContext.UNIONID,
  }
}

 

調用雲函數時,上下文中便可以得到玩家openid和uninid。玩家進入遊戲就先調用此函數,得到玩家的openid用於後邊更新玩家數據和獲取世界排行的條件。

小遊戲端調用雲函數前,需要初始雲環境。因為採用定製構建模板,所以我們直接在模板的game.js文件末尾初始我的雲環境

// author:herbert 464884492
// 地心俠士 初始雲環境
....
wxDownloader.init();
window.boot();

//初始化雲調用
this.wx.cloud.init({
    traceUser: true,
    env: 'dxxs-dxxs'
});
...

  

後續調用雲函數中,第一步都是要獲取openid,這裏定義一個全局變量將其保存起來,調用方法如下

// author:herbert 464884492
// 地心俠士 玩家openid
private static openId: string = null;
private static initenv() {
  return new Promise((resolve, reject) => {
      if (!this.wx) reject();
      //直接使用本地緩存
      if (this.openId != null) resolve();
      // 調用雲函數獲取
      this.wx.cloud.callFunction({
          name: 'getOpenId',
          complete: res => {
              this.openId = res.result.openid;
              resolve();
          }
      });
  });
}

 

3.2 動態生成授權按鈕

先看下地心俠士布局界面

上圖中可以看到,地心俠士虛擬了一個遊戲操作區域。玩家聚焦到世界排行時,需要渲染一個授權按鈕在確定的位置。需求很簡單,可考慮到移動端多分辨率,這個操作就變得複雜了。需要做屏幕適配。地心俠士採用自適應寬度的適配策略,配置如下圖

遊戲運行時獲取實際分辨率的寬度與設計的寬度相除,變可知道當前寬度變化比列,鍵盤容器九宮格使用了主鍵widget底部111px,高度161px。確定按鈕寬度105px

微信小遊戲以左上角為原點,通過topleft確定位置。然而,cocoscreator以左下角為原點,所以在計算top值時需要用屏幕寬度 – box上邊緣y坐標。適配代碼如下

// author:herbert 464884492
// 地心俠士 動態生成透明授權按鈕
 initUserInfoButton() {
  // 獲取設計尺寸
  let desingSize: cc.Size = cc.view.getDesignResolutionSize();
  //  獲取實際屏幕尺寸
  let screenSize: cc.Size = cc.view.getFrameSize();
  // 獲取寬度倍率
  let widthRate = screenSize.width / desingSize.width;
  // 獲取當前倍率下九宮格鍵盤實際高度
  let halfKcHeight = 161 * widthRate / 2;
  // 獲取當前倍率下確定按鈕實際寬度
  let btnwidth = this.btnKeySuer.width * widthRate;
  WxCloudFun.createUserinfoButton("", 
  // 確定按鈕中心點對應小遊戲left值 (屏幕寬度-確定按鈕實際寬度)/2
  // 定義實際授權按鈕size為105*40,所以還必須加上對應的偏差值
  // 以下代碼中left體現整體適配過程,不考慮中間過程可以直接使用
  // (屏幕寬度-授權按鈕)/2 即可得到left值
  screenSize.width / 2 - 52.5 * widthRate + (btnwidth - 105) / 2, 
  // Canvas 適配策略是 Fit Width,所以Canvas下邊沿不一定就是屏幕邊緣
  // 通過111*widthRate得到具體下沿值,在加上虛擬鍵盤一半高度,可得到中心位置
  // 由於微信原點在左上角,需要保持按鈕處於中心位置,坐標還需要上移一半按鈕高度
  screenSize.height - (111 * widthRate + halfKcHeight + 20),
 () => {
      this.keyCode = cc.macro.KEY.r;
      this.scheduleOnce(async () => {
          this.dlgRank.active = true;
          // 獲取排名數據
          await this.getRankInfo();
      }, 0);
  });
}

 

3.3 獲取用戶頭像昵稱信息

經過上一步驟的適配操作,只要玩家聚焦到【世界排行】,地心俠士虛擬鍵盤的確定按鈕正上方會覆蓋一個透明的userInfoButton,玩家點擊確定就會喚起授權對話框,然後在對應的回調函數就可以完成用戶數據保存操作

// author:herbert 464884492
// 地心俠士 獲取玩家基本信息
 public static createUserinfoButton(text: string, left: number, top: number, cb: Function) {
   this.userInfoButton = this.wx.createUserInfoButton({
      type: 'text',
      text: text,
      style: {
          left: left,
          top: top,
          height: 40,
          width: 105,
          lineHeight: 40,
          textAlign: 'center',
          fontSize: 16,
          backgroundColor: '#ff000000',// 透明
          color: '#ffffff',
      }
   });
   this.userInfoButton.hide();
   this.userInfoButton.onTap((res) => {
     // 將獲取到的用戶數據提交到雲端
      this.wx.cloud.callFunction({
          name: 'putUserinfo',
          data: { ...res.userInfo, openid: this.openId }
      });
      this.hideUserInfoButton();
      cb.call();
   });
   }

 

在代碼中,除了傳入玩家微信信息外。我還額外傳遞進入遊戲時就獲取的openid。正常情況下不需要的,因為,雲函數中天然會告訴你openid。不過,我們在後端使用了got獲取玩家頭像保存到雲端文件存儲中。引入此包后,後端就獲取不到openid了,相當奇怪。對應雲平台雲函數代碼如下

// author:herbert 464884492
// 地心俠士 雲函數保存玩家基本信息
const cloud = require('wx-server-sdk')
const got = require('got')
cloud.init()
// 雲函數入口函數
exports.main = async(event, context) => {
  const {
    nickName,
    avatarUrl,
    gender,
    openid
  } = event;
  let wxContext = cloud.getWXContext();
  // 如果後端拿不到openid就採用前端傳入的openid
  wxContext.OPENID = wxContext.OPENID || openid;
  const log = cloud.logger()
  log.info({
    tip: `正在請求頭像地址[${avatarUrl}]`
  })
  // 獲取頭像數據流
  const stream = await got.stream(avatarUrl);
  let chunks = [];
  let size = 0;
  const body = await (async() => {
    return new Promise((res, reg) => {
      stream.on('data', chunk => {
        chunks.push(chunk)
        size += chunk.length
        log.info({
          tip: `正在讀取圖片流信息:[${chunk.length}]`
        })
      })
      stream.on('end', async() => {
        const body = Buffer.concat(chunks, size)
        log.info({
          tip: `正在保存頭像文件:[${size}]`
        })
        res(body)
      })
    })
  })()
  //保存頭像到雲存儲
  const {
    fileID
  } = await cloud.uploadFile({
    cloudPath: `avatars/${wxContext.OPENID}.jpg`,
    fileContent: body
  })
  // 添加或更新玩家信息到數據庫
  const db = cloud.database()
  const {
    data
  } = await db.collection("dxxs").where({
    _openid: wxContext.OPENID
  }).get()
  const updateData = {
    fileId: fileID,
    nickName: nickName,
    sex: gender == 1 ? '男' : '女',
    avatarUrl: avatarUrl
  }
  if (data.length > 0) {
    log.info({
      tip: `正在修改數據庫信息:[${size}]`
    })
    await db.collection("dxxs").doc(data[0]._id).update({
      data: updateData
    })
  } else {
    log.info({
      tip: `正在添加數據庫信息:[${size}]`
    })
    await db.collection("dxxs").add({
      data: { ...updateData,
        _openid: openid
      }
    })
  }

  return {
    openid: wxContext.OPENID,
    appid: wxContext.APPID,
    unionid: wxContext.UNIONID
  }
}

 

3.4 獲取排行數據

保存完用戶數據后,通過一個回調函數,實現了玩家排名數據獲取。細心的朋友可以在前邊授權按鈕適配的章節看到await this.getRankInfo();這句代碼。後端雲函數就是一個簡單數據查詢。效果圖如下

從上圖可以看到,我實現了三個維度排名,需要在前端需要傳入排名字段。對應代碼如下

// author:herbert 464884492
// 地心俠士 獲取排名信息
 public static async getWorldRanking(field: string = "level") {
     const { result } = await this.wx.cloud.callFunction({
         name: 'getWordRanking',
         data: { order: field }
     });
     return result.ranks;
 }

 

雲函數代碼如下

// author:herbert 464884492
// 地心俠士 雲函數返回排名信息
const cloud = require('wx-server-sdk')
cloud.init()
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()
  const db = cloud.database();
  const {
    order = "level"
  } = event;

  const openData = await db.collection("dxxs")
    .orderBy(order, "asc")
    .get()
  const ranks = openData.data.map(item => {
    return {
      openid: item._openid,
      [order]: item[order],
      nickName: item.nickName,
      fileId: item.fileId,
      avatarUrl: item.avatarUrl
    }
  });
  return {
    ranks: ranks,
    openid: wxContext.OPENID,
    appid: wxContext.APPID,
    unionid: wxContext.UNIONID
  }
}

 

4. 總結

  • 微信子域數據很嚴格,數據只進不出。調用雲函數也不行
  • 雲函數中使用http請求,可能會得不到openid
  • 屏幕適配知道定位原則,也可以很簡單
  • avatarUrl通過Sprite現實頭像,需要設置安全域名
  • 目前部分華為手機分享截屏出現黑屏使用canvas.toTempFilePath就可以解決

這裡有一個CoscosCreator遊戲開發群,歡迎喜歡聊技術的朋友加入

 

 

歡迎感興趣的朋友關注我的訂閱號“小院不小”,或點擊下方二維碼關注。我將多年開發中遇到的難點,以及一些有意思的功能,體會都會一一發布到我的訂閱號中

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

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

NASH:基於豐富網絡態射和爬山算法的神經網絡架構搜索 | ICLR 2018

論文提出NASH方法來進行神經網絡結構搜索,核心思想與之前的EAS方法類似,使用網絡態射來生成一系列效果一致且繼承權重的複雜子網,本文的網絡態射更豐富,而且僅需要簡單的爬山算法輔助就可以完成搜索,耗時0.5GPU day

來源:曉飛的算法工程筆記 公眾號

論文: Simple And Efficient Architecture Search for Convolutional Neural Networks

  • 論文地址:https://arxiv.org/pdf/1711.04528.pdf

Introduction

  論文目標在於大量減少網絡搜索的計算量並保持結果的高性能,核心思想與EAS算法類似,主要貢獻如下:

  • 提供baseline方法,隨機構造網絡並配合SGDR進行訓練,在CIFAR-10上能達到6%-7%的錯誤率,高於大部分NAS方法。
  • 拓展了EAS在網絡態射(network morphisms)上的研究,能夠提供流行的網絡構造block,比如skip connection和BN。
  • 提出基於爬山算法的神經網絡結構搜索NASH,該方法迭代地進行網絡搜索,在每次迭代中,對當前網絡使用一系列網絡態射得到多個新網絡,然後使用餘弦退火進行快速優化,最終得到性能更好的新網絡。在CIFAR-10上,NASH僅需要單卡12小時就可以達到baseline的準確率。

Network Morphism

  $\mathcal{N}(\mathcal{X})$為$\mathcal{X}\in \mathbb{R}^n$上的一系列網絡,網絡態射(network morphism)為映射$M: \mathcal{N}(\mathcal{X}) \times \mathbb{R}^k \to \mathcal{N}(\mathcal{X}) \times \mathbb{R}^j$,從參數為$w\in \mathbb{R}k$的網絡$fw \in \mathcal{N}(\mathcal{X})$轉換為參數為$\tilde{w} \in \mathbb{R}j$的網絡$g\tilde{w} \in \mathcal{N}(\mathcal{X})$,並且滿足公式1,即對於相同的輸入,網絡的輸出不變。

  下面給出幾種標準網絡結構的網絡態射例子:

Network morphism Type I

  將$f^w$進行公式2的替換,$\tilde{w}=(w_i, C, d)$,為了滿足公式1,設定$A=1$和$b=0$,可用於添加全連接層。

  另外一種複雜點的策略如公式3,$\tilde{w}=(w_i, C, d)$,設定$C=A^{-1}$和$d=-Cb$,可用於表達BN層,其中$A$和$b$表示統計結構,$C$和$d$為可學習的$\gamma$和$\beta$。

Network morphism Type II

  假設$f_i{w_i}$可由任何函數$h$表示,即$f_i{w_i}=Ah^{w_h}(x)+b$

  則可以將$f^w$,$w_i = (w_h, A, b)$配合任意函數$\tilde{h}{w_{\tilde{h}}}(x)$根據公式4替換為$\tilde{f}{\tilde{w}i}$,$\tilde{w}=(w_i, w{\tilde{h}}, \tilde{A})$,設定$\tilde{A}=0$。這個態射可以表示為兩種結構:

  • 增加層寬度,將$h(x)$想象為待拓寬的層,設定$\tilde{h}=h$則可以增加兩倍的層寬度。
  • concatenation型的skip connection,假設$h(x)$本身就是一系列層操作$h(x)=h_n(x) \circ \cdots \circ h_0(x)$,設定$\tilde{h}(x)=x$來實現短路連接。

Network morphism Type III

  任何冪等的函數$f_i^{w_i}$都可以通過公式5進行替換,初始化$\tilde{w}_i=w_i$,公式5在無權重的冪等函數上也成立,比如ReLU。

Network morphism Type IV

  任何層$f_i^{w_i}$都可以配合任意函數$h$進行公式6的替換,初始化$\lambda=1$,可用於結合任意函數,特別是非線性函數,也可以用於加入additive型的skip connection。
  此外,不同的網絡態射組合也可以產生新的態射,比如可以通過公式2、3和5在ReLU層後面插入”Conv-BatchNorm-Relu”的網絡結構。

Architecture Search by Network Morphisms

  NASH方法基於爬山算法,先從小網絡開始,對其進行網絡態射生成更大的子網絡,由於公式1的約束,子網的性能與原網絡是一樣的,後續子網進行簡單的訓練看是否有更好的性能,最後選擇性能優異的子網進行重複的操作。

  圖1可視化了NASH方法的一個step,算法1的ApplyNetMorph(model, n)包含n個網絡態射操作,每個為以下方法的隨機一種:

  • 加深網絡,例如添加Conv-BatchNorm-Relu模塊,插入位置和卷積核大小都是隨機的,channel數量跟最近的卷積操作一致。
  • 加寬網絡,例如使用network morphism type II來加寬輸出的channel,加寬比例隨機。
  • 添加從層$i$到層$j$的skup connection,使用network morphism type II或IV,插入位置均隨機選擇。

  由於使用了網絡態射,子網繼承了原網絡的權重且性能一致,NASH方法優勢在於能夠很快的評估子網的性能,論文使用了簡單的爬山算法,當然也可以選擇其它的優化策略。

Experiments

Baslines

Retraining from Scratch

CIFAR-10

CIFAR-100

CONCLUSION

  論文提出NASH方法來進行神經網絡結構搜索,核心思想與之前的EAS方法類似,使用網絡態射來生成一系列效果一致且繼承權重的複雜子網,本文的網絡態射更豐富,而且僅需要簡單的爬山算法輔助就可以完成搜索,耗時0.5GPU day



如果本文對你有幫助,麻煩點個贊或在看唄~
更多內容請關注 微信公眾號【曉飛的算法工程筆記】

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

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

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

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

超詳細實戰教程丨多場景解析如何遷移Rancher Server

本文轉自Rancher Labs

作者介紹

王海龍,Rancher中國社區技術經理,負責Rancher中國技術社區的維護和運營。擁有6年的雲計算領域經驗,經歷了OpenStack到Kubernetes的技術變革,無論底層操作系統Linux,還是虛擬化KVM或是Docker容器技術都有豐富的運維和實踐經驗。

Rancher提供兩種安裝方法,單節點和高可用安裝。單節點安裝允許用戶快速部署適用於短期開發測試為目的的安裝工作。高可用部署明顯更適合Rancher的長期使用。

在實際使用中可能會遇到需要將Rancher Server遷移到其他的節點或local集群去管理的情況。 雖然可以使用最簡單的import集群方式納管,但帶來的問題是後續無法做集群的管理和升級維護,而且一些namespace和project的關聯關係將會消失。所以本文主要介紹如何將Rancher Server遷移到其他節點或local集群。

本文主要針對3個場景去講解如何遷移Rancher Server:

  1. Rancher單節點安裝遷移至其他主機

  2. Rancher單節點安裝遷移至高可用安裝

  3. Rancher高可用安裝遷移至其他Local集群

重要說明

  1. Rancher 官方文檔文檔中並沒有說明支持以下場景的遷移,本文檔只是利用一些Rancher和RKE現有的功能實現遷移。

  2. 如果您在此過程中遇到問題,則應該熟悉Rancher架構/故障排除

  3. 遷移非常危險,遷移前一定剛要做好備份,以免發生意外無法恢復

  4. 您應該熟悉單節點安裝和高可用安裝之間的體繫結構差異

  5. 本文檔基於Rancher 2.4.x測試,其他版本操作可能會略有不同

  6. 本文檔主要講解Rancher Server的遷移,遷移過程中不會影響業務集群的使用

準備集群直連 kubeconfig 配置文件

默認情況下, Rancher UI 上複製的 kubeconfig 通過cluster agent代理連接到 kubernetes 集群。變更 Rancher Server會導致cluster agent無法連接 Rancher Server,從而導致kubectl無法使用 Rancher UI 上複製的 kubeconfig 去操作 kubernetes 集群。但可以使用kubectl –context <CLUSTER_NAME>-fqdn 直接連接kubernetes集群進行操作。所以在執行遷移之前,請準備好所有集群的直連 kubeconfig 配置文件。

Rancher v2.2.2以及之後的版本,可以直接從UI上下載kubeconfig文件。

Rancher v2.2.2之前的版本,請參考:恢復 kubectl 配置文件

場景1:Rancher單節點安裝遷移至其他主機

Rancher單節點安裝遷移至其他主機,只需要將舊集群Rancher Server容器的/var/lib/rancher目錄打包,然後替換到新Rancher Server對應的目錄,最後啟動新Rancher Server容器之後再更新agent相關配置即可。

1. Rancher 單節點安裝

提示:以下步驟創建用於演示遷移的 Rancher 單節點環境,如果您需要遷移正式環境可以跳過此步驟。

執行以下 docker 命令運行單節點 Rancher Server 服務

docker run -itd -p 80:80 -p 443:443 --restart=unless-stopped rancher/rancher:v2.4.3

等容器初始化完成后,通過節點 IP 訪問 Rancher Server UI,設置密碼並登錄。

2. 創建自定義集群

提示: 以下步驟創建用於演示的業務集群,用來驗證 Rancher 遷移后數據是否丟失,如果您需要遷移正式環境可以跳過此步驟。

登錄 Rancher UI 后,添加一個自定義集群

授權集群訪問地址設置為啟用,FQDN 和證書可以不用填寫。

注意:

這一步很關鍵。因為Rancher 遷移后,地址或者 token 或者證書的變更,將會導致 agent 無法連接 Rancher Server。遷移后,需要通過 kubectl 去編輯配置文件更新一些 agent 相關的參數。默認 UI 上的 kubeconfig文件是通過 agent 代理連接到 Kubernetes,如果 agent 無法連接 Rancher Server,則通過這個 kubeconfig 文件也無法訪問 Kubernetes 集群。開啟授權集群訪問地址功能會生成多個 Contexts Cluster,這些 Contexts Cluster 是直連 Kubernetes,不通過 agent 代理。如果業務集群未開啟這個功能,可以通過編輯集群來開啟這個功能。

點擊下一步,根據預先分配的節點角色選擇需要的角色,然後複製命令到主機終端執行。

集群部署完成后,進入集群首頁,點擊kubeconfig文件按鈕。在彈窗頁面中複製 kubeconfg 配置文件備用。

3.部署測試應用

部署一個nginx workload。再從應用商店部署一個測試應用。

4. 備份單節點Racher Server數據

docker create --volumes-from <RANCHER_CONTAINER_NAME> --name rancher-data-<DATE> rancher/rancher:<RANCHER_CONTAINER_TAG>

docker run  --volumes-from rancher-data-<DATE> -v $PWD:/backup:z busybox tar pzcvf /backup/rancher-data-backup-<RANCHER_VERSION>-<DATE>.tar.gz -C /var/lib rancher

詳細請參考Rancher中文官網單節點備份指南。

5. 將生成的rancher-data-backup-<RANCHER_VERSION>-<DATE>.tar.gz複製到新的Rancher Server節點

scp rancher-data-backup-<RANCHER_VERSION>-<DATE>.tar.gz root@<new_rancher_ip>:/opt/

6. 使用備份數據啟動新節點Rancher Server

如果原Rancher Server通過使用已有的自簽名證書或使用已有的可信證書安裝,遷移時,需要將證書一起複制到新Rancher Server,使用相同啟動命令掛載證書和備份數據啟動Rancher Server。

cd /opt && tar -xvz -f rancher-data-backup-<RANCHER_VERSION>-<DATE>.tar.gz

docker run -itd -p 80:80 -p 443:443 -v /opt/rancher:/var/lib/rancher --restart=unless-stopped rancher/rancher:v2.4.3

7. 更新Rancher Server IP或域名

注意:

如果您的環境使用自簽名證書或Let’s Encrypt 證書,並且配置域名訪問Rancher Server。遷移之後集群狀態為Active,請直接跳到第9步去驗證集群。

此時訪問新的Rancher Server就可以看見已經被管理的Kubernetes集群了,但此時集群狀態是unavailable,因為agent還連的是舊Rancher Server所以需要更新agent信息。

  • 依次訪問全局 > 系統設置,頁面往下翻找到server-url文件

  • 單擊右側的省略號菜單,選擇升級

  • 修改server-url地址為新Rancher Server的地址

  • 保存

8. 更新agent配置

通過新域名或IP登錄 Rancher Server;

通過瀏覽器地址欄查詢集群ID, c/後面以c開頭的字段即為集群 ID,本例的集群ID為c-4wzvf

  • 訪問https://<新的server_url>/v3/clusters/<集群ID>/clusterregistrationtokens頁面;

  • 打開clusterRegistrationTokens頁面后,定位到data字段;找到insecureCommand字段,複製 YAML 連接備用;

可能會有多組"baseType": "clusterRegistrationToken",如上圖。這種情況以createdTS最大、時間最新的一組為準,一般是最後一組。

使用kubectl工具,通過前文中準備的直連kubeconfig配置文件和上面步驟中獲取的 YAML 文件,執行以下命令更新agent相關配置。

curl --insecure -sfL <替換為上面步驟獲取的YAML文件鏈接> | kubectl --context=xxx  apply -f -

關於--context=xxx說明請參考直接使用下游集群進行身份驗證。

9. 驗證

過一會,集群變為Active狀態,然後驗證我們之前部署的應用是否可用。

場景2:Rancher單節點安裝遷移至高可用安裝

從單個節點遷移到Rancher的高可用性安裝的過程可以概括為以下幾個步驟:

在Rancher單節點實例上:

  1. 備份Rancher單節點容器

  2. 備份etcd快照

  3. 停止舊的Rancher單節點容器

在RKE Local集群上:

  1. 使用RKE啟動Rancher Local集群

  2. 利用rke etcd snapshot-restore,將單節點備份的etcd快照恢復到RKE HA

  3. 在RKE Local集群中安裝Rancher

  4. 更新Local集群和業務集群的相關配置,使agent可以連接到正確的Rancher Server

在單節點Rancher Server上操作

1. Rancher 單節點安裝

提示: 以下步驟創建用於演示遷移的 Rancher 環境,如果您需要遷移正式環境可以跳過此步驟。

執行以下 docker 命令運行單節點 Rancher Server 服務

docker run -itd -p 80:80 -p 443:443 --restart=unless-stopped rancher/rancher:v2.4.3

等容器初始化完成后,通過節點 IP 訪問 Rancher Server UI,設置密碼並登錄。

2. 創建自定義集群

提示: 以下步驟創建用於演示的業務集群,用來驗證 Rancher 遷移后數據是否丟失,如果您需要遷移正式環境可以跳過此步驟。

登錄 Rancher UI 后,添加一個自定義集群

授權集群訪問地址設置為啟用,FQDN 和證書可以不用填寫。

注意: 這一步很關鍵。因為Rancher 遷移后,地址或者 token 或者證書的變更,將會導致 agent 無法連接 Rancher Server。遷移后,需要通過 kubectl 去編輯配置文件更新一些 agent 相關的參數。默認 UI 上的 kubeconfig文件是通過 agent 代理連接到 Kubernetes,如果 agent 無法連接 Rancher Server,則通過這個 kubeconfig 文件也無法訪問 Kubernetes 集群。開啟授權集群訪問地址功能會生成多個 Contexts Cluster,這些 Contexts Cluster 是直連 Kubernetes,不通過 agent 代理。如果業務集群未開啟這個功能,可以通過編輯集群來開啟這個功能。

點擊 下一步 ,根據預先分配的節點角色選擇需要的角色,然後複製命令到主機終端執行。

集群部署完成后,進入集群首頁,點擊kubeconfig文件按鈕。在彈窗頁面中複製 kubeconfg 配置文件備用。

3. 部署測試應用

部署一個nginx workload。再從應用商店部署一個測試應用。

4. 創建將單節點etcd快照

docker exec -it <RANCHER_CONTAINER_NAME> bash

root@78efdcbe08a6:/# cd /

root@78efdcbe08a6:/# ETCDCTL_API=3 etcdctl snapshot save single-node-etcd-snapshot

root@78efdcbe08a6:/# exit

docker cp <RANCHER_CONTAINER_NAME>:/single-node-etcd-snapshot .

5. 關閉單節點Rancher Server

docker stop <RANCHER_CONTAINER_NAME>

在RKE Local集群上

1. RKE部署Local Kubernetes 集群

根據RKE示例配置 創建 RKE 配置文件 cluster.yml:

nodes:
- address: 99.79.49.94
    internal_address: 172.31.13.209
    user: ubuntu
    role: [controlplane, worker, etcd]
- address: 35.183.174.120
    internal_address: 172.31.8.28
    user: ubuntu
    role: [controlplane, worker, etcd]
- address: 15.223.49.238
    internal_address: 172.31.0.199
    user: ubuntu
    role: [controlplane, worker, etcd]

執行 rke 命令創建 Local Kubernetes 集群

rke up --config cluster.yml

檢查 Kubernetes 集群運行狀態

使用kubectl檢查節點狀態,確認節點狀態為Ready

kubectl get nodes

NAME             STATUS   ROLES                      AGE   VERSION
15.223.49.238    Ready    controlplane,etcd,worker   93s   v1.17.6
35.183.174.120   Ready    controlplane,etcd,worker   92s   v1.17.6
99.79.49.94      Ready    controlplane,etcd,worker   93s   v1.17.6

檢查所有必需的 Pod 和容器是否狀況良好,然後可以繼續進行

kubectl get pods --all-namespaces

NAMESPACE       NAME                                      READY   STATUS      RESTARTS   AGE
ingress-nginx   default-http-backend-67cf578fc4-9vjq4     1/1     Running     0          67s
ingress-nginx   nginx-ingress-controller-8g7kq            1/1     Running     0          67s
ingress-nginx   nginx-ingress-controller-8jvsd            1/1     Running     0          67s
ingress-nginx   nginx-ingress-controller-lrt57            1/1     Running     0          67s
kube-system     canal-68j4r                               2/2     Running     0          100s
kube-system     canal-ff4qg                               2/2     Running     0          100s
kube-system     canal-wl9hd                               2/2     Running     0          100s
kube-system     coredns-7c5566588d-bhbmm                  1/1     Running     0          64s
kube-system     coredns-7c5566588d-rhjpv                  1/1     Running     0          87s
kube-system     coredns-autoscaler-65bfc8d47d-tq4gj       1/1     Running     0          86s
kube-system     metrics-server-6b55c64f86-vg7qs           1/1     Running     0          79s
kube-system     rke-coredns-addon-deploy-job-fr2bx        0/1     Completed   0          92s
kube-system     rke-ingress-controller-deploy-job-vksrk   0/1     Completed   0          72s
kube-system     rke-metrics-addon-deploy-job-d9hlv        0/1     Completed   0          82s
kube-system     rke-network-plugin-deploy-job-kf8bn       0/1     Completed   0          103s

2. 將生成的單節點etcd快照從Rancher單節點實例傳到RKE Local集群節點上

在RKE HA Local節點上創建一個/opt/rke/etcd-snapshots目錄,並將single-node-etcd-snapshot文件複製到該目錄:

mkdir -p /opt/rke/etcd-snapshots
scp root@<old_rancher_ip>:/root/single-node-etcd-snapshot /opt/rke/etcd-snapshots

3. 使用RKE將單節點etcd快照還原到新的HA節點

rke etcd snapshot-restore --name single-node-etcd-snapshot --config cluster.yml

4. Rancher HA 安裝

參考安裝文檔安裝 Rancher HA。

5. 為Rancher HA配置NGINX 負載均衡

參考NGINX 配置示例為Rancher HA配置負載均衡。

Nginx 配置:

worker_processes 4;
worker_rlimit_nofile 40000;

events {
    worker_connections 8192;
}

stream {
    upstream rancher_servers_http {
        least_conn;
        server 172.31.11.95:80 max_fails=3 fail_timeout=5s;
        server 172.31.0.201:80 max_fails=3 fail_timeout=5s;
        server 172.31.15.236:80 max_fails=3 fail_timeout=5s;
    }
    server {
        listen 80;
        proxy_pass rancher_servers_http;
    }

    upstream rancher_servers_https {
        least_conn;
        server 172.31.11.95:443 max_fails=3 fail_timeout=5s;
        server 172.31.0.201:443 max_fails=3 fail_timeout=5s;
        server 172.31.15.236:443 max_fails=3 fail_timeout=5s;
    }
    server {
        listen     443;
        proxy_pass rancher_servers_https;
    }
}

Nginx啟動后,我們就可以通過配置的域名/IP去訪問Rancher UI。可以看到業務集群demoUnavailable狀態,local集群雖然為Active,但cluster-agentnode-agent均啟動失敗。

這兩種情況都是因為agent依然連接的舊的Rancher Server。

6. 更新Rancher Server IP或域名

  • 依次訪問全局 > 系統設置,頁面往下翻找到server-url文件

  • 單擊右側的省略號菜單,選擇升級

  • 修改server-url地址為新Rancher server的地址

  • 保存

7. 更新local集群和業務集群的agent配置

通過新域名或IP登錄 Rancher Server;

通過瀏覽器地址欄查詢集群ID, c/後面以c開頭的字段即為集群 ID,本例的集群ID為c-hftcn

訪問https://<新的server_url>/v3/clusters/<集群ID>/clusterregistrationtokens頁面;

打開clusterRegistrationTokens頁面后,定位到data字段;找到insecureCommand字段,複製 YAML 連接備用;

可能會有多組"baseType": "clusterRegistrationToken",如上圖。這種情況以createdTS最大、時間最新的一組為準,一般是最後一組。

使用kubectl工具,通過前文中準備的直連kubeconfig配置文件和上面步驟中獲取的 YAML 文件,執行以下命令更新agent相關配置。

注意:

更新local集群和業務集群使用的kubeconfig是不同的,請針對不通集群選擇需要的kubeconfig。

關於--context=xxx說明請參考直接使用下游集群進行身份驗證。

curl --insecure -sfL <替換為上面步驟獲取的YAML文件鏈接> | kubectl --context=xxx  apply -f -

業務集群agent更新成功后,使用相同的方法更新local集群agent配置。

9. 驗證

過一會,localdemo集群都變為Active狀態:

Local集群的cluster-agentnode-agent啟動成功

Demo集群的cluster-agentnode-agent啟動成功

然後驗證我們之前部署的應用是否可用。

場景3:Rancehr高可用安裝遷移至其他Local集群

Rancehr高可用安裝遷移至其他Local集群,可以藉助rke的更新功能完成。通過rke將原來的3節點local集群擴展成6個節點,此時etcd數據將自動同步到local集群內的6個節點上,然後再使用rke將原有的3台節點移除,再次更新。這樣就將Rancher Server可以平滑的遷移到新的Rancher local集群。

1. RKE部署Local Kubernetes 集群

根據RKE示例配置創建 RKE 配置文件 cluster.yml:

nodes:
- address: 3.96.52.186
    internal_address: 172.31.11.95
    user: ubuntu
    role: [controlplane, worker, etcd]
- address: 35.183.186.213
    internal_address: 172.31.0.201
    user: ubuntu
    role: [controlplane, worker, etcd]
- address: 35.183.130.12
    internal_address: 172.31.15.236
    user: ubuntu
    role: [controlplane, worker, etcd]

執行 rke 命令創建 Local Kubernetes 集群

rke up --config cluster.yml

檢查 Kubernetes 集群運行狀態

使用kubectl檢查節點狀態,確認節點狀態為Ready

kubectl get nodes
NAME             STATUS   ROLES                      AGE   VERSION
3.96.52.186      Ready    controlplane,etcd,worker   71s   v1.17.6
35.183.130.12    Ready    controlplane,etcd,worker   72s   v1.17.6
35.183.186.213   Ready    controlplane,etcd,worker   72s   v1.17.6

檢查所有必需的 Pod 和容器是否狀況良好,然後可以繼續進行

kubectl get pods --all-namespaces

NAMESPACE       NAME                                      READY   STATUS      RESTARTS   AGE
ingress-nginx   default-http-backend-67cf578fc4-gnt5c     1/1     Running     0          72s
ingress-nginx   nginx-ingress-controller-47p4b            1/1     Running     0          72s
ingress-nginx   nginx-ingress-controller-85284            1/1     Running     0          72s
ingress-nginx   nginx-ingress-controller-9qbdz            1/1     Running     0          72s
kube-system     canal-9bx8k                               2/2     Running     0          97s
kube-system     canal-l2fjb                               2/2     Running     0          97s
kube-system     canal-v7fzs                               2/2     Running     0          97s
kube-system     coredns-7c5566588d-7kv7b                  1/1     Running     0          67s
kube-system     coredns-7c5566588d-t4jfm                  1/1     Running     0          90s
kube-system     coredns-autoscaler-65bfc8d47d-vnrzc       1/1     Running     0          90s
kube-system     metrics-server-6b55c64f86-r4p8w           1/1     Running     0          79s
kube-system     rke-coredns-addon-deploy-job-lx667        0/1     Completed   0          94s
kube-system     rke-ingress-controller-deploy-job-r2nw5   0/1     Completed   0          74s
kube-system     rke-metrics-addon-deploy-job-4bq76        0/1     Completed   0          84s
kube-system     rke-network-plugin-deploy-job-gjpm8       0/1     Completed   0          99s

2. Rancher HA 安裝

參考安裝文檔安裝 Rancher HA。

3. 為Rancher HA配置NGINX 負載均衡

參考NGINX 配置示例為Rancher HA配置負載均衡。

Nginx 配置:

worker_processes 4;
worker_rlimit_nofile 40000;

events {
    worker_connections 8192;
}

stream {
    upstream rancher_servers_http {
        least_conn;
        server 172.31.11.95:80 max_fails=3 fail_timeout=5s;
        server 172.31.0.201:80 max_fails=3 fail_timeout=5s;
        server 172.31.15.236:80 max_fails=3 fail_timeout=5s;
    }
    server {
        listen 80;
        proxy_pass rancher_servers_http;
    }

    upstream rancher_servers_https {
        least_conn;
        server 172.31.11.95:443 max_fails=3 fail_timeout=5s;
        server 172.31.0.201:443 max_fails=3 fail_timeout=5s;
        server 172.31.15.236:443 max_fails=3 fail_timeout=5s;
    }
    server {
        listen     443;
        proxy_pass rancher_servers_https;
    }
}

Nginx啟動后,我們就可以通過配置的域名/IP去訪問Rancher UI。可以導航到local->Nodes 查看到local集群三個節點的狀態:

4. 部署測試集群及應用

添加測試集群,Node Role同時選中etcdControl PlaneWorker

等待測試集群添加成功后,部署一個nginx workload。再從應用商店部署一個測試應用。

5. 將新集群的節點添加到Local集群

修改剛才創建local集群所使用的rke配置文件,增加新集群的配置。

cluster.yml:

nodes:
- address: 3.96.52.186
    internal_address: 172.31.11.95
    user: ubuntu
    role: [controlplane, worker, etcd]
- address: 35.183.186.213
    internal_address: 172.31.0.201
    user: ubuntu
    role: [controlplane, worker, etcd]
- address: 35.183.130.12
    internal_address: 172.31.15.236
    user: ubuntu
    role: [controlplane, worker, etcd]

# 以下內容為新增節點的配置
- address: 52.60.116.56
    internal_address: 172.31.14.146
    user: ubuntu
    role: [controlplane, worker, etcd]
- address: 99.79.9.244
    internal_address: 172.31.15.215
    user: ubuntu
    role: [controlplane, worker, etcd]
- address: 15.223.77.84
    internal_address: 172.31.8.64
    user: ubuntu
    role: [controlplane, worker, etcd]

更新集群,將local集群節點擴展到6個

rke up --cluster.yml

檢查 Kubernetes 集群運行狀態

使用kubectl測試您的連通性,並確認原節點(3.96.52.186、35.183.186.213、35.183.130.12)和新增節點(52.60.116.56、99.79.9.244、15.223.77.84)都處於Ready狀態

kubectl get nodes
NAME             STATUS   ROLES                      AGE    VERSION
15.223.77.84     Ready    controlplane,etcd,worker   33s    v1.17.6
3.96.52.186      Ready    controlplane,etcd,worker   88m    v1.17.6
35.183.130.12    Ready    controlplane,etcd,worker   89m    v1.17.6
35.183.186.213   Ready    controlplane,etcd,worker   89m    v1.17.6
52.60.116.56     Ready    controlplane,etcd,worker   101s   v1.17.6
99.79.9.244      Ready    controlplane,etcd,worker   67s    v1.17.6

檢查所有必需的 Pod 和容器是否狀況良好,然後可以繼續進行

kubectl get pods --all-namespaces

NAMESPACE       NAME                                      READY   STATUS      RESTARTS   AGE
cattle-system   cattle-cluster-agent-68898b5c4d-lkz5m     1/1     Running     0          46m
cattle-system   cattle-node-agent-9xrbs                   1/1     Running     0          109s
cattle-system   cattle-node-agent-lvdlf                   1/1     Running     0          46m
cattle-system   cattle-node-agent-mnk76                   1/1     Running     0          46m
cattle-system   cattle-node-agent-qfwcm                   1/1     Running     0          75s
cattle-system   cattle-node-agent-tk66h                   1/1     Running     0          2m23s
cattle-system   cattle-node-agent-v2vpf                   1/1     Running     0          46m
cattle-system   rancher-749fd64664-8cg4w                  1/1     Running     1          58m
cattle-system   rancher-749fd64664-fms8x                  1/1     Running     1          58m
cattle-system   rancher-749fd64664-rb5pt                  1/1     Running     1          58m
ingress-nginx   default-http-backend-67cf578fc4-gnt5c     1/1     Running     0          89m
ingress-nginx   nginx-ingress-controller-44c5z            1/1     Running     0          61s
ingress-nginx   nginx-ingress-controller-47p4b            1/1     Running     0          89m
ingress-nginx   nginx-ingress-controller-85284            1/1     Running     0          89m
ingress-nginx   nginx-ingress-controller-9qbdz            1/1     Running     0          89m
ingress-nginx   nginx-ingress-controller-kp7p6            1/1     Running     0          61s
ingress-nginx   nginx-ingress-controller-tfjrw            1/1     Running     0          61s
kube-system     canal-9bx8k                               2/2     Running     0          89m
kube-system     canal-fqrqv                               2/2     Running     0          109s
kube-system     canal-kkj7q                               2/2     Running     0          75s
kube-system     canal-l2fjb                               2/2     Running     0          89m
kube-system     canal-v7fzs                               2/2     Running     0          89m
kube-system     canal-w7t58                               2/2     Running     0          2m23s
kube-system     coredns-7c5566588d-7kv7b                  1/1     Running     0          89m
kube-system     coredns-7c5566588d-t4jfm                  1/1     Running     0          89m
kube-system     coredns-autoscaler-65bfc8d47d-vnrzc       1/1     Running     0          89m
kube-system     metrics-server-6b55c64f86-r4p8w           1/1     Running     0          89m
kube-system     rke-coredns-addon-deploy-job-lx667        0/1     Completed   0          89m
kube-system     rke-ingress-controller-deploy-job-r2nw5   0/1     Completed   0          89m
kube-system     rke-metrics-addon-deploy-job-4bq76        0/1     Completed   0          89m
kube-system     rke-network-plugin-deploy-job-gjpm8       0/1     Completed   0          89m

從上面的信息可以確認現在local集群已經擴展到6個,並且所有workload均正常運行。

6. 再次更新集群,剔除掉原Local集群節點

再次修改local集群所使用的rke配置文件,將原local集群節點配置註釋掉。

cluster.yml:

nodes:
#  - address: 3.96.52.186
#    internal_address: 172.31.11.95
#    user: ubuntu
#    role: [controlplane, worker, etcd]
#  - address: 35.183.186.213
#    internal_address: 172.31.0.201
#    user: ubuntu
#    role: [controlplane, worker, etcd]
#  - address: 35.183.130.12
#    internal_address: 172.31.15.236
#    user: ubuntu
#    role: [controlplane, worker, etcd]
# 以下內容為新增節點
- address: 52.60.116.56
    internal_address: 172.31.14.146
    user: ubuntu
    role: [controlplane, worker, etcd]
- address: 99.79.9.244
    internal_address: 172.31.15.215
    user: ubuntu
    role: [controlplane, worker, etcd]
- address: 15.223.77.84
    internal_address: 172.31.8.64
    user: ubuntu
    role: [controlplane, worker, etcd]

更新集群,完成遷移。

rke up --cluster.yml

檢查 Kubernetes 集群運行狀態

使用kubectl檢查節點狀態為Ready,可以看到local集群的節點已經替換成了以下3個:

kubectl get nodes
NAME           STATUS   ROLES                      AGE   VERSION
15.223.77.84   Ready    controlplane,etcd,worker   11m   v1.17.6
52.60.116.56   Ready    controlplane,etcd,worker   13m   v1.17.6
99.79.9.244    Ready    controlplane,etcd,worker   12m   v1.17.6

檢查所有必需的 Pod 和容器是否狀況良好,然後可以繼續進行

kubectl get pods --all-namespaces

NAMESPACE       NAME                                    READY   STATUS    RESTARTS   AGE
cattle-system   cattle-cluster-agent-68898b5c4d-tm6db   1/1     Running   3          3m14s
cattle-system   cattle-node-agent-9xrbs                 1/1     Running   0          14m
cattle-system   cattle-node-agent-qfwcm                 1/1     Running   0          14m
cattle-system   cattle-node-agent-tk66h                 1/1     Running   0          15m
cattle-system   rancher-749fd64664-47jw2                1/1     Running   0          3m14s
cattle-system   rancher-749fd64664-jpqdd                1/1     Running   0          3m14s
cattle-system   rancher-749fd64664-xn6js                1/1     Running   0          3m14s
ingress-nginx   default-http-backend-67cf578fc4-4668g   1/1     Running   0          3m14s
ingress-nginx   nginx-ingress-controller-44c5z          1/1     Running   0          13m
ingress-nginx   nginx-ingress-controller-kp7p6          1/1     Running   0          13m
ingress-nginx   nginx-ingress-controller-tfjrw          1/1     Running   0          13m
kube-system     canal-fqrqv                             2/2     Running   0          14m
kube-system     canal-kkj7q                             2/2     Running   0          14m
kube-system     canal-w7t58                             2/2     Running   0          15m
kube-system     coredns-7c5566588d-nmtrn                1/1     Running   0          3m13s
kube-system     coredns-7c5566588d-q6hlb                1/1     Running   0          3m13s
kube-system     coredns-autoscaler-65bfc8d47d-rx7fm     1/1     Running   0          3m14s
kube-system     metrics-server-6b55c64f86-mcx9z         1/1     Running   0          3m14s

從上面的信息可以確認現在local集群已經遷移成功,並且所有workload均正常運行。

修改nginx負載均衡配置,將新節點的信息更新到nginx配置文件中

worker_processes 4;
worker_rlimit_nofile 40000;

events {
    worker_connections 8192;
}

stream {
    upstream rancher_servers_http {
        least_conn;
        server 172.31.14.146:80 max_fails=3 fail_timeout=5s;
        server 172.31.8.64:80 max_fails=3 fail_timeout=5s;
        server 172.31.15.215:80 max_fails=3 fail_timeout=5s;
    }
    server {
        listen 80;
        proxy_pass rancher_servers_http;
    }

    upstream rancher_servers_https {
        least_conn;
        server 172.31.14.146:443 max_fails=3 fail_timeout=5s;
        server 172.31.8.64:443 max_fails=3 fail_timeout=5s;
        server 172.31.15.215:443 max_fails=3 fail_timeout=5s;
    }
    server {
        listen     443;
        proxy_pass rancher_servers_https;
    }

}

7. 驗證

確認local集群和業務集群狀態為Active

確認Local集群節點已被替換

原集群節點IP分別為:3.96.52.186、35.183.186.213、35.183.130.12

然後驗證我們之前部署的應用是否可用。

總 結

開源一直是Rancher的產品理念,我們也一向重視與開源社區用戶的交流,為此創建了20個微信交流群。本篇文章的誕生源於和社區用戶的多次交流,發現許多Rancher用戶都有類似的問題。於是,我總結了三個場景並經過反覆測試,最終完成這篇教程。我們也十分歡迎各位Rancher用戶以各種形式分享自己的使用經驗,一起共建愉快的開源社區。

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

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

Scrum Master教你四招,瓦解團隊內部刺頭

摘要:《Scrum精髓》一書中將Scrum Master的職責總結為六類:敏捷教練,服務型領導,“保護傘”,“清道夫”,過程權威,“變革代言人”。作為“保護傘“,Scrum Master應該保護團隊免受任何干擾,當然也包括團隊內衝突,成員關係等。

背景

拜訪企業的過程中,不少企業領導提到過一個相似的問題:“我們團隊有個人平時總是和我(或者其他成員)對着干,把團隊氛圍搞得很差,Scrum Master應該怎麼引導他們,讓他們好好工作?”

本文就針對這樣的問題來聊聊,團隊中遇到“刺頭”應該怎麼辦?

問題分析

學生時代班級里總有幾個刺頭,他們惹是生非,擾亂課堂紀律——課堂上講話,接老師話茬,讓老師很是頭疼。企業中,很多團隊也有一兩個成員,他們難以合作,常常捅婁子,給團隊交付帶來不良影響,令管理層也很頭疼。

在交流過程中,筆者從不同人口中了解到不同類型的刺頭,分別有:

  • 技術骨幹

技術骨幹通常掌握着項目的核心技術,是開發交付不可或缺的關鍵角色,項目少了他很可能會產生較大的影響。有的技術骨幹對其他人,甚至是領導都愛答不理,和團隊很難溝通協作。

  • 原地踏步的“老人”

同一時期入職的員工,有的人做上了項目經理,有的人還在原地踏步寫一些基礎代碼

做同一個項目的團隊成員,有的人績效一直是A,獎金豐厚,有的人一直作為“吊車尾”混跡於團隊尾端

兩種情況的後者會存在一部分人表現出對工作消極懈怠,在團隊內傳播負面能量。比如經常抱怨、不滿、碎碎念,對其他團隊成員尤其是新人加以冷嘲熱諷。

  • 有離職打算的員工

大多數人做事講究善始善終,離職時都會做好交接工作。但有小部分人在離職時喜歡破罐子破摔——反正都要走了,還遵守什麼規矩,於是不認真交接,消極怠工,就等着離職辦手續。

  • 工作經驗少的“新人”

正所謂”初生牛犢不怕虎“,有些應屆畢業生在學校做過幾個項目,便感覺自己懂得很多,比其他同學高一等,步入職場后,對其他同事不尊重;還有一些工作經驗少的年輕員工做過幾個技術框架簡單的項目,便感覺自己的技術能力很強,心裏有了“開發就那麼點東西”的錯誤想法,進而輕視日常工作,不服從領導安排。

除個別極端情況比如天生性格不好,大多數刺頭不配合都是有原因的。

以上幾種情況總結起來有如下幾點原因:

  • 性格外冷內熱

筆者接觸過的技術骨幹性格很多都是外冷內熱——他們本身是樂於助人的,但由於他們日常工作很忙或者工作太投入,沒有太多精力去顧及自己對別人的態度,所以給人造成愛答不理的錯覺。

  • 自負

有少數技術牛人因為自己能力突出而變得自負,看不起公司其他人。在這部分人看來團隊成員都應該很輕鬆的完成任務,團隊成員問的問題都沒有技術含量,懶得回答;而且這部分人技術至上,很多公司管理層因為不會開發技術而被他們輕視。

和他們類似,有些年輕員工因為閱歷有限,沒有接觸過複雜的場景,做兩個項目就以為自己能力很突出,表現同上。

  • 對工作存在怨念

做同樣工作,評價有的高有的低,如果不懂得正視自己的缺點,那獲得低評價的人難免心中不服。經常如此,就會感覺自己懷才不遇,對周遭事物存在怨念。

如果員工在一家公司工作的很開心,通常離職時也會站好最後一班崗;離職前搗蛋的員工則多數是因為工作憋了一肚子氣或者和團隊鬧不愉快,離職前這幾天正好把憋得氣全撒出去。

常見的怨念來源還有工作中與其他成員的衝突未得到解決,個人未被團隊關注等。

針對這些問題,Scrum Master應該如何引導呢?

解決措施

很多人對於Scrum Master的理解是Scrum Master的工作就是幫助團隊召開各種會議,其實這是對Scrum Master工作的一種誤解。Scrum Master除了組織團隊召開會議,還有幫助團隊掃除障礙,促進團隊溝通等工作要做。《Scrum精髓》一書中將Scrum Master的職責總結為六類:敏捷教練,服務型領導,“保護傘”,“清道夫”,過程權威,“變革代言人”。作為“保護傘“,Scrum Master應該保護團隊免受任何干擾,當然也包括團隊內衝突,成員關係等。

敏捷開發中,Scrum Master應該幫助團隊成員建立共同的願景與集體價值觀,幫助每個成員成長並實現其自身價值,同時鼓勵成員們相互尊重、信賴。當遇到上文的問題時,Scrum Master可通過引導的方式加強團隊協作改變團隊現狀。

對於之前提到的問題,Scrum Master可以參考如下措施。

組織團建,拉近團隊成員之間的距離

外冷內熱型的團隊成員通常沒有機會與其他成員交流,定期抽出時間比如每次完成發布計劃或者兩個月為間隔,搞一次團隊建設(以下簡稱團建),團建可以讓整個團隊放鬆身心,團建本身也是一個很好的拉近團隊成員之間距離的方法。

團建通常會策劃一系列團隊運動:參与團建的成員以組為單位進行PK,每組成員在團建中為了團隊榮譽,盡情的釋放自己的能量。

團建考驗團隊協作,工作中看起來很難合作的人,可能在遊戲中就很容易合作。如果遊戲中合作愉快,這次合作的經歷很容易就會被帶到工作中,從而推動團隊向一個更积極的方向發展,讓團隊更有凝聚力。

讓刺頭知道人外有人

自信的人通常對自己的能力有一個正確的判斷,清楚自己的能力範圍;而自負的人則會高估自己的能力,輕視他人。自負常常源於自己認知有限,自負的刺頭通常認為自己技術能力已經處於行業巔峰,如果讓刺頭意識到自己並沒有比他人強太多,就可以讓其認清事實,調整心態,具體有如下幾種做法:

讓刺頭與能力更強的人一起共事,一方面可以認識到自己的不足,另一方面可以提高自己的境界。

如果刺頭是一個剛工作的年輕人,與老員工一起工作通常會發現老員工思考問題方式,代碼編寫習慣等都和自己不同,Bug也更少。兩人對比如同《賣油翁》里的陳康肅和賣油翁,“無他,唯手熟爾”,習慣源自多年工作經驗的積累——走過的坑多了就知道如何避開了。差距會讓刺頭認識到自己能力不足,還有很多方面需要提升,同時也是年輕人學習的一個好機會。

技術骨幹和能力相當的人共事,可以了解到自身並沒有比其他人強太多,在團隊內也並非無可替代,進而消除其自負心理。

如果公司內沒有比刺頭更強的人,可以讓其處理更難的工作

更強的人應該接受更強的挑戰。Scrum Master可以建議刺頭認領更難的工作,而非其擅長的工作,比如讓其使用行業新技術優化現有產品或者開發一系列工具提高團隊工作效率,建議的同時可以說“你覺得這工作有困難么,大概多久能完成”,或者“我聽說XXX用了一周就作完了,你技術這麼強應該也沒問題吧” 之類能夠刺激到他的話。

如果刺頭能夠按時完成工作,項目一定程度上會從中獲益;如果不能,刺頭自身也會有一種挫敗感——原來自己並非無所不能,自己和別人比還是有差距的,自負的情況也會有所改善。

傾聽刺頭心聲,耐心疏導

對工作存有怨念的刺頭,我們應該找到怨念的根因,想辦法疏導。

面對既將離職的刺頭,Scrum Master可以通過稱讚其以往對團隊做出的貢獻,緩和其不滿情緒。雖然雙方合作關係即將結束,但刺頭多少對團隊有些感情,Scrum Master動之以情,曉之以理,在維持其情緒穩定的同時,鼓勵其做到善始善終,站好最後一班崗。

刺頭沒有離職打算:

  • 如果Scrum Master清楚其怨念的根因

Scrum Master可以通話一對一談話的形式,為其打開心結。比如可以從最近狀態切入,引出根因(比如績效不如別人好,晉陞沒有別人快),然後解析其他人狀態,將刺頭與其他人形成對比,並列舉差異;Scrum Master可以在最後進行鼓勵比如“如果你能完成XX目標,我覺得你就可以獲得更好的績效,而且你絕對有這個能力完成”,讓刺頭了解與別人差距的同時也得到認可,並且獲得前進的動力。

講一個親身經歷的故事,故事發生在筆者步入職場后的第一個團隊。團隊的項目經理A和技術人員B同年入職,兩人對項目貢獻都很多。論技術A不如B,但是A的職級比B高一級(職級直接影響待遇),B大為不滿,工作中處處與A對着干,消極怠工,嚴重影響項目交付。公司總部領導了解情況后,給B制定了目標,只要B完成目標就提升其職級,最後B努力完成了目標,領導兌現諾言,給B提升了職級。對於B來說,職級上調,其目的已經達到,工作狀態也慢慢變得积極。

  • 如果Scrum Master不清楚其怨念根因

Scrum Master也可以找刺頭單獨談話。如果感覺直奔主題不好的話,可以在閑暇之餘對其進行重點關注,比如午休一起打打遊戲等,建立一定社交基礎后再嘗試詢問,然後逐步引導。

如果刺頭負面情緒來源於衝突沒有得到很好解決,Scrum Master可以擔任衝突調解員。Scrum Master站在客觀角度,和衝突雙方一起重新審視衝突,並客觀的給出建議,解決衝突。

在日常工作中,Scrum Master應該多認可,多鼓勵團隊成員,多與成員溝通,營造出輕鬆,融洽的工作氛圍,避免團隊成員因工作產生負面情緒。

崗位調整

如果刺頭始終無法改變,雙方互相耗着必將是一個雙輸的局面。

調整其崗位,讓其在能力範圍內選擇自己想做的工作也是企業中常見的做法。

參考附錄

Kenneth S.Rubin:Scrum精髓. 北京:清華大學出版社

 

點擊關注,第一時間了解華為雲新鮮技術~

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

C# 9.0 新特性之參數非空檢查簡化

閱讀本文大概需要 1.5 分鐘。

參數非空檢查是縮寫類庫很常見的操作,在一個方法中要求參數不能為空,否則拋出相應的異常。比如:

public static string HashPassword(string password)
{
    if(password is null)
    {
        throw new ArgumentNullException(nameof(password));
    }
    ...
}

當異常發生時,調用者很容易知道是什麼問題。如果不加這個檢查,可能就會由系統拋出未將對象引用為實例之類的錯誤,這不利於調用者診斷錯誤。

由於這個場景太常見了,於是我經常在我的項目中通過一個輔助類來做此類檢查。這個類用來檢查方法參數,所以命名為 Guard,主要代碼如下:

public static class Guard
{
    public static void NotNull(object param, string paramName)
    {
        if (param is null)
        {
            throw new ArgumentNullException(paramName);
        }
    }

    public static void NotNullOrEmpty(string param, string paramName)
    {
        NotNull(param, paramName);
        if (param == string.Empty)
        {
            throw new ArgumentException($"The string can not be empty.", paramName);
        }
    }

    public static void NotNullOrEmpty<T>(IEnumerable<T> param, string paramName)
    {
        NotNull(param, paramName);
        if (param.Count() == 0)
        {
            throw new ArgumentException("The collection can not be empty.", paramName);
        }
    }
    ...
}

這個類包含了三個常見的非空檢查,包括 null、空字符串、空集合的檢查。使用示例:

public static string HashPassword(string password)
{
    Guard.NotNull(password, nameof(password));
    ...
}

public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector)
{
    Guard.NotNullOrEmpty(source, nameof(source));
    ...
}

介於這種非空檢查極其常見,C# 9.0 對此做了簡化,增加了操作符‘!’,放在參數名後面,表示此參數不接受 null 值。使用方式如下:

public static string HashPassword(string password!)
{
    ...
}

簡化了很多有木有。這個提案已經納入 C# 9.0 的特性中,但目前(2020-06-13)還沒有完成開發。

這個特性只支持非 null 檢查,其它參數檢查場景還是不夠用的,我還是會通過輔助類來進行像空字符串、空集合的檢查。

這個特性在寫公共類庫的時候很有用,但我想大多數人在寫業務邏輯代碼的時候可能用不到這個特性,一般會封自己的參數檢查機制。比如,我在項目中,對於上層 API 開發,我通過封裝一個輔助類(ApiGuard)來對對參數進行檢查,如果參數不通過,則拋出相應的業務異常,而不是 ArgumentNullException。比如下面的一段截取自我的 GeekGist 小項目的代碼:

public static class ApiGuard
{
    public static void EnsureNotNull(object param, string paramName)
    {
        if (param == null) throw new BadRequestException($"{paramName} can not be null.");
    }

    public static void EnsureNotEmpty<T>(IEnumerable<T> collection, string paramName)
    {
        if (collection == null || collection.Count() == 0)
            throw new BadRequestException($"{paramName} can not be null or empty.");
    }

    public static void EnsureExist(object value, string message = "Not found")
    {
        if (value == null) throw new BadRequestException(message);
    }

    public static void EnsureNotExist(object value, string message = "Already existed")
    {
        if (value != null) throw new BadRequestException(message);
    }
    ...
}

使用示例:

public async Task UpdateAsync(long id, BookUpdateDto dto)
{
    ApiGuard.EnsureNotNull(dto, nameof(dto));
    ApiGuard.EnsureNotEmpty(dto.TagValues, nameof(dto.TagValues));

    var book = await DbSet
        .Include(x => x.BookTags)
        .FirstOrDefaultAsync(x => x.Id == id);
    ApiGuard.EnsureExist(book);

    Mapper.Map(dto, book);

    ...
}

ApiGuard 的好處是,當 API 接口接到不合要求的參數時,可以自定義響應返回內容。比如,增加一個 Filter 或中間件用來全局捕獲業務代碼異常,根據不同的異常返回給前端不同的狀態碼和消息提示:

private Task HandleExceptionAsync(HttpContext context, Exception exception)
{
    ApiResult result;
    if (exception is BadRequestException)
    {
        result = ApiResult.Error(exception.Message, 400);
    }
    else if (exception is NotFoundException)
    {
        message = string.IsNullOrEmpty(message) ? "Not Found" : message;
        result = ApiResult.Error(message, 404);
    }
    else if (exception is UnauthorizedAccessException)
    {
        message = string.IsNullOrEmpty(message) ? "Unauthorized" : message;
        result = ApiResult.Error(message, 401);
    }
    ...
}

只是一個參數非空檢查,在實際開發中卻有不少的學問,所以學好了理論還要多實踐才能更透徹的理解它。

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

【其他文章推薦】

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

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

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

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

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

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